Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-06-04 01:23:33 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-06-04 01:23:33 +0300
commit6c3124c854cbeef391a38b5ae8330174d78348bf (patch)
treeaf77629bc34ccc517ed24d9db35895be5d02d23d
parent9a8ae3b4e90e56f71bb770463b943512efdcd1d1 (diff)
Add latest changes from gitlab-org/gitlab@15-0-stable-ee
-rw-r--r--.gitlab/ci/review-apps/main.gitlab-ci.yml2
-rw-r--r--app/assets/javascripts/issues/show/components/description.vue22
-rw-r--r--app/assets/javascripts/issues/show/utils.js50
-rw-r--r--app/assets/javascripts/notes/components/comment_form.vue5
-rw-r--r--app/assets/stylesheets/framework/source_editor.scss5
-rw-r--r--app/assets/stylesheets/page_bundles/issues_show.scss41
-rw-r--r--app/assets/stylesheets/pages/issuable.scss8
-rw-r--r--app/helpers/issues_helper.rb2
-rw-r--r--app/models/member.rb1
-rw-r--r--app/models/user.rb13
-rw-r--r--config/initializers/1_settings.rb6
-rw-r--r--data/whats_new/202204210001_14_10.yml4
-rw-r--r--data/whats_new/202205220001_15_0.yml114
-rw-r--r--doc/administration/audit_event_streaming.md22
-rw-r--r--doc/administration/package_information/postgresql_versions.md2
-rw-r--r--doc/user/application_security/dependency_scanning/index.md2
-rw-r--r--lib/backup/gitaly_backup.rb10
-rw-r--r--lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Jobs/Dependency-Scanning.gitlab-ci.yml6
-rw-r--r--lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml2
-rw-r--r--lib/gitlab/usage/service_ping_report.rb2
-rwxr-xr-xscripts/review_apps/review-apps.sh1
-rw-r--r--spec/frontend/issues/show/utils_spec.js116
-rw-r--r--spec/frontend/notes/components/comment_form_spec.js20
-rw-r--r--spec/helpers/issues_helper_spec.rb12
-rw-r--r--spec/lib/backup/gitaly_backup_spec.rb10
-rw-r--r--spec/lib/gitlab/usage/service_ping_report_spec.rb29
-rw-r--r--spec/models/user_spec.rb20
-rw-r--r--spec/requests/api/users_spec.rb20
-rw-r--r--spec/services/users/destroy_service_spec.rb21
31 files changed, 490 insertions, 82 deletions
diff --git a/.gitlab/ci/review-apps/main.gitlab-ci.yml b/.gitlab/ci/review-apps/main.gitlab-ci.yml
index dde08b15bc3..22fdce71243 100644
--- a/.gitlab/ci/review-apps/main.gitlab-ci.yml
+++ b/.gitlab/ci/review-apps/main.gitlab-ci.yml
@@ -77,7 +77,7 @@ review-build-cng:
variables:
HOST_SUFFIX: "${CI_ENVIRONMENT_SLUG}"
DOMAIN: "-${CI_ENVIRONMENT_SLUG}.${REVIEW_APPS_DOMAIN}"
- GITLAB_HELM_CHART_REF: "41d7632d9eba84f5816d808b98ccf3f5623e9fb5"
+ GITLAB_HELM_CHART_REF: "a6a609a19166f00b1a7774374041cd38a9f7e20d"
environment:
name: review/${CI_COMMIT_REF_SLUG}${FREQUENCY}
url: https://gitlab-${CI_ENVIRONMENT_SLUG}.${REVIEW_APPS_DOMAIN}
diff --git a/app/assets/javascripts/issues/show/components/description.vue b/app/assets/javascripts/issues/show/components/description.vue
index 4f97458dcd1..daa1632c4aa 100644
--- a/app/assets/javascripts/issues/show/components/description.vue
+++ b/app/assets/javascripts/issues/show/components/description.vue
@@ -12,6 +12,7 @@ import Vue from 'vue';
import { getIdFromGraphQLId, convertToGraphQLId } from '~/graphql_shared/utils';
import { TYPE_WORK_ITEM } from '~/graphql_shared/constants';
import createFlash from '~/flash';
+import { IssuableType } from '~/issues/constants';
import { isPositiveInteger } from '~/lib/utils/number_utils';
import { getParameterByName, setUrlParams, updateHistory } from '~/lib/utils/url_utility';
import { __, s__, sprintf } from '~/locale';
@@ -66,7 +67,7 @@ export default {
issuableType: {
type: String,
required: false,
- default: 'issue',
+ default: IssuableType.Issue,
},
updateUrl: {
type: String,
@@ -177,7 +178,9 @@ export default {
onError: this.taskListUpdateError.bind(this),
});
- this.renderSortableLists();
+ if (this.issuableType === IssuableType.Issue) {
+ this.renderSortableLists();
+ }
}
},
renderSortableLists() {
@@ -185,6 +188,10 @@ export default {
const lists = document.querySelectorAll('.description ul, .description ol');
lists.forEach((list) => {
+ if (list.children.length <= 1) {
+ return;
+ }
+
Array.from(list.children).forEach((listItem) => {
listItem.prepend(this.createDragIconElement());
this.addPointerEventListeners(listItem);
@@ -211,13 +218,18 @@ export default {
},
addPointerEventListeners(listItem) {
const pointeroverListener = (event) => {
- if (isDragging() || this.isUpdating) {
+ const dragIcon = event.target.closest('li').querySelector('.drag-icon');
+ if (!dragIcon || isDragging() || this.isUpdating) {
return;
}
- event.target.closest('li').querySelector('.drag-icon').style.visibility = 'visible'; // eslint-disable-line no-param-reassign
+ dragIcon.style.visibility = 'visible';
};
const pointeroutListener = (event) => {
- event.target.closest('li').querySelector('.drag-icon').style.visibility = 'hidden'; // eslint-disable-line no-param-reassign
+ const dragIcon = event.target.closest('li').querySelector('.drag-icon');
+ if (!dragIcon) {
+ return;
+ }
+ dragIcon.style.visibility = 'hidden';
};
// We use pointerover/pointerout instead of CSS so that when we hover over a
diff --git a/app/assets/javascripts/issues/show/utils.js b/app/assets/javascripts/issues/show/utils.js
index 60e66f59f92..05b06586362 100644
--- a/app/assets/javascripts/issues/show/utils.js
+++ b/app/assets/javascripts/issues/show/utils.js
@@ -1,39 +1,35 @@
import { COLON, HYPHEN, NEWLINE } from '~/lib/utils/text_utility';
/**
- * Get the index from sourcepos that represents the line of
- * the description when the description is split by newline.
+ * Returns the start and end `sourcepos` rows, converted to zero-based numbering.
*
* @param {String} sourcepos Source position in format `23:3-23:14`
- * @returns {Number} Index of description split by newline
+ * @returns {Array<Number>} Start and end `sourcepos` rows, zero-based numbered
*/
-const getDescriptionIndex = (sourcepos) => {
- const [startRange] = sourcepos.split(HYPHEN);
+const getSourceposRows = (sourcepos) => {
+ const [startRange, endRange] = sourcepos.split(HYPHEN);
const [startRow] = startRange.split(COLON);
- return startRow - 1;
+ const [endRow] = endRange.split(COLON);
+ return [startRow - 1, endRow - 1];
};
/**
- * Given a `ul` or `ol` element containing a new sort order, this function performs
- * a depth-first search to get the new sort order in the form of sourcepos indices.
+ * Given a `ul` or `ol` element containing a new sort order, this function returns
+ * an array of this new order which is derived from its list items' sourcepos values.
*
* @param {HTMLElement} list A `ul` or `ol` element containing a new sort order
- * @returns {Array<Number>} An array representing the new order of the list
+ * @returns {Array<Number>} A numerical array representing the new order of the list.
+ * The numbers represent the rows of the original markdown source.
*/
const getNewSourcePositions = (list) => {
const newSourcePositions = [];
- function pushPositionOfChildListItems(el) {
- if (!el) {
- return;
+ Array.from(list.children).forEach((listItem) => {
+ const [start, end] = getSourceposRows(listItem.dataset.sourcepos);
+ for (let i = start; i <= end; i += 1) {
+ newSourcePositions.push(i);
}
- if (el.tagName === 'LI') {
- newSourcePositions.push(getDescriptionIndex(el.dataset.sourcepos));
- }
- Array.from(el.children).forEach(pushPositionOfChildListItems);
- }
-
- pushPositionOfChildListItems(list);
+ });
return newSourcePositions;
};
@@ -56,17 +52,17 @@ const getNewSourcePositions = (list) => {
* And a reordered list (due to dragging Item 2 into Item 1's position) like:
*
* <pre>
- * <ul data-sourcepos="3:1-8:0">
- * <li data-sourcepos="4:1-4:8">
+ * <ul data-sourcepos="3:1-7:8">
+ * <li data-sourcepos="4:1-6:10">
* Item 2
- * <ul data-sourcepos="5:1-6:10">
- * <li data-sourcepos="5:1-5:10">Item 3</li>
- * <li data-sourcepos="6:1-6:10">Item 4</li>
+ * <ul data-sourcepos="5:3-6:10">
+ * <li data-sourcepos="5:3-5:10">Item 3</li>
+ * <li data-sourcepos="6:3-6:10">Item 4</li>
* </ul>
* </li>
* <li data-sourcepos="3:1-3:8">Item 1</li>
- * <li data-sourcepos="7:1-8:0">Item 5</li>
- * <ul>
+ * <li data-sourcepos="7:1-7:8">Item 5</li>
+ * </ul>
* </pre>
*
* This function returns:
@@ -87,7 +83,7 @@ const getNewSourcePositions = (list) => {
*/
export const convertDescriptionWithNewSort = (description, list) => {
const descriptionLines = description.split(NEWLINE);
- const startIndexOfList = getDescriptionIndex(list.dataset.sourcepos);
+ const [startIndexOfList] = getSourceposRows(list.dataset.sourcepos);
getNewSourcePositions(list)
.map((lineIndex) => descriptionLines[lineIndex])
diff --git a/app/assets/javascripts/notes/components/comment_form.vue b/app/assets/javascripts/notes/components/comment_form.vue
index 4e03bed8737..8ef071034e5 100644
--- a/app/assets/javascripts/notes/components/comment_form.vue
+++ b/app/assets/javascripts/notes/components/comment_form.vue
@@ -111,7 +111,7 @@ export default {
return this.getNoteableData.current_user.can_create_note;
},
canSetConfidential() {
- return this.getNoteableData.current_user.can_update;
+ return this.getNoteableData.current_user.can_update && (this.isIssue || this.isEpic);
},
issueActionButtonTitle() {
const openOrClose = this.isOpen ? 'close' : 'reopen';
@@ -166,6 +166,9 @@ export default {
isIssue() {
return constants.NOTEABLE_TYPE_MAPPING[this.noteableType] === constants.ISSUE_NOTEABLE_TYPE;
},
+ isEpic() {
+ return constants.NOTEABLE_TYPE_MAPPING[this.noteableType] === constants.EPIC_NOTEABLE_TYPE;
+ },
trackingLabel() {
return slugifyWithUnderscore(`${this.commentButtonTitle} button`);
},
diff --git a/app/assets/stylesheets/framework/source_editor.scss b/app/assets/stylesheets/framework/source_editor.scss
index 8b694b9be05..046b8636f65 100644
--- a/app/assets/stylesheets/framework/source_editor.scss
+++ b/app/assets/stylesheets/framework/source_editor.scss
@@ -83,6 +83,11 @@
}
}
}
+
+ // Remove custom focus from element
+ .inputarea {
+ @include gl-shadow-none;
+ }
}
.active-line-text {
diff --git a/app/assets/stylesheets/page_bundles/issues_show.scss b/app/assets/stylesheets/page_bundles/issues_show.scss
index 9873a0121c0..ade649faaae 100644
--- a/app/assets/stylesheets/page_bundles/issues_show.scss
+++ b/app/assets/stylesheets/page_bundles/issues_show.scss
@@ -3,8 +3,8 @@
.description {
ul,
ol {
- /* We're changing list-style-position to inside because the default of outside
- * doesn't move the negative margin to the left of the bullet. */
+ /* We're changing list-style-position to inside because the default of
+ * outside doesn't move negative margin to the left of the bullet. */
list-style-position: inside;
}
@@ -21,6 +21,43 @@
inset-block-start: 0.3rem;
inset-inline-start: 1rem;
}
+
+ /* The inside bullet aligns itself to the bottom, which we see when text to the right of
+ * a multi-line list item wraps. We fix this by aligning it to the top, and excluding
+ * other elements adversely affected by this. Targeting ::marker doesn't seem to work. */
+ > *:not(code):not(input):not(.gl-label) {
+ vertical-align: top;
+ }
+
+ /* The inside bullet is treated like an element inside the li element, so when we have a
+ * multi-paragraph list item, the text doesn't start on the right of the bullet because
+ * it is a block level p element. We make it inline to fix this. */
+ > p:first-of-type {
+ display: inline-block;
+ max-width: calc(100% - 1.5rem);
+ }
+
+ /* We fix the other paragraphs not indenting to the
+ * right of the bullet due to the inside bullet. */
+ p ~ a,
+ p ~ blockquote,
+ p ~ code,
+ p ~ details,
+ p ~ dl,
+ p ~ h1,
+ p ~ h2,
+ p ~ h3,
+ p ~ h4,
+ p ~ h5,
+ p ~ h6,
+ p ~ hr,
+ p ~ ol,
+ p ~ p,
+ p ~ table:not(.code), /* We need :not(.code) to override typography.scss */
+ p ~ ul,
+ p ~ .markdown-code-block {
+ margin-inline-start: 1rem;
+ }
}
ul.task-list {
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 4093ef087dc..086abcf3f86 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -769,8 +769,12 @@
.add-issuable-form-input-wrapper {
&.focus {
- border-color: $blue-300;
- box-shadow: 0 0 4px $dropdown-input-focus-shadow;
+ border-color: $gray-700;
+ @include gl-focus;
+
+ input {
+ @include gl-shadow-none;
+ }
}
.gl-show-field-errors &.form-control:not(textarea) {
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index 04de77dd484..60dba73447c 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -205,7 +205,7 @@ module IssuesHelper
is_anonymous_search_disabled: Feature.enabled?(:disable_anonymous_search, type: :ops).to_s,
is_issue_repositioning_disabled: issue_repositioning_disabled?.to_s,
is_public_visibility_restricted:
- Gitlab::CurrentSettings.restricted_visibility_levels.include?(Gitlab::VisibilityLevel::PUBLIC).to_s,
+ Gitlab::CurrentSettings.restricted_visibility_levels&.include?(Gitlab::VisibilityLevel::PUBLIC).to_s,
is_signed_in: current_user.present?.to_s,
jira_integration_path: help_page_url('integration/jira/issues', anchor: 'view-jira-issues'),
rss_path: url_for(safe_params.merge(rss_url_options)),
diff --git a/app/models/member.rb b/app/models/member.rb
index a5084c8a60c..45ad47f56a4 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -170,6 +170,7 @@ class Member < ApplicationRecord
scope :owners_and_maintainers, -> { active.where(access_level: [OWNER, MAINTAINER]) }
scope :with_user, -> (user) { where(user: user) }
scope :by_access_level, -> (access_level) { active.where(access_level: access_level) }
+ scope :all_by_access_level, -> (access_level) { where(access_level: access_level) }
scope :preload_user_and_notification_settings, -> { preload(user: :notification_settings) }
diff --git a/app/models/user.rb b/app/models/user.rb
index 8aae4441852..b9a8e5855bf 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -1366,9 +1366,16 @@ class User < ApplicationRecord
end
def solo_owned_groups
- @solo_owned_groups ||= owned_groups.includes(:owners).select do |group|
- group.owners == [self]
- end
+ # For each owned group, count the owners found in self and ancestors.
+ counts = GroupMember
+ .from('unnest(namespaces.traversal_ids) AS ancestors(ancestor_id), members')
+ .where('members.source_id = ancestors.ancestor_id')
+ .all_by_access_level(GroupMember::OWNER)
+ .having('count(members.user_id) = 1')
+
+ Group
+ .from(owned_groups, :namespaces)
+ .where_exists(counts)
end
def with_defaults
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 05d480f267e..7cc5b0130cf 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -629,6 +629,9 @@ Settings.cron_jobs['projects_schedule_refresh_build_artifacts_size_statistics_wo
Settings.cron_jobs['inactive_projects_deletion_cron_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['inactive_projects_deletion_cron_worker']['cron'] ||= '0 1 * * *'
Settings.cron_jobs['inactive_projects_deletion_cron_worker']['job_class'] = 'Projects::InactiveProjectsDeletionCronWorker'
+Settings.cron_jobs['loose_foreign_keys_cleanup_worker'] ||= Settingslogic.new({})
+Settings.cron_jobs['loose_foreign_keys_cleanup_worker']['cron'] ||= '*/1 * * * *'
+Settings.cron_jobs['loose_foreign_keys_cleanup_worker']['job_class'] = 'LooseForeignKeys::CleanupWorker'
Gitlab.ee do
Settings.cron_jobs['analytics_devops_adoption_create_all_snapshots_worker'] ||= Settingslogic.new({})
@@ -760,9 +763,6 @@ Gitlab.ee do
Settings.cron_jobs['app_sec_dast_profile_schedule_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['app_sec_dast_profile_schedule_worker']['cron'] ||= '7-59/15 * * * *'
Settings.cron_jobs['app_sec_dast_profile_schedule_worker']['job_class'] = 'AppSec::Dast::ProfileScheduleWorker'
- Settings.cron_jobs['loose_foreign_keys_cleanup_worker'] ||= Settingslogic.new({})
- Settings.cron_jobs['loose_foreign_keys_cleanup_worker']['cron'] ||= '*/1 * * * *'
- Settings.cron_jobs['loose_foreign_keys_cleanup_worker']['job_class'] = 'LooseForeignKeys::CleanupWorker'
Settings.cron_jobs['ci_namespace_mirrors_consistency_check_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['ci_namespace_mirrors_consistency_check_worker']['cron'] ||= '*/4 * * * *'
Settings.cron_jobs['ci_namespace_mirrors_consistency_check_worker']['job_class'] = 'Database::CiNamespaceMirrorsConsistencyCheckWorker'
diff --git a/data/whats_new/202204210001_14_10.yml b/data/whats_new/202204210001_14_10.yml
index 162738661a2..2f3d32bd87c 100644
--- a/data/whats_new/202204210001_14_10.yml
+++ b/data/whats_new/202204210001_14_10.yml
@@ -24,7 +24,9 @@
release: 14.10
- title: "Escalating manually created incidents"
body: |
- In GitLab 13.10, we [released](https://gitlab.com/gitlab-org/gl-openshift/gitlab-runner-operator/-/issues/6) the GitLab Runner Operator for the Red Hat OpenShift container platform for Kubernetes. That release provided OpenShift users with the automation and management capabilities of the Operator Framework and simplified the ongoing management of runners in an OpenShift Kubernetes cluster. Available starting in 14.10 is a GitLab Runner Operator v1.7.0 that you can use in non-OpenShift Kubernetes clusters. This GitLab Runner Operator is available on [OperatorHub.io](https://operatorhub.io/operator/gitlab-runner-operator).
+ Incident Management is set up to trigger escalation policies for new alerts. In this scenario, the on-call responder who is paged can end the paging by acknowledging the alert. If the responder changes the status back to triggered, we restart the escalation policy and begin paging again. When a user creates an incident manually, there is no associated alert and therefore no way to page on-call responders.
+
+ This release enables paging on manually created incidents. Responders now have the ability to acknowledge the page on incidents, or restart paging by resetting the status to triggered, just as you can for alerts.
stage: monitor
self-managed: true
gitlab-com: true
diff --git a/data/whats_new/202205220001_15_0.yml b/data/whats_new/202205220001_15_0.yml
new file mode 100644
index 00000000000..8aa09d442c8
--- /dev/null
+++ b/data/whats_new/202205220001_15_0.yml
@@ -0,0 +1,114 @@
+- title: Edit code blocks, links, and media inline in the WYSIWYG editor # Match the release post entry
+ body: | # Do not modify this line, instead modify the lines below.
+ GitLab 15.0 includes a few exciting improvements to speed up your workflow in the WYSIWYG Markdown editor for your wikis.
+
+ First, you'll find no more un-styled, monochrome code blocks: choose from over 100 languages in the dropdown list above the code block so your `CSS`, `YAML`, and `Python` code are distinct from each other with accurate syntax highlighting. The code blocks will even inherit your preferred syntax highlighting theme. You can also quickly copy the code block to your clipboard for use in your code editor of choice.
+
+ You'll also find working with links and media in the WYSIWYG editor easier than ever. Previously, you had to select from the editing toolbar to change a selected link or image on your wiki page, with some edits requiring you to delete the link or image and re-create it. Editing links and images is now easier, with a new popover menu that appears when you select a link or attached image. From the menu you can quickly edit a link's destination URL or description, copy the link or image to your clipboard, or even remove the link or image from the page.
+ stage: create # String value of the stage that the feature was created in. e.g., Growth
+ self-managed: true # Boolean value (true or false)
+ gitlab-com: true # Boolean value (true or false)
+ packages: [Free, Premium, Ultimate] # Array of strings. The Array brackets are required here. e.g., [Free, Starter, Premium, Ultimate]
+ url: https://docs.gitlab.com/ee/user/project/wiki/#content-editor # This is the documentation URL, but can be a URL to a video if there is one
+ image_url: https://about.gitlab.com/images/15_0/inline-editing-in-wysiwyg.png # This should be a full URL, generally taken from the release post content. If a video, use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
+ published_at: 2022-05-22 # YYYY-MM-DD
+ release: 15.0 # XX.Y
+- title: Advanced Search is compatible with OpenSearch # Match the release post entry
+ body: | # Do not modify this line, instead modify the lines below.
+ [OpenSearch](https://opensearch.org) is an open source Elasticsearch fork. Prior to GitLab 15.0, Advanced Search was not compatible with OpenSearch. If you used AWS-managed services, you had to use older versions of Elasticsearch.
+
+ You can now take full advantage of OpenSearch for Advanced Search.
+ stage: enablement # String value of the stage that the feature was created in. e.g., Growth
+ self-managed: true # Boolean value (true or false)
+ gitlab-com: true # Boolean value (true or false)
+ packages: [Premium, Ultimate] # Array of strings. The Array brackets are required here. e.g., [Free, Starter, Premium, Ultimate]
+ url: https://docs.gitlab.com/ee/integration/elasticsearch.html # This is the documentation URL, but can be a URL to a video if there is one
+ image_url: https://about.gitlab.com/images/15_0/gitlab_advanced_search_is_now_compatible_with_opensearch.png # This should be a full URL, generally taken from the release post content. If a video, use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
+ published_at: 2022-05-22 # YYYY-MM-DD
+ release: 15.0 # XX.Y
+- title: Plan and schedule issues with automated iteration cadences # Match the release post entry
+ body: | # Do not modify this line, instead modify the lines below.
+ In GitLab 14.10 and earlier, groups supported only one set of iterations. It made it difficult for different teams that worked in a single group to have autonomy with scheduling and tracking their issues from iteration to iteration. To improve this, we're adding the ability for a group to manage multiple sets of concurrent iterations with iteration cadences. This allows each team to have control over the start day and duration of each iteration in their iteration cadence.
+
+ The day-to-day management of iterations is now much more efficient too. When you create a new iteration cadence, select the first day of your first iteration, how many weeks each iteration should be, and how many upcoming iterations GitLab should maintain for you. You can also optionally enable unfinished issues to automatically roll over from one completed iteration to the next. After a cadence is created, GitLab automatically creates the specified number of upcoming iterations.
+
+ You can now also scope an issue board or issue list to an iteration.
+ stage: plan # String value of the stage that the feature was created in. e.g., Growth
+ self-managed: true # Boolean value (true or false)
+ gitlab-com: true # Boolean value (true or false)
+ packages: [Premium, Ultimate] # Array of strings. The Array brackets are required here. e.g., [Free, Starter, Premium, Ultimate]
+ url: https://docs.gitlab.com/ee/user/group/iterations/#iteration-cadences # This is the documentation URL, but can be a URL to a video if there is one
+ image_url: https://about.gitlab.com/images/15_0/iteration-cadences.png # This should be a full URL, generally taken from the release post content. If a video, use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
+ published_at: 2022-05-22 # YYYY-MM-DD
+ release: 15.0 # XX.Y
+- title: Internal notes # Match the release post entry
+ body: | # Do not modify this line, instead modify the lines below.
+ In many cases, organizations want to keep issues and epics public, but apply stricter governance to conversations within them. For example, when using GitLab issues as part of Service Desk workflows, organizations may want to make core details about an issue public, but not to expose customer-specific confidential data broadly.
+
+ With internal notes, you can redact discussions with internal or customer data that should only be visible to certain users, while keeping the core details about an issue public. Internal notes in issues or epics can only be seen by the issue author, assignee, and group or project members with at least the Reporter role.
+
+ Thanks [@leetickett](https://gitlab.com/leetickett) for collaborating with our team on this feature!
+ stage: plan # String value of the stage that the feature was created in. e.g., Growth
+ self-managed: true # Boolean value (true or false)
+ gitlab-com: true # Boolean value (true or false)
+ packages: [Free, Premium, Ultimate] # Array of strings. The Array brackets are required here. e.g., [Free, Starter, Premium, Ultimate]
+ url: https://docs.gitlab.com/ee/user/discussions/index.html#add-an-internal-note # This is the documentation URL, but can be a URL to a video if there is one
+ image_url: https://about.gitlab.com/images/15_0/add_internal_note_v15_0.png # This should be a full URL, generally taken from the release post content. If a video, use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
+ published_at: 2022-05-22 # YYYY-MM-DD
+ release: 15.0 # XX.Y
+- title: Link external organizations and contacts to issues # Match the release post entry
+ body: | # Do not modify this line, instead modify the lines below.
+ GitLab 15.0 introduces the first [MVC](https://about.gitlab.com/handbook/product/product-principles/#the-minimal-viable-change-mvc) toward [managing and billing external customers from GitLab](https://gitlab.com/groups/gitlab-org/-/epics/5323). With the customer relations management (CRM) feature, you can:
+
+ - Create organizations and contacts.
+ - Set a default bill rate for an organization.
+ - Add contacts to organizations.
+ - Link contacts to issues with the `/add_contacts` quick action.
+ - View issues associated with a given contact or all contacts belonging to an organization.
+
+ The customer relations feature is not enabled by default, and can only be managed from a top-level group. If you want to help shape the future direction for customer relations management within GitLab, please [contribute to this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/361946).
+
+ Thanks [@leeticket](https://gitlab.com/leetickett) for the dozens of contributions and countless hours spent leading this effort!
+ stage: plan # String value of the stage that the feature was created in. e.g., Growth
+ self-managed: true # Boolean value (true or false)
+ gitlab-com: true # Boolean value (true or false)
+ packages: [Free, Premium, Ultimate] # Array of strings. The Array brackets are required here. e.g., [Free, Starter, Premium, Ultimate]
+ url: https://docs.gitlab.com/ee/user/crm/ # This is the documentation URL, but can be a URL to a video if there is one
+ image_url: https://img.youtube.com/vi/8ubOS80yNvc/hqdefault.jpg # This should be a full URL, generally taken from the release post content. If a video, use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
+ published_at: 2022-05-22 # YYYY-MM-DD
+ release: 15.0 # XX.Y
+- title: Container Scanning available in all tiers # Match the release post entry
+ body: | # Do not modify this line, instead modify the lines below.
+ [Container Scanning](https://docs.gitlab.com/ee/user/application_security/container_scanning/) helps developers to easily find known security vulnerabilities in dependencies that are installed in their container images. With GitLab 15.0, we are making the basic Container Scanning features available in every [GitLab tier](/pricing/).
+ stage: protect # String value of the stage that the feature was created in. e.g., Growth
+ self-managed: true # Boolean value (true or false)
+ gitlab-com: true # Boolean value (true or false)
+ packages: [Free, Premium, Ultimate] # Array of strings. The Array brackets are required here. e.g., [Free, Starter, Premium, Ultimate]
+ url: https://docs.gitlab.com/ee/user/application_security/container_scanning/#capabilities # This is the documentation URL, but can be a URL to a video if there is one
+ image_url: https://img.youtube.com/vi/vge_DQ6af9Y/hqdefault.jpg # This should be a full URL, generally taken from the release post content. If a video, use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
+ published_at: 2022-05-22 # YYYY-MM-DD
+ release: 15.0 # XX.Y
+- title: Limited Availability GitLab SaaS runners on macOS (x86-64) # Match the release post entry
+ body: | # Do not modify this line, instead modify the lines below.
+ GitLab SaaS runners on macOS are now in [Limited Availability](https://about.gitlab.com/handbook/product/gitlab-the-product/#limited-availability-la). If you use GitLab SaaS and have a Premium or Ultimate subscription, you can build applications that require macOS in a secure, on-demand GitLab Runner build environment that's fully integrated with GitLab CI/CD. As part of the Limited Availability release, CI jobs that run on the macOS runners will count toward your CI/CD minutes quota at a [cost factor](https://docs.gitlab.com/ee/ci/pipelines/cicd_minutes.html#cost-factor) of 6.
+ stage: verify # String value of the stage that the feature was created in. e.g., Growth
+ self-managed: false # Boolean value (true or false)
+ gitlab-com: true # Boolean value (true or false)
+ packages: [Premium, Ultimate] # Array of strings. The Array brackets are required here. e.g., [Free, Starter, Premium, Ultimate]
+ url: https://docs.gitlab.com/ee/ci/runners/saas/macos_saas_runner.html # This is the documentation URL, but can be a URL to a video if there is one
+ image_url: https://img.youtube.com/vi/G7ektKx8slg/hqdefault.jpg # This should be a full URL, generally taken from the release post content. If a video, use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
+ published_at: 2022-05-22 # YYYY-MM-DD
+ release: 15.0 # XX.Y
+- title: Use nested CI/CD variables with environments in pipeline configuration # Match the release post entry
+ body: | # Do not modify this line, instead modify the lines below.
+ Using CI/CD variables with the `environments` keyword in your CI/CD configuration is great, because it lets you [create environments dynamically](https://docs.gitlab.com/ee/ci/environments/#create-a-dynamic-environment). While this is already a powerful feature, there were still some limitations, because you could not use nested variables to define environments.
+
+ Starting in GitLab 15.0, you can nest variables inside other variables, and have them all expand the way you expect. This makes dynamic environments even more powerful due to the increased flexibility!
+ stage: verify # String value of the stage that the feature was created in. e.g., Growth
+ self-managed: true # Boolean value (true or false)
+ gitlab-com: true # Boolean value (true or false)
+ packages: [Free, Premium, Ultimate] # Array of strings. The Array brackets are required here. e.g., [Free, Starter, Premium, Ultimate]
+ url: https://docs.gitlab.com/ee/ci/yaml/#environment # This is the documentation URL, but can be a URL to a video if there is one
+ image_url: https://about.gitlab.com/images/15_0/environment.png # This should be a full URL, generally taken from the release post content. If a video, use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
+ published_at: 2022-05-22 # YYYY-MM-DD
+ release: 15.0 # XX.Y
diff --git a/doc/administration/audit_event_streaming.md b/doc/administration/audit_event_streaming.md
index 07979e21038..4678e23dfc9 100644
--- a/doc/administration/audit_event_streaming.md
+++ b/doc/administration/audit_event_streaming.md
@@ -174,6 +174,8 @@ To configure streaming audit events for Git operations, see [Add a new event str
### Headers
+> `X-Gitlab-Audit-Event-Type` [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/86881) in GitLab 15.0.
+
Headers are formatted as follows:
```plaintext
@@ -181,6 +183,7 @@ POST /logs HTTP/1.1
Host: <DESTINATION_HOST>
Content-Type: application/x-www-form-urlencoded
X-Gitlab-Event-Streaming-Token: <DESTINATION_TOKEN>
+X-Gitlab-Audit-Event-Type: repository_git_operation
```
### Example payloads for SSH events
@@ -211,7 +214,8 @@ Fetch:
"target_details": "example-project",
"created_at": "2022-02-23T06:21:05.283Z",
"target_type": "Project",
- "target_id": 29
+ "target_id": 29,
+ "event_type": "repository_git_operation"
}
```
@@ -241,7 +245,8 @@ Push:
"target_details": "example-project",
"created_at": "2022-02-23T06:23:08.746Z",
"target_type": "Project",
- "target_id": 29
+ "target_id": 29,
+ "event_type": "repository_git_operation"
}
```
@@ -273,7 +278,8 @@ Fetch:
"target_details": "example-project",
"created_at": "2022-02-23T06:25:43.938Z",
"target_type": "Project",
- "target_id": 29
+ "target_id": 29,
+ "event_type": "repository_git_operation"
}
```
@@ -303,7 +309,8 @@ Push:
"target_details": "example-project",
"created_at": "2022-02-23T06:26:29.294Z",
"target_type": "Project",
- "target_id": 29
+ "target_id": 29,
+ "event_type": "repository_git_operation"
}
```
@@ -332,7 +339,8 @@ Fetch:
"target_details": "example-group/example-project",
"created_at": "2022-02-23T06:27:17.873Z",
"target_type": "Project",
- "target_id": 29
+ "target_id": 29,
+ "event_type": "repository_git_operation"
}
```
@@ -351,6 +359,7 @@ POST /logs HTTP/1.1
Host: <DESTINATION_HOST>
Content-Type: application/x-www-form-urlencoded
X-Gitlab-Event-Streaming-Token: <DESTINATION_TOKEN>
+X-Gitlab-Audit-Event-Type: audit_operation
```
### Example payload
@@ -376,6 +385,7 @@ X-Gitlab-Event-Streaming-Token: <DESTINATION_TOKEN>
"target_details": "merge request title",
"created_at": "2022-03-09T06:53:11.181Z",
"target_type": "MergeRequest",
- "target_id": 20
+ "target_id": 20,
+ "event_type": "audit_operation"
}
```
diff --git a/doc/administration/package_information/postgresql_versions.md b/doc/administration/package_information/postgresql_versions.md
index 97f93663003..1b3e49cfb82 100644
--- a/doc/administration/package_information/postgresql_versions.md
+++ b/doc/administration/package_information/postgresql_versions.md
@@ -26,7 +26,7 @@ Read more about update policies and warnings in the PostgreSQL
| GitLab version | PostgreSQL versions | Default version for fresh installs | Default version for upgrades | Notes |
| -------------- | --------------------- | ---------------------------------- | ---------------------------- | ----- |
-| 15.0 | 12.10, 13.6 | 13.6 | 13.6 | Users can manually upgrade to 13.6 following the [upgrade docs](https://docs.gitlab.com/omnibus/settings/database.html#gitlab-150-and-later). |
+| 15.0 | 12.10, 13.6 | 13.6 | 12.10 | For upgrades, users can manually upgrade to 13.6 following the [upgrade docs](https://docs.gitlab.com/omnibus/settings/database.html#gitlab-150-and-later). |
| 14.1 | 12.7, 13.3 | 12.7 | 12.7 | PostgreSQL 13 available for fresh installations if not using [Geo](../geo/index.md#requirements-for-running-geo) or [Patroni](../postgresql/index.md#postgresql-replication-and-failover-with-omnibus-gitlab).
| 14.0 | 12.7 | 12.7 | 12.7 | HA installations with repmgr are no longer supported and will be prevented from upgrading to Omnibus GitLab 14.0 |
| 13.8 | 11.9, 12.4 | 12.4 | 12.4 | Package upgrades automatically performed PostgreSQL upgrade for nodes that are not part of a Geo or HA cluster.). |
diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md
index 87d49ffa324..87689572866 100644
--- a/doc/user/application_security/dependency_scanning/index.md
+++ b/doc/user/application_security/dependency_scanning/index.md
@@ -579,7 +579,7 @@ The following variables allow configuration of global dependency scanning settin
| ----------------------------|------------ |
| `ADDITIONAL_CA_CERT_BUNDLE` | Bundle of CA certs to trust. The bundle of certificates provided here is also used by other tools during the scanning process, such as `git`, `yarn`, or `npm`. See [Using a custom SSL CA certificate authority](#using-a-custom-ssl-ca-certificate-authority) for more details. |
| `DS_EXCLUDED_ANALYZERS` | Specify the analyzers (by name) to exclude from Dependency Scanning. For more information, see [Dependency Scanning Analyzers](analyzers.md). |
-| `DS_DEFAULT_ANALYZERS` | This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/351963) in GitLab 14.8 and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/351963) in 15.0. Use `DS_EXCLUDED_ANALYZERS` instead. |
+| `DS_DEFAULT_ANALYZERS` | This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/287691) in GitLab 14.0 and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/333299) in 15.0. Use `DS_EXCLUDED_ANALYZERS` instead. |
| `DS_EXCLUDED_PATHS` | Exclude files and directories from the scan based on the paths. A comma-separated list of patterns. Patterns can be globs, or file or folder paths (for example, `doc,spec`). Parent directories also match patterns. Default: `"spec, test, tests, tmp"`. |
| `DS_IMAGE_SUFFIX` | Suffix added to the image name. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/354796) in GitLab 14.10.) Automatically set to `"-fips"` when FIPS mode is enabled. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/357922) in GitLab 15.0.) |
| `SECURE_ANALYZERS_PREFIX` | Override the name of the Docker registry providing the official default images (proxy). Read more about [customizing analyzers](analyzers.md). |
diff --git a/lib/backup/gitaly_backup.rb b/lib/backup/gitaly_backup.rb
index a8b0e7ad157..077eabdd131 100644
--- a/lib/backup/gitaly_backup.rb
+++ b/lib/backup/gitaly_backup.rb
@@ -19,6 +19,10 @@ module Backup
def start(type, backup_repos_path, backup_id: nil)
raise Error, 'already started' if started?
+ if type == :create && !incremental?
+ FileUtils.rm_rf(backup_repos_path)
+ end
+
command = case type
when :create
'create'
@@ -34,7 +38,7 @@ module Backup
if Feature.enabled?(:incremental_repository_backup)
args += ['-layout', 'pointer']
if type == :create
- args += ['-incremental'] if @incremental
+ args += ['-incremental'] if incremental?
args += ['-id', backup_id] if backup_id
end
end
@@ -68,6 +72,10 @@ module Backup
private
+ def incremental?
+ @incremental
+ end
+
# Schedule a new backup job through a non-blocking JSON based pipe protocol
#
# @see https://gitlab.com/gitlab-org/gitaly/-/blob/master/doc/gitaly-backup.md
diff --git a/lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml
index 04b1c4a6f73..6a6fc2cb702 100644
--- a/lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml
@@ -1,5 +1,5 @@
variables:
- DAST_AUTO_DEPLOY_IMAGE_VERSION: 'v2.25.0'
+ DAST_AUTO_DEPLOY_IMAGE_VERSION: 'v2.28.2'
.dast-auto-deploy:
image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:${DAST_AUTO_DEPLOY_IMAGE_VERSION}"
diff --git a/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.gitlab-ci.yml
index 5c56594da78..b95b36fd555 100644
--- a/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.gitlab-ci.yml
@@ -156,6 +156,9 @@ gemnasium-python-dependency_scanning:
bundler-audit-dependency_scanning:
extends: .ds-analyzer
+ variables:
+ DS_ANALYZER_NAME: "bundler-audit"
+ DS_MAJOR_VERSION: 2
script:
- echo "This job was deprecated in GitLab 14.8 and removed in GitLab 15.0"
- echo "For more information see https://gitlab.com/gitlab-org/gitlab/-/issues/347491"
@@ -165,6 +168,9 @@ bundler-audit-dependency_scanning:
retire-js-dependency_scanning:
extends: .ds-analyzer
+ variables:
+ DS_ANALYZER_NAME: "retire.js"
+ DS_MAJOR_VERSION: 2
script:
- echo "This job was deprecated in GitLab 14.8 and removed in GitLab 15.0"
- echo "For more information see https://gitlab.com/gitlab-org/gitlab/-/issues/289830"
diff --git a/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
index c29b5b74bfc..98c4216679f 100644
--- a/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
@@ -1,5 +1,5 @@
variables:
- AUTO_DEPLOY_IMAGE_VERSION: 'v2.25.0'
+ AUTO_DEPLOY_IMAGE_VERSION: 'v2.28.2'
.auto-deploy:
image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:${AUTO_DEPLOY_IMAGE_VERSION}"
diff --git a/lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml
index d09bb53a5b1..603be5b1cdb 100644
--- a/lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml
@@ -1,5 +1,5 @@
variables:
- AUTO_DEPLOY_IMAGE_VERSION: 'v2.25.0'
+ AUTO_DEPLOY_IMAGE_VERSION: 'v2.28.2'
.auto-deploy:
image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:${AUTO_DEPLOY_IMAGE_VERSION}"
diff --git a/lib/gitlab/usage/service_ping_report.rb b/lib/gitlab/usage/service_ping_report.rb
index e73200cbd4a..1eda72ba570 100644
--- a/lib/gitlab/usage/service_ping_report.rb
+++ b/lib/gitlab/usage/service_ping_report.rb
@@ -24,7 +24,7 @@ module Gitlab
instrumented_payload = Gitlab::Usage::ServicePing::InstrumentedPayload.new(instrumented_metrics_key_paths, output_method).build
- old_payload.deep_merge(instrumented_payload)
+ old_payload.with_indifferent_access.deep_merge(instrumented_payload)
end
def all_metrics_values(cached)
diff --git a/scripts/review_apps/review-apps.sh b/scripts/review_apps/review-apps.sh
index 829e806e378..36bab05067a 100755
--- a/scripts/review_apps/review-apps.sh
+++ b/scripts/review_apps/review-apps.sh
@@ -248,7 +248,6 @@ function download_chart() {
helm repo add gitlab https://charts.gitlab.io
echoinfo "Building the gitlab chart's dependencies..."
- helm dependency build "gitlab-${GITLAB_HELM_CHART_REF}"
}
function base_config_changed() {
diff --git a/spec/frontend/issues/show/utils_spec.js b/spec/frontend/issues/show/utils_spec.js
index e5f14cfc01a..603fb5cc2a6 100644
--- a/spec/frontend/issues/show/utils_spec.js
+++ b/spec/frontend/issues/show/utils_spec.js
@@ -2,7 +2,7 @@ import { convertDescriptionWithNewSort } from '~/issues/show/utils';
describe('app/assets/javascripts/issues/show/utils.js', () => {
describe('convertDescriptionWithNewSort', () => {
- it('converts markdown description with new list sort order', () => {
+ it('converts markdown description with nested lists with new list sort order', () => {
const description = `I am text
- Item 1
@@ -12,17 +12,17 @@ describe('app/assets/javascripts/issues/show/utils.js', () => {
- Item 5`;
// Drag Item 2 + children to Item 1's position
- const html = `<ul data-sourcepos="3:1-8:0">
- <li data-sourcepos="4:1-4:8">
+ const html = `<ul data-sourcepos="3:1-7:8">
+ <li data-sourcepos="4:1-6:10">
Item 2
- <ul data-sourcepos="5:1-6:10">
- <li data-sourcepos="5:1-5:10">Item 3</li>
- <li data-sourcepos="6:1-6:10">Item 4</li>
+ <ul data-sourcepos="5:3-6:10">
+ <li data-sourcepos="5:3-5:10">Item 3</li>
+ <li data-sourcepos="6:3-6:10">Item 4</li>
</ul>
</li>
<li data-sourcepos="3:1-3:8">Item 1</li>
- <li data-sourcepos="7:1-8:0">Item 5</li>
- <ul>`;
+ <li data-sourcepos="7:1-7:8">Item 5</li>
+ </ul>`;
const list = document.createElement('div');
list.innerHTML = html;
@@ -36,5 +36,105 @@ describe('app/assets/javascripts/issues/show/utils.js', () => {
expect(convertDescriptionWithNewSort(description, list.firstChild)).toBe(expected);
});
+
+ it('converts markdown description with multi-line list items with new list sort order', () => {
+ const description = `Labore ea omnis et officia excepturi.
+
+1. Item 1
+
+ Item 1 part 2
+
+1. Item 2
+ - Item 2.1
+ - Item 2.1.1
+ - Item 2.1.2
+ - Item 2.2
+ - Item 2.3
+1. Item 3
+1. Item 4
+
+ \`\`\`
+ const variable = 'string';
+ \`\`\`
+
+ ![iii](img.jpg)
+
+ last paragraph
+
+1. Item 5
+1. Item 6`;
+
+ // Drag Item 2 + children to Item 5's position
+ const html = `<ol data-sourcepos="3:1-25:7">
+ <li data-sourcepos="3:1-6:0">
+ <p data-sourcepos="3:4-3:7">Item 1</p>
+ <p data-sourcepos="5:4-5:8">Item 1 part 2</p>
+ </li>
+ <li data-sourcepos="13:1-13:7">
+ <p data-sourcepos="13:4-13:7">Item 3</p>
+ </li>
+ <li data-sourcepos="14:1-23:0">
+ <p data-sourcepos="14:4-14:7">Item 4</p>
+ <div>
+ <pre data-sourcepos="16:4-18:6">
+ <code><span lang="plaintext">const variabl = 'string';</span></code>
+ </pre>
+ </div>
+ <p data-sourcepos="20:4-20:32">
+ <a href="href"><img src="img.jpg" alt="description" /></a>
+ </p>
+ <p data-sourcepos="22:4-22:17">last paragraph</p>
+ </li>
+ <li data-sourcepos="24:1-24:7">
+ <p data-sourcepos="24:4-24:7">Item 5</p>
+ </li>
+ <li data-sourcepos="7:1-12:10">
+ <p data-sourcepos="7:4-7:7">Item 2</p>
+ <ul data-sourcepos="8:4-12:10">
+ <li data-sourcepos="8:4-10:15">Item 2.1
+ <ul data-sourcepos="9:6-10:15">
+ <li data-sourcepos="9:6-9:12">Item 2.1.1</li>
+ <li data-sourcepos="10:6-10:15">Item 2.1.2</li>
+ </ul>
+ </li>
+ <li data-sourcepos="11:4-11:10">Item 2.2</li>
+ <li data-sourcepos="12:4-12:10">Item 2.3</li>
+ </ul>
+ </li>
+ <li data-sourcepos="25:1-25:7">
+ <p data-sourcepos="25:4-25:7">Item 6</p>
+ </li>
+ </ol>`;
+ const list = document.createElement('div');
+ list.innerHTML = html;
+
+ const expected = `Labore ea omnis et officia excepturi.
+
+1. Item 1
+
+ Item 1 part 2
+
+1. Item 3
+1. Item 4
+
+ \`\`\`
+ const variable = 'string';
+ \`\`\`
+
+ ![iii](img.jpg)
+
+ last paragraph
+
+1. Item 5
+1. Item 2
+ - Item 2.1
+ - Item 2.1.1
+ - Item 2.1.2
+ - Item 2.2
+ - Item 2.3
+1. Item 6`;
+
+ expect(convertDescriptionWithNewSort(description, list.firstChild)).toBe(expected);
+ });
});
});
diff --git a/spec/frontend/notes/components/comment_form_spec.js b/spec/frontend/notes/components/comment_form_spec.js
index fb42e4d1d84..ba5d4d27e55 100644
--- a/spec/frontend/notes/components/comment_form_spec.js
+++ b/spec/frontend/notes/components/comment_form_spec.js
@@ -582,6 +582,26 @@ describe('issue_comment_form component', () => {
expect(checkbox.element.checked).toBe(false);
});
+ it.each`
+ noteableType | rendered | message
+ ${'Issue'} | ${true} | ${'render'}
+ ${'Epic'} | ${true} | ${'render'}
+ ${'MergeRequest'} | ${false} | ${'not render'}
+ `(
+ 'should $message checkbox when noteableType is $noteableType',
+ ({ noteableType, rendered }) => {
+ mountComponent({
+ mountFunction: mount,
+ noteableType,
+ initialData: { note: 'internal note' },
+ noteableData: { ...notableDataMockCanUpdateIssuable, noteableType },
+ features,
+ });
+
+ expect(findConfidentialNoteCheckbox().exists()).toBe(rendered);
+ },
+ );
+
describe.each`
shouldCheckboxBeChecked
${true}
diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb
index 0421c7b7458..58f06899cd6 100644
--- a/spec/helpers/issues_helper_spec.rb
+++ b/spec/helpers/issues_helper_spec.rb
@@ -302,7 +302,7 @@ RSpec.describe IssuesHelper do
is_anonymous_search_disabled: 'true',
is_issue_repositioning_disabled: 'true',
is_project: 'true',
- is_public_visibility_restricted: 'false',
+ is_public_visibility_restricted: Gitlab::CurrentSettings.restricted_visibility_levels ? 'false' : '',
is_signed_in: current_user.present?.to_s,
jira_integration_path: help_page_url('integration/jira/issues', anchor: 'view-jira-issues'),
markdown_help_path: help_page_path('user/markdown'),
@@ -337,6 +337,16 @@ RSpec.describe IssuesHelper do
let(:current_user) { nil }
end
end
+
+ context 'when restricted visibility levels is nil' do
+ before do
+ allow(Gitlab::CurrentSettings).to receive(:restricted_visibility_levels).and_return(nil)
+ end
+
+ it_behaves_like 'issues list data' do
+ let(:current_user) { double.as_null_object }
+ end
+ end
end
describe '#group_issues_list_data' do
diff --git a/spec/lib/backup/gitaly_backup_spec.rb b/spec/lib/backup/gitaly_backup_spec.rb
index 399e4ffa72b..ab198fcbe1f 100644
--- a/spec/lib/backup/gitaly_backup_spec.rb
+++ b/spec/lib/backup/gitaly_backup_spec.rb
@@ -59,6 +59,16 @@ RSpec.describe Backup::GitalyBackup do
expect(File).to exist(File.join(destination, project_snippet.disk_path, backup_id, '001.bundle'))
end
+ it 'erases any existing repository backups' do
+ existing_file = File.join(destination, 'some_existing_file')
+ IO.write(existing_file, "Some existing file.\n")
+
+ subject.start(:create, destination, backup_id: backup_id)
+ subject.finish!
+
+ expect(File).not_to exist(existing_file)
+ end
+
context 'parallel option set' do
let(:max_parallelism) { 3 }
diff --git a/spec/lib/gitlab/usage/service_ping_report_spec.rb b/spec/lib/gitlab/usage/service_ping_report_spec.rb
index e7096988035..e007554df4a 100644
--- a/spec/lib/gitlab/usage/service_ping_report_spec.rb
+++ b/spec/lib/gitlab/usage/service_ping_report_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Gitlab::Usage::ServicePingReport, :use_clean_rails_memory_store_caching do
include UsageDataHelpers
- let(:usage_data) { { uuid: "1111", counts: { issue: 0 } } }
+ let(:usage_data) { { uuid: "1111", counts: { issue: 0 } }.deep_stringify_keys }
before do
allow_next_instance_of(Gitlab::Usage::ServicePing::PayloadKeysProcessor) do |instance|
@@ -20,7 +20,7 @@ RSpec.describe Gitlab::Usage::ServicePingReport, :use_clean_rails_memory_store_c
context 'all_metrics_values' do
it 'generates the service ping when there are no missing values' do
expect(Gitlab::UsageData).to receive(:data).and_return(usage_data)
- expect(described_class.for(output: :all_metrics_values)).to eq({ uuid: "1111", counts: { issue: 0 } })
+ expect(described_class.for(output: :all_metrics_values)).to eq({ uuid: "1111", counts: { issue: 0 } }.deep_stringify_keys)
end
it 'generates the service ping with the missing values' do
@@ -33,7 +33,24 @@ RSpec.describe Gitlab::Usage::ServicePingReport, :use_clean_rails_memory_store_c
end
expect(Gitlab::UsageData).to receive(:data).and_return(usage_data)
- expect(described_class.for(output: :all_metrics_values)).to eq({ uuid: "1111", counts: { issue: 0, boards: 1 } })
+ expect(described_class.for(output: :all_metrics_values)).to eq({ uuid: "1111", counts: { issue: 0, boards: 1 } }.deep_stringify_keys)
+ end
+
+ context 'with usage data payload with symbol keys and instrumented payload with string keys' do
+ let(:usage_data) { { uuid: "1111", counts: { issue: 0 } } }
+
+ it 'correctly merges string and symbol keys' do
+ expect_next_instance_of(Gitlab::Usage::ServicePing::PayloadKeysProcessor, usage_data) do |instance|
+ expect(instance).to receive(:missing_instrumented_metrics_key_paths).and_return(['counts.boards'])
+ end
+
+ expect_next_instance_of(Gitlab::Usage::ServicePing::InstrumentedPayload, ['counts.boards'], :with_value) do |instance|
+ expect(instance).to receive(:build).and_return({ 'counts' => { 'boards' => 1 } })
+ end
+
+ expect(Gitlab::UsageData).to receive(:data).and_return(usage_data)
+ expect(described_class.for(output: :all_metrics_values)).to eq({ uuid: "1111", counts: { issue: 0, boards: 1 } }.deep_stringify_keys)
+ end
end
end
@@ -54,9 +71,9 @@ RSpec.describe Gitlab::Usage::ServicePingReport, :use_clean_rails_memory_store_c
end
context 'when using cached' do
- context 'for cached: true' do
- let(:new_usage_data) { { uuid: "1112" } }
+ let(:new_usage_data) { { 'uuid' => '1112' } }
+ context 'for cached: true' do
it 'caches the values' do
allow(Gitlab::UsageData).to receive(:data).and_return(usage_data, new_usage_data)
@@ -78,8 +95,6 @@ RSpec.describe Gitlab::Usage::ServicePingReport, :use_clean_rails_memory_store_c
end
context 'when no caching' do
- let(:new_usage_data) { { uuid: "1112" } }
-
it 'returns fresh data' do
allow(Gitlab::UsageData).to receive(:data).and_return(usage_data, new_usage_data)
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 71171f98492..f087fab1ef3 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -3740,7 +3740,7 @@ RSpec.describe User do
end
context 'has owned groups' do
- let_it_be(:group) { create(:group) }
+ let(:group) { create(:group) }
before do
group.add_owner(user)
@@ -3749,11 +3749,23 @@ RSpec.describe User do
context 'not solo owner' do
let_it_be(:user2) { create(:user) }
- before do
- group.add_owner(user2)
+ context 'with another direct owner' do
+ before do
+ group.add_owner(user2)
+ end
+
+ it { is_expected.to be_empty }
end
- it { is_expected.to be_empty }
+ context 'with an inherited owner' do
+ let_it_be(:group) { create(:group, :nested) }
+
+ before do
+ group.parent.add_owner(user2)
+ end
+
+ it { is_expected.to be_empty }
+ end
end
context 'solo owner' do
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index 040ac4f74a7..2c5a734a0e1 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -2098,7 +2098,7 @@ RSpec.describe API::Users do
describe "DELETE /users/:id" do
let_it_be(:issue) { create(:issue, author: user) }
- it "deletes user", :sidekiq_might_not_need_inline do
+ it "deletes user", :sidekiq_inline do
namespace_id = user.namespace.id
perform_enqueued_jobs { delete api("/users/#{user.id}", admin) }
@@ -2119,11 +2119,27 @@ RSpec.describe API::Users do
end
context "hard delete enabled" do
- it "delete user and group", :sidekiq_might_not_need_inline do
+ it "delete user and group", :sidekiq_inline do
perform_enqueued_jobs { delete api("/users/#{user.id}?hard_delete=true", admin) }
expect(response).to have_gitlab_http_status(:no_content)
expect(Group.exists?(group.id)).to be_falsy
end
+
+ context "with subgroup owning" do
+ let(:parent_group) { create(:group) }
+ let(:subgroup) { create(:group, parent: parent_group) }
+
+ before do
+ parent_group.add_owner(create(:user))
+ subgroup.add_owner(user)
+ end
+
+ it "delete only user", :sidekiq_inline do
+ perform_enqueued_jobs { delete api("/users/#{user.id}?hard_delete=true", admin) }
+ expect(response).to have_gitlab_http_status(:no_content)
+ expect(Group.exists?(subgroup.id)).to be_truthy
+ end
+ end
end
end
diff --git a/spec/services/users/destroy_service_spec.rb b/spec/services/users/destroy_service_spec.rb
index 45dbe83b496..90c4f70d749 100644
--- a/spec/services/users/destroy_service_spec.rb
+++ b/spec/services/users/destroy_service_spec.rb
@@ -215,6 +215,27 @@ RSpec.describe Users::DestroyService do
end
end
+ context 'deletions with inherited group owners' do
+ let(:group) { create(:group, :nested) }
+ let(:user) { create(:user) }
+ let(:inherited_owner) { create(:user) }
+
+ before do
+ group.parent.add_owner(inherited_owner)
+ group.add_owner(user)
+
+ service.execute(user, delete_solo_owned_groups: true)
+ end
+
+ it 'does not delete the group' do
+ expect(Group.exists?(id: group)).to be_truthy
+ end
+
+ it 'deletes the user' do
+ expect(User.exists?(id: user)).to be_falsey
+ end
+ end
+
context 'migrating associated records' do
let!(:issue) { create(:issue, author: user) }