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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab/issue_templates/Deprecations.md22
-rw-r--r--app/assets/javascripts/blob/pdf/pdf_viewer.vue8
-rw-r--r--app/assets/javascripts/pdf/index.vue2
-rw-r--r--app/assets/javascripts/repository/components/blob_viewers/index.js1
-rw-r--r--app/assets/javascripts/repository/components/blob_viewers/pdf_viewer.vue38
-rw-r--r--app/assets/javascripts/repository/constants.js3
-rw-r--r--app/assets/stylesheets/framework/snippets.scss5
-rw-r--r--app/assets/stylesheets/pages/commits.scss1
-rw-r--r--app/finders/groups_finder.rb21
-rw-r--r--app/graphql/types/issue_type_enum.rb2
-rw-r--r--app/models/work_item/type.rb7
-rw-r--r--config/feature_flags/development/use_traversal_ids_groups_finder.yml8
-rw-r--r--db/migrate/20211126204445_add_task_to_work_item_types.rb31
-rw-r--r--db/migrate/20211201061733_add_future_subscriptions_to_application_settings.rb7
-rw-r--r--db/post_migrate/20211203091642_add_index_to_projects_on_marked_for_deletion_at.rb15
-rw-r--r--db/schema_migrations/202111262044451
-rw-r--r--db/schema_migrations/202112010617331
-rw-r--r--db/schema_migrations/202112030916421
-rw-r--r--db/structure.sql3
-rw-r--r--doc/development/documentation/styleguide/img/callouts.pngbin0 -> 4875 bytes
-rw-r--r--doc/development/documentation/styleguide/index.md11
-rw-r--r--doc/user/project/repository/forking_workflow.md8
-rw-r--r--lib/api/entities/issue_basic.rb2
-rw-r--r--lib/api/issues.rb4
-rw-r--r--locale/gitlab.pot6
-rw-r--r--qa/qa/resource/group.rb3
-rw-r--r--qa/qa/resource/group_base.rb2
-rw-r--r--qa/qa/resource/sandbox.rb3
-rw-r--r--qa/qa/specs/features/api/1_manage/bulk_import_group_spec.rb22
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb9
-rw-r--r--spec/finders/groups_finder_spec.rb15
-rw-r--r--spec/frontend/repository/components/blob_viewers/pdf_viewer_spec.js47
-rw-r--r--spec/graphql/types/issue_type_enum_spec.rb6
-rw-r--r--spec/migrations/20210804150320_create_base_work_item_types_spec.rb22
-rw-r--r--spec/migrations/20210831203408_upsert_base_work_item_types_spec.rb31
-rw-r--r--spec/migrations/20211126204445_add_task_to_work_item_types_spec.rb54
-rw-r--r--spec/migrations/20211203091642_add_index_to_projects_on_marked_for_deletion_at_spec.rb18
-rw-r--r--spec/models/work_item/type_spec.rb4
-rw-r--r--spec/requests/api/graphql/ci/jobs_spec.rb2
-rw-r--r--spec/support/helpers/migrations_helpers/work_item_types_helper.rb27
40 files changed, 423 insertions, 50 deletions
diff --git a/.gitlab/issue_templates/Deprecations.md b/.gitlab/issue_templates/Deprecations.md
index caef5c64334..85db4314233 100644
--- a/.gitlab/issue_templates/Deprecations.md
+++ b/.gitlab/issue_templates/Deprecations.md
@@ -12,7 +12,10 @@ The description of the deprecation should state what actions the user should tak
### Breaking Change
-<!-- Is this a breaking change or not? If so, please add instructions for how users can update their workflow. -->
+<!-- Does this MR contain a breaking change? If yes:
+- Add the ~"breaking change" label to this issue.
+- Add instructions for how users can update their workflow. -->
+
### Affected Topology
<!--
@@ -52,3 +55,20 @@ Which tier is this feature available in?
<!--
Add links to any relevant documentation or code that will provide additional details or clarity regarding the planned change. Also, include a link to the removal issue if relevant.
-->
+
+<!-- Label reminders - you should have one of each of the following labels.
+Use the following resources to find the appropriate labels:
+- https://gitlab.com/gitlab-org/gitlab/-/labels
+- https://about.gitlab.com/handbook/product/categories/features/
+-->
+
+<!-- Populate the Section, Group, and Category -->
+/label ~devops:: ~group: ~Category:
+
+<!-- Choose the Pricing Tier(s) -->
+/label ~"GitLab Free" ~"GitLab Premium" ~"GitLab Ultimate"
+
+<!-- Identifies that this Issue is related to deprecating a feature -->
+/label ~"type::deprecation"
+
+<!-- Add the ~"breaking change" label to this issue if necessary --> \ No newline at end of file
diff --git a/app/assets/javascripts/blob/pdf/pdf_viewer.vue b/app/assets/javascripts/blob/pdf/pdf_viewer.vue
index 96d6f500960..a1a62abeb6f 100644
--- a/app/assets/javascripts/blob/pdf/pdf_viewer.vue
+++ b/app/assets/javascripts/blob/pdf/pdf_viewer.vue
@@ -38,7 +38,13 @@ export default {
<div v-if="loading && !error" class="text-center loading">
<gl-loading-icon class="mt-5" size="lg" />
</div>
- <pdf-lab v-if="!loadError" :pdf="pdf" @pdflabload="onLoad" @pdflaberror="onError" />
+ <pdf-lab
+ v-if="!loadError"
+ :pdf="pdf"
+ @pdflabload="onLoad"
+ @pdflaberror="onError"
+ v-on="$listeners"
+ />
<p v-if="error" class="text-center">
<span v-if="loadError" ref="loadError">
{{ __('An error occurred while loading the file. Please try again later.') }}
diff --git a/app/assets/javascripts/pdf/index.vue b/app/assets/javascripts/pdf/index.vue
index 6a64538abfe..644eccc0232 100644
--- a/app/assets/javascripts/pdf/index.vue
+++ b/app/assets/javascripts/pdf/index.vue
@@ -45,7 +45,7 @@ export default {
.promise.then(this.renderPages)
.then((pages) => {
this.pages = pages;
- this.$emit('pdflabload');
+ this.$emit('pdflabload', pages.length);
})
.catch((error) => {
this.$emit('pdflaberror', error);
diff --git a/app/assets/javascripts/repository/components/blob_viewers/index.js b/app/assets/javascripts/repository/components/blob_viewers/index.js
index b5c4c81b9d8..62d687e848b 100644
--- a/app/assets/javascripts/repository/components/blob_viewers/index.js
+++ b/app/assets/javascripts/repository/components/blob_viewers/index.js
@@ -40,6 +40,7 @@ export const viewerProps = (type, blob) => {
},
pdf: {
url: blob.rawPath,
+ fileSize: blob.rawSize,
},
}[type];
};
diff --git a/app/assets/javascripts/repository/components/blob_viewers/pdf_viewer.vue b/app/assets/javascripts/repository/components/blob_viewers/pdf_viewer.vue
index 3eefcd64b13..803a357df52 100644
--- a/app/assets/javascripts/repository/components/blob_viewers/pdf_viewer.vue
+++ b/app/assets/javascripts/repository/components/blob_viewers/pdf_viewer.vue
@@ -1,16 +1,50 @@
<script>
+import { GlButton } from '@gitlab/ui';
import PdfViewer from '~/blob/pdf/pdf_viewer.vue';
+import { __ } from '~/locale';
+import { PDF_MAX_FILE_SIZE, PDF_MAX_PAGE_LIMIT } from '../../constants';
export default {
- components: { PdfViewer },
+ components: { GlButton, PdfViewer },
+ i18n: {
+ tooLargeDescription: __('This PDF is too large to display. Please download to view.'),
+ tooLargeButtonText: __('Download PDF'),
+ },
props: {
url: {
type: String,
required: true,
},
+ fileSize: {
+ type: Number,
+ required: true,
+ },
+ },
+ data() {
+ return { totalPages: 0 };
+ },
+ computed: {
+ tooLargeToDisplay() {
+ return this.fileSize > PDF_MAX_FILE_SIZE || this.totalPages > PDF_MAX_PAGE_LIMIT;
+ },
+ },
+ methods: {
+ handleOnLoad(totalPages) {
+ this.totalPages = totalPages;
+ },
},
};
</script>
<template>
- <pdf-viewer :pdf="url" />
+ <div>
+ <pdf-viewer v-if="!tooLargeToDisplay" :pdf="url" @pdflabload="handleOnLoad" />
+
+ <div v-else class="gl-display-flex gl-flex-direction-column gl-align-items-center gl-p-5">
+ <p>{{ $options.i18n.tooLargeDescription }}</p>
+
+ <gl-button icon="download" category="secondary" variant="confirm" :href="url" download>{{
+ $options.i18n.tooLargeButtonText
+ }}</gl-button>
+ </div>
+ </div>
</template>
diff --git a/app/assets/javascripts/repository/constants.js b/app/assets/javascripts/repository/constants.js
index b4363c51165..cdc4818e493 100644
--- a/app/assets/javascripts/repository/constants.js
+++ b/app/assets/javascripts/repository/constants.js
@@ -20,3 +20,6 @@ export const COMMIT_MESSAGE_BODY_MAX_LENGTH = 72;
export const LIMITED_CONTAINER_WIDTH_CLASS = 'limit-container-width';
export const I18N_COMMIT_DATA_FETCH_ERROR = __('An error occurred while fetching commit data.');
+
+export const PDF_MAX_FILE_SIZE = 10000000; // 10 MB
+export const PDF_MAX_PAGE_LIMIT = 50;
diff --git a/app/assets/stylesheets/framework/snippets.scss b/app/assets/stylesheets/framework/snippets.scss
index c59e70c80df..39786aa0138 100644
--- a/app/assets/stylesheets/framework/snippets.scss
+++ b/app/assets/stylesheets/framework/snippets.scss
@@ -16,6 +16,11 @@
.snippet-file-content {
border-radius: 3px;
+ .file-content {
+ max-height: 500px;
+ overflow-y: auto;
+ }
+
+ .snippet-file-content {
@include gl-mt-5;
}
diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss
index 7f35b8fab43..cc8ea1493fc 100644
--- a/app/assets/stylesheets/pages/commits.scss
+++ b/app/assets/stylesheets/pages/commits.scss
@@ -149,7 +149,6 @@
.commit-content {
padding-right: 10px;
white-space: normal;
- overflow: hidden;
.commit-title {
display: flex;
diff --git a/app/finders/groups_finder.rb b/app/finders/groups_finder.rb
index 7ea3362fba1..7e3cdd79a4c 100644
--- a/app/finders/groups_finder.rb
+++ b/app/finders/groups_finder.rb
@@ -52,7 +52,16 @@ class GroupsFinder < UnionFinder
return [Group.all] if current_user&.can_read_all_resources? && all_available?
groups = []
- groups << Gitlab::ObjectHierarchy.new(groups_for_ancestors, groups_for_descendants).all_objects if current_user
+
+ if current_user
+ if Feature.enabled?(:use_traversal_ids_groups_finder, default_enabled: :yaml)
+ groups << current_user.authorized_groups.self_and_ancestors
+ groups << current_user.groups.self_and_descendants
+ else
+ groups << Gitlab::ObjectHierarchy.new(groups_for_ancestors, groups_for_descendants).all_objects
+ end
+ end
+
groups << Group.unscoped.public_to_user(current_user) if include_public_groups?
groups << Group.none if groups.empty?
groups
@@ -72,9 +81,13 @@ class GroupsFinder < UnionFinder
.groups
.where('members.access_level >= ?', params[:min_access_level])
- Gitlab::ObjectHierarchy
- .new(groups)
- .base_and_descendants
+ if Feature.enabled?(:use_traversal_ids_groups_finder, default_enabled: :yaml)
+ groups.self_and_descendants
+ else
+ Gitlab::ObjectHierarchy
+ .new(groups)
+ .base_and_descendants
+ end
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/graphql/types/issue_type_enum.rb b/app/graphql/types/issue_type_enum.rb
index 6999ea270a2..0cfba6bbbd0 100644
--- a/app/graphql/types/issue_type_enum.rb
+++ b/app/graphql/types/issue_type_enum.rb
@@ -5,7 +5,7 @@ module Types
graphql_name 'IssueType'
description 'Issue type'
- ::WorkItem::Type.base_types.keys.each do |issue_type|
+ ::WorkItem::Type.allowed_types_for_issues.each do |issue_type|
value issue_type.upcase, value: issue_type, description: "#{issue_type.titleize} issue type"
end
end
diff --git a/app/models/work_item/type.rb b/app/models/work_item/type.rb
index 7038beadd62..3acb9c0011c 100644
--- a/app/models/work_item/type.rb
+++ b/app/models/work_item/type.rb
@@ -15,7 +15,8 @@ class WorkItem::Type < ApplicationRecord
issue: { name: 'Issue', icon_name: 'issue-type-issue', enum_value: 0 },
incident: { name: 'Incident', icon_name: 'issue-type-incident', enum_value: 1 },
test_case: { name: 'Test Case', icon_name: 'issue-type-test-case', enum_value: 2 }, ## EE-only
- requirement: { name: 'Requirement', icon_name: 'issue-type-requirements', enum_value: 3 } ## EE-only
+ requirement: { name: 'Requirement', icon_name: 'issue-type-requirements', enum_value: 3 }, ## EE-only
+ task: { name: 'Task', icon_name: 'issue-type-task', enum_value: 4 }
}.freeze
cache_markdown_field :description, pipeline: :single_line
@@ -42,6 +43,10 @@ class WorkItem::Type < ApplicationRecord
default_by_type(:issue)
end
+ def self.allowed_types_for_issues
+ base_types.keys.excluding('task')
+ end
+
private
def strip_whitespace
diff --git a/config/feature_flags/development/use_traversal_ids_groups_finder.yml b/config/feature_flags/development/use_traversal_ids_groups_finder.yml
new file mode 100644
index 00000000000..b0550fe62d9
--- /dev/null
+++ b/config/feature_flags/development/use_traversal_ids_groups_finder.yml
@@ -0,0 +1,8 @@
+---
+name: use_traversal_ids_groups_finder
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67650
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/345666
+milestone: '14.6'
+type: development
+group: group::access
+default_enabled: false
diff --git a/db/migrate/20211126204445_add_task_to_work_item_types.rb b/db/migrate/20211126204445_add_task_to_work_item_types.rb
new file mode 100644
index 00000000000..875c2272c6d
--- /dev/null
+++ b/db/migrate/20211126204445_add_task_to_work_item_types.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+class AddTaskToWorkItemTypes < Gitlab::Database::Migration[1.0]
+ TASK_ENUM_VALUE = 4
+
+ class WorkItemType < ActiveRecord::Base
+ self.inheritance_column = :_type_disabled
+ self.table_name = 'work_item_types'
+
+ validates :name, uniqueness: { case_sensitive: false, scope: [:namespace_id] }
+ end
+
+ def up
+ # New instances will not run this migration and add this type via fixtures
+ # checking if record exists mostly because migration specs will run all migrations
+ # and that will conflict with the preloaded base work item types
+ task_work_item = WorkItemType.find_by(name: 'Task', namespace_id: nil)
+
+ if task_work_item
+ say('Task item record exist, skipping creation')
+ else
+ WorkItemType.create(name: 'Task', namespace_id: nil, base_type: TASK_ENUM_VALUE, icon_name: 'issue-type-task')
+ end
+ end
+
+ def down
+ # There's the remote possibility that issues could already be
+ # using this issue type, with a tight foreign constraint.
+ # Therefore we will not attempt to remove any data.
+ end
+end
diff --git a/db/migrate/20211201061733_add_future_subscriptions_to_application_settings.rb b/db/migrate/20211201061733_add_future_subscriptions_to_application_settings.rb
new file mode 100644
index 00000000000..9cbbef42327
--- /dev/null
+++ b/db/migrate/20211201061733_add_future_subscriptions_to_application_settings.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class AddFutureSubscriptionsToApplicationSettings < Gitlab::Database::Migration[1.0]
+ def change
+ add_column :application_settings, :future_subscriptions, :jsonb, null: false, default: []
+ end
+end
diff --git a/db/post_migrate/20211203091642_add_index_to_projects_on_marked_for_deletion_at.rb b/db/post_migrate/20211203091642_add_index_to_projects_on_marked_for_deletion_at.rb
new file mode 100644
index 00000000000..56b0df1f393
--- /dev/null
+++ b/db/post_migrate/20211203091642_add_index_to_projects_on_marked_for_deletion_at.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddIndexToProjectsOnMarkedForDeletionAt < Gitlab::Database::Migration[1.0]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_projects_not_aimed_for_deletion'
+
+ def up
+ add_concurrent_index :projects, :id, where: 'marked_for_deletion_at IS NULL', name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index :projects, :id, name: INDEX_NAME
+ end
+end
diff --git a/db/schema_migrations/20211126204445 b/db/schema_migrations/20211126204445
new file mode 100644
index 00000000000..b130d90b8ec
--- /dev/null
+++ b/db/schema_migrations/20211126204445
@@ -0,0 +1 @@
+e31592bbeb6ba6175f19cfceaafb37672633028dd021052542909999b46eac38 \ No newline at end of file
diff --git a/db/schema_migrations/20211201061733 b/db/schema_migrations/20211201061733
new file mode 100644
index 00000000000..722e7dd828c
--- /dev/null
+++ b/db/schema_migrations/20211201061733
@@ -0,0 +1 @@
+c5282e48f31c0896a3ce21fe238eb602dc006b0bfe62aa4f12ee39bbd620c76c \ No newline at end of file
diff --git a/db/schema_migrations/20211203091642 b/db/schema_migrations/20211203091642
new file mode 100644
index 00000000000..ef53b1d2ed9
--- /dev/null
+++ b/db/schema_migrations/20211203091642
@@ -0,0 +1 @@
+9954fb041a3f284f53cc9c5c68b1a9dff36513a1851e663c221eccd40736fb16 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 435ef8d4b0c..7307577f820 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -10479,6 +10479,7 @@ CREATE TABLE application_settings (
sentry_environment text,
max_ssh_key_lifetime integer,
static_objects_external_storage_auth_token_encrypted text,
+ future_subscriptions jsonb DEFAULT '[]'::jsonb NOT NULL,
CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)),
CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)),
CONSTRAINT app_settings_ext_pipeline_validation_service_url_text_limit CHECK ((char_length(external_pipeline_validation_service_url) <= 255)),
@@ -27106,6 +27107,8 @@ CREATE INDEX index_projects_api_vis20_path ON projects USING btree (path, id) WH
CREATE INDEX index_projects_api_vis20_updated_at ON projects USING btree (updated_at, id) WHERE (visibility_level = 20);
+CREATE INDEX index_projects_not_aimed_for_deletion ON projects USING btree (id) WHERE (marked_for_deletion_at IS NULL);
+
CREATE INDEX index_projects_on_created_at_and_id ON projects USING btree (created_at, id);
CREATE INDEX index_projects_on_creator_id_and_created_at_and_id ON projects USING btree (creator_id, created_at, id);
diff --git a/doc/development/documentation/styleguide/img/callouts.png b/doc/development/documentation/styleguide/img/callouts.png
new file mode 100644
index 00000000000..b84e9e269dc
--- /dev/null
+++ b/doc/development/documentation/styleguide/img/callouts.png
Binary files differ
diff --git a/doc/development/documentation/styleguide/index.md b/doc/development/documentation/styleguide/index.md
index 255fb3dc786..d56f604bf5a 100644
--- a/doc/development/documentation/styleguide/index.md
+++ b/doc/development/documentation/styleguide/index.md
@@ -1162,6 +1162,17 @@ review app in the merge request. Make sure the image isn't blurry or overwhelmin
- **Be consistent.** Coordinate screenshots with the other screenshots already on
a documentation page for a consistent reading experience.
+### Add callouts
+
+If you need to emphasize an area in a screenshot, use an arrow.
+
+- For color, use `#EE2604`. If you use the Preview application on macOS, this is the default red.
+- For the line width, use 3 pt. If you use the Preview application on macOS, this is the third line in the list.
+- Use the arrow style shown in the following image.
+- If you have multiple arrows, make them parallel when possible.
+
+![callout example](img/callouts.png)
+
### Save the image
- Resize any wide or tall screenshots if needed, but make sure the screenshot is
diff --git a/doc/user/project/repository/forking_workflow.md b/doc/user/project/repository/forking_workflow.md
index 13fd9572dc5..1ab21286a8e 100644
--- a/doc/user/project/repository/forking_workflow.md
+++ b/doc/user/project/repository/forking_workflow.md
@@ -26,17 +26,17 @@ To fork an existing project in GitLab:
1. Select the project to fork to:
- - *(Recommended method)* Below **Select a namespace to fork the project**, identify
+ - Recommended method. Below **Select a namespace to fork the project**, identify
the project you want to fork to, and click **Select**. Only namespaces you have
Developer and higher [permissions](../../permissions.md) for are shown.
![Choose namespace](img/forking_workflow_choose_namespace_v13_10.png)
- - *(Experimental method)* If your GitLab administrator has
+ - Experimental method. If your GitLab administrator has
[enabled the experimental fork project form](#enable-or-disable-the-fork-project-form), read
[Create a fork with the fork project form](#create-a-fork-with-the-fork-project-form).
- Only namespaces you have Developer and higher
- [permissions](../../permissions.md) for are shown.
+ Only namespaces you have at least the Developer
+ [role](../../permissions.md) for are shown.
NOTE:
The project path must be unique in the namespace.
diff --git a/lib/api/entities/issue_basic.rb b/lib/api/entities/issue_basic.rb
index ab248523028..6125dc05a6e 100644
--- a/lib/api/entities/issue_basic.rb
+++ b/lib/api/entities/issue_basic.rb
@@ -23,7 +23,7 @@ module API
expose :issue_type,
as: :type,
format_with: :upcase,
- documentation: { type: "String", desc: "One of #{::WorkItem::Type.base_types.keys.map(&:upcase)}" }
+ documentation: { type: "String", desc: "One of #{::WorkItem::Type.allowed_types_for_issues.map(&:upcase)}" }
expose :assignee, using: ::API::Entities::UserBasic do |issue|
issue.assignees.first
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 9958526fa7f..06d5e4cb504 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -82,7 +82,7 @@ module API
desc: 'Return issues sorted in `asc` or `desc` order.'
optional :due_date, type: String, values: %w[0 overdue week month next_month_and_previous_two_weeks] << '',
desc: 'Return issues that have no due date (`0`), or whose due date is this week, this month, between two weeks ago and next month, or which are overdue. Accepts: `overdue`, `week`, `month`, `next_month_and_previous_two_weeks`, `0`'
- optional :issue_type, type: String, values: WorkItem::Type.base_types.keys, desc: "The type of the issue. Accepts: #{WorkItem::Type.base_types.keys.join(', ')}"
+ optional :issue_type, type: String, values: WorkItem::Type.allowed_types_for_issues, desc: "The type of the issue. Accepts: #{WorkItem::Type.allowed_types_for_issues.join(', ')}"
use :issues_stats_params
use :pagination
@@ -99,7 +99,7 @@ module API
optional :due_date, type: String, desc: 'Date string in the format YEAR-MONTH-DAY'
optional :confidential, type: Boolean, desc: 'Boolean parameter if the issue should be confidential'
optional :discussion_locked, type: Boolean, desc: " Boolean parameter indicating if the issue's discussion is locked"
- optional :issue_type, type: String, values: WorkItem::Type.base_types.keys, desc: "The type of the issue. Accepts: #{WorkItem::Type.base_types.keys.join(', ')}"
+ optional :issue_type, type: String, values: WorkItem::Type.allowed_types_for_issues, desc: "The type of the issue. Accepts: #{WorkItem::Type.allowed_types_for_issues.join(', ')}"
use :optional_issue_params_ee
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index cd1f5967ce6..b6fac186500 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -12524,6 +12524,9 @@ msgstr ""
msgid "Download CSV"
msgstr ""
+msgid "Download PDF"
+msgstr ""
+
msgid "Download artifacts"
msgstr ""
@@ -35558,6 +35561,9 @@ msgstr ""
msgid "This GitLab instance is undergoing maintenance and is operating in read-only mode."
msgstr ""
+msgid "This PDF is too large to display. Please download to view."
+msgstr ""
+
msgid "This Project is currently archived and read-only. Please unarchive the project first if you want to resume Pull mirroring"
msgstr ""
diff --git a/qa/qa/resource/group.rb b/qa/qa/resource/group.rb
index ce85273c3b2..a325d96ccc2 100644
--- a/qa/qa/resource/group.rb
+++ b/qa/qa/resource/group.rb
@@ -68,7 +68,8 @@ module QA
path: path,
name: path,
visibility: 'public',
- require_two_factor_authentication: @require_two_factor_authentication
+ require_two_factor_authentication: @require_two_factor_authentication,
+ avatar: avatar
}
end
diff --git a/qa/qa/resource/group_base.rb b/qa/qa/resource/group_base.rb
index 932d39675a3..19bb5ea00d7 100644
--- a/qa/qa/resource/group_base.rb
+++ b/qa/qa/resource/group_base.rb
@@ -7,7 +7,7 @@ module QA
class GroupBase < Base
include Members
- attr_accessor :path
+ attr_accessor :path, :avatar
attributes :id,
:runners_token,
diff --git a/qa/qa/resource/sandbox.rb b/qa/qa/resource/sandbox.rb
index 385e0fa4f7e..555bfb1abc9 100644
--- a/qa/qa/resource/sandbox.rb
+++ b/qa/qa/resource/sandbox.rb
@@ -69,7 +69,8 @@ module QA
{
path: path,
name: path,
- visibility: 'public'
+ visibility: 'public',
+ avatar: avatar
}
end
diff --git a/qa/qa/specs/features/api/1_manage/bulk_import_group_spec.rb b/qa/qa/specs/features/api/1_manage/bulk_import_group_spec.rb
index 158881ed94c..fe88d7c949a 100644
--- a/qa/qa/specs/features/api/1_manage/bulk_import_group_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/bulk_import_group_spec.rb
@@ -26,6 +26,7 @@ module QA
Resource::Sandbox.fabricate_via_api! do |group|
group.api_client = api_client
group.path = "source-group-for-import-#{SecureRandom.hex(4)}"
+ group.avatar = File.new('qa/fixtures/designs/tanuki.jpg', 'r')
end
end
@@ -37,6 +38,10 @@ module QA
end
end
+ let(:import_failures) do
+ imported_group.import_details.sum([]) { |details| details[:failures] }
+ end
+
before do
sandbox.add_member(user, Resource::Members::AccessLevel::MAINTAINER)
end
@@ -73,6 +78,8 @@ module QA
label.group = subgroup
label.title = "subgroup-#{SecureRandom.hex(4)}"
end
+
+ imported_group # trigger import
end
it(
@@ -87,6 +94,8 @@ module QA
expect(imported_subgroup.reload!).to eq(subgroup)
expect(imported_subgroup.labels).to include(*subgroup.labels)
+
+ expect(import_failures).to be_empty, "Expected no errors, received: #{import_failures}"
end
end
end
@@ -108,6 +117,8 @@ module QA
badge.link_url = "http://example.com/badge"
badge.image_url = "http://shields.io/badge"
end
+
+ imported_group # trigger import
end
it(
@@ -124,6 +135,8 @@ module QA
expect(imported_milestone.updated_at).to eq(source_milestone.updated_at)
expect(imported_group.badges).to eq(source_group.badges)
+
+ expect(import_failures).to be_empty, "Expected no errors, received: #{import_failures}"
end
end
end
@@ -139,6 +152,8 @@ module QA
before do
member.set_public_email
source_group.add_member(member, Resource::Members::AccessLevel::DEVELOPER)
+
+ imported_group # trigger import
end
after do
@@ -153,8 +168,11 @@ module QA
imported_member = imported_group.reload!.members.find { |usr| usr.username == member.username }
- expect(imported_member).not_to be_nil
- expect(imported_member.access_level).to eq(Resource::Members::AccessLevel::DEVELOPER)
+ aggregate_failures do
+ expect(imported_member).not_to be_nil
+ expect(imported_member.access_level).to eq(Resource::Members::AccessLevel::DEVELOPER)
+ expect(import_failures).to be_empty, "Expected no errors, received: #{import_failures}"
+ end
end
end
end
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index 68cccfa8bde..ce8bbf92cdf 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -1197,6 +1197,15 @@ RSpec.describe Projects::IssuesController do
end
end
+ context 'when trying to create a task' do
+ it 'defaults to issue type' do
+ issue = post_new_issue(issue_type: 'task')
+
+ expect(issue.issue_type).to eq('issue')
+ expect(issue.work_item_type.base_type).to eq('issue')
+ end
+ end
+
it 'creates the issue successfully', :aggregate_failures do
issue = post_new_issue
diff --git a/spec/finders/groups_finder_spec.rb b/spec/finders/groups_finder_spec.rb
index 10a08d7326e..a4cbee6a124 100644
--- a/spec/finders/groups_finder_spec.rb
+++ b/spec/finders/groups_finder_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe GroupsFinder do
include AdminModeHelper
- describe '#execute' do
+ shared_examples '#execute' do
let(:user) { create(:user) }
describe 'root level groups' do
@@ -20,6 +20,7 @@ RSpec.describe GroupsFinder do
user_private_group)
:regular | { all_available: false } | %i(user_public_group user_internal_group user_private_group)
:regular | {} | %i(public_group internal_group user_public_group user_internal_group user_private_group)
+ :regular | { min_access_level: Gitlab::Access::DEVELOPER } | %i(user_public_group user_internal_group user_private_group)
:external | { all_available: true } | %i(public_group user_public_group user_internal_group user_private_group)
:external | { all_available: false } | %i(user_public_group user_internal_group user_private_group)
@@ -261,4 +262,16 @@ RSpec.describe GroupsFinder do
end
end
end
+
+ describe '#execute' do
+ include_examples '#execute'
+
+ context 'when use_traversal_ids_groups_finder feature flags is disabled' do
+ before do
+ stub_feature_flags(use_traversal_ids_groups_finder: false)
+ end
+
+ include_examples '#execute'
+ end
+ end
end
diff --git a/spec/frontend/repository/components/blob_viewers/pdf_viewer_spec.js b/spec/frontend/repository/components/blob_viewers/pdf_viewer_spec.js
index adee5b90863..fd910002529 100644
--- a/spec/frontend/repository/components/blob_viewers/pdf_viewer_spec.js
+++ b/spec/frontend/repository/components/blob_viewers/pdf_viewer_spec.js
@@ -1,22 +1,59 @@
-import { shallowMount } from '@vue/test-utils';
+import { GlButton } from '@gitlab/ui';
import Component from '~/repository/components/blob_viewers/pdf_viewer.vue';
import PdfViewer from '~/blob/pdf/pdf_viewer.vue';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
describe('PDF Viewer', () => {
let wrapper;
- const propsData = { url: 'some/pdf_blob.pdf' };
+ const defaultPropsData = { url: 'some/pdf_blob.pdf' };
- const createComponent = () => {
- wrapper = shallowMount(Component, { propsData });
+ const createComponent = (fileSize = 999) => {
+ wrapper = shallowMountExtended(Component, { propsData: { ...defaultPropsData, fileSize } });
};
const findPDFViewer = () => wrapper.findComponent(PdfViewer);
+ const findHelpText = () => wrapper.find('p');
+ const findDownLoadButton = () => wrapper.findComponent(GlButton);
it('renders a PDF Viewer component', () => {
createComponent();
expect(findPDFViewer().exists()).toBe(true);
- expect(findPDFViewer().props('pdf')).toBe(propsData.url);
+ expect(findPDFViewer().props('pdf')).toBe(defaultPropsData.url);
+ });
+
+ describe('Too large', () => {
+ beforeEach(() => createComponent(20000000));
+
+ it('does not a PDF Viewer component', () => {
+ expect(findPDFViewer().exists()).toBe(false);
+ });
+
+ it('renders help text', () => {
+ expect(findHelpText().text()).toBe(
+ 'This PDF is too large to display. Please download to view.',
+ );
+ });
+
+ it('renders a download button', () => {
+ expect(findDownLoadButton().text()).toBe('Download PDF');
+ expect(findDownLoadButton().props('icon')).toBe('download');
+ });
+ });
+
+ describe('Too many pages', () => {
+ beforeEach(() => {
+ createComponent();
+ findPDFViewer().vm.$emit('pdflabload', 100);
+ });
+
+ it('does not a PDF Viewer component', () => {
+ expect(findPDFViewer().exists()).toBe(false);
+ });
+
+ it('renders a download button', () => {
+ expect(findDownLoadButton().exists()).toBe(true);
+ });
});
});
diff --git a/spec/graphql/types/issue_type_enum_spec.rb b/spec/graphql/types/issue_type_enum_spec.rb
index 7ae5eb76f28..131e92aa5ed 100644
--- a/spec/graphql/types/issue_type_enum_spec.rb
+++ b/spec/graphql/types/issue_type_enum_spec.rb
@@ -5,9 +5,9 @@ require 'spec_helper'
RSpec.describe Types::IssueTypeEnum do
specify { expect(described_class.graphql_name).to eq('IssueType') }
- it 'exposes all the existing issue type values' do
- expect(described_class.values.keys).to include(
- *%w[ISSUE INCIDENT]
+ it 'exposes all the existing issue type values except for task' do
+ expect(described_class.values.keys).to match_array(
+ %w[ISSUE INCIDENT TEST_CASE REQUIREMENT]
)
end
end
diff --git a/spec/migrations/20210804150320_create_base_work_item_types_spec.rb b/spec/migrations/20210804150320_create_base_work_item_types_spec.rb
index 34ea7f53f51..6df8e1b2ebf 100644
--- a/spec/migrations/20210804150320_create_base_work_item_types_spec.rb
+++ b/spec/migrations/20210804150320_create_base_work_item_types_spec.rb
@@ -4,18 +4,28 @@ require 'spec_helper'
require_migration!
RSpec.describe CreateBaseWorkItemTypes, :migration do
- let!(:work_item_types) { table(:work_item_types) }
+ include MigrationHelpers::WorkItemTypesHelper
+
+ let_it_be(:work_item_types) { table(:work_item_types) }
+
+ let(:base_types) do
+ {
+ issue: 0,
+ incident: 1,
+ test_case: 2,
+ requirement: 3
+ }
+ end
after(:all) do
# Make sure base types are recreated after running the migration
# because migration specs are not run in a transaction
- WorkItem::Type.delete_all
- Gitlab::DatabaseImporters::WorkItems::BaseTypeImporter.import
+ reset_work_item_types
end
it 'creates default data' do
# Need to delete all as base types are seeded before entire test suite
- WorkItem::Type.delete_all
+ work_item_types.delete_all
reversible_migration do |migration|
migration.before -> {
@@ -24,8 +34,8 @@ RSpec.describe CreateBaseWorkItemTypes, :migration do
}
migration.after -> {
- expect(work_item_types.count).to eq 4
- expect(work_item_types.all.pluck(:base_type)).to match_array WorkItem::Type.base_types.values
+ expect(work_item_types.count).to eq(4)
+ expect(work_item_types.all.pluck(:base_type)).to match_array(base_types.values)
}
end
end
diff --git a/spec/migrations/20210831203408_upsert_base_work_item_types_spec.rb b/spec/migrations/20210831203408_upsert_base_work_item_types_spec.rb
index 3c8c55ccb80..1957a973ee1 100644
--- a/spec/migrations/20210831203408_upsert_base_work_item_types_spec.rb
+++ b/spec/migrations/20210831203408_upsert_base_work_item_types_spec.rb
@@ -4,19 +4,29 @@ require 'spec_helper'
require_migration!
RSpec.describe UpsertBaseWorkItemTypes, :migration do
- let!(:work_item_types) { table(:work_item_types) }
+ include MigrationHelpers::WorkItemTypesHelper
+
+ let_it_be(:work_item_types) { table(:work_item_types) }
+
+ let(:base_types) do
+ {
+ issue: 0,
+ incident: 1,
+ test_case: 2,
+ requirement: 3
+ }
+ end
after(:all) do
# Make sure base types are recreated after running the migration
# because migration specs are not run in a transaction
- WorkItem::Type.delete_all
- Gitlab::DatabaseImporters::WorkItems::BaseTypeImporter.import
+ reset_work_item_types
end
context 'when no default types exist' do
it 'creates default data' do
# Need to delete all as base types are seeded before entire test suite
- WorkItem::Type.delete_all
+ work_item_types.delete_all
expect(work_item_types.count).to eq(0)
@@ -29,7 +39,7 @@ RSpec.describe UpsertBaseWorkItemTypes, :migration do
migration.after -> {
expect(work_item_types.count).to eq(4)
- expect(work_item_types.all.pluck(:base_type)).to match_array(WorkItem::Type.base_types.values)
+ expect(work_item_types.all.pluck(:base_type)).to match_array(base_types.values)
}
end
end
@@ -37,16 +47,21 @@ RSpec.describe UpsertBaseWorkItemTypes, :migration do
context 'when default types already exist' do
it 'does not create default types again' do
- expect(work_item_types.all.pluck(:base_type)).to match_array(WorkItem::Type.base_types.values)
+ # Database needs to be in a similar state as when this migration was created
+ work_item_types.delete_all
+ work_item_types.find_or_create_by!(name: 'Issue', namespace_id: nil, base_type: base_types[:issue], icon_name: 'issue-type-issue')
+ work_item_types.find_or_create_by!(name: 'Incident', namespace_id: nil, base_type: base_types[:incident], icon_name: 'issue-type-incident')
+ work_item_types.find_or_create_by!(name: 'Test Case', namespace_id: nil, base_type: base_types[:test_case], icon_name: 'issue-type-test-case')
+ work_item_types.find_or_create_by!(name: 'Requirement', namespace_id: nil, base_type: base_types[:requirement], icon_name: 'issue-type-requirements')
reversible_migration do |migration|
migration.before -> {
- expect(work_item_types.all.pluck(:base_type)).to match_array(WorkItem::Type.base_types.values)
+ expect(work_item_types.all.pluck(:base_type)).to match_array(base_types.values)
}
migration.after -> {
expect(work_item_types.count).to eq(4)
- expect(work_item_types.all.pluck(:base_type)).to match_array(WorkItem::Type.base_types.values)
+ expect(work_item_types.all.pluck(:base_type)).to match_array(base_types.values)
}
end
end
diff --git a/spec/migrations/20211126204445_add_task_to_work_item_types_spec.rb b/spec/migrations/20211126204445_add_task_to_work_item_types_spec.rb
new file mode 100644
index 00000000000..b80e4703f07
--- /dev/null
+++ b/spec/migrations/20211126204445_add_task_to_work_item_types_spec.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe AddTaskToWorkItemTypes, :migration do
+ include MigrationHelpers::WorkItemTypesHelper
+
+ let_it_be(:work_item_types) { table(:work_item_types) }
+
+ let(:base_types) do
+ {
+ issue: 0,
+ incident: 1,
+ test_case: 2,
+ requirement: 3,
+ task: 4
+ }
+ end
+
+ after(:all) do
+ # Make sure base types are recreated after running the migration
+ # because migration specs are not run in a transaction
+ reset_work_item_types
+ end
+
+ it 'skips creating the record if it already exists' do
+ reset_db_state_prior_to_migration
+ work_item_types.find_or_create_by!(name: 'Task', namespace_id: nil, base_type: base_types[:task], icon_name: 'issue-type-task')
+
+ expect do
+ migrate!
+ end.to not_change(work_item_types, :count)
+ end
+
+ it 'adds task to base work item types' do
+ reset_db_state_prior_to_migration
+
+ expect do
+ migrate!
+ end.to change(work_item_types, :count).from(4).to(5)
+
+ expect(work_item_types.all.pluck(:base_type)).to include(base_types[:task])
+ end
+
+ def reset_db_state_prior_to_migration
+ # Database needs to be in a similar state as when this migration was created
+ work_item_types.delete_all
+ work_item_types.find_or_create_by!(name: 'Issue', namespace_id: nil, base_type: base_types[:issue], icon_name: 'issue-type-issue')
+ work_item_types.find_or_create_by!(name: 'Incident', namespace_id: nil, base_type: base_types[:incident], icon_name: 'issue-type-incident')
+ work_item_types.find_or_create_by!(name: 'Test Case', namespace_id: nil, base_type: base_types[:test_case], icon_name: 'issue-type-test-case')
+ work_item_types.find_or_create_by!(name: 'Requirement', namespace_id: nil, base_type: base_types[:requirement], icon_name: 'issue-type-requirements')
+ end
+end
diff --git a/spec/migrations/20211203091642_add_index_to_projects_on_marked_for_deletion_at_spec.rb b/spec/migrations/20211203091642_add_index_to_projects_on_marked_for_deletion_at_spec.rb
new file mode 100644
index 00000000000..2e1289c58f7
--- /dev/null
+++ b/spec/migrations/20211203091642_add_index_to_projects_on_marked_for_deletion_at_spec.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe AddIndexToProjectsOnMarkedForDeletionAt do
+ it 'correctly migrates up and down' do
+ reversible_migration do |migration|
+ migration.before -> {
+ expect(ActiveRecord::Base.connection.indexes('projects').map(&:name)).not_to include('index_projects_not_aimed_for_deletion')
+ }
+
+ migration.after -> {
+ expect(ActiveRecord::Base.connection.indexes('projects').map(&:name)).to include('index_projects_not_aimed_for_deletion')
+ }
+ end
+ end
+end
diff --git a/spec/models/work_item/type_spec.rb b/spec/models/work_item/type_spec.rb
index dd5324d63a0..cc18558975b 100644
--- a/spec/models/work_item/type_spec.rb
+++ b/spec/models/work_item/type_spec.rb
@@ -19,10 +19,10 @@ RSpec.describe WorkItem::Type do
it 'deletes type but not unrelated issues' do
type = create(:work_item_type)
- expect(WorkItem::Type.count).to eq(5)
+ expect(WorkItem::Type.count).to eq(6)
expect { type.destroy! }.not_to change(Issue, :count)
- expect(WorkItem::Type.count).to eq(4)
+ expect(WorkItem::Type.count).to eq(5)
end
end
diff --git a/spec/requests/api/graphql/ci/jobs_spec.rb b/spec/requests/api/graphql/ci/jobs_spec.rb
index 692dc8bfd93..fab4c78ce7a 100644
--- a/spec/requests/api/graphql/ci/jobs_spec.rb
+++ b/spec/requests/api/graphql/ci/jobs_spec.rb
@@ -86,7 +86,7 @@ RSpec.describe 'Query.project.pipeline' do
create(:ci_build_need, build: test_job, name: 'my test job')
end
- it 'reports the build needs and execution requirements' do
+ it 'reports the build needs and execution requirements', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/347290' do
post_graphql(query, current_user: user)
expect(jobs_graphql_data).to contain_exactly(
diff --git a/spec/support/helpers/migrations_helpers/work_item_types_helper.rb b/spec/support/helpers/migrations_helpers/work_item_types_helper.rb
new file mode 100644
index 00000000000..59b1f1b1305
--- /dev/null
+++ b/spec/support/helpers/migrations_helpers/work_item_types_helper.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module MigrationHelpers
+ module WorkItemTypesHelper
+ DEFAULT_WORK_ITEM_TYPES = {
+ issue: { name: 'Issue', icon_name: 'issue-type-issue', enum_value: 0 },
+ incident: { name: 'Incident', icon_name: 'issue-type-incident', enum_value: 1 },
+ test_case: { name: 'Test Case', icon_name: 'issue-type-test-case', enum_value: 2 },
+ requirement: { name: 'Requirement', icon_name: 'issue-type-requirements', enum_value: 3 },
+ task: { name: 'Task', icon_name: 'issue-type-task', enum_value: 4 }
+ }.freeze
+
+ def reset_work_item_types
+ work_item_types_table.delete_all
+
+ DEFAULT_WORK_ITEM_TYPES.each do |type, attributes|
+ work_item_types_table.create!(base_type: attributes[:enum_value], **attributes.slice(:name, :icon_name))
+ end
+ end
+
+ private
+
+ def work_item_types_table
+ table(:work_item_types)
+ end
+ end
+end