Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-02-14 12:12:55 +00:00
parent 336b65a1c7
commit 2389653f0e
105 changed files with 1174 additions and 424 deletions

View File

@ -264,7 +264,20 @@ include:
- remote: 'https://gitlab.com/gitlab-org/frontend/untamper-my-lockfile/-/raw/main/templates/merge_request_pipelines.yml'
rules:
- <<: *if-not-security-canonical-sync
- local: .gitlab/ci/gitlab-com/*.gitlab-ci.yml
- local: .gitlab/ci/includes/gitlab-com/*.gitlab-ci.yml
rules:
- if: '$CI_SERVER_HOST == "gitlab.com"'
- if: '$CI_SERVER_HOST == "jihulab.com"'
- local: .gitlab/ci/includes/as-if-jh.gitlab-ci.yml
rules:
# Only run as-if-jh triggerred pipelines for gitlab.com/gitlab-org/gitlab MRs that don't target stable branches
# and that don't have the quarantine or pipeline:expedite labels.
- if: '$CI_PROJECT_URL != "https://gitlab.com/gitlab-org/gitlab"'
when: never
- if: '$CI_MERGE_REQUEST_ID == null'
when: never
- if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME =~ /^[\d-]+-stable(-ee|-jh)?$/'
when: never
- if: '$CI_MERGE_REQUEST_LABELS =~ /quarantine/ || $CI_MERGE_REQUEST_LABELS =~ /pipeline:expedite/'
when: never
- when: always

View File

@ -462,9 +462,10 @@ lib/gitlab/checks/**
# Begin rake-managed-docs-block
/doc/administration/analytics/ @lciutacu
/doc/administration/application_settings_cache.md @jglassman1
/doc/administration/audit_event_reports.md @eread
/doc/administration/audit_event_schema.md @eread
/doc/administration/audit_event_streaming/ @eread
/doc/administration/audit_events.md @eread
/doc/administration/audit_reports.md @eread
/doc/administration/audit_event_types.md @eread
/doc/administration/auditor_users.md @jglassman1
/doc/administration/auth/ @jglassman1
/doc/administration/backup_restore/ @axil
@ -562,6 +563,7 @@ lib/gitlab/checks/**
/doc/administration/settings/project_integration_management.md @eread @ashrafkhamis
/doc/administration/settings/push_event_activities_limit.md @msedlakjakubowski
/doc/administration/settings/rate_limit_on_issues_creation.md @msedlakjakubowski
/doc/administration/settings/rate_limit_on_members_api.md @lciutacu
/doc/administration/settings/rate_limit_on_notes_creation.md @msedlakjakubowski
/doc/administration/settings/rate_limit_on_pipelines_creation.md @marcel.amirault @lyspin
/doc/administration/settings/rate_limit_on_projects_api.md @lciutacu
@ -814,6 +816,7 @@ lib/gitlab/checks/**
/doc/integration/akismet.md @phillipwells
/doc/integration/arkose.md @phillipwells
/doc/integration/datadog.md @eread @ashrafkhamis
/doc/integration/diffblue_cover.md @marcel.amirault @lyspin
/doc/integration/external-issue-tracker.md @eread @ashrafkhamis
/doc/integration/gitpod.md @ashrafkhamis
/doc/integration/gmail_action_buttons_for_gitlab.md @eread @ashrafkhamis
@ -872,6 +875,7 @@ lib/gitlab/checks/**
/doc/user/compliance/compliance_center/ @eread
/doc/user/compliance/index.md @eread
/doc/user/custom_roles.md @jglassman1
/doc/user/custom_roles/ @jglassman1
/doc/user/discussions/ @aqualls
/doc/user/emoji_reactions.md @msedlakjakubowski
/doc/user/enterprise_user/ @jglassman1
@ -885,7 +889,6 @@ lib/gitlab/checks/**
/doc/user/group/epics/ @msedlakjakubowski
/doc/user/group/import/ @eread @ashrafkhamis
/doc/user/group/index.md @lciutacu
/doc/user/group/insights/ @lciutacu
/doc/user/group/issues_analytics/ @lciutacu
/doc/user/group/iterations/ @msedlakjakubowski
/doc/user/group/manage.md @lciutacu
@ -935,6 +938,8 @@ lib/gitlab/checks/**
/doc/user/project/index.md @lciutacu
/doc/user/project/insights/ @lciutacu
/doc/user/project/integrations/ @eread @ashrafkhamis
/doc/user/project/integrations/beyond_identity.md @msedlakjakubowski
/doc/user/project/integrations/git_guardian.md @msedlakjakubowski
/doc/user/project/issues/csv_import.md @eread @ashrafkhamis
/doc/user/project/members/ @lciutacu
/doc/user/project/merge_requests/ @aqualls
@ -945,6 +950,8 @@ lib/gitlab/checks/**
/doc/user/project/merge_requests/reviews/data_usage.md @sselhorn
/doc/user/project/merge_requests/squash_and_merge.md @msedlakjakubowski
/doc/user/project/merge_requests/status_checks.md @eread
/doc/user/project/ml/experiment_tracking/ @sselhorn
/doc/user/project/ml/model_registry/ @sselhorn
/doc/user/project/organize_work_with_projects.md @lciutacu
/doc/user/project/releases/ @phillipwells
/doc/user/project/releases/release_evidence.md @eread
@ -958,6 +965,7 @@ lib/gitlab/checks/**
/doc/user/project/settings/migrate_projects.md @lciutacu
/doc/user/project/settings/project_access_tokens.md @jglassman1
/doc/user/project/settings/project_features_permissions.md @lciutacu
/doc/user/project/troubleshooting.md @lciutacu
/doc/user/project/use_project_as_go_package.md @lciutacu
/doc/user/project/web_ide/ @ashrafkhamis
/doc/user/project/working_with_projects.md @lciutacu

View File

@ -15,6 +15,7 @@ prepare-as-if-foss-branch:
before_script:
- git clone --single-branch --branch master "${FOSS_REPOSITORY}" gitlab-foss
- git -C gitlab-foss checkout -b "${AS_IF_FOSS_BRANCH}" master
- git -C gitlab-foss rev-parse HEAD
- rm -r .git/
- mv gitlab-foss/.git .
- rm -r gitlab-foss
@ -29,7 +30,9 @@ prepare-as-if-foss-branch:
- rm -f CHANGELOG-EE.md
- rm -f changelogs/*-ee.md
- git add -A
- git commit -m 'Update from merge request' # TODO: Mark which SHA we add
# --allow-empty accounts for the edge case where FOSS matchess EE repository
# and a merge request only contains EE related changes.
- git commit -m 'Update from merge request' --allow-empty # TODO: Mark which SHA we add
- git push -f "${FOSS_REPOSITORY}" "${AS_IF_FOSS_BRANCH}"
prepare-as-if-foss-env:

View File

@ -514,3 +514,8 @@
curl -f --header "Private-Token: ${PROJECT_TOKEN_FOR_CI_SCRIPTS_API_USAGE}" "${url}" --create-dirs --output scripts/utils.sh
- source scripts/utils.sh
- run_timed_command "download_files ${FILES_TO_DOWNLOAD}"
.with_secret:
id_tokens:
GCP_ID_TOKEN:
aud: https://iam.googleapis.com/projects/${GCP_PROJECT_NUMBER}/locations/global/workloadIdentityPools/${GCP_WORKLOAD_IDENTITY_FEDERATION_POOL_ID}/providers/${GCP_WORKLOAD_IDENTITY_FEDERATION_PROVIDER_ID}

View File

@ -1,7 +1,6 @@
.as-if-jh-sandbox-variables:
variables:
AS_IF_JH_BRANCH: "as-if-jh/${CI_COMMIT_REF_NAME}"
JH_MIRROR_REPOSITORY: "https://dummy:${ADD_JH_FILES_TOKEN}@gitlab.com/gitlab-org/gitlab-jh-mirrors/gitlab.git"
SANDBOX_REPOSITORY: "https://dummy:${AS_IF_JH_TOKEN}@gitlab.com/gitlab-org-sandbox/gitlab-jh-validation.git"
.shared-as-if-jh:
@ -14,12 +13,20 @@
add-jh-files:
extends:
- .shared-as-if-jh
- .with_secret
- .as-if-jh:rules:prepare-as-if-jh
image: ${GITLAB_DEPENDENCY_PROXY_ADDRESS}ruby:${RUBY_VERSION}
stage: prepare
needs: []
secrets:
ADD_JH_FILES_TOKEN:
gcp_secret_manager:
name: ADD_JH_FILES_TOKEN
token: $GCP_ID_TOKEN
before_script:
- source ./scripts/utils.sh
- export ADD_JH_FILES_TOKEN="$(cat ${ADD_JH_FILES_TOKEN})"
- export JH_MIRROR_REPOSITORY="https://dummy:${ADD_JH_FILES_TOKEN}@gitlab.com/gitlab-org/gitlab-jh-mirrors/gitlab.git"
- source ./scripts/setup/as-if-jh.sh
- install_gitlab_gem
script:

View File

@ -44,11 +44,6 @@ dont-interrupt-me:
script:
- !reference [.base-script, script]
- rspec_parallelized_job "--fail-fast=${RSPEC_FAIL_FAST_THRESHOLD} --tag ~quarantine --tag ~level:background_migration --tag ~zoekt --tag ~click_house"
artifacts:
expire_in: 7d
paths:
- "${RSPEC_MATCHING_TESTS_FOSS_PATH}"
- tmp/capybara/
<% if rspec_files_per_test_level[:migration][:files].size > 0 %>
rspec migration foss-impact:

View File

@ -623,7 +623,7 @@
- "vendor/assets/javascripts/**/*"
.feature-flag-development-config-patterns: &feature-flag-development-config-patterns
- "{,ee/,jh/}config/feature_flags/{development,ops}/*.yml"
- "{,ee/,jh/}config/feature_flags/**/*.yml"
.glfm-patterns: &glfm-patterns
- ".gitlab/ci/rules.gitlab-ci.yml"
@ -661,17 +661,6 @@
- <<: *if-jh
when: never
.as-if-jh-default-exclusion-rules:
rules:
- if: '$ADD_JH_FILES_TOKEN == null'
when: never
- <<: *if-security-merge-request
when: never
- <<: *if-merge-request-targeting-stable-branch
when: never
- <<: *if-merge-request-labels-pipeline-expedite
when: never
.rails:rules:run-search-tests:
rules:
- !reference [".rails:rules:default-branch-schedule-nightly--code-backstage-ee-only", rules]
@ -3179,10 +3168,8 @@
##################
.as-if-jh:rules:prepare-as-if-jh:
rules:
- !reference [".strict-ee-only-rules", rules]
- !reference [".as-if-jh-default-exclusion-rules", rules]
- <<: *if-merge-request-labels-as-if-jh
- <<: *if-dot-com-gitlab-org-merge-request
- <<: *if-merge-request
changes: *feature-flag-development-config-patterns
# This rule should share the same logic with .as-if-jh:rules:prepare-as-if-jh
@ -3204,8 +3191,6 @@
# dependencies changes.
.as-if-jh:rules:sync-as-if-jh:
rules:
- !reference [".strict-ee-only-rules", rules]
- !reference [".as-if-jh-default-exclusion-rules", rules]
- <<: *if-merge-request-labels-as-if-jh
changes: *dependency-patterns
# Ideally, we should be able to do this:
@ -3216,11 +3201,9 @@
# Because the jobs using this need jobs using the preparation rules
.as-if-jh:rules:start-as-if-jh:
rules:
- !reference [".strict-ee-only-rules", rules]
- !reference [".as-if-jh-default-exclusion-rules", rules]
- <<: *if-merge-request-labels-as-if-jh
allow_failure: true # See https://gitlab.com/gitlab-org/gitlab/-/issues/351136
- <<: *if-dot-com-gitlab-org-merge-request
- <<: *if-merge-request
changes: *feature-flag-development-config-patterns
allow_failure: true # See https://gitlab.com/gitlab-org/gitlab/-/issues/351136

View File

@ -1 +1 @@
af2fbf3d304a0cd637f8b9ea47817b8c9b6f109b
042a35ce7e9bd624b1f777d36eb3660e20f563e2

View File

@ -300,7 +300,7 @@ gem 'redis-actionpack', '~> 5.4.0' # rubocop:todo Gemfile/MissingFeatureCategory
gem 'discordrb-webhooks', '~> 3.4', require: false, feature_category: :integrations
# Jira integration
gem 'jira-ruby', '~> 2.1.4', feature_category: :integrations
gem 'jira-ruby', '~> 2.3.0', feature_category: :integrations
gem 'atlassian-jwt', '~> 0.2.0', feature_category: :integrations
# Slack integration

