Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
ec8587780b
commit
0fb62bd3e1
|
|
@ -720,7 +720,18 @@ export const searchBy = (query = '', searchSpace = {}) => {
|
|||
* @param {Object} label
|
||||
* @returns Boolean
|
||||
*/
|
||||
export const isScopedLabel = ({ title = '' }) => title.indexOf('::') !== -1;
|
||||
export const isScopedLabel = ({ title = '' } = {}) => title.indexOf('::') !== -1;
|
||||
|
||||
/**
|
||||
* Returns the base value of the scoped label
|
||||
*
|
||||
* Expected Label to be an Object with `title` as a key:
|
||||
* { title: 'LabelTitle', ...otherProperties };
|
||||
*
|
||||
* @param {Object} label
|
||||
* @returns String
|
||||
*/
|
||||
export const scopedLabelKey = ({ title = '' }) => isScopedLabel({ title }) && title.split('::')[0];
|
||||
|
||||
// Methods to set and get Cookie
|
||||
export const setCookie = (name, value) => Cookies.set(name, value, { expires: 365 });
|
||||
|
|
|
|||
|
|
@ -19,6 +19,11 @@ export default {
|
|||
type: String,
|
||||
required: true,
|
||||
},
|
||||
tabQueryParamValue: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
|
|
@ -55,6 +60,6 @@ export default {
|
|||
errorMessage
|
||||
}}</gl-alert>
|
||||
<filter-sort-container />
|
||||
<members-table />
|
||||
<members-table :tab-query-param-value="tabQueryParamValue" />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,11 @@ import { getParameterByName } from '~/lib/utils/common_utils';
|
|||
// eslint-disable-next-line import/no-deprecated
|
||||
import { setUrlParams, urlParamsToObject } from '~/lib/utils/url_utility';
|
||||
import { s__ } from '~/locale';
|
||||
import { SEARCH_TOKEN_TYPE, SORT_PARAM } from '~/members/constants';
|
||||
import {
|
||||
SEARCH_TOKEN_TYPE,
|
||||
SORT_QUERY_PARAM_NAME,
|
||||
ACTIVE_TAB_QUERY_PARAM_NAME,
|
||||
} from '~/members/constants';
|
||||
import { OPERATOR_IS_ONLY } from '~/vue_shared/components/filtered_search_bar/constants';
|
||||
import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
|
||||
|
||||
|
|
@ -118,10 +122,15 @@ export default {
|
|||
return accumulator;
|
||||
}, {});
|
||||
|
||||
const sortParam = getParameterByName(SORT_PARAM);
|
||||
const sortParamValue = getParameterByName(SORT_QUERY_PARAM_NAME);
|
||||
const activeTabParamValue = getParameterByName(ACTIVE_TAB_QUERY_PARAM_NAME);
|
||||
|
||||
window.location.href = setUrlParams(
|
||||
{ ...params, ...(sortParam && { sort: sortParam }) },
|
||||
{
|
||||
...params,
|
||||
...(sortParamValue && { [SORT_QUERY_PARAM_NAME]: sortParamValue }),
|
||||
...(activeTabParamValue && { [ACTIVE_TAB_QUERY_PARAM_NAME]: activeTabParamValue }),
|
||||
},
|
||||
window.location.href,
|
||||
true,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -4,14 +4,15 @@ import { mapState } from 'vuex';
|
|||
// eslint-disable-next-line import/no-deprecated
|
||||
import { urlParamsToObject } from '~/lib/utils/url_utility';
|
||||
import { __ } from '~/locale';
|
||||
import { MEMBER_TYPES } from '../constants';
|
||||
import { MEMBER_TYPES, TAB_QUERY_PARAM_VALUES, ACTIVE_TAB_QUERY_PARAM_NAME } from '../constants';
|
||||
import MembersApp from './app.vue';
|
||||
|
||||
const countComputed = (state, namespace) => state[namespace]?.pagination?.totalItems || 0;
|
||||
|
||||
export default {
|
||||
name: 'MembersTabs',
|
||||
tabs: [
|
||||
ACTIVE_TAB_QUERY_PARAM_NAME,
|
||||
TABS: [
|
||||
{
|
||||
namespace: MEMBER_TYPES.user,
|
||||
title: __('Members'),
|
||||
|
|
@ -20,19 +21,21 @@ export default {
|
|||
namespace: MEMBER_TYPES.group,
|
||||
title: __('Groups'),
|
||||
attrs: { 'data-qa-selector': 'groups_list_tab' },
|
||||
queryParamValue: TAB_QUERY_PARAM_VALUES.group,
|
||||
},
|
||||
{
|
||||
namespace: MEMBER_TYPES.invite,
|
||||
title: __('Invited'),
|
||||
canManageMembersPermissionsRequired: true,
|
||||
queryParamValue: TAB_QUERY_PARAM_VALUES.invite,
|
||||
},
|
||||
{
|
||||
namespace: MEMBER_TYPES.accessRequest,
|
||||
title: __('Access requests'),
|
||||
canManageMembersPermissionsRequired: true,
|
||||
queryParamValue: TAB_QUERY_PARAM_VALUES.accessRequest,
|
||||
},
|
||||
],
|
||||
urlParams: [],
|
||||
components: { MembersApp, GlTabs, GlTab, GlBadge },
|
||||
inject: ['canManageMembers'],
|
||||
data() {
|
||||
|
|
@ -60,29 +63,18 @@ export default {
|
|||
return Object.keys(urlParamsToObject(window.location.search));
|
||||
},
|
||||
activeTabIndexCalculatedFromUrlParams() {
|
||||
return this.$options.tabs.findIndex(({ namespace }) => {
|
||||
return this.$options.TABS.findIndex(({ namespace }) => {
|
||||
return this.getTabUrlParams(namespace).some((urlParam) =>
|
||||
this.urlParams.includes(urlParam),
|
||||
);
|
||||
});
|
||||
},
|
||||
},
|
||||
created() {
|
||||
if (this.activeTabIndexCalculatedFromUrlParams === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.selectedTabIndex = this.activeTabIndexCalculatedFromUrlParams;
|
||||
},
|
||||
methods: {
|
||||
getTabUrlParams(namespace) {
|
||||
const state = this.$store.state[namespace];
|
||||
const urlParams = [];
|
||||
|
||||
if (state?.pagination?.paramName) {
|
||||
urlParams.push(state.pagination.paramName);
|
||||
}
|
||||
|
||||
if (state?.filteredSearchBar?.searchParam) {
|
||||
urlParams.push(state.filteredSearchBar.searchParam);
|
||||
}
|
||||
|
|
@ -112,14 +104,23 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<gl-tabs v-model="selectedTabIndex">
|
||||
<template v-for="(tab, index) in $options.tabs">
|
||||
<gl-tab v-if="showTab(tab, index)" :key="tab.namespace" :title-link-attributes="tab.attrs">
|
||||
<gl-tabs
|
||||
v-model="selectedTabIndex"
|
||||
sync-active-tab-with-query-params
|
||||
:query-param-name="$options.ACTIVE_TAB_QUERY_PARAM_NAME"
|
||||
>
|
||||
<template v-for="(tab, index) in $options.TABS">
|
||||
<gl-tab
|
||||
v-if="showTab(tab, index)"
|
||||
:key="tab.namespace"
|
||||
:title-link-attributes="tab.attrs"
|
||||
:query-param-value="tab.queryParamValue"
|
||||
>
|
||||
<template slot="title">
|
||||
<span>{{ tab.title }}</span>
|
||||
<gl-badge size="sm" class="gl-tab-counter-badge">{{ getTabCount(tab) }}</gl-badge>
|
||||
</template>
|
||||
<members-app :namespace="tab.namespace" />
|
||||
<members-app :namespace="tab.namespace" :tab-query-param-value="tab.queryParamValue" />
|
||||
</gl-tab>
|
||||
</template>
|
||||
</gl-tabs>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import MembersTableCell from 'ee_else_ce/members/components/table/members_table_
|
|||
import { canOverride, canRemove, canResend, canUpdate } from 'ee_else_ce/members/utils';
|
||||
import { mergeUrlParams } from '~/lib/utils/url_utility';
|
||||
import initUserPopovers from '~/user_popovers';
|
||||
import { FIELDS } from '../../constants';
|
||||
import { FIELDS, ACTIVE_TAB_QUERY_PARAM_NAME } from '../../constants';
|
||||
import RemoveGroupLinkModal from '../modals/remove_group_link_modal.vue';
|
||||
import CreatedAt from './created_at.vue';
|
||||
import ExpirationDatepicker from './expiration_datepicker.vue';
|
||||
|
|
@ -34,6 +34,13 @@ export default {
|
|||
import('ee_component/members/components/ldap/ldap_override_confirmation_modal.vue'),
|
||||
},
|
||||
inject: ['namespace', 'currentUserId'],
|
||||
props: {
|
||||
tabQueryParamValue: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
members(state) {
|
||||
|
|
@ -112,7 +119,15 @@ export default {
|
|||
paginationLinkGenerator(page) {
|
||||
const { params = {}, paramName } = this.pagination;
|
||||
|
||||
return mergeUrlParams({ ...params, [paramName]: page }, window.location.href);
|
||||
return mergeUrlParams(
|
||||
{
|
||||
...params,
|
||||
[ACTIVE_TAB_QUERY_PARAM_NAME]:
|
||||
this.tabQueryParamValue !== '' ? this.tabQueryParamValue : null,
|
||||
[paramName]: page,
|
||||
},
|
||||
window.location.href,
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -89,6 +89,12 @@ export const MEMBER_TYPES = {
|
|||
accessRequest: 'accessRequest',
|
||||
};
|
||||
|
||||
export const TAB_QUERY_PARAM_VALUES = {
|
||||
group: 'groups',
|
||||
invite: 'invited',
|
||||
accessRequest: 'access_requests',
|
||||
};
|
||||
|
||||
export const DAYS_TO_EXPIRE_SOON = 7;
|
||||
|
||||
export const LEAVE_MODAL_ID = 'member-leave-modal';
|
||||
|
|
@ -97,7 +103,8 @@ export const REMOVE_GROUP_LINK_MODAL_ID = 'remove-group-link-modal-id';
|
|||
|
||||
export const SEARCH_TOKEN_TYPE = 'filtered-search-term';
|
||||
|
||||
export const SORT_PARAM = 'sort';
|
||||
export const SORT_QUERY_PARAM_NAME = 'sort';
|
||||
export const ACTIVE_TAB_QUERY_PARAM_NAME = 'tab';
|
||||
|
||||
export const MEMBER_ACCESS_LEVEL_PROPERTY_NAME = 'access_level';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { isScopedLabel, scopedLabelKey } from '~/lib/utils/common_utils';
|
||||
import { DropdownVariant } from '../constants';
|
||||
import * as types from './mutation_types';
|
||||
|
||||
|
|
@ -66,5 +67,16 @@ export default {
|
|||
candidateLabel.touched = true;
|
||||
candidateLabel.set = !candidateLabel.set;
|
||||
}
|
||||
|
||||
if (isScopedLabel(candidateLabel)) {
|
||||
const scopedBase = scopedLabelKey(candidateLabel);
|
||||
const currentActiveScopedLabel = state.labels.find(({ title }) => {
|
||||
return title.startsWith(scopedBase) && title !== '' && title !== candidateLabel.title;
|
||||
});
|
||||
|
||||
if (currentActiveScopedLabel) {
|
||||
currentActiveScopedLabel.set = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { isScopedLabel, scopedLabelKey } from '~/lib/utils/common_utils';
|
||||
import { DropdownVariant } from '../constants';
|
||||
import * as types from './mutation_types';
|
||||
|
||||
|
|
@ -55,5 +56,16 @@ export default {
|
|||
candidateLabel.touched = true;
|
||||
candidateLabel.set = !candidateLabel.set;
|
||||
}
|
||||
|
||||
if (isScopedLabel(candidateLabel)) {
|
||||
const scopedBase = scopedLabelKey(candidateLabel);
|
||||
const currentActiveScopedLabel = state.labels.find(
|
||||
({ title }) => title.indexOf(scopedBase) === 0 && title !== candidateLabel.title,
|
||||
);
|
||||
|
||||
if (currentActiveScopedLabel) {
|
||||
currentActiveScopedLabel.set = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: ci_workflow_rules_variables
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/52085
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/300997
|
||||
milestone: '13.11'
|
||||
type: development
|
||||
group: group::pipeline authoring
|
||||
default_enabled: true
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
Redis::Client.prepend(Gitlab::Instrumentation::RedisInterceptor)
|
||||
|
||||
# Make sure we initialize a Redis connection pool before multi-threaded
|
||||
# execution starts by
|
||||
# 1. Sidekiq
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddRunningContainerScanningMaxSizeToPlanLimits < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
add_column :plan_limits, :ci_max_artifact_size_running_container_scanning, :integer, null: false, default: 0
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
5dc0a4f91dc35b7720b20e89fa77374a0337c380b9234704e7d4143639e512f0
|
||||
|
|
@ -16299,7 +16299,8 @@ CREATE TABLE plan_limits (
|
|||
ci_registered_group_runners integer DEFAULT 1000 NOT NULL,
|
||||
ci_registered_project_runners integer DEFAULT 1000 NOT NULL,
|
||||
web_hook_calls integer DEFAULT 0 NOT NULL,
|
||||
ci_daily_pipeline_schedule_triggers integer DEFAULT 0 NOT NULL
|
||||
ci_daily_pipeline_schedule_triggers integer DEFAULT 0 NOT NULL,
|
||||
ci_max_artifact_size_running_container_scanning integer DEFAULT 0 NOT NULL
|
||||
);
|
||||
|
||||
CREATE SEQUENCE plan_limits_id_seq
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ Read more about [Gitaly concurrency limits](gitaly/configure_gitaly.md#limit-rpc
|
|||
|
||||
There's a limit to the number of comments that can be submitted on an issue,
|
||||
merge request, or commit. When the limit is reached, system notes can still be
|
||||
added so that the history of events is not lost, but the user-submitted
|
||||
added so that the history of events is not lost, but the user-submitted
|
||||
comment fails.
|
||||
|
||||
- **Max limit**: 5,000 comments.
|
||||
|
|
@ -443,33 +443,34 @@ setting is used:
|
|||
|
||||
| Artifact limit name | Default value |
|
||||
|---------------------------------------------|---------------|
|
||||
| `ci_max_artifact_size_accessibility` | 0 |
|
||||
| `ci_max_artifact_size_api_fuzzing` | 0 |
|
||||
| `ci_max_artifact_size_archive` | 0 |
|
||||
| `ci_max_artifact_size_browser_performance` | 0 |
|
||||
| `ci_max_artifact_size_cluster_applications` | 0 |
|
||||
| `ci_max_artifact_size_cobertura` | 0 |
|
||||
| `ci_max_artifact_size_codequality` | 0 |
|
||||
| `ci_max_artifact_size_container_scanning` | 0 |
|
||||
| `ci_max_artifact_size_coverage_fuzzing` | 0 |
|
||||
| `ci_max_artifact_size_dast` | 0 |
|
||||
| `ci_max_artifact_size_dependency_scanning` | 0 |
|
||||
| `ci_max_artifact_size_dotenv` | 0 |
|
||||
| `ci_max_artifact_size_junit` | 0 |
|
||||
| `ci_max_artifact_size_license_management` | 0 |
|
||||
| `ci_max_artifact_size_license_scanning` | 0 |
|
||||
| `ci_max_artifact_size_load_performance` | 0 |
|
||||
| `ci_max_artifact_size_lsif` | 100 MB ([Introduced at 20 MB](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37226) in GitLab 13.3 and [raised to 100 MB](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46980) in GitLab 13.6.) |
|
||||
| `ci_max_artifact_size_metadata` | 0 |
|
||||
| `ci_max_artifact_size_metrics_referee` | 0 |
|
||||
| `ci_max_artifact_size_metrics` | 0 |
|
||||
| `ci_max_artifact_size_network_referee` | 0 |
|
||||
| `ci_max_artifact_size_performance` | 0 |
|
||||
| `ci_max_artifact_size_requirements` | 0 |
|
||||
| `ci_max_artifact_size_sast` | 0 |
|
||||
| `ci_max_artifact_size_secret_detection` | 0 |
|
||||
| `ci_max_artifact_size_terraform` | 5 MB ([introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37018) in GitLab 13.3) |
|
||||
| `ci_max_artifact_size_trace` | 0 |
|
||||
| `ci_max_artifact_size_accessibility` | 0 |
|
||||
| `ci_max_artifact_size_api_fuzzing` | 0 |
|
||||
| `ci_max_artifact_size_archive` | 0 |
|
||||
| `ci_max_artifact_size_browser_performance` | 0 |
|
||||
| `ci_max_artifact_size_cluster_applications` | 0 |
|
||||
| `ci_max_artifact_size_cobertura` | 0 |
|
||||
| `ci_max_artifact_size_codequality` | 0 |
|
||||
| `ci_max_artifact_size_container_scanning` | 0 |
|
||||
| `ci_max_artifact_size_coverage_fuzzing` | 0 |
|
||||
| `ci_max_artifact_size_dast` | 0 |
|
||||
| `ci_max_artifact_size_dependency_scanning` | 0 |
|
||||
| `ci_max_artifact_size_dotenv` | 0 |
|
||||
| `ci_max_artifact_size_junit` | 0 |
|
||||
| `ci_max_artifact_size_license_management` | 0 |
|
||||
| `ci_max_artifact_size_license_scanning` | 0 |
|
||||
| `ci_max_artifact_size_load_performance` | 0 |
|
||||
| `ci_max_artifact_size_lsif` | 100 MB ([Introduced at 20 MB](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37226) in GitLab 13.3 and [raised to 100 MB](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46980) in GitLab 13.6.) |
|
||||
| `ci_max_artifact_size_metadata` | 0 |
|
||||
| `ci_max_artifact_size_metrics_referee` | 0 |
|
||||
| `ci_max_artifact_size_metrics` | 0 |
|
||||
| `ci_max_artifact_size_network_referee` | 0 |
|
||||
| `ci_max_artifact_size_performance` | 0 |
|
||||
| `ci_max_artifact_size_requirements` | 0 |
|
||||
| `ci_max_artifact_size_running_container_scanning` | 0 |
|
||||
| `ci_max_artifact_size_sast` | 0 |
|
||||
| `ci_max_artifact_size_secret_detection` | 0 |
|
||||
| `ci_max_artifact_size_terraform` | 5 MB ([introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37018) in GitLab 13.3) |
|
||||
| `ci_max_artifact_size_trace` | 0 |
|
||||
|
||||
For example, to set the `ci_max_artifact_size_junit` limit to 10 MB on a self-managed
|
||||
installation, run the following in the [GitLab Rails console](operations/rails_console.md#starting-a-rails-console-session):
|
||||
|
|
@ -607,7 +608,7 @@ Reports that go over the 20 MB limit won't be loaded. Affected reports:
|
|||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/8638) in GitLab 13.3.
|
||||
|
||||
You can set a limit on the content of repository files that are indexed in
|
||||
Elasticsearch. Any files larger than this limit is neither indexed
|
||||
Elasticsearch. Any files larger than this limit is neither indexed
|
||||
nor searchable.
|
||||
|
||||
Setting a limit helps reduce the memory usage of the indexing processes and
|
||||
|
|
|
|||
|
|
@ -98,6 +98,8 @@ The following metrics are available:
|
|||
| `gitlab_transaction_db_write_count_total` | Counter | 13.1 | Counter for total number of write SQL calls | `controller`, `action` |
|
||||
| `gitlab_transaction_db_cached_count_total` | Counter | 13.1 | Counter for total number of cached SQL calls | `controller`, `action` |
|
||||
| `gitlab_transaction_db_<role>_cached_count_total` | Counter | 13.1 | Counter for total number of cached SQL calls, grouped by database roles (primary/replica) | `controller`, `action` |
|
||||
| `gitlab_transaction_db_<role>_wal_count_total` | Counter | 14.0 | Counter for total number of WAL (write ahead log location) queries, grouped by database roles (primary/replica) | `controller`, `action` |
|
||||
| `gitlab_transaction_db_<role>_wal_cached_count_total` | Counter | 14.1 | Counter for total number of cached WAL (write ahead log location) queries, grouped by database roles (primary/replica)| `controller`, `action` |
|
||||
| `http_elasticsearch_requests_duration_seconds` **(PREMIUM)** | Histogram | 13.1 | Elasticsearch requests duration during web transactions | `controller`, `action` |
|
||||
| `http_elasticsearch_requests_total` **(PREMIUM)** | Counter | 13.1 | Elasticsearch requests count during web transactions | `controller`, `action` |
|
||||
| `pipelines_created_total` | Counter | 9.4 | Counter of pipelines created | |
|
||||
|
|
|
|||
|
|
@ -233,15 +233,7 @@ If your rules match both branch pipelines and merge request pipelines,
|
|||
#### `workflow:rules:variables`
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/294232) in GitLab 13.11.
|
||||
> - [Deployed behind a feature flag](../../user/feature_flags.md), disabled by default.
|
||||
> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/300997) in GitLab 13.12.
|
||||
> - Enabled on GitLab.com.
|
||||
> - Recommended for production use.
|
||||
> - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#enable-or-disable-workflowrulesvariables). **(FREE SELF)**
|
||||
|
||||
There can be
|
||||
[risks when disabling released features](../../user/feature_flags.md#risks-when-disabling-released-features).
|
||||
Refer to this feature's version history for more details.
|
||||
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/300997) in GitLab 14.1.
|
||||
|
||||
You can use [`variables`](#variables) in `workflow:rules:` to define variables for specific pipeline conditions.
|
||||
|
||||
|
|
@ -294,25 +286,6 @@ When the branch is something else:
|
|||
- job1's `DEPLOY_VARIABLE` is `job1-default-deploy`.
|
||||
- job2's `DEPLOY_VARIABLE` is `default-deploy`.
|
||||
|
||||
##### Enable or disable workflow:rules:variables **(FREE SELF)**
|
||||
|
||||
workflow:rules:variables is under development but ready for production use.
|
||||
It is deployed behind a feature flag that is **enabled by default**.
|
||||
[GitLab administrators with access to the GitLab Rails console](../../administration/feature_flags.md)
|
||||
can opt to disable it.
|
||||
|
||||
To enable it:
|
||||
|
||||
```ruby
|
||||
Feature.enable(:ci_workflow_rules_variables)
|
||||
```
|
||||
|
||||
To disable it:
|
||||
|
||||
```ruby
|
||||
Feature.disable(:ci_workflow_rules_variables)
|
||||
```
|
||||
|
||||
#### `workflow:rules` templates
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217732) in GitLab 13.0.
|
||||
|
|
|
|||
|
|
@ -95,8 +95,6 @@ renaming. For example
|
|||
class RenameUsersUpdatedAtToUpdatedAtTimestamp < ActiveRecord::Migration[4.2]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
DOWNTIME = false
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
|
|
@ -291,8 +289,6 @@ any remaining rows. For example:
|
|||
class MigrateRemainingIssuesClosedAt < ActiveRecord::Migration[4.2]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
DOWNTIME = false
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
class Issue < ActiveRecord::Base
|
||||
|
|
|
|||
|
|
@ -58,9 +58,9 @@ The **Time** metrics near the top of the page are measured as follows:
|
|||
|
||||
## How the stages are measured
|
||||
|
||||
Value Stream Analytics uses start events and stop events to measure the time that an issue or merge request spends in each stage.
|
||||
Value Stream Analytics uses start events and end events to measure the time that an issue or merge request spends in each stage.
|
||||
For example, a stage might start when one label is added to an issue and end when another label is added.
|
||||
Items aren't included in the stage time calculation if they have not reached the stop event.
|
||||
Items aren't included in the stage time calculation if they have not reached the end event.
|
||||
|
||||
| Stage | Description |
|
||||
|---------|---------------|
|
||||
|
|
|
|||
|
|
@ -96,9 +96,9 @@ You can learn more about these metrics in our [analytics definitions](../../anal
|
|||
|
||||
## How the stages are measured
|
||||
|
||||
Value Stream Analytics measures each stage from its start event to its stop event.
|
||||
Value Stream Analytics measures each stage from its start event to its end event.
|
||||
For example, a stage might start when one label is added to an issue, and end when another label is added.
|
||||
Value Stream Analytics excludes work in progress, meaning it ignores any items that have not reached the stop event.
|
||||
Value Stream Analytics excludes work in progress, meaning it ignores any items that have not reached the end event.
|
||||
|
||||
Each stage of Value Stream Analytics is further described in the table below.
|
||||
|
||||
|
|
|
|||
|
|
@ -10,10 +10,7 @@ module Gitlab
|
|||
|
||||
def perform!
|
||||
raise ArgumentError, 'missing YAML processor result' unless @command.yaml_processor_result
|
||||
|
||||
if ::Feature.enabled?(:ci_workflow_rules_variables, pipeline.project, default_enabled: :yaml)
|
||||
raise ArgumentError, 'missing workflow rules result' unless @command.workflow_rules_result
|
||||
end
|
||||
raise ArgumentError, 'missing workflow rules result' unless @command.workflow_rules_result
|
||||
|
||||
# Allocate next IID. This operation must be outside of transactions of pipeline creations.
|
||||
pipeline.ensure_project_iid!
|
||||
|
|
@ -51,13 +48,9 @@ module Gitlab
|
|||
end
|
||||
|
||||
def root_variables
|
||||
if ::Feature.enabled?(:ci_workflow_rules_variables, pipeline.project, default_enabled: :yaml)
|
||||
::Gitlab::Ci::Variables::Helpers.merge_variables(
|
||||
@command.yaml_processor_result.root_variables, @command.workflow_rules_result.variables
|
||||
)
|
||||
else
|
||||
@command.yaml_processor_result.root_variables
|
||||
end
|
||||
::Gitlab::Ci::Variables::Helpers.merge_variables(
|
||||
@command.yaml_processor_result.root_variables, @command.workflow_rules_result.variables
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -213,8 +213,6 @@ module Gitlab
|
|||
end
|
||||
|
||||
def recalculate_yaml_variables!
|
||||
return unless ::Feature.enabled?(:ci_workflow_rules_variables, @pipeline.project, default_enabled: :yaml)
|
||||
|
||||
@seed_attributes[:yaml_variables] = Gitlab::Ci::Variables::Helpers.inherit_yaml_variables(
|
||||
from: @context.root_variables, to: @job_variables, inheritance: @root_variables_inheritance
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'redis'
|
||||
|
||||
module Gitlab
|
||||
module Instrumentation
|
||||
module RedisInterceptor
|
||||
|
|
@ -99,7 +97,3 @@ module Gitlab
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
class ::Redis::Client
|
||||
prepend ::Gitlab::Instrumentation::RedisInterceptor
|
||||
end
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ module Gitlab
|
|||
TRANSACTION_DURATION_BUCKET = [0.1, 0.25, 1].freeze
|
||||
|
||||
DB_LOAD_BALANCING_COUNTERS = %i{
|
||||
db_replica_count db_replica_cached_count db_replica_wal_count
|
||||
db_primary_count db_primary_cached_count db_primary_wal_count
|
||||
db_replica_count db_replica_cached_count db_replica_wal_count db_replica_wal_cached_count
|
||||
db_primary_count db_primary_cached_count db_primary_wal_count db_primary_wal_cached_count
|
||||
}.freeze
|
||||
DB_LOAD_BALANCING_DURATIONS = %i{db_primary_duration_s db_replica_duration_s}.freeze
|
||||
|
||||
|
|
@ -91,9 +91,14 @@ module Gitlab
|
|||
end
|
||||
|
||||
def increment_db_role_counters(db_role, payload)
|
||||
cached = cached_query?(payload)
|
||||
increment("db_#{db_role}_count".to_sym)
|
||||
increment("db_#{db_role}_cached_count".to_sym) if cached_query?(payload)
|
||||
increment("db_#{db_role}_wal_count".to_sym) if !cached_query?(payload) && wal_command?(payload)
|
||||
increment("db_#{db_role}_cached_count".to_sym) if cached
|
||||
|
||||
if wal_command?(payload)
|
||||
increment("db_#{db_role}_wal_count".to_sym)
|
||||
increment("db_#{db_role}_wal_cached_count".to_sym) if cached
|
||||
end
|
||||
end
|
||||
|
||||
def observe_db_role_duration(db_role, event)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ import Vuex from 'vuex';
|
|||
import * as commonUtils from '~/lib/utils/common_utils';
|
||||
import MembersApp from '~/members/components/app.vue';
|
||||
import FilterSortContainer from '~/members/components/filter_sort/filter_sort_container.vue';
|
||||
import { MEMBER_TYPES } from '~/members/constants';
|
||||
import MembersTable from '~/members/components/table/members_table.vue';
|
||||
import { MEMBER_TYPES, TAB_QUERY_PARAM_VALUES } from '~/members/constants';
|
||||
import { RECEIVE_MEMBER_ROLE_ERROR, HIDE_ERROR } from '~/members/store/mutation_types';
|
||||
import mutations from '~/members/store/mutations';
|
||||
|
||||
|
|
@ -19,7 +20,7 @@ describe('MembersApp', () => {
|
|||
const createComponent = (state = {}, options = {}) => {
|
||||
store = new Vuex.Store({
|
||||
modules: {
|
||||
[MEMBER_TYPES.user]: {
|
||||
[MEMBER_TYPES.group]: {
|
||||
namespaced: true,
|
||||
state: {
|
||||
showError: true,
|
||||
|
|
@ -34,7 +35,8 @@ describe('MembersApp', () => {
|
|||
wrapper = shallowMount(MembersApp, {
|
||||
localVue,
|
||||
propsData: {
|
||||
namespace: MEMBER_TYPES.user,
|
||||
namespace: MEMBER_TYPES.group,
|
||||
tabQueryParamValue: TAB_QUERY_PARAM_VALUES.group,
|
||||
},
|
||||
store,
|
||||
...options,
|
||||
|
|
@ -57,7 +59,7 @@ describe('MembersApp', () => {
|
|||
it('renders and scrolls to error alert', async () => {
|
||||
createComponent({ showError: false, errorMessage: '' });
|
||||
|
||||
store.commit(`${MEMBER_TYPES.user}/${RECEIVE_MEMBER_ROLE_ERROR}`, {
|
||||
store.commit(`${MEMBER_TYPES.group}/${RECEIVE_MEMBER_ROLE_ERROR}`, {
|
||||
error: new Error('Network Error'),
|
||||
});
|
||||
|
||||
|
|
@ -77,7 +79,7 @@ describe('MembersApp', () => {
|
|||
it('does not render and scroll to error alert', async () => {
|
||||
createComponent();
|
||||
|
||||
store.commit(`${MEMBER_TYPES.user}/${HIDE_ERROR}`);
|
||||
store.commit(`${MEMBER_TYPES.group}/${HIDE_ERROR}`);
|
||||
|
||||
await nextTick();
|
||||
|
||||
|
|
@ -103,4 +105,13 @@ describe('MembersApp', () => {
|
|||
|
||||
expect(findFilterSortContainer().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('renders `MembersTable` component and passes `tabQueryParamValue` prop', () => {
|
||||
createComponent();
|
||||
|
||||
const membersTableComponent = wrapper.findComponent(MembersTable);
|
||||
|
||||
expect(membersTableComponent.exists()).toBe(true);
|
||||
expect(membersTableComponent.props('tabQueryParamValue')).toBe(TAB_QUERY_PARAM_VALUES.group);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -216,5 +216,17 @@ describe('MembersFilteredSearchBar', () => {
|
|||
'https://localhost/?two_factor=enabled&search=foobar&sort=name_asc',
|
||||
);
|
||||
});
|
||||
|
||||
it('adds active tab query param', () => {
|
||||
window.location.search = '?tab=invited';
|
||||
|
||||
createComponent();
|
||||
|
||||
findFilteredSearchBar().vm.$emit('onFilter', [
|
||||
{ type: 'filtered-search-term', value: { data: 'foobar' } },
|
||||
]);
|
||||
|
||||
expect(window.location.href).toBe('https://localhost/?search=foobar&tab=invited');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,9 +1,14 @@
|
|||
import { GlTabs } from '@gitlab/ui';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import { mountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import MembersApp from '~/members/components/app.vue';
|
||||
import MembersTabs from '~/members/components/members_tabs.vue';
|
||||
import { MEMBER_TYPES } from '~/members/constants';
|
||||
import {
|
||||
MEMBER_TYPES,
|
||||
TAB_QUERY_PARAM_VALUES,
|
||||
ACTIVE_TAB_QUERY_PARAM_NAME,
|
||||
} from '~/members/constants';
|
||||
import { pagination } from '../mock_data';
|
||||
|
||||
describe('MembersTabs', () => {
|
||||
|
|
@ -93,6 +98,18 @@ describe('MembersTabs', () => {
|
|||
wrapper.destroy();
|
||||
});
|
||||
|
||||
it('renders `GlTabs` with `syncActiveTabWithQueryParams` and `queryParamName` props set', async () => {
|
||||
await createComponent();
|
||||
|
||||
const glTabsComponent = wrapper.findComponent(GlTabs);
|
||||
|
||||
expect(glTabsComponent.exists()).toBe(true);
|
||||
expect(glTabsComponent.props()).toMatchObject({
|
||||
syncActiveTabWithQueryParams: true,
|
||||
queryParamName: ACTIVE_TAB_QUERY_PARAM_NAME,
|
||||
});
|
||||
});
|
||||
|
||||
describe('when tabs have a count', () => {
|
||||
it('renders tabs with count', async () => {
|
||||
await createComponent();
|
||||
|
|
@ -106,7 +123,7 @@ describe('MembersTabs', () => {
|
|||
expect(findActiveTab().text()).toContain('Members');
|
||||
});
|
||||
|
||||
it('renders `MembersApp` and passes `namespace` prop', async () => {
|
||||
it('renders `MembersApp` and passes `namespace` and `tabQueryParamValue` props', async () => {
|
||||
await createComponent();
|
||||
|
||||
const membersApps = wrapper.findAllComponents(MembersApp).wrappers;
|
||||
|
|
@ -115,6 +132,10 @@ describe('MembersTabs', () => {
|
|||
expect(membersApps[1].props('namespace')).toBe(MEMBER_TYPES.group);
|
||||
expect(membersApps[2].props('namespace')).toBe(MEMBER_TYPES.invite);
|
||||
expect(membersApps[3].props('namespace')).toBe(MEMBER_TYPES.accessRequest);
|
||||
|
||||
expect(membersApps[1].props('tabQueryParamValue')).toBe(TAB_QUERY_PARAM_VALUES.group);
|
||||
expect(membersApps[2].props('tabQueryParamValue')).toBe(TAB_QUERY_PARAM_VALUES.invite);
|
||||
expect(membersApps[3].props('tabQueryParamValue')).toBe(TAB_QUERY_PARAM_VALUES.accessRequest);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -127,56 +148,16 @@ describe('MembersTabs', () => {
|
|||
expect(findTabByText('Invited')).toBeUndefined();
|
||||
expect(findTabByText('Access requests')).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when url param matches `filteredSearchBar.searchParam`', () => {
|
||||
beforeEach(() => {
|
||||
window.location.search = '?search_groups=foo+bar';
|
||||
});
|
||||
|
||||
const expectGroupsTabActive = () => {
|
||||
expect(findActiveTab().text()).toContain('Groups');
|
||||
};
|
||||
|
||||
describe('when tab has a count', () => {
|
||||
it('sets tab that corresponds to search param as active tab', async () => {
|
||||
await createComponent();
|
||||
|
||||
expectGroupsTabActive();
|
||||
describe('when url param matches `filteredSearchBar.searchParam`', () => {
|
||||
beforeEach(() => {
|
||||
window.location.search = '?search_groups=foo+bar';
|
||||
});
|
||||
});
|
||||
|
||||
describe('when tab does not have a count', () => {
|
||||
it('sets tab that corresponds to search param as active tab', async () => {
|
||||
it('shows tab that corresponds to search param', async () => {
|
||||
await createComponent({ totalItems: 0 });
|
||||
|
||||
expectGroupsTabActive();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when url param matches `pagination.paramName`', () => {
|
||||
beforeEach(() => {
|
||||
window.location.search = '?invited_page=2';
|
||||
});
|
||||
|
||||
const expectInvitedTabActive = () => {
|
||||
expect(findActiveTab().text()).toContain('Invited');
|
||||
};
|
||||
|
||||
describe('when tab has a count', () => {
|
||||
it('sets tab that corresponds to pagination param as active tab', async () => {
|
||||
await createComponent();
|
||||
|
||||
expectInvitedTabActive();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when tab does not have a count', () => {
|
||||
it('sets tab that corresponds to pagination param as active tab', async () => {
|
||||
await createComponent({ totalItems: 0 });
|
||||
|
||||
expectInvitedTabActive();
|
||||
expect(findTabByText('Groups')).not.toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import MemberAvatar from '~/members/components/table/member_avatar.vue';
|
|||
import MemberSource from '~/members/components/table/member_source.vue';
|
||||
import MembersTable from '~/members/components/table/members_table.vue';
|
||||
import RoleDropdown from '~/members/components/table/role_dropdown.vue';
|
||||
import { MEMBER_TYPES } from '~/members/constants';
|
||||
import { MEMBER_TYPES, TAB_QUERY_PARAM_VALUES } from '~/members/constants';
|
||||
import * as initUserPopovers from '~/user_popovers';
|
||||
import {
|
||||
member as memberMock,
|
||||
|
|
@ -34,7 +34,7 @@ describe('MembersTable', () => {
|
|||
const createStore = (state = {}) => {
|
||||
return new Vuex.Store({
|
||||
modules: {
|
||||
[MEMBER_TYPES.user]: {
|
||||
[MEMBER_TYPES.invite]: {
|
||||
namespaced: true,
|
||||
state: {
|
||||
members: [],
|
||||
|
|
@ -54,11 +54,14 @@ describe('MembersTable', () => {
|
|||
const createComponent = (state, provide = {}) => {
|
||||
wrapper = mount(MembersTable, {
|
||||
localVue,
|
||||
propsData: {
|
||||
tabQueryParamValue: TAB_QUERY_PARAM_VALUES.invite,
|
||||
},
|
||||
store: createStore(state),
|
||||
provide: {
|
||||
sourceId: 1,
|
||||
currentUserId: 1,
|
||||
namespace: MEMBER_TYPES.user,
|
||||
namespace: MEMBER_TYPES.invite,
|
||||
...provide,
|
||||
},
|
||||
stubs: [
|
||||
|
|
@ -74,7 +77,7 @@ describe('MembersTable', () => {
|
|||
});
|
||||
};
|
||||
|
||||
const url = 'https://localhost/foo-bar/-/project_members';
|
||||
const url = 'https://localhost/foo-bar/-/project_members?tab=invited';
|
||||
|
||||
const getByText = (text, options) =>
|
||||
createWrapper(getByTextHelper(wrapper.element, text, options));
|
||||
|
|
@ -92,7 +95,7 @@ describe('MembersTable', () => {
|
|||
|
||||
const expectCorrectLinkToPage2 = () => {
|
||||
expect(findPagination().findByText('2', { selector: 'a' }).attributes('href')).toBe(
|
||||
`${url}?page=2`,
|
||||
`${url}&invited_members_page=2`,
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -271,7 +274,7 @@ describe('MembersTable', () => {
|
|||
currentPage: 1,
|
||||
perPage: 5,
|
||||
totalItems: 10,
|
||||
paramName: 'page',
|
||||
paramName: 'invited_members_page',
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -279,14 +282,14 @@ describe('MembersTable', () => {
|
|||
});
|
||||
|
||||
it('removes any url params defined as `null` in the `params` attribute', () => {
|
||||
window.location = new URL(`${url}?search_groups=foo`);
|
||||
window.location = new URL(`${url}&search_groups=foo`);
|
||||
|
||||
createComponent({
|
||||
pagination: {
|
||||
currentPage: 1,
|
||||
perPage: 5,
|
||||
totalItems: 10,
|
||||
paramName: 'page',
|
||||
paramName: 'invited_members_page',
|
||||
params: { search_groups: null },
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -153,7 +153,16 @@ describe('LabelsSelect Mutations', () => {
|
|||
});
|
||||
|
||||
describe(`${types.UPDATE_SELECTED_LABELS}`, () => {
|
||||
const labels = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }];
|
||||
let labels;
|
||||
|
||||
beforeEach(() => {
|
||||
labels = [
|
||||
{ id: 1, title: 'scoped::test', set: true },
|
||||
{ id: 2, set: false, title: 'scoped::one' },
|
||||
{ id: 3, title: '' },
|
||||
{ id: 4, title: '' },
|
||||
];
|
||||
});
|
||||
|
||||
it('updates `state.labels` to include `touched` and `set` props based on provided `labels` param', () => {
|
||||
const updatedLabelIds = [2];
|
||||
|
|
@ -169,5 +178,23 @@ describe('LabelsSelect Mutations', () => {
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('when label is scoped', () => {
|
||||
it('unsets the currently selected scoped label and sets the current label', () => {
|
||||
const state = {
|
||||
labels,
|
||||
};
|
||||
mutations[types.UPDATE_SELECTED_LABELS](state, {
|
||||
labels: [{ id: 2, title: 'scoped::one' }],
|
||||
});
|
||||
|
||||
expect(state.labels).toEqual([
|
||||
{ id: 1, title: 'scoped::test', set: false },
|
||||
{ id: 2, set: true, title: 'scoped::one', touched: true },
|
||||
{ id: 3, title: '' },
|
||||
{ id: 4, title: '' },
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -120,7 +120,16 @@ describe('LabelsSelect Mutations', () => {
|
|||
});
|
||||
|
||||
describe(`${types.UPDATE_SELECTED_LABELS}`, () => {
|
||||
const labels = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }];
|
||||
let labels;
|
||||
|
||||
beforeEach(() => {
|
||||
labels = [
|
||||
{ id: 1, title: 'scoped::test', set: true },
|
||||
{ id: 2, set: false, title: 'scoped::one' },
|
||||
{ id: 3, title: '' },
|
||||
{ id: 4, title: '' },
|
||||
];
|
||||
});
|
||||
|
||||
it('updates `state.labels` to include `touched` and `set` props based on provided `labels` param', () => {
|
||||
const updatedLabelIds = [2];
|
||||
|
|
@ -136,5 +145,23 @@ describe('LabelsSelect Mutations', () => {
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('when label is scoped', () => {
|
||||
it('unsets the currently selected scoped label and sets the current label', () => {
|
||||
const state = {
|
||||
labels,
|
||||
};
|
||||
mutations[types.UPDATE_SELECTED_LABELS](state, {
|
||||
labels: [{ id: 2, title: 'scoped::one' }],
|
||||
});
|
||||
|
||||
expect(state.labels).toEqual([
|
||||
{ id: 1, title: 'scoped::test', set: false },
|
||||
{ id: 2, set: true, title: 'scoped::one', touched: true },
|
||||
{ id: 3, title: '' },
|
||||
{ id: 4, title: '' },
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -200,6 +200,8 @@ RSpec.describe 'lograge', type: :request do
|
|||
%w[
|
||||
db_primary_wal_count
|
||||
db_replica_wal_count
|
||||
db_primary_wal_cached_count
|
||||
db_replica_wal_cached_count
|
||||
db_replica_count
|
||||
db_replica_cached_count
|
||||
db_primary_count
|
||||
|
|
|
|||
|
|
@ -203,18 +203,6 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
|
|||
|
||||
expect(rspec_variables['VAR1']).to eq('overridden var 1')
|
||||
end
|
||||
|
||||
context 'when the FF ci_workflow_rules_variables is disabled' do
|
||||
before do
|
||||
stub_feature_flags(ci_workflow_rules_variables: false)
|
||||
end
|
||||
|
||||
it 'sends root variable' do
|
||||
run_chain
|
||||
|
||||
expect(rspec_variables['VAR1']).to eq('var 1')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'N+1 queries' do
|
||||
|
|
|
|||
|
|
@ -250,19 +250,6 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build do
|
|||
{ key: 'VAR4', value: 'new var pipeline 4', public: true }]
|
||||
)
|
||||
end
|
||||
|
||||
context 'when FF ci_workflow_rules_variables is disabled' do
|
||||
before do
|
||||
stub_feature_flags(ci_workflow_rules_variables: false)
|
||||
end
|
||||
|
||||
it 'returns existing yaml variables' do
|
||||
expect(subject[:yaml_variables]).to match_array(
|
||||
[{ key: 'VAR2', value: 'var 2', public: true },
|
||||
{ key: 'VAR3', value: 'var 3', public: true }]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when root_variables_inheritance is false' do
|
||||
|
|
|
|||
|
|
@ -133,7 +133,9 @@ RSpec.describe Gitlab::InstrumentationHelper do
|
|||
db_primary_count: 0,
|
||||
db_primary_cached_count: 0,
|
||||
db_primary_wal_count: 0,
|
||||
db_replica_wal_count: 0)
|
||||
db_replica_wal_count: 0,
|
||||
db_primary_wal_cached_count: 0,
|
||||
db_replica_wal_cached_count: 0)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -150,7 +152,9 @@ RSpec.describe Gitlab::InstrumentationHelper do
|
|||
db_primary_count: 0,
|
||||
db_primary_cached_count: 0,
|
||||
db_primary_wal_count: 0,
|
||||
db_replica_wal_count: 0)
|
||||
db_replica_wal_count: 0,
|
||||
db_primary_wal_cached_count: 0,
|
||||
db_replica_wal_cached_count: 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -183,6 +183,8 @@ RSpec.describe Gitlab::Metrics::Subscribers::ActiveRecord do
|
|||
'SQL' | 'UPDATE users SET admin = true WHERE id = 10' | true | true | false | false
|
||||
'SQL' | 'SELECT pg_current_wal_insert_lsn()::text AS location' | true | false | false | true
|
||||
'SQL' | 'SELECT pg_last_wal_replay_lsn()::text AS location' | true | false | false | true
|
||||
'CACHE' | 'SELECT pg_current_wal_insert_lsn()::text AS location' | true | false | true | true
|
||||
'CACHE' | 'SELECT pg_last_wal_replay_lsn()::text AS location' | true | false | true | true
|
||||
'CACHE' | 'SELECT * FROM users WHERE id = 10' | true | false | true | false
|
||||
'SCHEMA' | "SELECT attr.attname FROM pg_attribute attr INNER JOIN pg_constraint cons ON attr.attrelid = cons.conrelid AND attr.attnum = any(cons.conkey) WHERE cons.contype = 'p' AND cons.conrelid = '\"projects\"'::regclass" | false | false | false | false
|
||||
nil | 'BEGIN' | false | false | false | false
|
||||
|
|
|
|||
|
|
@ -314,7 +314,9 @@ RSpec.describe Gitlab::SidekiqLogging::StructuredLogger do
|
|||
'db_primary_cached_count' => 0,
|
||||
'db_primary_wal_count' => 0,
|
||||
'db_primary_duration_s' => a_value > 0,
|
||||
"db_primary_#{dbname}_duration_s" => a_value > 0
|
||||
"db_primary_#{dbname}_duration_s" => a_value > 0,
|
||||
'db_primary_wal_cached_count' => 0,
|
||||
'db_replica_wal_cached_count' => 0
|
||||
)
|
||||
end
|
||||
|
||||
|
|
@ -336,6 +338,8 @@ RSpec.describe Gitlab::SidekiqLogging::StructuredLogger do
|
|||
'db_primary_count' => 0,
|
||||
'db_primary_cached_count' => 0,
|
||||
'db_primary_wal_count' => 0,
|
||||
'db_primary_wal_cached_count' => 0,
|
||||
'db_replica_wal_cached_count' => 0,
|
||||
'db_primary_duration_s' => 0
|
||||
)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -184,6 +184,7 @@ RSpec.describe PlanLimits do
|
|||
ci_max_artifact_size_junit
|
||||
ci_max_artifact_size_sast
|
||||
ci_max_artifact_size_dast
|
||||
ci_max_artifact_size_running_container_scanning
|
||||
ci_max_artifact_size_codequality
|
||||
ci_max_artifact_size_license_management
|
||||
ci_max_artifact_size_performance
|
||||
|
|
|
|||
|
|
@ -230,22 +230,6 @@ RSpec.describe Ci::CreatePipelineService do
|
|||
[nil, nil, nil, 'job var 4', nil, nil, 'overridden var 7']
|
||||
)
|
||||
end
|
||||
|
||||
context 'when FF ci_workflow_rules_variables is disabled' do
|
||||
before do
|
||||
stub_feature_flags(ci_workflow_rules_variables: false)
|
||||
end
|
||||
|
||||
it 'does not affect workflow variables but job variables' do
|
||||
expect(job1.scoped_variables.to_hash.values_at(*variable_keys)).to eq(
|
||||
['overridden var 1', 'job var 2', nil, 'workflow var 4', 'job var 5', nil, 'workflow var 7']
|
||||
)
|
||||
|
||||
expect(job2.scoped_variables.to_hash.values_at(*variable_keys)).to eq(
|
||||
[nil, nil, nil, 'job var 4', nil, nil, 'overridden var 7']
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when matching to the second rule' do
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ RSpec.shared_examples 'store ActiveRecord info in RequestStore' do |db_role|
|
|||
db_replica_count: 0,
|
||||
db_replica_duration_s: 0.0,
|
||||
db_primary_wal_count: record_wal_query ? 1 : 0,
|
||||
db_primary_wal_cached_count: record_wal_query && record_cached_query ? 1 : 0,
|
||||
db_replica_wal_cached_count: 0,
|
||||
db_replica_wal_count: 0
|
||||
}
|
||||
expected[:"db_primary_#{::Gitlab::Database.dbname(connection)}_duration_s"] = 0.002 if record_query
|
||||
|
|
@ -34,6 +36,8 @@ RSpec.shared_examples 'store ActiveRecord info in RequestStore' do |db_role|
|
|||
db_replica_count: record_query ? 1 : 0,
|
||||
db_replica_duration_s: record_query ? 0.002 : 0,
|
||||
db_replica_wal_count: record_wal_query ? 1 : 0,
|
||||
db_replica_wal_cached_count: record_wal_query && record_cached_query ? 1 : 0,
|
||||
db_primary_wal_cached_count: 0,
|
||||
db_primary_wal_count: 0
|
||||
}
|
||||
expected[:"db_replica_#{::Gitlab::Database.dbname(connection)}_duration_s"] = 0.002 if record_query
|
||||
|
|
@ -91,7 +95,10 @@ RSpec.shared_examples 'record ActiveRecord metrics in a metrics transaction' do
|
|||
end
|
||||
|
||||
if record_wal_query
|
||||
expect(transaction).to receive(:increment).with("gitlab_transaction_db_#{db_role}_wal_count_total".to_sym, 1) if db_role
|
||||
if db_role
|
||||
expect(transaction).to receive(:increment).with("gitlab_transaction_db_#{db_role}_wal_count_total".to_sym, 1)
|
||||
expect(transaction).to receive(:increment).with("gitlab_transaction_db_#{db_role}_wal_cached_count_total".to_sym, 1) if record_cached_query
|
||||
end
|
||||
else
|
||||
expect(transaction).not_to receive(:increment).with("gitlab_transaction_db_#{db_role}_wal_count_total".to_sym, 1) if db_role
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue