summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-05-11 00:13:54 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2023-05-11 00:13:54 +0000
commit2d9c62ffb595d2bf555046d09098a0d4af71e17f (patch)
treec837cf91cf3e50f443d1dcb852b82448637a5c8b
parentd9710d79c52bc73438022e79c79cfe3ab35b084b (diff)
downloadgitlab-ce-2d9c62ffb595d2bf555046d09098a0d4af71e17f.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab/ci/package-and-test/main.gitlab-ci.yml2
-rw-r--r--.gitlab/ci/qa-common/main.gitlab-ci.yml4
-rw-r--r--.gitlab/ci/test-on-gdk/main.gitlab-ci.yml2
-rw-r--r--app/assets/javascripts/content_editor/components/bubble_menus/code_block_bubble_menu.vue2
-rw-r--r--app/assets/javascripts/content_editor/components/toolbar_button.vue2
-rw-r--r--app/assets/javascripts/editor/schema/ci.json36
-rw-r--r--app/assets/javascripts/environments/environment_details/deployments_table.vue8
-rw-r--r--app/assets/javascripts/pages/projects/shared/web_ide_link/index.js9
-rw-r--r--app/assets/javascripts/super_sidebar/components/nav_item.vue7
-rw-r--r--app/assets/javascripts/vue_shared/components/web_ide_link.vue127
-rw-r--r--app/finders/members_finder.rb15
-rw-r--r--app/helpers/avatars_helper.rb2
-rw-r--r--app/helpers/nav_helper.rb10
-rw-r--r--app/models/users/callout.rb5
-rw-r--r--app/services/auth/container_registry_authentication_service.rb36
-rw-r--r--config/feature_flags/development/introduce_rules_with_needs.yml8
-rw-r--r--config/feature_flags/development/super_sidebar_nav_enrolled.yml (renamed from config/feature_flags/experiment/pql_three_cta_test.yml)12
-rw-r--r--data/deprecations/14-8-iteration-started-field.yml14
-rw-r--r--data/deprecations/15-1-pipelinesecurityreportfinding-projectfingerprint.yml4
-rw-r--r--data/removals/16_0/16-0-postgresql-12.yml17
-rw-r--r--doc/administration/gitaly/reference.md2
-rw-r--r--doc/administration/server_hooks.md4
-rw-r--r--doc/api/graphql/reference/index.md48
-rw-r--r--doc/api/group_iterations.md2
-rw-r--r--doc/api/iterations.md2
-rw-r--r--doc/ci/yaml/index.md49
-rw-r--r--doc/development/integrations/secure.md2
-rw-r--r--doc/topics/autodevops/cicd_variables.md52
-rw-r--r--doc/update/deprecations.md62
-rw-r--r--doc/update/removals.md14
-rw-r--r--doc/user/application_security/api_fuzzing/index.md13
-rw-r--r--doc/user/application_security/dast_api/index.md28
-rw-r--r--doc/user/application_security/index.md4
-rw-r--r--doc/user/application_security/policies/scan-execution-policies.md2
-rw-r--r--doc/user/application_security/policies/scan-result-policies.md16
-rw-r--r--doc/user/compliance/compliance_report/index.md33
-rw-r--r--doc/user/group/manage.md4
-rw-r--r--lib/api/helpers/members_helpers.rb3
-rw-r--r--lib/gitlab/ci/build/rules.rb11
-rw-r--r--lib/gitlab/ci/config/entry/rules/rule.rb10
-rw-r--r--lib/gitlab/ci/yaml_processor.rb12
-rw-r--r--lib/gitlab/database/partitioning/list/convert_table.rb6
-rw-r--r--locale/gitlab.pot15
-rw-r--r--qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/import/import_github_repo_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/revert/reverting_merge_request_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/container_registry/online_garbage_collection_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/infrastructure_registry/terraform_module_registry_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_project_level_spec.rb2
-rw-r--r--spec/finders/members_finder_spec.rb31
-rw-r--r--spec/frontend/content_editor/components/toolbar_button_spec.js2
-rw-r--r--spec/frontend/editor/schema/ci/ci_schema_spec.js4
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/negative_tests/rules_needs.yml46
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/positive_tests/rules_needs.yml32
-rw-r--r--spec/frontend/environments/environment_details/deployments_table_spec.js58
-rw-r--r--spec/frontend/fixtures/environments.rb2
-rw-r--r--spec/frontend/vue_shared/components/web_ide_link_spec.js150
-rw-r--r--spec/helpers/avatars_helper_spec.rb17
-rw-r--r--spec/helpers/nav_helper_spec.rb15
-rw-r--r--spec/lib/gitlab/ci/build/rules_spec.rb144
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/build_spec.rb98
-rw-r--r--spec/lib/gitlab/ci/yaml_processor_spec.rb185
-rw-r--r--spec/lib/gitlab/database/partitioning/list/convert_table_spec.rb20
-rw-r--r--spec/requests/api/members_spec.rb16
-rw-r--r--spec/services/ci/create_pipeline_service/rules_spec.rb103
-rw-r--r--spec/spec_helper.rb4
-rw-r--r--spec/support/shared_examples/services/container_registry_auth_service_shared_examples.rb55
69 files changed, 1279 insertions, 435 deletions
diff --git a/.gitlab/ci/package-and-test/main.gitlab-ci.yml b/.gitlab/ci/package-and-test/main.gitlab-ci.yml
index 774939c7e44..e90c0bbc7c4 100644
--- a/.gitlab/ci/package-and-test/main.gitlab-ci.yml
+++ b/.gitlab/ci/package-and-test/main.gitlab-ci.yml
@@ -523,5 +523,3 @@ notify-slack:
extends:
- .notify-slack
- .rules:report:process-results
- variables:
- TYPE: "(package-and-test) "
diff --git a/.gitlab/ci/qa-common/main.gitlab-ci.yml b/.gitlab/ci/qa-common/main.gitlab-ci.yml
index cc0220b12c0..3c83d7ace22 100644
--- a/.gitlab/ci/qa-common/main.gitlab-ci.yml
+++ b/.gitlab/ci/qa-common/main.gitlab-ci.yml
@@ -252,7 +252,7 @@ stages:
- .ruby-image
stage: notify
variables:
- QA_RSPEC_JSON_FILE_PATTERN: $CI_PROJECT_DIR/gitlab-qa-run-*/**/rspec-*.json
+ QA_RSPEC_XML_FILE_PATTERN: $CI_PROJECT_DIR/gitlab-qa-run-*/**/rspec-*.xml
SLACK_ICON_EMOJI: ci_failing
STATUS_SYM: ☠️
STATUS: failed
@@ -264,7 +264,7 @@ stages:
echo "Test suite passed. Exiting..."
exit 0
fi
- - bundle exec gitlab-qa-report --prepare-stage-reports "$QA_RSPEC_JSON_FILE_PATTERN" # generate summary
+ - bundle exec gitlab-qa-report --prepare-stage-reports "$QA_RSPEC_XML_FILE_PATTERN" # generate summary
- !reference [.notify-slack-qa, script]
# ==========================================
diff --git a/.gitlab/ci/test-on-gdk/main.gitlab-ci.yml b/.gitlab/ci/test-on-gdk/main.gitlab-ci.yml
index ac23ea75eb1..5cf38d578e5 100644
--- a/.gitlab/ci/test-on-gdk/main.gitlab-ci.yml
+++ b/.gitlab/ci/test-on-gdk/main.gitlab-ci.yml
@@ -119,4 +119,4 @@ notify-slack:
- .notify-slack
- .rules:report:process-results
variables:
- QA_RSPEC_JSON_FILE_PATTERN: $CI_PROJECT_DIR/test_output/rspec-*.json
+ QA_RSPEC_XML_FILE_PATTERN: $CI_PROJECT_DIR/test_output/rspec-*.xml
diff --git a/app/assets/javascripts/content_editor/components/bubble_menus/code_block_bubble_menu.vue b/app/assets/javascripts/content_editor/components/bubble_menus/code_block_bubble_menu.vue
index 98b7203778f..caac61fe9a6 100644
--- a/app/assets/javascripts/content_editor/components/bubble_menus/code_block_bubble_menu.vue
+++ b/app/assets/javascripts/content_editor/components/bubble_menus/code_block_bubble_menu.vue
@@ -250,7 +250,7 @@ export default {
variant="default"
category="tertiary"
size="medium"
- :class="{ active: showPreview }"
+ :class="{ 'gl-bg-gray-100!': showPreview }"
data-testid="preview-diagram"
:aria-label="__('Preview diagram')"
:title="__('Preview diagram')"
diff --git a/app/assets/javascripts/content_editor/components/toolbar_button.vue b/app/assets/javascripts/content_editor/components/toolbar_button.vue
index 1f3c7062b67..a62f66d8557 100644
--- a/app/assets/javascripts/content_editor/components/toolbar_button.vue
+++ b/app/assets/javascripts/content_editor/components/toolbar_button.vue
@@ -78,7 +78,7 @@ export default {
:variant="variant"
:category="category"
:size="size"
- :class="{ active: isActive }"
+ :class="{ 'gl-bg-gray-100!': isActive }"
:aria-label="label"
:title="label"
:icon="iconName"
diff --git a/app/assets/javascripts/editor/schema/ci.json b/app/assets/javascripts/editor/schema/ci.json
index 70f1dddcac9..1fb6f606b6b 100644
--- a/app/assets/javascripts/editor/schema/ci.json
+++ b/app/assets/javascripts/editor/schema/ci.json
@@ -774,6 +774,9 @@
},
"allow_failure": {
"$ref": "#/definitions/allow_failure"
+ },
+ "needs": {
+ "$ref": "#/definitions/rulesNeeds"
}
}
},
@@ -936,6 +939,39 @@
"markdownDescription": "Used in conjunction with 'when: delayed' to set how long to delay before starting a job. e.g. '5', 5 seconds, 30 minutes, 1 week, etc. [Learn More](https://docs.gitlab.com/ee/ci/jobs/job_control.html#run-a-job-after-a-delay).",
"minLength": 1
},
+ "rulesNeeds": {
+ "markdownDescription": "Use needs in rules to update job needs for specific conditions. When a condition matches a rule, the job's needs configuration is completely replaced with the needs in the rule. [Learn More](https://docs.gitlab.com/ee/ci/yaml/index.html#rulesneeds).",
+ "type": "array",
+ "items": {
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "job": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Name of a job that is defined in the pipeline."
+ },
+ "artifacts": {
+ "type": "boolean",
+ "description": "Download artifacts of the job in needs."
+ },
+ "optional": {
+ "type": "boolean",
+ "description": "Whether the job needs to be present in the pipeline to run ahead of the current job."
+ }
+ },
+ "required": [
+ "job"
+ ]
+ }
+ ]
+ }
+ },
"allow_failure": {
"markdownDescription": "Allow job to fail. A failed job does not cause the pipeline to fail. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#allow_failure).",
"oneOf": [
diff --git a/app/assets/javascripts/environments/environment_details/deployments_table.vue b/app/assets/javascripts/environments/environment_details/deployments_table.vue
index 128b1aae4d8..f37f93798ae 100644
--- a/app/assets/javascripts/environments/environment_details/deployments_table.vue
+++ b/app/assets/javascripts/environments/environment_details/deployments_table.vue
@@ -48,10 +48,14 @@ export default {
<deployment-job :job="item.job" />
</template>
<template #cell(created)="{ item }">
- <time-ago-tooltip :time="item.created" />
+ <time-ago-tooltip :time="item.created" data-testid="deployment-created-at" />
</template>
<template #cell(deployed)="{ item }">
- <time-ago-tooltip :time="item.deployed" />
+ <time-ago-tooltip
+ v-if="item.deployed"
+ :time="item.deployed"
+ data-testid="deployment-deployed-at"
+ />
</template>
<template #cell(actions)="{ item }">
<deployment-actions
diff --git a/app/assets/javascripts/pages/projects/shared/web_ide_link/index.js b/app/assets/javascripts/pages/projects/shared/web_ide_link/index.js
index 84ff802c268..43ff617dabe 100644
--- a/app/assets/javascripts/pages/projects/shared/web_ide_link/index.js
+++ b/app/assets/javascripts/pages/projects/shared/web_ide_link/index.js
@@ -1,15 +1,7 @@
import Vue from 'vue';
-import VueApollo from 'vue-apollo';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { joinPaths, webIDEUrl } from '~/lib/utils/url_utility';
import WebIdeButton from '~/vue_shared/components/web_ide_link.vue';
-import createDefaultClient from '~/lib/graphql';
-
-Vue.use(VueApollo);
-
-const apolloProvider = new VueApollo({
- defaultClient: createDefaultClient(),
-});
export default ({ el, router }) => {
if (!el) return;
@@ -23,7 +15,6 @@ export default ({ el, router }) => {
new Vue({
el,
router,
- apolloProvider,
render(h) {
return h(WebIdeButton, {
props: {
diff --git a/app/assets/javascripts/super_sidebar/components/nav_item.vue b/app/assets/javascripts/super_sidebar/components/nav_item.vue
index 11499784103..ec1c4069b1a 100644
--- a/app/assets/javascripts/super_sidebar/components/nav_item.vue
+++ b/app/assets/javascripts/super_sidebar/components/nav_item.vue
@@ -1,5 +1,5 @@
<script>
-import { GlButton, GlIcon, GlBadge } from '@gitlab/ui';
+import { GlButton, GlIcon, GlBadge, GlTooltipDirective } from '@gitlab/ui';
import { s__ } from '~/locale';
import {
CLICK_MENU_ITEM_ACTION,
@@ -23,6 +23,9 @@ export default {
NavItemLink,
NavItemRouterLink,
},
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
inject: {
pinnedItemIds: { default: { ids: [] } },
panelSupportsPins: { default: false },
@@ -153,6 +156,7 @@ export default {
</gl-badge>
<gl-button
v-if="isPinnable && !isPinned"
+ v-gl-tooltip.right.viewport="$options.i18n.pinItem"
size="small"
category="tertiary"
icon="thumbtack"
@@ -161,6 +165,7 @@ export default {
/>
<gl-button
v-else-if="isPinnable && isPinned"
+ v-gl-tooltip.right.viewport="$options.i18n.unpinItem"
size="small"
category="tertiary"
:aria-label="$options.i18n.unpinItem"
diff --git a/app/assets/javascripts/vue_shared/components/web_ide_link.vue b/app/assets/javascripts/vue_shared/components/web_ide_link.vue
index 28bec63b244..3c08142e2b9 100644
--- a/app/assets/javascripts/vue_shared/components/web_ide_link.vue
+++ b/app/assets/javascripts/vue_shared/components/web_ide_link.vue
@@ -1,8 +1,7 @@
<script>
-import { GlModal, GlSprintf, GlLink, GlPopover } from '@gitlab/ui';
+import { GlModal, GlSprintf, GlLink } from '@gitlab/ui';
import { s__, __ } from '~/locale';
import { visitUrl } from '~/lib/utils/url_utility';
-import UserCalloutDismisser from '~/vue_shared/components/user_callout_dismisser.vue';
import ActionsButton from '~/vue_shared/components/actions_button.vue';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
import ConfirmForkModal from '~/vue_shared/components/confirm_fork_modal.vue';
@@ -34,9 +33,7 @@ export default {
GlModal,
GlSprintf,
GlLink,
- GlPopover,
ConfirmForkModal,
- UserCalloutDismisser,
},
i18n,
mixins: [glFeatureFlagsMixin()],
@@ -312,9 +309,6 @@ export default {
},
};
},
- displayVscodeWebIdeCallout() {
- return this.glFeatures.vscodeWebIde && !this.showEditButton;
- },
},
mounted() {
this.resetPreferredEditor();
@@ -340,11 +334,6 @@ export default {
this.select(KEY_WEB_IDE);
},
- dismissCalloutOnActionClicked(dismiss) {
- if (this.displayVscodeWebIdeCallout) {
- dismiss();
- }
- },
},
webIdeButtonId: 'web-ide-link',
PREFERRED_EDITOR_KEY,
@@ -352,84 +341,38 @@ export default {
</script>
<template>
- <user-callout-dismisser
- :skip-query="!displayVscodeWebIdeCallout"
- feature-name="vscode_web_ide_callout"
- >
- <template #default="{ dismiss, shouldShowCallout }">
- <div class="gl-sm-ml-3">
- <actions-button
- :id="$options.webIdeButtonId"
- :actions="actions"
- :selected-key="selection"
- :variant="isBlob ? 'confirm' : 'default'"
- :category="isBlob ? 'primary' : 'secondary'"
- :show-action-tooltip="!displayVscodeWebIdeCallout || !shouldShowCallout"
- @select="select"
- @actionClicked="dismissCalloutOnActionClicked(dismiss)"
- />
- <local-storage-sync
- :storage-key="$options.PREFERRED_EDITOR_KEY"
- :value="selection"
- as-string
- @input="select"
- />
- <gl-modal
- v-if="computedShowGitpodButton && !gitpodEnabled"
- v-model="showEnableGitpodModal"
- v-bind="enableGitpodModalProps"
- >
- <gl-sprintf :message="$options.i18n.modal.content">
- <template #link="{ content }">
- <gl-link :href="userPreferencesGitpodPath">{{ content }}</gl-link>
- </template>
- </gl-sprintf>
- </gl-modal>
- <confirm-fork-modal
- v-if="showWebIdeButton || showEditButton"
- v-model="showForkModal"
- :modal-id="forkModalId"
- :fork-path="forkPath"
- />
- <gl-popover
- v-if="displayVscodeWebIdeCallout"
- :target="$options.webIdeButtonId"
- :show="shouldShowCallout"
- :css-classes="['web-ide-promo-popover']"
- :boundary-padding="80"
- show-close-button
- triggers="manual"
- @close-button-clicked="dismiss"
- >
- <img
- :src="webIdePromoPopoverImg"
- class="web-ide-promo-popover-illustration"
- width="280"
- height="140"
- />
- <div class="gl-mx-2">
- <h5 class="gl-mt-3 gl-mb-3">{{ __('The new Web IDE') }}</h5>
- <p>
- {{
- __(
- 'VS Code in your browser. View code and make changes from the same UI as in your local IDE.',
- )
- }}
- </p>
- <gl-link
- class="gl-button btn btn-confirm block gl-mb-4 gl-mt-5"
- variant="confirm"
- category="primary"
- target="_blank"
- :href="webIdeUrl"
- block
- @click="dismissCalloutOnActionClicked(dismiss)"
- >
- {{ __('Try it out now') }}
- </gl-link>
- </div>
- </gl-popover>
- </div>
- </template>
- </user-callout-dismisser>
+ <div class="gl-sm-ml-3">
+ <actions-button
+ :id="$options.webIdeButtonId"
+ :actions="actions"
+ :selected-key="selection"
+ :variant="isBlob ? 'confirm' : 'default'"
+ :category="isBlob ? 'primary' : 'secondary'"
+ show-action-tooltip
+ @select="select"
+ />
+ <local-storage-sync
+ :storage-key="$options.PREFERRED_EDITOR_KEY"
+ :value="selection"
+ as-string
+ @input="select"
+ />
+ <gl-modal
+ v-if="computedShowGitpodButton && !gitpodEnabled"
+ v-model="showEnableGitpodModal"
+ v-bind="enableGitpodModalProps"
+ >
+ <gl-sprintf :message="$options.i18n.modal.content">
+ <template #link="{ content }">
+ <gl-link :href="userPreferencesGitpodPath">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </gl-modal>
+ <confirm-fork-modal
+ v-if="showWebIdeButton || showEditButton"
+ v-model="showForkModal"
+ :modal-id="forkModalId"
+ :fork-path="forkPath"
+ />
+ </div>
</template>
diff --git a/app/finders/members_finder.rb b/app/finders/members_finder.rb
index d2122eccab1..3c0714441b2 100644
--- a/app/finders/members_finder.rb
+++ b/app/finders/members_finder.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class MembersFinder
- RELATIONS = %i[direct inherited descendants invited_groups].freeze
+ RELATIONS = %i[direct inherited descendants invited_groups shared_into_ancestors].freeze
DEFAULT_RELATIONS = %i[direct inherited].freeze
# Params can be any of the following:
@@ -58,15 +58,20 @@ class MembersFinder
def group_union_members(include_relations)
[].tap do |members|
- members << direct_group_members(include_relations.include?(:descendants)) if group
+ members << direct_group_members(include_relations) if group
members << project_invited_groups if include_relations.include?(:invited_groups)
end
end
- def direct_group_members(include_descendants)
+ def direct_group_members(include_relations)
requested_relations = [:inherited, :direct]
- requested_relations << :descendants if include_descendants
- GroupMembersFinder.new(group).execute(include_relations: requested_relations).non_invite.non_minimal_access # rubocop: disable CodeReuse/Finder
+ requested_relations << :descendants if include_relations.include?(:descendants)
+ requested_relations << :shared_from_groups if include_relations.include?(:shared_into_ancestors)
+
+ GroupMembersFinder.new(group, current_user) # rubocop: disable CodeReuse/Finder
+ .execute(include_relations: requested_relations)
+ .non_invite
+ .non_minimal_access
end
def project_invited_groups
diff --git a/app/helpers/avatars_helper.rb b/app/helpers/avatars_helper.rb
index 57075a44d0f..17f995ec0ad 100644
--- a/app/helpers/avatars_helper.rb
+++ b/app/helpers/avatars_helper.rb
@@ -28,7 +28,7 @@ module AvatarsHelper
end
def avatar_icon_for_email(email = nil, size = nil, scale = 2, only_path: true)
- return gravatar_icon(email, size, scale) if email.nil?
+ return default_avatar if email.blank?
Gitlab::AvatarCache.by_email(email, size, scale, only_path) do
avatar_icon_by_user_email_or_gravatar(email, size, scale, only_path: only_path)
diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb
index 6d6138057cf..4f30b555ba0 100644
--- a/app/helpers/nav_helper.rb
+++ b/app/helpers/nav_helper.rb
@@ -87,12 +87,20 @@ module NavHelper
end
def show_super_sidebar?(user = current_user)
+ return false unless Feature.enabled?(:super_sidebar_nav, user)
+
# The new sidebar is not enabled for anonymous use
# Once we enable the new sidebar by default, this
# should return true
return false unless user
- Feature.enabled?(:super_sidebar_nav, user) && user.use_new_navigation
+ # Users who got the special `super_sidebar_nav_enrolled` enabled,
+ # see the new nav as long as they don't explicitly opt-out via the toggle
+ if user.use_new_navigation.nil? && Feature.enabled?(:super_sidebar_nav_enrolled, user)
+ true
+ else
+ !!user.use_new_navigation
+ end
end
private
diff --git a/app/models/users/callout.rb b/app/models/users/callout.rb
index 0d6862fe3b6..896cccfa0e5 100644
--- a/app/models/users/callout.rb
+++ b/app/models/users/callout.rb
@@ -59,12 +59,11 @@ module Users
namespace_storage_limit_banner_warning_threshold: 56, # EE-only
namespace_storage_limit_banner_alert_threshold: 57, # EE-only
namespace_storage_limit_banner_error_threshold: 58, # EE-only
- project_quality_summary_feedback: 59, # EE-only
+ project_quality_summary_feedback: 59, # EE-only
merge_request_settings_moved_callout: 60,
new_top_level_group_alert: 61,
artifacts_management_page_feedback_banner: 62,
- vscode_web_ide: 63,
- vscode_web_ide_callout: 64,
+ # 63 and 64 were removed with https://gitlab.com/gitlab-org/gitlab/-/merge_requests/120233
branch_rules_info_callout: 65,
create_runner_workflow_banner: 66
}
diff --git a/app/services/auth/container_registry_authentication_service.rb b/app/services/auth/container_registry_authentication_service.rb
index 509c2d4d544..3827d199325 100644
--- a/app/services/auth/container_registry_authentication_service.rb
+++ b/app/services/auth/container_registry_authentication_service.rb
@@ -65,7 +65,12 @@ module Auth
token.expire_time = token_expire_at
token[:access] = names.map do |name|
- { type: type, name: name, actions: actions }
+ {
+ type: type,
+ name: name,
+ actions: actions,
+ meta: access_metadata(path: name)
+ }.compact
end
token.encoded
@@ -75,6 +80,28 @@ module Auth
Time.current + Gitlab::CurrentSettings.container_registry_token_expire_delay.minutes
end
+ def self.access_metadata(project: nil, path: nil)
+ # If the project is not given, try to infer it from the provided path
+ if project.nil?
+ return if path.nil? # If no path is given, return early
+ return if path == 'import' # Ignore the special 'import' path
+
+ # If the path ends with '/*', remove it so we can parse the actual repository path
+ path = path.chomp('/*')
+
+ # Parse the repository project from the path
+ begin
+ project = ContainerRegistry::Path.new(path).repository_project
+ rescue ContainerRegistry::Path::InvalidRegistryPathError
+ # If the path is invalid, gracefully handle the error
+ return
+ end
+ end
+
+ # Return the project path (lowercase) as metadata
+ { project_path: project&.full_path&.downcase }
+ end
+
private
def authorized_token(*accesses)
@@ -138,7 +165,12 @@ module Auth
#
ensure_container_repository!(path, authorized_actions)
- { type: type, name: path.to_s, actions: authorized_actions }
+ {
+ type: type,
+ name: path.to_s,
+ actions: authorized_actions,
+ meta: self.class.access_metadata(project: requested_project)
+ }
end
def actively_importing?(actions, path)
diff --git a/config/feature_flags/development/introduce_rules_with_needs.yml b/config/feature_flags/development/introduce_rules_with_needs.yml
new file mode 100644
index 00000000000..8b2940438ee
--- /dev/null
+++ b/config/feature_flags/development/introduce_rules_with_needs.yml
@@ -0,0 +1,8 @@
+---
+name: introduce_rules_with_needs
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112725
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/394769
+milestone: '16.0'
+type: development
+group: group::pipeline authoring
+default_enabled: false
diff --git a/config/feature_flags/experiment/pql_three_cta_test.yml b/config/feature_flags/development/super_sidebar_nav_enrolled.yml
index aa46c51d7ed..2ece807f6fe 100644
--- a/config/feature_flags/experiment/pql_three_cta_test.yml
+++ b/config/feature_flags/development/super_sidebar_nav_enrolled.yml
@@ -1,8 +1,8 @@
---
-name: pql_three_cta_test
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/74054
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/349799
-milestone: '14.7'
-type: experiment
-group: group::acquisition
+name: super_sidebar_nav_enrolled
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/119506
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/410121
+milestone: '16.0'
+type: development
+group: group::foundations
default_enabled: false
diff --git a/data/deprecations/14-8-iteration-started-field.yml b/data/deprecations/14-8-iteration-started-field.yml
index a3c693001c1..a591aa04db4 100644
--- a/data/deprecations/14-8-iteration-started-field.yml
+++ b/data/deprecations/14-8-iteration-started-field.yml
@@ -1,9 +1,17 @@
-- title: "`started` iterations API field" # The name of the feature to be deprecated
+- title: "`started` iteration state" # The name of the feature to be deprecated
announcement_milestone: "14.8" # The milestone when this feature was first announced as deprecated.
- removal_milestone: "15.0" # The milestone when this feature is planned to be removed
+ announcement_date: "2022-02-22" # The date of the milestone release when this feature was first announced as deprecated. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post.
+ removal_milestone: "16.0" # The milestone when this feature is planned to be removed
+ removal_date: "2022-05-22" # The date of the milestone release when this feature was first announced as deprecated. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post.
breaking_change: true # If this deprecation is a breaking change, set this value to true
body: | # Do not modify this line, instead modify the lines below.
- The `started` field in the [iterations API](https://docs.gitlab.com/ee/api/iterations.html#list-project-iterations) is being deprecated and will be removed in GitLab 15.0. This field is being replaced with the `current` field (already available) which aligns with the naming for other time-based entities, such as milestones.
+ The `started` iteration state in the [iterations GraphQL API](https://https://docs.gitlab.com/ee/api/graphql/reference/index.html#iterationstate)
+ and [iterations REST API](https://docs.gitlab.com/ee/api/iterations.html#list-project-iterations) is deprecated.
+
+ The GraphQL API version will be removed in GitLab 16.0. This state is being replaced with the `current` state (already available)
+ which aligns with the naming for other time-based entities, such as milestones.
+
+ We plan to continue to support the `started` state in REST API version until the next v5 REST API version.
# The following items are not published on the docs page, but may be used in the future.
stage: plan
tiers: # (optional - may be required in the future) An array of tiers that the feature is available in currently. e.g., [Free, Silver, Gold, Core, Premium, Ultimate]
diff --git a/data/deprecations/15-1-pipelinesecurityreportfinding-projectfingerprint.yml b/data/deprecations/15-1-pipelinesecurityreportfinding-projectfingerprint.yml
index 7e444ed1436..576b8a195c5 100644
--- a/data/deprecations/15-1-pipelinesecurityreportfinding-projectfingerprint.yml
+++ b/data/deprecations/15-1-pipelinesecurityreportfinding-projectfingerprint.yml
@@ -1,12 +1,12 @@
- title: "PipelineSecurityReportFinding projectFingerprint GraphQL field" # (required) The name of the feature to be deprecated
announcement_milestone: "15.1" # (required) The milestone when this feature was first announced as deprecated.
- removal_milestone: "16.0" # (required) The milestone when this feature is planned to be removed
+ removal_milestone: "17.0" # (required) The milestone when this feature is planned to be removed
breaking_change: true # (required) If this deprecation is a breaking change, set this value to true
reporter: matt_wilson # (required) GitLab username of the person reporting the deprecation
stage: Secure # (required) String value of the stage that the feature was created in. e.g., Growth
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/343475 # (required) Link to the deprecation issue in GitLab
body: | # (required) Do not modify this line, instead modify the lines below.
- The [`project_fingerprint`](https://gitlab.com/groups/gitlab-org/-/epics/2791) attribute of vulnerability findings is being deprecated in favor of a `uuid` attribute. By using UUIDv5 values to identify findings, we can easily associate any related entity with a finding. The `project_fingerprint` attribute is no longer being used to track findings, and will be removed in GitLab 16.0.
+ The [`project_fingerprint`](https://gitlab.com/groups/gitlab-org/-/epics/2791) attribute of vulnerability findings is being deprecated in favor of a `uuid` attribute. By using UUIDv5 values to identify findings, we can easily associate any related entity with a finding. The `project_fingerprint` attribute is no longer being used to track findings, and will be removed in GitLab 17.0.
# The following items are not published on the docs page, but may be used in the future.
tiers: Ultimate # (optional - may be required in the future) An array of tiers that the feature is available in currently. e.g., [Free, Silver, Gold, Core, Premium, Ultimate]
documentation_url: # (optional) This is a link to the current documentation page
diff --git a/data/removals/16_0/16-0-postgresql-12.yml b/data/removals/16_0/16-0-postgresql-12.yml
new file mode 100644
index 00000000000..9aa8102154b
--- /dev/null
+++ b/data/removals/16_0/16-0-postgresql-12.yml
@@ -0,0 +1,17 @@
+- title: "PostgreSQL 12 compatibility"
+ announcement_milestone: "15.0"
+ removal_milestone: "16.0"
+ breaking_change: true
+ reporter: twk3
+ stage: Enablement
+ issue_url: https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/7395
+ body: |
+ In GitLab 16.0, PostgreSQL 13 is the minimum supported PostgreSQL version. PostgreSQL 12 is no longer shipped with the GitLab Omnibus package.
+ Before upgrading to GitLab 16.0, if you are:
+
+ - Still using GitLab-packaged PostgreSQL 12, you must [perform a database upgrade](https://docs.gitlab.com/omnibus/settings/database.html#upgrade-packaged-postgresql-server)
+ to PostgreSQL 13.
+ - Using an externally-provided PostgreSQL 12, you must upgrade to PostgreSQL 13 or later to meet the
+ [minimum version requirements](https://docs.gitlab.com/ee/install/requirements.html#postgresql-requirements).
+ tiers: # (optional - may be required in the future) An array of tiers that the feature is available in currently. e.g., [Free, Silver, Gold, Core, Premium, Ultimate]
+ documentation_url: https://docs.gitlab.com/ee/administration/package_information/postgresql_versions.html
diff --git a/doc/administration/gitaly/reference.md b/doc/administration/gitaly/reference.md
index cc938c95548..81b3faf859e 100644
--- a/doc/administration/gitaly/reference.md
+++ b/doc/administration/gitaly/reference.md
@@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
Gitaly is configured via a [TOML](https://github.com/toml-lang/toml)
configuration file. Unlike installations from source, in Omnibus GitLab, you
-would not edit this file directly.
+would not edit this file directly. For Omnibus GitLab installations, the default file location is `/var/opt/gitlab/gitaly/config.toml`.
The configuration file is passed as an argument to the `gitaly` executable, which is usually done by either Omnibus
GitLab or your [init](https://en.wikipedia.org/wiki/Init) script.
diff --git a/doc/administration/server_hooks.md b/doc/administration/server_hooks.md
index 5e9863447a1..b167412075b 100644
--- a/doc/administration/server_hooks.md
+++ b/doc/administration/server_hooks.md
@@ -37,7 +37,9 @@ alternatives to server hooks include:
Prerequisites:
-- The [storage name and relative path](repository_storage_types.md#from-project-name-to-hashed-path) for the repository.
+- The [storage name](gitaly/configure_gitaly.md#gitlab-requires-a-default-repository-storage), path to the Gitaly configuration file
+ (default is `/var/opt/gitlab/gitaly/config.toml` on Omnibus GitLab instances), and the
+ [repository relative path](repository_storage_types.md#from-project-name-to-hashed-path) for the repository.
To set server hooks for a repository:
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 27dee816dff..9b72c7378b8 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -7072,6 +7072,29 @@ The edge type for [`AgentConfiguration`](#agentconfiguration).
| <a id="agentconfigurationedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="agentconfigurationedgenode"></a>`node` | [`AgentConfiguration`](#agentconfiguration) | The item at the end of the edge. |
+#### `AiMessageTypeConnection`
+
+The connection type for [`AiMessageType`](#aimessagetype).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="aimessagetypeconnectionedges"></a>`edges` | [`[AiMessageTypeEdge]`](#aimessagetypeedge) | A list of edges. |
+| <a id="aimessagetypeconnectionnodes"></a>`nodes` | [`[AiMessageType]`](#aimessagetype) | A list of nodes. |
+| <a id="aimessagetypeconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
+
+#### `AiMessageTypeEdge`
+
+The edge type for [`AiMessageType`](#aimessagetype).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="aimessagetypeedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
+| <a id="aimessagetypeedgenode"></a>`node` | [`AiMessageType`](#aimessagetype) | The item at the end of the edge. |
+
#### `AlertManagementAlertConnection`
The connection type for [`AlertManagementAlert`](#alertmanagementalert).
@@ -11445,6 +11468,18 @@ Information about a connected Agent.
| <a id="agentmetadatapodnamespace"></a>`podNamespace` | [`String`](#string) | Namespace of the pod running the Agent. |
| <a id="agentmetadataversion"></a>`version` | [`String`](#string) | Agent version tag. |
+### `AiMessageType`
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="aimessagetypecontent"></a>`content` | [`String`](#string) | Content of the message or null if loading. |
+| <a id="aimessagetypeerrors"></a>`errors` | [`[String!]!`](#string) | Errors that occurred while asynchronously fetching an AI(assistant) response. |
+| <a id="aimessagetypeid"></a>`id` | [`ID`](#id) | Global ID of the message. |
+| <a id="aimessagetypeisfetching"></a>`isFetching` | [`Boolean`](#boolean) | Whether the content is still being fetched, for a message with the assistant role. |
+| <a id="aimessagetyperole"></a>`role` | [`String!`](#string) | Role of the message (system, user, assistant). |
+
### `AiResponse`
#### Fields
@@ -18924,6 +18959,7 @@ Represents a product analytics dashboard visualization.
| ---- | ---- | ----------- |
| <a id="projectactualrepositorysizelimit"></a>`actualRepositorySizeLimit` | [`Float`](#float) | Size limit for the repository in bytes. |
| <a id="projectagentconfigurations"></a>`agentConfigurations` | [`AgentConfigurationConnection`](#agentconfigurationconnection) | Agent configurations defined by the project. (see [Connections](#connections)) |
+| <a id="projectaiconversations"></a>`aiConversations` **{warning-solid}** | [`ProjectConversations`](#projectconversations) | **Introduced** in 16.0. This feature is an Experiment. It can be changed or removed at any time. Ai Chat conversations related to a given project. |
| <a id="projectallowmergeonskippedpipeline"></a>`allowMergeOnSkippedPipeline` | [`Boolean`](#boolean) | If `only_allow_merge_if_pipeline_succeeds` is true, indicates if merge requests of the project can also be merged with skipped jobs. |
| <a id="projectapifuzzingciconfiguration"></a>`apiFuzzingCiConfiguration` | [`ApiFuzzingCiConfiguration`](#apifuzzingciconfiguration) | API fuzzing configuration for the project. |
| <a id="projectarchived"></a>`archived` | [`Boolean`](#boolean) | Indicates the archived status of the project. |
@@ -20375,6 +20411,14 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="projectcicdsettingoptinjwt"></a>`optInJwt` | [`Boolean`](#boolean) | When disabled, the JSON Web Token is always available in all jobs in the pipeline. |
| <a id="projectcicdsettingproject"></a>`project` | [`Project`](#project) | Project the CI/CD settings belong to. |
+### `ProjectConversations`
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="projectconversationsciconfigmessages"></a>`ciConfigMessages` **{warning-solid}** | [`AiMessageTypeConnection`](#aimessagetypeconnection) | **Introduced** in 16.0. This feature is an Experiment. It can be changed or removed at any time. Messages generated by open ai and the user. |
+
### `ProjectDataTransfer`
#### Fields
@@ -24513,7 +24557,6 @@ State of a GitLab iteration.
| <a id="iterationstateclosed"></a>`closed` | Closed iteration. |
| <a id="iterationstatecurrent"></a>`current` | Current iteration. |
| <a id="iterationstateopened"></a>`opened` | Open iteration. |
-| <a id="iterationstatestarted"></a>`started` **{warning-solid}** | **Deprecated** in 14.1. Use current instead. |
| <a id="iterationstateupcoming"></a>`upcoming` | Upcoming iteration. |
### `IterationWildcardId`
@@ -25035,6 +25078,7 @@ Project member relation.
| <a id="projectmemberrelationdirect"></a>`DIRECT` | Direct members. |
| <a id="projectmemberrelationinherited"></a>`INHERITED` | Inherited members. |
| <a id="projectmemberrelationinvited_groups"></a>`INVITED_GROUPS` | Invited Groups members. |
+| <a id="projectmemberrelationshared_into_ancestors"></a>`SHARED_INTO_ANCESTORS` | Shared Into Ancestors members. |
### `RegistryState`
@@ -25457,8 +25501,6 @@ Name of the feature that the callout is for.
| <a id="usercalloutfeaturenameenumunfinished_tag_cleanup_callout"></a>`UNFINISHED_TAG_CLEANUP_CALLOUT` | Callout feature name for unfinished_tag_cleanup_callout. |
| <a id="usercalloutfeaturenameenumuser_reached_limit_free_plan_alert"></a>`USER_REACHED_LIMIT_FREE_PLAN_ALERT` | Callout feature name for user_reached_limit_free_plan_alert. |
| <a id="usercalloutfeaturenameenumverification_reminder"></a>`VERIFICATION_REMINDER` | Callout feature name for verification_reminder. |
-| <a id="usercalloutfeaturenameenumvscode_web_ide"></a>`VSCODE_WEB_IDE` | Callout feature name for vscode_web_ide. |
-| <a id="usercalloutfeaturenameenumvscode_web_ide_callout"></a>`VSCODE_WEB_IDE_CALLOUT` | Callout feature name for vscode_web_ide_callout. |
| <a id="usercalloutfeaturenameenumweb_ide_alert_dismissed"></a>`WEB_IDE_ALERT_DISMISSED` | Callout feature name for web_ide_alert_dismissed. |
| <a id="usercalloutfeaturenameenumweb_ide_ci_environments_guidance"></a>`WEB_IDE_CI_ENVIRONMENTS_GUIDANCE` | Callout feature name for web_ide_ci_environments_guidance. |
diff --git a/doc/api/group_iterations.md b/doc/api/group_iterations.md
index b2439861c2f..cae271e6365 100644
--- a/doc/api/group_iterations.md
+++ b/doc/api/group_iterations.md
@@ -28,7 +28,7 @@ GET /groups/:id/iterations?updated_after=2013-10-02T09%3A24%3A18Z
| Attribute | Type | Required | Description |
| ------------------- | ------- | -------- | ----------- |
-| `state` | string | no | 'Return `opened`, `upcoming`, `current (previously started)`, `closed`, or `all` iterations. Filtering by `started` state is deprecated starting with 14.1, use `current` instead.' |
+| `state` | string | no | 'Return `opened`, `upcoming`, `current`, `closed`, or `all` iterations.' |
| `search` | string | no | Return only iterations with a title matching the provided string. |
| `include_ancestors` | boolean | no | Include iterations from parent group and its ancestors. Defaults to `true`. |
| `updated_before` | datetime | no | Return only iterations updated before the given datetime. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/378662) in GitLab 15.10. |
diff --git a/doc/api/iterations.md b/doc/api/iterations.md
index ca280437eaf..567a2def09f 100644
--- a/doc/api/iterations.md
+++ b/doc/api/iterations.md
@@ -30,7 +30,7 @@ GET /projects/:id/iterations?updated_after=2013-10-02T09%3A24%3A18Z
| Attribute | Type | Required | Description |
| ------------------- | ------- | -------- | ----------- |
-| `state` | string | no | 'Return `opened`, `upcoming`, `current (previously started)`, `closed`, or `all` iterations. Filtering by `started` state is deprecated starting with 14.1, please use `current` instead.' |
+| `state` | string | no | 'Return `opened`, `upcoming`, `current`, `closed`, or `all` iterations.' |
| `search` | string | no | Return only iterations with a title matching the provided string. |
| `include_ancestors` | boolean | no | Include iterations from parent group and its ancestors. Defaults to `true`. |
| `updated_before` | datetime | no | Return only iterations updated before the given datetime. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/378662) in GitLab 15.10. |
diff --git a/doc/ci/yaml/index.md b/doc/ci/yaml/index.md
index 8eb7e5a13df..49dbd08c90b 100644
--- a/doc/ci/yaml/index.md
+++ b/doc/ci/yaml/index.md
@@ -3666,6 +3666,55 @@ If the rule matches, then the job is a manual job with `allow_failure: true`.
- The rule-level `rules:allow_failure` overrides the job-level [`allow_failure`](#allow_failure),
and only applies when the specific rule triggers the job.
+#### `rules:needs`
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/31581) in GitLab 16.0 [with a flag](../../user/feature_flags.md) named `introduce_rules_with_needs`. Disabled by default.
+
+Use `needs` in rules to update a job's [`needs`](#needs) for specific conditions. When a condition matches a rule, the job's `needs` configuration is completely replaced with the `needs` in the rule.
+
+**Keyword type**: Job-specific. You can use it only as part of a job.
+
+**Possible inputs**:
+
+- An array of job names as strings.
+- A hash with a job name, optionally with additional attributes.
+- An empty array (`[]`), to set the job needs to none when the specific condition is met.
+
+**Example of `rules:needs`**:
+
+```yaml
+build-dev:
+ stage: build
+ rules:
+ - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
+ script: echo "Feature branch, so building dev version..."
+
+build-prod:
+ stage: build
+ rules:
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
+ script: echo "Default branch, so building prod version..."
+
+specs:
+ stage: test
+ needs: ['build-dev']
+ rules:
+ - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
+ needs: ['build-prod']
+ - when: on_success # Run the job in other cases
+ script: echo "Running dev specs by default, or prod specs when default branch..."
+```
+
+In this example:
+
+- If the pipeline runs on a branch that is not the default branch, the `specs` job needs the `build-dev` job (default behavior).
+- If the pipeline runs on the default branch, and therefore the rule matches the condition, the `specs` job needs the `build-prod` job instead.
+
+**Additional details**:
+
+- `needs` in rules override any `needs` defined at the job-level. When overridden, the behavior is same as [job-level `needs`](#needs).
+- `needs` in rules can accept [`artifacts`](#needsartifacts) and [`optional`](#needsoptional).
+
#### `rules:variables`
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/209864) in GitLab 13.7.
diff --git a/doc/development/integrations/secure.md b/doc/development/integrations/secure.md
index 55cc9ddb006..ee94e57a247 100644
--- a/doc/development/integrations/secure.md
+++ b/doc/development/integrations/secure.md
@@ -124,7 +124,7 @@ the project repository contains Java source code and the `dependency_scanning` f
```yaml
mysec_dependency_scanning:
rules:
- - if: $DEPENDENCY_SCANNING_DISABLED
+ - if: $DEPENDENCY_SCANNING_DISABLED == 'true'
when: never
- if: $GITLAB_FEATURES =~ /\bdependency_scanning\b/
exists:
diff --git a/doc/topics/autodevops/cicd_variables.md b/doc/topics/autodevops/cicd_variables.md
index f4c74fe3245..529f449e452 100644
--- a/doc/topics/autodevops/cicd_variables.md
+++ b/doc/topics/autodevops/cicd_variables.md
@@ -86,45 +86,39 @@ Use these variables to disable CI/CD jobs.
| **Job name** | **CI/CD variable** | **GitLab version** | **Description** |
|----------------------------------------|---------------------------------|-----------------------|-----------------|
-| `.fuzz_base` | `COVFUZZ_DISABLED` | [From GitLab 13.2](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/34984) | [Read more](../../user/application_security/coverage_fuzzing/index.md) about how `.fuzz_base` provide capability for your own jobs. If the variable is present, your jobs aren't created. |
-| `apifuzzer_fuzz` | `API_FUZZING_DISABLED` | [From GitLab 13.3](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39135) | If the variable is present, the job isn't created. |
+| `.fuzz_base` | `COVFUZZ_DISABLED` | [From GitLab 13.2](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/34984) | [Read more](../../user/application_security/coverage_fuzzing/index.md) about how `.fuzz_base` provide capability for your own jobs. The job isn't created if the value is `"true"`. |
+| `apifuzzer_fuzz` | `API_FUZZING_DISABLED` | [From GitLab 13.3](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39135) | The job isn't created if the value is `"true"`. |
| `build` | `BUILD_DISABLED` | | If the variable is present, the job isn't created. |
| `build_artifact` | `BUILD_DISABLED` | | If the variable is present, the job isn't created. |
-| `bandit-sast` | `SAST_DISABLED` | | If the variable is present, the job isn't created. |
-| `brakeman-sast` | `SAST_DISABLED` | | If the variable is present, the job isn't created. |
+| `brakeman-sast` | `SAST_DISABLED` | | The job isn't created if the value is `"true"`. |
| `canary` | `CANARY_ENABLED` | | This manual job is created if the variable is present. |
| `code_intelligence` | `CODE_INTELLIGENCE_DISABLED` | From GitLab 13.6 | If the variable is present, the job isn't created. |
-| `code_quality` | `CODE_QUALITY_DISABLED` | | If the variable is present, the job isn't created. |
-| `container_scanning` | `CONTAINER_SCANNING_DISABLED` | | If the variable is present, the job isn't created. |
-| `dast` | `DAST_DISABLED` | | If the variable is present, the job isn't created. |
-| `dast_environment_deploy` | `DAST_DISABLED_FOR_DEFAULT_BRANCH` or `DAST_DISABLED` | [From GitLab 12.4](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/17789) | If either variable is present, the job isn't created. |
-| `dependency_scanning` | `DEPENDENCY_SCANNING_DISABLED` | | If the variable is present, the job isn't created. |
-| `eslint-sast` | `SAST_DISABLED` | | If the variable is present, the job isn't created. |
-| `flawfinder-sast` | `SAST_DISABLED` | | If the variable is present, the job isn't created. |
-| `gemnasium-dependency_scanning` | `DEPENDENCY_SCANNING_DISABLED` | | If the variable is present, the job isn't created. |
-| `gemnasium-maven-dependency_scanning` | `DEPENDENCY_SCANNING_DISABLED` | | If the variable is present, the job isn't created. |
-| `gemnasium-python-dependency_scanning` | `DEPENDENCY_SCANNING_DISABLED` | | If the variable is present, the job isn't created. |
-| `gosec-sast` | `SAST_DISABLED` | | If the variable is present, the job isn't created. |
-| `kubesec-sast` | `SAST_DISABLED` | | If the variable is present, the job isn't created. |
+| `code_quality` | `CODE_QUALITY_DISABLED` | | The job isn't created if the value is `"true"`. |
+| `container_scanning` | `CONTAINER_SCANNING_DISABLED` | | The job isn't created if the value is `"true"`. |
+| `dast` | `DAST_DISABLED` | | The job isn't created if the value is `"true"`. |
+| `dast_environment_deploy` | `DAST_DISABLED_FOR_DEFAULT_BRANCH` or `DAST_DISABLED` | [From GitLab 12.4](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/17789) | The job isn't created if the value is `"true"`. |
+| `dependency_scanning` | `DEPENDENCY_SCANNING_DISABLED` | | The job isn't created if the value is `"true"`. |
+| `flawfinder-sast` | `SAST_DISABLED` | | The job isn't created if the value is `"true"`. |
+| `gemnasium-dependency_scanning` | `DEPENDENCY_SCANNING_DISABLED` | | The job isn't created if the value is `"true"`. |
+| `gemnasium-maven-dependency_scanning` | `DEPENDENCY_SCANNING_DISABLED` | | The job isn't created if the value is `"true"`. |
+| `gemnasium-python-dependency_scanning` | `DEPENDENCY_SCANNING_DISABLED` | | The job isn't created if the value is `"true"`. |
+| `kubesec-sast` | `SAST_DISABLED` | | The job isn't created if the value is `"true"`. |
| `license_management` | `LICENSE_MANAGEMENT_DISABLED` | GitLab 12.7 and earlier | If the variable is present, the job isn't created. Job deprecated [from GitLab 12.8](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/22773) |
-| `license_scanning` | `LICENSE_MANAGEMENT_DISABLED` | [From GitLab 12.8](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/22773) | If the variable is present, the job isn't created. |
+| `license_scanning` | `LICENSE_MANAGEMENT_DISABLED` | [From GitLab 12.8](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/22773) | The job isn't created if the value is `"true"`.|
| `load_performance` | `LOAD_PERFORMANCE_DISABLED` | From GitLab 13.2 | If the variable is present, the job isn't created. |
-| `nodejs-scan-sast` | `SAST_DISABLED` | | If the variable is present, the job isn't created. |
+| `nodejs-scan-sast` | `SAST_DISABLED` | | The job isn't created if the value is `"true"`. |
| `performance` | `PERFORMANCE_DISABLED` | GitLab 13.12 and earlier | Browser performance. If the variable is present, the job isn't created. Replaced by `browser_performance`. |
| `browser_performance` | `BROWSER_PERFORMANCE_DISABLED` | From GitLab 14.0 | Browser performance. If the variable is present, the job isn't created. Replaces `performance`. |
-| `phpcs-security-audit-sast` | `SAST_DISABLED` | | If the variable is present, the job isn't created. |
-| `pmd-apex-sast` | `SAST_DISABLED` | | If the variable is present, the job isn't created. |
+| `phpcs-security-audit-sast` | `SAST_DISABLED` | | The job isn't created if the value is `"true"`. |
+| `pmd-apex-sast` | `SAST_DISABLED` | | The job isn't created if the value is `"true"`. |
| `review` | `REVIEW_DISABLED` | | If the variable is present, the job isn't created. |
| `review:stop` | `REVIEW_DISABLED` | | Manual job. If the variable is present, the job isn't created. |
-| `sast` | `SAST_DISABLED` | | If the variable is present, the job isn't created. |
-| `sast:container` | `CONTAINER_SCANNING_DISABLED` | | If the variable is present, the job isn't created. |
-| `secret_detection` | `SECRET_DETECTION_DISABLED` | From GitLab 13.1 | If the variable is present, the job isn't created. |
-| `secret_detection_default_branch` | `SECRET_DETECTION_DISABLED` | [From GitLab 13.2](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/22773) | If the variable is present, the job isn't created. |
-| `security-code-scan-sast` | `SAST_DISABLED` | | If the variable is present, the job isn't created. |
-| `secrets-sast` | `SAST_DISABLED` | | If the variable is present, the job isn't created. |
-| `sobelaw-sast` | `SAST_DISABLED` | | If the variable is present, the job isn't created. |
-| `stop_dast_environment` | `DAST_DISABLED_FOR_DEFAULT_BRANCH` or `DAST_DISABLED` | [From GitLab 12.4](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/17789) | If either variable is present, the job isn't created. |
-| `spotbugs-sast` | `SAST_DISABLED` | | If the variable is present, the job isn't created. |
+| `secret_detection` | `SECRET_DETECTION_DISABLED` | From GitLab 13.1 | The job isn't created if the value is `"true"`. |
+| `secret_detection_default_branch` | `SECRET_DETECTION_DISABLED` | [From GitLab 13.2](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/22773) | The job isn't created if the value is `"true"`. |
+| `semgrep-sast` | `SAST_DISABLED` | | The job isn't created if the value is `"true"`. |
+| `sobelow-sast` | `SAST_DISABLED` | | The job isn't created if the value is `"true"`. |
+| `stop_dast_environment` | `DAST_DISABLED_FOR_DEFAULT_BRANCH` or `DAST_DISABLED` | [From GitLab 12.4](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/17789) | The job isn't created if the value is `"true"`. |
+| `spotbugs-sast` | `SAST_DISABLED` | | The job isn't created if the value is `"true"`. |
| `test` | `TEST_DISABLED` | | If the variable is present, the job isn't created. |
| `staging` | `STAGING_ENABLED` | | The job is created if the variable is present. |
| `stop_review` | `REVIEW_DISABLED` | | If the variable is present, the job isn't created. |
diff --git a/doc/update/deprecations.md b/doc/update/deprecations.md
index f48df6e2c86..cc9b7f786c0 100644
--- a/doc/update/deprecations.md
+++ b/doc/update/deprecations.md
@@ -315,6 +315,20 @@ Due to low customer usage, Load Performance Testing is deprecated and will be re
<div class="deprecation breaking-change" data-milestone="17.0">
+### PipelineSecurityReportFinding projectFingerprint GraphQL field
+
+<div class="deprecation-notes">
+- Announced in: GitLab <span class="milestone">15.1</span>
+- This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
+- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/343475).
+</div>
+
+The [`project_fingerprint`](https://gitlab.com/groups/gitlab-org/-/epics/2791) attribute of vulnerability findings is being deprecated in favor of a `uuid` attribute. By using UUIDv5 values to identify findings, we can easily associate any related entity with a finding. The `project_fingerprint` attribute is no longer being used to track findings, and will be removed in GitLab 17.0.
+
+</div>
+
+<div class="deprecation breaking-change" data-milestone="17.0">
+
### Queue selector for running Sidekiq is deprecated
<div class="deprecation-notes">
@@ -1646,20 +1660,6 @@ Previously, the [PipelineSecurityReportFinding GraphQL type was updated](https:/
<div class="deprecation breaking-change" data-milestone="16.0">
-### PipelineSecurityReportFinding projectFingerprint GraphQL field
-
-<div class="deprecation-notes">
-- Announced in: GitLab <span class="milestone">15.1</span>
-- This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
-- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/343475).
-</div>
-
-The [`project_fingerprint`](https://gitlab.com/groups/gitlab-org/-/epics/2791) attribute of vulnerability findings is being deprecated in favor of a `uuid` attribute. By using UUIDv5 values to identify findings, we can easily associate any related entity with a finding. The `project_fingerprint` attribute is no longer being used to track findings, and will be removed in GitLab 16.0.
-
-</div>
-
-<div class="deprecation breaking-change" data-milestone="16.0">
-
### PostgreSQL 12 deprecated
<div class="deprecation-notes">
@@ -2209,6 +2209,26 @@ To avoid confusion and duplication, the `environment_tier` parameter is deprecat
<div class="deprecation breaking-change" data-milestone="16.0">
+### `started` iteration state
+
+<div class="deprecation-notes">
+- Announced in: GitLab <span class="milestone">14.8</span>
+- This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
+- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/334018).
+</div>
+
+The `started` iteration state in the [iterations GraphQL API](https://https://docs.gitlab.com/ee/api/graphql/reference/index.html#iterationstate)
+and [iterations REST API](https://docs.gitlab.com/ee/api/iterations.html#list-project-iterations) is deprecated.
+
+The GraphQL API version will be removed in GitLab 16.0. This state is being replaced with the `current` state (already available)
+which aligns with the naming for other time-based entities, such as milestones.
+
+We plan to continue to support the `started` state in REST API version until the next v5 REST API version.
+
+</div>
+
+<div class="deprecation breaking-change" data-milestone="16.0">
+
### vulnerabilityFindingDismiss GraphQL mutation
<div class="deprecation-notes">
@@ -3727,20 +3747,6 @@ In GitLab 14.5, we introduced the command `gitlab-ctl promote` to promote any Ge
<div class="deprecation breaking-change" data-milestone="15.0">
-### `started` iterations API field
-
-<div class="deprecation-notes">
-- Announced in: GitLab <span class="milestone">14.8</span>
-- This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
-- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/334018).
-</div>
-
-The `started` field in the [iterations API](https://docs.gitlab.com/ee/api/iterations.html#list-project-iterations) is being deprecated and will be removed in GitLab 15.0. This field is being replaced with the `current` field (already available) which aligns with the naming for other time-based entities, such as milestones.
-
-</div>
-
-<div class="deprecation breaking-change" data-milestone="15.0">
-
### `type` and `types` keyword in CI/CD configuration
<div class="deprecation-notes">
diff --git a/doc/update/removals.md b/doc/update/removals.md
index 00dff9856cc..14e7f32105a 100644
--- a/doc/update/removals.md
+++ b/doc/update/removals.md
@@ -121,6 +121,20 @@ Review the details carefully before upgrading.
Previously, the [PipelineSecurityReportFinding GraphQL type was updated](https://gitlab.com/gitlab-org/gitlab/-/issues/335372) to include a new `title` field. This field is an alias for the current `name` field, making the less specific `name` field redundant. The `name` field is removed from the PipelineSecurityReportFinding type in GitLab 16.0.
+### PostgreSQL 12 compatibility
+
+WARNING:
+This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
+Review the details carefully before upgrading.
+
+In GitLab 16.0, PostgreSQL 13 is the minimum supported PostgreSQL version. PostgreSQL 12 is no longer shipped with the GitLab Omnibus package.
+Before upgrading to GitLab 16.0, if you are:
+
+- Still using GitLab-packaged PostgreSQL 12, you must [perform a database upgrade](https://docs.gitlab.com/omnibus/settings/database.html#upgrade-packaged-postgresql-server)
+ to PostgreSQL 13.
+- Using an externally-provided PostgreSQL 12, you must upgrade to PostgreSQL 13 or later to meet the
+ [minimum version requirements](https://docs.gitlab.com/ee/install/requirements.html#postgresql-requirements).
+
### Project REST API field `operations_access_level` removed
WARNING:
diff --git a/doc/user/application_security/api_fuzzing/index.md b/doc/user/application_security/api_fuzzing/index.md
index 30d29098bda..c0ba764e706 100644
--- a/doc/user/application_security/api_fuzzing/index.md
+++ b/doc/user/application_security/api_fuzzing/index.md
@@ -2351,9 +2351,12 @@ apifuzzer_v1:
FUZZAPI_EXCLUDE_PATHS: /api/v1/**
rules:
rules:
- - if: $API_FUZZING_DISABLED
+ - if: $API_FUZZING_DISABLED == 'true' || $API_FUZZING_DISABLED == '1'
when: never
- - if: $API_FUZZING_DISABLED_FOR_DEFAULT_BRANCH &&
+ - if: $API_FUZZING_DISABLED_FOR_DEFAULT_BRANCH == 'true' &&
+ $CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
+ when: never
+ - if: $API_FUZZING_DISABLED_FOR_DEFAULT_BRANCH == '1' &&
$CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
when: never
- if: $CI_COMMIT_BRANCH &&
@@ -2367,7 +2370,7 @@ apifuzzer_v2:
FUZZAPI_EXCLUDE_PATHS: /api/v2/**
rules:
rules:
- - if: $API_FUZZING_DISABLED
+ - if: $API_FUZZING_DISABLED == 'true' || $API_FUZZING_DISABLED == '1'
when: never
- if: $API_FUZZING_DISABLED_FOR_DEFAULT_BRANCH &&
$CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
@@ -2402,7 +2405,7 @@ apifuzzer_branch:
FUZZAPI_EXCLUDE_PATHS: /api/large_response_json
rules:
rules:
- - if: $API_FUZZING_DISABLED
+ - if: $API_FUZZING_DISABLED == 'true' || $API_FUZZING_DISABLED == '1'
when: never
- if: $API_FUZZING_DISABLED_FOR_DEFAULT_BRANCH &&
$CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
@@ -2420,7 +2423,7 @@ apifuzzer_branch:
apifuzzer_main:
extends: apifuzzer_fuzz
rules:
- - if: $API_FUZZING_DISABLED
+ - if: $API_FUZZING_DISABLED == 'true' || $API_FUZZING_DISABLED == '1'
when: never
- if: $API_FUZZING_DISABLED_FOR_DEFAULT_BRANCH &&
$CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
diff --git a/doc/user/application_security/dast_api/index.md b/doc/user/application_security/dast_api/index.md
index 22d4c92b9e1..0daa44aec16 100644
--- a/doc/user/application_security/dast_api/index.md
+++ b/doc/user/application_security/dast_api/index.md
@@ -2252,9 +2252,12 @@ dast_api_v1:
variables:
DAST_API_EXCLUDE_PATHS: /api/v1/**
rules:
- - if: $DAST_API_DISABLED
+ - if: $DAST_API_DISABLED == 'true' || $DAST_API_DISABLED == '1'
when: never
- - if: $DAST_API_DISABLED_FOR_DEFAULT_BRANCH &&
+ - if: $DAST_API_DISABLED_FOR_DEFAULT_BRANCH == 'true' &&
+ $CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
+ when: never
+ - if: $DAST_API_DISABLED_FOR_DEFAULT_BRANCH == '1' &&
$CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
when: never
- if: $CI_COMMIT_BRANCH &&
@@ -2267,9 +2270,12 @@ dast_api_v2:
variables:
DAST_API_EXCLUDE_PATHS: /api/v2/**
rules:
- - if: $DAST_API_DISABLED
+ - if: $DAST_API_DISABLED == 'true' || $DAST_API_DISABLED == '1'
+ when: never
+ - if: $DAST_API_DISABLED_FOR_DEFAULT_BRANCH == 'true' &&
+ $CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
when: never
- - if: $DAST_API_DISABLED_FOR_DEFAULT_BRANCH &&
+ - if: $DAST_API_DISABLED_FOR_DEFAULT_BRANCH == '1' &&
$CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
when: never
- if: $CI_COMMIT_BRANCH &&
@@ -2301,9 +2307,12 @@ dast_api_branch:
variables:
DAST_API_EXCLUDE_PATHS: /api/large_response_json
rules:
- - if: $DAST_API_DISABLED
+ - if: $DAST_API_DISABLED == 'true' || $DAST_API_DISABLED == '1'
when: never
- - if: $DAST_API_DISABLED_FOR_DEFAULT_BRANCH &&
+ - if: $DAST_API_DISABLED_FOR_DEFAULT_BRANCH == 'true' &&
+ $CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
+ when: never
+ - if: $DAST_API_DISABLED_FOR_DEFAULT_BRANCH == '1' &&
$CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
when: never
- if: $CI_COMMIT_BRANCH &&
@@ -2319,9 +2328,12 @@ dast_api_branch:
dast_api_main:
extends: dast_api
rules:
- - if: $DAST_API_DISABLED
+ - if: $DAST_API_DISABLED == 'true' || $DAST_API_DISABLED == '1'
+ when: never
+ - if: $DAST_API_DISABLED_FOR_DEFAULT_BRANCH == 'true' &&
+ $CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
when: never
- - if: $DAST_API_DISABLED_FOR_DEFAULT_BRANCH &&
+ - if: $DAST_API_DISABLED_FOR_DEFAULT_BRANCH == '1' &&
$CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
when: never
- if: $CI_COMMIT_BRANCH &&
diff --git a/doc/user/application_security/index.md b/doc/user/application_security/index.md
index 38625a12c25..a3c512a813c 100644
--- a/doc/user/application_security/index.md
+++ b/doc/user/application_security/index.md
@@ -240,9 +240,9 @@ reports are available to download. To download a report, select
### Ultimate
-A merge request contains a security widget which displays a summary of the new results. New results are determined by comparing the findings of the merge request against the findings of the most recent completed pipeline (`success`, `failed`, `canceled` or `skipped`) for the latest commit in the target branch.
+A merge request contains a security widget which displays a summary of the _new_ results. New results are determined by comparing the findings of the merge request against the findings of the most recent completed pipeline (`success`, `failed`, `canceled` or `skipped`) for the commit when the feature branch was created from the target branch.
-If security scans have not run for the most recent completed pipeline in the target branch there is no base for comparison. The vulnerabilities from the merge request findings are listed as new in the merge request security widget. We recommend you run a scan of the `default` (target) branch before enabling feature branch scans for your developers.
+If security scans have not run for the completed pipeline in the target branch when the feature branch was created, there is no base for comparison. The vulnerabilities from the merge request findings are listed as new in the merge request security widget. We recommend you run a scan of the `default` (target) branch before enabling feature branch scans for your developers.
The merge request security widget displays only a subset of the vulnerabilities in the generated JSON artifact because it contains both new and existing findings.
diff --git a/doc/user/application_security/policies/scan-execution-policies.md b/doc/user/application_security/policies/scan-execution-policies.md
index 55a4994e168..61671efab63 100644
--- a/doc/user/application_security/policies/scan-execution-policies.md
+++ b/doc/user/application_security/policies/scan-execution-policies.md
@@ -257,5 +257,5 @@ developer may want to try running a SAST scan with different variables than the
this case, two SAST jobs run in the pipeline, one with the developer's variables and one with the security and compliance team's variables.
If you want to avoid running duplicate scans, you can either remove the scans from the project's `.gitlab-ci.yml` file or disable your
-local jobs by setting `SAST_DISABLED: true`. Disabling jobs this way does not prevent the security jobs defined by scan execution
+local jobs by setting `SAST_DISABLED: "true"`. Disabling jobs this way does not prevent the security jobs defined by scan execution
policies from running.
diff --git a/doc/user/application_security/policies/scan-result-policies.md b/doc/user/application_security/policies/scan-result-policies.md
index 66ddee262d6..d0a736d0277 100644
--- a/doc/user/application_security/policies/scan-result-policies.md
+++ b/doc/user/application_security/policies/scan-result-policies.md
@@ -76,14 +76,14 @@ the following sections and tables provide an alternative.
This rule enforces the defined actions based on security scan findings.
-| Field | Type | Possible values | Description |
-|------------|------|-----------------|-------------|
-| `type` | `string` | `scan_finding` | The rule's type. |
-| `branches` | `array` of `string` | `[]` or the branch's name | Applicable only to protected target branches. An empty array, `[]`, applies the rule to all protected target branches. |
-| `scanners` | `array` of `string` | `sast`, `secret_detection`, `dependency_scanning`, `container_scanning`, `dast`, `coverage_fuzzing`, `api_fuzzing` | The security scanners for this rule to consider. `sast` includes results from both SAST and SAST IaC scanners. |
-| `vulnerabilities_allowed` | `integer` | Greater than or equal to zero | Number of vulnerabilities allowed before this rule is considered. |
-| `severity_levels` | `array` of `string` | `info`, `unknown`, `low`, `medium`, `high`, `critical`| The severity levels for this rule to consider. |
-| `vulnerability_states` | `array` of `string` | `newly_detected`, `detected`, `confirmed`, `resolved`, `dismissed` | All vulnerabilities fall into two categories:<br><br>**Newly Detected Vulnerabilities** - the `newly_detected` policy option covers vulnerabilities identified in the merge request branch itself but that do not currently exist on the default branch. This policy option requires a pipeline to complete before the rule is evaluated so that it knows whether vulnerabilities are newly detected or not. Merge requests are blocked until the pipeline and necessary security scans are complete. The `newly_detected` option considers both of the following statuses:<br><br> • Detected<br> • Dismissed<br><br>**Pre-Existing Vulnerabilities** - these policy options are evaluated immediately and do not require a pipeline complete as they consider only vulnerabilities previously detected in the default branch.<br><br> • `Detected` - the policy looks for vulnerabilities in the detected state.<br> • `Confirmed` - the policy looks for vulnerabilities in the confirmed state.<br> • `Dismissed` - the policy looks for vulnerabilities in the dismissed state.<br> • `Resolved` - the policy looks for vulnerabilities in the resolved state. |
+| Field | Type | Possible values | Description |
+|------------|------|--------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `type` | `string` | `scan_finding` | The rule's type. |
+| `branches` | `array` of `string` | `[]` or the branch's name | Applicable only to protected target branches. An empty array, `[]`, applies the rule to all protected target branches. |
+| `scanners` | `array` of `string` | `sast`, `secret_detection`, `dependency_scanning`, `container_scanning`, `dast`, `coverage_fuzzing`, `api_fuzzing` | The security scanners for this rule to consider. `sast` includes results from both SAST and SAST IaC scanners. |
+| `vulnerabilities_allowed` | `integer` | Greater than or equal to zero | Number of vulnerabilities allowed before this rule is considered. |
+| `severity_levels` | `array` of `string` | `info`, `unknown`, `low`, `medium`, `high`, `critical` | The severity levels for this rule to consider. |
+| `vulnerability_states` | `array` of `string` | `newly_detected`, `detected`, `confirmed`, `resolved`, `dismissed`, `new_needs_triage`, `new_dismissed` | All vulnerabilities fall into two categories:<br><br>**Newly Detected Vulnerabilities** - the `newly_detected` policy option covers vulnerabilities identified in the merge request branch itself but that do not currently exist on the default branch. This policy option requires a pipeline to complete before the rule is evaluated so that it knows whether vulnerabilities are newly detected or not. Merge requests are blocked until the pipeline and necessary security scans are complete. The `newly_detected` option considers both of the following statuses:<br><br> • Detected<br> • Dismissed<br><br> The `new_needs_triage` option considers the status<br><br> • Detected<br><br> The `new_dismissed` option considers the status<br><br> • Dismissed<br><br>**Pre-Existing Vulnerabilities** - these policy options are evaluated immediately and do not require a pipeline complete as they consider only vulnerabilities previously detected in the default branch.<br><br> • `Detected` - the policy looks for vulnerabilities in the detected state.<br> • `Confirmed` - the policy looks for vulnerabilities in the confirmed state.<br> • `Dismissed` - the policy looks for vulnerabilities in the dismissed state.<br> • `Resolved` - the policy looks for vulnerabilities in the resolved state. |
## `license_finding` rule type
diff --git a/doc/user/compliance/compliance_report/index.md b/doc/user/compliance/compliance_report/index.md
index c6684ba4083..d04aeec066f 100644
--- a/doc/user/compliance/compliance_report/index.md
+++ b/doc/user/compliance/compliance_report/index.md
@@ -195,40 +195,57 @@ To view the compliance frameworks report:
### Apply a compliance framework to projects in a group
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/383209) in GitLab 15.11.
+> - Adding compliance frameworks using bulk actions [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/383209) in GitLab 15.11.
+> - Adding compliance frameworks without using bulk actions [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/394795) in GitLab 16.0.
-You can apply a compliance framework to selected projects in a group.
+You can apply a compliance framework to projects in a group.
Prerequisites:
- You must have the Owner role for the group.
-To apply a compliance framework to projects in a group:
+To apply a compliance framework to one project in a group:
1. On the top bar, select **Main menu > Groups** and find your group.
1. On the left sidebar, select **Security and Compliance > Compliance report**.
1. On the page, select the **Frameworks** tab.
-1. Select one or more projects.
+1. Next to the project you want to add the compliance framework to, select **{plus}** **Add framework**.
+1. Select an existing compliance framework or create a new one.
+
+To apply a compliance framework to multiple projects in a group:
+
+1. On the top bar, select **Main menu > Groups** and find your group.
+1. On the left sidebar, select **Security and Compliance > Compliance report**.
+1. On the page, select the **Frameworks** tab.
+1. Select multiple projects.
1. From the **Choose one bulk action** dropdown list, select **Apply framework to selected projects**.
1. Select framework to apply.
1. Select **Apply**.
### Remove a compliance framework from projects in a group
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/383209) in GitLab 15.11.
+> - Removing compliance frameworks using bulk actions [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/383209) in GitLab 15.11.
+> - Removing compliance frameworks without using bulk actions [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/394795) in GitLab 16.0.
-You can remove a compliance framework from selected projects in a group.
+You can remove a compliance framework from projects in a group.
Prerequisites:
- You must have the Owner role for the group.
-To remove a compliance framework from projects in a group:
+To remove a compliance framework from one project in a group:
+
+1. On the top bar, select **Main menu > Groups** and find your group.
+1. On the left sidebar, select **Security and Compliance > Compliance report**.
+1. On the page, select the **Frameworks** tab.
+1. Next to the compliance framework to remove from the project, select **{close}** on the framework label.
+
+To remove a compliance framework from multiple projects in a group:
1. On the top bar, select **Main menu > Groups** and find your group.
1. On the left sidebar, select **Security and Compliance > Compliance report**.
1. On the page, select the **Frameworks** tab.
-1. Select one or more projects.
+1. Select multiple projects.
1. From the **Choose one bulk action** dropdown list, select **Remove framework from selected projects**.
1. Select **Remove**.
diff --git a/doc/user/group/manage.md b/doc/user/group/manage.md
index ea150436e5b..5b88315f497 100644
--- a/doc/user/group/manage.md
+++ b/doc/user/group/manage.md
@@ -699,7 +699,7 @@ To enable Code Suggestions for a group:
1. Find the **Code Suggestions** settings.
1. Select **Save changes**.
-## Group Experiment features setting **(ULTIMATE)**
+## Group Experiment features setting **(ULTIMATE SAAS)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/404856) in GitLab 16.0.
@@ -721,7 +721,7 @@ To enable Experiment features for a group:
1. Find the **Experiment features** settings.
1. Select **Save changes**.
-## Group third-party AI features setting **(ULTIMATE)**
+## Group third-party AI features setting **(ULTIMATE SAAS)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/404856) in GitLab 16.0.
diff --git a/lib/api/helpers/members_helpers.rb b/lib/api/helpers/members_helpers.rb
index 90f86688367..b3c79486465 100644
--- a/lib/api/helpers/members_helpers.rb
+++ b/lib/api/helpers/members_helpers.rb
@@ -55,7 +55,8 @@ module API
end
def find_all_members_for_project(project)
- MembersFinder.new(project, current_user).execute(include_relations: [:inherited, :direct, :invited_groups])
+ include_relations = [:inherited, :direct, :invited_groups, :shared_into_ancestors]
+ MembersFinder.new(project, current_user).execute(include_relations: include_relations)
end
def find_all_members_for_group(group)
diff --git a/lib/gitlab/ci/build/rules.rb b/lib/gitlab/ci/build/rules.rb
index dee95534b07..bc7aad1b186 100644
--- a/lib/gitlab/ci/build/rules.rb
+++ b/lib/gitlab/ci/build/rules.rb
@@ -6,12 +6,14 @@ module Gitlab
class Rules
include ::Gitlab::Utils::StrongMemoize
- Result = Struct.new(:when, :start_in, :allow_failure, :variables, :errors) do
+ Result = Struct.new(:when, :start_in, :allow_failure, :variables, :needs, :errors) do
def build_attributes
{
when: self.when,
options: { start_in: start_in }.compact,
- allow_failure: allow_failure
+ allow_failure: allow_failure,
+ scheduling_type: (:dag if needs),
+ needs_attributes: needs&.[](:job)
}.compact
end
@@ -33,13 +35,14 @@ module Gitlab
matched_rule.attributes[:when] || @default_when,
matched_rule.attributes[:start_in],
matched_rule.attributes[:allow_failure],
- matched_rule.attributes[:variables]
+ matched_rule.attributes[:variables],
+ (matched_rule.attributes[:needs] if Feature.enabled?(:introduce_rules_with_needs, pipeline.project))
)
else
Result.new('never')
end
rescue Rule::Clause::ParseError => e
- Result.new('never', nil, nil, nil, [e.message])
+ Result.new('never', nil, nil, nil, nil, [e.message])
end
private
diff --git a/lib/gitlab/ci/config/entry/rules/rule.rb b/lib/gitlab/ci/config/entry/rules/rule.rb
index 63bf1b38ac6..1e7f6056a65 100644
--- a/lib/gitlab/ci/config/entry/rules/rule.rb
+++ b/lib/gitlab/ci/config/entry/rules/rule.rb
@@ -9,7 +9,7 @@ module Gitlab
include ::Gitlab::Config::Entry::Configurable
include ::Gitlab::Config::Entry::Attributable
- ALLOWED_KEYS = %i[if changes exists when start_in allow_failure variables].freeze
+ ALLOWED_KEYS = %i[if changes exists when start_in allow_failure variables needs].freeze
ALLOWED_WHEN = %w[on_success on_failure always never manual delayed].freeze
attributes :if, :exists, :when, :start_in, :allow_failure
@@ -20,6 +20,11 @@ module Gitlab
entry :variables, Entry::Variables,
description: 'Environment variables to define for rule conditions.'
+ entry :needs, Entry::Needs,
+ description: 'Needs configuration to define for rule conditions.',
+ metadata: { allowed_needs: %i[job] },
+ inherit: false
+
validations do
validates :config, presence: true
validates :config, type: { with: Hash }
@@ -46,7 +51,8 @@ module Gitlab
def value
config.merge(
changes: (changes_value if changes_defined?),
- variables: (variables_value if variables_defined?)
+ variables: (variables_value if variables_defined?),
+ needs: (needs_value if needs_defined?)
).compact
end
diff --git a/lib/gitlab/ci/yaml_processor.rb b/lib/gitlab/ci/yaml_processor.rb
index 63242d60c85..c69d9218a66 100644
--- a/lib/gitlab/ci/yaml_processor.rb
+++ b/lib/gitlab/ci/yaml_processor.rb
@@ -94,16 +94,20 @@ module Gitlab
end
def validate_job_needs!(name, job)
- return unless needs = job.dig(:needs, :job)
+ validate_needs_specification!(name, job.dig(:needs, :job))
- validate_duplicate_needs!(name, needs)
+ job[:rules]&.each do |rule|
+ validate_needs_specification!(name, rule.dig(:needs, :job))
+ end
+ end
+
+ def validate_needs_specification!(name, needs)
+ return unless needs
needs.each do |need|
validate_job_dependency!(name, need[:name], 'need', optional: need[:optional])
end
- end
- def validate_duplicate_needs!(name, needs)
duplicated_needs =
needs
.group_by { |need| need[:name] }
diff --git a/lib/gitlab/database/partitioning/list/convert_table.rb b/lib/gitlab/database/partitioning/list/convert_table.rb
index d40ddc7a4d8..d4fb150d956 100644
--- a/lib/gitlab/database/partitioning/list/convert_table.rb
+++ b/lib/gitlab/database/partitioning/list/convert_table.rb
@@ -43,8 +43,13 @@ module Gitlab
create_parent_table
attach_foreign_keys_to_parent
+ locking_sql = locking_configuration.locking_statement_for(tables_that_will_lock_during_partitioning)
locking_configuration.with_lock_retries do
+ # Loose FKs trigger will exclusively lock the table and it might
+ # not follow the locking order needed to attach the partition.
+ migration_context.execute(locking_sql) if locking_sql.present?
+
redefine_loose_foreign_key_triggers do
migration_context.execute(sql_to_convert_table)
end
@@ -85,7 +90,6 @@ module Gitlab
# but they acquire the same locks so it's much faster to include them
# here.
[
- locking_configuration.locking_statement_for(tables_that_will_lock_during_partitioning),
attach_table_to_parent_statement,
alter_sequence_statements(old_table: table_name, new_table: parent_table_name),
remove_constraint_statement
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index ab435049daa..07c53fe6f03 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -1865,7 +1865,7 @@ msgstr ""
msgid "AI| %{link_start}How is my data used?%{link_end}"
msgstr ""
-msgid "AI| %{link_start}What are experiment features?%{link_end}"
+msgid "AI| %{link_start}What are Experiment features?%{link_end}"
msgstr ""
msgid "AI|Autocomplete"
@@ -1913,7 +1913,7 @@ msgstr ""
msgid "AI|There is too much text in the chat. Please try again with a shorter text."
msgstr ""
-msgid "AI|These features could cause performance and stability issues and may change over time."
+msgid "AI|These features can cause performance and stability issues and may change over time."
msgstr ""
msgid "AI|Third-party AI services"
@@ -1922,7 +1922,7 @@ msgstr ""
msgid "AI|Unhelpful"
msgstr ""
-msgid "AI|Use experiment features"
+msgid "AI|Use Experiment features"
msgstr ""
msgid "AI|Use third-party AI services"
@@ -45049,9 +45049,6 @@ msgstr ""
msgid "The name of the Jenkins project. Copy the name from the end of the URL to the project."
msgstr ""
-msgid "The new Web IDE"
-msgstr ""
-
msgid "The number of changes to fetch from GitLab when cloning a repository. Lower values can speed up pipeline execution. Set to %{code_open}0%{code_close} or blank to fetch all branches and tags for each job"
msgstr ""
@@ -47366,9 +47363,6 @@ msgstr ""
msgid "Try grouping with different labels"
msgstr ""
-msgid "Try it out now"
-msgstr ""
-
msgid "Try out GitLab Pipelines"
msgstr ""
@@ -48910,9 +48904,6 @@ msgstr ""
msgid "Using the %{codeStart}needs%{codeEnd} keyword makes jobs run before their stage is reached. Jobs run as soon as their %{codeStart}needs%{codeEnd} relationships are met, which speeds up your pipelines."
msgstr ""
-msgid "VS Code in your browser. View code and make changes from the same UI as in your local IDE."
-msgstr ""
-
msgid "Validate"
msgstr ""
diff --git a/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb b/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb
index fa64489fb83..79f16fc2965 100644
--- a/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Manage', product_group: :import_and_integrate,
+ RSpec.describe 'Manage', :requires_admin, product_group: :import_and_integrate,
quarantine: {
issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/407297',
type: :investigating
diff --git a/qa/qa/specs/features/browser_ui/1_manage/import/import_github_repo_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/import/import_github_repo_spec.rb
index 62da946d750..d2744244af2 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/import/import_github_repo_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/import/import_github_repo_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Manage', product_group: :import_and_integrate do
+ RSpec.describe 'Manage', :requires_admin, product_group: :import_and_integrate do
describe 'GitHub import' do
include_context 'with github import'
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/reverting_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/reverting_merge_request_spec.rb
index 8cdcf1dd721..54e9d3ed6c8 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/reverting_merge_request_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/reverting_merge_request_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Merged merge request', product_group: :code_review do
+ describe 'Merged merge request', :requires_admin, product_group: :code_review do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'revert'
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb
index 112149a7a5f..994baea7ad9 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Download merge request patch and diff', product_group: :code_review do
+ describe 'Download merge request patch and diff', :requires_admin, product_group: :code_review do
let(:merge_request) do
Resource::MergeRequest.fabricate_via_api! do |merge_request|
merge_request.title = 'This is a merge request'
diff --git a/qa/qa/specs/features/browser_ui/5_package/container_registry/online_garbage_collection_spec.rb b/qa/qa/specs/features/browser_ui/5_package/container_registry/online_garbage_collection_spec.rb
index 077267ae38a..1e076117e4e 100644
--- a/qa/qa/specs/features/browser_ui/5_package/container_registry/online_garbage_collection_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/container_registry/online_garbage_collection_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', product_group: :container_registry do
+ RSpec.describe 'Package', :requires_admin, product_group: :container_registry do
describe 'Container Registry Online Garbage Collection', :registry_gc, only: { subdomain: %i[pre] } do
let(:group) { Resource::Group.fabricate_via_api! }
diff --git a/qa/qa/specs/features/browser_ui/5_package/infrastructure_registry/terraform_module_registry_spec.rb b/qa/qa/specs/features/browser_ui/5_package/infrastructure_registry/terraform_module_registry_spec.rb
index 13ad0d1d22a..8d80e314d71 100644
--- a/qa/qa/specs/features/browser_ui/5_package/infrastructure_registry/terraform_module_registry_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/infrastructure_registry/terraform_module_registry_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :packages, product_group: :package_registry do
+ RSpec.describe 'Package', :requires_admin, :orchestrated, :packages, product_group: :package_registry do
describe 'Terraform Module Registry' do
include Runtime::Fixtures
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb
index e30703728b2..f5dff1b3e0b 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :packages, :object_storage, :reliable, product_group: :package_registry, feature_flag: { name: 'maven_central_request_forwarding', scope: :global } do
+ RSpec.describe 'Package', :orchestrated, :requires_admin, :packages, :object_storage, :reliable, product_group: :package_registry, feature_flag: { name: 'maven_central_request_forwarding', scope: :global } do
describe 'Maven group level endpoint' do
include Runtime::Fixtures
include Support::Helpers::MaskToken
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_project_level_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_project_level_spec.rb
index 653f42ac3f8..27bca6c17a2 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_project_level_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_project_level_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :packages, :object_storage, :reliable,
+ RSpec.describe 'Package', :orchestrated, :requires_admin, :packages, :object_storage, :reliable,
feature_flag: {
name: 'maven_central_request_forwarding',
scope: :global
diff --git a/spec/finders/members_finder_spec.rb b/spec/finders/members_finder_spec.rb
index dd995e99b9f..afab4514ce2 100644
--- a/spec/finders/members_finder_spec.rb
+++ b/spec/finders/members_finder_spec.rb
@@ -161,6 +161,37 @@ RSpec.describe MembersFinder, feature_category: :subgroups do
expect(result).to eq([member3, member2, member1])
end
+ context 'with :shared_into_ancestors' do
+ let_it_be(:invited_group) do
+ create(:group).tap do |invited_group|
+ create(:group_group_link, shared_group: nested_group, shared_with_group: invited_group)
+ end
+ end
+
+ let_it_be(:invited_group_member) { create(:group_member, :developer, group: invited_group, user: user1) }
+ let_it_be(:namespace_parent_member) { create(:group_member, :owner, group: group, user: user2) }
+ let_it_be(:namespace_member) { create(:group_member, :developer, group: nested_group, user: user3) }
+ let_it_be(:project_member) { create(:project_member, :developer, project: project, user: user4) }
+
+ subject(:result) { described_class.new(project, user4).execute(include_relations: include_relations) }
+
+ context 'when :shared_into_ancestors is included in the relations' do
+ let(:include_relations) { [:inherited, :direct, :invited_groups, :shared_into_ancestors] }
+
+ it "includes members of groups invited into ancestors of project's group" do
+ expect(result).to match_array([namespace_parent_member, namespace_member, invited_group_member, project_member])
+ end
+ end
+
+ context 'when :shared_into_ancestors is not included in the relations' do
+ let(:include_relations) { [:inherited, :direct, :invited_groups] }
+
+ it "does not include members of groups invited into ancestors of project's group" do
+ expect(result).to match_array([namespace_parent_member, namespace_member, project_member])
+ end
+ end
+ end
+
context 'when :invited_groups is passed' do
shared_examples 'with invited_groups param' do
subject { described_class.new(project, user2).execute(include_relations: [:inherited, :direct, :invited_groups]) }
diff --git a/spec/frontend/content_editor/components/toolbar_button_spec.js b/spec/frontend/content_editor/components/toolbar_button_spec.js
index 1556f761682..ffe1ae20ee9 100644
--- a/spec/frontend/content_editor/components/toolbar_button_spec.js
+++ b/spec/frontend/content_editor/components/toolbar_button_spec.js
@@ -81,7 +81,7 @@ describe('content_editor/components/toolbar_button', () => {
await emitEditorEvent({ event: 'transaction', tiptapEditor });
- expect(findButton().classes().includes('active')).toBe(outcome);
+ expect(findButton().classes().includes('gl-bg-gray-100!')).toBe(outcome);
expect(tiptapEditor.isActive).toHaveBeenCalledWith(CONTENT_TYPE);
},
);
diff --git a/spec/frontend/editor/schema/ci/ci_schema_spec.js b/spec/frontend/editor/schema/ci/ci_schema_spec.js
index 87208ec7aa8..51fcf26c39a 100644
--- a/spec/frontend/editor/schema/ci/ci_schema_spec.js
+++ b/spec/frontend/editor/schema/ci/ci_schema_spec.js
@@ -27,6 +27,7 @@ import CacheYaml from './yaml_tests/positive_tests/cache.yml';
import FilterYaml from './yaml_tests/positive_tests/filter.yml';
import IncludeYaml from './yaml_tests/positive_tests/include.yml';
import RulesYaml from './yaml_tests/positive_tests/rules.yml';
+import RulesNeedsYaml from './yaml_tests/positive_tests/rules_needs.yml';
import ProjectPathYaml from './yaml_tests/positive_tests/project_path.yml';
import VariablesYaml from './yaml_tests/positive_tests/variables.yml';
import JobWhenYaml from './yaml_tests/positive_tests/job_when.yml';
@@ -46,6 +47,7 @@ import ProjectPathIncludeLeadSlashYaml from './yaml_tests/negative_tests/project
import ProjectPathIncludeNoSlashYaml from './yaml_tests/negative_tests/project_path/include/no_slash.yml';
import ProjectPathIncludeTailSlashYaml from './yaml_tests/negative_tests/project_path/include/tailing_slash.yml';
import RulesNegativeYaml from './yaml_tests/negative_tests/rules.yml';
+import RulesNeedsNegativeYaml from './yaml_tests/negative_tests/rules_needs.yml';
import TriggerNegative from './yaml_tests/negative_tests/trigger.yml';
import VariablesInvalidOptionsYaml from './yaml_tests/negative_tests/variables/invalid_options.yml';
import VariablesInvalidSyntaxDescYaml from './yaml_tests/negative_tests/variables/invalid_syntax_desc.yml';
@@ -88,6 +90,7 @@ describe('positive tests', () => {
JobWhenYaml,
HooksYaml,
RulesYaml,
+ RulesNeedsYaml,
VariablesYaml,
ProjectPathYaml,
IdTokensYaml,
@@ -121,6 +124,7 @@ describe('negative tests', () => {
IncludeNegativeYaml,
JobWhenNegativeYaml,
RulesNegativeYaml,
+ RulesNeedsNegativeYaml,
TriggerNegative,
VariablesInvalidOptionsYaml,
VariablesInvalidSyntaxDescYaml,
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/rules_needs.yml b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/rules_needs.yml
new file mode 100644
index 00000000000..f2f1eb118f8
--- /dev/null
+++ b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/rules_needs.yml
@@ -0,0 +1,46 @@
+# invalid rules:needs
+lint_job:
+ script: exit 0
+ rules:
+ - if: $var == null
+ needs:
+
+# invalid rules:needs
+lint_job_2:
+ script: exit 0
+ rules:
+ - if: $var == null
+ needs: [20]
+
+# invalid rules:needs
+lint_job_3:
+ script: exit 0
+ rules:
+ - if: $var == null
+ needs:
+ - job:
+
+# invalid rules:needs
+lint_job_5:
+ script: exit 0
+ rules:
+ - if: $var == null
+ needs:
+ - pipeline: 5
+
+# invalid rules:needs
+lint_job_6:
+ script: exit 0
+ rules:
+ - if: $var == null
+ needs:
+ - project: namespace/group/project-name
+
+# invalid rules:needs
+lint_job_7:
+ script: exit 0
+ rules:
+ - if: $var == null
+ needs:
+ - pipeline: 5
+ job: lint_job_6
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/rules_needs.yml b/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/rules_needs.yml
new file mode 100644
index 00000000000..a4a5183dcf4
--- /dev/null
+++ b/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/rules_needs.yml
@@ -0,0 +1,32 @@
+# valid workflow:rules:needs
+pre_lint_job:
+ script: exit 0
+ rules:
+ - if: $var == null
+
+lint_job:
+ script: exit 0
+ rules:
+ - if: $var == null
+
+rspec_job:
+ script: exit 0
+ rules:
+ - if: $var == null
+ needs: [lint_job]
+
+job:
+ needs: [rspec_job]
+ script: exit 0
+ rules:
+ - if: $var == null
+ needs:
+ - job: lint_job
+ artifacts: false
+ optional: true
+ - job: pre_lint_job
+ artifacts: true
+ optional: false
+ - rspec_job
+ - if: $var == true
+ needs: [lint_job, pre_lint_job] \ No newline at end of file
diff --git a/spec/frontend/environments/environment_details/deployments_table_spec.js b/spec/frontend/environments/environment_details/deployments_table_spec.js
new file mode 100644
index 00000000000..7dad5617383
--- /dev/null
+++ b/spec/frontend/environments/environment_details/deployments_table_spec.js
@@ -0,0 +1,58 @@
+import resolvedEnvironmentDetails from 'test_fixtures/graphql/environments/graphql/queries/environment_details.query.graphql.json';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import Commit from '~/vue_shared/components/commit.vue';
+import DeploymentStatusLink from '~/environments/environment_details/components/deployment_status_link.vue';
+import DeploymentJob from '~/environments/environment_details/components/deployment_job.vue';
+import DeploymentTriggerer from '~/environments/environment_details/components/deployment_triggerer.vue';
+import DeploymentActions from '~/environments/environment_details/components/deployment_actions.vue';
+import DeploymentsTable from '~/environments/environment_details/deployments_table.vue';
+import { convertToDeploymentTableRow } from '~/environments/helpers/deployment_data_transformation_helper';
+
+const { environment } = resolvedEnvironmentDetails.data.project;
+const deployments = environment.deployments.nodes.map((d) =>
+ convertToDeploymentTableRow(d, environment),
+);
+
+describe('~/environments/environment_details/index.vue', () => {
+ let wrapper;
+
+ const createWrapper = (propsData = {}) => {
+ wrapper = mountExtended(DeploymentsTable, {
+ propsData: {
+ deployments,
+ ...propsData,
+ },
+ });
+ };
+
+ describe('deployment row', () => {
+ const [, , deployment] = deployments;
+
+ let row;
+
+ beforeEach(() => {
+ createWrapper();
+
+ row = wrapper.find('tr:nth-child(3)');
+ });
+
+ it.each`
+ cell | component | props
+ ${'status'} | ${DeploymentStatusLink} | ${{ deploymentJob: deployment.job, status: deployment.status }}
+ ${'triggerer'} | ${DeploymentTriggerer} | ${{ triggerer: deployment.triggerer }}
+ ${'commit'} | ${Commit} | ${deployment.commit}
+ ${'job'} | ${DeploymentJob} | ${{ job: deployment.job }}
+ ${'created date'} | ${'[data-testid="deployment-created-at"]'} | ${{ time: deployment.created }}
+ ${'deployed date'} | ${'[data-testid="deployment-deployed-at"]'} | ${{ time: deployment.deployed }}
+ ${'deployment actions'} | ${DeploymentActions} | ${{ actions: deployment.actions, rollback: deployment.rollback, approvalEnvironment: deployment.deploymentApproval }}
+ `('should show the correct component for $cell', ({ component, props }) => {
+ expect(row.findComponent(component).props()).toMatchObject(props);
+ });
+
+ it('hides the deployed at timestamp for not-finished deployments', () => {
+ row = wrapper.find('tr');
+
+ expect(row.find('[data-testid="deployment-deployed-at"]').exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/fixtures/environments.rb b/spec/frontend/fixtures/environments.rb
index 77e2a96b328..81f1eb11e3e 100644
--- a/spec/frontend/fixtures/environments.rb
+++ b/spec/frontend/fixtures/environments.rb
@@ -44,7 +44,7 @@ RSpec.describe 'Environments (JavaScript fixtures)', feature_category: :environm
end
let_it_be(:deployment_success) do
- create(:deployment, :success, environment: environment, deployable: build)
+ create(:deployment, :success, environment: environment, deployable: build, finished_at: 1.hour.since)
end
let_it_be(:deployment_failed) do
diff --git a/spec/frontend/vue_shared/components/web_ide_link_spec.js b/spec/frontend/vue_shared/components/web_ide_link_spec.js
index 4b2ce24a49f..d888abc19ef 100644
--- a/spec/frontend/vue_shared/components/web_ide_link_spec.js
+++ b/spec/frontend/vue_shared/components/web_ide_link_spec.js
@@ -1,4 +1,4 @@
-import { GlButton, GlLink, GlModal, GlPopover } from '@gitlab/ui';
+import { GlButton, GlModal } from '@gitlab/ui';
import { nextTick } from 'vue';
import ActionsButton from '~/vue_shared/components/actions_button.vue';
@@ -9,7 +9,6 @@ import WebIdeLink, {
PREFERRED_EDITOR_KEY,
} from '~/vue_shared/components/web_ide_link.vue';
import ConfirmForkModal from '~/vue_shared/components/confirm_fork_modal.vue';
-import UserCalloutDismisser from '~/vue_shared/components/user_callout_dismisser.vue';
import { KEY_WEB_IDE } from '~/vue_shared/components/constants';
import { stubComponent } from 'helpers/stub_component';
@@ -95,14 +94,7 @@ describe('Web IDE link component', () => {
let wrapper;
- function createComponent(
- props,
- {
- mountFn = shallowMountExtended,
- glFeatures = {},
- userCalloutDismisserSlotProps = { dismiss: jest.fn() },
- } = {},
- ) {
+ function createComponent(props, { mountFn = shallowMountExtended, glFeatures = {} } = {}) {
wrapper = mountFn(WebIdeLink, {
propsData: {
editUrl: TEST_EDIT_URL,
@@ -124,11 +116,6 @@ describe('Web IDE link component', () => {
<slot name="modal-footer"></slot>
</div>`,
}),
- UserCalloutDismisser: stubComponent(UserCalloutDismisser, {
- render() {
- return this.$scopedSlots.default(userCalloutDismisserSlotProps);
- },
- }),
},
});
}
@@ -141,13 +128,6 @@ describe('Web IDE link component', () => {
const findLocalStorageSync = () => wrapper.findComponent(LocalStorageSync);
const findModal = () => wrapper.findComponent(GlModal);
const findForkConfirmModal = () => wrapper.findComponent(ConfirmForkModal);
- const findUserCalloutDismisser = () => wrapper.findComponent(UserCalloutDismisser);
- const findNewWebIdeCalloutPopover = () => wrapper.findComponent(GlPopover);
- const findTryItOutLink = () =>
- wrapper
- .findAllComponents(GlLink)
- .filter((link) => link.text().includes('Try it out'))
- .at(0);
it.each([
{
@@ -446,132 +426,6 @@ describe('Web IDE link component', () => {
});
});
- describe('Web IDE callout', () => {
- describe('vscode_web_ide feature flag is enabled and the edit button is not shown', () => {
- let dismiss;
-
- beforeEach(() => {
- dismiss = jest.fn();
- createComponent(
- {
- showEditButton: false,
- },
- {
- glFeatures: { vscodeWebIde: true },
- userCalloutDismisserSlotProps: { dismiss },
- },
- );
- });
- it('does not skip the user_callout_dismisser query', () => {
- expect(findUserCalloutDismisser().props()).toEqual(
- expect.objectContaining({
- skipQuery: false,
- featureName: 'vscode_web_ide_callout',
- }),
- );
- });
-
- it('mounts new web ide callout popover', () => {
- expect(findNewWebIdeCalloutPopover().props()).toEqual(
- expect.objectContaining({
- showCloseButton: '',
- target: 'web-ide-link',
- triggers: 'manual',
- boundaryPadding: 80,
- }),
- );
- });
-
- describe.each`
- calloutStatus | shouldShowCallout | popoverVisibility | tooltipVisibility
- ${'show'} | ${true} | ${true} | ${false}
- ${'hide'} | ${false} | ${false} | ${true}
- `(
- 'when should $calloutStatus web ide callout',
- ({ shouldShowCallout, popoverVisibility, tooltipVisibility }) => {
- beforeEach(() => {
- createComponent(
- {
- showEditButton: false,
- },
- {
- glFeatures: { vscodeWebIde: true },
- userCalloutDismisserSlotProps: { shouldShowCallout, dismiss },
- },
- );
- });
-
- it(`popover visibility = ${popoverVisibility}`, () => {
- expect(findNewWebIdeCalloutPopover().props().show).toBe(popoverVisibility);
- });
-
- it(`action button tooltip visibility = ${tooltipVisibility}`, () => {
- expect(findActionsButton().props().showActionTooltip).toBe(tooltipVisibility);
- });
- },
- );
-
- it('dismisses the callout when popover close button is clicked', () => {
- findNewWebIdeCalloutPopover().vm.$emit('close-button-clicked');
-
- expect(dismiss).toHaveBeenCalled();
- });
-
- it('dismisses the callout when try it now link is clicked', () => {
- findTryItOutLink().vm.$emit('click');
-
- expect(dismiss).toHaveBeenCalled();
- });
-
- it('dismisses the callout when action button is clicked', () => {
- findActionsButton().vm.$emit('actionClicked');
-
- expect(dismiss).toHaveBeenCalled();
- });
- });
-
- describe.each`
- featureFlag | showEditButton
- ${false} | ${true}
- ${true} | ${false}
- ${false} | ${false}
- `(
- 'when vscode_web_ide=$featureFlag and showEditButton = $showEditButton',
- ({ vscodeWebIde, showEditButton }) => {
- let dismiss;
-
- beforeEach(() => {
- dismiss = jest.fn();
-
- createComponent(
- {
- showEditButton,
- },
- { glFeatures: { vscodeWebIde }, userCalloutDismisserSlotProps: { dismiss } },
- );
- });
-
- it('skips the user_callout_dismisser query', () => {
- expect(findUserCalloutDismisser().props().skipQuery).toBe(true);
- });
-
- it('displays actions button tooltip', () => {
- expect(findActionsButton().props().showActionTooltip).toBe(true);
- });
-
- it('mounts new web ide callout popover', () => {
- expect(findNewWebIdeCalloutPopover().exists()).toBe(false);
- });
-
- it('does not dismiss the callout when action button is clicked', () => {
- findActionsButton().vm.$emit('actionClicked');
-
- expect(dismiss).not.toHaveBeenCalled();
- });
- },
- );
- });
-
describe('when vscode_web_ide feature flag is enabled', () => {
describe('when is not showing edit button', () => {
describe(`when ${PREFERRED_EDITOR_RESET_KEY} is unset`, () => {
diff --git a/spec/helpers/avatars_helper_spec.rb b/spec/helpers/avatars_helper_spec.rb
index b7fdadbd036..dd0d6d1246f 100644
--- a/spec/helpers/avatars_helper_spec.rb
+++ b/spec/helpers/avatars_helper_spec.rb
@@ -102,7 +102,7 @@ RSpec.describe AvatarsHelper, feature_category: :source_code_management do
end
describe '#avatar_icon_for_email', :clean_gitlab_redis_cache do
- let(:user) { create(:user, :public_email, avatar: File.open(uploaded_image_temp_path)) }
+ let(:user) { create(:user, :public_email, :commit_email, avatar: File.open(uploaded_image_temp_path)) }
subject { helper.avatar_icon_for_email(user.email).to_s }
@@ -131,13 +131,22 @@ RSpec.describe AvatarsHelper, feature_category: :source_code_management do
end
context 'without an email passed' do
- it 'calls gravatar_icon' do
- expect(helper).to receive(:gravatar_icon).with(nil, 20, 2)
- expect(User).not_to receive(:find_by_any_email)
+ it 'returns the default avatar' do
+ expect(helper).to receive(:default_avatar)
+ expect(User).not_to receive(:with_public_email)
helper.avatar_icon_for_email(nil, 20, 2)
end
end
+
+ context 'with a blank email address' do
+ it 'returns the default avatar' do
+ expect(helper).to receive(:default_avatar)
+ expect(User).not_to receive(:with_public_email)
+
+ helper.avatar_icon_for_email('', 20, 2)
+ end
+ end
end
end
diff --git a/spec/helpers/nav_helper_spec.rb b/spec/helpers/nav_helper_spec.rb
index d1e3c7d2240..17d28b07763 100644
--- a/spec/helpers/nav_helper_spec.rb
+++ b/spec/helpers/nav_helper_spec.rb
@@ -161,6 +161,21 @@ RSpec.describe NavHelper, feature_category: :navigation do
context 'with feature flag on' do
let(:new_nav_ff) { true }
+ context 'when user has not interacted with the new nav toggle yet' do
+ let(:user_preference) { nil }
+
+ specify { expect(subject).to eq false }
+
+ context 'when the user was enrolled into the new nav via a special feature flag' do
+ before do
+ # this ff is disabled in globally to keep tests of the old nav working
+ stub_feature_flags(super_sidebar_nav_enrolled: true)
+ end
+
+ specify { expect(subject).to eq true }
+ end
+ end
+
context 'when user has new nav disabled' do
let(:user_preference) { false }
diff --git a/spec/lib/gitlab/ci/build/rules_spec.rb b/spec/lib/gitlab/ci/build/rules_spec.rb
index e82dcd0254d..1ece0f6b7b9 100644
--- a/spec/lib/gitlab/ci/build/rules_spec.rb
+++ b/spec/lib/gitlab/ci/build/rules_spec.rb
@@ -181,6 +181,108 @@ RSpec.describe Gitlab::Ci::Build::Rules do
end
end
+ context 'with needs' do
+ context 'when single needs is specified' do
+ let(:rule_list) do
+ [{ if: '$VAR == null', needs: [{ name: 'test', artifacts: true, optional: false }] }]
+ end
+
+ it {
+ is_expected.to eq(described_class::Result.new('on_success', nil, nil, nil,
+ [{ name: 'test', artifacts: true, optional: false }], nil))
+ }
+ end
+
+ context 'when multiple needs are specified' do
+ let(:rule_list) do
+ [{ if: '$VAR == null',
+ needs: [{ name: 'test', artifacts: true, optional: false },
+ { name: 'rspec', artifacts: true, optional: false }] }]
+ end
+
+ it {
+ is_expected.to eq(described_class::Result.new('on_success', nil, nil, nil,
+ [{ name: 'test', artifacts: true, optional: false },
+ { name: 'rspec', artifacts: true, optional: false }], nil))
+ }
+ end
+
+ context 'when there are no needs specified' do
+ let(:rule_list) { [{ if: '$VAR == null' }] }
+
+ it { is_expected.to eq(described_class::Result.new('on_success', nil, nil, nil, nil, nil)) }
+ end
+
+ context 'when need is specified with additional attibutes' do
+ let(:rule_list) do
+ [{ if: '$VAR == null', needs: [{
+ artifacts: true,
+ name: 'test',
+ optional: false,
+ when: 'never'
+ }] }]
+ end
+
+ it {
+ is_expected.to eq(
+ described_class::Result.new('on_success', nil, nil, nil,
+ [{ artifacts: true, name: 'test', optional: false, when: 'never' }], nil))
+ }
+ end
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(introduce_rules_with_needs: false)
+ end
+
+ context 'with needs' do
+ context 'when single needs is specified' do
+ let(:rule_list) do
+ [{ if: '$VAR == null', needs: [{ name: 'test', artifacts: true, optional: false }] }]
+ end
+
+ it {
+ is_expected.to eq(described_class::Result.new('on_success', nil, nil, nil, nil, nil))
+ }
+ end
+
+ context 'when multiple needs are specified' do
+ let(:rule_list) do
+ [{ if: '$VAR == null',
+ needs: [{ name: 'test', artifacts: true, optional: false },
+ { name: 'rspec', artifacts: true, optional: false }] }]
+ end
+
+ it {
+ is_expected.to eq(described_class::Result.new('on_success', nil, nil, nil, nil, nil))
+ }
+ end
+
+ context 'when there are no needs specified' do
+ let(:rule_list) { [{ if: '$VAR == null' }] }
+
+ it { is_expected.to eq(described_class::Result.new('on_success', nil, nil, nil, nil, nil)) }
+ end
+
+ context 'when need is specified with additional attibutes' do
+ let(:rule_list) do
+ [{ if: '$VAR == null', needs: [{
+ artifacts: true,
+ name: 'test',
+ optional: false,
+ when: 'never'
+ }] }]
+ end
+
+ it {
+ is_expected.to eq(
+ described_class::Result.new('on_success', nil, nil, nil, nil, nil))
+ }
+ end
+ end
+ end
+ end
+
context 'with variables' do
context 'with matching rule' do
let(:rule_list) { [{ if: '$VAR == null', variables: { MY_VAR: 'my var' } }] }
@@ -208,9 +310,10 @@ RSpec.describe Gitlab::Ci::Build::Rules do
let(:start_in) { nil }
let(:allow_failure) { nil }
let(:variables) { nil }
+ let(:needs) { nil }
subject(:result) do
- Gitlab::Ci::Build::Rules::Result.new(when_value, start_in, allow_failure, variables)
+ Gitlab::Ci::Build::Rules::Result.new(when_value, start_in, allow_failure, variables, needs)
end
describe '#build_attributes' do
@@ -221,6 +324,45 @@ RSpec.describe Gitlab::Ci::Build::Rules do
it 'compacts nil values' do
is_expected.to eq(options: {}, when: 'on_success')
end
+
+ context 'scheduling_type' do
+ context 'when rules have needs' do
+ context 'single need' do
+ let(:needs) do
+ { job: [{ name: 'test' }] }
+ end
+
+ it 'saves needs' do
+ expect(subject[:needs_attributes]).to eq([{ name: "test" }])
+ end
+
+ it 'adds schedule type to the build_attributes' do
+ expect(subject[:scheduling_type]).to eq(:dag)
+ end
+ end
+
+ context 'multiple needs' do
+ let(:needs) do
+ { job: [{ name: 'test' }, { name: 'test_2', artifacts: true, optional: false }] }
+ end
+
+ it 'saves needs' do
+ expect(subject[:needs_attributes]).to match_array([{ name: "test" },
+ { name: 'test_2', artifacts: true, optional: false }])
+ end
+
+ it 'adds schedule type to the build_attributes' do
+ expect(subject[:scheduling_type]).to eq(:dag)
+ end
+ end
+ end
+
+ context 'when rules do not have needs' do
+ it 'does not add schedule type to the build_attributes' do
+ expect(subject.key?(:scheduling_type)).to be_falsy
+ end
+ end
+ end
end
describe '#pass?' do
diff --git a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
index 86a11111283..9d5a9bc8058 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
@@ -109,6 +109,104 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build, feature_category: :pipeline_co
end
end
+ context 'with job:rules:[needs:]' do
+ context 'with a single rule' do
+ let(:job_needs_attributes) { [{ name: 'rspec' }] }
+
+ context 'when job has needs set' do
+ context 'when rule evaluates to true' do
+ let(:attributes) do
+ { name: 'rspec',
+ ref: 'master',
+ needs_attributes: job_needs_attributes,
+ rules: [{ if: '$VAR == null', needs: { job: [{ name: 'build-job' }] } }] }
+ end
+
+ it 'overrides the job needs' do
+ expect(subject).to include(needs_attributes: [{ name: 'build-job' }])
+ end
+ end
+
+ context 'when rule evaluates to false' do
+ let(:attributes) do
+ { name: 'rspec',
+ ref: 'master',
+ needs_attributes: job_needs_attributes,
+ rules: [{ if: '$VAR == true', needs: { job: [{ name: 'build-job' }] } }] }
+ end
+
+ it 'keeps the job needs' do
+ expect(subject).to include(needs_attributes: job_needs_attributes)
+ end
+ end
+
+ context 'with subkeys: artifacts, optional' do
+ let(:attributes) do
+ { name: 'rspec',
+ ref: 'master',
+ rules:
+ [
+ { if: '$VAR == null',
+ needs: {
+ job: [{
+ name: 'build-job',
+ optional: false,
+ artifacts: true
+ }]
+ } }
+ ] }
+ end
+
+ context 'when rule evaluates to true' do
+ it 'sets the job needs as well as the job subkeys' do
+ expect(subject[:needs_attributes]).to match_array([{ name: 'build-job', optional: false, artifacts: true }])
+ end
+
+ it 'sets the scheduling type to dag' do
+ expect(subject[:scheduling_type]).to eq(:dag)
+ end
+ end
+ end
+ end
+
+ context 'with multiple rules' do
+ context 'when a rule evaluates to true' do
+ let(:attributes) do
+ { name: 'rspec',
+ ref: 'master',
+ needs_attributes: job_needs_attributes,
+ rules: [
+ { if: '$VAR == true', needs: { job: [{ name: 'rspec-1' }] } },
+ { if: '$VAR2 == true', needs: { job: [{ name: 'rspec-2' }] } },
+ { if: '$VAR3 == null', needs: { job: [{ name: 'rspec' }, { name: 'lint' }] } }
+ ] }
+ end
+
+ it 'overrides the job needs' do
+ expect(subject).to include(needs_attributes: [{ name: 'rspec' }, { name: 'lint' }])
+ end
+ end
+
+ context 'when all rules evaluates to false' do
+ let(:attributes) do
+ { name: 'rspec',
+ ref: 'master',
+ needs_attributes: job_needs_attributes,
+ rules: [
+ { if: '$VAR == true', needs: { job: [{ name: 'rspec-1' }] } },
+ { if: '$VAR2 == true', needs: { job: [{ name: 'rspec-2' }] } },
+ { if: '$VAR3 == true', needs: { job: [{ name: 'rspec-3' }] } }
+ ] }
+ end
+
+ it 'keeps the job needs' do
+ expect(subject).to include(needs_attributes: job_needs_attributes)
+ end
+ end
+ end
+ end
+ end
+
context 'with job:tags' do
let(:attributes) do
{
diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb
index a35dd968cd6..f8c2889798f 100644
--- a/spec/lib/gitlab/ci/yaml_processor_spec.rb
+++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb
@@ -659,6 +659,191 @@ module Gitlab
it_behaves_like 'has warnings and expected error', /build job: need test is not defined in current or prior stages/
end
+
+ describe '#validate_job_needs!' do
+ context "when all validations pass" do
+ let(:config) do
+ <<-EOYML
+ stages:
+ - lint
+ lint_job:
+ needs: [lint_job_2]
+ stage: lint
+ script: 'echo lint_job'
+ rules:
+ - if: $var == null
+ needs:
+ - lint_job_2
+ - job: lint_job_3
+ optional: true
+ lint_job_2:
+ stage: lint
+ script: 'echo job'
+ rules:
+ - if: $var == null
+ lint_job_3:
+ stage: lint
+ script: 'echo job'
+ rules:
+ - if: $var == null
+ EOYML
+ end
+
+ it 'returns a valid response' do
+ expect(subject).to be_valid
+ expect(subject).to be_instance_of(Gitlab::Ci::YamlProcessor::Result)
+ end
+ end
+
+ context 'needs as array' do
+ context 'single need in following stage' do
+ let(:config) do
+ <<-EOYML
+ stages:
+ - lint
+ - test
+ lint_job:
+ stage: lint
+ script: 'echo lint_job'
+ rules:
+ - if: $var == null
+ needs: [test_job]
+ test_job:
+ stage: test
+ script: 'echo job'
+ rules:
+ - if: $var == null
+ EOYML
+ end
+
+ it_behaves_like 'returns errors', 'lint_job job: need test_job is not defined in current or prior stages'
+ end
+
+ context 'multiple needs in the following stage' do
+ let(:config) do
+ <<-EOYML
+ stages:
+ - lint
+ - test
+ lint_job:
+ stage: lint
+ script: 'echo lint_job'
+ rules:
+ - if: $var == null
+ needs: [test_job, test_job_2]
+ test_job:
+ stage: test
+ script: 'echo job'
+ rules:
+ - if: $var == null
+ test_job_2:
+ stage: test
+ script: 'echo job'
+ rules:
+ - if: $var == null
+ EOYML
+ end
+
+ it_behaves_like 'returns errors', 'lint_job job: need test_job is not defined in current or prior stages'
+ end
+
+ context 'single need in following state - hyphen need' do
+ let(:config) do
+ <<-EOYML
+ stages:
+ - lint
+ - test
+ lint_job:
+ stage: lint
+ script: 'echo lint_job'
+ rules:
+ - if: $var == null
+ needs:
+ - test_job
+ test_job:
+ stage: test
+ script: 'echo job'
+ rules:
+ - if: $var == null
+ EOYML
+ end
+
+ it_behaves_like 'returns errors', 'lint_job job: need test_job is not defined in current or prior stages'
+ end
+
+ context 'when there are duplicate needs (string and hash)' do
+ let(:config) do
+ <<-EOYML
+ stages:
+ - test
+ test_job_1:
+ stage: test
+ script: 'echo lint_job'
+ rules:
+ - if: $var == null
+ needs:
+ - test_job_2
+ - job: test_job_2
+ test_job_2:
+ stage: test
+ script: 'echo job'
+ rules:
+ - if: $var == null
+ EOYML
+ end
+
+ it_behaves_like 'returns errors', 'test_job_1 has the following needs duplicated: test_job_2.'
+ end
+ end
+
+ context 'rule needs as hash' do
+ context 'single hash need in following stage' do
+ let(:config) do
+ <<-EOYML
+ stages:
+ - lint
+ - test
+ lint_job:
+ stage: lint
+ script: 'echo lint_job'
+ rules:
+ - if: $var == null
+ needs:
+ - job: test_job
+ artifacts: false
+ optional: false
+ test_job:
+ stage: test
+ script: 'echo job'
+ rules:
+ - if: $var == null
+ EOYML
+ end
+
+ it_behaves_like 'returns errors', 'lint_job job: need test_job is not defined in current or prior stages'
+ end
+ end
+
+ context 'job rule need does not exist' do
+ let(:config) do
+ <<-EOYML
+ build:
+ stage: build
+ script: echo
+ rules:
+ - when: always
+ test:
+ stage: test
+ script: echo
+ rules:
+ - if: $var == null
+ needs: [unknown_job]
+ EOYML
+ end
+
+ it_behaves_like 'has warnings and expected error', /test job: undefined need: unknown_job/
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/database/partitioning/list/convert_table_spec.rb b/spec/lib/gitlab/database/partitioning/list/convert_table_spec.rb
index 81b00f82803..8e2a53ea76f 100644
--- a/spec/lib/gitlab/database/partitioning/list/convert_table_spec.rb
+++ b/spec/lib/gitlab/database/partitioning/list/convert_table_spec.rb
@@ -286,6 +286,26 @@ RSpec.describe Gitlab::Database::Partitioning::List::ConvertTable, feature_categ
expect(migration_context.has_loose_foreign_key?(table_name)).to be_truthy
expect(migration_context.has_loose_foreign_key?(parent_table_name)).to be_truthy
end
+
+ context 'with locking tables' do
+ let(:lock_tables) { [table_name] }
+
+ it 'locks the table before dropping the triggers' do
+ recorder = ActiveRecord::QueryRecorder.new { partition }
+
+ lock_index = recorder.log.find_index do |log|
+ log.start_with?('LOCK "_test_table_to_partition" IN ACCESS EXCLUSIVE MODE')
+ end
+
+ trigger_index = recorder.log.find_index do |log|
+ log.start_with?('DROP TRIGGER IF EXISTS _test_table_to_partition_loose_fk_trigger')
+ end
+
+ expect(lock_index).to be_present
+ expect(trigger_index).to be_present
+ expect(lock_index).to be < trigger_index
+ end
+ end
end
end
diff --git a/spec/requests/api/members_spec.rb b/spec/requests/api/members_spec.rb
index 85ccfa3cf51..353fddcb08d 100644
--- a/spec/requests/api/members_spec.rb
+++ b/spec/requests/api/members_spec.rb
@@ -130,6 +130,8 @@ RSpec.describe API::Members, feature_category: :subgroups do
let(:project_user) { create(:user) }
let(:linked_group_user) { create(:user) }
let!(:project_group_link) { create(:project_group_link, project: project, group: linked_group) }
+ let(:invited_group_developer) { create(:user, username: 'invited_group_developer') }
+ let(:invited_group) { create(:group) { |group| group.add_developer(invited_group_developer) } }
let(:project) do
create(:project, :public, group: nested_group) do |project|
@@ -146,19 +148,21 @@ RSpec.describe API::Members, feature_category: :subgroups do
let(:nested_group) do
create(:group, parent: group) do |nested_group|
nested_group.add_developer(nested_user)
+ create(:group_group_link, :guest, shared_with_group: invited_group, shared_group: nested_group)
end
end
- it 'finds all project members including inherited members' do
+ it 'finds all project members including inherited members and members shared into ancestor groups' do
get api("/projects/#{project.id}/members/all", developer)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
- expect(json_response.map { |u| u['id'] }).to match_array [maintainer.id, developer.id, nested_user.id, project_user.id, linked_group_user.id]
+ expected_user_ids = [maintainer.id, developer.id, nested_user.id, project_user.id, linked_group_user.id, invited_group_developer.id]
+ expect(json_response.map { |u| u['id'] }).to match_array expected_user_ids
end
- it 'returns only one member for each user without returning duplicated members' do
+ it 'returns only one member for each user without returning duplicated members with correct access levels' do
linked_group.add_developer(developer)
get api("/projects/#{project.id}/members/all", developer)
@@ -172,7 +176,8 @@ RSpec.describe API::Members, feature_category: :subgroups do
[maintainer.id, Gitlab::Access::OWNER],
[nested_user.id, Gitlab::Access::DEVELOPER],
[project_user.id, Gitlab::Access::DEVELOPER],
- [linked_group_user.id, Gitlab::Access::DEVELOPER]
+ [linked_group_user.id, Gitlab::Access::DEVELOPER],
+ [invited_group_developer.id, Gitlab::Access::GUEST]
]
expect(json_response.map { |u| [u['id'], u['access_level']] }).to match_array(expected_users_and_access_levels)
end
@@ -183,7 +188,8 @@ RSpec.describe API::Members, feature_category: :subgroups do
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
- expect(json_response.map { |u| u['id'] }).to match_array [maintainer.id, developer.id, nested_user.id]
+ expected_user_ids = [maintainer.id, developer.id, nested_user.id, invited_group_developer.id]
+ expect(json_response.map { |u| u['id'] }).to match_array expected_user_ids
end
context 'with a subgroup' do
diff --git a/spec/services/ci/create_pipeline_service/rules_spec.rb b/spec/services/ci/create_pipeline_service/rules_spec.rb
index 19f9e7e3e4a..87112137675 100644
--- a/spec/services/ci/create_pipeline_service/rules_spec.rb
+++ b/spec/services/ci/create_pipeline_service/rules_spec.rb
@@ -386,6 +386,109 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
expect(regular_job.allow_failure).to eq(true)
end
end
+
+ context 'with needs:' do
+ let(:config) do
+ <<-EOY
+ job1:
+ script: ls
+
+ job2:
+ script: ls
+ rules:
+ - if: $var == null
+ needs: [job1]
+ - when: on_success
+
+ job3:
+ script: ls
+ rules:
+ - if: $var == null
+ needs: [job1]
+ - needs: [job2]
+
+ job4:
+ script: ls
+ needs: [job1]
+ rules:
+ - if: $var == null
+ needs: [job2]
+ - when: on_success
+ needs: [job3]
+ EOY
+ end
+
+ let(:job1) { pipeline.builds.find_by(name: 'job1') }
+ let(:job2) { pipeline.builds.find_by(name: 'job2') }
+ let(:job3) { pipeline.builds.find_by(name: 'job3') }
+ let(:job4) { pipeline.builds.find_by(name: 'job4') }
+
+ context 'when the `$var` rule matches' do
+ it 'creates a pipeline with overridden needs' do
+ expect(pipeline).to be_persisted
+ expect(build_names).to contain_exactly('job1', 'job2', 'job3', 'job4')
+
+ expect(job1.needs).to be_empty
+ expect(job2.needs).to contain_exactly(an_object_having_attributes(name: 'job1'))
+ expect(job3.needs).to contain_exactly(an_object_having_attributes(name: 'job1'))
+ expect(job4.needs).to contain_exactly(an_object_having_attributes(name: 'job2'))
+ end
+ end
+
+ context 'when the `$var` rule does not match' do
+ let(:initialization_params) { base_initialization_params.merge(variables_attributes: variables_attributes) }
+
+ let(:variables_attributes) do
+ [{ key: 'var', secret_value: 'SOME_VAR' }]
+ end
+
+ it 'creates a pipeline with overridden needs' do
+ expect(pipeline).to be_persisted
+ expect(build_names).to contain_exactly('job1', 'job2', 'job3', 'job4')
+
+ expect(job1.needs).to be_empty
+ expect(job2.needs).to be_empty
+ expect(job3.needs).to contain_exactly(an_object_having_attributes(name: 'job2'))
+ expect(job4.needs).to contain_exactly(an_object_having_attributes(name: 'job3'))
+ end
+ end
+
+ context 'when the FF introduce_rules_with_needs is disabled' do
+ before do
+ stub_feature_flags(introduce_rules_with_needs: false)
+ end
+
+ context 'when the `$var` rule matches' do
+ it 'creates a pipeline without overridden needs' do
+ expect(pipeline).to be_persisted
+ expect(build_names).to contain_exactly('job1', 'job2', 'job3', 'job4')
+
+ expect(job1.needs).to be_empty
+ expect(job2.needs).to be_empty
+ expect(job3.needs).to be_empty
+ expect(job4.needs).to contain_exactly(an_object_having_attributes(name: 'job1'))
+ end
+ end
+
+ context 'when the `$var` rule does not match' do
+ let(:initialization_params) { base_initialization_params.merge(variables_attributes: variables_attributes) }
+
+ let(:variables_attributes) do
+ [{ key: 'var', secret_value: 'SOME_VAR' }]
+ end
+
+ it 'creates a pipeline without overridden needs' do
+ expect(pipeline).to be_persisted
+ expect(build_names).to contain_exactly('job1', 'job2', 'job3', 'job4')
+
+ expect(job1.needs).to be_empty
+ expect(job2.needs).to be_empty
+ expect(job3.needs).to be_empty
+ expect(job4.needs).to contain_exactly(an_object_having_attributes(name: 'job1'))
+ end
+ end
+ end
+ end
end
context 'changes:' do
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 470df53051e..f8bbad393e6 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -269,6 +269,10 @@ RSpec.configure do |config|
stub_feature_flags(ci_queueing_disaster_recovery_disable_fair_scheduling: false)
stub_feature_flags(ci_queueing_disaster_recovery_disable_quota: false)
+ # Only a few percent of users will be "enrolled" into the new nav with this flag.
+ # Having it enabled globally would make it impossible to test the current nav.
+ stub_feature_flags(super_sidebar_nav_enrolled: false)
+
# It's disabled in specs because we don't support certain features which
# cause spec failures.
stub_feature_flags(use_click_house_database_for_error_tracking: false)
diff --git a/spec/support/shared_examples/services/container_registry_auth_service_shared_examples.rb b/spec/support/shared_examples/services/container_registry_auth_service_shared_examples.rb
index 58659775d8c..493a96b8dae 100644
--- a/spec/support/shared_examples/services/container_registry_auth_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/container_registry_auth_service_shared_examples.rb
@@ -79,7 +79,8 @@ RSpec.shared_examples 'an accessible' do
let(:access) do
[{ 'type' => 'repository',
'name' => project.full_path,
- 'actions' => actions }]
+ 'actions' => actions,
+ 'meta' => { 'project_path' => project.full_path } }]
end
it_behaves_like 'a valid token'
@@ -244,12 +245,14 @@ RSpec.shared_examples 'a container registry auth service' do
{
'type' => 'repository',
'name' => project.full_path,
- 'actions' => ['pull']
+ 'actions' => ['pull'],
+ 'meta' => { 'project_path' => project.full_path }
},
{
'type' => 'repository',
'name' => "#{project.full_path}/*",
- 'actions' => ['pull']
+ 'actions' => ['pull'],
+ 'meta' => { 'project_path' => project.full_path }
}
]
end
@@ -822,16 +825,20 @@ RSpec.shared_examples 'a container registry auth service' do
[
{ 'type' => 'repository',
'name' => internal_project.full_path,
- 'actions' => ['pull'] },
+ 'actions' => ['pull'],
+ 'meta' => { 'project_path' => internal_project.full_path } },
{ 'type' => 'repository',
'name' => private_project.full_path,
- 'actions' => ['pull'] },
+ 'actions' => ['pull'],
+ 'meta' => { 'project_path' => private_project.full_path } },
{ 'type' => 'repository',
'name' => public_project.full_path,
- 'actions' => ['pull'] },
+ 'actions' => ['pull'],
+ 'meta' => { 'project_path' => public_project.full_path } },
{ 'type' => 'repository',
'name' => public_project_private_container_registry.full_path,
- 'actions' => ['pull'] }
+ 'actions' => ['pull'],
+ 'meta' => { 'project_path' => public_project_private_container_registry.full_path } }
]
end
end
@@ -845,10 +852,12 @@ RSpec.shared_examples 'a container registry auth service' do
[
{ 'type' => 'repository',
'name' => internal_project.full_path,
- 'actions' => ['pull'] },
+ 'actions' => ['pull'],
+ 'meta' => { 'project_path' => internal_project.full_path } },
{ 'type' => 'repository',
'name' => public_project.full_path,
- 'actions' => ['pull'] }
+ 'actions' => ['pull'],
+ 'meta' => { 'project_path' => public_project.full_path } }
]
end
end
@@ -862,7 +871,8 @@ RSpec.shared_examples 'a container registry auth service' do
[
{ 'type' => 'repository',
'name' => public_project.full_path,
- 'actions' => ['pull'] }
+ 'actions' => ['pull'],
+ 'meta' => { 'project_path' => public_project.full_path } }
]
end
end
@@ -1258,4 +1268,29 @@ RSpec.shared_examples 'a container registry auth service' do
end
end
end
+
+ context 'with a project with a path containing special characters' do
+ let_it_be(:bad_project) { create(:project) }
+
+ before do
+ bad_project.update_attribute(:path, "#{bad_project.path}_")
+ end
+
+ describe '#access_token' do
+ let(:token) { described_class.access_token(['pull'], [bad_project.full_path]) }
+ let(:access) do
+ [{ 'type' => 'repository',
+ 'name' => bad_project.full_path,
+ 'actions' => ['pull'] }]
+ end
+
+ subject { { token: token } }
+
+ it_behaves_like 'a valid token'
+
+ it 'has the correct scope' do
+ expect(payload).to include('access' => access)
+ end
+ end
+ end
end