View File

@ -326,7 +326,7 @@
{"name":"jaeger-client","version":"1.1.0","platform":"ruby","checksum":"cb5e9b9bbee6ee8d6a82d03d947a5b04543d8c0a949c22e484254f18d8a458a8"},
{"name":"jaro_winkler","version":"1.5.4","platform":"java","checksum":"0454333a50b44a09745878bfe57859893631ff7dfe48c029827894944514fe7c"},
{"name":"jaro_winkler","version":"1.5.4","platform":"ruby","checksum":"50c3e83c5a9e8769c1cf5b73c8b51bb6eebbf8852a0ee53bf6ad6e4dc63414f9"},
{"name":"jira-ruby","version":"2.1.4","platform":"ruby","checksum":"4267c095cac8323b9eef3ba866eb28bb1388b7623a5abb60c1e7caf12d4adb9e"},
{"name":"jira-ruby","version":"2.3.0","platform":"ruby","checksum":"abf26e6bff4a8ea40bae06f7df6276a5776905c63fb2070934823ca54f62eb62"},
{"name":"jmespath","version":"1.6.2","platform":"ruby","checksum":"238d774a58723d6c090494c8879b5e9918c19485f7e840f2c1c7532cf84ebcb1"},
{"name":"js_regex","version":"3.8.0","platform":"ruby","checksum":"7934bcdd5a0e6d5af4a520288fd4684a02a472ae55831d9178ccaf82356344b5"},
{"name":"json","version":"2.6.3","platform":"java","checksum":"ea8c47427a2c876121b9a0ab53043ca390013a76374330eabd923bd81914e563"},

View File

@ -969,7 +969,7 @@ GEM
opentracing (~> 0.3)
thrift
jaro_winkler (1.5.4)
jira-ruby (2.1.4)
jira-ruby (2.3.0)
activesupport
atlassian-jwt
multipart-post
@ -1986,7 +1986,7 @@ DEPENDENCIES
ipaddr (~> 1.2.5)
ipaddress (~> 0.8.3)
ipynbdiff!
jira-ruby (~> 2.1.4)
jira-ruby (~> 2.3.0)
js_regex (~> 3.8)
json (~> 2.6.3)
json_schemer (~> 0.2.18)

View File

