Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
e820415cea
commit
bfa1adf977
|
|
@ -556,7 +556,6 @@ Layout/ArgumentAlignment:
|
|||
- 'app/models/packages/cleanup/policy.rb'
|
||||
- 'app/models/packages/conan/metadatum.rb'
|
||||
- 'app/models/packages/debian/file_entry.rb'
|
||||
- 'app/models/packages/debian/file_metadatum.rb'
|
||||
- 'app/models/packages/package.rb'
|
||||
- 'app/models/packages/rpm/metadatum.rb'
|
||||
- 'app/models/pages_domain.rb'
|
||||
|
|
@ -665,7 +664,6 @@ Layout/ArgumentAlignment:
|
|||
- 'app/validators/feature_flag_user_xids_validator.rb'
|
||||
- 'app/workers/gitlab/github_import/stage/import_protected_branches_worker.rb'
|
||||
- 'app/workers/gitlab/jira_import/stuck_jira_import_jobs_worker.rb'
|
||||
- 'app/workers/packages/debian/process_package_file_worker.rb'
|
||||
- 'app/workers/repository_update_remote_mirror_worker.rb'
|
||||
- 'app/workers/run_pipeline_schedule_worker.rb'
|
||||
- 'app/workers/stuck_export_jobs_worker.rb'
|
||||
|
|
|
|||
|
|
@ -186,7 +186,6 @@ Layout/FirstHashElementIndentation:
|
|||
- 'spec/controllers/projects/web_ide_terminals_controller_spec.rb'
|
||||
- 'spec/controllers/projects_controller_spec.rb'
|
||||
- 'spec/factories/ci/builds.rb'
|
||||
- 'spec/factories/packages/debian/file_metadatum.rb'
|
||||
- 'spec/frontend/fixtures/autocomplete_sources.rb'
|
||||
- 'spec/graphql/types/ci/detailed_status_type_spec.rb'
|
||||
- 'spec/helpers/groups/observability_helper_spec.rb'
|
||||
|
|
|
|||
|
|
@ -3534,7 +3534,6 @@ Layout/LineLength:
|
|||
- 'spec/factories/keys.rb'
|
||||
- 'spec/factories/namespaces.rb'
|
||||
- 'spec/factories/notes.rb'
|
||||
- 'spec/factories/packages/debian/file_metadatum.rb'
|
||||
- 'spec/factories/packages/package_files.rb'
|
||||
- 'spec/factories/project_members.rb'
|
||||
- 'spec/factories/projects.rb'
|
||||
|
|
@ -4667,7 +4666,6 @@ Layout/LineLength:
|
|||
- 'spec/models/packages/composer/metadatum_spec.rb'
|
||||
- 'spec/models/packages/conan/metadatum_spec.rb'
|
||||
- 'spec/models/packages/debian/file_entry_spec.rb'
|
||||
- 'spec/models/packages/debian/file_metadatum_spec.rb'
|
||||
- 'spec/models/packages/debian/publication_spec.rb'
|
||||
- 'spec/models/packages/dependency_link_spec.rb'
|
||||
- 'spec/models/packages/dependency_spec.rb'
|
||||
|
|
|
|||
|
|
@ -84,7 +84,6 @@ Lint/SymbolConversion:
|
|||
- 'spec/controllers/jira_connect/branches_controller_spec.rb'
|
||||
- 'spec/factories/ci/reports/codequality_degradations.rb'
|
||||
- 'spec/factories/evidences.rb'
|
||||
- 'spec/factories/packages/debian/file_metadatum.rb'
|
||||
- 'spec/factories/packages/helm/file_metadatum.rb'
|
||||
- 'spec/factories/packages/npm/metadata.rb'
|
||||
- 'spec/features/file_uploads/graphql_add_design_spec.rb'
|
||||
|
|
@ -140,7 +139,6 @@ Lint/SymbolConversion:
|
|||
- 'spec/lib/service_ping/devops_report_spec.rb'
|
||||
- 'spec/models/integrations/prometheus_spec.rb'
|
||||
- 'spec/models/merge_request_diff_commit_spec.rb'
|
||||
- 'spec/models/packages/debian/file_metadatum_spec.rb'
|
||||
- 'spec/models/packages/helm/file_metadatum_spec.rb'
|
||||
- 'spec/models/packages/npm/metadatum_spec.rb'
|
||||
- 'spec/presenters/packages/npm/package_presenter_spec.rb'
|
||||
|
|
|
|||
|
|
@ -374,7 +374,6 @@ Lint/UnusedBlockArgument:
|
|||
- 'spec/models/concerns/each_batch_spec.rb'
|
||||
- 'spec/models/container_repository_spec.rb'
|
||||
- 'spec/models/network/graph_spec.rb'
|
||||
- 'spec/models/packages/debian/file_metadatum_spec.rb'
|
||||
- 'spec/requests/api/ci/pipeline_schedules_spec.rb'
|
||||
- 'spec/requests/api/graphql/gitlab_schema_spec.rb'
|
||||
- 'spec/requests/api/internal/container_registry/migration_spec.rb'
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ Naming/HeredocDelimiterNaming:
|
|||
- 'rubocop/cop/gitlab/predicate_memoization.rb'
|
||||
- 'spec/controllers/projects/pipelines_controller_spec.rb'
|
||||
- 'spec/deprecation_toolkit_env.rb'
|
||||
- 'spec/factories/packages/debian/file_metadatum.rb'
|
||||
- 'spec/features/projects/commit/user_comments_on_commit_spec.rb'
|
||||
- 'spec/features/task_lists_spec.rb'
|
||||
- 'spec/initializers/100_patch_omniauth_oauth2_spec.rb'
|
||||
|
|
|
|||
|
|
@ -2303,7 +2303,6 @@ RSpec/ContextWording:
|
|||
- 'spec/models/notification_setting_spec.rb'
|
||||
- 'spec/models/operations/feature_flag_spec.rb'
|
||||
- 'spec/models/packages/conan/file_metadatum_spec.rb'
|
||||
- 'spec/models/packages/debian/file_metadatum_spec.rb'
|
||||
- 'spec/models/packages/dependency_link_spec.rb'
|
||||
- 'spec/models/packages/dependency_spec.rb'
|
||||
- 'spec/models/packages/package_file_spec.rb'
|
||||
|
|
|
|||
|
|
@ -5264,7 +5264,6 @@ RSpec/MissingFeatureCategory:
|
|||
- 'spec/models/packages/conan/file_metadatum_spec.rb'
|
||||
- 'spec/models/packages/conan/metadatum_spec.rb'
|
||||
- 'spec/models/packages/debian/file_entry_spec.rb'
|
||||
- 'spec/models/packages/debian/file_metadatum_spec.rb'
|
||||
- 'spec/models/packages/debian/group_architecture_spec.rb'
|
||||
- 'spec/models/packages/debian/group_component_file_spec.rb'
|
||||
- 'spec/models/packages/debian/group_component_spec.rb'
|
||||
|
|
|
|||
|
|
@ -285,7 +285,6 @@ Style/ClassAndModuleChildren:
|
|||
- 'app/models/packages/build_info.rb'
|
||||
- 'app/models/packages/conan/file_metadatum.rb'
|
||||
- 'app/models/packages/conan/metadatum.rb'
|
||||
- 'app/models/packages/debian/file_metadatum.rb'
|
||||
- 'app/models/packages/debian/group_architecture.rb'
|
||||
- 'app/models/packages/debian/group_component.rb'
|
||||
- 'app/models/packages/debian/group_component_file.rb'
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
c9c3f444b7d9e54f706552e199f7b9239b0027c5
|
||||
140ee5c9aa5f4fb7dd4a0017677788ee88ce7149
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import {
|
|||
TOKEN_TYPE_WEIGHT,
|
||||
} from '~/vue_shared/components/filtered_search_bar/constants';
|
||||
import FilteredSearch from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
|
||||
import { AssigneeFilterType } from '~/boards/constants';
|
||||
import { AssigneeFilterType, GroupByParamType } from 'ee_else_ce/boards/constants';
|
||||
import { TYPENAME_ITERATION } from '~/graphql_shared/constants';
|
||||
import eventHub from '../eventhub';
|
||||
|
||||
|
|
@ -33,6 +33,11 @@ export default {
|
|||
components: { FilteredSearch },
|
||||
inject: ['initialFilterParams', 'isApolloBoard'],
|
||||
props: {
|
||||
isSwimlanesOn: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
tokens: {
|
||||
type: Array,
|
||||
required: true,
|
||||
|
|
@ -321,6 +326,7 @@ export default {
|
|||
release_tag: releaseTag,
|
||||
confidential,
|
||||
health_status: healthStatus,
|
||||
group_by: this.isSwimlanesOn ? GroupByParamType.epic : undefined,
|
||||
},
|
||||
(value) => {
|
||||
if (value || value === false) {
|
||||
|
|
|
|||
|
|
@ -226,12 +226,10 @@ export default {
|
|||
}
|
||||
this.cancel();
|
||||
|
||||
if (!this.isApolloBoard) {
|
||||
const param = getParameterByName('group_by')
|
||||
? `?group_by=${getParameterByName('group_by')}`
|
||||
: '';
|
||||
updateHistory({ url: `${this.boardBaseUrl}/${getIdFromGraphQLId(board.id)}${param}` });
|
||||
}
|
||||
const param = getParameterByName('group_by')
|
||||
? `?group_by=${getParameterByName('group_by')}`
|
||||
: '';
|
||||
updateHistory({ url: `${this.boardBaseUrl}/${getIdFromGraphQLId(board.id)}${param}` });
|
||||
} catch {
|
||||
this.setError({ message: this.$options.i18n.saveErrorMessage });
|
||||
} finally {
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ export default {
|
|||
<issue-board-filtered-search
|
||||
v-if="isIssueBoard"
|
||||
:board="board"
|
||||
:is-swimlanes-on="isSwimlanesOn"
|
||||
@setFilters="$emit('setFilters', $event)"
|
||||
/>
|
||||
<epic-board-filtered-search
|
||||
|
|
|
|||
|
|
@ -52,6 +52,11 @@ export default {
|
|||
required: false,
|
||||
default: () => {},
|
||||
},
|
||||
isSwimlanesOn: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
tokensCE() {
|
||||
|
|
@ -203,6 +208,7 @@ export default {
|
|||
data-testid="issue-board-filtered-search"
|
||||
:tokens="tokens"
|
||||
:board="board"
|
||||
:is-swimlanes-on="isSwimlanesOn"
|
||||
@setFilters="$emit('setFilters', $event)"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
import { __, s__ } from '~/locale';
|
||||
|
||||
export const GENERIC_ERROR = __('Something went wrong on our end. Please try again!');
|
||||
export const LOAD_SINGLE_DIFF_FAILED = s__(
|
||||
'MergeRequest|Encountered an issue while trying to fetch the single file diff.',
|
||||
);
|
||||
|
||||
export const DIFF_FILE_HEADER = {
|
||||
optionsDropdownTitle: __('Options'),
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ import {
|
|||
TRACKING_SINGLE_FILE_MODE,
|
||||
TRACKING_MULTIPLE_FILES_MODE,
|
||||
} from '../constants';
|
||||
import { LOAD_SINGLE_DIFF_FAILED } from '../i18n';
|
||||
import eventHub from '../event_hub';
|
||||
import { isCollapsed } from '../utils/diff_file';
|
||||
import { markFileReview, setReviewsForMergeRequest } from '../utils/file_reviews';
|
||||
|
|
@ -590,6 +591,31 @@ export const setCurrentFileHash = ({ commit }, hash) => {
|
|||
commit(types.SET_CURRENT_DIFF_FILE, hash);
|
||||
};
|
||||
|
||||
export const goToFile = ({ state, commit, dispatch, getters }, { path }) => {
|
||||
if (!state.viewDiffsFileByFile) {
|
||||
dispatch('scrollToFile', { path });
|
||||
} else {
|
||||
if (!state.treeEntries[path]) return;
|
||||
|
||||
const { fileHash } = state.treeEntries[path];
|
||||
|
||||
commit(types.SET_CURRENT_DIFF_FILE, fileHash);
|
||||
|
||||
if (!getters.isTreePathLoaded(path)) {
|
||||
document.location.hash = fileHash;
|
||||
dispatch('fetchFileByFile')
|
||||
.then(() => {
|
||||
dispatch('scrollToFile', { path });
|
||||
})
|
||||
.catch(() => {
|
||||
createAlert({
|
||||
message: LOAD_SINGLE_DIFF_FAILED,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const scrollToFile = ({ state, commit, getters }, { path }) => {
|
||||
if (!state.treeEntries[path]) return;
|
||||
|
||||
|
|
|
|||
|
|
@ -126,6 +126,26 @@ export const config = {
|
|||
};
|
||||
},
|
||||
},
|
||||
Group: {
|
||||
fields: {
|
||||
projects: {
|
||||
keyArgs: ['includeSubgroups', 'search'],
|
||||
},
|
||||
descendantGroups: {
|
||||
keyArgs: ['includeSubgroups', 'search'],
|
||||
},
|
||||
},
|
||||
},
|
||||
ProjectConnection: {
|
||||
fields: {
|
||||
nodes: concatPagination(),
|
||||
},
|
||||
},
|
||||
GroupConnection: {
|
||||
fields: {
|
||||
nodes: concatPagination(),
|
||||
},
|
||||
},
|
||||
Board: {
|
||||
fields: {
|
||||
epics: {
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ export default {
|
|||
<p class="gl-ml-3 gl-align-self-end gl-line-height-32">{{ __('UTC') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<gl-form-group v-if="glFeatures.incidentEventTags">
|
||||
<gl-form-group>
|
||||
<label class="gl-display-flex gl-align-items-center gl-gap-3" for="timeline-input-tags">
|
||||
{{ $options.i18n.tagsLabel }}
|
||||
<timeline-events-tags-popover />
|
||||
|
|
|
|||
|
|
@ -0,0 +1,78 @@
|
|||
import Vue from 'vue';
|
||||
import { createApolloProvider } from '@vue/apollo-option';
|
||||
import { ApolloMutation } from '@vue/apollo-components';
|
||||
|
||||
export { ApolloMutation };
|
||||
|
||||
const installed = new WeakMap();
|
||||
|
||||
function callLifecycle(hookName, ...extraArgs) {
|
||||
const { GITLAB_INTERNAL_ADDED_MIXINS: addedMixins } = this.$;
|
||||
if (!addedMixins) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return addedMixins.map((m) => m[hookName]?.apply(this, extraArgs));
|
||||
}
|
||||
|
||||
function createMixinForLateInit({ install, shouldInstall }) {
|
||||
return {
|
||||
created() {
|
||||
callLifecycle.call(this, 'created');
|
||||
},
|
||||
// @vue/compat normalizez lifecycle hook names so there is no error here
|
||||
destroyed() {
|
||||
callLifecycle.call(this, 'unmounted');
|
||||
},
|
||||
|
||||
data(...args) {
|
||||
const extraData = callLifecycle.call(this, 'data', ...args);
|
||||
if (!extraData.length) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return Object.assign({}, ...extraData);
|
||||
},
|
||||
|
||||
beforeCreate() {
|
||||
if (shouldInstall(this)) {
|
||||
const { mixins } = this.$.appContext;
|
||||
const globalMixinsBeforeInit = new Set(mixins);
|
||||
install(this);
|
||||
|
||||
this.$.GITLAB_INTERNAL_ADDED_MIXINS = mixins.filter((m) => !globalMixinsBeforeInit.has(m));
|
||||
|
||||
callLifecycle.call(this, 'beforeCreate');
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default class VueCompatApollo {
|
||||
constructor(...args) {
|
||||
// eslint-disable-next-line no-constructor-return
|
||||
return createApolloProvider(...args);
|
||||
}
|
||||
|
||||
static install() {
|
||||
Vue.mixin(
|
||||
createMixinForLateInit({
|
||||
shouldInstall: (vm) =>
|
||||
vm.$options.apolloProvider &&
|
||||
!installed.get(vm.$.appContext.app)?.has(vm.$options.apolloProvider),
|
||||
install: (vm) => {
|
||||
const { app } = vm.$.appContext;
|
||||
const { apolloProvider } = vm.$options;
|
||||
|
||||
if (!installed.has(app)) {
|
||||
installed.set(app, new WeakSet());
|
||||
}
|
||||
|
||||
installed.get(app).add(apolloProvider);
|
||||
|
||||
vm.$.appContext.app.use(vm.$options.apolloProvider);
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -43,6 +43,7 @@ const initRefSwitcher = () => {
|
|||
props: {
|
||||
projectId,
|
||||
value: ref,
|
||||
queryParams: { sort: 'updated_desc' },
|
||||
},
|
||||
on: {
|
||||
input(selectedRef) {
|
||||
|
|
|
|||
|
|
@ -187,6 +187,7 @@ export default {
|
|||
:roles="pushAccessLevels.roles"
|
||||
:users="pushAccessLevels.users"
|
||||
:groups="pushAccessLevels.groups"
|
||||
data-qa-selector="allowed_to_push_content"
|
||||
/>
|
||||
|
||||
<!-- Allowed to merge -->
|
||||
|
|
@ -197,6 +198,7 @@ export default {
|
|||
:roles="mergeAccessLevels.roles"
|
||||
:users="mergeAccessLevels.users"
|
||||
:groups="mergeAccessLevels.groups"
|
||||
data-qa-selector="allowed_to_merge_content"
|
||||
/>
|
||||
|
||||
<!-- Force push -->
|
||||
|
|
|
|||
|
|
@ -101,7 +101,13 @@ export default {
|
|||
|
||||
<div v-if="statusCheckUrl" class="gl-ml-7 gl-flex-grow-1">{{ statusCheckUrl }}</div>
|
||||
|
||||
<div v-for="(item, index) in accessLevels" :key="index" data-testid="access-level">
|
||||
<div
|
||||
v-for="(item, index) in accessLevels"
|
||||
:key="index"
|
||||
data-testid="access-level"
|
||||
data-qa-selector="access_level_content"
|
||||
:data-qa-role="item.accessLevelDescription"
|
||||
>
|
||||
<span v-if="commaSeparateList && index > 0" data-testid="comma-separator">,</span>
|
||||
{{ item.accessLevelDescription }}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -69,9 +69,14 @@ export default {
|
|||
|
||||
<div v-if="!branchRules.length" data-testid="empty">{{ $options.i18n.emptyState }}</div>
|
||||
|
||||
<gl-button v-gl-modal="$options.modalId" class="gl-mt-5" category="secondary" variant="info">{{
|
||||
$options.i18n.addBranchRule
|
||||
}}</gl-button>
|
||||
<gl-button
|
||||
v-gl-modal="$options.modalId"
|
||||
class="gl-mt-5"
|
||||
data-qa-selector="add_branch_rule_button"
|
||||
category="secondary"
|
||||
variant="info"
|
||||
>{{ $options.i18n.addBranchRule }}</gl-button
|
||||
>
|
||||
|
||||
<gl-modal
|
||||
:ref="$options.modalId"
|
||||
|
|
|
|||
|
|
@ -153,7 +153,11 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="gl-border-b gl-pt-5 gl-pb-5 gl-display-flex gl-justify-content-space-between">
|
||||
<div
|
||||
class="gl-border-b gl-pt-5 gl-pb-5 gl-display-flex gl-justify-content-space-between"
|
||||
data-qa-selector="branch_content"
|
||||
:data-qa-branch-name="name"
|
||||
>
|
||||
<div>
|
||||
<strong class="gl-font-monospace">{{ name }}</strong>
|
||||
|
||||
|
|
@ -169,7 +173,7 @@ export default {
|
|||
<li v-for="(detail, index) in approvalDetails" :key="index">{{ detail }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<gl-button class="gl-align-self-start" :href="detailsPath">
|
||||
<gl-button class="gl-align-self-start" data-qa-selector="details_button" :href="detailsPath">
|
||||
{{ $options.i18n.detailsButtonLabel }}</gl-button
|
||||
>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -42,6 +42,11 @@ export default {
|
|||
required: false,
|
||||
default: '',
|
||||
},
|
||||
queryParams: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: () => {},
|
||||
},
|
||||
refType: {
|
||||
type: String,
|
||||
required: false,
|
||||
|
|
@ -93,6 +98,7 @@ export default {
|
|||
matches: (state) => state.matches,
|
||||
lastQuery: (state) => state.query,
|
||||
selectedRef: (state) => state.selectedRef,
|
||||
params: (state) => state.params,
|
||||
}),
|
||||
...mapGetters(['isLoading', 'isQueryPossiblyASha']),
|
||||
i18n() {
|
||||
|
|
@ -186,6 +192,7 @@ export default {
|
|||
this.debouncedSearch = debounce(this.search, SEARCH_DEBOUNCE_MS);
|
||||
|
||||
this.setProjectId(this.projectId);
|
||||
this.setParams(this.queryParams);
|
||||
|
||||
this.$watch(
|
||||
'enabledRefTypes',
|
||||
|
|
@ -206,6 +213,7 @@ export default {
|
|||
...mapActions([
|
||||
'setEnabledRefTypes',
|
||||
'setUseSymbolicRefNames',
|
||||
'setParams',
|
||||
'setProjectId',
|
||||
'setSelectedRef',
|
||||
]),
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import * as types from './mutation_types';
|
|||
export const setEnabledRefTypes = ({ commit }, refTypes) =>
|
||||
commit(types.SET_ENABLED_REF_TYPES, refTypes);
|
||||
|
||||
export const setParams = ({ commit }, params) => commit(types.SET_PARAMS, params);
|
||||
|
||||
export const setUseSymbolicRefNames = ({ commit }, useSymbolicRefNames) =>
|
||||
commit(types.SET_USE_SYMBOLIC_REF_NAMES, useSymbolicRefNames);
|
||||
|
||||
|
|
@ -29,7 +31,7 @@ export const search = ({ state, dispatch, commit }, query) => {
|
|||
export const searchBranches = ({ commit, state }) => {
|
||||
commit(types.REQUEST_START);
|
||||
|
||||
Api.branches(state.projectId, state.query)
|
||||
Api.branches(state.projectId, state.query, state.params)
|
||||
.then((response) => {
|
||||
commit(types.RECEIVE_BRANCHES_SUCCESS, response);
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
export const SET_ENABLED_REF_TYPES = 'SET_ENABLED_REF_TYPES';
|
||||
export const SET_USE_SYMBOLIC_REF_NAMES = 'SET_USE_SYMBOLIC_REF_NAMES';
|
||||
export const SET_PARAMS = 'SET_PARAMS';
|
||||
|
||||
export const SET_PROJECT_ID = 'SET_PROJECT_ID';
|
||||
export const SET_SELECTED_REF = 'SET_SELECTED_REF';
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@ export default {
|
|||
[types.SET_USE_SYMBOLIC_REF_NAMES](state, useSymbolicRefNames) {
|
||||
state.useSymbolicRefNames = useSymbolicRefNames;
|
||||
},
|
||||
[types.SET_PARAMS](state, params) {
|
||||
state.params = params;
|
||||
},
|
||||
[types.SET_PROJECT_ID](state, projectId) {
|
||||
state.projectId = projectId;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -15,5 +15,6 @@ export default () => ({
|
|||
commits: createRefTypeState(),
|
||||
},
|
||||
selectedRef: null,
|
||||
params: null,
|
||||
requestCount: 0,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -137,6 +137,7 @@ export default function setupVueRepositoryList() {
|
|||
props: {
|
||||
projectId,
|
||||
value: ref,
|
||||
queryParams: { sort: 'updated_desc' },
|
||||
},
|
||||
on: {
|
||||
input(selectedRef) {
|
||||
|
|
|
|||
|
|
@ -14,10 +14,10 @@ import PersistentUserCallout from '~/persistent_user_callout';
|
|||
import UserNameGroup from './user_name_group.vue';
|
||||
|
||||
export default {
|
||||
feedbackUrl: 'https://gitlab.com/gitlab-org/gitlab/-/issues/391533',
|
||||
feedbackUrl: 'https://gitlab.com/gitlab-org/gitlab/-/issues/403059',
|
||||
i18n: {
|
||||
newNavigation: {
|
||||
badgeLabel: s__('NorthstarNavigation|Alpha'),
|
||||
badgeLabel: s__('NorthstarNavigation|Beta'),
|
||||
sectionTitle: s__('NorthstarNavigation|Navigation redesign'),
|
||||
},
|
||||
setStatus: s__('SetStatusModal|Set status'),
|
||||
|
|
|
|||
|
|
@ -610,10 +610,6 @@ $system-note-icon-m-left: $avatar-m-left + $icon-size-diff / $avatar-m-ratio;
|
|||
padding: 0;
|
||||
vertical-align: top;
|
||||
white-space: normal;
|
||||
|
||||
// Fixes subpixel rounding issue https://gitlab.com/gitlab-org/gitlab-foss/issues/53973
|
||||
// background-color is needed for dark code preference
|
||||
padding-bottom: 1px;
|
||||
background-color: $white;
|
||||
|
||||
&.parallel {
|
||||
|
|
@ -640,6 +636,14 @@ $system-note-icon-m-left: $avatar-m-left + $icon-size-diff / $avatar-m-ratio;
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.diff-grid-comments:last-child {
|
||||
.notes-content {
|
||||
border-bottom-width: 0;
|
||||
border-bottom-left-radius: #{$border-radius-default - 1px};
|
||||
border-bottom-right-radius: #{$border-radius-default - 1px};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.diffs {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ class Projects::IncidentsController < Projects::ApplicationController
|
|||
push_force_frontend_feature_flag(:work_items, @project&.work_items_feature_flag_enabled?)
|
||||
push_force_frontend_feature_flag(:work_items_mvc, @project&.work_items_mvc_feature_flag_enabled?)
|
||||
push_force_frontend_feature_flag(:work_items_mvc_2, @project&.work_items_mvc_2_feature_flag_enabled?)
|
||||
push_frontend_feature_flag(:incident_event_tags, project)
|
||||
end
|
||||
|
||||
feature_category :incident_management
|
||||
|
|
|
|||
|
|
@ -66,7 +66,6 @@ class Projects::IssuesController < Projects::ApplicationController
|
|||
push_force_frontend_feature_flag(:work_items_mvc, project&.work_items_mvc_feature_flag_enabled?)
|
||||
push_force_frontend_feature_flag(:work_items_mvc_2, project&.work_items_mvc_2_feature_flag_enabled?)
|
||||
push_frontend_feature_flag(:epic_widget_edit_confirmation, project)
|
||||
push_frontend_feature_flag(:incident_event_tags, project)
|
||||
push_frontend_feature_flag(:real_time_issue_due_date, project)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ module Namespaces
|
|||
elsif parent_id.nil?
|
||||
# There is no parent, so we are the root ancestor.
|
||||
self
|
||||
elsif traversal_ids.present?
|
||||
else
|
||||
Namespace.find_by(id: traversal_ids.first)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ module Packages
|
|||
|
||||
EMPTY_FILE_SHA256 = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'.freeze
|
||||
|
||||
INCOMING_PACKAGE_NAME = 'incoming'
|
||||
|
||||
def self.table_name_prefix
|
||||
'packages_debian_'
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,59 +1,69 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Packages::Debian::FileMetadatum < ApplicationRecord
|
||||
self.primary_key = :package_file_id
|
||||
module Packages
|
||||
module Debian
|
||||
class FileMetadatum < ApplicationRecord
|
||||
include UpdatedAtFilterable
|
||||
|
||||
belongs_to :package_file, inverse_of: :debian_file_metadatum
|
||||
self.primary_key = :package_file_id
|
||||
|
||||
validates :package_file, presence: true
|
||||
validate :valid_debian_package_type
|
||||
belongs_to :package_file, inverse_of: :debian_file_metadatum
|
||||
|
||||
enum file_type: {
|
||||
unknown: 1, source: 2, dsc: 3, deb: 4, udeb: 5, buildinfo: 6, changes: 7, ddeb: 8
|
||||
}
|
||||
validates :package_file, presence: true
|
||||
validate :valid_debian_package_type
|
||||
|
||||
validates :file_type, presence: true
|
||||
validates :file_type, inclusion: { in: %w[unknown] },
|
||||
if: -> { package_file&.package&.debian_incoming? || package_file&.package&.processing? }
|
||||
validates :file_type,
|
||||
inclusion: { in: %w[source dsc deb udeb buildinfo changes ddeb] },
|
||||
if: -> { package_file&.package&.debian_package? && !package_file&.package&.processing? }
|
||||
enum file_type: {
|
||||
unknown: 1, source: 2, dsc: 3, deb: 4, udeb: 5, buildinfo: 6, changes: 7, ddeb: 8
|
||||
}
|
||||
|
||||
validates :component,
|
||||
presence: true,
|
||||
format: { with: Gitlab::Regex.debian_component_regex },
|
||||
if: :requires_component?
|
||||
validates :component, absence: true, unless: :requires_component?
|
||||
validates :file_type, presence: true
|
||||
validates :file_type, inclusion: { in: %w[unknown] },
|
||||
if: -> { package_file&.package&.debian_incoming? || package_file&.package&.processing? }
|
||||
validates :file_type,
|
||||
inclusion: { in: %w[source dsc deb udeb buildinfo changes ddeb] },
|
||||
if: -> { package_file&.package&.debian_package? && !package_file&.package&.processing? }
|
||||
|
||||
validates :architecture,
|
||||
presence: true,
|
||||
format: { with: Gitlab::Regex.debian_architecture_regex },
|
||||
if: :requires_architecture?
|
||||
validates :architecture, absence: true, unless: :requires_architecture?
|
||||
validates :component,
|
||||
presence: true,
|
||||
format: { with: Gitlab::Regex.debian_component_regex },
|
||||
if: :requires_component?
|
||||
validates :component, absence: true, unless: :requires_component?
|
||||
|
||||
validates :fields,
|
||||
presence: true,
|
||||
json_schema: { filename: "debian_fields" },
|
||||
if: :requires_fields?
|
||||
validates :fields, absence: true, unless: :requires_fields?
|
||||
validates :architecture,
|
||||
presence: true,
|
||||
format: { with: Gitlab::Regex.debian_architecture_regex },
|
||||
if: :requires_architecture?
|
||||
validates :architecture, absence: true, unless: :requires_architecture?
|
||||
|
||||
private
|
||||
validates :fields,
|
||||
presence: true,
|
||||
json_schema: { filename: "debian_fields" },
|
||||
if: :requires_fields?
|
||||
validates :fields, absence: true, unless: :requires_fields?
|
||||
|
||||
def valid_debian_package_type
|
||||
return if package_file&.package&.debian?
|
||||
scope :with_file_type, ->(file_type) do
|
||||
where(file_type: file_type)
|
||||
end
|
||||
|
||||
errors.add(:package_file, _('Package type must be Debian'))
|
||||
end
|
||||
private
|
||||
|
||||
def requires_architecture?
|
||||
deb? || udeb? || ddeb?
|
||||
end
|
||||
def valid_debian_package_type
|
||||
return if package_file&.package&.debian?
|
||||
|
||||
def requires_component?
|
||||
source? || dsc? || requires_architecture? || buildinfo?
|
||||
end
|
||||
errors.add(:package_file, _('Package type must be Debian'))
|
||||
end
|
||||
|
||||
def requires_fields?
|
||||
dsc? || requires_architecture? || buildinfo? || changes?
|
||||
def requires_architecture?
|
||||
deb? || udeb? || ddeb?
|
||||
end
|
||||
|
||||
def requires_component?
|
||||
source? || dsc? || requires_architecture? || buildinfo?
|
||||
end
|
||||
|
||||
def requires_fields?
|
||||
dsc? || requires_architecture? || buildinfo? || changes?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ class Packages::Package < ApplicationRecord
|
|||
validates :name, format: { with: Gitlab::Regex.nuget_package_name_regex }, if: :nuget?
|
||||
validates :name, format: { with: Gitlab::Regex.terraform_module_package_name_regex }, if: :terraform_module?
|
||||
validates :name, format: { with: Gitlab::Regex.debian_package_name_regex }, if: :debian_package?
|
||||
validates :name, inclusion: { in: %w[incoming] }, if: :debian_incoming?
|
||||
validates :name, inclusion: { in: [Packages::Debian::INCOMING_PACKAGE_NAME] }, if: :debian_incoming?
|
||||
validates :version, format: { with: Gitlab::Regex.nuget_version_regex }, if: :nuget?
|
||||
validates :version, format: { with: Gitlab::Regex.conan_recipe_component_regex }, if: :conan?
|
||||
validates :version, format: { with: Gitlab::Regex.maven_version_regex }, if: -> { version? && maven? }
|
||||
|
|
|
|||
|
|
@ -85,6 +85,13 @@ class Packages::PackageFile < ApplicationRecord
|
|||
.where(packages_debian_file_metadata: { architecture: architecture_name })
|
||||
end
|
||||
|
||||
scope :with_debian_unknown_since, ->(updated_before) do
|
||||
file_metadata = Packages::Debian::FileMetadatum.with_file_type(:unknown)
|
||||
.updated_before(updated_before)
|
||||
.where('packages_package_files.id = packages_debian_file_metadata.package_file_id')
|
||||
where('EXISTS (?)', file_metadata.select(1))
|
||||
end
|
||||
|
||||
scope :with_conan_package_reference, ->(conan_package_reference) do
|
||||
joins(:conan_file_metadatum)
|
||||
.where(packages_conan_file_metadata: { conan_package_reference: conan_package_reference })
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ module Packages
|
|||
module Debian
|
||||
class FindOrCreateIncomingService < ::Packages::CreatePackageService
|
||||
def execute
|
||||
find_or_create_package!(:debian, name: 'incoming', version: nil)
|
||||
find_or_create_package!(:debian, name: ::Packages::Debian::INCOMING_PACKAGE_NAME, version: nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,5 +2,5 @@ Reassigned Issue <%= @issue.iid %>
|
|||
|
||||
<%= url_for([@issue.project, @issue, { only_path: false }]) %>
|
||||
|
||||
Assignee changed <%= "from #{sanitize_name(@previous_assignees.map(&:name).to_sentence)}" if @previous_assignees.any? -%>
|
||||
Assignee changed<%= " from #{sanitize_name(@previous_assignees.map(&:name).to_sentence)}" if @previous_assignees.any? -%>
|
||||
to <%= "#{@issue.assignees.any? ? @issue.assignee_list : 'Unassigned'}" %>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
- show_status_checks = @project.licensed_feature_available?(:external_status_checks)
|
||||
- show_approvers = @project.licensed_feature_available?(:merge_request_approvers)
|
||||
|
||||
%section.settings.no-animate#branch-rules{ class: ('expanded' if expanded) }
|
||||
%section.settings.no-animate#branch-rules{ class: ('expanded' if expanded), data: { qa_selector: 'branch_rules_content' } }
|
||||
.settings-header
|
||||
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only= _('Branch rules')
|
||||
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
.detail-page-description.py-2.gl-display-flex.gl-align-items-center.gl-flex-wrap{ class: "#{'is-merge-request' if moved_mr_sidebar_enabled? && !fluid_layout}" }
|
||||
.detail-page-description.gl-pt-2.gl-pb-4.gl-display-flex.gl-align-items-center.gl-flex-wrap{ class: "#{'is-merge-request' if moved_mr_sidebar_enabled? && !fluid_layout}" }
|
||||
= render 'shared/issuable/status_box', issuable: @merge_request
|
||||
= merge_request_header(@project, @merge_request)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
= c.body do
|
||||
= _('The source project of this merge request has been removed.')
|
||||
|
||||
.detail-page-header.border-bottom-0.pb-0.gl-display-block{ class: "gl-md-display-flex! #{'is-merge-request' if moved_mr_sidebar_enabled? && !fluid_layout}" }
|
||||
.detail-page-header.border-bottom-0.gl-display-block.gl-pt-5{ class: "gl-md-display-flex! #{'is-merge-request' if moved_mr_sidebar_enabled? && !fluid_layout}" }
|
||||
.detail-page-header-body
|
||||
.issuable-meta.gl-display-flex
|
||||
#js-issuable-header-warnings{ data: { hidden: @merge_request.hidden?.to_s } }
|
||||
|
|
|
|||
|
|
@ -579,6 +579,15 @@
|
|||
:weight: 1
|
||||
:idempotent: true
|
||||
:tags: []
|
||||
- :name: cronjob:packages_debian_cleanup_dangling_package_files
|
||||
:worker_name: Packages::Debian::CleanupDanglingPackageFilesWorker
|
||||
:feature_category: :package_registry
|
||||
:has_external_dependencies: false
|
||||
:urgency: :low
|
||||
:resource_boundary: :unknown
|
||||
:weight: 1
|
||||
:idempotent: true
|
||||
:tags: []
|
||||
- :name: cronjob:pages_domain_removal_cron
|
||||
:worker_name: PagesDomainRemovalCronWorker
|
||||
:feature_category: :pages
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Packages
|
||||
module Debian
|
||||
class CleanupDanglingPackageFilesWorker
|
||||
include ApplicationWorker
|
||||
include CronjobQueue # rubocop:disable Scalability/CronWorkerContext
|
||||
|
||||
data_consistency :always
|
||||
|
||||
deduplicate :until_executed
|
||||
idempotent!
|
||||
|
||||
feature_category :package_registry
|
||||
|
||||
THREE_HOUR = 3.hours.freeze
|
||||
BATCH_TIMEOUT = 250.seconds.freeze
|
||||
|
||||
def perform
|
||||
return unless Feature.enabled?(:debian_packages)
|
||||
|
||||
package_files = Packages::PackageFile.with_debian_unknown_since(THREE_HOUR.ago)
|
||||
.installable
|
||||
|
||||
Packages::MarkPackageFilesForDestructionService.new(package_files)
|
||||
.execute(batch_deadline: Time.zone.now + BATCH_TIMEOUT)
|
||||
rescue StandardError => e
|
||||
Gitlab::ErrorTracking.log_exception(e)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -26,7 +26,8 @@ module Packages
|
|||
::Packages::Debian::ProcessPackageFileService.new(package_file, distribution_name, component_name).execute
|
||||
rescue StandardError => e
|
||||
Gitlab::ErrorTracking.log_exception(e, package_file_id: @package_file_id,
|
||||
distribution_name: @distribution_name, component_name: @component_name)
|
||||
distribution_name: @distribution_name, component_name: @component_name)
|
||||
package_file.update_column(:status, :error)
|
||||
package_file.package.update_column(:status, :error)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: incident_event_tags
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107194
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/387647
|
||||
milestone: '15.8'
|
||||
type: development
|
||||
group: group::respond
|
||||
default_enabled: true
|
||||
|
|
@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/390664
|
|||
milestone: '15.9'
|
||||
type: development
|
||||
group: group::optimize
|
||||
default_enabled: false
|
||||
default_enabled: true
|
||||
|
|
|
|||
|
|
@ -682,6 +682,9 @@ Settings.cron_jobs['users_migrate_records_to_ghost_user_in_batches_worker']['job
|
|||
Settings.cron_jobs['ci_runners_stale_machines_cleanup_worker'] ||= Settingslogic.new({})
|
||||
Settings.cron_jobs['ci_runners_stale_machines_cleanup_worker']['cron'] ||= '36 4 * * *'
|
||||
Settings.cron_jobs['ci_runners_stale_machines_cleanup_worker']['job_class'] = 'Ci::Runners::StaleMachinesCleanupCronWorker'
|
||||
Settings.cron_jobs['cleanup_dangling_debian_package_files_worker'] ||= Settingslogic.new({})
|
||||
Settings.cron_jobs['cleanup_dangling_debian_package_files_worker']['cron'] ||= '20 21 * * *'
|
||||
Settings.cron_jobs['cleanup_dangling_debian_package_files_worker']['job_class'] = 'Packages::Debian::CleanupDanglingPackageFilesWorker'
|
||||
|
||||
Gitlab.ee do
|
||||
Settings.cron_jobs['analytics_devops_adoption_create_all_snapshots_worker'] ||= Settingslogic.new({})
|
||||
|
|
|
|||
|
|
@ -324,6 +324,7 @@ if (USE_VUE3) {
|
|||
Object.assign(alias, {
|
||||
vue: '@vue/compat',
|
||||
vuex: path.join(ROOT_PATH, 'app/assets/javascripts/lib/utils/vue3compat/vuex.js'),
|
||||
'vue-apollo': path.join(ROOT_PATH, 'app/assets/javascripts/lib/utils/vue3compat/vue_apollo.js'),
|
||||
});
|
||||
|
||||
vueLoaderOptions.compiler = require.resolve('./vue3migration/compiler');
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddIndexPackagesDebianFileMetadataWhenUnknown < Gitlab::Database::Migration[2.1]
|
||||
disable_ddl_transaction!
|
||||
|
||||
INDEX_NAME = 'i_pkgs_deb_file_meta_on_updated_at_package_file_id_when_unknown'
|
||||
UNKNOWN = 1
|
||||
|
||||
def up
|
||||
add_concurrent_index :packages_debian_file_metadata, [:updated_at, :package_file_id],
|
||||
where: "file_type = #{UNKNOWN}", name: INDEX_NAME
|
||||
end
|
||||
|
||||
def down
|
||||
remove_concurrent_index_by_name :packages_debian_file_metadata, name: INDEX_NAME
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddIndexToVulnerabilityFindingSignaturesOnSignatureSha < Gitlab::Database::Migration[2.1]
|
||||
INDEX_NAME = 'index_vulnerability_finding_signatures_on_signature_sha'
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
add_concurrent_index :vulnerability_finding_signatures, :signature_sha, name: INDEX_NAME
|
||||
end
|
||||
|
||||
def down
|
||||
remove_concurrent_index_by_name :vulnerability_finding_signatures, name: INDEX_NAME
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class DropSoftwareLicensesTempIndex < Gitlab::Database::Migration[2.1]
|
||||
disable_ddl_transaction!
|
||||
|
||||
TABLE_NAME = :software_licenses
|
||||
INDEX_NAME = 'tmp_index_for_software_licenses_spdx_identifier_cleanup'
|
||||
|
||||
def up
|
||||
remove_concurrent_index_by_name(TABLE_NAME, INDEX_NAME)
|
||||
end
|
||||
|
||||
def down
|
||||
add_concurrent_index TABLE_NAME, :spdx_identifier, where: 'spdx_identifier IS NULL', name: INDEX_NAME
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
dd965c40fa107f487bda00d71dfdf40aabd013dd2cb05a4d9621cb1aa87d8060
|
||||
|
|
@ -0,0 +1 @@
|
|||
70c83ed052082e1f37bd46c5abcb0b1b101ea08b719a68d8f39cb7545da97e61
|
||||
|
|
@ -0,0 +1 @@
|
|||
9e9f4b2ed1a56fb3dd780cd22f82eab741639bb972c524984741d4f8cd799e5c
|
||||
|
|
@ -29059,6 +29059,8 @@ CREATE INDEX i_dast_profiles_tags_on_scanner_profiles_id ON dast_profiles_tags U
|
|||
|
||||
CREATE INDEX i_dast_scanner_profiles_tags_on_scanner_profiles_id ON dast_scanner_profiles_tags USING btree (dast_scanner_profile_id);
|
||||
|
||||
CREATE INDEX i_pkgs_deb_file_meta_on_updated_at_package_file_id_when_unknown ON packages_debian_file_metadata USING btree (updated_at, package_file_id) WHERE (file_type = 1);
|
||||
|
||||
CREATE UNIQUE INDEX i_pm_licenses_on_spdx_identifier ON pm_licenses USING btree (spdx_identifier);
|
||||
|
||||
CREATE UNIQUE INDEX i_pm_package_version_licenses_join_ids ON pm_package_version_licenses USING btree (pm_package_version_id, pm_license_id);
|
||||
|
|
@ -32479,6 +32481,8 @@ CREATE INDEX index_vulnerability_feedback_on_pipeline_id ON vulnerability_feedba
|
|||
|
||||
CREATE INDEX index_vulnerability_finding_signatures_on_finding_id ON vulnerability_finding_signatures USING btree (finding_id);
|
||||
|
||||
CREATE INDEX index_vulnerability_finding_signatures_on_signature_sha ON vulnerability_finding_signatures USING btree (signature_sha);
|
||||
|
||||
CREATE INDEX index_vulnerability_findings_remediations_on_remediation_id ON vulnerability_findings_remediations USING btree (vulnerability_remediation_id);
|
||||
|
||||
CREATE UNIQUE INDEX index_vulnerability_findings_remediations_on_unique_keys ON vulnerability_findings_remediations USING btree (vulnerability_occurrence_id, vulnerability_remediation_id);
|
||||
|
|
@ -32755,8 +32759,6 @@ CREATE INDEX tmp_index_for_null_member_namespace_id ON members USING btree (memb
|
|||
|
||||
CREATE INDEX tmp_index_for_project_namespace_id_migration_on_routes ON routes USING btree (id) WHERE ((namespace_id IS NULL) AND ((source_type)::text = 'Project'::text));
|
||||
|
||||
CREATE INDEX tmp_index_for_software_licenses_spdx_identifier_cleanup ON software_licenses USING btree (spdx_identifier) WHERE (spdx_identifier IS NULL);
|
||||
|
||||
CREATE INDEX tmp_index_members_on_state ON members USING btree (state) WHERE (state = 2);
|
||||
|
||||
CREATE INDEX tmp_index_migrated_container_registries ON container_repositories USING btree (project_id) WHERE ((migration_state = 'import_done'::text) OR (created_at >= '2022-01-23 00:00:00'::timestamp without time zone));
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
status: accepted
|
||||
status: implemented
|
||||
creation-date: "2021-02-08"
|
||||
authors: [ "@abrandl" ]
|
||||
coach: "@glopezfernandez"
|
||||
|
|
@ -10,6 +10,11 @@ participating-stages: []
|
|||
|
||||
# Database Testing
|
||||
|
||||
**Notice:** This blueprints has been partially implemented. We still plan to
|
||||
iterate on the tooling. The content below is a historical version of the
|
||||
blueprint, written prior to incorporating database testing into our development
|
||||
workflow.
|
||||
|
||||
We have identified [common themes of reverted migrations](https://gitlab.com/gitlab-org/gitlab/-/issues/233391) and discovered failed migrations breaking in both production and staging even when successfully tested in a developer environment. We have also experienced production incidents even with successful testing in staging. These failures are quite expensive: they can have a significant effect on availability, block deployments, and generate incident escalations. These escalations must be triaged and either reverted or fixed forward. Often, this can take place without the original author's involvement due to time zones and/or the criticality of the escalation. With our increased deployment speeds and stricter uptime requirements, the need for improving database testing is critical, particularly earlier in the development process (shift left).
|
||||
|
||||
From a developer's perspective, it is hard, if not unfeasible, to validate a migration on a large enough dataset before it goes into production.
|
||||
|
|
|
|||
|
|
@ -78,7 +78,8 @@ see [epic 3559](https://gitlab.com/groups/gitlab-org/-/epics/3559).
|
|||
|
||||
### Allow access to your project with a job token
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/346298/) in GitLab 15.9. [Deployed behind the `:inbound_ci_scoped_job_token` feature flag](../../user/feature_flags.md), enabled by default.
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/346298/) in GitLab 15.9. [Deployed behind the `:inbound_ci_scoped_job_token` feature flag](../../user/feature_flags.md), enabled by default.
|
||||
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/346298/) in GitLab 15.10.
|
||||
|
||||
Create an **inbound** allowlist of projects which can access your project through
|
||||
their `CI_JOB_TOKEN`.
|
||||
|
|
|
|||
|
|
@ -113,10 +113,7 @@ Alternatively:
|
|||
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/8741) in GitLab 15.9 [with a flag](../../administration/feature_flags.md) named `incident_event_tags`. Disabled by default.
|
||||
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/387647) in GitLab 15.9.
|
||||
> - [Enabled on self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/387647) in GitLab 15.10.
|
||||
|
||||
FLAG:
|
||||
On self-managed GitLab, by default this feature is available. To hide the feature, ask an administrator to [disable the feature flag](../../administration/feature_flags.md) named `incident_event_tags`.
|
||||
On GitLab.com, this feature is available.
|
||||
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/387647) in GitLab 15.11. Feature flag `incident_event_tags` removed.
|
||||
|
||||
[When creating an event using the form](#using-the-form) or editing it,
|
||||
you can specify incident tags to capture relevant incident timestamps.
|
||||
|
|
|
|||
|
|
@ -35,16 +35,17 @@ the most out of GitLab.
|
|||
| [Take advantage of Git rebase](https://about.gitlab.com/blog/2022/10/06/take-advantage-of-git-rebase/)| Learn how to use the `rebase` command in your workflow. | |
|
||||
| [Git cheat sheet](https://about.gitlab.com/images/press/git-cheat-sheet.pdf) | Download a PDF of common Git commands. | |
|
||||
|
||||
## Plan your work in projects
|
||||
## Plan and track your work
|
||||
|
||||
Your work takes place in a project, from creating code, to planning,
|
||||
collaborating, and more.
|
||||
Create a project to host your code, and plan your work using
|
||||
issues, epics, and more.
|
||||
|
||||
| Topic | Description | Good for beginners |
|
||||
|-------|-------------|--------------------|
|
||||
| [Create a project from a template](https://gitlab.com/projects/new#create_from_template) | Choose a project template and create a project with files to get you started. | |
|
||||
| [Migrate to GitLab](../user/project/import/index.md) | If you are coming to GitLab from another platform, you can import or convert your projects. | |
|
||||
| [Run an agile iteration](agile_sprint.md) | Use group, projects, and iterations to run an agile development iteration. |
|
||||
| [Epics and Issue Boards](https://www.youtube.com/watch?v=I1bFIAQBHB8) | Find out how to use epics and issue boards for project management. | |
|
||||
|
||||
## Use CI/CD pipelines
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ group: Optimize
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Value Streams Dashboard **(ULTIMATE)**
|
||||
# Value Streams Dashboard (Beta) **(ULTIMATE)**
|
||||
|
||||
> Introduced in GitLab 15.8 as a Closed [Beta](../../policy/alpha-beta-support.md#beta-features) feature [with a flag](../../administration/feature_flags.md) named `group_analytics_dashboards_page`. Disabled by default.
|
||||
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ Create the group you want to import to and connect the source GitLab instance:
|
|||
1. Enter the [personal access token](../../../user/profile/personal_access_tokens.md) for your source GitLab instance.
|
||||
1. Select **Connect instance**.
|
||||
|
||||
### Select the groups to import
|
||||
### Select the groups and projects to import
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/385689) in GitLab 15.8, option to import groups with or without projects.
|
||||
|
||||
|
|
@ -220,12 +220,15 @@ Group items that are migrated to the destination GitLab instance include:
|
|||
- Already exists in the destination GitLab instance.
|
||||
- Has a public email in the source GitLab instance that matches a confirmed email in the destination GitLab instance.
|
||||
|
||||
### Migrated project items (beta)
|
||||
### Migrated project items (Beta)
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/267945) in GitLab 14.4 [with a flag](../../feature_flags.md) named `bulk_import_projects`. Disabled by default.
|
||||
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/339941) in GitLab 15.6.
|
||||
> - `bulk_import_projects` feature flag [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/339941) in GitLab 15.10.
|
||||
|
||||
If you choose to migrate projects when you [select groups to migrate](#select-the-groups-and-projects-to-import),
|
||||
project items are migrated with the projects.
|
||||
|
||||
The project items that are migrated depends on the version of GitLab you use on the destination. To determine if a
|
||||
specific project item is migrated:
|
||||
|
||||
|
|
|
|||
|
|
@ -124,21 +124,50 @@ You can install a package from a GitLab project or instance:
|
|||
- **Instance-level**: Use when you have many npm packages in different GitLab groups or in their own namespace.
|
||||
- **Project-level**: Use when you have few npm packages and they are not in the same GitLab group.
|
||||
|
||||
### Authenticate to the Package Registry
|
||||
|
||||
You must authenticate to the Package Registry to install a package from a private project.
|
||||
No authentication is needed if the project is public.
|
||||
|
||||
To authenticate with `npm`:
|
||||
|
||||
```shell
|
||||
npm config set -- //your_domain_name/:_authToken=your_token
|
||||
```
|
||||
|
||||
With npm version 7 or earlier, use the full URL to the endpoint.
|
||||
|
||||
If you're installing:
|
||||
|
||||
- From the instance level:
|
||||
|
||||
```shell
|
||||
npm config set -- //your_domain_name/api/v4/packages/npm/:_authToken=your_token
|
||||
```
|
||||
|
||||
From the project level:
|
||||
|
||||
```shell
|
||||
npm config set -- //your_domain_name/api/v4/projects/your_project_id/packages/npm/:_authToken=your_token
|
||||
```
|
||||
|
||||
In these examples:
|
||||
|
||||
- Replace `your_domain_name` with your domain name, for example, `gitlab.com`.
|
||||
- Replace `your_project_id` is your project ID, found on the project's home page.
|
||||
- Replace `your_token` with a deploy token, group access token, project access token, or personal access token.
|
||||
|
||||
NOTE:
|
||||
Starting with npm version 8, you can [use a URI fragment instead of a full URL](https://docs.npmjs.com/cli/v8/configuring-npm/npmrc?v=true#auth-related-configuration)
|
||||
in the `_authToken` parameter. However, [group-level endpoints](https://gitlab.com/gitlab-org/gitlab/-/issues/299834)
|
||||
are not supported.
|
||||
|
||||
### Install from the instance level
|
||||
|
||||
WARNING:
|
||||
To install a package from the instance level, the package must have been published following the scoped [naming convention](#naming-convention).
|
||||
|
||||
1. Authenticate to the Package Registry
|
||||
|
||||
If you would like to install a package from a private project, you would have to authenticate to the Package Registry. Skip this step if the project is not private.
|
||||
|
||||
```shell
|
||||
npm config set -- //your_domain_name/api/v4/packages/npm/:_authToken=your_token
|
||||
```
|
||||
|
||||
- Replace `your_domain_name` with your domain name, for example, `gitlab.com`.
|
||||
- Replace `your_token` with a deploy token, group access token, project access token, or personal access token.
|
||||
1. [Authenticate to the Package Registry](#authenticate-to-the-package-registry).
|
||||
|
||||
1. Set the registry
|
||||
|
||||
|
|
@ -158,17 +187,7 @@ To install a package from the instance level, the package must have been publish
|
|||
|
||||
### Install from the project level
|
||||
|
||||
1. Authenticate to the Package Registry
|
||||
|
||||
If you would like to install a package from a private project, you would have to authenticate to the Package Registry. Skip this step if the project is not private.
|
||||
|
||||
```shell
|
||||
npm config set -- //your_domain_name/api/v4/projects/your_project_id/packages/npm/:_authToken=your_token
|
||||
```
|
||||
|
||||
- Replace `your_domain_name` with your domain name, for example, `gitlab.com`.
|
||||
- Replace `your_project_id` is your project ID, found on the project's home page.
|
||||
- Replace `your_token` with a deploy token, group access token, project access token, or personal access token.
|
||||
1. [Authenticate to the Package Registry](#authenticate-to-the-package-registry).
|
||||
|
||||
1. Set the registry
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ group: Product Analytics
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Product analytics **(ULTIMATE)**
|
||||
# Product analytics (Alpha) **(ULTIMATE)**
|
||||
|
||||
> - Introduced in GitLab 15.4 as an [Alpha](../../policy/alpha-beta-support.md#alpha-features) feature [with a flag](../../administration/feature_flags.md) named `cube_api_proxy`. Disabled by default.
|
||||
> - `cube_api_proxy` revised to only reference the [Product Analytics API](../../api/product_analytics.md) in GitLab 15.6.
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ module.exports = (path, options = {}) => {
|
|||
|
||||
// Library wrappers
|
||||
'^vuex$': '<rootDir>/app/assets/javascripts/lib/utils/vue3compat/vuex.js',
|
||||
'^vue-apollo$': '<rootDir>/app/assets/javascripts/lib/utils/vue3compat/vue_apollo.js',
|
||||
});
|
||||
Object.assign(globals, {
|
||||
'vue-jest': {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Sidebars
|
||||
module Groups
|
||||
module SuperSidebarMenus
|
||||
class AnalyzeMenu < ::Sidebars::Menu
|
||||
override :title
|
||||
def title
|
||||
s_('Navigation|Analyze')
|
||||
end
|
||||
|
||||
override :sprite_icon
|
||||
def sprite_icon
|
||||
'chart'
|
||||
end
|
||||
|
||||
override :configure_menu_items
|
||||
def configure_menu_items
|
||||
[
|
||||
:cycle_analytics,
|
||||
:ci_cd_analytics,
|
||||
:contribution_analytics,
|
||||
:devops_adoption,
|
||||
:insights,
|
||||
:issues_analytics,
|
||||
:productivity_analytics,
|
||||
:repository_analytics
|
||||
].each { |id| add_item(::Sidebars::NilMenuItem.new(item_id: id)) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Sidebars
|
||||
module Groups
|
||||
module SuperSidebarMenus
|
||||
class BuildMenu < ::Sidebars::Menu
|
||||
override :title
|
||||
def title
|
||||
s_('Navigation|Build')
|
||||
end
|
||||
|
||||
override :sprite_icon
|
||||
def sprite_icon
|
||||
'rocket'
|
||||
end
|
||||
|
||||
override :configure_menu_items
|
||||
def configure_menu_items
|
||||
[
|
||||
:runners
|
||||
].each { |id| add_item(::Sidebars::NilMenuItem.new(item_id: id)) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Sidebars
|
||||
module Groups
|
||||
module SuperSidebarMenus
|
||||
class ManageMenu < ::Sidebars::Menu
|
||||
override :title
|
||||
def title
|
||||
s_('Navigation|Manage')
|
||||
end
|
||||
|
||||
override :sprite_icon
|
||||
def sprite_icon
|
||||
'users'
|
||||
end
|
||||
|
||||
override :configure_menu_items
|
||||
def configure_menu_items
|
||||
[
|
||||
:activity,
|
||||
:members,
|
||||
:labels,
|
||||
:milestones,
|
||||
:iterations
|
||||
].each { |id| add_item(::Sidebars::NilMenuItem.new(item_id: id)) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Sidebars
|
||||
module Groups
|
||||
module SuperSidebarMenus
|
||||
class MonitorMenu < ::Sidebars::Menu
|
||||
override :title
|
||||
def title
|
||||
s_('Navigation|Monitor')
|
||||
end
|
||||
|
||||
override :sprite_icon
|
||||
def sprite_icon
|
||||
'monitor'
|
||||
end
|
||||
|
||||
override :configure_menu_items
|
||||
def configure_menu_items
|
||||
[
|
||||
:explore,
|
||||
:datasources
|
||||
].each { |id| add_item(::Sidebars::NilMenuItem.new(item_id: id)) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -6,13 +6,23 @@ module Sidebars
|
|||
class OperationsMenu < ::Sidebars::Menu
|
||||
override :title
|
||||
def title
|
||||
_('Operations')
|
||||
s_('Navigation|Operate')
|
||||
end
|
||||
|
||||
override :sprite_icon
|
||||
def sprite_icon
|
||||
'deployments'
|
||||
end
|
||||
|
||||
override :configure_menu_items
|
||||
def configure_menu_items
|
||||
[
|
||||
:dependency_proxy,
|
||||
:packages_registry,
|
||||
:container_registry,
|
||||
:group_kubernetes_clusters
|
||||
].each { |id| add_item(::Sidebars::NilMenuItem.new(item_id: id)) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,13 +6,25 @@ module Sidebars
|
|||
class PlanMenu < ::Sidebars::Menu
|
||||
override :title
|
||||
def title
|
||||
_('Plan')
|
||||
s_('Navigation|Plan')
|
||||
end
|
||||
|
||||
override :sprite_icon
|
||||
def sprite_icon
|
||||
'planning'
|
||||
end
|
||||
|
||||
override :configure_menu_items
|
||||
def configure_menu_items
|
||||
[
|
||||
:issue_boards,
|
||||
:epic_boards,
|
||||
:roadmap,
|
||||
:group_wiki,
|
||||
:crm_contacts,
|
||||
:crm_organizations
|
||||
].each { |id| add_item(::Sidebars::NilMenuItem.new(item_id: id)) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Sidebars
|
||||
module Groups
|
||||
module SuperSidebarMenus
|
||||
class SecureMenu < ::Sidebars::Menu
|
||||
override :title
|
||||
def title
|
||||
s_('Navigation|Secure')
|
||||
end
|
||||
|
||||
override :sprite_icon
|
||||
def sprite_icon
|
||||
'shield'
|
||||
end
|
||||
|
||||
override :configure_menu_items
|
||||
def configure_menu_items
|
||||
[
|
||||
:audit_events,
|
||||
:security_dashboard,
|
||||
:vulnerability_report,
|
||||
:compliance,
|
||||
:scan_policies
|
||||
].each { |id| add_item(::Sidebars::NilMenuItem.new(item_id: id)) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -13,15 +13,16 @@ module Sidebars
|
|||
@menus = []
|
||||
|
||||
add_menu(Sidebars::StaticMenu.new(context))
|
||||
add_menu(Sidebars::Groups::SuperSidebarMenus::ManageMenu.new(context))
|
||||
add_menu(Sidebars::Groups::SuperSidebarMenus::PlanMenu.new(context))
|
||||
add_menu(Sidebars::Groups::SuperSidebarMenus::BuildMenu.new(context))
|
||||
add_menu(Sidebars::Groups::SuperSidebarMenus::SecureMenu.new(context))
|
||||
add_menu(Sidebars::Groups::SuperSidebarMenus::OperationsMenu.new(context))
|
||||
add_menu(Sidebars::Groups::SuperSidebarMenus::MonitorMenu.new(context))
|
||||
add_menu(Sidebars::Groups::SuperSidebarMenus::AnalyzeMenu.new(context))
|
||||
|
||||
pick_from_old_menus(old_menus)
|
||||
|
||||
insert_menu_before(
|
||||
Sidebars::Groups::Menus::ObservabilityMenu,
|
||||
Sidebars::Groups::SuperSidebarMenus::OperationsMenu.new(context)
|
||||
)
|
||||
|
||||
insert_menu_before(
|
||||
Sidebars::Groups::Menus::SettingsMenu,
|
||||
Sidebars::UncategorizedMenu.new(context)
|
||||
|
|
|
|||
|
|
@ -38,9 +38,9 @@ module Sidebars
|
|||
{ controller: [:user, :gcp] }
|
||||
end
|
||||
|
||||
override :pick_into_super_sidebar?
|
||||
def pick_into_super_sidebar?
|
||||
true
|
||||
override :serialize_as_menu_item_args
|
||||
def serialize_as_menu_item_args
|
||||
nil
|
||||
end
|
||||
|
||||
private
|
||||
|
|
@ -57,6 +57,7 @@ module Sidebars
|
|||
::Sidebars::MenuItem.new(
|
||||
title: _('Metrics'),
|
||||
link: project_metrics_dashboard_path(context.project),
|
||||
super_sidebar_parent: ::Sidebars::Projects::SuperSidebarMenus::MonitorMenu,
|
||||
active_routes: { path: 'metrics_dashboard#show' },
|
||||
container_html_options: { class: 'shortcuts-metrics' },
|
||||
item_id: :metrics
|
||||
|
|
@ -71,6 +72,7 @@ module Sidebars
|
|||
::Sidebars::MenuItem.new(
|
||||
title: _('Error Tracking'),
|
||||
link: project_error_tracking_index_path(context.project),
|
||||
super_sidebar_parent: ::Sidebars::Projects::SuperSidebarMenus::MonitorMenu,
|
||||
active_routes: { controller: :error_tracking },
|
||||
item_id: :error_tracking
|
||||
)
|
||||
|
|
@ -84,6 +86,7 @@ module Sidebars
|
|||
::Sidebars::MenuItem.new(
|
||||
title: _('Alerts'),
|
||||
link: project_alert_management_index_path(context.project),
|
||||
super_sidebar_parent: ::Sidebars::Projects::SuperSidebarMenus::MonitorMenu,
|
||||
active_routes: { controller: :alert_management },
|
||||
item_id: :alert_management
|
||||
)
|
||||
|
|
@ -97,6 +100,7 @@ module Sidebars
|
|||
::Sidebars::MenuItem.new(
|
||||
title: _('Incidents'),
|
||||
link: project_incidents_path(context.project),
|
||||
super_sidebar_parent: ::Sidebars::Projects::SuperSidebarMenus::MonitorMenu,
|
||||
active_routes: { controller: [:incidents, :incident_management] },
|
||||
item_id: :incidents
|
||||
)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,18 @@ module Sidebars
|
|||
def sprite_icon
|
||||
'monitor'
|
||||
end
|
||||
|
||||
override :configure_menu_items
|
||||
def configure_menu_items
|
||||
[
|
||||
:metrics,
|
||||
:error_tracking,
|
||||
:alert_management,
|
||||
:incidents,
|
||||
:on_call_schedules,
|
||||
:escalation_policies
|
||||
].each { |id| add_item(::Sidebars::NilMenuItem.new(item_id: id)) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -27313,6 +27313,9 @@ msgstr ""
|
|||
msgid "MergeRequest|Compare %{target} and %{source}"
|
||||
msgstr ""
|
||||
|
||||
msgid "MergeRequest|Encountered an issue while trying to fetch the single file diff."
|
||||
msgstr ""
|
||||
|
||||
msgid "MergeRequest|Error dismissing suggestion popover. Please try again."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -29225,6 +29228,9 @@ msgstr ""
|
|||
msgid "NorthstarNavigation|Alpha"
|
||||
msgstr ""
|
||||
|
||||
msgid "NorthstarNavigation|Beta"
|
||||
msgstr ""
|
||||
|
||||
msgid "NorthstarNavigation|Could not update the new navigation preference. Please try again later."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -98,6 +98,8 @@
|
|||
"@tiptap/pm": "^2.0.0-beta.220",
|
||||
"@tiptap/suggestion": "^2.0.0-beta.220",
|
||||
"@tiptap/vue-2": "2.0.0-beta.220",
|
||||
"@vue/apollo-components": "^4.0.0-beta.4",
|
||||
"@vue/apollo-option": "^4.0.0-beta.4",
|
||||
"apollo-upload-client": "15.0.0",
|
||||
"apollo3-cache-persist": "^0.14.1",
|
||||
"autosize": "^5.0.1",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module QA
|
||||
module Page
|
||||
module Project
|
||||
module Settings
|
||||
class BranchRules < Page::Base
|
||||
view 'app/assets/javascripts/projects/settings/repository/branch_rules/app.vue' do
|
||||
element :add_branch_rule_button
|
||||
end
|
||||
|
||||
view 'app/assets/javascripts/projects/settings/repository/branch_rules/components/branch_rule.vue' do
|
||||
element :branch_content
|
||||
element :details_button
|
||||
end
|
||||
|
||||
def click_add_branch_rule
|
||||
click_element(:add_branch_rule_button)
|
||||
click_button('Create protected branch')
|
||||
end
|
||||
|
||||
def navigate_to_branch_rules_details(branch_name)
|
||||
within_element(:branch_content, branch_name: branch_name) do
|
||||
click_element(:details_button)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
QA::Page::Project::Settings::BranchRules.prepend_mod_with('Page::Project::Settings::BranchRules', namespace: QA)
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module QA
|
||||
module Page
|
||||
module Project
|
||||
module Settings
|
||||
class BranchRulesDetails < Page::Base
|
||||
view 'app/assets/javascripts/projects/settings/branch_rules/components/view/index.vue' do
|
||||
element :allowed_to_push_content
|
||||
element :allowed_to_merge_content
|
||||
end
|
||||
|
||||
view 'app/assets/javascripts/projects/settings/branch_rules/components/view/protection_row.vue' do
|
||||
element :access_level_content
|
||||
end
|
||||
|
||||
def has_allowed_to_push?(role)
|
||||
within_element(:allowed_to_push_content) do
|
||||
has_element?(:access_level_content, role: role)
|
||||
end
|
||||
end
|
||||
|
||||
def has_allowed_to_merge?(role)
|
||||
within_element(:allowed_to_merge_content) do
|
||||
has_element?(:access_level_content, role: role)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
QA::Page::Project::Settings::BranchRulesDetails.prepend_mod_with( # rubocop:disable Cop/InjectEnterpriseEditionModule
|
||||
'Page::Project::Settings::BranchRulesDetails', namespace: QA)
|
||||
|
|
@ -27,6 +27,10 @@ module QA
|
|||
element :protected_tag_settings_content
|
||||
end
|
||||
|
||||
view 'app/views/projects/branch_rules/_show.html.haml' do
|
||||
element :branch_rules_content
|
||||
end
|
||||
|
||||
def expand_deploy_tokens(&block)
|
||||
expand_content(:deploy_tokens_settings_content) do
|
||||
Settings::DeployTokens.perform(&block)
|
||||
|
|
@ -57,6 +61,10 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
def expand_branch_rules
|
||||
expand_content(:branch_rules_content)
|
||||
end
|
||||
|
||||
def expand_default_branch(&block)
|
||||
within('#branch-defaults-settings') do
|
||||
find('.btn-default').click do
|
||||
|
|
|
|||
|
|
@ -26,6 +26,9 @@ module QA
|
|||
file.name = "text-#{SecureRandom.hex(8)}.txt"
|
||||
file.content = 'New file'
|
||||
end
|
||||
rescue StandardError => e
|
||||
QA::Runtime::Logger.error("Full failure message: #{e.message}")
|
||||
raise
|
||||
end.not_to raise_error
|
||||
end
|
||||
|
||||
|
|
@ -42,6 +45,9 @@ module QA
|
|||
commit.commit_message = 'Add new file'
|
||||
commit.add_files([{ file_path: "text-#{SecureRandom.hex(8)}.txt", content: 'new file' }])
|
||||
end
|
||||
rescue StandardError => e
|
||||
QA::Runtime::Logger.error("Full failure message: #{e.message}")
|
||||
raise
|
||||
end.not_to raise_error
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -24,6 +24,9 @@ module QA
|
|||
file.name = "text-#{SecureRandom.hex(8)}.txt"
|
||||
file.content = 'New file'
|
||||
end
|
||||
rescue StandardError => e
|
||||
QA::Runtime::Logger.error("Full failure message: #{e.message}")
|
||||
raise
|
||||
end.not_to raise_error
|
||||
end
|
||||
|
||||
|
|
@ -37,6 +40,9 @@ module QA
|
|||
commit.commit_message = 'Add new file'
|
||||
commit.add_files([{ file_path: "text-#{SecureRandom.hex(8)}.txt", content: 'new file' }])
|
||||
end
|
||||
rescue StandardError => e
|
||||
QA::Runtime::Logger.error("Full failure message: #{e.message}")
|
||||
raise
|
||||
end.not_to raise_error
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module QA
|
||||
RSpec.describe 'Create' do
|
||||
describe 'Branch Rules Overview', product_group: :source_code, feature_flag: {
|
||||
name: 'branch_rules',
|
||||
scope: :project
|
||||
} do
|
||||
let(:branch_name) { 'new-branch' }
|
||||
let(:allowed_to_push_role) { Resource::ProtectedBranch::Roles::NO_ONE }
|
||||
let(:allowed_to_merge_role) { Resource::ProtectedBranch::Roles::MAINTAINERS }
|
||||
let(:project) do
|
||||
Resource::Project.fabricate_via_api! do |project|
|
||||
project.name = 'branch-rule-project'
|
||||
project.initialize_with_readme = true
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
Runtime::Feature.enable(:branch_rules, project: project)
|
||||
|
||||
Flow::Login.sign_in
|
||||
|
||||
Resource::Repository::Commit.fabricate_via_api! do |commit|
|
||||
commit.project = project
|
||||
commit.branch = branch_name
|
||||
commit.start_branch = project.default_branch
|
||||
commit.commit_message = 'First commit'
|
||||
commit.add_files([{ file_path: 'new_file.rb', content: '# new content' }])
|
||||
end
|
||||
end
|
||||
|
||||
after do
|
||||
Runtime::Feature.disable(:branch_rules, project: project)
|
||||
end
|
||||
|
||||
it 'adds a new branch rule', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/397587' do
|
||||
project.visit!
|
||||
|
||||
Page::Project::Menu.perform(&:go_to_repository_settings)
|
||||
|
||||
Page::Project::Settings::Repository.perform(&:expand_branch_rules)
|
||||
|
||||
Page::Project::Settings::BranchRules.perform(&:click_add_branch_rule)
|
||||
|
||||
Page::Project::Settings::ProtectedBranches.perform do |settings|
|
||||
settings.select_branch(branch_name)
|
||||
settings.select_allowed_to_push(roles: allowed_to_push_role)
|
||||
settings.select_allowed_to_merge(roles: allowed_to_merge_role)
|
||||
settings.protect_branch
|
||||
end
|
||||
|
||||
Page::Project::Settings::Repository.perform(&:expand_branch_rules)
|
||||
|
||||
Page::Project::Settings::BranchRules.perform do |rules|
|
||||
expect(rules).to have_content(branch_name)
|
||||
rules.navigate_to_branch_rules_details(branch_name)
|
||||
end
|
||||
|
||||
Page::Project::Settings::BranchRulesDetails.perform do |details|
|
||||
aggregate_failures 'branch rules details' do
|
||||
expect(details).to have_allowed_to_push(allowed_to_push_role[:description])
|
||||
expect(details).to have_allowed_to_merge(allowed_to_merge_role[:description])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -6,7 +6,7 @@ FactoryBot.define do
|
|||
file_type { 'deb' }
|
||||
component { 'main' }
|
||||
architecture { 'amd64' }
|
||||
fields { { 'a': 'b' } }
|
||||
fields { { 'a' => 'b' } }
|
||||
|
||||
trait(:unknown) do
|
||||
file_type { 'unknown' }
|
||||
|
|
@ -32,19 +32,20 @@ FactoryBot.define do
|
|||
'Source' => package_file.package.name,
|
||||
'Binary' => 'sample-dev, libsample0, sample-udeb, sample-ddeb',
|
||||
'Architecture' => 'any',
|
||||
'Version': package_file.package.version,
|
||||
'Version' => package_file.package.version,
|
||||
'Maintainer' => "#{FFaker::Name.name} <#{FFaker::Internet.email}>",
|
||||
'Homepage' => FFaker::Internet.http_url,
|
||||
'Standards-Version' => '4.5.0',
|
||||
'Build-Depends' => 'debhelper-compat (= 13)',
|
||||
'Package-List' => <<~EOF.rstrip,
|
||||
libsample0 deb libs optional arch=any',
|
||||
'sample-ddeb deb libs optional arch=any',
|
||||
sample-dev deb libdevel optional arch=any',
|
||||
sample-udeb udeb libs optional arch=any',
|
||||
EOF
|
||||
'Package-List' => <<~PACKAGELIST.rstrip,
|
||||
libsample0 deb libs optional arch=any
|
||||
sample-ddeb deb libs optional arch=any
|
||||
sample-dev deb libdevel optional arch=any
|
||||
sample-udeb udeb libs optional arch=any
|
||||
PACKAGELIST
|
||||
'Checksums-Sha1' => "\n4a9cb2a7c77a68dc0fe54ba8ecef133a7c949e9d 964 sample_1.2.3~alpha2.tar.xz",
|
||||
'Checksums-Sha256' => "\nc9d05185ca158bb804977fa9d7b922e8a0f644a2da41f99d2787dd61b1e2e2c5 964 sample_1.2.3~alpha2.tar.xz",
|
||||
'Checksums-Sha256' =>
|
||||
"\nc9d05185ca158bb804977fa9d7b922e8a0f644a2da41f99d2787dd61b1e2e2c5 964 sample_1.2.3~alpha2.tar.xz",
|
||||
'Files' => "\nadc69e57cda38d9bb7c8d59cacfb6869 964 sample_1.2.3~alpha2.tar.xz"
|
||||
}
|
||||
end
|
||||
|
|
@ -56,22 +57,22 @@ FactoryBot.define do
|
|||
architecture { 'amd64' }
|
||||
fields do
|
||||
{
|
||||
'Package' => 'libsample0',
|
||||
'Source' => package_file.package.name,
|
||||
'Version' => package_file.package.version,
|
||||
'Architecture' => 'amd64',
|
||||
'Maintainer' => "#{FFaker::Name.name} <#{FFaker::Internet.email}>",
|
||||
'Installed-Size' => '7',
|
||||
'Section' => 'libs',
|
||||
'Priority' => 'optional',
|
||||
'Multi-Arch' => 'same',
|
||||
'Homepage' => FFaker::Internet.http_url,
|
||||
'Description' => <<~EOF.rstrip
|
||||
Some mostly empty lib
|
||||
Used in GitLab tests.
|
||||
'Package' => 'libsample0',
|
||||
'Source' => package_file.package.name,
|
||||
'Version' => package_file.package.version,
|
||||
'Architecture' => 'amd64',
|
||||
'Maintainer' => "#{FFaker::Name.name} <#{FFaker::Internet.email}>",
|
||||
'Installed-Size' => '7',
|
||||
'Section' => 'libs',
|
||||
'Priority' => 'optional',
|
||||
'Multi-Arch' => 'same',
|
||||
'Homepage' => FFaker::Internet.http_url,
|
||||
'Description' => <<~DESCRIPTION.rstrip
|
||||
Some mostly empty lib
|
||||
Used in GitLab tests.
|
||||
|
||||
Testing another paragraph.
|
||||
EOF
|
||||
Testing another paragraph.
|
||||
DESCRIPTION
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
@ -93,12 +94,12 @@ FactoryBot.define do
|
|||
'Priority' => 'optional',
|
||||
'Multi-Arch' => 'same',
|
||||
'Homepage' => FFaker::Internet.http_url,
|
||||
'Description' => <<~EOF.rstrip
|
||||
'Description' => <<~DESCRIPTION.rstrip
|
||||
Some mostly empty development files
|
||||
Used in GitLab tests.
|
||||
|
||||
Testing another paragraph.
|
||||
EOF
|
||||
DESCRIPTION
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
@ -107,28 +108,28 @@ FactoryBot.define do
|
|||
file_type { 'udeb' }
|
||||
component { 'main' }
|
||||
architecture { 'amd64' }
|
||||
fields { { 'a': 'b' } }
|
||||
fields { { 'a' => 'b' } }
|
||||
end
|
||||
|
||||
trait(:ddeb) do
|
||||
file_type { 'ddeb' }
|
||||
component { 'main' }
|
||||
architecture { 'amd64' }
|
||||
fields { { 'a': 'b' } }
|
||||
fields { { 'a' => 'b' } }
|
||||
end
|
||||
|
||||
trait(:buildinfo) do
|
||||
file_type { 'buildinfo' }
|
||||
component { 'main' }
|
||||
architecture { nil }
|
||||
fields { { 'Architecture': 'amd64 source' } }
|
||||
fields { { 'Architecture' => 'amd64 source' } }
|
||||
end
|
||||
|
||||
trait(:changes) do
|
||||
file_type { 'changes' }
|
||||
component { nil }
|
||||
architecture { nil }
|
||||
fields { { 'Architecture': 'source amd64' } }
|
||||
fields { { 'Architecture' => 'source amd64' } }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -215,6 +215,7 @@ FactoryBot.define do
|
|||
end
|
||||
|
||||
trait(:keep) do
|
||||
# do not override attributes
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -43,9 +43,7 @@ RSpec.describe 'Incident timeline events', :js, feature_category: :incident_mana
|
|||
expect(page).to have_content(s_('Incident|No timeline items have been added yet.'))
|
||||
end
|
||||
|
||||
it 'submits event data on save with feature flag on' do
|
||||
stub_feature_flags(incident_event_tags: true)
|
||||
|
||||
it 'submits event data on save' do
|
||||
# Add event
|
||||
click_button(s_('Incident|Add new timeline event'))
|
||||
|
||||
|
|
|
|||
|
|
@ -294,7 +294,9 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
|
|||
end
|
||||
end
|
||||
|
||||
context 'with valid username/password' do
|
||||
# Freeze time to prevent failures when time between code being entered and
|
||||
# validated greater than otp_allowed_drift
|
||||
context 'with valid username/password', :freeze_time do
|
||||
let(:user) { create(:user, :two_factor) }
|
||||
|
||||
before do
|
||||
|
|
@ -321,8 +323,7 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
|
|||
end
|
||||
|
||||
context 'using one-time code' do
|
||||
it 'allows login with valid code',
|
||||
quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/402322' do
|
||||
it 'allows login with valid code' do
|
||||
expect(authentication_metrics)
|
||||
.to increment(:user_authenticated_counter)
|
||||
.and increment(:user_two_factor_authenticated_counter)
|
||||
|
|
@ -348,8 +349,7 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
|
|||
expect(page).to have_content('Invalid two-factor code')
|
||||
end
|
||||
|
||||
it 'allows login with invalid code, then valid code',
|
||||
quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/402322' do
|
||||
it 'allows login with invalid code, then valid code' do
|
||||
expect(authentication_metrics)
|
||||
.to increment(:user_authenticated_counter)
|
||||
.and increment(:user_two_factor_authenticated_counter)
|
||||
|
|
@ -363,8 +363,7 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
|
|||
expect(page).to have_current_path root_path, ignore_query: true
|
||||
end
|
||||
|
||||
it 'triggers ActiveSession.cleanup for the user',
|
||||
quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/402322' do
|
||||
it 'triggers ActiveSession.cleanup for the user' do
|
||||
expect(authentication_metrics)
|
||||
.to increment(:user_authenticated_counter)
|
||||
.and increment(:user_two_factor_authenticated_counter)
|
||||
|
|
@ -421,8 +420,10 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
|
|||
end
|
||||
end
|
||||
|
||||
context 'when two factor authentication is required' do
|
||||
it 'shows 2FA prompt after OAuth login', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/402615' do
|
||||
# Freeze time to prevent failures when time between code being entered and
|
||||
# validated greater than otp_allowed_drift
|
||||
context 'when two factor authentication is required', :freeze_time do
|
||||
it 'shows 2FA prompt after OAuth login' do
|
||||
expect(authentication_metrics)
|
||||
.to increment(:user_authenticated_counter)
|
||||
.and increment(:user_two_factor_authenticated_counter)
|
||||
|
|
@ -613,23 +614,21 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
|
|||
end
|
||||
|
||||
context 'within the grace period' do
|
||||
it 'redirects to two-factor configuration page' do
|
||||
freeze_time do
|
||||
expect(authentication_metrics)
|
||||
.to increment(:user_authenticated_counter)
|
||||
it 'redirects to two-factor configuration page', :freeze_time do
|
||||
expect(authentication_metrics)
|
||||
.to increment(:user_authenticated_counter)
|
||||
|
||||
gitlab_sign_in(user)
|
||||
gitlab_sign_in(user)
|
||||
|
||||
expect(page).to have_current_path profile_two_factor_auth_path, ignore_query: true
|
||||
expect(page).to have_content(
|
||||
'The group settings for Group 1 and Group 2 require you to enable '\
|
||||
'Two-Factor Authentication for your account. '\
|
||||
'You can leave Group 1 and leave Group 2. '\
|
||||
'You need to do this '\
|
||||
'before '\
|
||||
"#{(Time.zone.now + 2.days).strftime("%a, %d %b %Y %H:%M:%S %z")}"
|
||||
)
|
||||
end
|
||||
expect(page).to have_current_path profile_two_factor_auth_path, ignore_query: true
|
||||
expect(page).to have_content(
|
||||
'The group settings for Group 1 and Group 2 require you to enable '\
|
||||
'Two-Factor Authentication for your account. '\
|
||||
'You can leave Group 1 and leave Group 2. '\
|
||||
'You need to do this '\
|
||||
'before '\
|
||||
"#{(Time.zone.now + 2.days).strftime("%a, %d %b %Y %H:%M:%S %z")}"
|
||||
)
|
||||
end
|
||||
|
||||
it 'allows skipping two-factor configuration', :js do
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import {
|
|||
INLINE_DIFF_VIEW_TYPE,
|
||||
PARALLEL_DIFF_VIEW_TYPE,
|
||||
} from '~/diffs/constants';
|
||||
import { LOAD_SINGLE_DIFF_FAILED } from '~/diffs/i18n';
|
||||
import * as diffActions from '~/diffs/store/actions';
|
||||
import * as types from '~/diffs/store/mutation_types';
|
||||
import * as utils from '~/diffs/store/utils';
|
||||
|
|
@ -994,6 +995,87 @@ describe('DiffsStoreActions', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('goToFile', () => {
|
||||
const getters = {};
|
||||
const file = { path: 'path' };
|
||||
const fileHash = 'test';
|
||||
let state;
|
||||
let dispatch;
|
||||
let commit;
|
||||
|
||||
beforeEach(() => {
|
||||
getters.isTreePathLoaded = () => false;
|
||||
state = {
|
||||
viewDiffsFileByFile: true,
|
||||
treeEntries: {
|
||||
path: {
|
||||
fileHash,
|
||||
},
|
||||
},
|
||||
};
|
||||
commit = jest.fn();
|
||||
dispatch = jest.fn().mockResolvedValue();
|
||||
});
|
||||
|
||||
it('immediately defers to scrollToFile if the app is not in file-by-file mode', () => {
|
||||
state.viewDiffsFileByFile = false;
|
||||
|
||||
diffActions.goToFile({ state, dispatch }, file);
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith('scrollToFile', file);
|
||||
});
|
||||
|
||||
describe('when the app is in fileByFile mode', () => {
|
||||
it('commits SET_CURRENT_DIFF_FILE', () => {
|
||||
diffActions.goToFile({ state, commit, dispatch, getters }, file);
|
||||
|
||||
expect(commit).toHaveBeenCalledWith(types.SET_CURRENT_DIFF_FILE, fileHash);
|
||||
});
|
||||
|
||||
it('does nothing more if the path has already been loaded', () => {
|
||||
getters.isTreePathLoaded = () => true;
|
||||
|
||||
diffActions.goToFile({ state, dispatch, getters, commit }, file);
|
||||
|
||||
expect(commit).toHaveBeenCalledWith(types.SET_CURRENT_DIFF_FILE, fileHash);
|
||||
expect(dispatch).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
describe('when the tree entry has not been loaded', () => {
|
||||
it('updates location hash', () => {
|
||||
diffActions.goToFile({ state, commit, getters, dispatch }, file);
|
||||
|
||||
expect(document.location.hash).toBe('#test');
|
||||
});
|
||||
|
||||
it('loads the file and then scrolls to it', async () => {
|
||||
diffActions.goToFile({ state, commit, getters, dispatch }, file);
|
||||
|
||||
// Wait for the fetchFileByFile dispatch to return, to trigger scrollToFile
|
||||
await waitForPromises();
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith('fetchFileByFile');
|
||||
expect(dispatch).toHaveBeenCalledWith('scrollToFile', file);
|
||||
expect(dispatch).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('shows an alert when there was an error fetching the file', async () => {
|
||||
dispatch = jest.fn().mockRejectedValue();
|
||||
|
||||
diffActions.goToFile({ state, commit, getters, dispatch }, file);
|
||||
|
||||
// Wait for the fetchFileByFile dispatch to return, to trigger the catch
|
||||
await waitForPromises();
|
||||
|
||||
expect(createAlert).toHaveBeenCalledTimes(1);
|
||||
expect(createAlert).toHaveBeenCalledWith({
|
||||
message: expect.stringMatching(LOAD_SINGLE_DIFF_FAILED),
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('scrollToFile', () => {
|
||||
let commit;
|
||||
const getters = { isVirtualScrollingEnabled: false };
|
||||
|
|
|
|||
|
|
@ -86,7 +86,6 @@ describe('Create Timeline events', () => {
|
|||
provide: {
|
||||
fullPath: 'group/project',
|
||||
issuableId: '1',
|
||||
glFeatures: { incidentEventTags: true },
|
||||
},
|
||||
apolloProvider,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -113,17 +113,7 @@ describe('Timeline events form', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
describe('with incident_event_tag feature flag enabled', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent(
|
||||
{},
|
||||
{},
|
||||
{
|
||||
incidentEventTags: true,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe('Event Tags', () => {
|
||||
describe('event tags listbox', () => {
|
||||
it('should render option list from provided array', () => {
|
||||
expect(findTagsListbox().props('items')).toEqual(mockTags);
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ describe('Ref selector component', () => {
|
|||
const projectId = '8';
|
||||
const totalBranchesCount = 123;
|
||||
const totalTagsCount = 456;
|
||||
const queryParams = { sort: 'updated_desc' };
|
||||
|
||||
let wrapper;
|
||||
let branchesApiCallSpy;
|
||||
|
|
@ -738,4 +739,25 @@ describe('Ref selector component', () => {
|
|||
expect(lastCallProps.matches).toMatchObject(expectedMatches);
|
||||
});
|
||||
});
|
||||
describe('when queryParam prop is present', () => {
|
||||
it('passes params to a branches API call', () => {
|
||||
createComponent({ propsData: { queryParams } });
|
||||
|
||||
return waitForRequests().then(() => {
|
||||
expect(branchesApiCallSpy).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ params: { per_page: 20, search: '', sort: queryParams.sort } }),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('does not pass params to tags API call', () => {
|
||||
createComponent({ propsData: { queryParams } });
|
||||
|
||||
return waitForRequests().then(() => {
|
||||
expect(tagsApiCallSpy).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ params: { per_page: 20, search: '' } }),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -52,6 +52,13 @@ describe('Ref selector Vuex store actions', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('setParams', () => {
|
||||
it(`commits ${types.SET_PARAMS} with the provided params`, () => {
|
||||
const params = { sort: 'updated_asc' };
|
||||
testAction(actions.setParams, params, state, [{ type: types.SET_PARAMS, payload: params }]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('search', () => {
|
||||
it(`commits ${types.SET_QUERY} with the new search query`, () => {
|
||||
const query = 'hello';
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ describe('Ref selector Vuex store mutations', () => {
|
|||
error: null,
|
||||
},
|
||||
},
|
||||
params: null,
|
||||
selectedRef: null,
|
||||
requestCount: 0,
|
||||
});
|
||||
|
|
@ -56,6 +57,15 @@ describe('Ref selector Vuex store mutations', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe(`${types.SET_PARAMS}`, () => {
|
||||
it('sets the additional query params', () => {
|
||||
const params = { sort: 'updated_desc' };
|
||||
mutations[types.SET_PARAMS](state, params);
|
||||
|
||||
expect(state.params).toBe(params);
|
||||
});
|
||||
});
|
||||
|
||||
describe(`${types.SET_PROJECT_ID}`, () => {
|
||||
it('updates the project ID', () => {
|
||||
const newProjectId = '4';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::Groups::SuperSidebarMenus::AnalyzeMenu, feature_category: :navigation do
|
||||
subject { described_class.new({}) }
|
||||
|
||||
let(:items) { subject.instance_variable_get(:@items) }
|
||||
|
||||
it 'has title and sprite_icon' do
|
||||
expect(subject.title).to eq(s_("Navigation|Analyze"))
|
||||
expect(subject.sprite_icon).to eq("chart")
|
||||
end
|
||||
|
||||
it 'defines list of NilMenuItem placeholders' do
|
||||
expect(items.map(&:class).uniq).to eq([Sidebars::NilMenuItem])
|
||||
expect(items.map(&:item_id)).to eq([
|
||||
:cycle_analytics,
|
||||
:ci_cd_analytics,
|
||||
:contribution_analytics,
|
||||
:devops_adoption,
|
||||
:insights,
|
||||
:issues_analytics,
|
||||
:productivity_analytics,
|
||||
:repository_analytics
|
||||
])
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::Groups::SuperSidebarMenus::BuildMenu, feature_category: :navigation do
|
||||
subject { described_class.new({}) }
|
||||
|
||||
let(:items) { subject.instance_variable_get(:@items) }
|
||||
|
||||
it 'has title and sprite_icon' do
|
||||
expect(subject.title).to eq(s_("Navigation|Build"))
|
||||
expect(subject.sprite_icon).to eq("rocket")
|
||||
end
|
||||
|
||||
it 'defines list of NilMenuItem placeholders' do
|
||||
expect(items.map(&:class).uniq).to eq([Sidebars::NilMenuItem])
|
||||
expect(items.map(&:item_id)).to eq([
|
||||
:runners
|
||||
])
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::Groups::SuperSidebarMenus::ManageMenu, feature_category: :navigation do
|
||||
subject { described_class.new({}) }
|
||||
|
||||
let(:items) { subject.instance_variable_get(:@items) }
|
||||
|
||||
it 'has title and sprite_icon' do
|
||||
expect(subject.title).to eq(s_("Navigation|Manage"))
|
||||
expect(subject.sprite_icon).to eq("users")
|
||||
end
|
||||
|
||||
it 'defines list of NilMenuItem placeholders' do
|
||||
expect(items.map(&:class).uniq).to eq([Sidebars::NilMenuItem])
|
||||
expect(items.map(&:item_id)).to eq([
|
||||
:activity,
|
||||
:members,
|
||||
:labels,
|
||||
:milestones,
|
||||
:iterations
|
||||
])
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::Groups::SuperSidebarMenus::MonitorMenu, feature_category: :navigation do
|
||||
subject { described_class.new({}) }
|
||||
|
||||
let(:items) { subject.instance_variable_get(:@items) }
|
||||
|
||||
it 'has title and sprite_icon' do
|
||||
expect(subject.title).to eq(s_("Navigation|Monitor"))
|
||||
expect(subject.sprite_icon).to eq("monitor")
|
||||
end
|
||||
|
||||
it 'defines list of NilMenuItem placeholders' do
|
||||
expect(items.map(&:class).uniq).to eq([Sidebars::NilMenuItem])
|
||||
expect(items.map(&:item_id)).to eq([
|
||||
:explore,
|
||||
:datasources
|
||||
])
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::Groups::SuperSidebarMenus::OperationsMenu, feature_category: :navigation do
|
||||
subject { described_class.new({}) }
|
||||
|
||||
let(:items) { subject.instance_variable_get(:@items) }
|
||||
|
||||
it 'has title and sprite_icon' do
|
||||
expect(subject.title).to eq(s_("Navigation|Operate"))
|
||||
expect(subject.sprite_icon).to eq("deployments")
|
||||
end
|
||||
|
||||
it 'defines list of NilMenuItem placeholders' do
|
||||
expect(items.map(&:class).uniq).to eq([Sidebars::NilMenuItem])
|
||||
expect(items.map(&:item_id)).to eq([
|
||||
:dependency_proxy,
|
||||
:packages_registry,
|
||||
:container_registry,
|
||||
:group_kubernetes_clusters
|
||||
])
|
||||
end
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue