summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab/ci/docs.gitlab-ci.yml3
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.checksum2
-rw-r--r--Gemfile.lock4
-rw-r--r--app/assets/javascripts/boards/components/board_card_inner.vue4
-rw-r--r--app/assets/javascripts/ci/runner/admin_new_runner/admin_new_runner_app.vue19
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_form_fields.vue140
-rw-r--r--app/assets/javascripts/ci/runner/constants.js2
-rw-r--r--app/assets/stylesheets/framework/files.scss190
-rw-r--r--app/assets/stylesheets/page_bundles/boards.scss10
-rw-r--r--app/controllers/concerns/issuable_actions.rb12
-rw-r--r--app/controllers/search_controller.rb2
-rw-r--r--app/graphql/mutations/issues/bulk_update.rb28
-rw-r--r--app/graphql/types/permission_types/merge_request.rb5
-rw-r--r--app/services/issuable/bulk_update_service.rb3
-rw-r--r--app/services/protected_branches/cache_service.rb6
-rw-r--r--app/views/projects/blame/_page.html.haml34
-rw-r--r--app/views/projects/blame/show.html.haml46
-rw-r--r--data/deprecations/15-9-license-compliance-ci-template.yml15
-rw-r--r--data/deprecations/15-9-sast-analyzer-consolidation.yml36
-rw-r--r--db/post_migrate/20230214154101_fix_partition_ids_on_ci_sources_pipelines.rb36
-rw-r--r--db/schema_migrations/202302141541011
-rw-r--r--doc/.markdownlint/require_helper.js14
-rw-r--r--doc/.markdownlint/rules/tabs_blank_lines.js7
-rw-r--r--doc/.markdownlint/rules/tabs_title_markup.js3
-rw-r--r--doc/.markdownlint/rules/tabs_title_text.js7
-rw-r--r--doc/api/graphql/reference/index.md4
-rw-r--r--doc/development/database/database_debugging.md18
-rw-r--r--doc/development/documentation/styleguide/word_list.md14
-rw-r--r--doc/update/deprecations.md61
-rw-r--r--doc/user/application_security/iac_scanning/index.md13
-rw-r--r--doc/user/application_security/policies/scan-result-policies.md6
-rw-r--r--doc/user/application_security/sast/index.md16
-rw-r--r--lib/api/namespaces.rb6
-rw-r--r--lib/gitlab/cache/metadata.rb35
-rw-r--r--lib/gitlab/cache/metrics.rb32
-rw-r--r--lib/tasks/lint.rake5
-rw-r--r--locale/gitlab.pot18
-rw-r--r--package.json2
-rwxr-xr-xscripts/lint-doc.sh26
-rw-r--r--spec/controllers/search_controller_spec.rb5
-rw-r--r--spec/features/merge_request/batch_comments_spec.rb3
-rw-r--r--spec/features/projects/files/user_browses_files_spec.rb4
-rw-r--r--spec/frontend/ci/runner/admin_new_runner_app/admin_new_runner_app_spec.js16
-rw-r--r--spec/frontend/ci/runner/components/runner_form_fields_spec.js87
-rw-r--r--spec/graphql/types/permission_types/merge_request_spec.rb2
-rw-r--r--spec/lib/gitlab/cache/metadata_spec.rb94
-rw-r--r--spec/lib/gitlab/cache/metrics_spec.rb24
-rw-r--r--spec/lib/gitlab/github_import/logger_spec.rb12
-rw-r--r--spec/lib/gitlab/import/logger_spec.rb12
-rw-r--r--spec/lib/gitlab/json_logger_spec.rb8
-rw-r--r--spec/migrations/20230214154101_fix_partition_ids_on_ci_sources_pipelines_spec.rb45
-rw-r--r--spec/requests/api/graphql/mutations/issues/bulk_update_spec.rb30
-rw-r--r--spec/requests/api/graphql/project/merge_request_spec.rb3
-rw-r--r--spec/requests/api/namespaces_spec.rb9
-rw-r--r--yarn.lock8
56 files changed, 962 insertions, 287 deletions
diff --git a/.gitlab/ci/docs.gitlab-ci.yml b/.gitlab/ci/docs.gitlab-ci.yml
index f7783cc1d33..b404444f815 100644
--- a/.gitlab/ci/docs.gitlab-ci.yml
+++ b/.gitlab/ci/docs.gitlab-ci.yml
@@ -65,9 +65,12 @@ docs-lint markdown:
- .default-retry
- .docs:rules:docs-lint
- .docs-markdown-lint-image
+ - .yarn-cache
stage: lint
needs: []
script:
+ - source ./scripts/utils.sh
+ - yarn_install_script
- scripts/lint-doc.sh
docs-lint blueprint:
diff --git a/Gemfile b/Gemfile
index 92fec94f8c7..bbda77ae01d 100644
--- a/Gemfile
+++ b/Gemfile
@@ -348,7 +348,7 @@ gem 'pg_query', '~> 2.2', '>= 2.2.1'
gem 'premailer-rails', '~> 1.10.3'
-gem 'gitlab-labkit', '~> 0.31.0'
+gem 'gitlab-labkit', '~> 0.30.1'
gem 'thrift', '>= 0.16.0'
# I18n
diff --git a/Gemfile.checksum b/Gemfile.checksum
index 0351e8d258a..a68b2f221ef 100644
--- a/Gemfile.checksum
+++ b/Gemfile.checksum
@@ -203,7 +203,7 @@
{"name":"gitlab-dangerfiles","version":"3.7.0","platform":"ruby","checksum":"35c5bc42e60c575ab5701192ca2384ab414b14c2963602b39e143b1aaeb7e54d"},
{"name":"gitlab-experiment","version":"0.7.1","platform":"ruby","checksum":"166dddb3aa83428bcaa93c35684ed01dc4d61f321fd2ae40b020806dc54a7824"},
{"name":"gitlab-fog-azure-rm","version":"1.4.0","platform":"ruby","checksum":"af4163c32b028aa5208814a3f4765a5817d50527e6c61931f766bf18a2e0eb7e"},
-{"name":"gitlab-labkit","version":"0.31.0","platform":"ruby","checksum":"5b044c4ededd7005e6d1ca5a53ac5f9d7a4d12a7363673fbc898e1844246ed1f"},
+{"name":"gitlab-labkit","version":"0.30.1","platform":"ruby","checksum":"bdedbd86014c83dfd6a50d20dbc1709697bba2bb9e3666383e5f28cbd312b113"},
{"name":"gitlab-license","version":"2.2.1","platform":"ruby","checksum":"39fcf6be8b2887df8afe01b5dcbae8d08b7c5d937ff56b0fb40484a8c4f02d30"},
{"name":"gitlab-mail_room","version":"0.0.9","platform":"ruby","checksum":"6700374b5c0aa9d9ad4e711aeb677f0b7d415a6d01d3baa699efab25349d851c"},
{"name":"gitlab-markup","version":"1.9.0","platform":"ruby","checksum":"7eda045a08ec2d110084252fa13a8c9eac8bdac0e302035ca7db4b82bcbd7ed4"},
diff --git a/Gemfile.lock b/Gemfile.lock
index c55cc5d2f45..2a5a163dcc5 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -584,7 +584,7 @@ GEM
fog-json (~> 1.2.0)
mime-types
ms_rest_azure (~> 0.12.0)
- gitlab-labkit (0.31.0)
+ gitlab-labkit (0.30.1)
actionpack (>= 5.0.0, < 8.0.0)
activesupport (>= 5.0.0, < 8.0.0)
grpc (>= 1.37)
@@ -1679,7 +1679,7 @@ DEPENDENCIES
gitlab-dangerfiles (~> 3.7.0)
gitlab-experiment (~> 0.7.1)
gitlab-fog-azure-rm (~> 1.4.0)
- gitlab-labkit (~> 0.31.0)
+ gitlab-labkit (~> 0.30.1)
gitlab-license (~> 2.2.1)
gitlab-mail_room (~> 0.0.9)
gitlab-markup (~> 1.9.0)
diff --git a/app/assets/javascripts/boards/components/board_card_inner.vue b/app/assets/javascripts/boards/components/board_card_inner.vue
index 77df111afc1..88f51c71e06 100644
--- a/app/assets/javascripts/boards/components/board_card_inner.vue
+++ b/app/assets/javascripts/boards/components/board_card_inner.vue
@@ -214,7 +214,9 @@ export default {
<template>
<div>
<div class="gl-display-flex" dir="auto">
- <h4 class="board-card-title gl-mb-0 gl-mt-0 gl-mr-3 gl-font-base gl-overflow-break-word">
+ <h4
+ class="board-card-title gl-min-w-0 gl-mb-0 gl-mt-0 gl-mr-3 gl-font-base gl-overflow-break-word"
+ >
<issuable-blocked-icon
v-if="item.blocked"
:item="item"
diff --git a/app/assets/javascripts/ci/runner/admin_new_runner/admin_new_runner_app.vue b/app/assets/javascripts/ci/runner/admin_new_runner/admin_new_runner_app.vue
index db65268166c..5401c7c1c28 100644
--- a/app/assets/javascripts/ci/runner/admin_new_runner/admin_new_runner_app.vue
+++ b/app/assets/javascripts/ci/runner/admin_new_runner/admin_new_runner_app.vue
@@ -2,7 +2,8 @@
import { GlSprintf, GlLink, GlModalDirective } from '@gitlab/ui';
import RunnerInstructionsModal from '~/vue_shared/components/runner_instructions/runner_instructions_modal.vue';
import RunnerPlatformsRadioGroup from '~/ci/runner/components/runner_platforms_radio_group.vue';
-import { DEFAULT_PLATFORM } from '../constants';
+import RunnerFormFields from '~/ci/runner/components/runner_form_fields.vue';
+import { DEFAULT_PLATFORM, DEFAULT_ACCESS_LEVEL } from '../constants';
export default {
name: 'AdminNewRunnerApp',
@@ -11,6 +12,7 @@ export default {
GlSprintf,
RunnerInstructionsModal,
RunnerPlatformsRadioGroup,
+ RunnerFormFields,
},
directives: {
GlModal: GlModalDirective,
@@ -24,6 +26,15 @@ export default {
data() {
return {
platform: DEFAULT_PLATFORM,
+ runner: {
+ description: '',
+ maintenanceNote: '',
+ paused: false,
+ accessLevel: DEFAULT_ACCESS_LEVEL,
+ runUntagged: false,
+ tagList: '',
+ maximumTimeout: ' ',
+ },
};
},
modalId: 'runners-legacy-registration-instructions-modal',
@@ -53,11 +64,15 @@ export default {
</gl-sprintf>
</p>
- <hr />
+ <hr aria-hidden="true" />
<h2 class="gl-font-weight-normal gl-font-lg gl-my-5">
{{ s__('Runners|Platform') }}
</h2>
<runner-platforms-radio-group v-model="platform" />
+
+ <hr aria-hidden="true" />
+
+ <runner-form-fields v-model="runner" />
</div>
</template>
diff --git a/app/assets/javascripts/ci/runner/components/runner_form_fields.vue b/app/assets/javascripts/ci/runner/components/runner_form_fields.vue
new file mode 100644
index 00000000000..e37ac5e6e26
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/runner_form_fields.vue
@@ -0,0 +1,140 @@
+<script>
+import { GlFormGroup, GlFormCheckbox, GlFormInput, GlLink, GlSprintf } from '@gitlab/ui';
+import { helpPagePath } from '~/helpers/help_page_helper';
+import { ACCESS_LEVEL_NOT_PROTECTED, ACCESS_LEVEL_REF_PROTECTED } from '../constants';
+
+export default {
+ name: 'RunnerFormFields',
+ components: {
+ GlFormGroup,
+ GlFormCheckbox,
+ GlFormInput,
+ GlLink,
+ GlSprintf,
+ RunnerMaintenanceNoteField: () =>
+ import('ee_component/ci/runner/components/runner_maintenance_note_field.vue'),
+ },
+ props: {
+ value: {
+ type: Object,
+ default: null,
+ required: false,
+ },
+ },
+ data() {
+ return {
+ model: {
+ ...this.value,
+ },
+ };
+ },
+ watch: {
+ model: {
+ handler() {
+ this.$emit('input', this.model);
+ },
+ deep: true,
+ },
+ },
+ HELP_LABELS_PAGE_PATH: helpPagePath('ci/runners/configure_runners', {
+ anchor: 'use-tags-to-control-which-jobs-a-runner-can-run',
+ }),
+ ACCESS_LEVEL_NOT_PROTECTED,
+ ACCESS_LEVEL_REF_PROTECTED,
+};
+</script>
+<template>
+ <div>
+ <h2 class="gl-font-weight-normal gl-font-lg gl-my-5">
+ {{ s__('Runners|Details') }}
+ {{ __('(optional)') }}
+ </h2>
+ <gl-form-group :label="s__('Runners|Runner description')" label-for="runner-description">
+ <gl-form-input id="runner-description" v-model="model.description" name="description" />
+ </gl-form-group>
+
+ <runner-maintenance-note-field v-model="model.maintenanceNote" class="gl-mt-5" />
+
+ <hr aria-hidden="true" />
+
+ <h2 class="gl-font-weight-normal gl-font-lg gl-my-5">
+ {{ s__('Runners|Configuration') }}
+ {{ __('(optional)') }}
+ </h2>
+
+ <div class="gl-mb-5">
+ <gl-form-checkbox v-model="model.paused" name="paused">
+ {{ __('Paused') }}
+ <template #help>
+ {{ s__('Runners|Stop the runner from accepting new jobs.') }}
+ </template>
+ </gl-form-checkbox>
+
+ <gl-form-checkbox
+ v-model="model.accessLevel"
+ name="protected"
+ :value="$options.ACCESS_LEVEL_REF_PROTECTED"
+ :unchecked-value="$options.ACCESS_LEVEL_NOT_PROTECTED"
+ >
+ {{ __('Protected') }}
+ <template #help>
+ {{ s__('Runners|Use the runner on pipelines for protected branches only.') }}
+ </template>
+ </gl-form-checkbox>
+
+ <gl-form-checkbox v-model="model.runUntagged" name="run-untagged">
+ {{ __('Run untagged jobs') }}
+ <template #help>
+ {{ s__('Runners|Use the runner for jobs without tags in addition to tagged jobs.') }}
+ </template>
+ </gl-form-checkbox>
+ </div>
+
+ <gl-form-group :label="__('Tags')" label-for="runner-tags">
+ <template #description>
+ <gl-sprintf
+ :message="
+ s__('Runners|Multiple tags must be separated by a comma. For example, %{example}.')
+ "
+ >
+ <template #example>
+ <!-- eslint-disable-next-line @gitlab/vue-require-i18n-strings -->
+ <code>macos, shared</code>
+ </template>
+ </gl-sprintf>
+ </template>
+ <template #label-description>
+ <gl-sprintf
+ :message="
+ s__(
+ 'Runners|Add tags for the types of jobs the runner processes to ensure that the runner only runs jobs that you intend it to. %{helpLinkStart}Learn more.%{helpLinkEnd}',
+ )
+ "
+ >
+ <template #helpLink="{ content }">
+ <gl-link :href="$options.HELP_LABELS_PAGE_PATH" target="_blank">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </template>
+ <gl-form-input id="runner-tags" v-model="model.tagList" name="tags" />
+ </gl-form-group>
+
+ <gl-form-group
+ :label="__('Maximum job timeout')"
+ :label-description="
+ s__(
+ 'Runners|Maximum amount of time the runner can run before it terminates. If a project has a shorter job timeout period, the job timeout period of the instance runner is used instead.',
+ )
+ "
+ label-for="runner-max-timeout"
+ :description="s__('Runners|Enter the number of seconds.')"
+ >
+ <gl-form-input
+ id="runner-max-timeout"
+ v-model.number="model.maximumTimeout"
+ name="max-timeout"
+ type="number"
+ />
+ </gl-form-group>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/runner/constants.js b/app/assets/javascripts/ci/runner/constants.js
index ddad456a6dc..318eb7e74bd 100644
--- a/app/assets/javascripts/ci/runner/constants.js
+++ b/app/assets/javascripts/ci/runner/constants.js
@@ -152,6 +152,8 @@ export const JOB_STATUS_IDLE = 'IDLE';
export const ACCESS_LEVEL_NOT_PROTECTED = 'NOT_PROTECTED';
export const ACCESS_LEVEL_REF_PROTECTED = 'REF_PROTECTED';
+export const DEFAULT_ACCESS_LEVEL = ACCESS_LEVEL_NOT_PROTECTED;
+
// CiRunnerSort
export const CREATED_DESC = 'CREATED_DESC';
diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss
index 06c5b26f39b..9ea5a66b3bc 100644
--- a/app/assets/stylesheets/framework/files.scss
+++ b/app/assets/stylesheets/framework/files.scss
@@ -142,106 +142,6 @@
padding: 100px 0;
}
- /**
- * Blame file
- */
- &.blame {
- table {
- border: 0;
- margin: 0;
- }
-
- //
- // IMPORTANT PERFORMANCE OPTIMIZATION
- //
- // When viewinng a blame with many commits a lot of content is rendered on the page.
- // content-visibility rule below ensure that we only render what is visible to the user,
- // thus reducing TBT in the browser.
- // Grid is used instead of table layout because content-visibility performs better with it.
- tr {
- content-visibility: auto;
- display: grid;
- grid-template-columns: 400px max-content auto;
- border-bottom: 1px solid $gray-darker;
-
- &:last-child {
- border-bottom: 0;
- }
- }
-
- td {
- border-top: 0;
- border-bottom: 0;
-
- &:first-child {
- border-left: 0;
- }
-
- &:last-child {
- border-right: 0;
- }
-
- &.blame-commit {
- padding: 5px 10px;
- min-width: 400px;
- max-width: 400px;
- background: $gray-light;
- border-left: 3px solid;
-
- .commit-row-title {
- display: flex;
- }
-
- .item-title {
- flex: 1;
- margin-right: 0.5em;
- }
- }
-
- &.line-numbers {
- float: none;
- border-left: 1px solid $gray-100;
-
- .file-line-num {
- @include gl-min-w-9;
- }
-
- i {
- float: none;
- margin-right: 0;
- }
- }
-
- &.lines {
- padding: 0;
- }
-
- .code {
- height: 100%;
- }
- }
-
- @for $i from 0 through 5 {
- td.blame-commit-age-#{$i} {
- border-left-color: mix($blame-cyan, $blame-blue, $i / 5 * 100%);
- }
- }
-
- @for $i from 1 through 4 {
- td.blame-commit-age-#{$i + 5} {
- border-left-color: mix($blame-gray, $blame-cyan, $i / 4 * 100%);
- }
- }
-
- .doc-versions {
- color: $gray-400;
-
- &:hover {
- color: $gray-900;
- }
- }
- }
-
&.logs {
background: $gray-darker;
max-height: 700px;
@@ -271,14 +171,6 @@
}
}
- /**
- * Code file
- */
- &.code {
- padding: 0;
- border-radius: 0 0 $border-radius-default $border-radius-default;
- }
-
.list-inline.previews {
display: flex;
flex-wrap: wrap;
@@ -606,3 +498,85 @@ span.idiff {
background-color: var(--gray-100, $gray-100);
}
}
+
+.blame-table {
+ margin: 0;
+}
+
+.blame-table-wrapper {
+ overflow-x: auto;
+ min-width: max-content;
+}
+
+.blame {
+ position: relative;
+
+ .tr {
+ display: flex;
+ border-bottom: 1px solid $gray-darker;
+
+ &.last-row {
+ border-bottom: 0;
+ }
+ }
+
+ .blame-commit {
+ padding: 5px 10px;
+ width: 400px;
+ flex: none;
+ background: $gray-light;
+ border-left: 3px solid;
+
+ .commit-row-title {
+ display: flex;
+ }
+
+ .item-title {
+ flex: 1;
+ margin-right: 0.5em;
+ }
+ }
+
+ .lines {
+ flex: 1;
+ }
+
+ .code {
+ height: 100%;
+ }
+
+ @for $i from 0 through 5 {
+ .blame-commit-age-#{$i} {
+ border-left-color: mix($blame-cyan, $blame-blue, $i / 5 * 100%);
+ }
+ }
+
+ @for $i from 1 through 4 {
+ .blame-commit-age-#{$i + 5} {
+ border-left-color: mix($blame-gray, $blame-cyan, $i / 4 * 100%);
+ }
+ }
+
+ .doc-versions {
+ color: $gray-400;
+
+ &:hover {
+ color: $gray-900;
+ }
+ }
+}
+
+.blame.file-content .td.line-numbers {
+ float: none;
+ border-left: 1px solid $gray-100;
+ border-radius: 0;
+
+ .file-line-num {
+ @include gl-min-w-9;
+ }
+}
+
+.code {
+ padding: 0;
+ border-radius: 0 0 $border-radius-default $border-radius-default;
+}
diff --git a/app/assets/stylesheets/page_bundles/boards.scss b/app/assets/stylesheets/page_bundles/boards.scss
index bdbcf7ab58c..99e7f7ae0a4 100644
--- a/app/assets/stylesheets/page_bundles/boards.scss
+++ b/app/assets/stylesheets/page_bundles/boards.scss
@@ -103,13 +103,9 @@
}
}
-.board-card-title {
- width: 95%;
-
- a {
- @include media-breakpoint-down(md) {
- font-size: $gl-font-size-sm;
- }
+.board-card-title a {
+ @include media-breakpoint-down(md) {
+ font-size: $gl-font-size-sm;
}
}
diff --git a/app/controllers/concerns/issuable_actions.rb b/app/controllers/concerns/issuable_actions.rb
index 0ec23a3265f..e1381b4173f 100644
--- a/app/controllers/concerns/issuable_actions.rb
+++ b/app/controllers/concerns/issuable_actions.rb
@@ -252,10 +252,15 @@ module IssuableActions
end
def clean_bulk_update_params(permitted_params)
- assignee_ids = permitted_params[:assignee_ids]
- return permitted_params unless assignee_ids.is_a?(Array) && assignee_ids.compact.empty?
+ permitted_params.delete_if do |k, v|
+ next if k == :issuable_ids
- permitted_params.except(:assignee_ids)
+ if v.is_a?(Array)
+ v.compact.empty?
+ else
+ v.blank?
+ end
+ end
end
def bulk_update_permitted_keys
@@ -263,7 +268,6 @@ module IssuableActions
:issuable_ids,
:assignee_id,
:milestone_id,
- :sprint_id,
:state_event,
:subscription_event,
assignee_ids: [],
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index 5bedf9512e7..1ca34dee3d6 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -24,6 +24,8 @@ class SearchController < ApplicationController
before_action :block_anonymous_global_searches, :check_scope_global_search_enabled, except: :opensearch
skip_before_action :authenticate_user!
+ skip_before_action :default_cache_headers, only: :count
+
requires_cross_project_access if: -> do
search_term_present = params[:search].present? || params[:term].present?
search_term_present && !params[:project_id].present?
diff --git a/app/graphql/mutations/issues/bulk_update.rb b/app/graphql/mutations/issues/bulk_update.rb
index 5d72a9372c9..7f3d5f6ffb2 100644
--- a/app/graphql/mutations/issues/bulk_update.rb
+++ b/app/graphql/mutations/issues/bulk_update.rb
@@ -27,6 +27,10 @@ module Mutations
description: 'Global ID array of the users that will be assigned to the given issues. ' \
'Existing assignees will be replaced with the ones on this list.'
+ argument :milestone_id, ::Types::GlobalIDType[::Milestone],
+ required: false,
+ description: 'Global ID of the milestone that will be assigned to the issues.'
+
field :updated_issue_count, GraphQL::Types::Int,
null: true,
description: 'Number of issues that were successfully updated.'
@@ -71,14 +75,32 @@ module Mutations
def prepared_params(attributes, ids)
prepared = { issuable_ids: model_ids_from(ids).uniq }
- prepared[:assignee_ids] = model_ids_from(attributes[:assignee_ids]) if attributes[:assignee_ids]
- prepared
+ global_id_arguments.each do |argument|
+ next unless attributes.key?(argument)
+
+ prepared[argument] = model_ids_from(attributes[argument])
+ end
+
+ prepared.transform_keys(param_mappings)
+ end
+
+ def param_mappings
+ {}
+ end
+
+ def global_id_arguments
+ %i[assignee_ids milestone_id]
end
def model_ids_from(attributes)
- attributes.map(&:model_id)
+ return if attributes.nil?
+ return attributes.map(&:model_id) if attributes.is_a?(Array)
+
+ attributes.model_id
end
end
end
end
+
+Mutations::Issues::BulkUpdate.prepend_mod
diff --git a/app/graphql/types/permission_types/merge_request.rb b/app/graphql/types/permission_types/merge_request.rb
index 73a2f820f79..88d8c38361a 100644
--- a/app/graphql/types/permission_types/merge_request.rb
+++ b/app/graphql/types/permission_types/merge_request.rb
@@ -21,10 +21,15 @@ module Types
end
permission_field :can_merge, calls_gitaly: true
+ permission_field :can_approve
def can_merge
object.can_be_merged_by?(context[:current_user])
end
+
+ def can_approve
+ object.eligible_for_approval_by?(context[:current_user])
+ end
end
end
end
diff --git a/app/services/issuable/bulk_update_service.rb b/app/services/issuable/bulk_update_service.rb
index 48bfa71ee92..c01509bc4d1 100644
--- a/app/services/issuable/bulk_update_service.rb
+++ b/app/services/issuable/bulk_update_service.rb
@@ -36,7 +36,6 @@ module Issuable
def set_update_params(type)
params.slice!(*permitted_attrs(type))
- params.delete_if { |_, v| !v.is_a?(Array) && v.blank? }
if params[:assignee_ids] == [IssuableFinder::Params::NONE.to_s]
params[:assignee_ids] = []
@@ -46,8 +45,6 @@ module Issuable
def permitted_attrs(type)
attrs = %i(state_event milestone_id add_label_ids remove_label_ids subscription_event)
- attrs.push(:sprint_id) if type == 'issue'
-
if type == 'issue' || type == 'merge_request'
attrs.push(:assignee_ids)
else
diff --git a/app/services/protected_branches/cache_service.rb b/app/services/protected_branches/cache_service.rb
index af8c9ce74bb..4a9fc335421 100644
--- a/app/services/protected_branches/cache_service.rb
+++ b/app/services/protected_branches/cache_service.rb
@@ -81,7 +81,11 @@ module ProtectedBranches
end
def metrics
- @metrics ||= Gitlab::Cache::Metrics.new(
+ @metrics ||= Gitlab::Cache::Metrics.new(cache_metadata)
+ end
+
+ def cache_metadata
+ Gitlab::Cache::Metadata.new(
caller_id: Gitlab::ApplicationContext.current_context_attribute(:caller_id),
cache_identifier: "#{self.class}#fetch",
feature_category: :source_code_management,
diff --git a/app/views/projects/blame/_page.html.haml b/app/views/projects/blame/_page.html.haml
new file mode 100644
index 00000000000..92fb99c30a6
--- /dev/null
+++ b/app/views/projects/blame/_page.html.haml
@@ -0,0 +1,34 @@
+- current_line = @blame.first_line
+
+.file-content.blame.code{ class: user_color_scheme }
+ - groups_length = @blame.groups.size - 1
+ - @blame.groups.each_with_index do |blame_group, index|
+ - commit_data = @blame.commit_data(blame_group[:commit])
+ - line_count = blame_group[:lines].count
+
+ .tr{ class: ('last-row' if groups_length == index) }
+ .td.blame-commit.commit{ class: commit_data.age_map_class }
+ = commit_data.author_avatar
+
+ .commit-row-title
+ %span.item-title.str-truncated-100
+ = commit_data.commit_link
+ = commit_data.project_blame_link
+
+ .light
+ = commit_data.commit_author_link
+ = _('committed')
+ #{commit_data.time_ago_tooltip}
+
+ .td.line-numbers
+ - (current_line...(current_line + line_count)).each do |i|
+ %a.diff-line-num.file-line-num.no-link{ href: "#L#{i}", id: "L#{i}", 'data-line-number' => i }
+ = i
+
+ .td.lines
+ %pre.code.highlight
+ %code
+ - blame_group[:lines].each do |line|
+ #{line}
+
+ - current_line += line_count
diff --git a/app/views/projects/blame/show.html.haml b/app/views/projects/blame/show.html.haml
index dd041377b49..827aa86d61a 100644
--- a/app/views/projects/blame/show.html.haml
+++ b/app/views/projects/blame/show.html.haml
@@ -1,10 +1,11 @@
- page_title _("Blame"), @blob.path, @ref
- add_page_specific_style 'page_bundles/tree'
+- dataset = { testid: 'blob-content-holder', qa_selector: 'blame_file_content', per_page: @blame_per_page }
-#blob-content-holder.tree-holder.js-per-page{ data: { testid: 'blob-content-holder', per_page: @blame_per_page } }
+#blob-content-holder.tree-holder.js-per-page{ data: dataset }
= render "projects/blob/breadcrumb", blob: @blob, blame: true
- .file-holder.gl-overflow-hidden
+ .file-holder
= render "projects/blob/header", blob: @blob, blame: true
.file-blame-legend
@@ -21,44 +22,9 @@
%span.legend-box.legend-box-9
%span.right-label Older
- .table-responsive.file-content.blame.code{ class: "#{user_color_scheme} gl-rounded-0!", data: { qa_selector: 'blame_file_content' } }
- %table
- - current_line = @blame.first_line
- - @blame.groups.each do |blame_group|
- - commit_data = @blame.commit_data(blame_group[:commit])
- - line_count = blame_group[:lines].count
-
- %tr{ style: intrinsic_row_css(line_count) }
- %td.blame-commit{ class: commit_data.age_map_class }
- .commit
- = commit_data.author_avatar
-
- .commit-row-title
- %span.item-title.str-truncated-100
- = commit_data.commit_link
- %span
- = commit_data.project_blame_link
- &nbsp;
-
- .light
- = commit_data.commit_author_link
- = _('committed')
- #{commit_data.time_ago_tooltip}
-
- %td.line-numbers
- - (current_line...(current_line + line_count)).each do |i|
- %a.diff-line-num.gl-justify-content-end{ href: "#L#{i}", id: "L#{i}", 'data-line-number' => i, class: "gl-display-flex!" }
- .file-line-num
- = i
- \
-
- %td.lines.gl-w-full
- %pre.code.highlight
- %code
- - blame_group[:lines].each do |line|
- #{line}
-
- - current_line += line_count
+ .table-responsive.blame-table{ data: { qa_selector: 'blame_file_content' } }
+ .blame-table-wrapper
+ = render partial: 'page'
- if @blame_pagination && @blame_pagination.total_pages > 1
.gl-display-flex.gl-justify-content-center.gl-flex-direction-column.gl-align-items-center.gl-p-3.gl-bg-gray-50.gl-border-t-solid.gl-border-t-1.gl-border-gray-100
diff --git a/data/deprecations/15-9-license-compliance-ci-template.yml b/data/deprecations/15-9-license-compliance-ci-template.yml
new file mode 100644
index 00000000000..7fd6a348915
--- /dev/null
+++ b/data/deprecations/15-9-license-compliance-ci-template.yml
@@ -0,0 +1,15 @@
+- title: "License Compliance CI Template"
+ announcement_milestone: "15.9"
+ removal_milestone: "16.0"
+ breaking_change: true
+ reporter: sam.white
+ stage: secure
+ issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/387561
+ body: |
+ The GitLab [License Compliance](https://docs.gitlab.com/ee/user/compliance/license_compliance/) CI template is now deprecated and is scheduled for removal in the GitLab 16.0 release. Users who wish to continue using GitLab for License Compliance should remove the License Compliance template from their CI pipeline and add the [Dependency Scanning template](https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#configuration). The Dependency Scanning template is now capable of gathering the required license information so it is no longer necessary to run a separate License Compliance job. The License Compliance CI template should not be removed prior to verifying that the `license_scanning_sbom_scanner` and `package_metadata_synchronization` flags are enabled for the instance and that the instance has been upgraded to a version that supports [the new method of license scanning](https://docs.gitlab.com/ee/user/compliance/license_scanning_of_cyclonedx_files/).
+
+ | CI Pipeline Includes | GitLab <= 15.8 | 15.9 <= GitLab < 16.0 | GitLab >= 16.0 |
+ | ------------- | ------------- | ------------- | ------------- |
+ | Both DS and LS templates | License data from LS job is used | License data from LS job is used | License data from DS job is used |
+ | DS template is included but LS template is not | No license data | License data from DS job is used | License data from DS job is used |
+ | LS template is included but DS template is not | License data from LS job is used | License data from LS job is used | No license data |
diff --git a/data/deprecations/15-9-sast-analyzer-consolidation.yml b/data/deprecations/15-9-sast-analyzer-consolidation.yml
new file mode 100644
index 00000000000..9bbeb36b597
--- /dev/null
+++ b/data/deprecations/15-9-sast-analyzer-consolidation.yml
@@ -0,0 +1,36 @@
+- title: "SAST analyzer coverage changing in GitLab 16.0" # (required) Clearly explain the change, or planned change. For example, "The `confidential` field for a `Note` is deprecated" or "CI/CD job names will be limited to 250 characters."
+ announcement_milestone: "15.9" # (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
+ breaking_change: true # (required) Change to false if this is not a breaking change.
+ reporter: connorgilbert # (required) GitLab username of the person reporting the change
+ 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/390416 # (required) Link to the deprecation issue in GitLab
+ body: | # (required) Do not modify this line, instead modify the lines below.
+ GitLab SAST uses various [analyzers](https://docs.gitlab.com/ee/user/application_security/sast/analyzers/) to scan code for vulnerabilities.
+
+ We're reducing the number of supported analyzers used by default in GitLab SAST.
+ This is part of our long-term strategy to deliver a faster, more consistent user experience across different programming languages.
+
+ Starting in GitLab 16.0, the GitLab SAST CI/CD template will no longer use the following analyzers, and they will enter End of Support status:
+
+ - [Security Code Scan](https://gitlab.com/gitlab-org/security-products/analyzers/security-code-scan) (.NET)
+ - [PHPCS Security Audit](https://gitlab.com/gitlab-org/security-products/analyzers/phpcs-security-audit) (PHP)
+
+ We'll remove these analyzers from the [SAST CI/CD template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml) and replace them with GitLab-supported detection rules and the [Semgrep-based analyzer](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep).
+ Effective immediately, these analyzers will receive only security updates; other routine improvements or updates are not guaranteed.
+ After these analyzers reach End of Support, no further updates will be provided.
+ However, we won't delete container images previously published for these analyzers or remove the ability to run them by using a custom CI/CD pipeline job.
+
+ We will also remove Scala from the scope of the [SpotBugs-based analyzer](https://gitlab.com/gitlab-org/security-products/analyzers/spotbugs) and replace it with the [Semgrep-based analyzer](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep).
+ This change will make it simpler to scan Scala code; compilation will no longer be required.
+ This change will be reflected in the automatic language detection portion of the [GitLab-managed SAST CI/CD template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml).
+ Note that the SpotBugs-based analyzer will continue to cover Groovy and Kotlin.
+
+ If you've already dismissed a vulnerability finding from one of the deprecated analyzers, the replacement attempts to respect your previous dismissal. The system behavior depends on:
+
+ - whether you've excluded the Semgrep-based analyzer from running in the past.
+ - which analyzer first discovered the vulnerabilities shown in the project's Vulnerability Report.
+
+ See [Vulnerability translation documentation](https://docs.gitlab.com/ee/user/application_security/sast/analyzers.html#vulnerability-translation) for further details.
+
+ If you applied customizations to any of the affected analyzers or if you currently disable the Semgrep analyzer in your pipelines, you must take action as detailed in the [deprecation issue for this change](https://gitlab.com/gitlab-org/gitlab/-/issues/390416#breaking-change).
diff --git a/db/post_migrate/20230214154101_fix_partition_ids_on_ci_sources_pipelines.rb b/db/post_migrate/20230214154101_fix_partition_ids_on_ci_sources_pipelines.rb
new file mode 100644
index 00000000000..c05b759c2d0
--- /dev/null
+++ b/db/post_migrate/20230214154101_fix_partition_ids_on_ci_sources_pipelines.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+class FixPartitionIdsOnCiSourcesPipelines < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+ restrict_gitlab_migration gitlab_schema: :gitlab_ci
+
+ BATCH_SIZE = 50
+
+ def up
+ return unless Gitlab.com?
+
+ model = define_batchable_model(:ci_sources_pipelines)
+
+ batch_update_records(model, :partition_id, from: 101, to: 100, source_partition_id: 100)
+ batch_update_records(model, :source_partition_id, from: 101, to: 100)
+ end
+
+ def down
+ # no-op
+ end
+
+ private
+
+ def batch_update_records(model, column, from:, to:, **updates)
+ updates.reverse_merge!(column => to)
+
+ model
+ .where(model.arel_table[column].eq(from))
+ .each_batch(of: BATCH_SIZE) { |batch| update_records(batch, updates) }
+ end
+
+ def update_records(relation, updates)
+ relation.update_all(updates)
+ sleep 0.1
+ end
+end
diff --git a/db/schema_migrations/20230214154101 b/db/schema_migrations/20230214154101
new file mode 100644
index 00000000000..97ea6dfb259
--- /dev/null
+++ b/db/schema_migrations/20230214154101
@@ -0,0 +1 @@
+89f5c87983f2739ad20f1f3f3542aea5cd9373879d399835207028792e1e097c \ No newline at end of file
diff --git a/doc/.markdownlint/require_helper.js b/doc/.markdownlint/require_helper.js
deleted file mode 100644
index 7d06cf67419..00000000000
--- a/doc/.markdownlint/require_helper.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Look up the global node modules directory.
- *
- * Because we install markdownlint packages globally
- * in the Docker image where this runs, we need to
- * provide the path to the global install location
- * when referencing global functions from our own node
- * modules.
- *
- * Image:
- * https://gitlab.com/gitlab-org/gitlab-docs/-/blob/main/dockerfiles/gitlab-docs-lint-markdown.Dockerfile
- */
-const { execSync } = require('child_process');
-module.exports.globalPath = execSync('yarn global dir').toString().trim() + '/node_modules/';
diff --git a/doc/.markdownlint/rules/tabs_blank_lines.js b/doc/.markdownlint/rules/tabs_blank_lines.js
index e0e2c1a0a9b..8a9e9c2434e 100644
--- a/doc/.markdownlint/rules/tabs_blank_lines.js
+++ b/doc/.markdownlint/rules/tabs_blank_lines.js
@@ -1,9 +1,4 @@
-const { globalPath } = require('../require_helper');
-const {
- forEachLine,
- getLineMetadata,
- isBlankLine,
-} = require(`${globalPath}/markdownlint-rule-helpers`);
+const { forEachLine, getLineMetadata, isBlankLine } = require(`markdownlint-rule-helpers`);
module.exports = {
names: ['tabs-blank-lines'],
diff --git a/doc/.markdownlint/rules/tabs_title_markup.js b/doc/.markdownlint/rules/tabs_title_markup.js
index 9c1de1e630d..0461ac8385f 100644
--- a/doc/.markdownlint/rules/tabs_title_markup.js
+++ b/doc/.markdownlint/rules/tabs_title_markup.js
@@ -1,5 +1,4 @@
-const { globalPath } = require('../require_helper');
-const { forEachLine, getLineMetadata } = require(`${globalPath}/markdownlint-rule-helpers`);
+const { forEachLine, getLineMetadata } = require(`markdownlint-rule-helpers`);
module.exports = {
names: ['tabs-title-markup'],
diff --git a/doc/.markdownlint/rules/tabs_title_text.js b/doc/.markdownlint/rules/tabs_title_text.js
index 672aa70f562..beb329231b1 100644
--- a/doc/.markdownlint/rules/tabs_title_text.js
+++ b/doc/.markdownlint/rules/tabs_title_text.js
@@ -1,9 +1,4 @@
-const { globalPath } = require('../require_helper');
-const {
- forEachLine,
- getLineMetadata,
- isBlankLine,
-} = require(`${globalPath}/markdownlint-rule-helpers`);
+const { forEachLine, getLineMetadata, isBlankLine } = require(`markdownlint-rule-helpers`);
module.exports = {
names: ['tabs-title-text'],
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index a2aae23dd65..5c66c98cb0c 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -3652,6 +3652,8 @@ Input type: `IssuesBulkUpdateInput`
| <a id="mutationissuesbulkupdateassigneeids"></a>`assigneeIds` | [`[UserID!]`](#userid) | Global ID array of the users that will be assigned to the given issues. Existing assignees will be replaced with the ones on this list. |
| <a id="mutationissuesbulkupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationissuesbulkupdateids"></a>`ids` | [`[IssueID!]!`](#issueid) | Global ID array of the issues that will be updated. IDs that the user can't update will be ignored. A max of 100 can be provided. |
+| <a id="mutationissuesbulkupdateiterationid"></a>`iterationId` | [`IterationID`](#iterationid) | Global ID of the iteration that will be assigned to the issues. |
+| <a id="mutationissuesbulkupdatemilestoneid"></a>`milestoneId` | [`MilestoneID`](#milestoneid) | Global ID of the milestone that will be assigned to the issues. |
| <a id="mutationissuesbulkupdateparentid"></a>`parentId` | [`IssueParentID!`](#issueparentid) | Global ID of the parent that the bulk update will be scoped to . Example `IssueParentID` are `"gid://gitlab/Project/1"` and `"gid://gitlab/Group/1"`. |
#### Fields
@@ -15656,6 +15658,7 @@ Information relating to rules that must be satisfied to merge this merge request
| <a id="mergerequestapprovalstateapprovalrulesoverwritten"></a>`approvalRulesOverwritten` | [`Boolean`](#boolean) | Indicates if the merge request approval rules are overwritten for the merge request. |
| <a id="mergerequestapprovalstateinvalidapproversrules"></a>`invalidApproversRules` | [`[ApprovalRule!]`](#approvalrule) | List of approval rules that are associated with the merge request, but invalid. |
| <a id="mergerequestapprovalstaterules"></a>`rules` | [`[ApprovalRule!]`](#approvalrule) | List of approval rules associated with the merge request. |
+| <a id="mergerequestapprovalstatesuggestedapprovers"></a>`suggestedApprovers` | [`UserCoreConnection`](#usercoreconnection) | List of suggested approvers. (see [Connections](#connections)) |
### `MergeRequestAssignee`
@@ -16423,6 +16426,7 @@ Check permissions for the current user on a merge request.
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mergerequestpermissionsadminmergerequest"></a>`adminMergeRequest` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_merge_request` on this resource. |
+| <a id="mergerequestpermissionscanapprove"></a>`canApprove` | [`Boolean!`](#boolean) | Indicates the user can perform `can_approve` on this resource. |
| <a id="mergerequestpermissionscanmerge"></a>`canMerge` | [`Boolean!`](#boolean) | Indicates the user can perform `can_merge` on this resource. |
| <a id="mergerequestpermissionscherrypickoncurrentmergerequest"></a>`cherryPickOnCurrentMergeRequest` | [`Boolean!`](#boolean) | Indicates the user can perform `cherry_pick_on_current_merge_request` on this resource. |
| <a id="mergerequestpermissionscreatenote"></a>`createNote` | [`Boolean!`](#boolean) | Indicates the user can perform `create_note` on this resource. |
diff --git a/doc/development/database/database_debugging.md b/doc/development/database/database_debugging.md
index edc35dd95e8..9cc85610e98 100644
--- a/doc/development/database/database_debugging.md
+++ b/doc/development/database/database_debugging.md
@@ -177,3 +177,21 @@ you should set the `SKIP_SCHEMA_VERSION_CHECK` environment variable.
```shell
bundle exec rake db:migrate SKIP_SCHEMA_VERSION_CHECK=true
```
+
+## Performance issues
+
+### Reduce connection overhead with connection pooling
+
+Creating new database connections is not free, and in PostgreSQL specifically, it requires
+forking an entire process to handle each new one. In case a connection lives for a very long time,
+this is no problem. However, forking a process for several small queries can turn out to be costly.
+If left unattended, peaks of new database connections can cause performance degradation,
+or even lead to a complete outage.
+
+A proven solution for instances that deal with surges of small, short-lived database connections
+is to implement [PgBouncer](../../administration/postgresql/pgbouncer.md#pgbouncer-as-part-of-a-fault-tolerant-gitlab-installation) as a connection pooler.
+This pool can be used to hold thousands of connections for almost no overhead. The drawback is the addition of
+a small amount of latency, in exchange for up to more than 90% performance improvement, depending on the usage patterns.
+
+PgBouncer can be fine-tuned to fit different installations. See our documentation on
+[fine-tuning PgBouncer](../../administration/postgresql/pgbouncer.md#fine-tuning) for more information.
diff --git a/doc/development/documentation/styleguide/word_list.md b/doc/development/documentation/styleguide/word_list.md
index 4f8a9334787..e64fd4df7ff 100644
--- a/doc/development/documentation/styleguide/word_list.md
+++ b/doc/development/documentation/styleguide/word_list.md
@@ -316,6 +316,20 @@ Use title case for the GitLab Container Registry.
Do not use **currently** when talking about the product or its features. The documentation describes the product as it is today.
([Vale](../testing.md#vale) rule: [`CurrentStatus.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/CurrentStatus.yml))
+## data
+
+Use **data** as a singular noun.
+
+Use:
+
+- Data is collected.
+- The data shows a performance increase.
+
+Instead of:
+
+- Data are collected.
+- The data show a performance increase.
+
## default branch
Use **default branch** to refer generically to the primary branch in the repository.
diff --git a/doc/update/deprecations.md b/doc/update/deprecations.md
index 461ab73f909..6f0cbf81408 100644
--- a/doc/update/deprecations.md
+++ b/doc/update/deprecations.md
@@ -274,6 +274,26 @@ Update any scripts or bookmarks that reference the legacy URLs. GitLab APIs are
</div>
+<div class="deprecation removal-160 breaking-change">
+
+### License Compliance CI Template
+
+Planned removal: GitLab <span class="removal-milestone">16.0</span> <span class="removal-date"></span>
+
+WARNING:
+This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
+Review the details carefully before upgrading.
+
+The GitLab [License Compliance](https://docs.gitlab.com/ee/user/compliance/license_compliance/) CI template is now deprecated and is scheduled for removal in the GitLab 16.0 release. Users who wish to continue using GitLab for License Compliance should remove the License Compliance template from their CI pipeline and add the [Dependency Scanning template](https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#configuration). The Dependency Scanning template is now capable of gathering the required license information so it is no longer necessary to run a separate License Compliance job. The License Compliance CI template should not be removed prior to verifying that the `license_scanning_sbom_scanner` and `package_metadata_synchronization` flags are enabled for the instance and that the instance has been upgraded to a version that supports [the new method of license scanning](https://docs.gitlab.com/ee/user/compliance/license_scanning_of_cyclonedx_files/).
+
+| CI Pipeline Includes | GitLab <= 15.8 | 15.9 <= GitLab < 16.0 | GitLab >= 16.0 |
+| ------------- | ------------- | ------------- | ------------- |
+| Both DS and LS templates | License data from LS job is used | License data from LS job is used | License data from DS job is used |
+| DS template is included but LS template is not | No license data | License data from DS job is used | License data from DS job is used |
+| LS template is included but DS template is not | License data from LS job is used | License data from LS job is used | No license data |
+
+</div>
+
<div class="deprecation removal-170 breaking-change">
### Load Performance Testing is deprecated
@@ -369,6 +389,47 @@ that is available now. We recommend this alternative solution because it provide
<div class="deprecation removal-160 breaking-change">
+### SAST analyzer coverage changing in GitLab 16.0
+
+Planned removal: GitLab <span class="removal-milestone">16.0</span> <span class="removal-date"></span>
+
+WARNING:
+This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
+Review the details carefully before upgrading.
+
+GitLab SAST uses various [analyzers](https://docs.gitlab.com/ee/user/application_security/sast/analyzers/) to scan code for vulnerabilities.
+
+We're reducing the number of supported analyzers used by default in GitLab SAST.
+This is part of our long-term strategy to deliver a faster, more consistent user experience across different programming languages.
+
+Starting in GitLab 16.0, the GitLab SAST CI/CD template will no longer use the following analyzers, and they will enter End of Support status:
+
+- [Security Code Scan](https://gitlab.com/gitlab-org/security-products/analyzers/security-code-scan) (.NET)
+- [PHPCS Security Audit](https://gitlab.com/gitlab-org/security-products/analyzers/phpcs-security-audit) (PHP)
+
+We'll remove these analyzers from the [SAST CI/CD template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml) and replace them with GitLab-supported detection rules and the [Semgrep-based analyzer](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep).
+Effective immediately, these analyzers will receive only security updates; other routine improvements or updates are not guaranteed.
+After these analyzers reach End of Support, no further updates will be provided.
+However, we won't delete container images previously published for these analyzers or remove the ability to run them by using a custom CI/CD pipeline job.
+
+We will also remove Scala from the scope of the [SpotBugs-based analyzer](https://gitlab.com/gitlab-org/security-products/analyzers/spotbugs) and replace it with the [Semgrep-based analyzer](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep).
+This change will make it simpler to scan Scala code; compilation will no longer be required.
+This change will be reflected in the automatic language detection portion of the [GitLab-managed SAST CI/CD template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml).
+Note that the SpotBugs-based analyzer will continue to cover Groovy and Kotlin.
+
+If you've already dismissed a vulnerability finding from one of the deprecated analyzers, the replacement attempts to respect your previous dismissal. The system behavior depends on:
+
+- whether you've excluded the Semgrep-based analyzer from running in the past.
+- which analyzer first discovered the vulnerabilities shown in the project's Vulnerability Report.
+
+See [Vulnerability translation documentation](https://docs.gitlab.com/ee/user/application_security/sast/analyzers.html#vulnerability-translation) for further details.
+
+If you applied customizations to any of the affected analyzers or if you currently disable the Semgrep analyzer in your pipelines, you must take action as detailed in the [deprecation issue for this change](https://gitlab.com/gitlab-org/gitlab/-/issues/390416#breaking-change).
+
+</div>
+
+<div class="deprecation removal-160 breaking-change">
+
### Secure analyzers major version update
Planned removal: GitLab <span class="removal-milestone">16.0</span> <span class="removal-date"></span>
diff --git a/doc/user/application_security/iac_scanning/index.md b/doc/user/application_security/iac_scanning/index.md
index 9d464d40868..c2f1257f989 100644
--- a/doc/user/application_security/iac_scanning/index.md
+++ b/doc/user/application_security/iac_scanning/index.md
@@ -241,6 +241,19 @@ kics-iac-sast:
SAST_ANALYZER_IMAGE_TAG: "3.1"
```
+## Automatic vulnerability resolution
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/368284) in GitLab 15.9 [with a project-level flag](../../../administration/feature_flags.md) named `sec_mark_dropped_findings_as_resolved`. Enabled by default on GitLab.com; disabled by default in self-managed. On GitLab.com, [contact Support](https://about.gitlab.com/support/) if you need to disable the flag for your project.
+
+To help you focus on the vulnerabilities that are still relevant, GitLab IaC Scanning automatically [resolves](../vulnerabilities/index.md#vulnerability-status-values) vulnerabilities when:
+
+- You [disable a predefined rule](#disable-predefined-analyzer-rules).
+- We remove a rule from the default ruleset.
+
+The Vulnerability Management system leaves a comment on automatically-resolved vulnerabilities so you still have a historical record of the vulnerability.
+
+If you re-enable the rule later, the findings are reopened for triage.
+
## Reports JSON format
The IaC tool emits a JSON report file in the existing SAST report format. For more information, see the
diff --git a/doc/user/application_security/policies/scan-result-policies.md b/doc/user/application_security/policies/scan-result-policies.md
index a4493c25870..bc74b8bdfb1 100644
--- a/doc/user/application_security/policies/scan-result-policies.md
+++ b/doc/user/application_security/policies/scan-result-policies.md
@@ -83,6 +83,12 @@ This rule enforces the defined actions based on security scan findings.
## `license_finding` rule type
+> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/8092) in GitLab 15.9 [with a flag](../../../administration/feature_flags.md) named `license_scanning_policies`. Disabled by default.
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available, ask an administrator to [enable the feature flag](../../../administration/feature_flags.md) named `license_scanning_policies`.
+On GitLab.com, this feature is not available.
+
This rule enforces the defined actions based on license findings.
| Field | Type | Possible values | Description |
diff --git a/doc/user/application_security/sast/index.md b/doc/user/application_security/sast/index.md
index 90b8a34a9cb..b0d84e4cff9 100644
--- a/doc/user/application_security/sast/index.md
+++ b/doc/user/application_security/sast/index.md
@@ -181,9 +181,23 @@ Support for more languages and analyzers is tracked in [this epic](https://gitla
For more information, see the confidential project `https://gitlab.com/gitlab-org/security-products/post-analyzers/tracking-calculator`. The content of this project is available only to GitLab team members.
+## Automatic vulnerability resolution
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/368284) in GitLab 15.9 [with a project-level flag](../../../administration/feature_flags.md) named `sec_mark_dropped_findings_as_resolved`. Enabled by default on GitLab.com; disabled by default in self-managed. On GitLab.com, [contact Support](https://about.gitlab.com/support/) if you need to disable the flag for your project.
+
+To help you focus on the vulnerabilities that are still relevant, GitLab SAST automatically [resolves](../vulnerabilities/index.md#vulnerability-status-values) vulnerabilities when:
+
+- You [disable a predefined rule](customize_rulesets.md#disable-predefined-rules).
+- We remove a rule from the default ruleset.
+
+Automatic resolution is available only for findings from the [Semgrep-based analyzer](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep).
+The Vulnerability Management system leaves a comment on automatically-resolved vulnerabilities so you still have a historical record of the vulnerability.
+
+If you re-enable the rule later, the findings are reopened for triage.
+
## Supported distributions
-The default scanner images are build off a base Alpine image for size and maintainability.
+The default scanner images are built on a base Alpine image for size and maintainability.
### FIPS-enabled images
diff --git a/lib/api/namespaces.rb b/lib/api/namespaces.rb
index 2b1007e715a..c971f73ccbb 100644
--- a/lib/api/namespaces.rb
+++ b/lib/api/namespaces.rb
@@ -81,13 +81,13 @@ module API
tags NAMESPACES_TAGS
end
params do
- requires :namespace, type: String, desc: "Namespace’s path"
+ requires :id, type: String, desc: "Namespace’s path"
optional :parent_id, type: Integer, desc: 'The ID of the parent namespace. If no ID is specified, only top-level namespaces are considered.'
end
- get ':namespace/exists', requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS, feature_category: :subgroups, urgency: :low do
+ get ':id/exists', requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS, feature_category: :subgroups, urgency: :low do
check_rate_limit!(:namespace_exists, scope: current_user)
- namespace_path = params[:namespace]
+ namespace_path = params[:id]
existing_namespaces_within_the_parent = Namespace.without_project_namespaces.by_parent(params[:parent_id])
exists = existing_namespaces_within_the_parent.filter_by_path(namespace_path).exists?
diff --git a/lib/gitlab/cache/metadata.rb b/lib/gitlab/cache/metadata.rb
new file mode 100644
index 00000000000..d6c89b5b2c3
--- /dev/null
+++ b/lib/gitlab/cache/metadata.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Cache
+ # Value object for cache metadata
+ class Metadata
+ VALID_BACKING_RESOURCES = [:cpu, :database, :gitaly, :memory, :unknown].freeze
+ DEFAULT_BACKING_RESOURCE = :unknown
+
+ def initialize(
+ cache_identifier:,
+ feature_category:,
+ caller_id: Gitlab::ApplicationContext.current_context_attribute(:caller_id),
+ backing_resource: DEFAULT_BACKING_RESOURCE
+ )
+ @cache_identifier = cache_identifier
+ @feature_category = Gitlab::FeatureCategories.default.get!(feature_category)
+ @caller_id = caller_id
+ @backing_resource = fetch_backing_resource!(backing_resource)
+ end
+
+ attr_reader :caller_id, :cache_identifier, :feature_category, :backing_resource
+
+ private
+
+ def fetch_backing_resource!(resource)
+ return resource if VALID_BACKING_RESOURCES.include?(resource)
+
+ raise "Unknown backing resource: #{resource}" if Gitlab.dev_or_test_env?
+
+ DEFAULT_BACKING_RESOURCE
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/cache/metrics.rb b/lib/gitlab/cache/metrics.rb
index 0143052beb1..00d4e6e4d4e 100644
--- a/lib/gitlab/cache/metrics.rb
+++ b/lib/gitlab/cache/metrics.rb
@@ -5,19 +5,9 @@ module Gitlab
module Cache
class Metrics
DEFAULT_BUCKETS = [0, 1, 5].freeze
- VALID_BACKING_RESOURCES = [:cpu, :database, :gitaly, :memory, :unknown].freeze
- DEFAULT_BACKING_RESOURCE = :unknown
- def initialize(
- caller_id:,
- cache_identifier:,
- feature_category: ::Gitlab::FeatureCategories::FEATURE_CATEGORY_DEFAULT,
- backing_resource: DEFAULT_BACKING_RESOURCE
- )
- @caller_id = caller_id
- @cache_identifier = cache_identifier
- @feature_category = Gitlab::FeatureCategories.default.get!(feature_category)
- @backing_resource = fetch_backing_resource!(backing_resource)
+ def initialize(cache_metadata)
+ @cache_metadata = cache_metadata
end
# Increase cache hit counter
@@ -51,7 +41,7 @@ module Gitlab
private
- attr_reader :caller_id, :cache_identifier, :feature_category, :backing_resource
+ attr_reader :cache_metadata
def counter
@counter ||= Gitlab::Metrics.counter(:redis_hit_miss_operations_total, "Hit/miss Redis cache counter")
@@ -68,20 +58,12 @@ module Gitlab
def labels
@labels ||= {
- caller_id: caller_id,
- cache_identifier: cache_identifier,
- feature_category: feature_category,
- backing_resource: backing_resource
+ caller_id: cache_metadata.caller_id,
+ cache_identifier: cache_metadata.cache_identifier,
+ feature_category: cache_metadata.feature_category,
+ backing_resource: cache_metadata.backing_resource
}
end
-
- def fetch_backing_resource!(resource)
- return resource if VALID_BACKING_RESOURCES.include?(resource)
-
- raise "Unknown backing resource: #{resource}" if Gitlab.dev_or_test_env?
-
- DEFAULT_BACKING_RESOURCE
- end
end
end
end
diff --git a/lib/tasks/lint.rake b/lib/tasks/lint.rake
index 62d31803f6e..6e50e417776 100644
--- a/lib/tasks/lint.rake
+++ b/lib/tasks/lint.rake
@@ -34,6 +34,11 @@ unless Rails.env.production?
exit(1)
end
+ desc "GitLab | Lint | Lint docs Markdown files"
+ task :markdown do
+ sh "./scripts/lint-doc.sh"
+ end
+
desc "GitLab | Lint | Run several lint checks"
task :all do
status = 0
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 0fa5287f4ed..c8b63b58559 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -36741,6 +36741,9 @@ msgstr ""
msgid "Runners|Add notes such as the runner owner or what it should be used for."
msgstr ""
+msgid "Runners|Add tags for the types of jobs the runner processes to ensure that the runner only runs jobs that you intend it to. %{helpLinkStart}Learn more.%{helpLinkEnd}"
+msgstr ""
+
msgid "Runners|Administrator"
msgstr ""
@@ -36878,6 +36881,9 @@ msgstr ""
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
msgid "Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project."
msgstr ""
@@ -36938,6 +36944,9 @@ msgstr ""
msgid "Runners|Maintenance note"
msgstr ""
+msgid "Runners|Maximum amount of time the runner can run before it terminates. If a project has a shorter job timeout period, the job timeout period of the instance runner is used instead."
+msgstr ""
+
msgid "Runners|Maximum job timeout"
msgstr ""
@@ -36947,6 +36956,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
msgid "Runners|Name"
msgstr ""
@@ -37093,6 +37105,9 @@ msgstr ""
msgid "Runners|Runner authentication tokens will expire based on a set interval. They will automatically rotate once expired."
msgstr ""
+msgid "Runners|Runner description"
+msgstr ""
+
msgid "Runners|Runner has contacted GitLab within the last %{elapsedTime}"
msgstr ""
@@ -37275,6 +37290,9 @@ msgstr ""
msgid "Runners|Use Group runners when you want all projects in a group to have access to a set of runners."
msgstr ""
+msgid "Runners|Use the runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
msgid "Runners|Use the runner for jobs without tags, in addition to tagged jobs."
msgstr ""
diff --git a/package.json b/package.json
index ebf860be405..7b4eb71fe99 100644
--- a/package.json
+++ b/package.json
@@ -59,7 +59,7 @@
"@gitlab/svgs": "3.20.0",
"@gitlab/ui": "55.2.1",
"@gitlab/visual-review-tools": "1.7.3",
- "@gitlab/web-ide": "0.0.1-dev-20230210211358",
+ "@gitlab/web-ide": "0.0.1-dev-20230216131813",
"@rails/actioncable": "6.1.4-7",
"@rails/ujs": "6.1.4-7",
"@sourcegraph/code-host-integration": "0.0.84",
diff --git a/scripts/lint-doc.sh b/scripts/lint-doc.sh
index 6fb5dfbd6e8..18e7d7d1c1c 100755
--- a/scripts/lint-doc.sh
+++ b/scripts/lint-doc.sh
@@ -119,19 +119,25 @@ else
fi
fi
-function run_locally_or_in_docker() {
+function run_locally_or_in_container() {
local cmd=$1
local args=$2
+ local registry_url="registry.gitlab.com/gitlab-org/gitlab-docs/lint-markdown:alpine-3.16-vale-2.22.0-markdownlint-0.32.2-markdownlint2-0.6.0"
if hash ${cmd} 2>/dev/null
then
$cmd $args
- elif hash docker 2>/dev/null
+ # When using software like Rancher Desktop, both nerdctl and docker binaries are available
+ # but only one is configured. To check which one to use, we need to probe each runtime
+ elif (hash nerdctl 2>/dev/null) && (nerdctl info 2>&1 1>/dev/null)
then
- docker run -t -v ${PWD}:/gitlab -w /gitlab --rm registry.gitlab.com/gitlab-org/gitlab-docs/lint-markdown:alpine-3.16-vale-2.22.0-markdownlint-0.32.2-markdownlint2-0.6.0 ${cmd} ${args}
+ nerdctl run -t -v "${PWD}:/gitlab" -w /gitlab --rm ${registry_url} ${cmd} ${args}
+ elif (hash docker 2>/dev/null) && (docker info 2>&1 1>/dev/null)
+ then
+ docker run -t -v "${PWD}:/gitlab" -w /gitlab --rm ${registry_url} ${cmd} ${args}
else
echo
- echo " ✖ ERROR: '${cmd}' not found. Install '${cmd}' or Docker to proceed." >&2
+ echo " ✖ ERROR: '${cmd}' not found. Install '${cmd}' or a container runtime (Docker/Nerdctl) to proceed." >&2
echo
((ERRORCODE++))
fi
@@ -151,11 +157,19 @@ if [ -z "${MD_DOC_PATH}" ]
then
echo "Merged results pipeline detected, but no markdown files found. Skipping."
else
- run_locally_or_in_docker 'markdownlint' "--config .markdownlint.yml ${MD_DOC_PATH} --rules doc/.markdownlint/rules"
+ yarn markdownlint --config .markdownlint.yml ${MD_DOC_PATH} --rules doc/.markdownlint/rules
+
+ if [ $? -ne 0 ]
+ then
+ echo
+ echo '✖ ERROR: Markdownlint failed with errors.' >&2
+ echo
+ ((ERRORCODE++))
+ fi
fi
echo '=> Linting prose...'
-run_locally_or_in_docker 'vale' "--minAlertLevel error --output=doc/.vale/vale.tmpl ${MD_DOC_PATH}"
+run_locally_or_in_container 'vale' "--minAlertLevel error --output=doc/.vale/vale.tmpl ${MD_DOC_PATH}"
if [ $ERRORCODE -ne 0 ]
then
diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb
index 37fc5a033ba..0f7f4a1910b 100644
--- a/spec/controllers/search_controller_spec.rb
+++ b/spec/controllers/search_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe SearchController do
+RSpec.describe SearchController, feature_category: :global_search do
include ExternalAuthorizationServiceHelpers
context 'authorized user' do
@@ -359,12 +359,13 @@ RSpec.describe SearchController do
end.to raise_error(ActionController::ParameterMissing)
end
- it 'sets private cache control headers' do
+ it 'sets correct cache control headers' do
get :count, params: { search: 'hello', scope: 'projects' }
expect(response).to have_gitlab_http_status(:ok)
expect(response.headers['Cache-Control']).to eq('max-age=60, private')
+ expect(response.headers['Pragma']).to be_nil
end
it 'does NOT blow up if search param is NOT a string' do
diff --git a/spec/features/merge_request/batch_comments_spec.rb b/spec/features/merge_request/batch_comments_spec.rb
index cfa1a1fbbe4..ddbcb04fa80 100644
--- a/spec/features/merge_request/batch_comments_spec.rb
+++ b/spec/features/merge_request/batch_comments_spec.rb
@@ -221,7 +221,8 @@ RSpec.describe 'Merge request > Batch comments', :js, feature_category: :code_re
end
end
- it 'publishes review and unresolves the thread' do
+ it 'publishes review and unresolves the thread',
+ quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/337931' do
expect(active_discussion.resolved?).to eq(true)
wait_for_requests
diff --git a/spec/features/projects/files/user_browses_files_spec.rb b/spec/features/projects/files/user_browses_files_spec.rb
index c797fd85555..8082d1bdf63 100644
--- a/spec/features/projects/files/user_browses_files_spec.rb
+++ b/spec/features/projects/files/user_browses_files_spec.rb
@@ -338,8 +338,8 @@ RSpec.describe "User browses files", :js, feature_category: :projects do
.and have_content("Initial commit")
.and have_content("Ignore DS files")
- previous_commit_anchor = "//a[@title='Ignore DS files']/parent::span/following-sibling::span/a"
- find(:xpath, previous_commit_anchor).click
+ previous_commit_link = find('.tr', text: "Ignore DS files").find("[aria-label='View blame prior to this change']")
+ previous_commit_link.click
expect(page).to have_content("*.rb")
.and have_content("Dmitriy Zaporozhets")
diff --git a/spec/frontend/ci/runner/admin_new_runner_app/admin_new_runner_app_spec.js b/spec/frontend/ci/runner/admin_new_runner_app/admin_new_runner_app_spec.js
index 9c254f43504..edf3d1706cc 100644
--- a/spec/frontend/ci/runner/admin_new_runner_app/admin_new_runner_app_spec.js
+++ b/spec/frontend/ci/runner/admin_new_runner_app/admin_new_runner_app_spec.js
@@ -7,6 +7,7 @@ import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import AdminNewRunnerApp from '~/ci/runner/admin_new_runner/admin_new_runner_app.vue';
import RunnerInstructionsModal from '~/vue_shared/components/runner_instructions/runner_instructions_modal.vue';
import RunnerPlatformsRadioGroup from '~/ci/runner/components/runner_platforms_radio_group.vue';
+import RunnerFormFields from '~/ci/runner/components/runner_form_fields.vue';
import { DEFAULT_PLATFORM } from '~/ci/runner/constants';
const mockLegacyRegistrationToken = 'LEGACY_REGISTRATION_TOKEN';
@@ -19,6 +20,7 @@ describe('AdminNewRunnerApp', () => {
const findLegacyInstructionsLink = () => wrapper.findByTestId('legacy-instructions-link');
const findRunnerInstructionsModal = () => wrapper.findComponent(RunnerInstructionsModal);
const findRunnerPlatformsRadioGroup = () => wrapper.findComponent(RunnerPlatformsRadioGroup);
+ const findRunnerFormFields = () => wrapper.findComponent(RunnerFormFields);
const createComponent = ({ props = {}, mountFn = shallowMountExtended, ...options } = {}) => {
wrapper = mountFn(AdminNewRunnerApp, {
@@ -60,5 +62,19 @@ describe('AdminNewRunnerApp', () => {
expect(findRunnerPlatformsRadioGroup().props('value')).toBe(DEFAULT_PLATFORM);
});
});
+
+ describe('Runner', () => {
+ it('shows the runners fields', () => {
+ expect(findRunnerFormFields().props('value')).toEqual({
+ accessLevel: 'NOT_PROTECTED',
+ paused: false,
+ description: '',
+ maintenanceNote: '',
+ maximumTimeout: ' ',
+ runUntagged: false,
+ tagList: '',
+ });
+ });
+ });
});
});
diff --git a/spec/frontend/ci/runner/components/runner_form_fields_spec.js b/spec/frontend/ci/runner/components/runner_form_fields_spec.js
new file mode 100644
index 00000000000..5b429645d17
--- /dev/null
+++ b/spec/frontend/ci/runner/components/runner_form_fields_spec.js
@@ -0,0 +1,87 @@
+import { nextTick } from 'vue';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import RunnerFormFields from '~/ci/runner/components/runner_form_fields.vue';
+import { ACCESS_LEVEL_NOT_PROTECTED, ACCESS_LEVEL_REF_PROTECTED } from '~/ci/runner/constants';
+
+const mockDescription = 'My description';
+const mockMaxTimeout = 60;
+const mockTags = 'tag, tag2';
+
+describe('RunnerFormFields', () => {
+ let wrapper;
+
+ const findInput = (name) => wrapper.find(`input[name="${name}"]`);
+
+ const createComponent = ({ runner } = {}) => {
+ wrapper = mountExtended(RunnerFormFields, {
+ propsData: {
+ value: runner,
+ },
+ });
+ };
+
+ it('updates runner fields', async () => {
+ createComponent();
+
+ expect(wrapper.emitted('input')).toBe(undefined);
+
+ findInput('description').setValue(mockDescription);
+ findInput('max-timeout').setValue(mockMaxTimeout);
+ findInput('paused').setChecked(true);
+ findInput('protected').setChecked(true);
+ findInput('run-untagged').setChecked(true);
+ findInput('tags').setValue(mockTags);
+
+ await nextTick();
+
+ expect(wrapper.emitted('input')[0][0]).toMatchObject({
+ description: mockDescription,
+ maximumTimeout: mockMaxTimeout,
+ tagList: mockTags,
+ });
+ });
+
+ it('checks checkbox fields', async () => {
+ createComponent({
+ runner: {
+ paused: false,
+ accessLevel: ACCESS_LEVEL_NOT_PROTECTED,
+ runUntagged: false,
+ },
+ });
+
+ findInput('paused').setChecked(true);
+ findInput('protected').setChecked(true);
+ findInput('run-untagged').setChecked(true);
+
+ await nextTick();
+
+ expect(wrapper.emitted('input')[0][0]).toEqual({
+ paused: true,
+ accessLevel: ACCESS_LEVEL_REF_PROTECTED,
+ runUntagged: true,
+ });
+ });
+
+ it('unchecks checkbox fields', async () => {
+ createComponent({
+ runner: {
+ paused: true,
+ accessLevel: ACCESS_LEVEL_REF_PROTECTED,
+ runUntagged: true,
+ },
+ });
+
+ findInput('paused').setChecked(false);
+ findInput('protected').setChecked(false);
+ findInput('run-untagged').setChecked(false);
+
+ await nextTick();
+
+ expect(wrapper.emitted('input')[0][0]).toEqual({
+ paused: false,
+ accessLevel: ACCESS_LEVEL_NOT_PROTECTED,
+ runUntagged: false,
+ });
+ });
+});
diff --git a/spec/graphql/types/permission_types/merge_request_spec.rb b/spec/graphql/types/permission_types/merge_request_spec.rb
index 2849dead9a8..2c5da9a933c 100644
--- a/spec/graphql/types/permission_types/merge_request_spec.rb
+++ b/spec/graphql/types/permission_types/merge_request_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe Types::PermissionTypes::MergeRequest do
:read_merge_request, :admin_merge_request, :update_merge_request,
:create_note, :push_to_source_branch, :remove_source_branch,
:cherry_pick_on_current_merge_request, :revert_on_current_merge_request,
- :can_merge
+ :can_merge, :can_approve
]
expect(described_class).to have_graphql_fields(expected_permissions)
diff --git a/spec/lib/gitlab/cache/metadata_spec.rb b/spec/lib/gitlab/cache/metadata_spec.rb
new file mode 100644
index 00000000000..2e8af7a9c44
--- /dev/null
+++ b/spec/lib/gitlab/cache/metadata_spec.rb
@@ -0,0 +1,94 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Cache::Metadata, feature_category: :source_code_management do
+ subject(:attributes) do
+ described_class.new(
+ caller_id: caller_id,
+ cache_identifier: cache_identifier,
+ feature_category: feature_category,
+ backing_resource: backing_resource
+ )
+ end
+
+ let(:caller_id) { 'caller-id' }
+ let(:cache_identifier) { 'ApplicationController#show' }
+ let(:feature_category) { :source_code_management }
+ let(:backing_resource) { :unknown }
+
+ describe '#initialize' do
+ context 'when optional arguments are not set' do
+ before do
+ Gitlab::ApplicationContext.push(caller_id: 'context-id')
+ end
+
+ it 'sets default value for them' do
+ attributes = described_class.new(
+ cache_identifier: cache_identifier,
+ feature_category: feature_category
+ )
+
+ expect(attributes.backing_resource).to eq(:unknown)
+ expect(attributes.caller_id).to eq('context-id')
+ end
+ end
+
+ context 'when invalid feature category is set' do
+ let(:feature_category) { :not_supported }
+
+ it { expect { attributes }.to raise_error(RuntimeError) }
+
+ context 'when on production' do
+ before do
+ allow(Gitlab).to receive(:dev_or_test_env?).and_return(false)
+ end
+
+ it 'does not raise an exception' do
+ expect { attributes }.not_to raise_error
+ expect(attributes.feature_category).to eq('unknown')
+ end
+ end
+ end
+
+ context 'when backing resource is not supported' do
+ let(:backing_resource) { 'foo' }
+
+ it { expect { attributes }.to raise_error(RuntimeError) }
+
+ context 'when on production' do
+ before do
+ allow(Gitlab).to receive(:dev_or_test_env?).and_return(false)
+ end
+
+ it 'does not raise an exception' do
+ expect { attributes }.not_to raise_error
+ end
+ end
+ end
+ end
+
+ describe '#caller_id' do
+ subject { attributes.caller_id }
+
+ it { is_expected.to eq caller_id }
+ end
+
+ describe '#cache_identifier' do
+ subject { attributes.cache_identifier }
+
+ it { is_expected.to eq cache_identifier }
+ end
+
+ describe '#feature_category' do
+ subject { attributes.feature_category }
+
+ it { is_expected.to eq feature_category }
+ end
+
+ describe '#backing_resource' do
+ subject { attributes.backing_resource }
+
+ it { is_expected.to eq backing_resource }
+ end
+end
diff --git a/spec/lib/gitlab/cache/metrics_spec.rb b/spec/lib/gitlab/cache/metrics_spec.rb
index d8103837708..24b274f4209 100644
--- a/spec/lib/gitlab/cache/metrics_spec.rb
+++ b/spec/lib/gitlab/cache/metrics_spec.rb
@@ -3,8 +3,10 @@
require 'spec_helper'
RSpec.describe Gitlab::Cache::Metrics do
- subject(:metrics) do
- described_class.new(
+ subject(:metrics) { described_class.new(metadata) }
+
+ let(:metadata) do
+ Gitlab::Cache::Metadata.new(
caller_id: caller_id,
cache_identifier: cache_identifier,
feature_category: feature_category,
@@ -27,24 +29,6 @@ RSpec.describe Gitlab::Cache::Metrics do
).and_return(counter_mock)
end
- describe '#initialize' do
- context 'when backing resource is not supported' do
- let(:backing_resource) { 'foo' }
-
- it { expect { metrics }.to raise_error(RuntimeError) }
-
- context 'when on production' do
- before do
- allow(Gitlab).to receive(:dev_or_test_env?).and_return(false)
- end
-
- it 'does not raise an exception' do
- expect { metrics }.not_to raise_error
- end
- end
- end
- end
-
describe '#increment_cache_hit' do
subject { metrics.increment_cache_hit }
diff --git a/spec/lib/gitlab/github_import/logger_spec.rb b/spec/lib/gitlab/github_import/logger_spec.rb
index d9ffc03831e..6fd0f5db93e 100644
--- a/spec/lib/gitlab/github_import/logger_spec.rb
+++ b/spec/lib/gitlab/github_import/logger_spec.rb
@@ -8,14 +8,18 @@ RSpec.describe Gitlab::GithubImport::Logger do
let(:now) { Time.zone.now }
describe '#format_message' do
+ before do
+ allow(Labkit::Correlation::CorrelationId).to receive(:current_id).and_return('new-correlation-id')
+ end
+
it 'formats strings' do
output = subject.format_message('INFO', now, 'test', 'Hello world')
- expect(Gitlab::Json.parse(output)).to include({
+ expect(Gitlab::Json.parse(output)).to eq({
'severity' => 'INFO',
'time' => now.utc.iso8601(3),
'message' => 'Hello world',
- 'correlation_id' => an_instance_of(String),
+ 'correlation_id' => 'new-correlation-id',
'feature_category' => 'importers',
'import_type' => 'github'
})
@@ -24,11 +28,11 @@ RSpec.describe Gitlab::GithubImport::Logger do
it 'formats hashes' do
output = subject.format_message('INFO', now, 'test', { hello: 1 })
- expect(Gitlab::Json.parse(output)).to include({
+ expect(Gitlab::Json.parse(output)).to eq({
'severity' => 'INFO',
'time' => now.utc.iso8601(3),
'hello' => 1,
- 'correlation_id' => an_instance_of(String),
+ 'correlation_id' => 'new-correlation-id',
'feature_category' => 'importers',
'import_type' => 'github'
})
diff --git a/spec/lib/gitlab/import/logger_spec.rb b/spec/lib/gitlab/import/logger_spec.rb
index cf5e3a00c31..60978aaa25c 100644
--- a/spec/lib/gitlab/import/logger_spec.rb
+++ b/spec/lib/gitlab/import/logger_spec.rb
@@ -8,14 +8,18 @@ RSpec.describe Gitlab::Import::Logger do
let(:now) { Time.zone.now }
describe '#format_message' do
+ before do
+ allow(Labkit::Correlation::CorrelationId).to receive(:current_id).and_return('new-correlation-id')
+ end
+
it 'formats strings' do
output = subject.format_message('INFO', now, 'test', 'Hello world')
- expect(Gitlab::Json.parse(output)).to include({
+ expect(Gitlab::Json.parse(output)).to eq({
'severity' => 'INFO',
'time' => now.utc.iso8601(3),
'message' => 'Hello world',
- 'correlation_id' => an_instance_of(String),
+ 'correlation_id' => 'new-correlation-id',
'feature_category' => 'importers'
})
end
@@ -23,11 +27,11 @@ RSpec.describe Gitlab::Import::Logger do
it 'formats hashes' do
output = subject.format_message('INFO', now, 'test', { hello: 1 })
- expect(Gitlab::Json.parse(output)).to include({
+ expect(Gitlab::Json.parse(output)).to eq({
'severity' => 'INFO',
'time' => now.utc.iso8601(3),
'hello' => 1,
- 'correlation_id' => an_instance_of(String),
+ 'correlation_id' => 'new-correlation-id',
'feature_category' => 'importers'
})
end
diff --git a/spec/lib/gitlab/json_logger_spec.rb b/spec/lib/gitlab/json_logger_spec.rb
index e975fc1b128..801de357ddc 100644
--- a/spec/lib/gitlab/json_logger_spec.rb
+++ b/spec/lib/gitlab/json_logger_spec.rb
@@ -28,6 +28,10 @@ RSpec.describe Gitlab::JsonLogger do
end
describe '#format_message' do
+ before do
+ allow(Labkit::Correlation::CorrelationId).to receive(:current_id).and_return('new-correlation-id')
+ end
+
it 'formats strings' do
output = subject.format_message('INFO', now, 'test', 'Hello world')
data = Gitlab::Json.parse(output)
@@ -35,7 +39,7 @@ RSpec.describe Gitlab::JsonLogger do
expect(data['severity']).to eq('INFO')
expect(data['time']).to eq(now.utc.iso8601(3))
expect(data['message']).to eq('Hello world')
- expect(data['correlation_id']).to be_an_instance_of(String)
+ expect(data['correlation_id']).to eq('new-correlation-id')
end
it 'formats hashes' do
@@ -46,7 +50,7 @@ RSpec.describe Gitlab::JsonLogger do
expect(data['time']).to eq(now.utc.iso8601(3))
expect(data['hello']).to eq(1)
expect(data['message']).to be_nil
- expect(data['correlation_id']).to be_an_instance_of(String)
+ expect(data['correlation_id']).to eq('new-correlation-id')
end
end
end
diff --git a/spec/migrations/20230214154101_fix_partition_ids_on_ci_sources_pipelines_spec.rb b/spec/migrations/20230214154101_fix_partition_ids_on_ci_sources_pipelines_spec.rb
new file mode 100644
index 00000000000..44031175497
--- /dev/null
+++ b/spec/migrations/20230214154101_fix_partition_ids_on_ci_sources_pipelines_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe FixPartitionIdsOnCiSourcesPipelines, migration: :gitlab_ci, feature_category: :continuous_integration do
+ let(:sources_pipelines) { table(:ci_sources_pipelines, database: :ci) }
+
+ before do
+ sources_pipelines.insert_all!([
+ { partition_id: 100, source_partition_id: 100 },
+ { partition_id: 100, source_partition_id: 101 },
+ { partition_id: 101, source_partition_id: 100 },
+ { partition_id: 101, source_partition_id: 101 }
+ ])
+ end
+
+ describe '#up' do
+ context 'when on sass' do
+ before do
+ allow(Gitlab).to receive(:com?).and_return(true)
+ end
+
+ it 'fixes partition_id and source_partition_id' do
+ expect { migrate! }.not_to raise_error
+
+ expect(sources_pipelines.where(partition_id: 100).count).to eq(4)
+ expect(sources_pipelines.where(partition_id: 101).count).to eq(0)
+ expect(sources_pipelines.where(source_partition_id: 100).count).to eq(4)
+ expect(sources_pipelines.where(source_partition_id: 101).count).to eq(0)
+ end
+ end
+
+ context 'when on self managed' do
+ it 'does not change partition_id or source_partition_id' do
+ expect { migrate! }.not_to raise_error
+
+ expect(sources_pipelines.where(partition_id: 100).count).to eq(2)
+ expect(sources_pipelines.where(partition_id: 100).count).to eq(2)
+ expect(sources_pipelines.where(source_partition_id: 101).count).to eq(2)
+ expect(sources_pipelines.where(source_partition_id: 101).count).to eq(2)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/issues/bulk_update_spec.rb b/spec/requests/api/graphql/mutations/issues/bulk_update_spec.rb
index cb1819653c2..b9c83311908 100644
--- a/spec/requests/api/graphql/mutations/issues/bulk_update_spec.rb
+++ b/spec/requests/api/graphql/mutations/issues/bulk_update_spec.rb
@@ -8,7 +8,8 @@ RSpec.describe 'Bulk update issues', feature_category: :team_planning do
let_it_be(:developer) { create(:user) }
let_it_be(:group) { create(:group).tap { |group| group.add_developer(developer) } }
let_it_be(:project) { create(:project, group: group) }
- let_it_be(:updatable_issues, reload: true) { create_list(:issue, 3, project: project) }
+ let_it_be(:updatable_issues, reload: true) { create_list(:issue, 2, project: project) }
+ let_it_be(:milestone) { create(:milestone, group: group) }
let(:parent) { project }
let(:max_issues) { Mutations::Issues::BulkUpdate::MAX_ISSUES }
@@ -16,7 +17,13 @@ RSpec.describe 'Bulk update issues', feature_category: :team_planning do
let(:mutation_response) { graphql_mutation_response(:issues_bulk_update) }
let(:current_user) { developer }
let(:base_arguments) { { parent_id: parent.to_gid.to_s, ids: updatable_issues.map { |i| i.to_gid.to_s } } }
- let(:additional_arguments) { { assignee_ids: [current_user.to_gid.to_s] } }
+
+ let(:additional_arguments) do
+ {
+ assignee_ids: [current_user.to_gid.to_s],
+ milestone_id: milestone.to_gid.to_s
+ }
+ end
context 'when the `bulk_update_issues_mutation` feature flag is disabled' do
before do
@@ -43,7 +50,7 @@ RSpec.describe 'Bulk update issues', feature_category: :team_planning do
updatable_issues.each(&:reset)
forbidden_issue.reset
- end.to change { updatable_issues.flat_map(&:assignee_ids) }.from([]).to([current_user.id] * 3).and(
+ end.to change { updatable_issues.flat_map(&:assignee_ids) }.from([]).to([current_user.id] * 2).and(
not_change(forbidden_issue, :assignee_ids).from([])
)
@@ -58,7 +65,8 @@ RSpec.describe 'Bulk update issues', feature_category: :team_planning do
expect do
post_graphql_mutation(mutation, current_user: current_user)
updatable_issues.each(&:reload)
- end.to change { updatable_issues.flat_map(&:assignee_ids) }.from([]).to([current_user.id] * 3)
+ end.to change { updatable_issues.flat_map(&:assignee_ids) }.from([]).to([current_user.id] * 2)
+ .and(change { updatable_issues.map(&:milestone_id) }.from([nil] * 2).to([milestone.id] * 2))
expect(mutation_response).to include(
'updatedIssueCount' => updatable_issues.count
@@ -87,7 +95,8 @@ RSpec.describe 'Bulk update issues', feature_category: :team_planning do
expect do
post_graphql_mutation(mutation, current_user: current_user)
updatable_issues.each(&:reload)
- end.to change { updatable_issues.flat_map(&:assignee_ids) }.from([]).to([current_user.id] * 3)
+ end.to change { updatable_issues.flat_map(&:assignee_ids) }.from([]).to([current_user.id] * 2)
+ .and(change { updatable_issues.map(&:milestone_id) }.from([nil] * 2).to([milestone.id] * 2))
expect(mutation_response).to include(
'updatedIssueCount' => updatable_issues.count
@@ -110,18 +119,21 @@ RSpec.describe 'Bulk update issues', feature_category: :team_planning do
end
end
- context 'when removing all assignees' do
- let(:additional_arguments) { { assignee_ids: [] } }
+ context 'when setting arguments to null or none' do
+ let(:additional_arguments) { { assignee_ids: [], milestone_id: nil } }
before do
- updatable_issues.each { |issue| issue.update!(assignees: [current_user]) }
+ updatable_issues.each do |issue|
+ issue.update!(assignees: [current_user], milestone: milestone)
+ end
end
it 'updates all issues' do
expect do
post_graphql_mutation(mutation, current_user: current_user)
updatable_issues.each(&:reload)
- end.to change { updatable_issues.flat_map(&:assignee_ids) }.from([current_user.id] * 3).to([])
+ end.to change { updatable_issues.flat_map(&:assignee_ids) }.from([current_user.id] * 2).to([])
+ .and(change { updatable_issues.map(&:milestone_id) }.from([milestone.id] * 2).to([nil] * 2))
expect(mutation_response).to include(
'updatedIssueCount' => updatable_issues.count
diff --git a/spec/requests/api/graphql/project/merge_request_spec.rb b/spec/requests/api/graphql/project/merge_request_spec.rb
index 6aa96cfc070..76e5d687fd1 100644
--- a/spec/requests/api/graphql/project/merge_request_spec.rb
+++ b/spec/requests/api/graphql/project/merge_request_spec.rb
@@ -193,7 +193,8 @@ RSpec.describe 'getting merge request information nested in a project', feature_
'cherryPickOnCurrentMergeRequest' => false,
'revertOnCurrentMergeRequest' => false,
'updateMergeRequest' => false,
- 'canMerge' => false
+ 'canMerge' => false,
+ 'canApprove' => false
}
post_graphql(query, current_user: current_user)
diff --git a/spec/requests/api/namespaces_spec.rb b/spec/requests/api/namespaces_spec.rb
index 30616964371..44574caf54a 100644
--- a/spec/requests/api/namespaces_spec.rb
+++ b/spec/requests/api/namespaces_spec.rb
@@ -263,6 +263,7 @@ RSpec.describe API::Namespaces, feature_category: :subgroups do
describe 'GET /namespaces/:namespace/exists' do
let_it_be(:namespace1) { create(:group, name: 'Namespace 1', path: 'namespace-1') }
let_it_be(:namespace2) { create(:group, name: 'Namespace 2', path: 'namespace-2') }
+ let_it_be(:namespace_with_dot) { create(:group, name: 'With Dot', path: 'with.dot') }
let_it_be(:namespace1sub) { create(:group, name: 'Sub Namespace 1', path: 'sub-namespace-1', parent: namespace1) }
let_it_be(:namespace2sub) { create(:group, name: 'Sub Namespace 2', path: 'sub-namespace-2', parent: namespace2) }
@@ -301,6 +302,14 @@ RSpec.describe API::Namespaces, feature_category: :subgroups do
expect(response.body).to eq(expected_json)
end
+ it 'supports dot in namespace path' do
+ get api("/namespaces/#{namespace_with_dot.path}/exists", user)
+
+ expected_json = { exists: true, suggests: ["#{namespace_with_dot.path}1"] }.to_json
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response.body).to eq(expected_json)
+ end
+
it 'returns JSON indicating the namespace does not exist without a suggestion' do
get api("/namespaces/non-existing-namespace/exists", user)
diff --git a/yarn.lock b/yarn.lock
index 83cffa6c497..244e5dada65 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1366,10 +1366,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/visual-review-tools/-/visual-review-tools-1.7.3.tgz#9ea641146436da388ffbad25d7f2abe0df52c235"
integrity sha512-NMV++7Ew1FSBDN1xiZaauU9tfeSfgDHcOLpn+8bGpP+O5orUPm2Eu66R5eC5gkjBPaXosNAxNWtriee+aFk4+g==
-"@gitlab/web-ide@0.0.1-dev-20230210211358":
- version "0.0.1-dev-20230210211358"
- resolved "https://registry.yarnpkg.com/@gitlab/web-ide/-/web-ide-0.0.1-dev-20230210211358.tgz#1417d4beec86879aec4e6c13a4ba2ffbd3cb8874"
- integrity sha512-U5Q9Dmb/rkfWqzb0TOpxzSzs1BJ1v2/IOj+8AwL+16CWaQE3Lh/d5XizWULwk29McLtm6H8Em2OZwjOqWZvouA==
+"@gitlab/web-ide@0.0.1-dev-20230216131813":
+ version "0.0.1-dev-20230216131813"
+ resolved "https://registry.yarnpkg.com/@gitlab/web-ide/-/web-ide-0.0.1-dev-20230216131813.tgz#f1c5de4e9bea0a1736296b0e63356ca39c065f54"
+ integrity sha512-eqGh/gol3vnT62Fs2dR1JWfkX/hVDwcJaYT1JkFPtiaTi2hFwvqw7k3uKL3qIiYzL7V22avxwRIkbAZCI7aKbQ==
"@graphql-eslint/eslint-plugin@3.12.0":
version "3.12.0"