Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
040df42a88
commit
b49ce524ed
|
|
@ -1,8 +1,10 @@
|
||||||
<script>
|
<script>
|
||||||
import { GlBadge, GlTab, GlTabs } from '@gitlab/ui';
|
import { GlBadge, GlPagination, GlTab, GlTabs } from '@gitlab/ui';
|
||||||
import { __, s__ } from '~/locale';
|
import { s__, __, sprintf } from '~/locale';
|
||||||
|
import { updateHistory, setUrlParams, queryToObject } from '~/lib/utils/url_utility';
|
||||||
import environmentAppQuery from '../graphql/queries/environment_app.query.graphql';
|
import environmentAppQuery from '../graphql/queries/environment_app.query.graphql';
|
||||||
import pollIntervalQuery from '../graphql/queries/poll_interval.query.graphql';
|
import pollIntervalQuery from '../graphql/queries/poll_interval.query.graphql';
|
||||||
|
import pageInfoQuery from '../graphql/queries/page_info.query.graphql';
|
||||||
import EnvironmentFolder from './new_environment_folder.vue';
|
import EnvironmentFolder from './new_environment_folder.vue';
|
||||||
import EnableReviewAppModal from './enable_review_app_modal.vue';
|
import EnableReviewAppModal from './enable_review_app_modal.vue';
|
||||||
|
|
||||||
|
|
@ -11,6 +13,7 @@ export default {
|
||||||
EnvironmentFolder,
|
EnvironmentFolder,
|
||||||
EnableReviewAppModal,
|
EnableReviewAppModal,
|
||||||
GlBadge,
|
GlBadge,
|
||||||
|
GlPagination,
|
||||||
GlTab,
|
GlTab,
|
||||||
GlTabs,
|
GlTabs,
|
||||||
},
|
},
|
||||||
|
|
@ -20,6 +23,7 @@ export default {
|
||||||
variables() {
|
variables() {
|
||||||
return {
|
return {
|
||||||
scope: this.scope,
|
scope: this.scope,
|
||||||
|
page: this.page ?? 1,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
pollInterval() {
|
pollInterval() {
|
||||||
|
|
@ -29,6 +33,9 @@ export default {
|
||||||
interval: {
|
interval: {
|
||||||
query: pollIntervalQuery,
|
query: pollIntervalQuery,
|
||||||
},
|
},
|
||||||
|
pageInfo: {
|
||||||
|
query: pageInfoQuery,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
inject: ['newEnvironmentPath', 'canCreateEnvironment'],
|
inject: ['newEnvironmentPath', 'canCreateEnvironment'],
|
||||||
i18n: {
|
i18n: {
|
||||||
|
|
@ -36,11 +43,21 @@ export default {
|
||||||
reviewAppButtonLabel: s__('Environments|Enable review app'),
|
reviewAppButtonLabel: s__('Environments|Enable review app'),
|
||||||
available: __('Available'),
|
available: __('Available'),
|
||||||
stopped: __('Stopped'),
|
stopped: __('Stopped'),
|
||||||
|
prevPage: __('Go to previous page'),
|
||||||
|
nextPage: __('Go to next page'),
|
||||||
|
next: __('Next'),
|
||||||
|
prev: __('Prev'),
|
||||||
|
goto: (page) => sprintf(__('Go to page %{page}'), { page }),
|
||||||
},
|
},
|
||||||
modalId: 'enable-review-app-info',
|
modalId: 'enable-review-app-info',
|
||||||
data() {
|
data() {
|
||||||
const scope = new URLSearchParams(window.location.search).get('scope') || 'available';
|
const { page = '1', scope = 'available' } = queryToObject(window.location.search);
|
||||||
return { interval: undefined, scope, isReviewAppModalVisible: false };
|
return {
|
||||||
|
interval: undefined,
|
||||||
|
isReviewAppModalVisible: false,
|
||||||
|
page: parseInt(page, 10),
|
||||||
|
scope,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
canSetupReviewApp() {
|
canSetupReviewApp() {
|
||||||
|
|
@ -82,6 +99,19 @@ export default {
|
||||||
stoppedCount() {
|
stoppedCount() {
|
||||||
return this.environmentApp?.stoppedCount;
|
return this.environmentApp?.stoppedCount;
|
||||||
},
|
},
|
||||||
|
totalItems() {
|
||||||
|
return this.pageInfo?.total;
|
||||||
|
},
|
||||||
|
itemsPerPage() {
|
||||||
|
return this.pageInfo?.perPage;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
window.addEventListener('popstate', this.syncPageFromQueryParams);
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
window.removeEventListener('popstate', this.syncPageFromQueryParams);
|
||||||
|
this.$apollo.queries.environmentApp.stopPolling();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
showReviewAppModal() {
|
showReviewAppModal() {
|
||||||
|
|
@ -89,12 +119,30 @@ export default {
|
||||||
},
|
},
|
||||||
setScope(scope) {
|
setScope(scope) {
|
||||||
this.scope = scope;
|
this.scope = scope;
|
||||||
|
this.resetPolling();
|
||||||
|
},
|
||||||
|
movePage(direction) {
|
||||||
|
this.moveToPage(this.pageInfo[`${direction}Page`]);
|
||||||
|
},
|
||||||
|
moveToPage(page) {
|
||||||
|
this.page = page;
|
||||||
|
updateHistory({
|
||||||
|
url: setUrlParams({ page: this.page }),
|
||||||
|
title: document.title,
|
||||||
|
});
|
||||||
|
this.resetPolling();
|
||||||
|
},
|
||||||
|
syncPageFromQueryParams() {
|
||||||
|
const { page = '1' } = queryToObject(window.location.search);
|
||||||
|
this.page = parseInt(page, 10);
|
||||||
|
},
|
||||||
|
resetPolling() {
|
||||||
this.$apollo.queries.environmentApp.stopPolling();
|
this.$apollo.queries.environmentApp.stopPolling();
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
if (this.interval) {
|
if (this.interval) {
|
||||||
this.$apollo.queries.environmentApp.startPolling(this.interval);
|
this.$apollo.queries.environmentApp.startPolling(this.interval);
|
||||||
} else {
|
} else {
|
||||||
this.$apollo.queries.environmentApp.refetch({ scope });
|
this.$apollo.queries.environmentApp.refetch({ scope: this.scope, page: this.page });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
@ -139,5 +187,19 @@ export default {
|
||||||
class="gl-mb-3"
|
class="gl-mb-3"
|
||||||
:nested-environment="folder"
|
:nested-environment="folder"
|
||||||
/>
|
/>
|
||||||
|
<gl-pagination
|
||||||
|
align="center"
|
||||||
|
:total-items="totalItems"
|
||||||
|
:per-page="itemsPerPage"
|
||||||
|
:value="page"
|
||||||
|
:next="$options.i18n.next"
|
||||||
|
:prev="$options.i18n.prev"
|
||||||
|
:label-previous-page="$options.prevPage"
|
||||||
|
:label-next-page="$options.nextPage"
|
||||||
|
:label-page="$options.goto"
|
||||||
|
@next="movePage('next')"
|
||||||
|
@previous="movePage('previous')"
|
||||||
|
@input="moveToPage"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import VueApollo from 'vue-apollo';
|
import VueApollo from 'vue-apollo';
|
||||||
import createDefaultClient from '~/lib/graphql';
|
import createDefaultClient from '~/lib/graphql';
|
||||||
import environmentApp from './queries/environment_app.query.graphql';
|
import environmentApp from './queries/environment_app.query.graphql';
|
||||||
|
import pageInfoQuery from './queries/page_info.query.graphql';
|
||||||
import { resolvers } from './resolvers';
|
import { resolvers } from './resolvers';
|
||||||
import typeDefs from './typedefs.graphql';
|
import typeDefs from './typedefs.graphql';
|
||||||
|
|
||||||
|
|
@ -19,6 +20,19 @@ export const apolloProvider = (endpoint) => {
|
||||||
stoppedCount: 0,
|
stoppedCount: 0,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
cache.writeQuery({
|
||||||
|
query: pageInfoQuery,
|
||||||
|
data: {
|
||||||
|
pageInfo: {
|
||||||
|
total: 0,
|
||||||
|
perPage: 20,
|
||||||
|
nextPage: 0,
|
||||||
|
previousPage: 0,
|
||||||
|
__typename: 'LocalPageInfo',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
return new VueApollo({
|
return new VueApollo({
|
||||||
defaultClient,
|
defaultClient,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
query getEnvironmentApp($scope: String) {
|
query getEnvironmentApp($page: Int, $scope: String) {
|
||||||
environmentApp(scope: $scope) @client {
|
environmentApp(page: $page, scope: $scope) @client {
|
||||||
availableCount
|
availableCount
|
||||||
stoppedCount
|
stoppedCount
|
||||||
environments
|
environments
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
query getPageInfo {
|
||||||
|
pageInfo @client {
|
||||||
|
total
|
||||||
|
perPage
|
||||||
|
nextPage
|
||||||
|
previousPage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,15 @@
|
||||||
import axios from '~/lib/utils/axios_utils';
|
import axios from '~/lib/utils/axios_utils';
|
||||||
import { s__ } from '~/locale';
|
import { s__ } from '~/locale';
|
||||||
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
|
import {
|
||||||
|
convertObjectPropsToCamelCase,
|
||||||
|
parseIntPagination,
|
||||||
|
normalizeHeaders,
|
||||||
|
} from '~/lib/utils/common_utils';
|
||||||
|
|
||||||
import pollIntervalQuery from './queries/poll_interval.query.graphql';
|
import pollIntervalQuery from './queries/poll_interval.query.graphql';
|
||||||
import environmentToRollbackQuery from './queries/environment_to_rollback.query.graphql';
|
import environmentToRollbackQuery from './queries/environment_to_rollback.query.graphql';
|
||||||
import environmentToDeleteQuery from './queries/environment_to_delete.query.graphql';
|
import environmentToDeleteQuery from './queries/environment_to_delete.query.graphql';
|
||||||
|
import pageInfoQuery from './queries/page_info.query.graphql';
|
||||||
|
|
||||||
const buildErrors = (errors = []) => ({
|
const buildErrors = (errors = []) => ({
|
||||||
errors,
|
errors,
|
||||||
|
|
@ -21,9 +27,11 @@ const mapEnvironment = (env) => ({
|
||||||
|
|
||||||
export const resolvers = (endpoint) => ({
|
export const resolvers = (endpoint) => ({
|
||||||
Query: {
|
Query: {
|
||||||
environmentApp(_context, { scope }, { cache }) {
|
environmentApp(_context, { page, scope }, { cache }) {
|
||||||
return axios.get(endpoint, { params: { nested: true, scope } }).then((res) => {
|
return axios.get(endpoint, { params: { nested: true, page, scope } }).then((res) => {
|
||||||
const interval = res.headers['poll-interval'];
|
const headers = normalizeHeaders(res.headers);
|
||||||
|
const interval = headers['POLL-INTERVAL'];
|
||||||
|
const pageInfo = { ...parseIntPagination(headers), __typename: 'LocalPageInfo' };
|
||||||
|
|
||||||
if (interval) {
|
if (interval) {
|
||||||
cache.writeQuery({ query: pollIntervalQuery, data: { interval: parseFloat(interval) } });
|
cache.writeQuery({ query: pollIntervalQuery, data: { interval: parseFloat(interval) } });
|
||||||
|
|
@ -31,6 +39,11 @@ export const resolvers = (endpoint) => ({
|
||||||
cache.writeQuery({ query: pollIntervalQuery, data: { interval: undefined } });
|
cache.writeQuery({ query: pollIntervalQuery, data: { interval: undefined } });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cache.writeQuery({
|
||||||
|
query: pageInfoQuery,
|
||||||
|
data: { pageInfo },
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
availableCount: res.data.available_count,
|
availableCount: res.data.available_count,
|
||||||
environments: res.data.environments.map(mapNestedEnvironment),
|
environments: res.data.environments.map(mapNestedEnvironment),
|
||||||
|
|
|
||||||
|
|
@ -55,10 +55,18 @@ type LocalErrors {
|
||||||
errors: [String!]!
|
errors: [String!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LocalPageInfo {
|
||||||
|
total: Int!
|
||||||
|
perPage: Int!
|
||||||
|
nextPage: Int!
|
||||||
|
previousPage: Int!
|
||||||
|
}
|
||||||
|
|
||||||
extend type Query {
|
extend type Query {
|
||||||
environmentApp: LocalEnvironmentApp
|
environmentApp(page: Int, scope: String): LocalEnvironmentApp
|
||||||
folder(environment: NestedLocalEnvironmentInput): LocalEnvironmentFolder
|
folder(environment: NestedLocalEnvironmentInput): LocalEnvironmentFolder
|
||||||
environmentToDelete: LocalEnvironment
|
environmentToDelete: LocalEnvironment
|
||||||
|
pageInfo: LocalPageInfo
|
||||||
environmentToRollback: LocalEnvironment
|
environmentToRollback: LocalEnvironment
|
||||||
isLastDeployment: Boolean
|
isLastDeployment: Boolean
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ export const BV_HIDE_MODAL = 'bv::hide::modal';
|
||||||
export const BV_HIDE_TOOLTIP = 'bv::hide::tooltip';
|
export const BV_HIDE_TOOLTIP = 'bv::hide::tooltip';
|
||||||
export const BV_DROPDOWN_SHOW = 'bv::dropdown::show';
|
export const BV_DROPDOWN_SHOW = 'bv::dropdown::show';
|
||||||
export const BV_DROPDOWN_HIDE = 'bv::dropdown::hide';
|
export const BV_DROPDOWN_HIDE = 'bv::dropdown::hide';
|
||||||
|
export const BV_COLLAPSE_STATE = 'bv::collapse::state';
|
||||||
|
|
||||||
export const DEFAULT_TH_CLASSES =
|
export const DEFAULT_TH_CLASSES =
|
||||||
'gl-bg-transparent! gl-border-b-solid! gl-border-b-gray-100! gl-p-5! gl-border-b-1!';
|
'gl-bg-transparent! gl-border-b-solid! gl-border-b-gray-100! gl-p-5! gl-border-b-1!';
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@
|
||||||
= render 'shared/user_dropdown_instance_review'
|
= render 'shared/user_dropdown_instance_review'
|
||||||
- if Gitlab.com_but_not_canary?
|
- if Gitlab.com_but_not_canary?
|
||||||
%li.d-md-none
|
%li.d-md-none
|
||||||
= link_to _("Switch to GitLab Next"), "https://next.gitlab.com/"
|
= link_to _("Switch to GitLab Next"), Gitlab::Saas.canary_toggle_com_url
|
||||||
|
|
||||||
- if current_user_menu?(:sign_out)
|
- if current_user_menu?(:sign_out)
|
||||||
%li.divider
|
%li.divider
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
%span.logo-text.d-none.d-lg-block.gl-ml-3
|
%span.logo-text.d-none.d-lg-block.gl-ml-3
|
||||||
= logo_text
|
= logo_text
|
||||||
- if Gitlab.com_and_canary?
|
- if Gitlab.com_and_canary?
|
||||||
= link_to 'https://next.gitlab.com', class: 'canary-badge bg-transparent', data: { qa_selector: 'canary_badge_link' }, target: :_blank, rel: :_noopener do
|
= link_to Gitlab::Saas.canary_toggle_com_url, class: 'canary-badge bg-transparent', data: { qa_selector: 'canary_badge_link' }, target: :_blank, rel: 'noopener noreferrer' do
|
||||||
%span.gl-badge.gl-bg-green-500.gl-text-white.gl-rounded-pill.gl-font-weight-bold.gl-py-1
|
%span.gl-badge.gl-bg-green-500.gl-text-white.gl-rounded-pill.gl-font-weight-bold.gl-py-1
|
||||||
= _('Next')
|
= _('Next')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,4 +20,4 @@
|
||||||
= render 'shared/user_dropdown_instance_review'
|
= render 'shared/user_dropdown_instance_review'
|
||||||
- if Gitlab.com_but_not_canary?
|
- if Gitlab.com_but_not_canary?
|
||||||
%li
|
%li
|
||||||
= link_to _("Switch to GitLab Next"), "https://next.gitlab.com/"
|
= link_to _("Switch to GitLab Next"), Gitlab::Saas.canary_toggle_com_url
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,7 @@
|
||||||
.card-header
|
.card-header
|
||||||
%strong
|
%strong
|
||||||
= s_('PrometheusService|Custom metrics')
|
= s_('PrometheusService|Custom metrics')
|
||||||
-# haml-lint:disable NoPlainNodes
|
= gl_badge_tag 0, nil, class: 'js-custom-monitored-count'
|
||||||
%span.badge.badge-pill.js-custom-monitored-count 0
|
|
||||||
-# haml-lint:enable NoPlainNodes
|
|
||||||
= link_to s_('PrometheusService|New metric'), new_project_prometheus_metric_path(project), class: 'btn gl-button btn-confirm gl-ml-auto js-new-metric-button hidden', data: { qa_selector: 'new_metric_button' }
|
= link_to s_('PrometheusService|New metric'), new_project_prometheus_metric_path(project), class: 'btn gl-button btn-confirm gl-ml-auto js-new-metric-button hidden', data: { qa_selector: 'new_metric_button' }
|
||||||
.card-body
|
.card-body
|
||||||
.flash-container.hidden
|
.flash-container.hidden
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
.card-header
|
.card-header
|
||||||
%strong
|
%strong
|
||||||
= s_('PrometheusService|Common metrics')
|
= s_('PrometheusService|Common metrics')
|
||||||
%span.badge.badge-pill.js-monitored-count 0
|
= gl_badge_tag 0, nil, class: 'js-monitored-count'
|
||||||
.card-body
|
.card-body
|
||||||
.loading-metrics.js-loading-metrics
|
.loading-metrics.js-loading-metrics
|
||||||
%p.m-3
|
%p.m-3
|
||||||
|
|
@ -28,7 +28,7 @@
|
||||||
= sprite_icon('chevron-lg-right', css_class: 'panel-toggle js-panel-toggle-right' )
|
= sprite_icon('chevron-lg-right', css_class: 'panel-toggle js-panel-toggle-right' )
|
||||||
= sprite_icon('chevron-lg-down', css_class: 'panel-toggle js-panel-toggle-down hidden' )
|
= sprite_icon('chevron-lg-down', css_class: 'panel-toggle js-panel-toggle-down hidden' )
|
||||||
= s_('PrometheusService|Missing environment variable')
|
= s_('PrometheusService|Missing environment variable')
|
||||||
%span.badge.badge-pill.js-env-var-count 0
|
= gl_badge_tag 0, nil, class: 'js-env-var-count'
|
||||||
.card-body.hidden
|
.card-body.hidden
|
||||||
.flash-container
|
.flash-container
|
||||||
.flash-notice
|
.flash-notice
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,12 @@
|
||||||
- count_badge_classes = 'badge badge-muted badge-pill gl-badge gl-tab-counter-badge sm gl-display-none gl-sm-display-inline-flex'
|
- count_badge_classes = 'gl-display-none gl-sm-display-inline-flex'
|
||||||
|
|
||||||
= gl_tabs_nav( {class: 'gl-border-b-0 gl-flex-grow-1', data: { testid: 'milestones-filter' } } ) do
|
= gl_tabs_nav( {class: 'gl-border-b-0 gl-flex-grow-1', data: { testid: 'milestones-filter' } } ) do
|
||||||
= gl_tab_link_to milestones_filter_path(state: 'opened'), { item_active: params[:state].blank? || params[:state] == 'opened' } do
|
= gl_tab_link_to milestones_filter_path(state: 'opened'), { item_active: params[:state].blank? || params[:state] == 'opened' } do
|
||||||
= _('Open')
|
= _('Open')
|
||||||
%span{ class: count_badge_classes }
|
= gl_tab_counter_badge counts[:opened], { class: count_badge_classes }
|
||||||
= counts[:opened]
|
|
||||||
= gl_tab_link_to milestones_filter_path(state: 'closed', sort: 'due_date_desc'), { item_active: params[:state] == 'closed' } do
|
= gl_tab_link_to milestones_filter_path(state: 'closed', sort: 'due_date_desc'), { item_active: params[:state] == 'closed' } do
|
||||||
= _('Closed')
|
= _('Closed')
|
||||||
%span{ class: count_badge_classes }
|
= gl_tab_counter_badge counts[:closed], { class: count_badge_classes }
|
||||||
= counts[:closed]
|
|
||||||
= gl_tab_link_to milestones_filter_path(state: 'all', sort: 'due_date_desc'), { item_active: params[:state] == 'all' } do
|
= gl_tab_link_to milestones_filter_path(state: 'all', sort: 'due_date_desc'), { item_active: params[:state] == 'all' } do
|
||||||
= _('All')
|
= _('All')
|
||||||
%span{ class: count_badge_classes }
|
= gl_tab_counter_badge counts[:all], { class: count_badge_classes }
|
||||||
= counts[:all]
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class RemoveVulnerabilityFindingLinksAgain < Gitlab::Database::Migration[1.0]
|
||||||
|
BATCH_SIZE = 50_000
|
||||||
|
MIGRATION = 'RemoveVulnerabilityFindingLinks'
|
||||||
|
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
def up
|
||||||
|
queue_background_migration_jobs_by_range_at_intervals(
|
||||||
|
define_batchable_model('vulnerability_finding_links'),
|
||||||
|
MIGRATION,
|
||||||
|
2.minutes,
|
||||||
|
batch_size: BATCH_SIZE
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
# no ops
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
9bbd4c3e396e0de130418e705a370ce629ca507c82fa2ff5bbf085cdf01c2ff3
|
||||||
|
|
@ -35,7 +35,7 @@ verification methods:
|
||||||
| Git | Project Snippets | Geo with Gitaly | Gitaly Checksum |
|
| Git | Project Snippets | Geo with Gitaly | Gitaly Checksum |
|
||||||
| Git | Personal Snippets | Geo with Gitaly | Gitaly Checksum |
|
| Git | Personal Snippets | Geo with Gitaly | Gitaly Checksum |
|
||||||
| Git | Group wiki repository | Geo with Gitaly | _Not implemented_ |
|
| Git | Group wiki repository | Geo with Gitaly | _Not implemented_ |
|
||||||
| Blobs | User uploads _(file system)_ | Geo with API | _Not implemented_ |
|
| Blobs | User uploads _(file system)_ | Geo with API | SHA256 checksum |
|
||||||
| Blobs | User uploads _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
|
| Blobs | User uploads _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
|
||||||
| Blobs | LFS objects _(file system)_ | Geo with API | SHA256 checksum |
|
| Blobs | LFS objects _(file system)_ | Geo with API | SHA256 checksum |
|
||||||
| Blobs | LFS objects _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
|
| Blobs | LFS objects _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
|
||||||
|
|
@ -188,8 +188,8 @@ successfully, you must replicate their data using some other means.
|
||||||
|[Project repository](../../../user/project/repository/) | **Yes** (10.2) | **Yes** (10.7) | No | |
|
|[Project repository](../../../user/project/repository/) | **Yes** (10.2) | **Yes** (10.7) | No | |
|
||||||
|[Project wiki repository](../../../user/project/wiki/) | **Yes** (10.2) | **Yes** (10.7) | No | |
|
|[Project wiki repository](../../../user/project/wiki/) | **Yes** (10.2) | **Yes** (10.7) | No | |
|
||||||
|[Group wiki repository](../../../user/project/wiki/group.md) | [**Yes** (13.10)](https://gitlab.com/gitlab-org/gitlab/-/issues/208147) | No | No | Behind feature flag `geo_group_wiki_repository_replication`, enabled by default. |
|
|[Group wiki repository](../../../user/project/wiki/group.md) | [**Yes** (13.10)](https://gitlab.com/gitlab-org/gitlab/-/issues/208147) | No | No | Behind feature flag `geo_group_wiki_repository_replication`, enabled by default. |
|
||||||
|[Uploads](../../uploads.md) | **Yes** (10.2) | [No](https://gitlab.com/groups/gitlab-org/-/epics/1817) | No | Verified only on transfer or manually using [Integrity Check Rake Task](../../raketasks/check.md) on both sites and comparing the output between them. |
|
|[Uploads](../../uploads.md) | **Yes** (10.2) | **Yes** (14.6) | Via Object Storage provider if supported. Native Geo support (Beta). | Replication is behind the feature flag `geo_upload_replication`, enabled by default. Verification is behind the feature flag `geo_upload_verification` introduced and enabled by default in 14.6. |
|
||||||
|[LFS objects](../../lfs/index.md) | **Yes** (10.2) | **Yes**(14.6) | Via Object Storage provider if supported. Native Geo support (Beta). | GitLab versions 11.11.x and 12.0.x are affected by [a bug that prevents any new LFS objects from replicating](https://gitlab.com/gitlab-org/gitlab/-/issues/32696).<br /><br />Replication is behind the feature flag `geo_lfs_object_replication`, enabled by default. Verification is behind the feature flag `geo_lfs_object_verification` enabled by default in 14.6. |
|
|[LFS objects](../../lfs/index.md) | **Yes** (10.2) | **Yes** (14.6) | Via Object Storage provider if supported. Native Geo support (Beta). | GitLab versions 11.11.x and 12.0.x are affected by [a bug that prevents any new LFS objects from replicating](https://gitlab.com/gitlab-org/gitlab/-/issues/32696).<br /><br />Replication is behind the feature flag `geo_lfs_object_replication`, enabled by default. Verification is behind the feature flag `geo_lfs_object_verification` introduced and enabled by default in 14.6. |
|
||||||
|[Personal snippets](../../../user/snippets.md) | **Yes** (10.2) | **Yes** (10.2) | No | |
|
|[Personal snippets](../../../user/snippets.md) | **Yes** (10.2) | **Yes** (10.2) | No | |
|
||||||
|[Project snippets](../../../user/snippets.md) | **Yes** (10.2) | **Yes** (10.2) | No | |
|
|[Project snippets](../../../user/snippets.md) | **Yes** (10.2) | **Yes** (10.2) | No | |
|
||||||
|[CI job artifacts](../../../ci/pipelines/job_artifacts.md) | **Yes** (10.4) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/8923) | Via Object Storage provider if supported. Native Geo support (Beta). | Verified only manually using [Integrity Check Rake Task](../../raketasks/check.md) on both sites and comparing the output between them. Job logs also verified on transfer. |
|
|[CI job artifacts](../../../ci/pipelines/job_artifacts.md) | **Yes** (10.4) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/8923) | Via Object Storage provider if supported. Native Geo support (Beta). | Verified only manually using [Integrity Check Rake Task](../../raketasks/check.md) on both sites and comparing the output between them. Job logs also verified on transfer. |
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ This document lists the configuration options for your GitLab `.gitlab-ci.yml` f
|
||||||
When you are editing your `.gitlab-ci.yml` file, you can validate it with the
|
When you are editing your `.gitlab-ci.yml` file, you can validate it with the
|
||||||
[CI Lint](../lint.md) tool.
|
[CI Lint](../lint.md) tool.
|
||||||
|
|
||||||
|
If you are editing this page, make sure you follow the [CI/CD YAML reference style guide](../../development/cicd/cicd_reference_documentation_guide.md).
|
||||||
|
|
||||||
## Keywords
|
## Keywords
|
||||||
|
|
||||||
A GitLab CI/CD pipeline configuration includes:
|
A GitLab CI/CD pipeline configuration includes:
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,14 @@ Try to avoid using **above** when referring to an example or table in a document
|
||||||
|
|
||||||
Do not use **above** when referring to versions of the product. Use [**later**](#later) instead.
|
Do not use **above** when referring to versions of the product. Use [**later**](#later) instead.
|
||||||
|
|
||||||
- Do: In GitLab 14.4 and later...
|
Use:
|
||||||
- Do not: In GitLab 14.4 and above...
|
|
||||||
- Do not: In GitLab 14.4 and higher...
|
- In GitLab 14.4 and later...
|
||||||
|
|
||||||
|
Instead of:
|
||||||
|
|
||||||
|
- In GitLab 14.4 and above...
|
||||||
|
- In GitLab 14.4 and higher...
|
||||||
|
|
||||||
## access level
|
## access level
|
||||||
|
|
||||||
|
|
@ -56,9 +61,14 @@ To view the administrator access level, in the GitLab UI, go to the Admin Area a
|
||||||
|
|
||||||
An **administrator** is not a [role](#roles) or [permission](#permissions).
|
An **administrator** is not a [role](#roles) or [permission](#permissions).
|
||||||
|
|
||||||
- Do: To do this thing, you must be an administrator.
|
Use:
|
||||||
- Do: To do this thing, you must have the administrator access level.
|
|
||||||
- Do not: To do this thing, you must have the Admin role.
|
- To do this thing, you must be an administrator.
|
||||||
|
- To do this thing, you must have the administrator access level.
|
||||||
|
|
||||||
|
Instead of:
|
||||||
|
|
||||||
|
- To do this thing, you must have the Admin role.
|
||||||
|
|
||||||
## Admin Area
|
## Admin Area
|
||||||
|
|
||||||
|
|
@ -67,10 +77,16 @@ This area of the UI says **Admin Area** at the top of the page and on the menu.
|
||||||
|
|
||||||
## allow, enable
|
## allow, enable
|
||||||
|
|
||||||
Try to avoid **allow** and **enable**, unless you are talking about security-related features. For example:
|
Try to avoid **allow** and **enable**, unless you are talking about security-related features.
|
||||||
|
|
||||||
- Do: Use this feature to create a pipeline.
|
Use:
|
||||||
- Do not: This feature allows you to create a pipeline.
|
|
||||||
|
- You can add a file to your repository.
|
||||||
|
|
||||||
|
Instead of:
|
||||||
|
|
||||||
|
- This feature allows you to add a file to your repository.
|
||||||
|
- This feature enables users to add files to their repository.
|
||||||
|
|
||||||
This phrasing is more active and is from the user perspective, rather than the person who implemented the feature.
|
This phrasing is more active and is from the user perspective, rather than the person who implemented the feature.
|
||||||
[View details in the Microsoft style guide](https://docs.microsoft.com/en-us/style-guide/a-z-word-list-term-collections/a/allow-allows).
|
[View details in the Microsoft style guide](https://docs.microsoft.com/en-us/style-guide/a-z-word-list-term-collections/a/allow-allows).
|
||||||
|
|
@ -126,8 +142,13 @@ Use **text box** to refer to the UI field. Do not use **field** or **box**. For
|
||||||
|
|
||||||
Don't use a descriptor with **button**.
|
Don't use a descriptor with **button**.
|
||||||
|
|
||||||
- Do: Select **Run pipelines**.
|
Use:
|
||||||
- Do not: Select the **Run pipelines** button.
|
|
||||||
|
- Select **Run pipelines**.
|
||||||
|
|
||||||
|
Instead of:
|
||||||
|
|
||||||
|
- Select the **Run pipelines** button.
|
||||||
|
|
||||||
## cannot, can not
|
## cannot, can not
|
||||||
|
|
||||||
|
|
@ -194,8 +215,8 @@ When writing about the Developer role:
|
||||||
- Do not use the phrase, **if you are a developer** to mean someone who is assigned the Developer
|
- Do not use the phrase, **if you are a developer** to mean someone who is assigned the Developer
|
||||||
role. Instead, write it out. For example, **if you are assigned the Developer role**.
|
role. Instead, write it out. For example, **if you are assigned the Developer role**.
|
||||||
- To describe a situation where the Developer role is the minimum required:
|
- To describe a situation where the Developer role is the minimum required:
|
||||||
- Do: at least the Developer role
|
- Use: at least the Developer role
|
||||||
- Do not: the Developer role or higher
|
- Instead of: the Developer role or higher
|
||||||
|
|
||||||
Do not use **Developer permissions**. A user who is assigned the Developer role has a set of associated permissions.
|
Do not use **Developer permissions**. A user who is assigned the Developer role has a set of associated permissions.
|
||||||
|
|
||||||
|
|
@ -217,8 +238,13 @@ For example:
|
||||||
|
|
||||||
Use **earlier** when talking about version numbers.
|
Use **earlier** when talking about version numbers.
|
||||||
|
|
||||||
- Do: In GitLab 14.1 and earlier.
|
Use:
|
||||||
- Do not: In GitLab 14.1 and lower.
|
|
||||||
|
- In GitLab 14.1 and earlier.
|
||||||
|
|
||||||
|
Instead of:
|
||||||
|
|
||||||
|
- In GitLab 14.1 and lower.
|
||||||
|
|
||||||
## easily
|
## easily
|
||||||
|
|
||||||
|
|
@ -254,8 +280,13 @@ Use lowercase for **epic board**.
|
||||||
Try to avoid **etc.**. Be as specific as you can. Do not use
|
Try to avoid **etc.**. Be as specific as you can. Do not use
|
||||||
[**and so on**](#and-so-on) as a replacement.
|
[**and so on**](#and-so-on) as a replacement.
|
||||||
|
|
||||||
- Do: You can update objects, like merge requests and issues.
|
Use:
|
||||||
- Do not: You can update objects, like merge requests, issues, etc.
|
|
||||||
|
- You can update objects, like merge requests and issues.
|
||||||
|
|
||||||
|
Instead of:
|
||||||
|
|
||||||
|
- You can update objects, like merge requests, issues, etc.
|
||||||
|
|
||||||
## expand
|
## expand
|
||||||
|
|
||||||
|
|
@ -265,8 +296,13 @@ Use **expand** instead of **open** when you are talking about expanding or colla
|
||||||
|
|
||||||
Use **box** instead of **field** or **text box**.
|
Use **box** instead of **field** or **text box**.
|
||||||
|
|
||||||
- Do: In the **Variable name** box, enter `my text`.
|
Use:
|
||||||
- Do not: In the **Variable name** field, enter `my text`.
|
|
||||||
|
- In the **Variable name** box, enter `my text`.
|
||||||
|
|
||||||
|
Instead of:
|
||||||
|
|
||||||
|
- In the **Variable name** field, enter `my text`.
|
||||||
|
|
||||||
However, you can make an exception when you are writing a task and you need to refer to all
|
However, you can make an exception when you are writing a task and you need to refer to all
|
||||||
of the fields at once. For example:
|
of the fields at once. For example:
|
||||||
|
|
@ -320,8 +356,8 @@ When writing about the Guest role:
|
||||||
- Do not use the phrase, **if you are a guest** to mean someone who is assigned the Guest
|
- Do not use the phrase, **if you are a guest** to mean someone who is assigned the Guest
|
||||||
role. Instead, write it out. For example, **if you are assigned the Guest role**.
|
role. Instead, write it out. For example, **if you are assigned the Guest role**.
|
||||||
- To describe a situation where the Guest role is the minimum required:
|
- To describe a situation where the Guest role is the minimum required:
|
||||||
- Do: at least the Guest role
|
- Use: at least the Guest role
|
||||||
- Do not: the Guest role or higher
|
- Instead of: the Guest role or higher
|
||||||
|
|
||||||
Do not use **Guest permissions**. A user who is assigned the Guest role has a set of associated permissions.
|
Do not use **Guest permissions**. A user who is assigned the Guest role has a set of associated permissions.
|
||||||
|
|
||||||
|
|
@ -337,16 +373,26 @@ Do not use **high availability** or **HA**. Instead, direct readers to the GitLa
|
||||||
|
|
||||||
Do not use **higher** when talking about version numbers.
|
Do not use **higher** when talking about version numbers.
|
||||||
|
|
||||||
- Do: In GitLab 14.4 and later...
|
Use:
|
||||||
- Do not: In GitLab 14.4 and higher...
|
|
||||||
- Do not: In GitLab 14.4 and above...
|
- In GitLab 14.4 and later...
|
||||||
|
|
||||||
|
Instead of:
|
||||||
|
|
||||||
|
- In GitLab 14.4 and higher...
|
||||||
|
- In GitLab 14.4 and above...
|
||||||
|
|
||||||
## hit
|
## hit
|
||||||
|
|
||||||
Don't use **hit** to mean **press**.
|
Don't use **hit** to mean **press**.
|
||||||
|
|
||||||
- Do: Press **ENTER**.
|
Use:
|
||||||
- Do not: Hit the **ENTER** button.
|
|
||||||
|
- Press **ENTER**.
|
||||||
|
|
||||||
|
Instead of:
|
||||||
|
|
||||||
|
- Hit the **ENTER** button.
|
||||||
|
|
||||||
## I
|
## I
|
||||||
|
|
||||||
|
|
@ -395,9 +441,14 @@ Do not use:
|
||||||
|
|
||||||
Use **later** when talking about version numbers.
|
Use **later** when talking about version numbers.
|
||||||
|
|
||||||
- Do: In GitLab 14.1 and later...
|
Use:
|
||||||
- Do not: In GitLab 14.1 and higher...
|
|
||||||
- Do not: In GitLab 14.1 and above...
|
- In GitLab 14.1 and later...
|
||||||
|
|
||||||
|
Instead of:
|
||||||
|
|
||||||
|
- In GitLab 14.1 and higher...
|
||||||
|
- In GitLab 14.1 and above...
|
||||||
|
|
||||||
## list
|
## list
|
||||||
|
|
||||||
|
|
@ -412,8 +463,13 @@ Do not use **log in** or **log on**. Use [sign in](#sign-in) instead. If the use
|
||||||
|
|
||||||
Do not use **lower** when talking about version numbers.
|
Do not use **lower** when talking about version numbers.
|
||||||
|
|
||||||
- Do: In GitLab 14.1 and earlier.
|
Use:
|
||||||
- Do not: In GitLab 14.1 and lower.
|
|
||||||
|
- In GitLab 14.1 and earlier.
|
||||||
|
|
||||||
|
Instead of:
|
||||||
|
|
||||||
|
- In GitLab 14.1 and lower.
|
||||||
|
|
||||||
## Maintainer
|
## Maintainer
|
||||||
|
|
||||||
|
|
@ -424,8 +480,8 @@ When writing about the Maintainer role:
|
||||||
- Do not use the phrase, **if you are a maintainer** to mean someone who is assigned the Maintainer
|
- Do not use the phrase, **if you are a maintainer** to mean someone who is assigned the Maintainer
|
||||||
role. Instead, write it out. For example, **if you are assigned the Maintainer role**.
|
role. Instead, write it out. For example, **if you are assigned the Maintainer role**.
|
||||||
- To describe a situation where the Maintainer role is the minimum required:
|
- To describe a situation where the Maintainer role is the minimum required:
|
||||||
- Do: at least the Maintainer role
|
- Use: at least the Maintainer role
|
||||||
- Do not: the Maintainer role or higher
|
- Instead of: the Maintainer role or higher
|
||||||
|
|
||||||
Do not use **Maintainer permissions**. A user who is assigned the Maintainer role has a set of associated permissions.
|
Do not use **Maintainer permissions**. A user who is assigned the Maintainer role has a set of associated permissions.
|
||||||
|
|
||||||
|
|
@ -468,8 +524,14 @@ Do not use **navigate**. Use **go** instead. For example:
|
||||||
|
|
||||||
Try to avoid **needs to**, because it's wordy. Avoid **should** when you can be more specific. If something is required, use **must**.
|
Try to avoid **needs to**, because it's wordy. Avoid **should** when you can be more specific. If something is required, use **must**.
|
||||||
|
|
||||||
- Do: You must set the variable. Or: Set the variable.
|
Use:
|
||||||
- Do not: You need to set the variable.
|
|
||||||
|
- You must set the variable.
|
||||||
|
- Set the variable.
|
||||||
|
|
||||||
|
Instead of:
|
||||||
|
|
||||||
|
- You need to set the variable.
|
||||||
|
|
||||||
**Should** is acceptable for recommended actions or items, or in cases where an event may not
|
**Should** is acceptable for recommended actions or items, or in cases where an event may not
|
||||||
happen. For example:
|
happen. For example:
|
||||||
|
|
@ -483,22 +545,37 @@ happen. For example:
|
||||||
|
|
||||||
Do not use **note that** because it's wordy.
|
Do not use **note that** because it's wordy.
|
||||||
|
|
||||||
- Do: You can change the settings.
|
Use:
|
||||||
- Do not: Note that you can change the settings.
|
|
||||||
|
- You can change the settings.
|
||||||
|
|
||||||
|
Instead of:
|
||||||
|
|
||||||
|
- Note that you can change the settings.
|
||||||
|
|
||||||
## on
|
## on
|
||||||
|
|
||||||
When documenting how to select high-level UI elements, use the word **on**.
|
When documenting how to select high-level UI elements, use the word **on**.
|
||||||
|
|
||||||
- Do: `On the left sidebar...`
|
Use:
|
||||||
|
|
||||||
|
- `On the left sidebar...`
|
||||||
|
|
||||||
|
Instead of:
|
||||||
|
|
||||||
- Do not: `From the left sidebar...` or `In the left sidebar...`
|
- Do not: `From the left sidebar...` or `In the left sidebar...`
|
||||||
|
|
||||||
## once
|
## once
|
||||||
|
|
||||||
The word **once** means **one time**. Don't use it to mean **after** or **when**.
|
The word **once** means **one time**. Don't use it to mean **after** or **when**.
|
||||||
|
|
||||||
- Do: When the process is complete...
|
Use:
|
||||||
- Do not: Once the process is complete...
|
|
||||||
|
- When the process is complete...
|
||||||
|
|
||||||
|
Instead of:
|
||||||
|
|
||||||
|
- Once the process is complete...
|
||||||
|
|
||||||
## only
|
## only
|
||||||
|
|
||||||
|
|
@ -566,8 +643,8 @@ When writing about the Reporter role:
|
||||||
- Do not use the phrase, **if you are a reporter** to mean someone who is assigned the Reporter
|
- Do not use the phrase, **if you are a reporter** to mean someone who is assigned the Reporter
|
||||||
role. Instead, write it out. For example, **if you are assigned the Reporter role**.
|
role. Instead, write it out. For example, **if you are assigned the Reporter role**.
|
||||||
- To describe a situation where the Reporter role is the minimum required:
|
- To describe a situation where the Reporter role is the minimum required:
|
||||||
- Do: at least the Reporter role
|
- Use: at least the Reporter role
|
||||||
- Do not: the Reporter role or higher
|
- Instead of: the Reporter role or higher
|
||||||
|
|
||||||
Do not use **Reporter permissions**. A user who is assigned the Reporter role has a set of associated permissions.
|
Do not use **Reporter permissions**. A user who is assigned the Reporter role has a set of associated permissions.
|
||||||
|
|
||||||
|
|
@ -589,8 +666,13 @@ Use lowercase for **runners**. These are the agents that run CI/CD jobs. See als
|
||||||
|
|
||||||
Do not use **(s)** to make a word optionally plural. It can slow down comprehension. For example:
|
Do not use **(s)** to make a word optionally plural. It can slow down comprehension. For example:
|
||||||
|
|
||||||
- Do: Select the jobs you want.
|
Use:
|
||||||
- Do not: Select the job(s) you want.
|
|
||||||
|
- Select the jobs you want.
|
||||||
|
|
||||||
|
Instead of:
|
||||||
|
|
||||||
|
- Select the job(s) you want.
|
||||||
|
|
||||||
If you can select multiples of something, then write the word as plural.
|
If you can select multiples of something, then write the word as plural.
|
||||||
|
|
||||||
|
|
@ -612,7 +694,12 @@ into separate areas, refer to these areas as sections.
|
||||||
We often think of expandable/collapsible areas as **sections**. When you refer to expanding
|
We often think of expandable/collapsible areas as **sections**. When you refer to expanding
|
||||||
or collapsing a section, don't include the word **section**.
|
or collapsing a section, don't include the word **section**.
|
||||||
|
|
||||||
- Do: Expand **Auto DevOps**.
|
Use:
|
||||||
|
|
||||||
|
- Expand **Auto DevOps**.
|
||||||
|
|
||||||
|
Instead of:
|
||||||
|
|
||||||
- Do not: Expand the **Auto DevOps** section.
|
- Do not: Expand the **Auto DevOps** section.
|
||||||
|
|
||||||
## select
|
## select
|
||||||
|
|
@ -645,8 +732,13 @@ Do not use **simply** or **simple**. If the user doesn't find the process to be
|
||||||
|
|
||||||
The word **since** indicates a timeframe. For example, **Since 1984, Bon Jovi has existed**. Don't use **since** to mean **because**.
|
The word **since** indicates a timeframe. For example, **Since 1984, Bon Jovi has existed**. Don't use **since** to mean **because**.
|
||||||
|
|
||||||
- Do: Because you have the Developer role, you can delete the widget.
|
Use:
|
||||||
- Do not: Since you have the Developer role, you can delete the widget.
|
|
||||||
|
- Because you have the Developer role, you can delete the widget.
|
||||||
|
|
||||||
|
Instead of:
|
||||||
|
|
||||||
|
- Since you have the Developer role, you can delete the widget.
|
||||||
|
|
||||||
## slashes
|
## slashes
|
||||||
|
|
||||||
|
|
@ -664,8 +756,13 @@ Use **subgroup** (no hyphen) instead of **sub-group**. ([Vale](../testing.md#val
|
||||||
|
|
||||||
Do not use **that** when describing a noun. For example:
|
Do not use **that** when describing a noun. For example:
|
||||||
|
|
||||||
- Do: The file you save...
|
Use:
|
||||||
- Do not: The file **that** you save...
|
|
||||||
|
- The file you save...
|
||||||
|
|
||||||
|
Instead of:
|
||||||
|
|
||||||
|
- The file **that** you save...
|
||||||
|
|
||||||
See also [this, these, that, those](#this-these-that-those).
|
See also [this, these, that, those](#this-these-that-those).
|
||||||
|
|
||||||
|
|
@ -684,8 +781,13 @@ Use **text box** instead of **field** or **box** when referring to the UI elemen
|
||||||
|
|
||||||
Try to avoid **there is** and **there are**. These phrases hide the subject.
|
Try to avoid **there is** and **there are**. These phrases hide the subject.
|
||||||
|
|
||||||
- Do: The bucket has holes.
|
Use:
|
||||||
- Do not: There are holes in the bucket.
|
|
||||||
|
- The bucket has holes.
|
||||||
|
|
||||||
|
Instead of:
|
||||||
|
|
||||||
|
- There are holes in the bucket.
|
||||||
|
|
||||||
## they
|
## they
|
||||||
|
|
||||||
|
|
@ -697,17 +799,17 @@ a gender-neutral pronoun.
|
||||||
|
|
||||||
Always follow these words with a noun. For example:
|
Always follow these words with a noun. For example:
|
||||||
|
|
||||||
- Do: **This setting** improves performance.
|
- Use: **This setting** improves performance.
|
||||||
- Do not: **This** improves performance.
|
- Instead of: **This** improves performance.
|
||||||
|
|
||||||
- Do: **These pants** are the best.
|
- Use: **These pants** are the best.
|
||||||
- Do not: **These** are the best.
|
- Instead of: **These** are the best.
|
||||||
|
|
||||||
- Do: **That droid** is the one you are looking for.
|
- Use: **That droid** is the one you are looking for.
|
||||||
- Do not: **That** is the one you are looking for.
|
- Instead of: **That** is the one you are looking for.
|
||||||
|
|
||||||
- Do: **Those settings** need to be configured. (Or even better, **Configure those settings.**)
|
- Use: **Those settings** need to be configured. (Or even better, **Configure those settings.**)
|
||||||
- Do not: **Those** need to be configured.
|
- Instead of: **Those** need to be configured.
|
||||||
|
|
||||||
## to-do item
|
## to-do item
|
||||||
|
|
||||||
|
|
@ -736,8 +838,13 @@ Do not use **useful**. If the user doesn't find the process to be useful, we los
|
||||||
When possible, address the reader directly, instead of calling them **users**.
|
When possible, address the reader directly, instead of calling them **users**.
|
||||||
Use the [second person](#you-your-yours), **you**, instead.
|
Use the [second person](#you-your-yours), **you**, instead.
|
||||||
|
|
||||||
- Do: You can configure a pipeline.
|
Use:
|
||||||
- Do not: Users can configure a pipeline.
|
|
||||||
|
- You can configure a pipeline.
|
||||||
|
|
||||||
|
Instead of:
|
||||||
|
|
||||||
|
- Users can configure a pipeline.
|
||||||
|
|
||||||
## utilize
|
## utilize
|
||||||
|
|
||||||
|
|
@ -756,8 +863,13 @@ Do not use Latin abbreviations. Use **with**, **through**, or **by using** inste
|
||||||
|
|
||||||
Try to avoid **we** and focus instead on how the user can accomplish something in GitLab.
|
Try to avoid **we** and focus instead on how the user can accomplish something in GitLab.
|
||||||
|
|
||||||
- Do: Use widgets when you have work you want to organize.
|
Use:
|
||||||
- Do not: We created a feature for you to add widgets.
|
|
||||||
|
- Use widgets when you have work you want to organize.
|
||||||
|
|
||||||
|
Instead of:
|
||||||
|
|
||||||
|
- We created a feature for you to add widgets.
|
||||||
|
|
||||||
One exception: You can use **we recommend** instead of **it is recommended** or **GitLab recommends**. ([Vale](../testing.md#vale) rule: [`SubstitutionSuggestions.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/SubstitutionSuggestions.yml))
|
One exception: You can use **we recommend** instead of **it is recommended** or **GitLab recommends**. ([Vale](../testing.md#vale) rule: [`SubstitutionSuggestions.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/SubstitutionSuggestions.yml))
|
||||||
|
|
||||||
|
|
@ -770,8 +882,13 @@ Do not use **whitelist**. Another option is **allowlist**. ([Vale](../testing.md
|
||||||
Use **you**, **your**, and **yours** instead of [**the user** and **the user's**](#user-users).
|
Use **you**, **your**, and **yours** instead of [**the user** and **the user's**](#user-users).
|
||||||
Documentation should be from the [point of view](https://design.gitlab.com/content/voice-tone#point-of-view) of the reader.
|
Documentation should be from the [point of view](https://design.gitlab.com/content/voice-tone#point-of-view) of the reader.
|
||||||
|
|
||||||
- Do: You can configure a pipeline.
|
Use:
|
||||||
- Do not: Users can configure a pipeline.
|
|
||||||
|
- You can configure a pipeline.
|
||||||
|
|
||||||
|
Instead of:
|
||||||
|
|
||||||
|
- Users can configure a pipeline.
|
||||||
|
|
||||||
<!-- vale on -->
|
<!-- vale on -->
|
||||||
<!-- markdownlint-enable -->
|
<!-- markdownlint-enable -->
|
||||||
|
|
|
||||||
|
|
@ -492,10 +492,13 @@ image::screenshot.png[block image,800,450]
|
||||||
Press image:reload.svg[reload,16,opts=interactive] to reload the page.
|
Press image:reload.svg[reload,16,opts=interactive] to reload the page.
|
||||||
|
|
||||||
video::movie.mp4[width=640,start=60,end=140,options=autoplay]
|
video::movie.mp4[width=640,start=60,end=140,options=autoplay]
|
||||||
|
```
|
||||||
|
|
||||||
video::aHjpOzsQ9YI[youtube]
|
GitLab does not support embedding YouTube and Vimeo videos in AsciiDoc content.
|
||||||
|
Use a standard AsciiDoc link:
|
||||||
|
|
||||||
video::300817511[vimeo]
|
```plaintext
|
||||||
|
https://www.youtube.com/watch?v=BlaZ65-b7y0[Link text for the video]
|
||||||
```
|
```
|
||||||
|
|
||||||
### Breaks
|
### Breaks
|
||||||
|
|
|
||||||
|
|
@ -344,6 +344,11 @@ Here is an example of milestones with no releases, one release, and two releases
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
NOTE:
|
||||||
|
A subgroup's project releases cannot be associated with a supergroup's milestone. To learn
|
||||||
|
more, read issue #328054,
|
||||||
|
[Releases cannot be associated with a supergroup milestone](https://gitlab.com/gitlab-org/gitlab/-/issues/328054).
|
||||||
|
|
||||||
## Get notified when a release is created
|
## Get notified when a release is created
|
||||||
|
|
||||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/26001) in GitLab 12.4.
|
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/26001) in GitLab 12.4.
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,9 @@ you can choose from:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
When filtering by a deploy date, you must enter the date manually. Deploy dates
|
When filtering by `Deployed-before` or `Deployed-after`, the date refers to when
|
||||||
|
the deployment to an environment (triggered by the merge commit) completed successfully.
|
||||||
|
You must enter the deploy date manually. Deploy dates
|
||||||
use the format `YYYY-MM-DD`, and must be quoted if you wish to specify
|
use the format `YYYY-MM-DD`, and must be quoted if you wish to specify
|
||||||
both a date and time (`"YYYY-MM-DD HH:MM"`):
|
both a date and time (`"YYYY-MM-DD HH:MM"`):
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,11 @@ module Gitlab
|
||||||
@result_dir = result_dir
|
@result_dir = result_dir
|
||||||
end
|
end
|
||||||
|
|
||||||
def observe(version:, name:, &block)
|
def observe(version:, name:, connection:, &block)
|
||||||
observation = Observation.new(version, name)
|
observation = Observation.new(version, name)
|
||||||
observation.success = true
|
observation.success = true
|
||||||
|
|
||||||
observers = observer_classes.map { |c| c.new(observation, @result_dir) }
|
observers = observer_classes.map { |c| c.new(observation, @result_dir, connection) }
|
||||||
|
|
||||||
exception = nil
|
exception = nil
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ module Gitlab
|
||||||
class MigrationObserver
|
class MigrationObserver
|
||||||
attr_reader :connection, :observation, :output_dir
|
attr_reader :connection, :observation, :output_dir
|
||||||
|
|
||||||
def initialize(observation, output_dir)
|
def initialize(observation, output_dir, connection)
|
||||||
@connection = ActiveRecord::Base.connection
|
@connection = connection
|
||||||
@observation = observation
|
@observation = observation
|
||||||
@output_dir = output_dir
|
@output_dir = output_dir
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ module Gitlab
|
||||||
instrumentation = Instrumentation.new(result_dir: result_dir)
|
instrumentation = Instrumentation.new(result_dir: result_dir)
|
||||||
|
|
||||||
sorted_migrations.each do |migration|
|
sorted_migrations.each do |migration|
|
||||||
instrumentation.observe(version: migration.version, name: migration.name) do
|
instrumentation.observe(version: migration.version, name: migration.name, connection: ActiveRecord::Migration.connection) do
|
||||||
ActiveRecord::Migrator.new(direction, migration_context.migrations, migration_context.schema_migration, migration.version).run
|
ActiveRecord::Migrator.new(direction, migration_context.migrations, migration_context.schema_migration, migration.version).run
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,10 @@ module Gitlab
|
||||||
'https://staging.gitlab.com'
|
'https://staging.gitlab.com'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.canary_toggle_com_url
|
||||||
|
'https://next.gitlab.com'
|
||||||
|
end
|
||||||
|
|
||||||
def self.subdomain_regex
|
def self.subdomain_regex
|
||||||
%r{\Ahttps://[a-z0-9]+\.gitlab\.com\z}.freeze
|
%r{\Ahttps://[a-z0-9]+\.gitlab\.com\z}.freeze
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -16406,6 +16406,9 @@ msgstr ""
|
||||||
msgid "Go to next page"
|
msgid "Go to next page"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Go to page %{page}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Go to parent"
|
msgid "Go to parent"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import environmentToRollback from '~/environments/graphql/queries/environment_to
|
||||||
import environmentToDelete from '~/environments/graphql/queries/environment_to_delete.query.graphql';
|
import environmentToDelete from '~/environments/graphql/queries/environment_to_delete.query.graphql';
|
||||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||||
import pollIntervalQuery from '~/environments/graphql/queries/poll_interval.query.graphql';
|
import pollIntervalQuery from '~/environments/graphql/queries/poll_interval.query.graphql';
|
||||||
|
import pageInfoQuery from '~/environments/graphql/queries/page_info.query.graphql';
|
||||||
import { TEST_HOST } from 'helpers/test_constants';
|
import { TEST_HOST } from 'helpers/test_constants';
|
||||||
import {
|
import {
|
||||||
environmentsApp,
|
environmentsApp,
|
||||||
|
|
@ -37,9 +38,11 @@ describe('~/frontend/environments/graphql/resolvers', () => {
|
||||||
it('should fetch environments and map them to frontend data', async () => {
|
it('should fetch environments and map them to frontend data', async () => {
|
||||||
const cache = { writeQuery: jest.fn() };
|
const cache = { writeQuery: jest.fn() };
|
||||||
const scope = 'available';
|
const scope = 'available';
|
||||||
mock.onGet(ENDPOINT, { params: { nested: true, scope } }).reply(200, environmentsApp, {});
|
mock
|
||||||
|
.onGet(ENDPOINT, { params: { nested: true, scope, page: 1 } })
|
||||||
|
.reply(200, environmentsApp, {});
|
||||||
|
|
||||||
const app = await mockResolvers.Query.environmentApp(null, { scope }, { cache });
|
const app = await mockResolvers.Query.environmentApp(null, { scope, page: 1 }, { cache });
|
||||||
expect(app).toEqual(resolvedEnvironmentsApp);
|
expect(app).toEqual(resolvedEnvironmentsApp);
|
||||||
expect(cache.writeQuery).toHaveBeenCalledWith({
|
expect(cache.writeQuery).toHaveBeenCalledWith({
|
||||||
query: pollIntervalQuery,
|
query: pollIntervalQuery,
|
||||||
|
|
@ -49,14 +52,70 @@ describe('~/frontend/environments/graphql/resolvers', () => {
|
||||||
it('should set the poll interval when there is one', async () => {
|
it('should set the poll interval when there is one', async () => {
|
||||||
const cache = { writeQuery: jest.fn() };
|
const cache = { writeQuery: jest.fn() };
|
||||||
const scope = 'stopped';
|
const scope = 'stopped';
|
||||||
|
const interval = 3000;
|
||||||
mock
|
mock
|
||||||
.onGet(ENDPOINT, { params: { nested: true, scope } })
|
.onGet(ENDPOINT, { params: { nested: true, scope, page: 1 } })
|
||||||
.reply(200, environmentsApp, { 'poll-interval': 3000 });
|
.reply(200, environmentsApp, {
|
||||||
|
'poll-interval': interval,
|
||||||
|
});
|
||||||
|
|
||||||
await mockResolvers.Query.environmentApp(null, { scope }, { cache });
|
await mockResolvers.Query.environmentApp(null, { scope, page: 1 }, { cache });
|
||||||
expect(cache.writeQuery).toHaveBeenCalledWith({
|
expect(cache.writeQuery).toHaveBeenCalledWith({
|
||||||
query: pollIntervalQuery,
|
query: pollIntervalQuery,
|
||||||
data: { interval: 3000 },
|
data: { interval },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('should set page info if there is any', async () => {
|
||||||
|
const cache = { writeQuery: jest.fn() };
|
||||||
|
const scope = 'stopped';
|
||||||
|
mock
|
||||||
|
.onGet(ENDPOINT, { params: { nested: true, scope, page: 1 } })
|
||||||
|
.reply(200, environmentsApp, {
|
||||||
|
'x-next-page': '2',
|
||||||
|
'x-page': '1',
|
||||||
|
'X-Per-Page': '2',
|
||||||
|
'X-Prev-Page': '',
|
||||||
|
'X-TOTAL': '37',
|
||||||
|
'X-Total-Pages': '5',
|
||||||
|
});
|
||||||
|
|
||||||
|
await mockResolvers.Query.environmentApp(null, { scope, page: 1 }, { cache });
|
||||||
|
expect(cache.writeQuery).toHaveBeenCalledWith({
|
||||||
|
query: pageInfoQuery,
|
||||||
|
data: {
|
||||||
|
pageInfo: {
|
||||||
|
total: 37,
|
||||||
|
perPage: 2,
|
||||||
|
previousPage: NaN,
|
||||||
|
totalPages: 5,
|
||||||
|
nextPage: 2,
|
||||||
|
page: 1,
|
||||||
|
__typename: 'LocalPageInfo',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('should not set page info if there is none', async () => {
|
||||||
|
const cache = { writeQuery: jest.fn() };
|
||||||
|
const scope = 'stopped';
|
||||||
|
mock
|
||||||
|
.onGet(ENDPOINT, { params: { nested: true, scope, page: 1 } })
|
||||||
|
.reply(200, environmentsApp, {});
|
||||||
|
|
||||||
|
await mockResolvers.Query.environmentApp(null, { scope, page: 1 }, { cache });
|
||||||
|
expect(cache.writeQuery).toHaveBeenCalledWith({
|
||||||
|
query: pageInfoQuery,
|
||||||
|
data: {
|
||||||
|
pageInfo: {
|
||||||
|
__typename: 'LocalPageInfo',
|
||||||
|
nextPage: NaN,
|
||||||
|
page: NaN,
|
||||||
|
perPage: NaN,
|
||||||
|
previousPage: NaN,
|
||||||
|
total: NaN,
|
||||||
|
totalPages: NaN,
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
import Vue, { nextTick } from 'vue';
|
import Vue, { nextTick } from 'vue';
|
||||||
import VueApollo from 'vue-apollo';
|
import VueApollo from 'vue-apollo';
|
||||||
|
import { GlPagination } from '@gitlab/ui';
|
||||||
import { mountExtended } from 'helpers/vue_test_utils_helper';
|
import { mountExtended } from 'helpers/vue_test_utils_helper';
|
||||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||||
import waitForPromises from 'helpers/wait_for_promises';
|
import waitForPromises from 'helpers/wait_for_promises';
|
||||||
import { __, s__ } from '~/locale';
|
import setWindowLocation from 'helpers/set_window_location_helper';
|
||||||
|
import { sprintf, __, s__ } from '~/locale';
|
||||||
import EnvironmentsApp from '~/environments/components/new_environments_app.vue';
|
import EnvironmentsApp from '~/environments/components/new_environments_app.vue';
|
||||||
import EnvironmentsFolder from '~/environments/components/new_environment_folder.vue';
|
import EnvironmentsFolder from '~/environments/components/new_environment_folder.vue';
|
||||||
import { resolvedEnvironmentsApp, resolvedFolder } from './graphql/mock_data';
|
import { resolvedEnvironmentsApp, resolvedFolder } from './graphql/mock_data';
|
||||||
|
|
@ -14,12 +16,14 @@ describe('~/environments/components/new_environments_app.vue', () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
let environmentAppMock;
|
let environmentAppMock;
|
||||||
let environmentFolderMock;
|
let environmentFolderMock;
|
||||||
|
let paginationMock;
|
||||||
|
|
||||||
const createApolloProvider = () => {
|
const createApolloProvider = () => {
|
||||||
const mockResolvers = {
|
const mockResolvers = {
|
||||||
Query: {
|
Query: {
|
||||||
environmentApp: environmentAppMock,
|
environmentApp: environmentAppMock,
|
||||||
folder: environmentFolderMock,
|
folder: environmentFolderMock,
|
||||||
|
pageInfo: paginationMock,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -37,9 +41,23 @@ describe('~/environments/components/new_environments_app.vue', () => {
|
||||||
apolloProvider,
|
apolloProvider,
|
||||||
});
|
});
|
||||||
|
|
||||||
const createWrapperWithMocked = async ({ provide = {}, environmentsApp, folder }) => {
|
const createWrapperWithMocked = async ({
|
||||||
|
provide = {},
|
||||||
|
environmentsApp,
|
||||||
|
folder,
|
||||||
|
pageInfo = {
|
||||||
|
total: 20,
|
||||||
|
perPage: 5,
|
||||||
|
nextPage: 3,
|
||||||
|
page: 2,
|
||||||
|
previousPage: 1,
|
||||||
|
__typename: 'LocalPageInfo',
|
||||||
|
},
|
||||||
|
}) => {
|
||||||
|
setWindowLocation('?scope=available&page=2');
|
||||||
environmentAppMock.mockReturnValue(environmentsApp);
|
environmentAppMock.mockReturnValue(environmentsApp);
|
||||||
environmentFolderMock.mockReturnValue(folder);
|
environmentFolderMock.mockReturnValue(folder);
|
||||||
|
paginationMock.mockReturnValue(pageInfo);
|
||||||
const apolloProvider = createApolloProvider();
|
const apolloProvider = createApolloProvider();
|
||||||
wrapper = createWrapper({ apolloProvider, provide });
|
wrapper = createWrapper({ apolloProvider, provide });
|
||||||
|
|
||||||
|
|
@ -50,6 +68,7 @@ describe('~/environments/components/new_environments_app.vue', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
environmentAppMock = jest.fn();
|
environmentAppMock = jest.fn();
|
||||||
environmentFolderMock = jest.fn();
|
environmentFolderMock = jest.fn();
|
||||||
|
paginationMock = jest.fn();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
|
@ -118,6 +137,7 @@ describe('~/environments/components/new_environments_app.vue', () => {
|
||||||
expect(button.exists()).toBe(false);
|
expect(button.exists()).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('tabs', () => {
|
||||||
it('should show tabs for available and stopped environmets', async () => {
|
it('should show tabs for available and stopped environmets', async () => {
|
||||||
await createWrapperWithMocked({
|
await createWrapperWithMocked({
|
||||||
environmentsApp: resolvedEnvironmentsApp,
|
environmentsApp: resolvedEnvironmentsApp,
|
||||||
|
|
@ -133,13 +153,10 @@ describe('~/environments/components/new_environments_app.vue', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should change the requested scope on tab change', async () => {
|
it('should change the requested scope on tab change', async () => {
|
||||||
environmentAppMock.mockReturnValue(resolvedEnvironmentsApp);
|
await createWrapperWithMocked({
|
||||||
environmentFolderMock.mockReturnValue(resolvedFolder);
|
environmentsApp: resolvedEnvironmentsApp,
|
||||||
const apolloProvider = createApolloProvider();
|
folder: resolvedFolder,
|
||||||
wrapper = createWrapper({ apolloProvider });
|
});
|
||||||
|
|
||||||
await waitForPromises();
|
|
||||||
await nextTick();
|
|
||||||
const stopped = wrapper.findByRole('tab', {
|
const stopped = wrapper.findByRole('tab', {
|
||||||
name: `${__('Stopped')} ${resolvedEnvironmentsApp.stoppedCount}`,
|
name: `${__('Stopped')} ${resolvedEnvironmentsApp.stoppedCount}`,
|
||||||
});
|
});
|
||||||
|
|
@ -151,9 +168,104 @@ describe('~/environments/components/new_environments_app.vue', () => {
|
||||||
|
|
||||||
expect(environmentAppMock).toHaveBeenCalledWith(
|
expect(environmentAppMock).toHaveBeenCalledWith(
|
||||||
expect.anything(),
|
expect.anything(),
|
||||||
{ scope: 'stopped' },
|
expect.objectContaining({ scope: 'stopped' }),
|
||||||
expect.anything(),
|
expect.anything(),
|
||||||
expect.anything(),
|
expect.anything(),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('pagination', () => {
|
||||||
|
it('should sync page from query params on load', async () => {
|
||||||
|
await createWrapperWithMocked({
|
||||||
|
environmentsApp: resolvedEnvironmentsApp,
|
||||||
|
folder: resolvedFolder,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper.findComponent(GlPagination).props('value')).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should change the requested page on next page click', async () => {
|
||||||
|
await createWrapperWithMocked({
|
||||||
|
environmentsApp: resolvedEnvironmentsApp,
|
||||||
|
folder: resolvedFolder,
|
||||||
|
});
|
||||||
|
const next = wrapper.findByRole('link', {
|
||||||
|
name: __('Go to next page'),
|
||||||
|
});
|
||||||
|
|
||||||
|
next.trigger('click');
|
||||||
|
|
||||||
|
await nextTick();
|
||||||
|
await waitForPromises();
|
||||||
|
|
||||||
|
expect(environmentAppMock).toHaveBeenCalledWith(
|
||||||
|
expect.anything(),
|
||||||
|
expect.objectContaining({ page: 3 }),
|
||||||
|
expect.anything(),
|
||||||
|
expect.anything(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should change the requested page on previous page click', async () => {
|
||||||
|
await createWrapperWithMocked({
|
||||||
|
environmentsApp: resolvedEnvironmentsApp,
|
||||||
|
folder: resolvedFolder,
|
||||||
|
});
|
||||||
|
const prev = wrapper.findByRole('link', {
|
||||||
|
name: __('Go to previous page'),
|
||||||
|
});
|
||||||
|
|
||||||
|
prev.trigger('click');
|
||||||
|
|
||||||
|
await nextTick();
|
||||||
|
await waitForPromises();
|
||||||
|
|
||||||
|
expect(environmentAppMock).toHaveBeenCalledWith(
|
||||||
|
expect.anything(),
|
||||||
|
expect.objectContaining({ page: 1 }),
|
||||||
|
expect.anything(),
|
||||||
|
expect.anything(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should change the requested page on specific page click', async () => {
|
||||||
|
await createWrapperWithMocked({
|
||||||
|
environmentsApp: resolvedEnvironmentsApp,
|
||||||
|
folder: resolvedFolder,
|
||||||
|
});
|
||||||
|
|
||||||
|
const page = 1;
|
||||||
|
const pageButton = wrapper.findByRole('link', {
|
||||||
|
name: sprintf(__('Go to page %{page}'), { page }),
|
||||||
|
});
|
||||||
|
|
||||||
|
pageButton.trigger('click');
|
||||||
|
|
||||||
|
await nextTick();
|
||||||
|
await waitForPromises();
|
||||||
|
|
||||||
|
expect(environmentAppMock).toHaveBeenCalledWith(
|
||||||
|
expect.anything(),
|
||||||
|
expect.objectContaining({ page }),
|
||||||
|
expect.anything(),
|
||||||
|
expect.anything(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should sync the query params to the new page', async () => {
|
||||||
|
await createWrapperWithMocked({
|
||||||
|
environmentsApp: resolvedEnvironmentsApp,
|
||||||
|
folder: resolvedFolder,
|
||||||
|
});
|
||||||
|
const next = wrapper.findByRole('link', {
|
||||||
|
name: __('Go to next page'),
|
||||||
|
});
|
||||||
|
|
||||||
|
next.trigger('click');
|
||||||
|
|
||||||
|
await nextTick();
|
||||||
|
expect(window.location.search).toBe('?scope=available&page=3');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ require 'spec_helper'
|
||||||
|
|
||||||
RSpec.describe Gitlab::Database::Migrations::Instrumentation do
|
RSpec.describe Gitlab::Database::Migrations::Instrumentation do
|
||||||
let(:result_dir) { Dir.mktmpdir }
|
let(:result_dir) { Dir.mktmpdir }
|
||||||
|
let(:connection) { ActiveRecord::Migration.connection }
|
||||||
|
|
||||||
after do
|
after do
|
||||||
FileUtils.rm_rf(result_dir)
|
FileUtils.rm_rf(result_dir)
|
||||||
|
|
@ -14,11 +15,11 @@ RSpec.describe Gitlab::Database::Migrations::Instrumentation do
|
||||||
let(:migration_version) { '12345' }
|
let(:migration_version) { '12345' }
|
||||||
|
|
||||||
it 'executes the given block' do
|
it 'executes the given block' do
|
||||||
expect { |b| subject.observe(version: migration_version, name: migration_name, &b) }.to yield_control
|
expect { |b| subject.observe(version: migration_version, name: migration_name, connection: connection, &b) }.to yield_control
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'behavior with observers' do
|
context 'behavior with observers' do
|
||||||
subject { described_class.new(observer_classes: [Gitlab::Database::Migrations::Observers::MigrationObserver], result_dir: result_dir).observe(version: migration_version, name: migration_name) {} }
|
subject { described_class.new(observer_classes: [Gitlab::Database::Migrations::Observers::MigrationObserver], result_dir: result_dir).observe(version: migration_version, name: migration_name, connection: connection) {} }
|
||||||
|
|
||||||
let(:observer) { instance_double('Gitlab::Database::Migrations::Observers::MigrationObserver', before: nil, after: nil, record: nil) }
|
let(:observer) { instance_double('Gitlab::Database::Migrations::Observers::MigrationObserver', before: nil, after: nil, record: nil) }
|
||||||
|
|
||||||
|
|
@ -29,7 +30,7 @@ RSpec.describe Gitlab::Database::Migrations::Instrumentation do
|
||||||
it 'instantiates observer with observation' do
|
it 'instantiates observer with observation' do
|
||||||
expect(Gitlab::Database::Migrations::Observers::MigrationObserver)
|
expect(Gitlab::Database::Migrations::Observers::MigrationObserver)
|
||||||
.to receive(:new)
|
.to receive(:new)
|
||||||
.with(instance_of(Gitlab::Database::Migrations::Observation), anything) { |observation| expect(observation.version).to eq(migration_version) }
|
.with(instance_of(Gitlab::Database::Migrations::Observation), anything, connection) { |observation| expect(observation.version).to eq(migration_version) }
|
||||||
.and_return(observer)
|
.and_return(observer)
|
||||||
|
|
||||||
subject
|
subject
|
||||||
|
|
@ -63,7 +64,7 @@ RSpec.describe Gitlab::Database::Migrations::Instrumentation do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'on successful execution' do
|
context 'on successful execution' do
|
||||||
subject { described_class.new(result_dir: result_dir).observe(version: migration_version, name: migration_name) {} }
|
subject { described_class.new(result_dir: result_dir).observe(version: migration_version, name: migration_name, connection: connection) {} }
|
||||||
|
|
||||||
it 'records walltime' do
|
it 'records walltime' do
|
||||||
expect(subject.walltime).not_to be_nil
|
expect(subject.walltime).not_to be_nil
|
||||||
|
|
@ -83,7 +84,7 @@ RSpec.describe Gitlab::Database::Migrations::Instrumentation do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'upon failure' do
|
context 'upon failure' do
|
||||||
subject { described_class.new(result_dir: result_dir).observe(version: migration_version, name: migration_name) { raise 'something went wrong' } }
|
subject { described_class.new(result_dir: result_dir).observe(version: migration_version, name: migration_name, connection: connection) { raise 'something went wrong' } }
|
||||||
|
|
||||||
it 'raises the exception' do
|
it 'raises the exception' do
|
||||||
expect { subject }.to raise_error(/something went wrong/)
|
expect { subject }.to raise_error(/something went wrong/)
|
||||||
|
|
@ -93,7 +94,7 @@ RSpec.describe Gitlab::Database::Migrations::Instrumentation do
|
||||||
subject { instance.observations.first }
|
subject { instance.observations.first }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
instance.observe(version: migration_version, name: migration_name) { raise 'something went wrong' }
|
instance.observe(version: migration_version, name: migration_name, connection: connection) { raise 'something went wrong' }
|
||||||
rescue StandardError
|
rescue StandardError
|
||||||
# ignore
|
# ignore
|
||||||
end
|
end
|
||||||
|
|
@ -125,8 +126,8 @@ RSpec.describe Gitlab::Database::Migrations::Instrumentation do
|
||||||
let(:migration2) { double('migration2', call: nil) }
|
let(:migration2) { double('migration2', call: nil) }
|
||||||
|
|
||||||
it 'records observations for all migrations' do
|
it 'records observations for all migrations' do
|
||||||
subject.observe(version: migration_version, name: migration_name) {}
|
subject.observe(version: migration_version, name: migration_name, connection: connection) {}
|
||||||
subject.observe(version: migration_version, name: migration_name) { raise 'something went wrong' } rescue nil
|
subject.observe(version: migration_version, name: migration_name, connection: connection) { raise 'something went wrong' } rescue nil
|
||||||
|
|
||||||
expect(subject.observations.size).to eq(2)
|
expect(subject.observations.size).to eq(2)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
RSpec.describe Gitlab::Database::Migrations::Observers::QueryDetails do
|
RSpec.describe Gitlab::Database::Migrations::Observers::QueryDetails do
|
||||||
subject { described_class.new(observation, directory_path) }
|
subject { described_class.new(observation, directory_path, connection) }
|
||||||
|
|
||||||
|
let(:connection) { ActiveRecord::Migration.connection }
|
||||||
let(:observation) { Gitlab::Database::Migrations::Observation.new(migration_version, migration_name) }
|
let(:observation) { Gitlab::Database::Migrations::Observation.new(migration_version, migration_name) }
|
||||||
let(:connection) { ActiveRecord::Base.connection }
|
|
||||||
let(:query) { "select date_trunc('day', $1::timestamptz) + $2 * (interval '1 hour')" }
|
let(:query) { "select date_trunc('day', $1::timestamptz) + $2 * (interval '1 hour')" }
|
||||||
let(:query_binds) { [Time.current, 3] }
|
let(:query_binds) { [Time.current, 3] }
|
||||||
let(:directory_path) { Dir.mktmpdir }
|
let(:directory_path) { Dir.mktmpdir }
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
RSpec.describe Gitlab::Database::Migrations::Observers::QueryLog do
|
RSpec.describe Gitlab::Database::Migrations::Observers::QueryLog do
|
||||||
subject { described_class.new(observation, directory_path) }
|
subject { described_class.new(observation, directory_path, connection) }
|
||||||
|
|
||||||
let(:observation) { Gitlab::Database::Migrations::Observation.new(migration_version, migration_name) }
|
let(:observation) { Gitlab::Database::Migrations::Observation.new(migration_version, migration_name) }
|
||||||
let(:connection) { ActiveRecord::Base.connection }
|
let(:connection) { ActiveRecord::Migration.connection }
|
||||||
let(:query) { 'select 1' }
|
let(:query) { 'select 1' }
|
||||||
let(:directory_path) { Dir.mktmpdir }
|
let(:directory_path) { Dir.mktmpdir }
|
||||||
let(:migration_version) { 20210422152437 }
|
let(:migration_version) { 20210422152437 }
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
RSpec.describe Gitlab::Database::Migrations::Observers::QueryStatistics do
|
RSpec.describe Gitlab::Database::Migrations::Observers::QueryStatistics do
|
||||||
subject { described_class.new(observation, double("unused path")) }
|
subject { described_class.new(observation, double("unused path"), connection) }
|
||||||
|
|
||||||
let(:observation) { Gitlab::Database::Migrations::Observation.new }
|
let(:observation) { Gitlab::Database::Migrations::Observation.new }
|
||||||
let(:connection) { ActiveRecord::Base.connection }
|
let(:connection) { ActiveRecord::Migration.connection }
|
||||||
|
|
||||||
def mock_pgss(enabled: true)
|
def mock_pgss(enabled: true)
|
||||||
if enabled
|
if enabled
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
RSpec.describe Gitlab::Database::Migrations::Observers::TotalDatabaseSizeChange do
|
RSpec.describe Gitlab::Database::Migrations::Observers::TotalDatabaseSizeChange do
|
||||||
subject { described_class.new(observation, double('unused path')) }
|
subject { described_class.new(observation, double('unused path'), connection) }
|
||||||
|
|
||||||
let(:observation) { Gitlab::Database::Migrations::Observation.new }
|
let(:observation) { Gitlab::Database::Migrations::Observation.new }
|
||||||
let(:connection) { ActiveRecord::Base.connection }
|
let(:connection) { ActiveRecord::Migration.connection }
|
||||||
let(:query) { 'select pg_database_size(current_database())' }
|
let(:query) { 'select pg_database_size(current_database())' }
|
||||||
|
|
||||||
it 'records the size change' do
|
it 'records the size change' do
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,9 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
RSpec.describe Gitlab::Database::Migrations::Observers::TransactionDuration do
|
RSpec.describe Gitlab::Database::Migrations::Observers::TransactionDuration do
|
||||||
subject(:transaction_duration_observer) { described_class.new(observation, directory_path) }
|
subject(:transaction_duration_observer) { described_class.new(observation, directory_path, connection) }
|
||||||
|
|
||||||
|
let(:connection) { ActiveRecord::Migration.connection }
|
||||||
let(:observation) { Gitlab::Database::Migrations::Observation.new(migration_version, migration_name) }
|
let(:observation) { Gitlab::Database::Migrations::Observation.new(migration_version, migration_name) }
|
||||||
let(:directory_path) { Dir.mktmpdir }
|
let(:directory_path) { Dir.mktmpdir }
|
||||||
let(:log_file) { "#{directory_path}/#{migration_version}_#{migration_name}-transaction-duration.json" }
|
let(:log_file) { "#{directory_path}/#{migration_version}_#{migration_name}-transaction-duration.json" }
|
||||||
|
|
@ -78,17 +79,17 @@ RSpec.describe Gitlab::Database::Migrations::Observers::TransactionDuration do
|
||||||
end
|
end
|
||||||
|
|
||||||
def run_real_transactions
|
def run_real_transactions
|
||||||
ActiveRecord::Base.transaction do
|
ApplicationRecord.transaction do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def run_sub_transactions
|
def run_sub_transactions
|
||||||
ActiveRecord::Base.transaction(requires_new: true) do
|
ApplicationRecord.transaction(requires_new: true) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def run_transaction
|
def run_transaction
|
||||||
ActiveRecord::Base.connection_pool.with_connection do |connection|
|
ApplicationRecord.connection_pool.with_connection do |connection|
|
||||||
Gitlab::Database::SharedModel.using_connection(connection) do
|
Gitlab::Database::SharedModel.using_connection(connection) do
|
||||||
Gitlab::Database::SharedModel.transaction do
|
Gitlab::Database::SharedModel.transaction do
|
||||||
Gitlab::Database::SharedModel.transaction(requires_new: true) do
|
Gitlab::Database::SharedModel.transaction(requires_new: true) do
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ RSpec.describe Gitlab::Database::Migrations::Runner do
|
||||||
it 'runs the unapplied migrations in version order', :aggregate_failures do
|
it 'runs the unapplied migrations in version order', :aggregate_failures do
|
||||||
up.run
|
up.run
|
||||||
|
|
||||||
expect(migration_runs.map(&:dir)).to eq([:up, :up])
|
expect(migration_runs.map(&:dir)).to match_array([:up, :up])
|
||||||
expect(migration_runs.map(&:version_to_migrate)).to eq(pending_migrations.map(&:version))
|
expect(migration_runs.map(&:version_to_migrate)).to eq(pending_migrations.map(&:version))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -101,7 +101,7 @@ RSpec.describe Gitlab::Database::Migrations::Runner do
|
||||||
it 'runs the applied migrations for the current branch in reverse order', :aggregate_failures do
|
it 'runs the applied migrations for the current branch in reverse order', :aggregate_failures do
|
||||||
down.run
|
down.run
|
||||||
|
|
||||||
expect(migration_runs.map(&:dir)).to eq([:down, :down])
|
expect(migration_runs.map(&:dir)).to match_array([:down, :down])
|
||||||
expect(migration_runs.map(&:version_to_migrate)).to eq(applied_migrations_this_branch.reverse.map(&:version))
|
expect(migration_runs.map(&:version_to_migrate)).to eq(applied_migrations_this_branch.reverse.map(&:version))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
RSpec.describe Gitlab::Saas do
|
||||||
|
describe '.canary_toggle_com_url' do
|
||||||
|
subject { described_class.canary_toggle_com_url }
|
||||||
|
|
||||||
|
let(:next_url) { 'https://next.gitlab.com' }
|
||||||
|
|
||||||
|
it { is_expected.to eq(next_url) }
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Reference in New Issue