summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-05-12 12:08:30 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2022-05-12 12:08:30 +0000
commitcb3b9f9243555b0c26145e2992a9f01f7fa47bf5 (patch)
tree5fea3438f0c21330e2fba8c958cbc505810ab990
parent71d34aac9a0fae0507c265929767422391816b01 (diff)
downloadgitlab-ce-cb3b9f9243555b0c26145e2992a9f01f7fa47bf5.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/ci_secure_files/components/secure_files_list.vue8
-rw-r--r--app/assets/javascripts/clusters_list/components/agent_table.vue2
-rw-r--r--app/assets/javascripts/clusters_list/components/clusters.vue2
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_table.vue2
-rw-r--r--app/assets/javascripts/diffs/components/compare_dropdown_layout.vue7
-rw-r--r--app/assets/javascripts/members/components/table/members_table.vue2
-rw-r--r--app/assets/stylesheets/page_bundles/merge_requests.scss17
-rw-r--r--app/controllers/projects/releases_controller.rb8
-rw-r--r--app/models/ci/secure_file.rb7
-rw-r--r--app/models/event.rb4
-rw-r--r--app/models/merge_request.rb24
-rw-r--r--app/models/wiki.rb40
-rw-r--r--app/models/work_items/type.rb4
-rw-r--r--app/serializers/release_entity.rb9
-rw-r--r--app/services/environments/stop_service.rb4
-rw-r--r--app/views/events/event/_note.html.haml2
-rw-r--r--app/views/projects/_merge_request_merge_checks_settings.html.haml2
-rw-r--r--app/views/projects/_merge_request_merge_options_settings.html.haml2
-rw-r--r--app/views/shared/issuable/_sidebar.html.haml2
-rw-r--r--app/workers/bulk_imports/pipeline_worker.rb10
-rw-r--r--config/feature_flags/development/remove_sha_from_releases_json.yml (renamed from config/feature_flags/development/fix_related_environments_for_merge_requests.yml)10
-rw-r--r--config/feature_flags/undefined/gitaly_replace_wiki_update_page.yml8
-rw-r--r--db/fixtures/development/001_create_base_work_item_types.rb2
-rw-r--r--db/fixtures/production/003_create_base_work_item_types.rb2
-rw-r--r--doc/administration/audit_events.md1
-rw-r--r--doc/api/graphql/reference/index.md17
-rw-r--r--doc/api/secure_files.md5
-rw-r--r--doc/api/status_checks.md6
-rw-r--r--doc/ci/secure_files/index.md2
-rw-r--r--doc/development/ee_features.md24
-rw-r--r--doc/development/index.md2
-rw-r--r--doc/user/application_security/dependency_scanning/index.md22
-rw-r--r--doc/user/group/iterations/index.md22
-rw-r--r--doc/user/packages/pypi_repository/index.md3
-rw-r--r--lib/api/ci/secure_files.rb4
-rw-r--r--lib/api/entities/ci/secure_file.rb1
-rw-r--r--lib/api/helpers/projects_helpers.rb4
-rw-r--r--lib/bulk_imports/common/pipelines/entity_finisher.rb2
-rw-r--r--lib/bulk_imports/groups/pipelines/group_attributes_pipeline.rb2
-rw-r--r--lib/bulk_imports/groups/pipelines/namespace_settings_pipeline.rb2
-rw-r--r--lib/bulk_imports/ndjson_pipeline.rb2
-rw-r--r--lib/bulk_imports/pipeline.rb8
-rw-r--r--lib/bulk_imports/projects/pipelines/project_attributes_pipeline.rb2
-rw-r--r--lib/gitlab/database_importers/work_items/base_type_importer.rb14
-rw-r--r--locale/gitlab.pot28
-rw-r--r--package.json2
-rw-r--r--spec/controllers/projects/releases_controller_spec.rb25
-rw-r--r--spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb12
-rw-r--r--spec/frontend/ci_secure_files/components/secure_files_list_spec.js7
-rw-r--r--spec/lib/bulk_imports/ndjson_pipeline_spec.rb2
-rw-r--r--spec/lib/bulk_imports/pipeline_spec.rb4
-rw-r--r--spec/lib/gitlab/database_importers/work_items/base_type_importer_spec.rb2
-rw-r--r--spec/models/ci/secure_file_spec.rb7
-rw-r--r--spec/models/event_spec.rb30
-rw-r--r--spec/models/merge_request_spec.rb44
-rw-r--r--spec/requests/api/ci/secure_files_spec.rb22
-rw-r--r--spec/serializers/release_serializer_spec.rb4
-rw-r--r--spec/services/environments/stop_service_spec.rb12
-rw-r--r--spec/services/issues/create_service_spec.rb8
-rw-r--r--spec/support/helpers/test_env.rb2
-rw-r--r--spec/support/shared_examples/models/wiki_shared_examples.rb10
-rw-r--r--spec/support/shared_examples/work_item_base_types_importer.rb42
-rw-r--r--spec/workers/bulk_imports/pipeline_worker_spec.rb14
-rw-r--r--workhorse/go.mod1
-rw-r--r--workhorse/internal/git/error.go96
-rw-r--r--workhorse/internal/git/error_test.go80
-rw-r--r--workhorse/internal/git/git-http.go14
-rw-r--r--workhorse/internal/git/receive-pack.go2
-rw-r--r--yarn.lock7
69 files changed, 498 insertions, 304 deletions
diff --git a/app/assets/javascripts/ci_secure_files/components/secure_files_list.vue b/app/assets/javascripts/ci_secure_files/components/secure_files_list.vue
index d70ade36fe9..1283db5c8eb 100644
--- a/app/assets/javascripts/ci_secure_files/components/secure_files_list.vue
+++ b/app/assets/javascripts/ci_secure_files/components/secure_files_list.vue
@@ -41,10 +41,6 @@ export default {
label: __('Filename'),
},
{
- key: 'permissions',
- label: __('Permissions'),
- },
- {
key: 'created_at',
label: __('Uploaded'),
},
@@ -112,10 +108,6 @@ export default {
{{ item.name }}
</template>
- <template #cell(permissions)="{ item }">
- {{ item.permissions }}
- </template>
-
<template #cell(created_at)="{ item }">
<timeago-tooltip :time="item.created_at" />
</template>
diff --git a/app/assets/javascripts/clusters_list/components/agent_table.vue b/app/assets/javascripts/clusters_list/components/agent_table.vue
index 2decdb5307b..b878a6835b2 100644
--- a/app/assets/javascripts/clusters_list/components/agent_table.vue
+++ b/app/assets/javascripts/clusters_list/components/agent_table.vue
@@ -165,8 +165,6 @@ export default {
:items="agentsList"
:fields="fields"
stacked="md"
- head-variant="white"
- thead-class="gl-border-b-solid gl-border-b-2 gl-border-b-gray-100"
class="gl-mb-4!"
data-testid="cluster-agent-list-table"
>
diff --git a/app/assets/javascripts/clusters_list/components/clusters.vue b/app/assets/javascripts/clusters_list/components/clusters.vue
index 02eac5a6268..fb3c8ff66b0 100644
--- a/app/assets/javascripts/clusters_list/components/clusters.vue
+++ b/app/assets/javascripts/clusters_list/components/clusters.vue
@@ -235,8 +235,6 @@ export default {
:fields="fields"
fixed
stacked="md"
- head-variant="white"
- thead-class="gl-border-b-solid gl-border-b-2 gl-border-b-gray-100"
class="qa-clusters-table gl-mb-4!"
data-testid="cluster_list_table"
>
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_table.vue b/app/assets/javascripts/cycle_analytics/components/stage_table.vue
index 6a45969fd1a..e4236968efc 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_table.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_table.vue
@@ -191,9 +191,7 @@ export default {
/>
<gl-table
v-else
- head-variant="white"
stacked="lg"
- thead-class="border-bottom"
show-empty
:sort-by.sync="sort"
:sort-direction.sync="direction"
diff --git a/app/assets/javascripts/diffs/components/compare_dropdown_layout.vue b/app/assets/javascripts/diffs/components/compare_dropdown_layout.vue
index 6c5973b7c28..fd219a7d00f 100644
--- a/app/assets/javascripts/diffs/components/compare_dropdown_layout.vue
+++ b/app/assets/javascripts/diffs/components/compare_dropdown_layout.vue
@@ -24,7 +24,12 @@ export default {
</script>
<template>
- <gl-dropdown :text="selectedVersionName" data-qa-selector="dropdown_content">
+ <gl-dropdown
+ :text="selectedVersionName"
+ data-qa-selector="dropdown_content"
+ size="small"
+ category="tertiary"
+ >
<template v-for="version in versions">
<gl-dropdown-divider v-if="version.addDivider" :key="version.id" />
<gl-dropdown-item
diff --git a/app/assets/javascripts/members/components/table/members_table.vue b/app/assets/javascripts/members/components/table/members_table.vue
index 0b97ce7e33e..14d628e455c 100644
--- a/app/assets/javascripts/members/components/table/members_table.vue
+++ b/app/assets/javascripts/members/components/table/members_table.vue
@@ -232,12 +232,10 @@ export default {
v-bind="tableAttrs.table"
class="members-table"
data-testid="members-table"
- head-variant="white"
stacked="lg"
:fields="filteredAndModifiedFields"
:items="members"
primary-key="id"
- thead-class="border-bottom"
:empty-text="__('No members found')"
show-empty
:tbody-tr-attr="tbodyTrAttr"
diff --git a/app/assets/stylesheets/page_bundles/merge_requests.scss b/app/assets/stylesheets/page_bundles/merge_requests.scss
index bef7ecc8a7e..269ce4042fc 100644
--- a/app/assets/stylesheets/page_bundles/merge_requests.scss
+++ b/app/assets/stylesheets/page_bundles/merge_requests.scss
@@ -702,18 +702,21 @@ $tabs-holder-z-index: 250;
.mr-version-dropdown,
.mr-version-compare-dropdown {
- margin: 0 0.5rem;
+ margin: 0 $gl-spacing-scale-1;
+
+ .dropdown-toggle.gl-button {
+ padding: $gl-spacing-scale-2 2px $gl-spacing-scale-2 $gl-spacing-scale-2;
+ font-weight: $gl-font-weight-bold;
+
+ .gl-button-icon {
+ margin-left: $gl-spacing-scale-1;
+ }
+ }
}
.dropdown-title {
color: var(--gl-text-color, $gl-text-color);
}
-
- // Shortening button height by 1px to make compare-versions
- // header 56px and fit into our 8px design grid
- .btn {
- height: 34px;
- }
}
.mr-section-container .resize-observer > object {
diff --git a/app/controllers/projects/releases_controller.rb b/app/controllers/projects/releases_controller.rb
index 84c763088e5..1dfb71842bd 100644
--- a/app/controllers/projects/releases_controller.rb
+++ b/app/controllers/projects/releases_controller.rb
@@ -17,7 +17,13 @@ class Projects::ReleasesController < Projects::ApplicationController
format.html do
require_non_empty_project
end
- format.json { render json: releases }
+ format.json do
+ if Feature.enabled?(:remove_sha_from_releases_json, project)
+ render json: ReleaseSerializer.new.represent(releases)
+ else
+ render json: releases
+ end
+ end
end
end
diff --git a/app/models/ci/secure_file.rb b/app/models/ci/secure_file.rb
index 6a26a5341aa..9c82e106d6e 100644
--- a/app/models/ci/secure_file.rb
+++ b/app/models/ci/secure_file.rb
@@ -3,8 +3,11 @@
module Ci
class SecureFile < Ci::ApplicationRecord
include FileStoreMounter
+ include IgnorableColumns
include Limitable
+ ignore_column :permissions, remove_with: '15.2', remove_after: '2022-06-22'
+
FILE_SIZE_LIMIT = 5.megabytes.freeze
CHECKSUM_ALGORITHM = 'sha256'
@@ -14,14 +17,12 @@ module Ci
belongs_to :project, optional: false
validates :file, presence: true, file_size: { maximum: FILE_SIZE_LIMIT }
- validates :checksum, :file_store, :name, :permissions, :project_id, presence: true
+ validates :checksum, :file_store, :name, :project_id, presence: true
validates :name, uniqueness: { scope: :project }
after_initialize :generate_key_data
before_validation :assign_checksum
- enum permissions: { read_only: 0, read_write: 1, execute: 2 }
-
default_value_for(:file_store) { Ci::SecureFileUploader.default_store }
mount_file_store_uploader Ci::SecureFileUploader
diff --git a/app/models/event.rb b/app/models/event.rb
index e9a98c06b59..8ae2f61f36d 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -369,6 +369,10 @@ class Event < ApplicationRecord
Event._to_partial_path
end
+ def has_no_project_and_group?
+ project_id.nil? && group_id.nil?
+ end
+
protected
def capability
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 5adc5a656c8..39b5949ea7a 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -1438,30 +1438,8 @@ class MergeRequest < ApplicationRecord
actual_head_pipeline.success?
end
- ##
- # This method is for looking for active environments which created via pipelines for merge requests.
- # Since deployments run on a merge request ref (e.g. `refs/merge-requests/:iid/head`),
- # we cannot look up environments with source branch name.
- def legacy_environments
- return Environment.none unless actual_head_pipeline&.merge_request?
-
- build_for_actual_head_pipeline = Ci::Build.latest.where(pipeline: actual_head_pipeline)
-
- environments = build_for_actual_head_pipeline.joins(:metadata)
- .where.not('ci_builds_metadata.expanded_environment_name' => nil)
- .distinct('ci_builds_metadata.expanded_environment_name')
- .limit(100)
- .pluck(:expanded_environment_name)
-
- Environment.where(project: project, name: environments)
- end
-
def environments_in_head_pipeline(deployment_status: nil)
- if ::Feature.enabled?(:fix_related_environments_for_merge_requests, target_project)
- actual_head_pipeline&.environments_in_self_and_descendants(deployment_status: deployment_status) || Environment.none
- else
- legacy_environments
- end
+ actual_head_pipeline&.environments_in_self_and_descendants(deployment_status: deployment_status) || Environment.none
end
def fetch_ref!
diff --git a/app/models/wiki.rb b/app/models/wiki.rb
index ca1266e50f4..32d70fcd3b7 100644
--- a/app/models/wiki.rb
+++ b/app/models/wiki.rb
@@ -261,36 +261,26 @@ class Wiki
end
def update_page(page, content:, title: nil, format: :markdown, message: nil)
- if Feature.enabled?(:gitaly_replace_wiki_update_page, container, type: :undefined)
- with_valid_format(format) do |default_extension|
- title = title.presence || Pathname(page.path).sub_ext('').to_s
+ with_valid_format(format) do |default_extension|
+ title = title.presence || Pathname(page.path).sub_ext('').to_s
- # If the format is the same we keep the former extension. This check is for formats
- # that can have more than one extension like Markdown (.md, .markdown)
- # If we don't do this we will override the existing extension.
- extension = page.format != format.to_sym ? default_extension : File.extname(page.path).downcase[1..]
+ # If the format is the same we keep the former extension. This check is for formats
+ # that can have more than one extension like Markdown (.md, .markdown)
+ # If we don't do this we will override the existing extension.
+ extension = page.format != format.to_sym ? default_extension : File.extname(page.path).downcase[1..]
- capture_git_error(:updated) do
- repository.update_file(
- user,
- sluggified_full_path(title, extension),
- content,
- previous_path: page.path,
- **multi_commit_options(:updated, message, title))
+ capture_git_error(:updated) do
+ repository.update_file(
+ user,
+ sluggified_full_path(title, extension),
+ content,
+ previous_path: page.path,
+ **multi_commit_options(:updated, message, title))
- after_wiki_activity
+ after_wiki_activity
- true
- end
+ true
end
- else
- commit = commit_details(:updated, message, page.title)
-
- wiki.update_page(page.path, title || page.name, format.to_sym, content, commit)
-
- after_wiki_activity
-
- true
end
end
diff --git a/app/models/work_items/type.rb b/app/models/work_items/type.rb
index e2d38dc9903..0d390fa131d 100644
--- a/app/models/work_items/type.rb
+++ b/app/models/work_items/type.rb
@@ -41,6 +41,10 @@ module WorkItems
scope :by_type, ->(base_type) { where(base_type: base_type) }
def self.default_by_type(type)
+ found_type = find_by(namespace_id: nil, base_type: type)
+ return found_type if found_type
+
+ Gitlab::DatabaseImporters::WorkItems::BaseTypeImporter.upsert_types
find_by(namespace_id: nil, base_type: type)
end
diff --git a/app/serializers/release_entity.rb b/app/serializers/release_entity.rb
index 6777b0f9780..5c3d06b82d3 100644
--- a/app/serializers/release_entity.rb
+++ b/app/serializers/release_entity.rb
@@ -1,6 +1,15 @@
# frozen_string_literal: true
+# TODO: consider removing this entity after https://gitlab.com/gitlab-org/gitlab/-/issues/360631
class ReleaseEntity < Grape::Entity
expose :id
expose :tag # see https://gitlab.com/gitlab-org/gitlab/-/issues/36338
+ expose :name
+ expose :description
+ expose :project_id
+ expose :author_id
+
+ expose :created_at
+ expose :updated_at
+ expose :released_at
end
diff --git a/app/services/environments/stop_service.rb b/app/services/environments/stop_service.rb
index 5a0dca4e35b..54ad94947ff 100644
--- a/app/services/environments/stop_service.rb
+++ b/app/services/environments/stop_service.rb
@@ -19,9 +19,7 @@ module Environments
end
def execute_for_merge_request_pipeline(merge_request)
- if ::Feature.enabled?(:fix_related_environments_for_merge_requests, merge_request.target_project)
- return unless merge_request.actual_head_pipeline&.merge_request?
- end
+ return unless merge_request.actual_head_pipeline&.merge_request?
merge_request.environments_in_head_pipeline(deployment_status: :success).each do |environment|
execute(environment)
diff --git a/app/views/events/event/_note.html.haml b/app/views/events/event/_note.html.haml
index d08c3d5ba41..53c59474d83 100644
--- a/app/views/events/event/_note.html.haml
+++ b/app/views/events/event/_note.html.haml
@@ -1,3 +1,5 @@
+- return if !event.personal_snippet_note? && event.has_no_project_and_group?
+
= icon_for_profile_event(event)
= event_user_info(event)
diff --git a/app/views/projects/_merge_request_merge_checks_settings.html.haml b/app/views/projects/_merge_request_merge_checks_settings.html.haml
index baaa3067c81..3345b3043b8 100644
--- a/app/views/projects/_merge_request_merge_checks_settings.html.haml
+++ b/app/views/projects/_merge_request_merge_checks_settings.html.haml
@@ -13,6 +13,6 @@
help_text: s_('ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline.'),
checkbox_options: { class: 'gl-pl-6' }
= form.gitlab_ui_checkbox_component :only_allow_merge_if_all_discussions_are_resolved,
- s_('ProjectSettings|All discussions must be resolved'),
+ s_('ProjectSettings|All threads must be resolved'),
checkbox_options: { data: { qa_selector: 'allow_merge_if_all_discussions_are_resolved_checkbox' } }
= render_if_exists 'projects/merge_request_merge_checks_jira_enforcement', form: form, project: @project
diff --git a/app/views/projects/_merge_request_merge_options_settings.html.haml b/app/views/projects/_merge_request_merge_options_settings.html.haml
index 8bed8e20b66..e91c001ea3d 100644
--- a/app/views/projects/_merge_request_merge_options_settings.html.haml
+++ b/app/views/projects/_merge_request_merge_options_settings.html.haml
@@ -6,7 +6,7 @@
= render_if_exists 'projects/merge_pipelines_settings', form: form
= render_if_exists 'projects/merge_trains_settings', form: form
= form.gitlab_ui_checkbox_component :resolve_outdated_diff_discussions,
- s_('ProjectSettings|Automatically resolve merge request diff discussions when they become outdated')
+ s_('ProjectSettings|Automatically resolve merge request diff threads when they become outdated')
= form.gitlab_ui_checkbox_component :printing_merge_request_link_enabled,
s_('ProjectSettings|Show link to create or view a merge request when pushing from the command line')
= form.gitlab_ui_checkbox_component :remove_source_branch_after_merge,
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index bb6cc693ad9..25d69a8fc1b 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -90,7 +90,7 @@
.gl-display-flex.gl-align-items-center.gl-justify-content-space-between.gl-mb-2.hide-collapsed
%span.gl-overflow-hidden.gl-text-overflow-ellipsis.gl-white-space-nowrap
= _('Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}').html_safe % { source_branch_open: "<span class='gl-font-monospace' data-testid='ref-name' title='#{html_escape(source_branch)}'>".html_safe, source_branch_close: "</span>".html_safe, source_branch: html_escape(source_branch) }
- = clipboard_button(text: source_branch, title: _('Copy branch name'), placement: "left", boundary: 'viewport')
+ = clipboard_button(text: source_branch, title: _('Copy branch name'), placement: "left", boundary: 'viewport', class: 'btn-clipboard gl-button btn-default-tertiary btn-icon btn-sm js-source-branch-copy')
- if show_forwarding_email
.block
diff --git a/app/workers/bulk_imports/pipeline_worker.rb b/app/workers/bulk_imports/pipeline_worker.rb
index abfa6dc6299..b515f0fa202 100644
--- a/app/workers/bulk_imports/pipeline_worker.rb
+++ b/app/workers/bulk_imports/pipeline_worker.rb
@@ -4,7 +4,7 @@ module BulkImports
class PipelineWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
- NDJSON_PIPELINE_PERFORM_DELAY = 10.seconds
+ FILE_EXTRACTION_PIPELINE_PERFORM_DELAY = 10.seconds
data_consistency :always
feature_category :importers
@@ -46,7 +46,7 @@ module BulkImports
raise(Entity::FailedError, 'Failed entity status')
end
- if ndjson_pipeline?(pipeline_tracker)
+ if file_extraction_pipeline?(pipeline_tracker)
export_status = ExportStatus.new(pipeline_tracker, pipeline_tracker.pipeline_class.relation)
raise(Pipeline::ExpiredError, 'Pipeline timeout') if job_timeout?(pipeline_tracker)
@@ -104,15 +104,15 @@ module BulkImports
@logger ||= Gitlab::Import::Logger.build
end
- def ndjson_pipeline?(pipeline_tracker)
- pipeline_tracker.pipeline_class.ndjson_pipeline?
+ def file_extraction_pipeline?(pipeline_tracker)
+ pipeline_tracker.pipeline_class.file_extraction_pipeline?
end
def job_timeout?(pipeline_tracker)
(Time.zone.now - pipeline_tracker.entity.created_at) > Pipeline::NDJSON_EXPORT_TIMEOUT
end
- def reenqueue(pipeline_tracker, delay: NDJSON_PIPELINE_PERFORM_DELAY)
+ def reenqueue(pipeline_tracker, delay: FILE_EXTRACTION_PIPELINE_PERFORM_DELAY)
self.class.perform_in(
delay,
pipeline_tracker.id,
diff --git a/config/feature_flags/development/fix_related_environments_for_merge_requests.yml b/config/feature_flags/development/remove_sha_from_releases_json.yml
index d958f1d4de0..27b62c62978 100644
--- a/config/feature_flags/development/fix_related_environments_for_merge_requests.yml
+++ b/config/feature_flags/development/remove_sha_from_releases_json.yml
@@ -1,8 +1,8 @@
---
-name: fix_related_environments_for_merge_requests
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/83382
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/356642
-milestone: '14.10'
+name: remove_sha_from_releases_json
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/86233
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/360903
+milestone: '15.0'
type: development
group: group::release
-default_enabled: true
+default_enabled: false
diff --git a/config/feature_flags/undefined/gitaly_replace_wiki_update_page.yml b/config/feature_flags/undefined/gitaly_replace_wiki_update_page.yml
deleted file mode 100644
index 4cc89769420..00000000000
--- a/config/feature_flags/undefined/gitaly_replace_wiki_update_page.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: gitaly_replace_wiki_update_page
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/83833
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/357246
-milestone: '14.10'
-type: undefined
-group: group::editor
-default_enabled: false
diff --git a/db/fixtures/development/001_create_base_work_item_types.rb b/db/fixtures/development/001_create_base_work_item_types.rb
index 7a541ca20b0..8bd43fd9df6 100644
--- a/db/fixtures/development/001_create_base_work_item_types.rb
+++ b/db/fixtures/development/001_create_base_work_item_types.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
Gitlab::Seeder.quiet do
- Gitlab::DatabaseImporters::WorkItems::BaseTypeImporter.import
+ Gitlab::DatabaseImporters::WorkItems::BaseTypeImporter.upsert_types
end
diff --git a/db/fixtures/production/003_create_base_work_item_types.rb b/db/fixtures/production/003_create_base_work_item_types.rb
index 7a541ca20b0..8bd43fd9df6 100644
--- a/db/fixtures/production/003_create_base_work_item_types.rb
+++ b/db/fixtures/production/003_create_base_work_item_types.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
Gitlab::Seeder.quiet do
- Gitlab::DatabaseImporters::WorkItems::BaseTypeImporter.import
+ Gitlab::DatabaseImporters::WorkItems::BaseTypeImporter.upsert_types
end
diff --git a/doc/administration/audit_events.md b/doc/administration/audit_events.md
index 55b826d637c..a948908b157 100644
--- a/doc/administration/audit_events.md
+++ b/doc/administration/audit_events.md
@@ -116,6 +116,7 @@ From there, you can see the following actions:
- Group deploy token was successfully created, revoked, or deleted. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/353452) in GitLab 14.9.
- Failed attempt to create a group deploy token. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/353452) in GitLab 14.9.
- [IP restrictions](../user/group/index.md#restrict-group-access-by-ip-address) changed. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/358986) in GitLab 15.0
+- Changes to push rules. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/227629) in GitLab 15.0.
Group events can also be accessed via the [Group Audit Events API](../api/audit_events.md#group-audit-events)
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 90ec7e35495..ac634a3502f 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -3109,12 +3109,12 @@ Input type: `IterationCadenceCreateInput`
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationiterationcadencecreateactive"></a>`active` | [`Boolean!`](#boolean) | Whether the iteration cadence is active. |
-| <a id="mutationiterationcadencecreateautomatic"></a>`automatic` | [`Boolean!`](#boolean) | Whether the iteration cadence should automatically generate future iterations. |
+| <a id="mutationiterationcadencecreateautomatic"></a>`automatic` | [`Boolean!`](#boolean) | Whether the iteration cadence should automatically generate upcoming iterations. |
| <a id="mutationiterationcadencecreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationiterationcadencecreatedescription"></a>`description` | [`String`](#string) | Description of the iteration cadence. Maximum length is 5000 characters. |
| <a id="mutationiterationcadencecreatedurationinweeks"></a>`durationInWeeks` | [`Int`](#int) | Duration in weeks of the iterations within this cadence. |
| <a id="mutationiterationcadencecreategrouppath"></a>`groupPath` | [`ID!`](#id) | Group where the iteration cadence is created. |
-| <a id="mutationiterationcadencecreateiterationsinadvance"></a>`iterationsInAdvance` | [`Int`](#int) | Future iterations to be created when iteration cadence is set to automatic. |
+| <a id="mutationiterationcadencecreateiterationsinadvance"></a>`iterationsInAdvance` | [`Int`](#int) | Upcoming iterations to be created when iteration cadence is set to automatic. |
| <a id="mutationiterationcadencecreaterollover"></a>`rollOver` | [`Boolean`](#boolean) | Whether the iteration cadence should roll over issues to the next iteration or not. |
| <a id="mutationiterationcadencecreatestartdate"></a>`startDate` | [`Time`](#time) | Timestamp of the iteration cadence start date. |
| <a id="mutationiterationcadencecreatetitle"></a>`title` | [`String`](#string) | Title of the iteration cadence. |
@@ -3155,12 +3155,12 @@ Input type: `IterationCadenceUpdateInput`
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationiterationcadenceupdateactive"></a>`active` | [`Boolean`](#boolean) | Whether the iteration cadence is active. |
-| <a id="mutationiterationcadenceupdateautomatic"></a>`automatic` | [`Boolean`](#boolean) | Whether the iteration cadence should automatically generate future iterations. |
+| <a id="mutationiterationcadenceupdateautomatic"></a>`automatic` | [`Boolean`](#boolean) | Whether the iteration cadence should automatically generate upcoming iterations. |
| <a id="mutationiterationcadenceupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationiterationcadenceupdatedescription"></a>`description` | [`String`](#string) | Description of the iteration cadence. Maximum length is 5000 characters. |
| <a id="mutationiterationcadenceupdatedurationinweeks"></a>`durationInWeeks` | [`Int`](#int) | Duration in weeks of the iterations within this cadence. |
| <a id="mutationiterationcadenceupdateid"></a>`id` | [`IterationsCadenceID!`](#iterationscadenceid) | Global ID of the iteration cadence. |
-| <a id="mutationiterationcadenceupdateiterationsinadvance"></a>`iterationsInAdvance` | [`Int`](#int) | Future iterations to be created when iteration cadence is set to automatic. |
+| <a id="mutationiterationcadenceupdateiterationsinadvance"></a>`iterationsInAdvance` | [`Int`](#int) | Upcoming iterations to be created when iteration cadence is set to automatic. |
| <a id="mutationiterationcadenceupdaterollover"></a>`rollOver` | [`Boolean`](#boolean) | Whether the iteration cadence should roll over issues to the next iteration or not. |
| <a id="mutationiterationcadenceupdatestartdate"></a>`startDate` | [`Time`](#time) | Timestamp of the iteration cadence start date. |
| <a id="mutationiterationcadenceupdatetitle"></a>`title` | [`String`](#string) | Title of the iteration cadence. |
@@ -11313,6 +11313,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| ---- | ---- | ----------- |
| <a id="groupactualrepositorysizelimit"></a>`actualRepositorySizeLimit` | [`Float`](#float) | Size limit for repositories in the namespace in bytes. |
| <a id="groupadditionalpurchasedstoragesize"></a>`additionalPurchasedStorageSize` | [`Float`](#float) | Additional storage purchased for the root namespace in bytes. |
+| <a id="groupallowstalerunnerpruning"></a>`allowStaleRunnerPruning` | [`Boolean!`](#boolean) | Indicates whether to regularly prune stale group runners. Defaults to false. |
| <a id="groupautodevopsenabled"></a>`autoDevopsEnabled` | [`Boolean`](#boolean) | Indicates whether Auto DevOps is enabled for all projects within this group. |
| <a id="groupavatarurl"></a>`avatarUrl` | [`String`](#string) | Avatar URL of the group. |
| <a id="groupcontacts"></a>`contacts` | [`CustomerRelationsContactConnection`](#customerrelationscontactconnection) | Find contacts of this group. (see [Connections](#connections)) |
@@ -11636,7 +11637,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="groupiterationcadencesactive"></a>`active` | [`Boolean`](#boolean) | Whether the iteration cadence is active. |
-| <a id="groupiterationcadencesautomatic"></a>`automatic` | [`Boolean`](#boolean) | Whether the iteration cadence should automatically generate future iterations. |
+| <a id="groupiterationcadencesautomatic"></a>`automatic` | [`Boolean`](#boolean) | Whether the iteration cadence should automatically generate upcoming iterations. |
| <a id="groupiterationcadencesdurationinweeks"></a>`durationInWeeks` | [`Int`](#int) | Duration in weeks of the iterations within this cadence. |
| <a id="groupiterationcadencesid"></a>`id` | [`IterationsCadenceID`](#iterationscadenceid) | Global ID of the iteration cadence to look up. |
| <a id="groupiterationcadencesincludeancestorgroups"></a>`includeAncestorGroups` | [`Boolean`](#boolean) | Whether to include ancestor groups to search iterations cadences in. |
@@ -12373,11 +12374,11 @@ Represents an iteration cadence.
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="iterationcadenceactive"></a>`active` | [`Boolean`](#boolean) | Whether the iteration cadence is active. |
-| <a id="iterationcadenceautomatic"></a>`automatic` | [`Boolean`](#boolean) | Whether the iteration cadence should automatically generate future iterations. |
+| <a id="iterationcadenceautomatic"></a>`automatic` | [`Boolean`](#boolean) | Whether the iteration cadence should automatically generate upcoming iterations. |
| <a id="iterationcadencedescription"></a>`description` | [`String`](#string) | Description of the iteration cadence. Maximum length is 5000 characters. |
| <a id="iterationcadencedurationinweeks"></a>`durationInWeeks` | [`Int`](#int) | Duration in weeks of the iterations within this cadence. |
| <a id="iterationcadenceid"></a>`id` | [`IterationsCadenceID!`](#iterationscadenceid) | Global ID of the iteration cadence. |
-| <a id="iterationcadenceiterationsinadvance"></a>`iterationsInAdvance` | [`Int`](#int) | Future iterations to be created when iteration cadence is set to automatic. |
+| <a id="iterationcadenceiterationsinadvance"></a>`iterationsInAdvance` | [`Int`](#int) | Upcoming iterations to be created when iteration cadence is set to automatic. |
| <a id="iterationcadencerollover"></a>`rollOver` | [`Boolean!`](#boolean) | Whether the iteration cadence should roll over issues to the next iteration or not. |
| <a id="iterationcadencestartdate"></a>`startDate` | [`Time`](#time) | Timestamp of the iteration cadence start date. |
| <a id="iterationcadencetitle"></a>`title` | [`String!`](#string) | Title of the iteration cadence. |
@@ -15008,7 +15009,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="projectiterationcadencesactive"></a>`active` | [`Boolean`](#boolean) | Whether the iteration cadence is active. |
-| <a id="projectiterationcadencesautomatic"></a>`automatic` | [`Boolean`](#boolean) | Whether the iteration cadence should automatically generate future iterations. |
+| <a id="projectiterationcadencesautomatic"></a>`automatic` | [`Boolean`](#boolean) | Whether the iteration cadence should automatically generate upcoming iterations. |
| <a id="projectiterationcadencesdurationinweeks"></a>`durationInWeeks` | [`Int`](#int) | Duration in weeks of the iterations within this cadence. |
| <a id="projectiterationcadencesid"></a>`id` | [`IterationsCadenceID`](#iterationscadenceid) | Global ID of the iteration cadence to look up. |
| <a id="projectiterationcadencesincludeancestorgroups"></a>`includeAncestorGroups` | [`Boolean`](#boolean) | Whether to include ancestor groups to search iterations cadences in. |
diff --git a/doc/api/secure_files.md b/doc/api/secure_files.md
index 1284ac8e81f..3532b5a7aeb 100644
--- a/doc/api/secure_files.md
+++ b/doc/api/secure_files.md
@@ -42,7 +42,6 @@ Example response:
"name": "myfile.jks",
"checksum": "16630b189ab34b2e3504f4758e1054d2e478deda510b2b08cc0ef38d12e80aac",
"checksum_algorithm": "sha256",
- "permissions": "read_only",
"created_at": "2022-02-22T22:22:22.222Z"
},
{
@@ -50,7 +49,6 @@ Example response:
"name": "myotherfile.jks",
"checksum": "16630b189ab34b2e3504f4758e1054d2e478deda510b2b08cc0ef38d12e80aa2",
"checksum_algorithm": "sha256",
- "permissions": "execute",
"created_at": "2022-02-22T22:22:22.222Z"
}
]
@@ -85,7 +83,6 @@ Example response:
"name": "myfile.jks",
"checksum": "16630b189ab34b2e3504f4758e1054d2e478deda510b2b08cc0ef38d12e80aac",
"checksum_algorithm": "sha256",
- "permissions": "read_only",
"created_at": "2022-02-22T22:22:22.222Z"
}
```
@@ -105,7 +102,6 @@ Supported attributes:
| `project_id` | integer/string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. |
| `name` | string | **{check-circle}** Yes | The `name` of the file being uploaded. The file name must be unique within the project. |
| `file` | file | **{check-circle}** Yes | The `file` being uploaded (5 MB limit). |
-| `permissions` | string | **{dotted-circle}** No | The file is created with the specified permissions when created in the CI/CD job. Available types are: `read_only` (default), `read_write`, and `execute`. |
Example request:
@@ -122,7 +118,6 @@ Example response:
"name": "myfile.jks",
"checksum": "16630b189ab34b2e3504f4758e1054d2e478deda510b2b08cc0ef38d12e80aac",
"checksum_algorithm": "sha256",
- "permissions": "read_only",
"created_at": "2022-02-22T22:22:22.222Z"
}
```
diff --git a/doc/api/status_checks.md b/doc/api/status_checks.md
index 42b07119bbc..92e003bf80d 100644
--- a/doc/api/status_checks.md
+++ b/doc/api/status_checks.md
@@ -47,11 +47,7 @@ GET /projects/:id/merge_requests/:merge_request_iid/status_checks
> - Introduced in GitLab 14.9, `passed` status to pass external status checks. Introduced [with a flag](../administration/feature_flags.md) named `status_checks_add_status_field`. Disabled by default.
> - Introduced in GitLab 14.9, `failed` status to fail external status checks. Introduced [with a flag](../administration/feature_flags.md) named `status_checks_add_status_field`. Disabled by default.
> - `pass` status to pass checks is [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/339039) in GitLab 14.9. Replaced with `passed`.
-> - Support for `failed` and `passed` [enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/353836) in GitLab 15.0.
-
-FLAG:
-To remove support for `failed` checks (and `pass` instead of `passed`), ask an administrator to
-[disable the feature flag](../administration/feature_flags.md) named `status_checks_add_status_field`.
+> - Support for `failed` and `passed` [enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/353836) in GitLab 15.0 and feature flag removed.
For a single merge request, use the API to inform GitLab that a merge request has passed a check by an external service.
To set the status of an external check, the personal access token used must belong to a user with at least the Developer role on the target project of the merge request.
diff --git a/doc/ci/secure_files/index.md b/doc/ci/secure_files/index.md
index 3cc38a8b74c..2bf360e69f1 100644
--- a/doc/ci/secure_files/index.md
+++ b/doc/ci/secure_files/index.md
@@ -47,7 +47,6 @@ The response returns all of the metadata for the file you just uploaded. For exa
"name": "myfile.jks",
"checksum": "16630b189ab34b2e3504f4758e1054d2e478deda510b2b08cc0ef38d12e80aac",
"checksum_algorithm": "sha256",
- "permissions": "read_only",
"created_at": "2022-02-22T22:22:22.222Z"
}
```
@@ -71,7 +70,6 @@ The response returns an array of all of the secure files in the project. For exa
"name": "myfile.jks",
"checksum": "16630b189ab34b2e3504f4758e1054d2e478deda510b2b08cc0ef38d12e80aac",
"checksum_algorithm": "sha256",
- "permissions": "read_only",
"created_at": "2022-02-22T22:22:22.222Z"
}]
```
diff --git a/doc/development/ee_features.md b/doc/development/ee_features.md
index 019dbb13599..28cf6d4e1e3 100644
--- a/doc/development/ee_features.md
+++ b/doc/development/ee_features.md
@@ -74,6 +74,30 @@ setting the [`FOSS_ONLY` environment variable](https://gitlab.com/gitlab-org/git
to something that evaluates as `true`. The same works for running tests
(for example `FOSS_ONLY=1 yarn jest`).
+### Running feature specs as CE
+
+When running [feature specs](testing_guide/best_practices.md#system--feature-tests)
+as CE, you should ensure that the edition of backend and frontend match.
+To do so:
+
+1. Set the `FOSS_ONLY=1` environment variable:
+
+ ```shell
+ export FOSS_ONLY=1
+ ```
+
+1. Start GDK:
+
+ ```shell
+ gdk start
+ ```
+
+1. Run feature specs:
+
+ ```shell
+ bin/rspec spec/features/<path_to_your_spec>
+ ```
+
## CI pipelines in a FOSS context
By default, merge request pipelines for development run in an EE-context only. If you are
diff --git a/doc/development/index.md b/doc/development/index.md
index 50a074457e9..3d5ec24d3e2 100644
--- a/doc/development/index.md
+++ b/doc/development/index.md
@@ -21,7 +21,7 @@ For information on using GitLab to work on your own software projects, see the
For information on working with the GitLab APIs, see the [API documentation](../api/index.md).
For information about how to install, configure, update, and upgrade your own
-GitLab instance, see the [administration documentation](../administration/index.md).
+GitLab instance, see the [Administrator documentation](../administration/index.md).
## Get started
diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md
index 0452e63db8b..0cec6750202 100644
--- a/doc/user/application_security/dependency_scanning/index.md
+++ b/doc/user/application_security/dependency_scanning/index.md
@@ -43,17 +43,17 @@ possible, we encourage you to use all of our security scanning tools:
efforts to de-duplicate these findings can be tracked in
[this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/348655).
-The following diagram summarizes which types of dependencies each scanning tool can detect:
-
-| Feature | Dependency Scanning | Container Scanning |
-| ----------------------------------------------------------- | ------------------- | ------------------ |
-| Identify the manifest, lock file, or static file that introduced the dependency | :white_check_mark: | :x: |
-| Development dependencies | :white_check_mark: | :x: |
-| Dependencies in a lock file committed to your repository | :white_check_mark: | :white_check_mark: <sup>1</sup> |
-| Binaries built by Go | :x: | :white_check_mark: <sup>2</sup> |
-| Dynamically-linked language-specific dependencies installed by the Operating System | :x: | :white_check_mark: |
-| Operating system dependencies | :x: | :white_check_mark: |
-| Language-specific dependencies installed on the operating system (not built by your project) | :x: | :white_check_mark: |
+The following table summarizes which types of dependencies each scanning tool can detect:
+
+| Feature | Dependency Scanning | Container Scanning |
+| ----------------------------------------------------------- | ------------------- | ------------------ |
+| Identify the manifest, lock file, or static file that introduced the dependency | **{check-circle}** | **{dotted-circle}** |
+| Development dependencies | **{check-circle}** | **{dotted-circle}** |
+| Dependencies in a lock file committed to your repository | **{check-circle}** | **{check-circle}** <sup>1</sup> |
+| Binaries built by Go | **{dotted-circle}** | **{check-circle}** <sup>2</sup> |
+| Dynamically-linked language-specific dependencies installed by the Operating System | **{dotted-circle}** | **{check-circle}** |
+| Operating system dependencies | **{dotted-circle}** | **{check-circle}** |
+| Language-specific dependencies installed on the operating system (not built by your project) | **{dotted-circle}** | **{check-circle}** |
1. Lock file must be present in the image to be detected.
1. Binary file must be present in the image to be detected.
diff --git a/doc/user/group/iterations/index.md b/doc/user/group/iterations/index.md
index 43dcbdf2996..bacb73f2616 100644
--- a/doc/user/group/iterations/index.md
+++ b/doc/user/group/iterations/index.md
@@ -201,10 +201,10 @@ To create an iteration cadence:
1. Select **New iteration cadence**.
1. Complete the fields.
- Enter the title and description of the iteration cadence.
- - Enter the start date of the iteration cadence. Iterations will be scheduled to
+ - Enter the first iteration start date of the iteration cadence. Iterations will be scheduled to
begin on the same day of the week as the day of the week of the start date.
- From the **Duration** dropdown list, select how many weeks each iteration should last.
- - From the **Future iterations** dropdown list, select how many future iterations should be
+ - From the **Upcoming iterations** dropdown list, select how many upcoming iterations should be
created and maintained by GitLab.
- Optional. To move incomplete issues to the next iteration, select **Roll over issues**.
1. Select **Create cadence**. The cadence list page opens.
@@ -221,14 +221,14 @@ To edit an iteration cadence:
1. On the left sidebar, select **Issues > Iterations**.
1. Select **Edit iteration cadence**.
-When you edit the **Duration**, **Future iterations**, or **Start date** fields,
-only future iterations are affected.
+When you edit the **Duration**, **Upcoming iterations**, or **First iteration start date** fields,
+only upcoming iterations are affected.
-You can edit the start date of a cadence if the cadence has not started yet.
+You can edit the first iteration start date of a cadence if the cadence has not started yet.
-Editing **Future iterations** is a non-destructive action.
-If ten future iterations already exist, changing the number under **Future iterations** to `2`
-doesn't delete the eight existing future iterations.
+Editing **Upcoming iterations** is a non-destructive action.
+If ten upcoming iterations already exist, changing the number under **Upcoming iterations** to `2`
+doesn't delete the eight existing upcoming iterations.
### Delete an iteration cadence
@@ -267,12 +267,12 @@ To upgrade the iteration cadence to use the automation features:
1. On the top bar, select **Menu > Groups** and find your group.
1. On the left sidebar, select **Issues > Iterations**.
1. Select the three-dot menu (**{ellipsis_v}**) > **Edit cadence** for the cadence you want to upgrade.
-1. Complete the required fields **Duration** and **Future iterations**.
+1. Complete the required fields **Duration** and **Upcoming iterations**.
1. Select **Save changes**.
#### Start dates of converted cadences
-The start date of your converted cadence is set to the start date of its
+The first iteration start date of your converted cadence is set to the start date of its
**first** existing iteration.
If you attempt to set a new start date, the conversion fails with an error message.
@@ -283,7 +283,7 @@ GitLab will start scheduling new iterations on the same day of the week as the s
starting from the nearest such day from the current date.
During the conversion process GitLab does not delete or modify existing **ongoing** or
-**closed** iterations. If you have iterations with start dates in the future,
+**closed** iterations. If you have iterations with start dates in the ,
they are updated to fit your cadence settings.
#### Converted cadences example
diff --git a/doc/user/packages/pypi_repository/index.md b/doc/user/packages/pypi_repository/index.md
index 4d46032d229..eee6d55a3ce 100644
--- a/doc/user/packages/pypi_repository/index.md
+++ b/doc/user/packages/pypi_repository/index.md
@@ -325,7 +325,8 @@ python -m twine upload --repository <source_name> dist/<package_file>
### Publishing packages with the same name or version
You cannot publish a package if a package of the same name and version already exists.
-You must delete the existing package first. If you attempt to publish the same package
+You must [delete the existing package](../../packages/package_registry/reduce_package_registry_storage.md#delete-a-package) first.
+If you attempt to publish the same package
more than once, a `400 Bad Request` error occurs.
## Install a PyPI package
diff --git a/lib/api/ci/secure_files.rb b/lib/api/ci/secure_files.rb
index 66e5e8ea5b0..6c7f502b428 100644
--- a/lib/api/ci/secure_files.rb
+++ b/lib/api/ci/secure_files.rb
@@ -62,13 +62,11 @@ module API
params do
requires :name, type: String, desc: 'The name of the file'
requires :file, types: [Rack::Multipart::UploadedFile, ::API::Validations::Types::WorkhorseFile], desc: 'The secure file to be uploaded'
- optional :permissions, type: String, desc: 'The file permissions', default: 'read_only', values: %w[read_only read_write execute]
end
route_setting :authentication, basic_auth_personal_access_token: true, job_token_allowed: true
post ':id/secure_files' do
secure_file = user_project.secure_files.new(
- name: params[:name],
- permissions: params[:permissions] || :read_only
+ name: params[:name]
)
secure_file.file = params[:file]
diff --git a/lib/api/entities/ci/secure_file.rb b/lib/api/entities/ci/secure_file.rb
index b60a1a6ac90..639615e5779 100644
--- a/lib/api/entities/ci/secure_file.rb
+++ b/lib/api/entities/ci/secure_file.rb
@@ -6,7 +6,6 @@ module API
class SecureFile < Grape::Entity
expose :id
expose :name
- expose :permissions
expose :checksum
expose :checksum_algorithm
expose :created_at
diff --git a/lib/api/helpers/projects_helpers.rb b/lib/api/helpers/projects_helpers.rb
index 9a191d98913..7a9dd78e4ed 100644
--- a/lib/api/helpers/projects_helpers.rb
+++ b/lib/api/helpers/projects_helpers.rb
@@ -42,7 +42,7 @@ module API
optional :warn_about_potentially_unwanted_characters, type: Boolean, desc: 'Warn about Potentially Unwanted Characters'
optional :enforce_auth_checks_on_uploads, type: Boolean, desc: 'Enforce auth check on uploads'
optional :shared_runners_enabled, type: Boolean, desc: 'Flag indication if shared runners are enabled for that project'
- optional :resolve_outdated_diff_discussions, type: Boolean, desc: 'Automatically resolve merge request diffs discussions on lines changed with a push'
+ optional :resolve_outdated_diff_discussions, type: Boolean, desc: 'Automatically resolve merge request diff threads on lines changed with a push'
optional :remove_source_branch_after_merge, type: Boolean, desc: 'Remove the source branch by default after merge'
optional :container_registry_enabled, type: Boolean, desc: 'Deprecated: Use :container_registry_access_level instead. Flag indication if the container registry is enabled for that project'
optional :container_expiration_policy_attributes, type: Hash do
@@ -54,7 +54,7 @@ module API
optional :request_access_enabled, type: Boolean, desc: 'Allow users to request member access'
optional :only_allow_merge_if_pipeline_succeeds, type: Boolean, desc: 'Only allow to merge if builds succeed'
optional :allow_merge_on_skipped_pipeline, type: Boolean, desc: 'Allow to merge if pipeline is skipped'
- optional :only_allow_merge_if_all_discussions_are_resolved, type: Boolean, desc: 'Only allow to merge if all discussions are resolved'
+ optional :only_allow_merge_if_all_discussions_are_resolved, type: Boolean, desc: 'Only allow to merge if all threads are resolved'
optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'Deprecated: Use :topics instead'
optional :topics, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The list of topics for a project'
# TODO: remove rubocop disable - https://gitlab.com/gitlab-org/gitlab/issues/14960
diff --git a/lib/bulk_imports/common/pipelines/entity_finisher.rb b/lib/bulk_imports/common/pipelines/entity_finisher.rb
index 0f4def3b17a..915dcf1b455 100644
--- a/lib/bulk_imports/common/pipelines/entity_finisher.rb
+++ b/lib/bulk_imports/common/pipelines/entity_finisher.rb
@@ -4,7 +4,7 @@ module BulkImports
module Common
module Pipelines
class EntityFinisher
- def self.ndjson_pipeline?
+ def self.file_extraction_pipeline?
false
end
diff --git a/lib/bulk_imports/groups/pipelines/group_attributes_pipeline.rb b/lib/bulk_imports/groups/pipelines/group_attributes_pipeline.rb
index 4fd394718d9..d6c6b5d44a8 100644
--- a/lib/bulk_imports/groups/pipelines/group_attributes_pipeline.rb
+++ b/lib/bulk_imports/groups/pipelines/group_attributes_pipeline.rb
@@ -6,7 +6,7 @@ module BulkImports
class GroupAttributesPipeline
include Pipeline
- ndjson_pipeline!
+ file_extraction_pipeline!
relation_name 'self'
diff --git a/lib/bulk_imports/groups/pipelines/namespace_settings_pipeline.rb b/lib/bulk_imports/groups/pipelines/namespace_settings_pipeline.rb
index e67bd8d70a3..1bd6486b413 100644
--- a/lib/bulk_imports/groups/pipelines/namespace_settings_pipeline.rb
+++ b/lib/bulk_imports/groups/pipelines/namespace_settings_pipeline.rb
@@ -6,7 +6,7 @@ module BulkImports
class NamespaceSettingsPipeline
include Pipeline
- ndjson_pipeline!
+ file_extraction_pipeline!
relation_name 'namespace_settings'
diff --git a/lib/bulk_imports/ndjson_pipeline.rb b/lib/bulk_imports/ndjson_pipeline.rb
index d85e51984df..05d724a5e42 100644
--- a/lib/bulk_imports/ndjson_pipeline.rb
+++ b/lib/bulk_imports/ndjson_pipeline.rb
@@ -7,7 +7,7 @@ module BulkImports
include Pipeline
included do
- ndjson_pipeline!
+ file_extraction_pipeline!
def transform(context, data)
return unless data
diff --git a/lib/bulk_imports/pipeline.rb b/lib/bulk_imports/pipeline.rb
index 6798936576b..dc2ebdddd14 100644
--- a/lib/bulk_imports/pipeline.rb
+++ b/lib/bulk_imports/pipeline.rb
@@ -170,12 +170,12 @@ module BulkImports
class_attributes[:abort_on_failure]
end
- def ndjson_pipeline!
- class_attributes[:ndjson_pipeline] = true
+ def file_extraction_pipeline!
+ class_attributes[:file_extraction_pipeline] = true
end
- def ndjson_pipeline?
- class_attributes[:ndjson_pipeline]
+ def file_extraction_pipeline?
+ class_attributes[:file_extraction_pipeline]
end
def relation_name(name)
diff --git a/lib/bulk_imports/projects/pipelines/project_attributes_pipeline.rb b/lib/bulk_imports/projects/pipelines/project_attributes_pipeline.rb
index 2492a023cbe..a187a4821b9 100644
--- a/lib/bulk_imports/projects/pipelines/project_attributes_pipeline.rb
+++ b/lib/bulk_imports/projects/pipelines/project_attributes_pipeline.rb
@@ -6,6 +6,8 @@ module BulkImports
class ProjectAttributesPipeline
include Pipeline
+ file_extraction_pipeline!
+
transformer ::BulkImports::Common::Transformers::ProhibitedAttributesTransformer
def extract(_context)
diff --git a/lib/gitlab/database_importers/work_items/base_type_importer.rb b/lib/gitlab/database_importers/work_items/base_type_importer.rb
index 2d9700cb2bc..1e29ae7761b 100644
--- a/lib/gitlab/database_importers/work_items/base_type_importer.rb
+++ b/lib/gitlab/database_importers/work_items/base_type_importer.rb
@@ -4,10 +4,18 @@ module Gitlab
module DatabaseImporters
module WorkItems
module BaseTypeImporter
- def self.import
- ::WorkItems::Type::BASE_TYPES.each do |type, attributes|
- ::WorkItems::Type.create!(base_type: type, **attributes.slice(:name, :icon_name))
+ def self.upsert_types
+ current_time = Time.current
+
+ base_types = ::WorkItems::Type::BASE_TYPES.map do |type, attributes|
+ attributes.slice(:name, :icon_name)
+ .merge(created_at: current_time, updated_at: current_time, base_type: type)
end
+
+ ::WorkItems::Type.upsert_all(
+ base_types,
+ unique_by: :idx_work_item_types_on_namespace_id_and_name_null_namespace
+ )
end
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index aba871fe1d6..acfa96eacd2 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -5896,6 +5896,9 @@ msgstr ""
msgid "Billings|Extend trial"
msgstr ""
+msgid "Billings|Free groups are limited to %{number} seats."
+msgstr ""
+
msgid "Billings|In a seat"
msgstr ""
@@ -21204,7 +21207,7 @@ msgstr ""
msgid "Iterations"
msgstr ""
-msgid "Iterations|Add a duration, and number of future iterations in order to convert this cadence to automatic scheduling."
+msgid "Iterations|Add a duration, and number of upcoming iterations in order to convert this cadence to automatic scheduling."
msgstr ""
msgid "Iterations|Add iteration"
@@ -21264,7 +21267,7 @@ msgstr ""
msgid "Iterations|Error loading iteration cadences."
msgstr ""
-msgid "Iterations|Future iterations"
+msgid "Iterations|First iteration start date"
msgstr ""
msgid "Iterations|Iteration cadences"
@@ -21279,7 +21282,7 @@ msgstr ""
msgid "Iterations|Learn more about automatic scheduling"
msgstr ""
-msgid "Iterations|Move incomplete issues to the next iteration"
+msgid "Iterations|Move incomplete issues to the next iteration."
msgstr ""
msgid "Iterations|New iteration"
@@ -21300,10 +21303,13 @@ msgstr ""
msgid "Iterations|No iterations in cadence."
msgstr ""
+msgid "Iterations|No one can change this date after the cadence has begun."
+msgstr ""
+
msgid "Iterations|No open iterations."
msgstr ""
-msgid "Iterations|Number of future iterations you would like to have scheduled"
+msgid "Iterations|Number of upcoming iterations that should be scheduled at a time."
msgstr ""
msgid "Iterations|Open"
@@ -21333,13 +21339,13 @@ msgstr ""
msgid "Iterations|Start date"
msgstr ""
-msgid "Iterations|The duration for each iteration (in weeks)"
+msgid "Iterations|The duration of each iteration (in weeks)."
msgstr ""
msgid "Iterations|The iteration has been deleted."
msgstr ""
-msgid "Iterations|The start date of your first iteration"
+msgid "Iterations|The start date of the first iteration determines when your cadence begins."
msgstr ""
msgid "Iterations|This cadence requires an update"
@@ -21363,6 +21369,9 @@ msgstr ""
msgid "Iterations|Unable to save cadence. Please try again."
msgstr ""
+msgid "Iterations|Upcoming iterations"
+msgstr ""
+
msgid "Iteration|Dates cannot overlap with other existing Iterations within this group"
msgstr ""
@@ -29479,7 +29488,7 @@ msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
-msgid "ProjectSettings|All discussions must be resolved"
+msgid "ProjectSettings|All threads must be resolved"
msgstr ""
msgid "ProjectSettings|Allow"
@@ -29491,7 +29500,7 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
-msgid "ProjectSettings|Automatically resolve merge request diff discussions when they become outdated"
+msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
@@ -43040,9 +43049,6 @@ msgstr ""
msgid "You cannot change the start date after the cadence has started. Please create a new cadence."
msgstr ""
-msgid "You cannot change the start date because the first iteration has already started on %{start_date}."
-msgstr ""
-
msgid "You cannot combine replace_ids with add_ids or remove_ids"
msgstr ""
diff --git a/package.json b/package.json
index 05635a2c081..c93020594f3 100644
--- a/package.json
+++ b/package.json
@@ -120,7 +120,7 @@
"dateformat": "^5.0.1",
"deckar01-task_list": "^2.3.1",
"diff": "^3.4.0",
- "dompurify": "^2.3.6",
+ "dompurify": "^2.3.7",
"dropzone": "^4.2.0",
"editorconfig": "^0.15.3",
"emoji-regex": "^10.0.0",
diff --git a/spec/controllers/projects/releases_controller_spec.rb b/spec/controllers/projects/releases_controller_spec.rb
index 9dd18e58109..0dba7dab643 100644
--- a/spec/controllers/projects/releases_controller_spec.rb
+++ b/spec/controllers/projects/releases_controller_spec.rb
@@ -78,14 +78,12 @@ RSpec.describe Projects::ReleasesController do
end
describe 'GET #index' do
- before do
- get_index
- end
-
context 'as html' do
let(:format) { :html }
it 'returns a text/html content_type' do
+ get_index
+
expect(response.media_type).to eq 'text/html'
end
@@ -95,6 +93,8 @@ RSpec.describe Projects::ReleasesController do
let(:project) { private_project }
it 'returns a redirect' do
+ get_index
+
expect(response).to have_gitlab_http_status(:redirect)
end
end
@@ -104,11 +104,24 @@ RSpec.describe Projects::ReleasesController do
let(:format) { :json }
it 'returns an application/json content_type' do
+ get_index
+
expect(response.media_type).to eq 'application/json'
end
it "returns the project's releases as JSON, ordered by released_at" do
- expect(response.body).to eq([release_2, release_1].to_json)
+ get_index
+
+ expect(json_response.map { |release| release["id"] } ).to eq([release_2.id, release_1.id])
+ end
+
+ # TODO: remove in https://gitlab.com/gitlab-org/gitlab/-/issues/360903
+ it "returns release sha when remove_sha_from_releases_json is disabled" do
+ stub_feature_flags(remove_sha_from_releases_json: false)
+
+ get_index
+
+ expect(json_response).to eq([release_2, release_1].as_json)
end
it_behaves_like 'common access controls'
@@ -117,6 +130,8 @@ RSpec.describe Projects::ReleasesController do
let(:project) { private_project }
it 'returns a redirect' do
+ get_index
+
expect(response).to have_gitlab_http_status(:redirect)
end
end
diff --git a/spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb b/spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb
index 77be351f3d8..6aa59f72d2a 100644
--- a/spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb
+++ b/spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb
@@ -50,7 +50,7 @@ RSpec.describe 'Projects > Settings > User manages merge request settings' do
context 'when Pipelines are initially enabled' do
it 'shows the Merge Requests settings' do
expect(page).to have_content 'Pipelines must succeed'
- expect(page).to have_content 'All discussions must be resolved'
+ expect(page).to have_content 'All threads must be resolved'
within('.sharing-permissions-form') do
find('.project-feature-controls[data-for="project[project_feature_attributes][merge_requests_access_level]"] .gl-toggle').click
@@ -58,7 +58,7 @@ RSpec.describe 'Projects > Settings > User manages merge request settings' do
end
expect(page).not_to have_content 'Pipelines must succeed'
- expect(page).not_to have_content 'All discussions must be resolved'
+ expect(page).not_to have_content 'All threads must be resolved'
end
end
@@ -70,7 +70,7 @@ RSpec.describe 'Projects > Settings > User manages merge request settings' do
it 'shows the Merge Requests settings that do not depend on Builds feature' do
expect(page).to have_content 'Pipelines must succeed'
- expect(page).to have_content 'All discussions must be resolved'
+ expect(page).to have_content 'All threads must be resolved'
within('.sharing-permissions-form') do
find('.project-feature-controls[data-for="project[project_feature_attributes][builds_access_level]"] .gl-toggle').click
@@ -78,7 +78,7 @@ RSpec.describe 'Projects > Settings > User manages merge request settings' do
end
expect(page).to have_content 'Pipelines must succeed'
- expect(page).to have_content 'All discussions must be resolved'
+ expect(page).to have_content 'All threads must be resolved'
end
end
end
@@ -91,7 +91,7 @@ RSpec.describe 'Projects > Settings > User manages merge request settings' do
it 'does not show the Merge Requests settings' do
expect(page).not_to have_content 'Pipelines must succeed'
- expect(page).not_to have_content 'All discussions must be resolved'
+ expect(page).not_to have_content 'All threads must be resolved'
within('.sharing-permissions-form') do
find('.project-feature-controls[data-for="project[project_feature_attributes][merge_requests_access_level]"] .gl-toggle').click
@@ -99,7 +99,7 @@ RSpec.describe 'Projects > Settings > User manages merge request settings' do
end
expect(page).to have_content 'Pipelines must succeed'
- expect(page).to have_content 'All discussions must be resolved'
+ expect(page).to have_content 'All threads must be resolved'
end
end
diff --git a/spec/frontend/ci_secure_files/components/secure_files_list_spec.js b/spec/frontend/ci_secure_files/components/secure_files_list_spec.js
index 042376c71e8..ea4e17e43bd 100644
--- a/spec/frontend/ci_secure_files/components/secure_files_list_spec.js
+++ b/spec/frontend/ci_secure_files/components/secure_files_list_spec.js
@@ -57,7 +57,7 @@ describe('SecureFilesList', () => {
});
it('displays a table with expected headers', () => {
- const headers = ['Filename', 'Permissions', 'Uploaded'];
+ const headers = ['Filename', 'Uploaded'];
headers.forEach((header, i) => {
expect(findHeaderAt(i).text()).toBe(header);
});
@@ -69,8 +69,7 @@ describe('SecureFilesList', () => {
const [secureFile] = secureFiles;
expect(findCell(0, 0).text()).toBe(secureFile.name);
- expect(findCell(0, 1).text()).toBe(secureFile.permissions);
- expect(findCell(0, 2).find(TimeAgoTooltip).props('time')).toBe(secureFile.created_at);
+ expect(findCell(0, 1).find(TimeAgoTooltip).props('time')).toBe(secureFile.created_at);
});
});
@@ -84,7 +83,7 @@ describe('SecureFilesList', () => {
});
it('displays a table with expected headers', () => {
- const headers = ['Filename', 'Permissions', 'Uploaded'];
+ const headers = ['Filename', 'Uploaded'];
headers.forEach((header, i) => {
expect(findHeaderAt(i).text()).toBe(header);
});
diff --git a/spec/lib/bulk_imports/ndjson_pipeline_spec.rb b/spec/lib/bulk_imports/ndjson_pipeline_spec.rb
index 8ea6ceb7619..25edc9feea8 100644
--- a/spec/lib/bulk_imports/ndjson_pipeline_spec.rb
+++ b/spec/lib/bulk_imports/ndjson_pipeline_spec.rb
@@ -29,7 +29,7 @@ RSpec.describe BulkImports::NdjsonPipeline do
subject { NdjsonPipelineClass.new(group, user) }
it 'marks pipeline as ndjson' do
- expect(NdjsonPipelineClass.ndjson_pipeline?).to eq(true)
+ expect(NdjsonPipelineClass.file_extraction_pipeline?).to eq(true)
end
describe '#deep_transform_relation!' do
diff --git a/spec/lib/bulk_imports/pipeline_spec.rb b/spec/lib/bulk_imports/pipeline_spec.rb
index 48c265d6118..e4ecf99dab0 100644
--- a/spec/lib/bulk_imports/pipeline_spec.rb
+++ b/spec/lib/bulk_imports/pipeline_spec.rb
@@ -63,7 +63,7 @@ RSpec.describe BulkImports::Pipeline do
BulkImports::MyPipeline.transformer(klass, options)
BulkImports::MyPipeline.loader(klass, options)
BulkImports::MyPipeline.abort_on_failure!
- BulkImports::MyPipeline.ndjson_pipeline!
+ BulkImports::MyPipeline.file_extraction_pipeline!
expect(BulkImports::MyPipeline.get_extractor).to eq({ klass: klass, options: options })
@@ -75,7 +75,7 @@ RSpec.describe BulkImports::Pipeline do
expect(BulkImports::MyPipeline.get_loader).to eq({ klass: klass, options: options })
expect(BulkImports::MyPipeline.abort_on_failure?).to eq(true)
- expect(BulkImports::MyPipeline.ndjson_pipeline?).to eq(true)
+ expect(BulkImports::MyPipeline.file_extraction_pipeline?).to eq(true)
end
end
end
diff --git a/spec/lib/gitlab/database_importers/work_items/base_type_importer_spec.rb b/spec/lib/gitlab/database_importers/work_items/base_type_importer_spec.rb
index 8c3d372cc55..d044170dc75 100644
--- a/spec/lib/gitlab/database_importers/work_items/base_type_importer_spec.rb
+++ b/spec/lib/gitlab/database_importers/work_items/base_type_importer_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Gitlab::DatabaseImporters::WorkItems::BaseTypeImporter do
- subject { described_class.import }
+ subject { described_class.upsert_types }
it_behaves_like 'work item base types importer'
end
diff --git a/spec/models/ci/secure_file_spec.rb b/spec/models/ci/secure_file_spec.rb
index f92db3fe8db..40ddafad013 100644
--- a/spec/models/ci/secure_file_spec.rb
+++ b/spec/models/ci/secure_file_spec.rb
@@ -25,7 +25,6 @@ RSpec.describe Ci::SecureFile do
it { is_expected.to validate_presence_of(:checksum) }
it { is_expected.to validate_presence_of(:file_store) }
it { is_expected.to validate_presence_of(:name) }
- it { is_expected.to validate_presence_of(:permissions) }
it { is_expected.to validate_presence_of(:project_id) }
context 'unique filename' do
let_it_be(:project1) { create(:project) }
@@ -49,12 +48,6 @@ RSpec.describe Ci::SecureFile do
end
end
- describe '#permissions' do
- it 'defaults to read_only file permssions' do
- expect(subject.permissions).to eq('read_only')
- end
- end
-
describe '#checksum' do
it 'computes SHA256 checksum on the file before encrypted' do
expect(subject.checksum).to eq(Digest::SHA256.hexdigest(sample_file))
diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb
index f099015e63e..26e86207fd6 100644
--- a/spec/models/event_spec.rb
+++ b/spec/models/event_spec.rb
@@ -1040,6 +1040,36 @@ RSpec.describe Event do
end
end
+ describe '#has_no_project_and_group' do
+ context 'with project event' do
+ it 'returns false when the event has project' do
+ event = build(:event, project: create(:project))
+
+ expect(event.has_no_project_and_group?).to be false
+ end
+
+ it 'returns true when the event has no project' do
+ event = build(:event, project: nil)
+
+ expect(event.has_no_project_and_group?).to be true
+ end
+ end
+
+ context 'with group event' do
+ it 'returns false when the event has group' do
+ event = build(:event, group: create(:group))
+
+ expect(event.has_no_project_and_group?).to be false
+ end
+
+ it 'returns true when the event has no group' do
+ event = build(:event, group: nil)
+
+ expect(event.has_no_project_and_group?).to be true
+ end
+ end
+ end
+
def create_push_event(project, user)
event = create(:push_event, project: project, author: user)
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 14cad1174ef..d40c78b5b60 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -3540,50 +3540,6 @@ RSpec.describe MergeRequest, factory_default: :keep do
end
end
- describe "#legacy_environments" do
- subject { merge_request.legacy_environments }
-
- let(:merge_request) { create(:merge_request, source_branch: 'feature', target_branch: 'master') }
- let(:project) { merge_request.project }
-
- let(:pipeline) do
- create(:ci_pipeline,
- source: :merge_request_event,
- merge_request: merge_request, project: project,
- sha: merge_request.diff_head_sha,
- merge_requests_as_head_pipeline: [merge_request])
- end
-
- let!(:job) { create(:ci_build, :with_deployment, :start_review_app, pipeline: pipeline, project: project) }
-
- it 'returns environments' do
- is_expected.to eq(pipeline.environments_in_self_and_descendants.to_a)
- expect(subject.count).to be(1)
- end
-
- context 'when pipeline is not associated with environments' do
- let!(:job) { create(:ci_build, pipeline: pipeline, project: project) }
-
- it 'returns empty array' do
- is_expected.to be_empty
- end
- end
-
- context 'when pipeline is not a pipeline for merge request' do
- let(:pipeline) do
- create(:ci_pipeline,
- project: project,
- ref: 'feature',
- sha: merge_request.diff_head_sha,
- merge_requests_as_head_pipeline: [merge_request])
- end
-
- it 'returns empty relation' do
- is_expected.to be_empty
- end
- end
- end
-
describe "#reload_diff" do
it 'calls MergeRequests::ReloadDiffsService#execute with correct params' do
user = create(:user)
diff --git a/spec/requests/api/ci/secure_files_spec.rb b/spec/requests/api/ci/secure_files_spec.rb
index 6de6d1ef222..6f16fe5460b 100644
--- a/spec/requests/api/ci/secure_files_spec.rb
+++ b/spec/requests/api/ci/secure_files_spec.rb
@@ -143,7 +143,6 @@ RSpec.describe API::Ci::SecureFiles do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['name']).to eq(secure_file.name)
- expect(json_response['permissions']).to eq(secure_file.permissions)
end
it 'responds with 404 Not Found if requesting non-existing secure file' do
@@ -159,7 +158,6 @@ RSpec.describe API::Ci::SecureFiles do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['name']).to eq(secure_file.name)
- expect(json_response['permissions']).to eq(secure_file.permissions)
end
end
@@ -250,12 +248,11 @@ RSpec.describe API::Ci::SecureFiles do
context 'authenticated user with admin permissions' do
it 'creates a secure file' do
expect do
- post api("/projects/#{project.id}/secure_files", maintainer), params: file_params.merge(permissions: 'execute')
+ post api("/projects/#{project.id}/secure_files", maintainer), params: file_params
end.to change {project.secure_files.count}.by(1)
expect(response).to have_gitlab_http_status(:created)
expect(json_response['name']).to eq('upload-keystore.jks')
- expect(json_response['permissions']).to eq('execute')
expect(json_response['checksum']).to eq(secure_file.checksum)
expect(json_response['checksum_algorithm']).to eq('sha256')
@@ -267,14 +264,6 @@ RSpec.describe API::Ci::SecureFiles do
expect(Time.parse(json_response['created_at'])).to be_like_time(secure_file.created_at)
end
- it 'creates a secure file with read_only permissions by default' do
- expect do
- post api("/projects/#{project.id}/secure_files", maintainer), params: file_params
- end.to change {project.secure_files.count}.by(1)
-
- expect(json_response['permissions']).to eq('read_only')
- end
-
it 'uploads and downloads a secure file' do
post api("/projects/#{project.id}/secure_files", maintainer), params: file_params
@@ -327,15 +316,6 @@ RSpec.describe API::Ci::SecureFiles do
expect(json_response['message']['name']).to include('has already been taken')
end
- it 'returns an error when an unexpected permission is supplied' do
- expect do
- post api("/projects/#{project.id}/secure_files", maintainer), params: file_params.merge(permissions: 'foo')
- end.not_to change { project.secure_files.count }
-
- expect(response).to have_gitlab_http_status(:bad_request)
- expect(json_response['error']).to eq('permissions does not have a valid value')
- end
-
it 'returns an error when an unexpected validation failure happens' do
allow_next_instance_of(Ci::SecureFile) do |instance|
allow(instance).to receive(:valid?).and_return(false)
diff --git a/spec/serializers/release_serializer_spec.rb b/spec/serializers/release_serializer_spec.rb
index 518d281f370..b31172c3a50 100644
--- a/spec/serializers/release_serializer_spec.rb
+++ b/spec/serializers/release_serializer_spec.rb
@@ -19,6 +19,10 @@ RSpec.describe ReleaseSerializer do
it 'serializes the label object' do
expect(subject[:tag]).to eq resource.tag
end
+
+ it 'does not expose git-sha as sensitive information' do
+ expect(subject[:sha]).to be_nil
+ end
end
context 'when multiple objects are being serialized' do
diff --git a/spec/services/environments/stop_service_spec.rb b/spec/services/environments/stop_service_spec.rb
index 6cfbd765785..afbc0ba70f9 100644
--- a/spec/services/environments/stop_service_spec.rb
+++ b/spec/services/environments/stop_service_spec.rb
@@ -223,18 +223,6 @@ RSpec.describe Environments::StopService do
expect(prepare_staging_job.persisted_environment.state).to eq('available')
end
-
- context 'when fix_related_environments_for_merge_requests feature flag is disabled' do
- before do
- stub_feature_flags(fix_related_environments_for_merge_requests: false)
- end
-
- it 'stops unrelated environments too' do
- subject
-
- expect(prepare_staging_job.persisted_environment.state).to eq('stopped')
- end
- end
end
end
diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb
index 6b7b72d83fc..3934ca04a00 100644
--- a/spec/services/issues/create_service_spec.rb
+++ b/spec/services/issues/create_service_spec.rb
@@ -47,6 +47,14 @@ RSpec.describe Issues::CreateService do
due_date: Date.tomorrow }
end
+ it 'works if base work item types were not created yet' do
+ WorkItems::Type.delete_all
+
+ expect do
+ issue
+ end.to change(Issue, :count).by(1)
+ end
+
it 'creates the issue with the given params' do
expect(Issuable::CommonSystemNotesService).to receive_message_chain(:new, :execute)
diff --git a/spec/support/helpers/test_env.rb b/spec/support/helpers/test_env.rb
index d81d0d436a1..11f469c1d27 100644
--- a/spec/support/helpers/test_env.rb
+++ b/spec/support/helpers/test_env.rb
@@ -374,7 +374,7 @@ module TestEnv
end
def seed_db
- Gitlab::DatabaseImporters::WorkItems::BaseTypeImporter.import
+ Gitlab::DatabaseImporters::WorkItems::BaseTypeImporter.upsert_types
end
private
diff --git a/spec/support/shared_examples/models/wiki_shared_examples.rb b/spec/support/shared_examples/models/wiki_shared_examples.rb
index 50062456d49..6f17231a040 100644
--- a/spec/support/shared_examples/models/wiki_shared_examples.rb
+++ b/spec/support/shared_examples/models/wiki_shared_examples.rb
@@ -676,16 +676,6 @@ RSpec.shared_examples 'wiki model' do
end
end
end
-
- context 'when feature flag :gitaly_replace_wiki_update_page is disabled' do
- before do
- stub_feature_flags(gitaly_replace_wiki_update_page: false)
- end
-
- it_behaves_like 'update_page tests' do
- include_context 'common examples'
- end
- end
end
describe '#delete_page' do
diff --git a/spec/support/shared_examples/work_item_base_types_importer.rb b/spec/support/shared_examples/work_item_base_types_importer.rb
index 68e37171ea2..593670ac4b8 100644
--- a/spec/support/shared_examples/work_item_base_types_importer.rb
+++ b/spec/support/shared_examples/work_item_base_types_importer.rb
@@ -1,10 +1,48 @@
# frozen_string_literal: true
RSpec.shared_examples 'work item base types importer' do
- it 'creates all base work item types' do
- # Fixtures need to run on a pristine DB, but the test suite preloads the base types before(:suite)
+ it "creates all base work item types if they don't exist" do
WorkItems::Type.delete_all
expect { subject }.to change(WorkItems::Type, :count).from(0).to(WorkItems::Type::BASE_TYPES.count)
+
+ types_in_db = WorkItems::Type.all.map { |type| type.slice(:base_type, :icon_name, :name).symbolize_keys }
+ expected_types = WorkItems::Type::BASE_TYPES.map do |type, attributes|
+ attributes.slice(:icon_name, :name).merge(base_type: type.to_s)
+ end
+
+ expect(types_in_db).to match_array(expected_types)
+ expect(WorkItems::Type.all).to all(be_valid)
+ end
+
+ it 'upserts base work item types if they already exist' do
+ first_type = WorkItems::Type.first
+ original_name = first_type.name
+
+ first_type.update!(name: original_name.upcase)
+
+ expect do
+ subject
+ first_type.reload
+ end.to not_change(WorkItems::Type, :count).and(
+ change(first_type, :name).from(original_name.upcase).to(original_name)
+ )
+ end
+
+ it 'executes a single INSERT query' do
+ expect { subject }.to make_queries_matching(/INSERT/, 1)
+ end
+
+ context 'when some base types exist' do
+ before do
+ WorkItems::Type.limit(1).delete_all
+ end
+
+ it 'inserts all types and does nothing if some already existed' do
+ expect { subject }.to make_queries_matching(/INSERT/, 1).and(
+ change(WorkItems::Type, :count).by(1)
+ )
+ expect(WorkItems::Type.count).to eq(WorkItems::Type::BASE_TYPES.count)
+ end
end
end
diff --git a/spec/workers/bulk_imports/pipeline_worker_spec.rb b/spec/workers/bulk_imports/pipeline_worker_spec.rb
index 3578fec5bc0..209ae8862b6 100644
--- a/spec/workers/bulk_imports/pipeline_worker_spec.rb
+++ b/spec/workers/bulk_imports/pipeline_worker_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe BulkImports::PipelineWorker do
def run; end
- def self.ndjson_pipeline?
+ def self.file_extraction_pipeline?
false
end
end
@@ -222,14 +222,14 @@ RSpec.describe BulkImports::PipelineWorker do
end
end
- context 'when ndjson pipeline' do
- let(:ndjson_pipeline) do
+ context 'when file extraction pipeline' do
+ let(:file_extraction_pipeline) do
Class.new do
def initialize(_); end
def run; end
- def self.ndjson_pipeline?
+ def self.file_extraction_pipeline?
true
end
@@ -249,11 +249,11 @@ RSpec.describe BulkImports::PipelineWorker do
end
before do
- stub_const('NdjsonPipeline', ndjson_pipeline)
+ stub_const('NdjsonPipeline', file_extraction_pipeline)
allow_next_instance_of(BulkImports::Groups::Stage) do |instance|
allow(instance).to receive(:pipelines)
- .and_return([[0, ndjson_pipeline]])
+ .and_return([[0, file_extraction_pipeline]])
end
end
@@ -278,7 +278,7 @@ RSpec.describe BulkImports::PipelineWorker do
expect(described_class)
.to receive(:perform_in)
.with(
- described_class::NDJSON_PIPELINE_PERFORM_DELAY,
+ described_class::FILE_EXTRACTION_PIPELINE_PERFORM_DELAY,
pipeline_tracker.id,
pipeline_tracker.stage,
entity.id
diff --git a/workhorse/go.mod b/workhorse/go.mod
index d156890d245..01dc6e468bc 100644
--- a/workhorse/go.mod
+++ b/workhorse/go.mod
@@ -36,5 +36,6 @@ require (
golang.org/x/net v0.0.0-20211008194852-3b03d305991f
golang.org/x/tools v0.1.5
google.golang.org/grpc v1.40.0
+ google.golang.org/protobuf v1.27.1
honnef.co/go/tools v0.1.3
)
diff --git a/workhorse/internal/git/error.go b/workhorse/internal/git/error.go
index 2b7cad6bb64..86a2ba44767 100644
--- a/workhorse/internal/git/error.go
+++ b/workhorse/internal/git/error.go
@@ -1,4 +1,100 @@
package git
+import (
+ "errors"
+ "fmt"
+ "io"
+
+ "gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb"
+ "google.golang.org/grpc/status"
+
+ "gitlab.com/gitlab-org/gitlab/workhorse/internal/log"
+)
+
+// For unwrapping google.golang.org/grpc/internal/status.Error
+type grpcErr interface {
+ GRPCStatus() *status.Status
+ Error() string
+}
+
// For cosmetic purposes in Sentry
type copyError struct{ error }
+
+// handleLimitErr handles errors that come back from Gitaly that may be a
+// LimitError. A LimitError is returned by Gitaly when it is at its limit in
+// handling requests. Since this is a known error, we should print a sensible
+// error message to the end user.
+func handleLimitErr(err error, w io.Writer, f func(w io.Writer) error) {
+ var statusErr grpcErr
+ if !errors.As(err, &statusErr) {
+ return
+ }
+
+ if st, ok := status.FromError(statusErr); ok {
+ details := st.Details()
+ for _, detail := range details {
+ switch detail.(type) {
+ case *gitalypb.LimitError:
+ if err := f(w); err != nil {
+ log.WithError(fmt.Errorf("handling limit error: %w", err))
+ }
+ }
+ }
+ }
+}
+
+// writeReceivePackError writes a "server is busy" error message to the
+// git-recieve-pack-result.
+//
+// 0023\x01001aunpack server is busy
+// 00000044\x2GitLab is currently unable to handle this request due to load.
+// 0000
+//
+// We write a line reporting that unpack failed, and then provide some progress
+// information through the side-band 2 channel.
+// See https://gitlab.com/gitlab-org/gitaly/-/tree/jc-return-structured-error-limits
+// for more details.
+func writeReceivePackError(w io.Writer) error {
+ if _, err := fmt.Fprintf(w, "%04x", 35); err != nil {
+ return err
+ }
+
+ if _, err := w.Write([]byte{0x01}); err != nil {
+ return err
+ }
+
+ if _, err := fmt.Fprintf(w, "%04xunpack server is busy\n", 26); err != nil {
+ return err
+ }
+
+ if _, err := w.Write([]byte("0000")); err != nil {
+ return err
+ }
+
+ if _, err := fmt.Fprintf(w, "%04x", 68); err != nil {
+ return err
+ }
+
+ if _, err := w.Write([]byte{0x2}); err != nil {
+ return err
+ }
+
+ if _, err := fmt.Fprint(w, "GitLab is currently unable to handle this request due to load.\n"); err != nil {
+ return err
+ }
+
+ if _, err := w.Write([]byte("0000")); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// writeUploadPackError writes a "server is busy" error message that git
+// understands and prints to stdout. UploadPack expects to receive pack data in
+// PKT-LINE format. An error-line can be passed that begins with ERR.
+// See https://git-scm.com/docs/pack-protocol/2.29.0#_pkt_line_format.
+func writeUploadPackError(w io.Writer) error {
+ _, err := fmt.Fprintf(w, "%04xERR GitLab is currently unable to handle this request due to load.\n", 71)
+ return err
+}
diff --git a/workhorse/internal/git/error_test.go b/workhorse/internal/git/error_test.go
new file mode 100644
index 00000000000..d87c81fc83c
--- /dev/null
+++ b/workhorse/internal/git/error_test.go
@@ -0,0 +1,80 @@
+package git
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
+ "google.golang.org/protobuf/proto"
+ "google.golang.org/protobuf/types/known/anypb"
+ "google.golang.org/protobuf/types/known/durationpb"
+)
+
+func TestHandleLimitErr(t *testing.T) {
+ testCases := []struct {
+ desc string
+ errWriter func(io.Writer) error
+ expectedBytes []byte
+ }{
+ {
+ desc: "upload pack",
+ errWriter: writeUploadPackError,
+ expectedBytes: bytes.Join([][]byte{
+ []byte{'0', '0', '4', '7'},
+ []byte("ERR GitLab is currently unable to handle this request due to load.\n"),
+ }, []byte{}),
+ },
+ {
+ desc: "recieve pack",
+ errWriter: writeReceivePackError,
+ expectedBytes: bytes.Join([][]byte{
+ {'0', '0', '2', '3', 1, '0', '0', '1', 'a'},
+ []byte("unpack server is busy\n"),
+ {'0', '0', '0', '0', '0', '0', '4', '4', 2},
+ []byte("GitLab is currently unable to handle this request due to load.\n"),
+ {'0', '0', '0', '0'},
+ }, []byte{}),
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.desc, func(t *testing.T) {
+ var body bytes.Buffer
+ err := errWithDetail(t, &gitalypb.LimitError{
+ ErrorMessage: "concurrency queue wait time reached",
+ RetryAfter: durationpb.New(0)})
+
+ handleLimitErr(fmt.Errorf("wrapped error: %w", err), &body, tc.errWriter)
+ require.Equal(t, tc.expectedBytes, body.Bytes())
+ })
+ }
+
+ t.Run("non LimitError", func(t *testing.T) {
+ var body bytes.Buffer
+ err := status.Error(codes.Internal, "some internal error")
+ handleLimitErr(fmt.Errorf("wrapped error: %w", err), &body, writeUploadPackError)
+ require.Equal(t, []byte(nil), body.Bytes())
+
+ handleLimitErr(fmt.Errorf("wrapped error: %w", err), &body, writeReceivePackError)
+ require.Equal(t, []byte(nil), body.Bytes())
+
+ })
+}
+
+// errWithDetail adds the given details to the error if it is a gRPC status whose code is not OK.
+func errWithDetail(t *testing.T, detail proto.Message) error {
+ st := status.New(codes.Unavailable, "too busy")
+
+ proto := st.Proto()
+ marshaled, err := anypb.New(detail)
+ require.NoError(t, err)
+
+ proto.Details = append(proto.Details, marshaled)
+
+ return status.ErrorProto(proto)
+}
diff --git a/workhorse/internal/git/git-http.go b/workhorse/internal/git/git-http.go
index 7f5c1b6c584..86007e16064 100644
--- a/workhorse/internal/git/git-http.go
+++ b/workhorse/internal/git/git-http.go
@@ -22,11 +22,11 @@ const (
)
func ReceivePack(a *api.API) http.Handler {
- return postRPCHandler(a, "handleReceivePack", handleReceivePack)
+ return postRPCHandler(a, "handleReceivePack", handleReceivePack, writeReceivePackError)
}
func UploadPack(a *api.API) http.Handler {
- return postRPCHandler(a, "handleUploadPack", handleUploadPack)
+ return postRPCHandler(a, "handleUploadPack", handleUploadPack, writeUploadPackError)
}
func gitConfigOptions(a *api.Response) []string {
@@ -39,7 +39,12 @@ func gitConfigOptions(a *api.Response) []string {
return out
}
-func postRPCHandler(a *api.API, name string, handler func(*HttpResponseWriter, *http.Request, *api.Response) error) http.Handler {
+func postRPCHandler(
+ a *api.API,
+ name string,
+ handler func(*HttpResponseWriter, *http.Request, *api.Response) error,
+ errWriter func(io.Writer) error,
+) http.Handler {
return repoPreAuthorizeHandler(a, func(rw http.ResponseWriter, r *http.Request, ar *api.Response) {
cr := &countReadCloser{ReadCloser: r.Body}
r.Body = cr
@@ -50,7 +55,8 @@ func postRPCHandler(a *api.API, name string, handler func(*HttpResponseWriter, *
}()
if err := handler(w, r, ar); err != nil {
- // If the handler already wrote a response this WriteHeader call is a
+ handleLimitErr(err, w, errWriter)
+ // If the handler, or handleLimitErr already wrote a response this WriteHeader call is a
// no-op. It never reaches net/http because GitHttpResponseWriter calls
// WriteHeader on its underlying ResponseWriter at most once.
w.WriteHeader(500)
diff --git a/workhorse/internal/git/receive-pack.go b/workhorse/internal/git/receive-pack.go
index ccde9331b83..e3af472fffa 100644
--- a/workhorse/internal/git/receive-pack.go
+++ b/workhorse/internal/git/receive-pack.go
@@ -26,7 +26,7 @@ func handleReceivePack(w *HttpResponseWriter, r *http.Request, a *api.Response)
}
if err := smarthttp.ReceivePack(ctx, &a.Repository, a.GL_ID, a.GL_USERNAME, a.GL_REPOSITORY, a.GitConfigOptions, cr, cw, gitProtocol); err != nil {
- return fmt.Errorf("smarthttp.ReceivePack: %v", err)
+ return fmt.Errorf("smarthttp.ReceivePack: %w", err)
}
return nil
diff --git a/yarn.lock b/yarn.lock
index 6894334ef66..deacf960e31 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5019,11 +5019,16 @@ domhandler@^4.0.0, domhandler@^4.2.0:
dependencies:
domelementtype "^2.2.0"
-dompurify@2.3.6, dompurify@^2.3.6:
+dompurify@2.3.6:
version "2.3.6"
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.6.tgz#2e019d7d7617aacac07cbbe3d88ae3ad354cf875"
integrity sha512-OFP2u/3T1R5CEgWCEONuJ1a5+MFKnOYpkywpUSxv/dj1LeBT1erK+JwM7zK0ROy2BRhqVCf0LRw/kHqKuMkVGg==
+dompurify@^2.3.6, dompurify@^2.3.7:
+ version "2.3.7"
+ resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.7.tgz#30aa7feddc1420f3e554b1b3fe9e2f318a28066e"
+ integrity sha512-fsVZLywBd3awZIG3qU4JEdw7DCb0uUCajTfWRrLhsgKjTBd5CIIluPoAkNfco05GuNYQGj4/+bQIhlq96eT9eQ==
+
domutils@^2.5.2, domutils@^2.6.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.6.0.tgz#2e15c04185d43fb16ae7057cb76433c6edb938b7"