@ -38,9 +38,12 @@ export default {
},
},
methods: {
...mapActions(['toggleDiscussion']),
...mapActions('diffs', ['toggleFileDiscussion']),
isExpanded(discussion) {
return this.shouldCollapseDiscussions ? discussion.expanded : true;
return this.shouldCollapseDiscussions ? discussion.expandedOnDiff : true;
},
toggleVisibility(discussion) {
this.toggleFileDiscussion(discussion);
},
},
};
@ -59,11 +62,11 @@ export default {
<ul :data-discussion-id="discussion.id" class="notes">
<template v-if="shouldCollapseDiscussions">
<button
v-if="discussion.expanded"
v-if="discussion.expandedOnDiff"
class="diff-notes-collapse js-diff-notes-toggle"
type="button"
:aria-label="__('Show comments')"
@click="toggleDiscussion({ discussionId: discussion.id })"
@click="toggleVisibility(discussion)"
>
<gl-icon name="collapse" class="collapse-icon" />
</button>
@ -73,7 +76,7 @@ export default {
:is-resolved="discussion.resolved"
size="sm"
class="js-diff-notes-toggle gl-translate-x-n50"
@click="toggleDiscussion({ discussionId: discussion.id })"
@click="toggleVisibility(discussion)"
/>
</template>
<noteable-discussion

View File

@ -213,7 +213,6 @@ export default {
},
methods: {
...mapActions('diffs', [
'toggleFileDiscussions',
'toggleFileDiscussionWrappers',
'toggleFullDiff',
'setCurrentFileHash',

View File

@ -586,29 +586,10 @@ export const loadCollapsedDiff = ({ commit, getters, state }, { file, params = {
/**
* Toggles the file discussions after user clicked on the toggle discussions button.
*
* Gets the discussions for the provided diff.
*
* If all discussions are expanded, it will collapse all of them
* If all discussions are collapsed, it will expand all of them
* If some discussions are open and others closed, it will expand the closed ones.
*
* @param {Object} diff
* @param {Object} discussion
*/
export const toggleFileDiscussions = ({ getters, dispatch }, diff) => {
const discussions = getters.getDiffFileDiscussions(diff);
const shouldCloseAll = getters.diffHasAllExpandedDiscussions(diff);
const shouldExpandAll = getters.diffHasAllCollapsedDiscussions(diff);
discussions.forEach((discussion) => {
const data = { discussionId: discussion.id };
if (shouldCloseAll) {
dispatch('collapseDiscussion', data, { root: true });
} else if (shouldExpandAll || (!shouldCloseAll && !shouldExpandAll && !discussion.expanded)) {
dispatch('expandDiscussion', data, { root: true });
}
});
export const toggleFileDiscussion = ({ commit }, discussion) => {
commit(types.TOGGLE_FILE_DISCUSSION_EXPAND, discussion);
};
export const toggleFileDiscussionWrappers = ({ commit }, diff) => {
@ -1116,3 +1097,7 @@ export const unpinFile = ({ getters, commit }) => {
newUrl.hash = '';
window.history.replaceState(null, undefined, newUrl);
};
export const toggleAllDiffDiscussions = ({ commit, getters }) => {
commit(types.SET_EXPAND_ALL_DIFF_DISCUSSIONS, !getters.allDiffDiscussionsExpanded);
};

View File

@ -71,6 +71,25 @@ export const diffHasExpandedDiscussions = () => (diff) => {
return diffFileDiscussionsExpanded || diffLineDiscussionsExpanded;
};
/**
* Checks if every diff has every discussion open
* @returns {Boolean}
*/
export const allDiffDiscussionsExpanded = (state) => {
return state.diffFiles.every((diff) => {
const highlightedLines = diff[INLINE_DIFF_LINES_KEY];
if (highlightedLines.length) {
return highlightedLines
.filter((l) => l.discussions.length >= 1)
.every((l) => l.discussionsExpanded);
}
if (diff.viewer.name === 'image') {
return diff.discussions.every((discussion) => discussion.expandedOnDiff);
}
return true;
});
};
/**
* Checks if the diff has any discussion
* @param {Boolean} diff

View File

@ -18,6 +18,7 @@ export const ADD_CONTEXT_LINES = 'ADD_CONTEXT_LINES';
export const ADD_COLLAPSED_DIFFS = 'ADD_COLLAPSED_DIFFS';
export const RENDER_FILE = 'RENDER_FILE';
export const SET_LINE_DISCUSSIONS_FOR_FILE = 'SET_LINE_DISCUSSIONS_FOR_FILE';
export const TOGGLE_FILE_DISCUSSION_EXPAND = 'TOGGLE_FILE_DISCUSSION_EXPAND';
export const REMOVE_LINE_DISCUSSIONS_FOR_FILE = 'REMOVE_LINE_DISCUSSIONS_FOR_FILE';
export const TOGGLE_FOLDER_OPEN = 'TOGGLE_FOLDER_OPEN';
export const TREE_ENTRY_DIFF_LOADING = 'TREE_ENTRY_DIFF_LOADING';
@ -51,6 +52,7 @@ export const SET_DIFF_FILE_VIEWER = 'SET_DIFF_FILE_VIEWER';
export const SET_SHOW_SUGGEST_POPOVER = 'SET_SHOW_SUGGEST_POPOVER';
export const SET_EXPAND_ALL_DIFF_DISCUSSIONS = 'SET_EXPAND_ALL_DIFF_DISCUSSIONS';
export const TOGGLE_LINE_DISCUSSIONS = 'TOGGLE_LINE_DISCUSSIONS';
export const DISABLE_VIRTUAL_SCROLLING = 'DISABLE_VIRTUAL_SCROLLING';

View File

@ -173,7 +173,6 @@ export default {
[types.SET_LINE_DISCUSSIONS_FOR_FILE](state, { discussion, diffPositionByLineCode, hash }) {
const { latestDiff } = state;
const originalStartLineCode = discussion.original_position?.line_range?.start?.line_code;
const positionType = discussion.position?.position_type;
const discussionLineCodes = [
@ -182,7 +181,11 @@ export default {
...(discussion.line_codes || []),
];
const fileHash = discussion.diff_file?.file_hash;
const lineCheck = (line) =>
const isHashTargeted = (discussionItem) =>
discussionItem.notes && discussionItem.notes.some((note) => hash === `note_${note.id}`);
const isTargetLine = (line) =>
discussionLineCodes.some(
(discussionLineCode) =>
line.line_code === discussionLineCode &&
@ -192,65 +195,40 @@ export default {
latestDiff,
}),
);
const mapDiscussions = (line, extraCheck = () => true) => ({
...line,
discussions: extraCheck()
? line.discussions &&
line.discussions
.filter(() => !line.discussions.some(({ id }) => discussion.id === id))
.concat(lineCheck(line) ? discussion : line.discussions)
: [],
});
const setDiscussionsExpanded = (line) => {
const isLineNoteTargeted =
line.discussions &&
line.discussions.some(
(disc) => disc.notes && disc.notes.find((note) => hash === `note_${note.id}`),
);
return {
...line,
discussionsExpanded:
line.discussionsExpanded ||
(line.discussions && line.discussions.length
? line.discussions.some((disc) => !disc.resolved) || isLineNoteTargeted
: false),
};
const isExpandedDiscussion = (discussionItem) => {
return !discussionItem.resolved || isHashTargeted(discussionItem);
};
state.diffFiles.forEach((file) => {
if (file.file_hash === fileHash) {
if (positionType === FILE_DIFF_POSITION_TYPE) {
const newDiscussions = (file.discussions || [])
.filter((d) => d.id !== discussion.id)
.concat(discussion);
const addDiscussion = (discussions) =>
discussions.filter(({ id }) => discussion.id !== id).concat(discussion);
Object.assign(file, {
discussions: newDiscussions,
});
} else {
if (file[INLINE_DIFF_LINES_KEY].length) {
file[INLINE_DIFF_LINES_KEY].forEach((line) => {
Object.assign(
line,
setDiscussionsExpanded(lineCheck(line) ? mapDiscussions(line) : line),
);
});
}
const file = state.diffFiles.find((diff) => diff.file_hash === fileHash);
// a file batch might not be loaded yet when we try to add a discussion
if (!file) return;
const diffLines = file[INLINE_DIFF_LINES_KEY];
if (!file[INLINE_DIFF_LINES_KEY].length) {
const newDiscussions = (file.discussions || [])
.filter((d) => d.id !== discussion.id)
.concat(discussion);
if (diffLines.length && positionType !== FILE_DIFF_POSITION_TYPE) {
const line = diffLines.find(isTargetLine);
const discussions = addDiscussion(line.discussions || []);
Object.assign(line, {
discussions,
discussionsExpanded: line.discussionsExpanded || discussions.some(isExpandedDiscussion),
});
} else {
Object.assign(discussion, { expandedOnDiff: isExpandedDiscussion(discussion) });
Object.assign(file, {
discussions: addDiscussion(file.discussions || []),
});
}
},
Object.assign(file, {
discussions: newDiscussions,
});
}
}
}
});
[types.TOGGLE_FILE_DISCUSSION_EXPAND](state, discussion) {
Object.assign(discussion, { expandedOnDiff: !discussion.expandedOnDiff });
const fileHash = discussion.diff_file.file_hash;
const diff = state.diffFiles.find((f) => f.file_hash === fileHash);
// trigger Vue reactivity
Object.assign(diff, { discussions: [...diff.discussions] });
},
[types.REMOVE_LINE_DISCUSSIONS_FOR_FILE](state, { fileHash, lineCode }) {
@ -278,6 +256,27 @@ export default {
});
},
[types.SET_EXPAND_ALL_DIFF_DISCUSSIONS](state, expanded) {
const lineHasDiscussion = (line) => Boolean(line.discussions?.length);
state.diffFiles.forEach((file) => {
const highlightedLines = file[INLINE_DIFF_LINES_KEY];
if (highlightedLines.length) {
const discussionLines = highlightedLines.filter(lineHasDiscussion);
discussionLines.forEach(({ line_code }) => {
updateLineInFile(file, line_code, (line) => {
Object.assign(line, { discussionsExpanded: expanded });
});
});
} else {
const discussions = file.discussions.map((discussion) => {
Object.assign(discussion, { expandedOnDiff: expanded });
return discussion;
});
Object.assign(file, { discussions });
}
});
},
[types.TOGGLE_FOLDER_OPEN](state, path) {
state.treeEntries[path].opened = !state.treeEntries[path].opened;
},

View File

@ -21,3 +21,11 @@ export async function fetchMrMetadata({ state, commit }) {
}
}
}
export const toggleAllVisibleDiscussions = ({ getters, dispatch }) => {
if (getters.isDiffsPage) {
dispatch('diffs/toggleAllDiffDiscussions');
} else {
dispatch('toggleAllDiscussions');
}
};

View File

@ -7,4 +7,11 @@ export default {
isLoggedIn(state, getters) {
return Boolean(getters.getUserData.id);
},
isDiffsPage(state) {
return state.activeTab === 'diffs';
},
allVisibleDiscussionsExpanded(state, getters) {
if (getters.isDiffsPage) return getters['diffs/allDiffDiscussionsExpanded'];
return getters.allDiscussionsExpanded;
},
};

View File

@ -171,7 +171,7 @@ export default {
:file-hash="discussion.diff_file.file_hash"
:show-comment-icon="true"
:should-toggle-discussion="false"
badge-class="image-comment-badge gl-text-gray-500"
badge-class="image-comment-badge gl-text-purple-500 gl-bg-white gl-rounded-full gl-border-white gl-border-1 gl-border-solid gl-pointer-events-none gl-shadow-md"
/>
</template>
</diff-viewer>

View File

@ -42,15 +42,15 @@ export default {
'resolvableDiscussionsCount',
'unresolvedDiscussionsCount',
'allResolvableDiscussions',
'allVisibleDiscussionsExpanded',
]),
allResolved() {
return this.unresolvedDiscussionsCount === 0;
},
allExpanded() {
return this.allResolvableDiscussions.every((discussion) => discussion.expanded);
},
toggleThreadsLabel() {
return this.allExpanded ? __('Collapse all threads') : __('Expand all threads');
return !this.allVisibleDiscussionsExpanded
? __('Show all comments')
: __('Hide all comments');
},
nextUnresolvedDiscussionShortcutKey() {
return shouldDisableShortcuts() ? null : keysFor(MR_NEXT_UNRESOLVED_DISCUSSION)[0];
@ -85,7 +85,7 @@ export default {
const options = [
{
text: this.toggleThreadsLabel,
action: this.handleExpandDiscussions,
action: this.toggleAllVisibleDiscussions,
extraAttrs: {
'data-testid': 'toggle-all-discussions-btn',
},
@ -109,13 +109,7 @@ export default {
},
},
methods: {
...mapActions(['setExpandDiscussions']),
handleExpandDiscussions() {
this.setExpandDiscussions({
discussionIds: this.allResolvableDiscussions.map((discussion) => discussion.id),
expanded: !this.allExpanded,
});
},
...mapActions(['toggleAllVisibleDiscussions']),
},
};
</script>

View File

@ -466,7 +466,7 @@ export default {
:href="author.path"
:data-user-id="author.id"
:data-username="author.username"
class="js-user-link"
class="js-user-link gl-relative"
>
<gl-avatar
:src="author.avatar_url"

View File

@ -82,8 +82,9 @@ export const setNotesFetchedState = ({ commit }, state) =>
export const toggleDiscussion = ({ commit }, data) => commit(types.TOGGLE_DISCUSSION, data);
export const setExpandDiscussions = ({ commit }, { discussionIds, expanded }) => {
commit(types.SET_EXPAND_DISCUSSIONS, { discussionIds, expanded });
export const toggleAllDiscussions = ({ commit, getters }) => {
const expanded = getters.allDiscussionsExpanded;
commit(types.SET_EXPAND_ALL_DISCUSSIONS, !expanded);
};
export const fetchDiscussions = (

View File

@ -380,3 +380,7 @@ export const getFetchDiscussionsConfig = (state, getters) => {
}
return defaultConfig;
};
export const allDiscussionsExpanded = (state) => {
return state.discussions.every((discussion) => discussion.expanded);
};

View File

@ -34,6 +34,7 @@ export const COLLAPSE_DISCUSSION = 'COLLAPSE_DISCUSSION';
export const EXPAND_DISCUSSION = 'EXPAND_DISCUSSION';
export const TOGGLE_DISCUSSION = 'TOGGLE_DISCUSSION';
export const SET_EXPAND_DISCUSSIONS = 'SET_EXPAND_DISCUSSIONS';
export const SET_EXPAND_ALL_DISCUSSIONS = 'SET_EXPAND_ALL_DISCUSSIONS';
export const UPDATE_RESOLVABLE_DISCUSSIONS_COUNTS = 'UPDATE_RESOLVABLE_DISCUSSIONS_COUNTS';
export const SET_CURRENT_DISCUSSION_ID = 'SET_CURRENT_DISCUSSION_ID';
export const SET_DISCUSSIONS_SORT = 'SET_DISCUSSIONS_SORT';

View File

@ -233,6 +233,12 @@ export default {
}
},
[types.SET_EXPAND_ALL_DISCUSSIONS](state, expanded) {
state.discussions.forEach((discussion) => {
Object.assign(discussion, { expanded });
});
},
[types.SET_RESOLVING_DISCUSSION](state, isResolving) {
state.isResolvingDiscussion = isResolving;
},

View File

@ -514,7 +514,8 @@ module ApplicationSettingsHelper
:ci_max_total_yaml_size_bytes,
:project_jobs_api_rate_limit,
:security_txt_content,
:allow_project_creation_for_guest_and_below
:allow_project_creation_for_guest_and_below,
:downstream_pipeline_trigger_limit_per_project_user_sha
].tap do |settings|
next if Gitlab.com?

View File

@ -597,11 +597,13 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
:sidekiq_job_limiter_compression_threshold_bytes,
:sidekiq_job_limiter_limit_bytes,
:terminal_max_session_time,
:users_get_by_id_limit
:users_get_by_id_limit,
:downstream_pipeline_trigger_limit_per_project_user_sha
end
jsonb_accessor :rate_limits,
members_delete_limit: [:integer, { default: 60 }]
members_delete_limit: [:integer, { default: 60 }],
downstream_pipeline_trigger_limit_per_project_user_sha: [:integer, { default: 0 }]
validates :rate_limits, json_schema: { filename: "application_setting_rate_limits" }

View File

@ -280,7 +280,8 @@ module ApplicationSettingImplementation
security_txt_content: nil,
allow_project_creation_for_guest_and_below: true,
enable_member_promotion_management: false,
security_approval_policies_limit: 5
security_approval_policies_limit: 5,
downstream_pipeline_trigger_limit_per_project_user_sha: 0
}.tap do |hsh|
hsh.merge!(non_production_defaults) unless Rails.env.production?
end

View File

@ -48,7 +48,7 @@ module Ci
end
def by_scope(relation, scope)
if scope == :namespaces && Feature.enabled?(:ci_guard_for_catalog_resource_scope, current_user)
if scope == :namespaces
relation.visible_to_user(current_user)
else
relation.public_or_visible_to_user(current_user)

View File

@ -13,5 +13,15 @@ module Members
validates :new_access_level, presence: true
validates :old_access_level, presence: true
validate :validate_unique_pending_approval, on: [:create, :update]
private
def validate_unique_pending_approval
if pending? && self.class.where(member_id: member_id, member_namespace_id: member_namespace_id,
new_access_level: new_access_level, status: 0).exists?
errors.add(:base, 'A pending approval for the same member, namespace, and access level already exists.')
end
end
end
end

View File

@ -3,10 +3,6 @@
module Ci
# Enqueues the downstream pipeline worker.
class TriggerDownstreamPipelineService
# This is a temporary constant. It may be converted into an application setting
# in the future. See https://gitlab.com/gitlab-org/gitlab/-/issues/425941.
DOWNSTREAM_PIPELINE_TRIGGER_LIMIT_PER_PROJECT_USER_SHA = 200
def initialize(bridge)
@bridge = bridge
@current_user = bridge.user

View File

@ -8,6 +8,11 @@
"type": "integer",
"minimum": 0,
"description": "Number of project or group members a user can delete per minute."
},
"downstream_pipeline_trigger_limit_per_project_user_sha": {
"type": "integer",
"minimum": 0,
"description": "Maximum number of downstream pipelines triggered in a project per user"
}
}
}

View File

@ -50,6 +50,11 @@
= f.number_field :ci_max_includes, class: 'form-control gl-form-input'
.form-text.text-muted
= s_('AdminSettings|The maximum number of included files per pipeline.')
.form-group
= f.label :downstream_pipeline_trigger_limit_per_project_user_sha, s_('AdminSettings|Maximum downstream pipelines triggered in a project per user'), class: 'label-bold'
= f.number_field :downstream_pipeline_trigger_limit_per_project_user_sha, min: 0, class: 'form-control gl-form-input'
.form-text.text-muted
= s_('AdminSettings|The maximum number of downstream pipelines triggered in a project per user.')
.form-group
= f.label :ci_config_path, _('Default CI/CD configuration file'), class: 'label-bold'
= f.text_field :default_ci_config_path, class: 'form-control gl-form-input', placeholder: '.gitlab-ci.yml'

View File

@ -1,4 +1,4 @@
= render_if_exists 'notify/address_new_reviewer_with_diff_summary'
%p
= change_reviewer_notification_text(@merge_request.reviewers, @previous_reviewers, :strong)
= change_reviewer_notification_text(@merge_request.reviewers, @previous_reviewers)

View File

@ -1,3 +1,11 @@
%p
= html_escape(s_('Notify|%{name} requested a new review on %{mr_link}.')) % {name: sanitize_name(@updated_by.name), mr_link: merge_request_reference_link(@merge_request).html_safe}
- long_mr = '%{reference} %{mrtitle}' % { reference: @merge_request.to_reference, mrtitle: @merge_request.title }
- mr_url = merge_request_url(@merge_request)
%h4{ style: 'margin-bottom: 0' }
= s_('Notify|Review requested')
%p{ style: 'margin-top: 0' }
= html_escape(s_('Notify|You were added as a reviewer on %{long_mr} by %{name}.')) % {name: sanitize_name(@updated_by.name), long_mr: long_mr}
= render_if_exists 'notify/diff_summary'
%p
%a{ href: mr_url, target: "_blank", rel: "noopener noreferrer nofollow", style: "-webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; font-size: 14px; font-family: 'Source Sans Pro', helvetica, arial, sans-serif; color: #ffffff; text-decoration: none; border-radius: 4px; -webkit-border-radius: 4px; background-color: #1f75cb; display: inline-block; padding: 8px 12px; box-shadow: inset 0 0 0 1px #1068bf" }
= s_('Notify|Review changes')

View File

@ -1,8 +0,0 @@
---
name: ci_guard_for_catalog_resource_scope
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/137015
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/432219
milestone: '16.7'
type: development
group: group::pipeline authoring
default_enabled: true

View File

@ -1,8 +0,0 @@
---
name: usage_data_api
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41301
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/267114
milestone: '13.4'
type: ops
group: group::analytics instrumentation
default_enabled: true

View File

@ -816,9 +816,9 @@ Gitlab.ee do
Settings.cron_jobs['sync_service_token_worker'] ||= {}
Settings.cron_jobs['sync_service_token_worker']['cron'] ||= "#{rand(60)} #{rand(5..6)} * * * UTC"
Settings.cron_jobs['sync_service_token_worker']['job_class'] = '::Ai::SyncServiceTokenWorker'
Settings.cron_jobs['llm_embedding_gitlab_documentation_create_empty_embeddings_records_worker'] ||= {}
Settings.cron_jobs['llm_embedding_gitlab_documentation_create_empty_embeddings_records_worker']['cron'] ||= '0 5 * * 1,2,3,4,5'
Settings.cron_jobs['llm_embedding_gitlab_documentation_create_empty_embeddings_records_worker']['job_class'] ||= 'Llm::Embedding::GitlabDocumentation::CreateEmptyEmbeddingsRecordsWorker'
Settings.cron_jobs['llm_embedding_gitlab_documentation_create_embeddings_records_worker'] ||= {}
Settings.cron_jobs['llm_embedding_gitlab_documentation_create_embeddings_records_worker']['cron'] ||= '0 5 * * 1,2,3,4,5'
Settings.cron_jobs['llm_embedding_gitlab_documentation_create_embeddings_records_worker']['job_class'] ||= 'Llm::Embedding::GitlabDocumentation::CreateEmbeddingsRecordsWorker'
Settings.cron_jobs['llm_embedding_gitlab_documentation_cleanup_previous_versions_records_worker'] ||= {}
Settings.cron_jobs['llm_embedding_gitlab_documentation_cleanup_previous_versions_records_worker']['cron'] ||= '0 0 * * *'
Settings.cron_jobs['llm_embedding_gitlab_documentation_cleanup_previous_versions_records_worker']['job_class'] ||= 'Llm::Embedding::GitlabDocumentation::CleanupPreviousVersionsRecordsWorker'

View File

@ -0,0 +1,14 @@
- title: "Removal of tags from small SaaS runners on Linux"
removal_milestone: "17.0"
announcement_milestone: "16.9"
breaking_change: true
reporter: gabrielengel_gl
stage: Verify
issue_url: https://gitlab.com/gitlab-org/gitlab-runner/-/issues/30829
manual_task: true
body: | # (required) Don't change this line.
Due to historical reasons, small Linux SaaS Runners had a lot of tags attached because they were used as labels. We want to streamline the tag to just use `saas-linux-small-amd64` and be consistent across all SaaS runners.
We are deprecating the tags: `docker`, `east-c`, `gce`, `git-annex`, `linux`, `mongo`, `mysql`, `postgres`, `ruby`, `shared`.
For more information, see [Removing tags from our small SaaS runner on Linux](https://about.gitlab.com/blog/2023/08/15/removing-tags-from-small-saas-runner-on-linux/).

View File

@ -0,0 +1,15 @@
- title: "Upgrading the operating system version of GitLab SaaS runners on Linux"
removal_milestone: "17.0"
announcement_milestone: "16.9"
breaking_change: true
reporter: gabrielengel_gl
stage: Verify
issue_url: https://gitlab.com/gitlab-org/ci-cd/shared-runners/infrastructure/-/issues/60
manual_task: true
body: | # (required) Don't change this line.
GitLab is upgrading the container-optimized operating system (COS) of the ephemeral VMs used to execute jobs for SaaS runners on Linux.
That COS upgrade includes a Docker Engine upgrade from Version 19.03.15 to Version 23.0.5, which introduces a known compatibility issue.
Docker-in-Docker prior to version 20.10 or Kaniko images older than v1.9.0, will be unable to detect the container runtime and fail.
For more information, see [Upgrading the operating system version of our SaaS runners on Linux](https://about.gitlab.com/blog/2023/10/04/updating-the-os-version-of-saas-runners-on-linux/).

View File

@ -7,4 +7,19 @@ feature_categories:
description: Join table relating packages_packages with ci_pipelines
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/19796
milestone: '12.6'
gitlab_schema: gitlab_main
gitlab_schema: gitlab_main_cell
allow_cross_joins:
- gitlab_main_clusterwide
allow_cross_transactions:
- gitlab_main_clusterwide
allow_cross_foreign_keys:
- gitlab_main_clusterwide
desired_sharding_key:
project_id:
references: projects
backfill_via:
parent:
foreign_key: package_id
table: packages_packages
sharding_key: project_id
belongs_to: package

View File

@ -7,4 +7,19 @@ feature_categories:
description: Composer package metadata
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30448
milestone: '13.1'
gitlab_schema: gitlab_main
gitlab_schema: gitlab_main_cell
allow_cross_joins:
- gitlab_main_clusterwide
allow_cross_transactions:
- gitlab_main_clusterwide
allow_cross_foreign_keys:
- gitlab_main_clusterwide
desired_sharding_key:
project_id:
references: projects
backfill_via:
parent:
foreign_key: package_id
table: packages_packages
sharding_key: project_id
belongs_to: package

View File

@ -7,4 +7,19 @@ feature_categories:
description: Conan package metadata
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/16418
milestone: '12.5'
gitlab_schema: gitlab_main
gitlab_schema: gitlab_main_cell
allow_cross_joins:
- gitlab_main_clusterwide
allow_cross_transactions:
- gitlab_main_clusterwide
allow_cross_foreign_keys:
- gitlab_main_clusterwide
desired_sharding_key:
project_id:
references: projects
backfill_via:
parent:
foreign_key: package_id
table: packages_packages
sharding_key: project_id
belongs_to: package

View File

@ -7,4 +7,19 @@ feature_categories:
description: Debian registry group-level architectures
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/51265
milestone: '13.8'
gitlab_schema: gitlab_main
gitlab_schema: gitlab_main_cell
allow_cross_joins:
- gitlab_main_clusterwide
allow_cross_transactions:
- gitlab_main_clusterwide
allow_cross_foreign_keys:
- gitlab_main_clusterwide
desired_sharding_key:
project_id:
references: projects
backfill_via:
parent:
foreign_key: distribution_id
table: packages_debian_project_distributions
sharding_key: project_id
belongs_to: distribution

View File

@ -7,4 +7,19 @@ feature_categories:
description: Debian package project-level distribution components
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/51732
milestone: '13.9'
gitlab_schema: gitlab_main
gitlab_schema: gitlab_main_cell
allow_cross_joins:
- gitlab_main_clusterwide
allow_cross_transactions:
- gitlab_main_clusterwide
allow_cross_foreign_keys:
- gitlab_main_clusterwide
desired_sharding_key:
project_id:
references: projects
backfill_via:
parent:
foreign_key: distribution_id
table: packages_debian_project_distributions
sharding_key: project_id
belongs_to: distribution

View File

@ -7,4 +7,19 @@ feature_categories:
description: Debian project-level distribution keys
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/60993
milestone: '14.0'
gitlab_schema: gitlab_main
gitlab_schema: gitlab_main_cell
allow_cross_joins:
- gitlab_main_clusterwide
allow_cross_transactions:
- gitlab_main_clusterwide
allow_cross_foreign_keys:
- gitlab_main_clusterwide
desired_sharding_key:
project_id:
references: projects
backfill_via:
parent:
foreign_key: distribution_id
table: packages_debian_project_distributions
sharding_key: project_id
belongs_to: distribution

View File

@ -7,4 +7,19 @@ feature_categories:
description: Debian package publications relating distributions to packages
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/52916
milestone: '13.9'
gitlab_schema: gitlab_main
gitlab_schema: gitlab_main_cell
allow_cross_joins:
- gitlab_main_clusterwide
allow_cross_transactions:
- gitlab_main_clusterwide
allow_cross_foreign_keys:
- gitlab_main_clusterwide
desired_sharding_key:
project_id:
references: projects
backfill_via:
parent:
foreign_key: package_id
table: packages_packages
sharding_key: project_id
belongs_to: package

View File

@ -7,4 +7,19 @@ feature_categories:
description: Join table between packages_packages and packages_dependencies
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20549
milestone: '12.6'
gitlab_schema: gitlab_main
gitlab_schema: gitlab_main_cell
allow_cross_joins:
- gitlab_main_clusterwide
allow_cross_transactions:
- gitlab_main_clusterwide
allow_cross_foreign_keys:
- gitlab_main_clusterwide
desired_sharding_key:
project_id:
references: projects
backfill_via:
parent:
foreign_key: package_id
table: packages_packages
sharding_key: project_id
belongs_to: package

View File

@ -7,4 +7,19 @@ feature_categories:
description: Maven package metadata
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/6607
milestone: '11.3'
gitlab_schema: gitlab_main
gitlab_schema: gitlab_main_cell
allow_cross_joins:
- gitlab_main_clusterwide
allow_cross_transactions:
- gitlab_main_clusterwide
allow_cross_foreign_keys:
- gitlab_main_clusterwide
desired_sharding_key:
project_id:
references: projects
backfill_via:
parent:
foreign_key: package_id
table: packages_packages
sharding_key: project_id
belongs_to: package

View File

@ -7,4 +7,19 @@ feature_categories:
description: Npm package metadata
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73639
milestone: '14.5'
gitlab_schema: gitlab_main
gitlab_schema: gitlab_main_cell
allow_cross_joins:
- gitlab_main_clusterwide
allow_cross_transactions:
- gitlab_main_clusterwide
allow_cross_foreign_keys:
- gitlab_main_clusterwide
desired_sharding_key:
project_id:
references: projects
backfill_via:
parent:
foreign_key: package_id
table: packages_packages
sharding_key: project_id
belongs_to: package

View File

@ -7,4 +7,19 @@ feature_categories:
description: Nuget package metadata
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30994
milestone: '13.1'
gitlab_schema: gitlab_main
gitlab_schema: gitlab_main_cell
allow_cross_joins:
- gitlab_main_clusterwide
allow_cross_transactions:
- gitlab_main_clusterwide
allow_cross_foreign_keys:
- gitlab_main_clusterwide
desired_sharding_key:
project_id:
references: projects
backfill_via:
parent:
foreign_key: package_id
table: packages_packages
sharding_key: project_id
belongs_to: package

View File

@ -7,4 +7,19 @@ feature_categories:
description: Package registry file links and file metadata for all package types
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/6607
milestone: '11.3'
gitlab_schema: gitlab_main
gitlab_schema: gitlab_main_cell
allow_cross_joins:
- gitlab_main_clusterwide
allow_cross_transactions:
- gitlab_main_clusterwide
allow_cross_foreign_keys:
- gitlab_main_clusterwide
desired_sharding_key:
project_id:
references: projects
backfill_via:
parent:
foreign_key: package_id
table: packages_packages
sharding_key: project_id
belongs_to: package

View File

@ -7,4 +7,19 @@ feature_categories:
description: PyPI package metadata
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/27632
milestone: '13.0'
gitlab_schema: gitlab_main
gitlab_schema: gitlab_main_cell
allow_cross_joins:
- gitlab_main_clusterwide
allow_cross_transactions:
- gitlab_main_clusterwide
allow_cross_foreign_keys:
- gitlab_main_clusterwide
desired_sharding_key:
project_id:
references: projects
backfill_via:
parent:
foreign_key: package_id
table: packages_packages
sharding_key: project_id
belongs_to: package

View File

@ -7,4 +7,19 @@ feature_categories:
description: Rpm package metadata
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96019
milestone: '15.4'
gitlab_schema: gitlab_main
gitlab_schema: gitlab_main_cell
allow_cross_joins:
- gitlab_main_clusterwide
allow_cross_transactions:
- gitlab_main_clusterwide
allow_cross_foreign_keys:
- gitlab_main_clusterwide
desired_sharding_key:
project_id:
references: projects
backfill_via:
parent:
foreign_key: package_id
table: packages_packages
sharding_key: project_id
belongs_to: package

View File

@ -7,4 +7,19 @@ feature_categories:
description: Ruby gems metadata
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/52639
milestone: '13.9'
gitlab_schema: gitlab_main
gitlab_schema: gitlab_main_cell
allow_cross_joins:
- gitlab_main_clusterwide
allow_cross_transactions:
- gitlab_main_clusterwide
allow_cross_foreign_keys:
- gitlab_main_clusterwide
desired_sharding_key:
project_id:
references: projects
backfill_via:
parent:
foreign_key: package_id
table: packages_packages
sharding_key: project_id
belongs_to: package

View File

@ -0,0 +1,18 @@
# frozen_string_literal: true
class AddConditionalUniqueIndexToMemberApprovals < Gitlab::Database::Migration[2.2]
milestone '16.10'
disable_ddl_transaction!
INDEX_NAME = 'unique_member_approvals_on_pending_status'
def up
add_concurrent_index :member_approvals, [:member_id, :member_namespace_id, :new_access_level],
unique: true, where: "status = 0", name: INDEX_NAME
end
def down
remove_concurrent_index_by_name :member_approvals, INDEX_NAME
end
end

View File

@ -0,0 +1 @@
f8ae8294d45a5d796a86d629bef9b25142895b497db778c694d8573338a274d2

View File

@ -36549,6 +36549,8 @@ CREATE UNIQUE INDEX unique_instance_google_cloud_logging_configurations ON audit
CREATE UNIQUE INDEX unique_instance_google_cloud_logging_configurations_name ON audit_events_instance_google_cloud_logging_configurations USING btree (name);
CREATE UNIQUE INDEX unique_member_approvals_on_pending_status ON member_approvals USING btree (member_id, member_namespace_id, new_access_level) WHERE (status = 0);
CREATE UNIQUE INDEX unique_merge_request_diff_llm_summaries_on_mr_diff_id ON merge_request_diff_llm_summaries USING btree (merge_request_diff_id);
CREATE UNIQUE INDEX unique_merge_request_metrics_by_merge_request_id ON merge_request_metrics USING btree (merge_request_id);

View File

@ -205,6 +205,18 @@ The default is `150`.
1. Change the value of **Maximum includes**.
1. Select **Save changes** for the changes to take effect.
## Maximum downstream pipelines triggered per project
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/144077) in GitLab 16.10 [with feature flag](../feature_flags.md) named `ci_rate_limit_downstream_pipelines`. Disabled by default.
The maximum number of [downstream pipelines](../../ci/pipelines/downstream_pipelines.md) per project per user can be set at the instance level.
The default is `0` (no restriction).
1. On the left sidebar, at the bottom, select **Admin Area**.
1. Select **Settings > CI/CD**.
1. Change the value of **Maximum downstream pipelines triggered in a project per user**.
1. Select **Save changes** for the changes to take effect.
## Default CI/CD configuration file
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/18073) in GitLab 12.5.

View File

@ -108,7 +108,7 @@ With this method:
- Set up an internet-facing reverse proxy in front of your self-managed instance. To secure this proxy further, only allow inbound
traffic from [Atlassian IP addresses](https://support.atlassian.com/organization-administration/docs/ip-addresses-and-domains-for-atlassian-cloud-products/#Outgoing-Connections).
- Add [GitLab IP addresses](../../user/gitlab_com/index.md#ip-range) to the allowlist of your firewall.
- The Jira user that installs and configures the GitLab for Jira Cloud app must meet certain [requirements](#jira-user-requirements).
- The Jira user that installs and configures the app must meet certain [requirements](#jira-user-requirements).
### Set up your instance
@ -176,7 +176,7 @@ To support your self-managed instance with Jira Cloud, do one of the following:
- The instance must be publicly available.
- You must set up [OAuth authentication](#set-up-oauth-authentication).
- The Jira user that installs and configures the GitLab for Jira Cloud app must meet certain [requirements](#jira-user-requirements).
- The Jira user that installs and configures the app must meet certain [requirements](#jira-user-requirements).
### Install the app in development mode

View File

@ -101,8 +101,8 @@ Depending on how you installed the app, you might want to check the following:
1. Select all checkboxes, then select **Next**.
1. Enter your **GitLab instance URL**, then select **Save**.
If this method does not work, [submit a support ticket](https://support.gitlab.com/hc/en-us/requests/new) if you're a Premium or Ultimate customer
and provide your GitLab instance URL and Jira URL. GitLab Support can try to run the following scripts to resolve the issue:
If this method does not work, [submit a support ticket](https://support.gitlab.com/hc/en-us/requests/new) if you're a Premium or Ultimate customer.
Provide your GitLab instance URL and Jira URL. GitLab Support can try to run the following scripts to resolve the issue:
```ruby
# Check if GitLab.com can connect to the self-managed instance

View File

@ -281,7 +281,8 @@ Example response:
"bulk_import_max_download_file_size": 5120,
"project_jobs_api_rate_limit": 600,
"security_txt_content": null,
"bulk_import_concurrent_pipeline_batch_limit": 25
"bulk_import_concurrent_pipeline_batch_limit": 25,
"downstream_pipeline_trigger_limit_per_project_user_sha": 0
}
```
@ -390,6 +391,7 @@ listed in the descriptions of the relevant settings.
| `domain_denylist_enabled` | boolean | no | (**If enabled, requires:** `domain_denylist`) Allows blocking sign-ups from emails from specific domains. |
| `domain_denylist` | array of strings | no | Users with email addresses that match these domains **cannot** sign up. Wildcards allowed. Use separate lines for multiple entries. For example: `domain.com`, `*.domain.com`. |
| `domain_allowlist` | array of strings | no | Force people to use only corporate emails for sign-up. Default is `null`, meaning there is no restriction. |
| `downstream_pipeline_trigger_limit_per_project_user_sha` | integer | no | Rate limit creation of downstream pipelines. Default: `0`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/144077) in GitLab 16.10 with a [flag](../administration/feature_flags.md) named `ci_rate_limit_downstream_pipelines`. Disabled by default. |
| `dsa_key_restriction` | integer | no | The minimum allowed bit length of an uploaded DSA key. Default is `0` (no restriction). `-1` disables DSA keys. |
| `ecdsa_key_restriction` | integer | no | The minimum allowed curve size (in bits) of an uploaded ECDSA key. Default is `0` (no restriction). `-1` disables ECDSA keys. |
| `ecdsa_sk_key_restriction` | integer | no | The minimum allowed curve size (in bits) of an uploaded ECDSA_SK key. Default is `0` (no restriction). `-1` disables ECDSA_SK keys. |

View File

@ -240,3 +240,6 @@ In progress.
- 2022-06-31: [Pipeline partitioning design](pipeline_partitioning.md) document [merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87683) merged.
- 2022-09-01: Engineering effort started to implement partitioning.
- 2022-11-01: The fastest growing CI table partitioned: `ci_builds_metadata`.
- 2023-06-30: The second largest table partitioned: `ci_builds`.
- 2023-12-12: `ci_builds` and `ci_builds_metadata` growth is stopped by writing data to new partitions.
- 2024-02-05: `ci_pipeline_variables` is partitioned.

View File

@ -43,7 +43,7 @@ multiple GitLab deployments, instances, and cells. We use it as an umbrella term
embeddings are stored in the `vertex_gitlab_docs` database table in the
`embeddings` database. The embeddings search is done in Postgres using the
`vector` extension. The vertex embeddings database is updated based on the
latest version of GitLab documentation on daily basis by running `Llm::Embedding::GitlabDocumentation::CreateEmptyEmbeddingsRecordsWorker` as a cronjob.
latest version of GitLab documentation on a daily basis by running `Llm::Embedding::GitlabDocumentation::CreateEmbeddingsRecordsWorker` as a cronjob.
- **Golden Questions**: a small subset of the types of questions we think a user
should be able to ask GitLab Duo Chat. Used to generate data for Chat evaluation.
[Questions for Chat Beta](https://gitlab.com/groups/gitlab-org/-/epics/10550#what-the-user-can-ask).

View File

@ -48,8 +48,8 @@ DETAILS:
Prerequisites:
- You must have [site administrator](https://support.atlassian.com/user-management/docs/give-users-admin-permissions/#Make-someone-a-site-admin) access to the Jira instance.
- Your network must allow inbound and outbound connections between GitLab and Jira.
- You must meet certain [Jira user requirements](../../administration/settings/jira_cloud_app.md#jira-user-requirements).
To install the GitLab for Jira Cloud app:
@ -75,16 +75,16 @@ DETAILS:
Prerequisites:
- You must have at least the Maintainer role for the GitLab group.
- The Jira user that installs and configures the GitLab for Jira Cloud app must meet certain [requirements](../../administration/settings/jira_cloud_app.md#jira-user-requirements).
- You must meet certain [Jira user requirements](../../administration/settings/jira_cloud_app.md#jira-user-requirements).
You can sync data from GitLab to Jira by linking the GitLab for Jira Cloud app to one or more GitLab groups.
To configure the GitLab for Jira Cloud app:
1. In Jira, on the top bar, select **Apps > Manage your apps**.
1. Expand **GitLab for Jira**.
1. Expand **GitLab for Jira (GitLab.com)**.
1. Select **Get started**.
1. Optional. Select **Change GitLab version** to set the GitLab instance to use with Jira.
1. Select **Sign into GitLab**.
1. Optional. To set the GitLab instance to use with Jira, select **Change GitLab version**.
1. Select **Sign in to GitLab**.
1. For a list of groups you can link to, select **Link groups**.
1. To link to a group, select **Link**.

View File

@ -21,18 +21,17 @@ To create Jira credentials, here's what we're going to do:
Prerequisites:
- You must have [site administrator](https://support.atlassian.com/user-management/docs/give-users-admin-permissions/#Make-someone-a-site-admin) access to the Jira instance.
- You must have at least the `Jira Administrators` [global permission](https://confluence.atlassian.com/adminjiraserver/managing-global-permissions-938847142.html).
## Create a Jira user
To create a Jira user:
1. Sign in to your Jira instance as an administrator.
1. On the top bar, in the upper-right corner, select **Administration** (**{settings}**) > **User management**.
1. [Create a new user account](https://confluence.atlassian.com/adminjiraserver/create-edit-or-remove-a-user-938847025.html#Create,edit,orremoveauser-CreateusersmanuallyinJira) with write access to your Jira projects.
Alternatively, you can use an existing user account, provided the user belongs to a Jira group that has been granted
the **Administer Projects** [permission scheme](#create-a-permission-scheme-for-the-group).
the `Administer Projects` [permission scheme](#create-a-permission-scheme-for-the-group).
- In **Email address**, enter a valid email address.
- In **Username**, enter `gitlab`.
@ -45,7 +44,6 @@ Now that you've created a user named `gitlab`, it's time to create a group for t
To create a Jira group for the user:
1. Sign in to your Jira instance as an administrator.
1. On the top bar, in the upper-right corner, select **Administration** (**{settings}**) > **User management**.
1. On the left sidebar, select **Groups**.
1. In the **Add group** section, enter a name for the group (for example,
@ -65,7 +63,6 @@ it's time to create a permission scheme for the group.
To create a permission scheme for the group:
1. Sign in to your Jira instance as an administrator.
1. On the top bar, in the upper-right corner, select **Administration** (**{settings}**) > **Issues**.
1. On the left sidebar, select **Permission schemes**.
1. Select **Add permission scheme**.

View File

@ -1,6 +1,6 @@
---
stage: Fulfillment
group: Purchase
group: Provision
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---

View File

@ -1,6 +1,6 @@
---
stage: Fulfillment
group: Purchase
group: Subscription Management
description: Options for accessing GitLab.
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---

View File

@ -1,6 +1,6 @@
---
stage: Fulfillment
group: Purchase
group: Subscription Management
description: Education, Open Source, Startups.
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---

View File

@ -1,6 +1,6 @@
---
stage: Fulfillment
group: Purchase
group: Subscription Management
description: Payment and company details.
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---

View File

@ -1,6 +1,6 @@
---
stage: Fulfillment
group: Purchase
group: Subscription Management
description: Seat usage, compute minutes, storage limits, renewal info.
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@ -387,6 +387,28 @@ To add a secondary contact for your subscription:
[Customers Portal](https://customers.gitlab.com/customers/sign_in) for the user you want to add.
1. [Create a ticket with the Support team](https://support.gitlab.com/hc/en-us/requests/new?ticket_form_id=360000071293). Include any relevant material in your request.
## GitLab Duo Pro
Increase developer productivity across the software development lifecycle. Refer to [GitLab Duo](../../user/ai_features.md) for more information.
### Purchase additional GitLab Duo Pro seats
If you're using GitLab SaaS, you can purchase additional seats for the GitLab Duo Pro product.
<!-- vale gitlab.Substitutions = NO -->
1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > Usage Quotas**.
1. Select **Duo Pro**.
1. Select **Add seats**. GitLab redirects you to the Customers Portal.
1. Enter the desired quantity of GitLab Duo Pro seats. Mind that it should not be higher than the amount of seats in your group namespace main subscription.
1. In the **Billing information** section select the payment method from the dropdown list.
1. Select the **Privacy Policy** and **Terms of Service** checkbox.
1. Select **Purchase seats**.
1. Switch back to the GitLab SaaS tab and refresh the page.
<!-- vale gitlab.Substitutions = YES -->
After your payment is processed, the additional seats are available for your group namespace.
## Compute
Compute is the resource consumed when running [pipelines](../../ci/pipelines/index.md)

View File

@ -1,6 +1,6 @@
---
stage: Fulfillment
group: Purchase
group: Subscription Management
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---

View File

@ -1,6 +1,6 @@
---
stage: Fulfillment
group: Purchase
group: Subscription Management
description: Billing examples.
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---

View File

@ -1,6 +1,6 @@
---
stage: Fulfillment
group: Purchase
group: Provision
description: Seat assignment, GitLab Duo Pro add-on
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@ -21,12 +21,10 @@ add-ons can be assigned to billable users only.
Prerequisites:
- You must purchase the GitLab Duo Pro add-on from the [GitLab Sales Team](https://about.gitlab.com/solutions/gitlab-duo-pro/sales/).
- For self-managed and GitLab Dedicated, the GitLab Duo Pro add-on is available for GitLab 16.8 and later only.
After you purchase GitLab Duo Pro, you can assign seats to billable users to grant access to the add-on.
NOTE:
For self-managed and GitLab Dedicated, the GitLab Duo Pro add-on is available for GitLab 16.8 and later only.
### For GitLab.com
1. On the left sidebar, select **Search or go to** and find your group.

View File

@ -1509,6 +1509,24 @@ This change is a breaking change. You should [create a runner in the UI](../ci/r
<div class="deprecation breaking-change" data-milestone="17.0">
### Removal of tags from small SaaS runners on Linux
<div class="deprecation-notes">
- Announced in GitLab <span class="milestone">16.9</span>
- Removal in GitLab <span class="milestone">17.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/30829).
</div>
Due to historical reasons, small Linux SaaS Runners had a lot of tags attached because they were used as labels. We want to streamline the tag to just use `saas-linux-small-amd64` and be consistent across all SaaS runners.
We are deprecating the tags: `docker`, `east-c`, `gce`, `git-annex`, `linux`, `mongo`, `mysql`, `postgres`, `ruby`, `shared`.
For more information, see [Removing tags from our small SaaS runner on Linux](https://about.gitlab.com/blog/2023/08/15/removing-tags-from-small-saas-runner-on-linux/).
</div>
<div class="deprecation breaking-change" data-milestone="17.0">
### Rename the 'require_password_to_approve' field
<div class="deprecation-notes">
@ -1849,6 +1867,25 @@ You can still access unified approval rules with the API.
<div class="deprecation breaking-change" data-milestone="17.0">
### Upgrading the operating system version of GitLab SaaS runners on Linux
<div class="deprecation-notes">
- Announced in GitLab <span class="milestone">16.9</span>
- Removal in GitLab <span class="milestone">17.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/ci-cd/shared-runners/infrastructure/-/issues/60).
</div>
GitLab is upgrading the container-optimized operating system (COS) of the ephemeral VMs used to execute jobs for SaaS runners on Linux.
That COS upgrade includes a Docker Engine upgrade from Version 19.03.15 to Version 23.0.5, which introduces a known compatibility issue.
Docker-in-Docker prior to version 20.10 or Kaniko images older than v1.9.0, will be unable to detect the container runtime and fail.
For more information, see [Upgrading the operating system version of our SaaS runners on Linux](https://about.gitlab.com/blog/2023/10/04/updating-the-os-version-of-saas-runners-on-linux/).
</div>
<div class="deprecation breaking-change" data-milestone="17.0">
### Vulnerability confidence field
<div class="deprecation-notes">

View File

@ -76,13 +76,16 @@ GitLab uses these IDs to look up users.
If the identity provider does not know the current values for these fields,
that provider may create duplicate users, or fail to complete expected actions.
To change the identifier values to match:
To change the identifier values to match, you can do one of the following:
1. Have users unlink and relink themselves, based on the
- Have users unlink and relink themselves, based on the
[SAML authentication failed: User has already been taken](troubleshooting.md#message-saml-authentication-failed-user-has-already-been-taken)
section.
1. Unlink all users simultaneously by removing all users from the SCIM app while provisioning is turned on.
1. Use the [SAML API](../../../api/saml.md) or [SCIM API](../../../api/scim.md) to manually correct the `extern_uid` stored for users to match the SAML
- Unlink all users simultaneously by removing all users from the SCIM app while provisioning is turned on.
WARNING:
This resets all users' roles in the top level group and subgroups to the [configured default membership role](index.md#configure-gitlab).
- Use the [SAML API](../../../api/saml.md) or [SCIM API](../../../api/scim.md) to manually correct the `extern_uid` stored for users to match the SAML
`NameId` or SCIM `externalId`.
You must not:

View File

@ -229,6 +229,7 @@ module API
optional :namespace_aggregation_schedule_lease_duration_in_seconds, type: Integer, desc: 'Maximum duration (in seconds) between refreshes of namespace statistics (Default: 300)'
optional :project_jobs_api_rate_limit, type: Integer, desc: 'Maximum authenticated requests to /project/:id/jobs per minute'
optional :security_txt_content, type: String, desc: 'Public security contact information made available at https://gitlab.example.com/.well-known/security.txt'
optional :downstream_pipeline_trigger_limit_per_project_user_sha, type: Integer, desc: 'Maximum number of downstream pipelines triggered per project'
Gitlab::SSHPublicKey.supported_types.each do |type|
optional :"#{type}_key_restriction",

View File

@ -10,7 +10,6 @@ module API
namespace 'usage_data' do
before do
not_found! unless Feature.enabled?(:usage_data_api, type: :ops)
forbidden!('Invalid CSRF token is provided') unless verified_request?
end

View File

@ -67,7 +67,7 @@ module Gitlab
threshold: -> { application_settings.projects_api_rate_limit_unauthenticated }, interval: 10.minutes
},
downstream_pipeline_trigger: {
threshold: -> { ::Ci::TriggerDownstreamPipelineService::DOWNSTREAM_PIPELINE_TRIGGER_LIMIT_PER_PROJECT_USER_SHA }, interval: 1.minute
threshold: -> { application_settings.downstream_pipeline_trigger_limit_per_project_user_sha }, interval: 1.minute
}
}.freeze
end

View File

@ -72,7 +72,6 @@ module Gitlab
# Initialize gon.features with any flags that should be
# made globally available to the frontend
push_frontend_feature_flag(:usage_data_api, type: :ops)
push_frontend_feature_flag(:security_auto_fix)
push_frontend_feature_flag(:source_editor_toolbar)
push_frontend_feature_flag(:vscode_web_ide, current_user)

View File

@ -68,7 +68,6 @@ namespace :tw do
CodeOwnerRule.new('Product Planning', '@msedlakjakubowski'),
CodeOwnerRule.new('Project Management', '@msedlakjakubowski'),
CodeOwnerRule.new('Provision', '@fneill'),
CodeOwnerRule.new('Purchase', '@fneill'),
CodeOwnerRule.new('Redirect', 'Redirect'),
# CodeOwnerRule.new('Respond', ''),
CodeOwnerRule.new('Runner', '@fneill'),
@ -77,6 +76,7 @@ namespace :tw do
CodeOwnerRule.new('Solutions Architecture', '@jfullam @brianwald @Darwinjs'),
CodeOwnerRule.new('Source Code', '@msedlakjakubowski'),
CodeOwnerRule.new('Static Analysis', '@rdickenson'),
# CodeOwnerRule.new('Subscription Management', ''),
CodeOwnerRule.new('Tenant Scale', '@lciutacu'),
CodeOwnerRule.new('Testing', '@eread'),
CodeOwnerRule.new('Threat Insights', '@rdickenson'),

View File

@ -3584,6 +3584,9 @@ msgstr ""
msgid "AdminSettings|Limit the number of namespaces and projects that can be indexed."
msgstr ""
msgid "AdminSettings|Maximum downstream pipelines triggered in a project per user"
msgstr ""
msgid "AdminSettings|Maximum duration of a session for Git operations when 2FA is enabled."
msgstr ""
@ -3743,6 +3746,9 @@ msgstr ""
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
msgid "AdminSettings|The maximum number of downstream pipelines triggered in a project per user."
msgstr ""
msgid "AdminSettings|The maximum number of included files per pipeline."
msgstr ""
@ -4289,10 +4295,10 @@ msgstr ""
msgid "Admin|Deploy Keys"
msgstr ""
msgid "Admin|Duo Pro"
msgid "Admin|Geo"
msgstr ""
msgid "Admin|Geo"
msgid "Admin|GitLab Duo Pro"
msgstr ""
msgid "Admin|Kubernetes"
@ -8096,13 +8102,13 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
msgid "Billing|An error occurred while loading details for the Duo Pro add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgid "Billing|An error occurred while loading details for the GitLab Duo Pro add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
msgstr ""
msgid "Billing|An error occurred while loading users of the Duo Pro add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgid "Billing|An error occurred while loading users of the GitLab Duo Pro add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while removing a billable member."
@ -8120,10 +8126,10 @@ msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
msgid "Billing|Error assigning Duo Pro add-on"
msgid "Billing|Error assigning GitLab Duo Pro add-on"
msgstr ""
msgid "Billing|Error un-assigning Duo Pro add-on"
msgid "Billing|Error un-assigning GitLab Duo Pro add-on"
msgstr ""
msgid "Billing|Explore paid plans"
@ -8185,7 +8191,7 @@ msgstr ""
msgid "Billing|You can upgrade to a paid tier to get access to more features."
msgstr ""
msgid "Billing|You have assigned all available Duo Pro add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
msgid "Billing|You have assigned all available GitLab Duo Pro add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
msgstr ""
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
@ -12106,7 +12112,7 @@ msgstr ""
msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
msgid "CodeSuggestions|A user can be assigned a Duo Pro seat only once each billable month."
msgid "CodeSuggestions|A user can be assigned a GitLab Duo Pro seat only once each billable month."
msgstr ""
msgid "CodeSuggestions|Boost productivity by using %{linkStart}Code Suggestions%{linkEnd} to write and understand code. Starting in February 2024, Code Suggestions will be part of %{duoLinkStart}GitLab Duo Pro%{duoLinkEnd}, available to Premium and Ultimate users for purchase now."
@ -12115,28 +12121,28 @@ msgstr ""
msgid "CodeSuggestions|Code Suggestions"
msgstr ""
msgid "CodeSuggestions|Duo Pro"
msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}GitLab Duo Pro%{linkEnd} offers features that use generative AI to suggest code."
msgstr ""
msgid "CodeSuggestions|Duo Pro add-on"
msgid "CodeSuggestions|GitLab Duo Pro"
msgstr ""
msgid "CodeSuggestions|Duo Pro add-on status"
msgid "CodeSuggestions|GitLab Duo Pro add-on"
msgstr ""
msgid "CodeSuggestions|Duo Pro seats used"
msgid "CodeSuggestions|GitLab Duo Pro add-on status"
msgstr ""
msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Duo Pro%{linkEnd} offers features that use generative AI to suggest code."
msgid "CodeSuggestions|GitLab Duo Pro seats used"
msgstr ""
msgid "CodeSuggestions|Introducing Duo Pro"
msgid "CodeSuggestions|Introducing GitLab Duo Pro"
msgstr ""
msgid "CodeSuggestions|Introducing the GitLab Duo Pro add-on"
msgstr ""
msgid "CodeSuggestions|Manage seat assignments for Duo Pro across your instance."
msgid "CodeSuggestions|Manage seat assignments for GitLab Duo Pro across your instance."
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@ -12210,9 +12216,6 @@ msgstr ""
msgid "Collapse AI-generated summary"
msgstr ""
msgid "Collapse all threads"
msgstr ""
msgid "Collapse eligible approvers"
msgstr ""
@ -20308,9 +20311,6 @@ msgstr ""
msgid "Expand all files"
msgstr ""
msgid "Expand all threads"
msgstr ""
msgid "Expand eligible approvers"
msgstr ""
@ -24601,6 +24601,9 @@ msgstr ""
msgid "Hide Live Preview"
msgstr ""
msgid "Hide all comments"
msgstr ""
msgid "Hide archived projects"
msgstr ""
@ -33496,6 +33499,12 @@ msgstr ""
msgid "Notify|Remote mirror"
msgstr ""
msgid "Notify|Review changes"
msgstr ""
msgid "Notify|Review requested"
msgstr ""
msgid "Notify|SMTP host issue:"
msgstr ""
@ -33589,6 +33598,9 @@ msgstr ""
msgid "Notify|You have been unsubscribed from receiving GitLab administrator notifications."
msgstr ""
msgid "Notify|You were added as a reviewer on %{long_mr} by %{name}."
msgstr ""
msgid "Notify|Your CSV import for project %{project_link} has been completed."
msgstr ""
@ -46546,6 +46558,9 @@ msgstr ""
msgid "Show all breadcrumbs"
msgstr ""
msgid "Show all comments"
msgstr ""
msgid "Show all epics"
msgstr ""
@ -53336,9 +53351,6 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
msgid "UsageQuota|Duo Pro"
msgstr ""
msgid "UsageQuota|Filter charts by year"
msgstr ""
@ -53348,6 +53360,9 @@ msgstr ""
msgid "UsageQuota|Git repository."
msgstr ""
msgid "UsageQuota|GitLab Duo Pro"
msgstr ""
msgid "UsageQuota|Gitlab-integrated Docker Container Registry for storing Docker Images."
msgstr ""

View File

@ -0,0 +1,34 @@
# frozen_string_literal: true
FactoryBot.define do
factory :member_approval, class: 'Members::MemberApproval' do
requested_by { association(:user) }
reviewed_by { association(:user) }
old_access_level { ::Gitlab::Access::GUEST }
new_access_level { ::Gitlab::Access::DEVELOPER }
status { ::Members::MemberApproval.statuses[:pending] }
member { association(:project_member) } # default
member_namespace_id { member.member_namespace_id }
# Traits for specific group members
trait :for_group_member do
member { association(:group_member) }
end
trait :for_project_member do
member { association(:project_member) }
end
trait(:guest) { old_access_level { GroupMember::GUEST } }
trait(:reporter) { old_access_level { GroupMember::REPORTER } }
trait(:developer) { old_access_level { GroupMember::DEVELOPER } }
trait(:maintainer) { old_access_level { GroupMember::MAINTAINER } }
trait(:owner) { old_access_level { GroupMember::OWNER } }
trait(:to_guest) { new_access_level { GroupMember::GUEST } }
trait(:to_reporter) { new_access_level { GroupMember::REPORTER } }
trait(:to_developer) { new_access_level { GroupMember::DEVELOPER } }
trait(:to_maintainer) { new_access_level { GroupMember::MAINTAINER } }
trait(:to_owner) { new_access_level { GroupMember::OWNER } }
end
end

View File

@ -459,6 +459,7 @@ RSpec.describe 'Admin updates settings', feature_category: :shared do
uncheck 'Keep the latest artifacts for all jobs in the latest successful pipelines'
uncheck 'Enable pipeline suggestion banner'
fill_in 'application_setting_ci_max_includes', with: 200
fill_in 'application_setting_downstream_pipeline_trigger_limit_per_project_user_sha', with: 500
click_button 'Save changes'
end
@ -467,6 +468,7 @@ RSpec.describe 'Admin updates settings', feature_category: :shared do
expect(current_settings.keep_latest_artifact).to be false
expect(current_settings.suggest_pipeline_enabled).to be false
expect(current_settings.ci_max_includes).to be 200
expect(current_settings.downstream_pipeline_trigger_limit_per_project_user_sha).to be 500
expect(page).to have_content "Application settings saved successfully"
end

View File

@ -14,12 +14,12 @@ describe('DiffDiscussions', () => {
let wrapper;
const getDiscussionsMockData = () => [{ ...discussionsMockData }];
const createComponent = (props) => {
const createComponent = (props, discussions = getDiscussionsMockData()) => {
store = createStore();
wrapper = mount(DiffDiscussions, {
store,
propsData: {
discussions: getDiscussionsMockData(),
discussions,
...props,
},
});
@ -43,7 +43,9 @@ describe('DiffDiscussions', () => {
const findDiffNotesToggle = () => wrapper.find('.js-diff-notes-toggle');
it('renders collapsible discussion button', () => {
createComponent({ shouldCollapseDiscussions: true });
const discussions = getDiscussionsMockData();
discussions[0].expandedOnDiff = true;
createComponent({ shouldCollapseDiscussions: true }, discussions);
const diffNotesToggle = findDiffNotesToggle();
expect(diffNotesToggle.exists()).toBe(true);
@ -52,19 +54,19 @@ describe('DiffDiscussions', () => {
});
it('dispatches toggleDiscussion when clicking collapse button', () => {
createComponent({ shouldCollapseDiscussions: true });
const discussions = getDiscussionsMockData();
discussions[0].expandedOnDiff = true;
createComponent({ shouldCollapseDiscussions: true }, discussions);
jest.spyOn(store, 'dispatch').mockImplementation();
findDiffNotesToggle().trigger('click');
expect(store.dispatch).toHaveBeenCalledWith('toggleDiscussion', {
discussionId: discussionsMockData.id,
});
expect(store.dispatch).toHaveBeenCalledWith('diffs/toggleFileDiscussion', discussions[0]);
});
it('renders expand button when discussion is collapsed', () => {
const discussions = getDiscussionsMockData();
discussions[0].expanded = false;
discussions[0].expandedOnDiff = false;
createComponent({ discussions, shouldCollapseDiscussions: true });
const diffNotesToggle = findDiffNotesToggle();
@ -76,7 +78,7 @@ describe('DiffDiscussions', () => {
it('hides discussion when collapsed', () => {
const discussions = getDiscussionsMockData();
discussions[0].expanded = false;
discussions[0].expandedOnDiff = false;
createComponent({ discussions, shouldCollapseDiscussions: true });
expect(findNoteableDiscussion().isVisible()).toBe(false);

View File

@ -67,7 +67,6 @@ describe('DiffFileHeader component', () => {
diffHasDiscussions: () => diffHasDiscussionsResultMock,
},
actions: {
toggleFileDiscussions: jest.fn(),
toggleFileDiscussionWrappers: jest.fn(),
toggleFullDiff: jest.fn(),
setCurrentFileHash: jest.fn(),

View File

@ -1059,62 +1059,6 @@ describe('DiffsStoreActions', () => {
});
});
describe('toggleFileDiscussions', () => {
it('should dispatch collapseDiscussion when all discussions are expanded', () => {
const getters = {
getDiffFileDiscussions: jest.fn(() => [{ id: 1 }]),
diffHasAllExpandedDiscussions: jest.fn(() => true),
diffHasAllCollapsedDiscussions: jest.fn(() => false),
};
const dispatch = jest.fn();
diffActions.toggleFileDiscussions({ getters, dispatch });
expect(dispatch).toHaveBeenCalledWith(
'collapseDiscussion',
{ discussionId: 1 },
{ root: true },
);
});
it('should dispatch expandDiscussion when all discussions are collapsed', () => {
const getters = {
getDiffFileDiscussions: jest.fn(() => [{ id: 1 }]),
diffHasAllExpandedDiscussions: jest.fn(() => false),
diffHasAllCollapsedDiscussions: jest.fn(() => true),
};
const dispatch = jest.fn();
diffActions.toggleFileDiscussions({ getters, dispatch });
expect(dispatch).toHaveBeenCalledWith(
'expandDiscussion',
{ discussionId: 1 },
{ root: true },
);
});
it('should dispatch expandDiscussion when some discussions are collapsed and others are expanded for the collapsed discussion', () => {
const getters = {
getDiffFileDiscussions: jest.fn(() => [{ expanded: false, id: 1 }]),
diffHasAllExpandedDiscussions: jest.fn(() => false),
diffHasAllCollapsedDiscussions: jest.fn(() => false),
};
const dispatch = jest.fn();
diffActions.toggleFileDiscussions({ getters, dispatch });
expect(dispatch).toHaveBeenCalledWith(
'expandDiscussion',
{ discussionId: 1 },
{ root: true },
);
});
});
describe('scrollToLineIfNeededInline', () => {
const lineMock = {
line_code: 'ABC_123',

View File

@ -1,4 +1,8 @@
import { PARALLEL_DIFF_VIEW_TYPE, INLINE_DIFF_VIEW_TYPE } from '~/diffs/constants';
import {
PARALLEL_DIFF_VIEW_TYPE,
INLINE_DIFF_VIEW_TYPE,
INLINE_DIFF_LINES_KEY,
} from '~/diffs/constants';
import * as getters from '~/diffs/store/getters';
import state from '~/diffs/store/modules/diff_state';
import { getDiffFileMock } from 'jest/diffs/mock_data/diff_file';
@ -527,4 +531,63 @@ describe('Diffs Module Getters', () => {
expect(getters.pinnedFile({}, {})).toBe(null);
});
});
describe('allDiffDiscussionsExpanded', () => {
it('returns true when all line discussions are expanded', () => {
localState.diffFiles = [
{
[INLINE_DIFF_LINES_KEY]: [
{ discussionsExpanded: true, discussions: [{}] },
{ discussionsExpanded: true, discussions: [{}] },
],
},
];
expect(getters.allDiffDiscussionsExpanded(localState)).toBe(true);
});
it('returns false if at least one line discussion is collapsed', () => {
localState.diffFiles = [
{
[INLINE_DIFF_LINES_KEY]: [
{ discussionsExpanded: true, discussions: [{}] },
{ discussionsExpanded: false, discussions: [{}] },
],
},
];
expect(getters.allDiffDiscussionsExpanded(localState)).toBe(false);
});
it('returns false if at least one image discussion is collapsed', () => {
localState.diffFiles = [
{
[INLINE_DIFF_LINES_KEY]: [
{ discussionsExpanded: true, discussions: [{}] },
{ discussionsExpanded: true, discussions: [{}] },
],
},
{
[INLINE_DIFF_LINES_KEY]: [],
viewer: { name: 'image' },
discussions: [{ expandedOnDiff: false }],
},
];
expect(getters.allDiffDiscussionsExpanded(localState)).toBe(false);
});
it('returns true if all image discussions are expanded', () => {
localState.diffFiles = [
{
viewer: { name: 'text' },
[INLINE_DIFF_LINES_KEY]: [],
discussions: [],
},
{
viewer: { name: 'image' },
[INLINE_DIFF_LINES_KEY]: [],
discussions: [{ expandedOnDiff: true }, { expandedOnDiff: true }],
},
];
expect(getters.allDiffDiscussionsExpanded(localState)).toBe(true);
});
});
});

View File

@ -674,6 +674,167 @@ describe('DiffsStoreMutations', () => {
expect(state.diffFiles[0].discussions.length).toEqual(1);
});
describe('expanded state', () => {
it('should expand discussion by default', () => {
const diffPosition = {
base_sha: 'ed13df29948c41ba367caa757ab3ec4892509910',
head_sha: 'b921914f9a834ac47e6fd9420f78db0f83559130',
new_line: null,
new_path: '500-lines-4.txt',
old_line: 5,
old_path: '500-lines-4.txt',
start_sha: 'ed13df29948c41ba367caa757ab3ec4892509910',
};
const state = {
latestDiff: true,
diffFiles: [
{
file_hash: 'ABC',
[INLINE_DIFF_LINES_KEY]: [
{
line_code: 'ABC_1',
discussions: [],
},
],
},
],
};
const discussion = {
id: 1,
line_code: 'ABC_2',
line_codes: ['ABC_1'],
diff_discussion: true,
resolvable: true,
original_position: {},
position: {},
positions: [diffPosition],
diff_file: {
file_hash: state.diffFiles[0].file_hash,
},
};
const diffPositionByLineCode = {
ABC_1: diffPosition,
};
mutations[types.SET_LINE_DISCUSSIONS_FOR_FILE](state, {
discussion,
diffPositionByLineCode,
});
expect(state.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussionsExpanded).toBe(true);
});
it('should collapse resolved discussion', () => {
const diffPosition = {
base_sha: 'ed13df29948c41ba367caa757ab3ec4892509910',
head_sha: 'b921914f9a834ac47e6fd9420f78db0f83559130',
new_line: null,
new_path: '500-lines-4.txt',
old_line: 5,
old_path: '500-lines-4.txt',
start_sha: 'ed13df29948c41ba367caa757ab3ec4892509910',
};
const state = {
latestDiff: true,
diffFiles: [
{
file_hash: 'ABC',
[INLINE_DIFF_LINES_KEY]: [
{
line_code: 'ABC_1',
discussions: [],
},
],
},
],
};
const discussion = {
id: 1,
line_code: 'ABC_2',
line_codes: ['ABC_1'],
diff_discussion: true,
resolvable: true,
original_position: {},
position: {},
positions: [diffPosition],
diff_file: {
file_hash: state.diffFiles[0].file_hash,
},
resolved: true,
};
const diffPositionByLineCode = {
ABC_1: diffPosition,
};
mutations[types.SET_LINE_DISCUSSIONS_FOR_FILE](state, {
discussion,
diffPositionByLineCode,
});
expect(state.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussionsExpanded).toBe(false);
});
it('should keep resolved state for expanded discussion update', () => {
const diffPosition = {
base_sha: 'ed13df29948c41ba367caa757ab3ec4892509910',
head_sha: 'b921914f9a834ac47e6fd9420f78db0f83559130',
new_line: null,
new_path: '500-lines-4.txt',
old_line: 5,
old_path: '500-lines-4.txt',
start_sha: 'ed13df29948c41ba367caa757ab3ec4892509910',
};
const state = {
latestDiff: true,
diffFiles: [
{
file_hash: 'ABC',
[INLINE_DIFF_LINES_KEY]: [
{
line_code: 'ABC_1',
discussions: [],
},
],
},
],
};
const discussion = {
id: 1,
line_code: 'ABC_2',
line_codes: ['ABC_1'],
diff_discussion: true,
resolvable: true,
original_position: {},
position: {},
positions: [diffPosition],
diff_file: {
file_hash: state.diffFiles[0].file_hash,
},
};
const diffPositionByLineCode = {
ABC_1: diffPosition,
};
mutations[types.SET_LINE_DISCUSSIONS_FOR_FILE](state, {
discussion,
diffPositionByLineCode,
});
mutations[types.SET_LINE_DISCUSSIONS_FOR_FILE](state, {
discussion: { ...discussion, resolved: true },
diffPositionByLineCode,
});
expect(state.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussionsExpanded).toBe(true);
});
});
});
describe('REMOVE_LINE_DISCUSSIONS', () => {
@ -1121,6 +1282,61 @@ describe('DiffsStoreMutations', () => {
});
});
describe('TOGGLE_FILE_DISCUSSION_EXPAND', () => {
const fileHash = 'foo';
it('expands collapsed discussion', () => {
const discussion = {
diff_file: { file_hash: fileHash },
expandedOnDiff: false,
};
const state = {
diffFiles: [{ file_hash: fileHash, discussions: [discussion] }],
};
mutations[types.TOGGLE_FILE_DISCUSSION_EXPAND](state, discussion);
expect(state.diffFiles[0].discussions[0].expandedOnDiff).toBe(true);
});
it('collapses expanded discussion', () => {
const discussion = {
diff_file: { file_hash: fileHash },
expandedOnDiff: true,
};
const state = {
diffFiles: [{ file_hash: fileHash, discussions: [discussion] }],
};
mutations[types.TOGGLE_FILE_DISCUSSION_EXPAND](state, discussion);
expect(state.diffFiles[0].discussions[0].expandedOnDiff).toBe(false);
});
});
describe('SET_EXPAND_ALL_DIFF_DISCUSSIONS', () => {
it('expands all discussions', () => {
const state = {
diffFiles: [
{
[INLINE_DIFF_LINES_KEY]: [
{ line_code: 'foo', discussions: [{}], discussionsExpanded: false },
],
},
{
[INLINE_DIFF_LINES_KEY]: [],
discussions: [{ expandedOnDiff: false }],
},
],
};
mutations[types.SET_EXPAND_ALL_DIFF_DISCUSSIONS](state, true);
expect(state.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussionsExpanded).toBe(true);
expect(state.diffFiles[1].discussions[0].expandedOnDiff).toBe(true);
});
});
describe('SET_PINNED_FILE_HASH', () => {
it('set pinned file hash', () => {
const state = {};

View File

@ -2,6 +2,13 @@ import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
import { createStore } from '~/mr_notes/stores';
import { getDiffFileMock } from 'jest/diffs/mock_data/diff_file';
import { SET_DIFF_DATA_BATCH, SET_LINE_DISCUSSIONS_FOR_FILE } from '~/diffs/store/mutation_types';
import { discussionMock } from 'jest/notes/mock_data';
import { getDiffPositionByLineCode } from '~/diffs/store/utils';
import { INLINE_DIFF_LINES_KEY } from '~/diffs/constants';
import { ADD_OR_UPDATE_DISCUSSIONS } from '~/notes/stores/mutation_types';
import mutationTypes from '~/mr_notes/stores/mutation_types';
describe('MR Notes Mutator Actions', () => {
let store;
@ -61,4 +68,44 @@ describe('MR Notes Mutator Actions', () => {
expect(store.state.page.failedToLoadMetadata).toBe(true);
});
});
describe('toggleAllVisibleDiscussions', () => {
beforeEach(() => {
const diff = getDiffFileMock();
const discussion = {
...discussionMock,
diff_file: diff,
line_code: diff[INLINE_DIFF_LINES_KEY][0].line_code,
};
store.commit(ADD_OR_UPDATE_DISCUSSIONS, [discussion]);
store.commit(`diffs/${SET_DIFF_DATA_BATCH}`, { diff_files: [diff] });
store.commit(`diffs/${SET_LINE_DISCUSSIONS_FOR_FILE}`, {
discussion,
diffPositionByLineCode: getDiffPositionByLineCode(store.state.diffs.diffFiles),
hash: diff.file_hash,
});
});
it('dispatches toggleAllDiscussions', async () => {
expect(store.state.notes.discussions[0].expanded).toEqual(true);
await store.dispatch('toggleAllVisibleDiscussions');
expect(store.state.notes.discussions[0].expanded).toEqual(false);
});
it('dispatches toggleAllDiffDiscussions when on diffs page', async () => {
store.commit(mutationTypes.SET_ACTIVE_TAB, 'diffs');
expect(store.state.diffs.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussionsExpanded).toEqual(
true,
);
await store.dispatch('toggleAllVisibleDiscussions');
expect(store.state.diffs.diffFiles[0][INLINE_DIFF_LINES_KEY][0].discussionsExpanded).toEqual(
false,
);
});
});
});

View File

@ -1,37 +1,22 @@
import { GlDisclosureDropdown, GlDisclosureDropdownItem } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
import Vue from 'vue';
// eslint-disable-next-line no-restricted-imports
import Vuex from 'vuex';
import DiscussionCounter from '~/notes/components/discussion_counter.vue';
import notesModule from '~/notes/stores/modules';
import * as types from '~/notes/stores/mutation_types';
import { discussionMock, noteableDataMock, notesDataMock, userDataMock } from '../mock_data';
import { createStore } from '~/mr_notes/stores';
import { discussionMock, noteableDataMock, notesDataMock } from '../mock_data';
describe('DiscussionCounter component', () => {
let store;
let wrapper;
let setExpandDiscussionsFn;
Vue.use(Vuex);
beforeEach(() => {
window.mrTabs = {};
const { state, getters, mutations, actions } = notesModule();
setExpandDiscussionsFn = jest.fn().mockImplementation(actions.setExpandDiscussions);
store = new Vuex.Store({
state: {
...state,
userData: userDataMock,
},
getters,
mutations,
actions: {
...actions,
setExpandDiscussions: setExpandDiscussionsFn,
},
});
store = createStore();
store.dispatch('setNoteableData', {
...noteableDataMock,
create_issue_to_resolve_discussions_path: '/test',
@ -39,10 +24,6 @@ describe('DiscussionCounter component', () => {
store.dispatch('setNotesData', notesDataMock);
});
afterEach(() => {
wrapper.vm.$destroy();
});
describe('has no discussions', () => {
it('does not render', () => {
wrapper = mount(DiscussionCounter, { store, propsData: { blocksMerge: true } });
@ -88,7 +69,7 @@ describe('DiscussionCounter component', () => {
'changes background color to $color if blocksMerge is $blocksMerge',
({ blocksMerge, color }) => {
updateStore();
store.state.unresolvedDiscussionsCount = 1;
store.state.notes.unresolvedDiscussionsCount = 1;
wrapper = mount(DiscussionCounter, { store, propsData: { blocksMerge } });
expect(wrapper.find('[data-testid="discussions-counter-text"]').classes()).toContain(color);
@ -125,8 +106,10 @@ describe('DiscussionCounter component', () => {
describe('toggle all threads button', () => {
let toggleAllButton;
let discussion;
const updateStoreWithExpanded = async (expanded) => {
const discussion = { ...discussionMock, expanded };
discussion = { ...discussionMock, expanded };
store.commit(types.ADD_OR_UPDATE_DISCUSSIONS, [discussion]);
store.dispatch('updateResolvableDiscussionsCounts');
wrapper = mount(DiscussionCounter, { store, propsData: { blocksMerge: true } });
@ -134,34 +117,25 @@ describe('DiscussionCounter component', () => {
toggleAllButton = wrapper.find('[data-testid="toggle-all-discussions-btn"]');
};
it('calls button handler when clicked', async () => {
await updateStoreWithExpanded(true);
toggleAllButton.trigger('click');
expect(setExpandDiscussionsFn).toHaveBeenCalledTimes(1);
afterEach(() => {
toggleAllButton = undefined;
discussion = undefined;
});
it('collapses all discussions if expanded', async () => {
await updateStoreWithExpanded(true);
expect(wrapper.vm.allExpanded).toBe(true);
toggleAllButton.trigger('click');
await nextTick();
expect(wrapper.vm.allExpanded).toBe(false);
expect(store.state.notes.discussions[0].expanded).toBe(false);
});
it('expands all discussions if collapsed', async () => {
await updateStoreWithExpanded(false);
expect(wrapper.vm.allExpanded).toBe(false);
toggleAllButton.trigger('click');
await nextTick();
expect(wrapper.vm.allExpanded).toBe(true);
expect(store.state.notes.discussions[0].expanded).toBe(true);
});
});
});

View File

@ -1449,4 +1449,16 @@ describe('Actions Notes Store', () => {
);
});
});
describe('toggleAllDiscussions', () => {
it('commits SET_EXPAND_ALL_DISCUSSIONS', () => {
return testAction(
actions.toggleAllDiscussions,
undefined,
{ allDiscussionsExpanded: false },
[{ type: mutationTypes.SET_EXPAND_ALL_DISCUSSIONS, payload: true }],
[],
);
});
});
});

View File

@ -578,4 +578,20 @@ describe('Getters Notes Store', () => {
},
);
});
describe('allDiscussionsExpanded', () => {
it('returns true when every discussion is expanded', () => {
state = {
discussions: [{ expanded: true }, { expanded: true }],
};
expect(getters.allDiscussionsExpanded(state)).toBe(true);
});
it('returns false when at least one discussion is collapsed', () => {
state = {
discussions: [{ expanded: true }, { expanded: false }],
};
expect(getters.allDiscussionsExpanded(state)).toBe(false);
});
});
});

View File

@ -940,4 +940,16 @@ describe('Notes Store mutations', () => {
expect(state.doneFetchingBatchDiscussions).toEqual(true);
});
});
describe('SET_EXPAND_ALL_DISCUSSIONS', () => {
it('should set expanded for every discussion', () => {
const state = {
discussions: [{ expanded: false }, { expanded: false }],
};
mutations.SET_EXPAND_ALL_DISCUSSIONS(state, true);
expect(state.discussions).toStrictEqual([{ expanded: true }, { expanded: true }]);
});
});
});

View File

@ -85,17 +85,6 @@ RSpec.describe Resolvers::Ci::Catalog::ResourcesResolver, feature_category: :pip
end
end
context 'and the ci_guard_for_catalog_resource_scope FF is disabled' do
before do
stub_feature_flags(ci_guard_for_catalog_resource_scope: false)
end
it 'returns all the catalog resources' do
expect(result.items.count).to be(3)
expect(result.items.pluck(:name)).to contain_exactly('public', 'internal', 'z private test')
end
end
context 'when the scope is invalid' do
let(:scope) { 'INVALID' }

View File

@ -65,7 +65,7 @@ RSpec.describe ApplicationSettingsHelper do
project_download_export_limit project_export_limit project_import_limit
raw_blob_request_limit group_export_limit group_download_export_limit
group_import_limit users_get_by_id_limit search_rate_limit search_rate_limit_unauthenticated
members_delete_limit
members_delete_limit downstream_pipeline_trigger_limit_per_project_user_sha
])
end

View File

@ -29,6 +29,7 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
it { expect(setting.bulk_import_concurrent_pipeline_batch_limit).to eq(25) }
it { expect(setting.allow_project_creation_for_guest_and_below).to eq(true) }
it { expect(setting.members_delete_limit).to eq(60) }
it { expect(setting.downstream_pipeline_trigger_limit_per_project_user_sha).to eq(0) }
end
describe 'validations' do
@ -244,6 +245,7 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
sidekiq_job_limiter_limit_bytes
terminal_max_session_time
users_get_by_id_limit
downstream_pipeline_trigger_limit_per_project_user_sha
]
end

View File

@ -74,23 +74,9 @@ RSpec.describe Ci::Catalog::Listing, feature_category: :pipeline_composition do
let(:params) { { scope: :namespaces } }
context 'when the `ci_guard_query_for_catalog_resource_scope` ff is enabled' do
it "returns the catalog resources belonging to the user's authorized namespaces" do
is_expected.to contain_exactly(public_resource_a, public_resource_b, internal_resource,
private_namespace_resource)
end
end
context 'when the `ci_guard_query_for_catalog_resource_scope` ff is disabled' do
before do
stub_feature_flags(ci_guard_for_catalog_resource_scope: false)
end
it 'returns all resources visible to the current user' do
is_expected.to contain_exactly(
public_resource_a, public_resource_b, private_namespace_resource,
internal_resource)
end
it "returns the catalog resources belonging to the user's authorized namespaces" do
is_expected.to contain_exactly(public_resource_a, public_resource_b, internal_resource,
private_namespace_resource)
end
end

Some files were not shown because too many files have changed in this diff Show More