summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-03-31 15:07:53 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-03-31 15:07:53 +0000
commitd7a028e20d29b8c6d0e780ac168544dfbb712d3c (patch)
treef9fc9ea12e166aec6c4ffe476ba7a3566396b696
parent0d0cddc9ce20c5a7d8a2723d0aa620ca184a711a (diff)
downloadgitlab-ce-d7a028e20d29b8c6d0e780ac168544dfbb712d3c.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--CHANGELOG-EE.md14
-rw-r--r--CHANGELOG.md19
-rw-r--r--app/assets/javascripts/registry/explorer/pages/details.vue3
-rw-r--r--app/assets/stylesheets/framework/header.scss2
-rw-r--r--app/assets/stylesheets/framework/variables.scss1
-rw-r--r--app/assets/stylesheets/pages/editor.scss4
-rw-r--r--app/graphql/mutations/jira_import/start.rb58
-rw-r--r--app/graphql/types/mutation_type.rb1
-rw-r--r--app/models/ci/build.rb2
-rw-r--r--app/models/ci/build_dependencies.rb85
-rw-r--r--app/models/ci/processable/dependencies.rb87
-rw-r--r--app/models/label_note.rb29
-rw-r--r--app/models/milestone_note.rb34
-rw-r--r--app/models/synthetic_note.rb50
-rw-r--r--app/views/admin/application_settings/_account_and_limit.html.haml9
-rw-r--r--changelogs/unreleased/197920-add-filter-by-name-option-to-the-package-list-view-user-interface.yml5
-rw-r--r--changelogs/unreleased/211660-jira-imports.yml5
-rw-r--r--changelogs/unreleased/212264-gcs-job-log-is-stored-with-content-type-invalid-invalid.yml5
-rw-r--r--changelogs/unreleased/docs-rename-skip-outdated-jobs.yml5
-rw-r--r--changelogs/unreleased/georgekoltsov-fix-issues-mrs-state.yml6
-rw-r--r--changelogs/unreleased/issue_11391_2.yml5
-rw-r--r--changelogs/unreleased/nicolasdular-storage-limit-settings.yml5
-rw-r--r--changelogs/unreleased/sh-check-features-table-gitaly.yml5
-rw-r--r--changelogs/unreleased/sh-disable-archive-rate-throttle-default.yml5
-rw-r--r--changelogs/unreleased/sh-fix-import-by-url-retries.yml5
-rw-r--r--changelogs/unreleased/start-jira-import-graphql-mutation.yml5
-rw-r--r--db/migrate/20200314060834_add_scanned_resources_count_to_security_scan.rb16
-rw-r--r--db/migrate/20200326114443_create_jira_imports_table.rb29
-rw-r--r--db/migrate/20200326124443_add_projects_fk_to_jira_imports_table.rb19
-rw-r--r--db/migrate/20200326134443_add_users_fk_to_jira_imports_table.rb19
-rw-r--r--db/migrate/20200326135443_add_users_fk_index_on_jira_imports_table.rb17
-rw-r--r--db/migrate/20200326144443_add_labels_fk_to_jira_imports_table.rb19
-rw-r--r--db/migrate/20200326145443_add_labels_fk_index_on_jira_imports_table.rb17
-rw-r--r--db/structure.sql57
-rw-r--r--doc/api/graphql/reference/gitlab_schema.graphql46
-rw-r--r--doc/api/graphql/reference/gitlab_schema.json153
-rw-r--r--doc/api/graphql/reference/index.md10
-rw-r--r--doc/install/installation.md7
-rw-r--r--doc/user/admin_area/settings/account_and_limit_settings.md13
-rw-r--r--lib/gitlab/ci/pipeline/chain/config/content.rb18
-rw-r--r--lib/gitlab/ci/pipeline/chain/config/content/legacy_auto_devops.rb34
-rw-r--r--lib/gitlab/ci/pipeline/chain/config/content/legacy_repository.rb31
-rw-r--r--locale/gitlab.pot36
-rw-r--r--spec/fixtures/api/schemas/entities/discussion.json2
-rw-r--r--spec/frontend/registry/explorer/pages/details_spec.js62
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb140
-rw-r--r--spec/models/ci/build_dependencies_spec.rb (renamed from spec/models/ci/processable/dependencies_spec.rb)2
-rw-r--r--spec/requests/api/graphql/mutations/jira_import/start_spec.rb130
-rw-r--r--spec/requests/api/project_clusters_spec.rb80
-rw-r--r--spec/support/helpers/stub_gitlab_calls.rb8
50 files changed, 951 insertions, 468 deletions
diff --git a/CHANGELOG-EE.md b/CHANGELOG-EE.md
index 2d1ef56eb69..c570a5d2fdf 100644
--- a/CHANGELOG-EE.md
+++ b/CHANGELOG-EE.md
@@ -1,5 +1,19 @@
Please view this file on the master branch, on stable branches it's out of date.
+## 12.9.2 (2020-03-31)
+
+### Fixed (4 changes)
+
+- Fix direct access to individual design on deprecated issue route. !27650
+- Fix error when viewing events from design notes on project activity page. !27840
+- Allow Seat Link to be disabled through configuration or admin toggle. !28015
+- Allow active_users param to be optional for SyncSeatLinkRequestWorker#perform. !28241
+
+### Changed (1 change)
+
+- Send active users for each day in seat link POST request. !27481
+
+
## 12.9.1 (2020-03-26)
### Security (1 change)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f5d55efc24a..d11761e0607 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,25 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
+## 12.9.2 (2020-03-31)
+
+### Fixed (5 changes)
+
+- Ensure import by URL works after a failed import. !27546
+- Fix issue/MR state not being preserved when importing a project using Project Import/Export. !27816
+- Leave upload Content-Type unchaged. !27864
+- Disable archive rate limit by default. !28264
+- Fix rake gitlab:setup failing on new installs. !28270
+
+### Changed (1 change)
+
+- Rename feature on the FE and locale.
+
+### Performance (1 change)
+
+- Index issues on sent_notifications table. !27034
+
+
## 12.9.1 (2020-03-26)
### Security (16 changes)
diff --git a/app/assets/javascripts/registry/explorer/pages/details.vue b/app/assets/javascripts/registry/explorer/pages/details.vue
index 68a066f97e1..b558ed51a5b 100644
--- a/app/assets/javascripts/registry/explorer/pages/details.vue
+++ b/app/assets/javascripts/registry/explorer/pages/details.vue
@@ -77,9 +77,10 @@ export default {
return name;
},
fields() {
+ const tagClass = this.isDesktop ? 'w-25' : '';
return [
{ key: LIST_KEY_CHECKBOX, label: '', class: 'gl-w-16' },
- { key: LIST_KEY_TAG, label: LIST_LABEL_TAG, class: 'w-25' },
+ { key: LIST_KEY_TAG, label: LIST_LABEL_TAG, class: `${tagClass} js-tag-column` },
{ key: LIST_KEY_IMAGE_ID, label: LIST_LABEL_IMAGE_ID },
{ key: LIST_KEY_SIZE, label: LIST_LABEL_SIZE },
{ key: LIST_KEY_LAST_UPDATED, label: LIST_LABEL_LAST_UPDATED },
diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss
index 3792e6cb0a6..a0a020ec548 100644
--- a/app/assets/stylesheets/framework/header.scss
+++ b/app/assets/stylesheets/framework/header.scss
@@ -1,6 +1,6 @@
.navbar-gitlab {
padding: 0 16px;
- z-index: 1000;
+ z-index: $header-zindex;
margin-bottom: 0;
min-height: $header-height;
border: 0;
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index b4ed6587fca..a3c1d8b1709 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -418,6 +418,7 @@ $browser-scrollbar-size: 10px;
* Misc
*/
$header-height: 40px;
+$header-zindex: 1000;
$suggestion-header-height: 46px;
$ide-statusbar-height: 25px;
$fixed-layout-width: 1280px;
diff --git a/app/assets/stylesheets/pages/editor.scss b/app/assets/stylesheets/pages/editor.scss
index b716c6e14fe..eb9684c7b3c 100644
--- a/app/assets/stylesheets/pages/editor.scss
+++ b/app/assets/stylesheets/pages/editor.scss
@@ -221,3 +221,7 @@
.editor-title-row {
margin-bottom: 20px;
}
+
+.popover.suggest-gitlab-ci-yml {
+ z-index: $header-zindex - 1;
+}
diff --git a/app/graphql/mutations/jira_import/start.rb b/app/graphql/mutations/jira_import/start.rb
new file mode 100644
index 00000000000..ffd3ce53b57
--- /dev/null
+++ b/app/graphql/mutations/jira_import/start.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+module Mutations
+ module JiraImport
+ class Start < BaseMutation
+ include Mutations::ResolvesProject
+
+ graphql_name 'JiraImportStart'
+
+ field :jira_import,
+ Types::JiraImportType,
+ null: true,
+ description: 'The Jira import data after mutation'
+
+ argument :project_path, GraphQL::ID_TYPE,
+ required: true,
+ description: 'The project to import the Jira project into'
+ argument :jira_project_key, GraphQL::STRING_TYPE,
+ required: true,
+ description: 'Project key of the importer Jira project'
+ argument :jira_project_name, GraphQL::STRING_TYPE,
+ required: false,
+ description: 'Project name of the importer Jira project'
+
+ def resolve(project_path:, jira_project_key:)
+ project = find_project!(project_path: project_path)
+
+ raise_resource_not_available_error! unless project
+
+ service_response = ::JiraImport::StartImportService
+ .new(context[:current_user], project, jira_project_key)
+ .execute
+ import_data = service_response.payload[:import_data]
+
+ {
+ jira_import: import_data.errors.blank? ? import_data.projects.last : nil,
+ errors: errors_on_object(import_data)
+ }
+ end
+
+ private
+
+ def find_project!(project_path:)
+ return unless project_path.present?
+
+ authorized_find!(full_path: project_path)
+ end
+
+ def find_object(full_path:)
+ resolve_project(full_path: full_path)
+ end
+
+ def authorized_resource?(project)
+ Ability.allowed?(context[:current_user], :admin_project, project)
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb
index d3c0d9732d2..ab25d5baf71 100644
--- a/app/graphql/types/mutation_type.rb
+++ b/app/graphql/types/mutation_type.rb
@@ -39,6 +39,7 @@ module Types
mount_mutation Mutations::Snippets::Update
mount_mutation Mutations::Snippets::Create
mount_mutation Mutations::Snippets::MarkAsSpam
+ mount_mutation Mutations::JiraImport::Start
end
end
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index fb9e341dff7..5b794f7ccf0 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -914,7 +914,7 @@ module Ci
def dependencies
strong_memoize(:dependencies) do
- Ci::Processable::Dependencies.new(self)
+ Ci::BuildDependencies.new(self)
end
end
diff --git a/app/models/ci/build_dependencies.rb b/app/models/ci/build_dependencies.rb
new file mode 100644
index 00000000000..b5d67ef8e96
--- /dev/null
+++ b/app/models/ci/build_dependencies.rb
@@ -0,0 +1,85 @@
+# frozen_string_literal: true
+
+module Ci
+ class BuildDependencies
+ attr_reader :processable
+
+ def initialize(processable)
+ @processable = processable
+ end
+
+ def all
+ (local + cross_pipeline).uniq
+ end
+
+ # Dependencies local to the given pipeline
+ def local
+ return [] if no_local_dependencies_specified?
+
+ deps = model_class.where(pipeline_id: processable.pipeline_id).latest
+ deps = from_previous_stages(deps)
+ deps = from_needs(deps)
+ deps = from_dependencies(deps)
+ deps
+ end
+
+ # Dependencies that are defined in other pipelines
+ def cross_pipeline
+ []
+ end
+
+ def invalid_local
+ local.reject(&:valid_dependency?)
+ end
+
+ def valid?
+ valid_local? && valid_cross_pipeline?
+ end
+
+ private
+
+ # Dependencies can only be of Ci::Build type because only builds
+ # can create artifacts
+ def model_class
+ ::Ci::Build
+ end
+
+ def valid_local?
+ return true if Feature.enabled?('ci_disable_validates_dependencies')
+
+ local.all?(&:valid_dependency?)
+ end
+
+ def valid_cross_pipeline?
+ true
+ end
+
+ def project
+ processable.project
+ end
+
+ def no_local_dependencies_specified?
+ processable.options[:dependencies]&.empty?
+ end
+
+ def from_previous_stages(scope)
+ scope.before_stage(processable.stage_idx)
+ end
+
+ def from_needs(scope)
+ return scope unless Feature.enabled?(:ci_dag_support, project, default_enabled: true)
+ return scope unless processable.scheduling_type_dag?
+
+ needs_names = processable.needs.artifacts.select(:name)
+ scope.where(name: needs_names)
+ end
+
+ def from_dependencies(scope)
+ return scope unless processable.options[:dependencies].present?
+
+ scope.where(name: processable.options[:dependencies])
+ end
+ end
+end
+
+Ci::BuildDependencies.prepend_if_ee('EE::Ci::BuildDependencies')
diff --git a/app/models/ci/processable/dependencies.rb b/app/models/ci/processable/dependencies.rb
deleted file mode 100644
index 9d42ac4dc00..00000000000
--- a/app/models/ci/processable/dependencies.rb
+++ /dev/null
@@ -1,87 +0,0 @@
-# frozen_string_literal: true
-
-module Ci
- class Processable
- class Dependencies
- attr_reader :processable
-
- def initialize(processable)
- @processable = processable
- end
-
- def all
- (local + cross_pipeline).uniq
- end
-
- # Dependencies local to the given pipeline
- def local
- return [] if no_local_dependencies_specified?
-
- deps = model_class.where(pipeline_id: processable.pipeline_id).latest
- deps = from_previous_stages(deps)
- deps = from_needs(deps)
- deps = from_dependencies(deps)
- deps
- end
-
- # Dependencies that are defined in other pipelines
- def cross_pipeline
- []
- end
-
- def invalid_local
- local.reject(&:valid_dependency?)
- end
-
- def valid?
- valid_local? && valid_cross_pipeline?
- end
-
- private
-
- # Dependencies can only be of Ci::Build type because only builds
- # can create artifacts
- def model_class
- ::Ci::Build
- end
-
- def valid_local?
- return true if Feature.enabled?('ci_disable_validates_dependencies')
-
- local.all?(&:valid_dependency?)
- end
-
- def valid_cross_pipeline?
- true
- end
-
- def project
- processable.project
- end
-
- def no_local_dependencies_specified?
- processable.options[:dependencies]&.empty?
- end
-
- def from_previous_stages(scope)
- scope.before_stage(processable.stage_idx)
- end
-
- def from_needs(scope)
- return scope unless Feature.enabled?(:ci_dag_support, project, default_enabled: true)
- return scope unless processable.scheduling_type_dag?
-
- needs_names = processable.needs.artifacts.select(:name)
- scope.where(name: needs_names)
- end
-
- def from_dependencies(scope)
- return scope unless processable.options[:dependencies].present?
-
- scope.where(name: processable.options[:dependencies])
- end
- end
- end
-end
-
-Ci::Processable::Dependencies.prepend_if_ee('EE::Ci::Processable::Dependencies')
diff --git a/app/models/label_note.rb b/app/models/label_note.rb
index 13a2e1b0c72..e90028ce835 100644
--- a/app/models/label_note.rb
+++ b/app/models/label_note.rb
@@ -1,26 +1,13 @@
# frozen_string_literal: true
-class LabelNote < Note
+class LabelNote < SyntheticNote
attr_accessor :resource_parent
attr_reader :events
def self.from_events(events, resource: nil, resource_parent: nil)
resource ||= events.first.issuable
- attrs = {
- system: true,
- author: events.first.user,
- created_at: events.first.created_at,
- discussion_id: events.first.discussion_id,
- noteable: resource,
- system_note_metadata: SystemNoteMetadata.new(action: 'label'),
- events: events,
- resource_parent: resource_parent
- }
-
- if resource_parent.is_a?(Project)
- attrs[:project_id] = resource_parent.id
- end
+ attrs = note_attributes('label', events.first, resource, resource_parent).merge(events: events)
LabelNote.new(attrs)
end
@@ -35,22 +22,10 @@ class LabelNote < Note
true
end
- def note
- @note ||= note_text
- end
-
def note_html
@note_html ||= "<p dir=\"auto\">#{note_text(html: true)}</p>"
end
- def project
- resource_parent if resource_parent.is_a?(Project)
- end
-
- def group
- resource_parent if resource_parent.is_a?(Group)
- end
-
private
def update_outdated_markdown
diff --git a/app/models/milestone_note.rb b/app/models/milestone_note.rb
index 4b027b0782c..2ff9791feb0 100644
--- a/app/models/milestone_note.rb
+++ b/app/models/milestone_note.rb
@@ -1,46 +1,18 @@
# frozen_string_literal: true
-class MilestoneNote < ::Note
- attr_accessor :resource_parent, :event, :milestone
+class MilestoneNote < SyntheticNote
+ attr_accessor :milestone
def self.from_event(event, resource: nil, resource_parent: nil)
- resource ||= event.resource
-
- attrs = {
- system: true,
- author: event.user,
- created_at: event.created_at,
- noteable: resource,
- milestone: event.milestone,
- discussion_id: event.discussion_id,
- event: event,
- system_note_metadata: ::SystemNoteMetadata.new(action: 'milestone'),
- resource_parent: resource_parent
- }
-
- if resource_parent.is_a?(Project)
- attrs[:project_id] = resource_parent.id
- end
+ attrs = note_attributes('milestone', event, resource, resource_parent).merge(milestone: event.milestone)
MilestoneNote.new(attrs)
end
- def note
- @note ||= note_text
- end
-
def note_html
@note_html ||= Banzai::Renderer.cacheless_render_field(self, :note, { group: group, project: project })
end
- def project
- resource_parent if resource_parent.is_a?(Project)
- end
-
- def group
- resource_parent if resource_parent.is_a?(Group)
- end
-
private
def note_text(html: false)
diff --git a/app/models/synthetic_note.rb b/app/models/synthetic_note.rb
new file mode 100644
index 00000000000..3017140f871
--- /dev/null
+++ b/app/models/synthetic_note.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+class SyntheticNote < Note
+ attr_accessor :resource_parent, :event
+
+ self.abstract_class = true
+
+ def self.note_attributes(action, event, resource, resource_parent)
+ resource ||= event.resource
+
+ attrs = {
+ system: true,
+ author: event.user,
+ created_at: event.created_at,
+ discussion_id: event.discussion_id,
+ noteable: resource,
+ event: event,
+ system_note_metadata: ::SystemNoteMetadata.new(action: action),
+ resource_parent: resource_parent
+ }
+
+ if resource_parent.is_a?(Project)
+ attrs[:project_id] = resource_parent.id
+ end
+
+ attrs
+ end
+
+ def project
+ resource_parent if resource_parent.is_a?(Project)
+ end
+
+ def group
+ resource_parent if resource_parent.is_a?(Group)
+ end
+
+ def note
+ @note ||= note_text
+ end
+
+ def note_html
+ raise NotImplementedError
+ end
+
+ private
+
+ def note_text(html: false)
+ raise NotImplementedError
+ end
+end
diff --git a/app/views/admin/application_settings/_account_and_limit.html.haml b/app/views/admin/application_settings/_account_and_limit.html.haml
index aa377886edc..94a7a1be455 100644
--- a/app/views/admin/application_settings/_account_and_limit.html.haml
+++ b/app/views/admin/application_settings/_account_and_limit.html.haml
@@ -7,6 +7,15 @@
= f.check_box :gravatar_enabled, class: 'form-check-input'
= f.label :gravatar_enabled, class: 'form-check-label' do
= _('Gravatar enabled')
+
+ .form-group
+ = f.label :namespace_storage_size_limit, class: 'label-bold' do
+ = _('Maximum namespace storage (MB)')
+ = f.number_field :namespace_storage_size_limit, class: 'form-control', min: 0
+ %span.form-text.text-muted
+ = _('Includes repository storage, wiki storage, LFS objects, build artifacts and packages. 0 for unlimited.')
+ = link_to _('More information'), help_page_path('user/admin_area/settings/account_and_limit_settings', anchor: 'maximum-namespace-storage-size'), target: '_blank'
+
.form-group
= f.label :default_projects_limit, _('Default projects limit'), class: 'label-bold'
= f.number_field :default_projects_limit, class: 'form-control', title: _('Maximum number of projects.'), data: { toggle: 'tooltip', container: 'body' }
diff --git a/changelogs/unreleased/197920-add-filter-by-name-option-to-the-package-list-view-user-interface.yml b/changelogs/unreleased/197920-add-filter-by-name-option-to-the-package-list-view-user-interface.yml
new file mode 100644
index 00000000000..2e7fb9ffacf
--- /dev/null
+++ b/changelogs/unreleased/197920-add-filter-by-name-option-to-the-package-list-view-user-interface.yml
@@ -0,0 +1,5 @@
+---
+title: Adds filter by name to the packages list
+merge_request: 27586
+author:
+type: added
diff --git a/changelogs/unreleased/211660-jira-imports.yml b/changelogs/unreleased/211660-jira-imports.yml
new file mode 100644
index 00000000000..210e55440dd
--- /dev/null
+++ b/changelogs/unreleased/211660-jira-imports.yml
@@ -0,0 +1,5 @@
+---
+title: Add jira_imports table to track current jira import progress as well as historical imports data
+merge_request: 28108
+author:
+type: added
diff --git a/changelogs/unreleased/212264-gcs-job-log-is-stored-with-content-type-invalid-invalid.yml b/changelogs/unreleased/212264-gcs-job-log-is-stored-with-content-type-invalid-invalid.yml
deleted file mode 100644
index e6b9528780d..00000000000
--- a/changelogs/unreleased/212264-gcs-job-log-is-stored-with-content-type-invalid-invalid.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Leave upload Content-Type unchaged
-merge_request: 27864
-author:
-type: fixed
diff --git a/changelogs/unreleased/docs-rename-skip-outdated-jobs.yml b/changelogs/unreleased/docs-rename-skip-outdated-jobs.yml
deleted file mode 100644
index 2f11cbcc484..00000000000
--- a/changelogs/unreleased/docs-rename-skip-outdated-jobs.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Rename feature on the FE and locale
-merge_request:
-author:
-type: changed
diff --git a/changelogs/unreleased/georgekoltsov-fix-issues-mrs-state.yml b/changelogs/unreleased/georgekoltsov-fix-issues-mrs-state.yml
deleted file mode 100644
index 018a14121e4..00000000000
--- a/changelogs/unreleased/georgekoltsov-fix-issues-mrs-state.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: Fix issue/MR state not being preserved when importing a project using Project
- Import/Export
-merge_request: 27816
-author:
-type: fixed
diff --git a/changelogs/unreleased/issue_11391_2.yml b/changelogs/unreleased/issue_11391_2.yml
deleted file mode 100644
index c59ac2d9ae4..00000000000
--- a/changelogs/unreleased/issue_11391_2.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Index issues on sent_notifications table
-merge_request: 27034
-author:
-type: performance
diff --git a/changelogs/unreleased/nicolasdular-storage-limit-settings.yml b/changelogs/unreleased/nicolasdular-storage-limit-settings.yml
new file mode 100644
index 00000000000..4f8a9a19772
--- /dev/null
+++ b/changelogs/unreleased/nicolasdular-storage-limit-settings.yml
@@ -0,0 +1,5 @@
+---
+title: Add namespace storage size limit setting
+merge_request:
+author:
+type: added
diff --git a/changelogs/unreleased/sh-check-features-table-gitaly.yml b/changelogs/unreleased/sh-check-features-table-gitaly.yml
deleted file mode 100644
index e9ae3e89a08..00000000000
--- a/changelogs/unreleased/sh-check-features-table-gitaly.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix rake gitlab:setup failing on new installs
-merge_request: 28270
-author:
-type: fixed
diff --git a/changelogs/unreleased/sh-disable-archive-rate-throttle-default.yml b/changelogs/unreleased/sh-disable-archive-rate-throttle-default.yml
deleted file mode 100644
index f9786f4e388..00000000000
--- a/changelogs/unreleased/sh-disable-archive-rate-throttle-default.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Disable archive rate limit by default
-merge_request: 28264
-author:
-type: fixed
diff --git a/changelogs/unreleased/sh-fix-import-by-url-retries.yml b/changelogs/unreleased/sh-fix-import-by-url-retries.yml
deleted file mode 100644
index b66026f4891..00000000000
--- a/changelogs/unreleased/sh-fix-import-by-url-retries.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Ensure import by URL works after a failed import
-merge_request: 27546
-author:
-type: fixed
diff --git a/changelogs/unreleased/start-jira-import-graphql-mutation.yml b/changelogs/unreleased/start-jira-import-graphql-mutation.yml
new file mode 100644
index 00000000000..0d9bd8dac1b
--- /dev/null
+++ b/changelogs/unreleased/start-jira-import-graphql-mutation.yml
@@ -0,0 +1,5 @@
+---
+title: Allow to start Jira import through graphql mutation
+merge_request: 27684
+author:
+type: added
diff --git a/db/migrate/20200314060834_add_scanned_resources_count_to_security_scan.rb b/db/migrate/20200314060834_add_scanned_resources_count_to_security_scan.rb
new file mode 100644
index 00000000000..e8f7a693e99
--- /dev/null
+++ b/db/migrate/20200314060834_add_scanned_resources_count_to_security_scan.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+class AddScannedResourcesCountToSecurityScan < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_column :security_scans, :scanned_resources_count, :integer
+ end
+
+ def down
+ remove_column :security_scans, :scanned_resources_count
+ end
+end
diff --git a/db/migrate/20200326114443_create_jira_imports_table.rb b/db/migrate/20200326114443_create_jira_imports_table.rb
new file mode 100644
index 00000000000..e114bd513f4
--- /dev/null
+++ b/db/migrate/20200326114443_create_jira_imports_table.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+class CreateJiraImportsTable < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def change
+ create_table :jira_imports do |t|
+ t.integer :project_id, null: false, limit: 8
+ t.integer :user_id, limit: 8
+ t.integer :label_id, limit: 8
+ t.timestamps_with_timezone
+ t.datetime_with_timezone :finished_at
+ t.integer :jira_project_xid, null: false, limit: 8
+ t.integer :total_issue_count, null: false, default: 0, limit: 4
+ t.integer :imported_issues_count, null: false, default: 0, limit: 4
+ t.integer :failed_to_import_count, null: false, default: 0, limit: 4
+ t.integer :status, limit: 2, null: false, default: 0
+ t.string :jid, limit: 255
+ t.string :jira_project_key, null: false, limit: 255
+ t.string :jira_project_name, null: false, limit: 255
+ end
+
+ add_index :jira_imports, [:project_id, :jira_project_key], name: 'index_jira_imports_on_project_id_and_jira_project_key'
+ end
+end
diff --git a/db/migrate/20200326124443_add_projects_fk_to_jira_imports_table.rb b/db/migrate/20200326124443_add_projects_fk_to_jira_imports_table.rb
new file mode 100644
index 00000000000..6410f530b30
--- /dev/null
+++ b/db/migrate/20200326124443_add_projects_fk_to_jira_imports_table.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class AddProjectsFkToJiraImportsTable < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def up
+ with_lock_retries do
+ add_foreign_key :jira_imports, :projects, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ end
+ end
+
+ def down
+ with_lock_retries do
+ remove_foreign_key :jira_imports, :projects
+ end
+ end
+end
diff --git a/db/migrate/20200326134443_add_users_fk_to_jira_imports_table.rb b/db/migrate/20200326134443_add_users_fk_to_jira_imports_table.rb
new file mode 100644
index 00000000000..0956a8e814b
--- /dev/null
+++ b/db/migrate/20200326134443_add_users_fk_to_jira_imports_table.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class AddUsersFkToJiraImportsTable < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def up
+ with_lock_retries do
+ add_foreign_key :jira_imports, :users, on_delete: :nullify # rubocop:disable Migration/AddConcurrentForeignKey
+ end
+ end
+
+ def down
+ with_lock_retries do
+ remove_foreign_key :jira_imports, :users
+ end
+ end
+end
diff --git a/db/migrate/20200326135443_add_users_fk_index_on_jira_imports_table.rb b/db/migrate/20200326135443_add_users_fk_index_on_jira_imports_table.rb
new file mode 100644
index 00000000000..5a26672f305
--- /dev/null
+++ b/db/migrate/20200326135443_add_users_fk_index_on_jira_imports_table.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddUsersFkIndexOnJiraImportsTable < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :jira_imports, :user_id
+ end
+
+ def down
+ remove_concurrent_index :jira_imports, :user_id
+ end
+end
diff --git a/db/migrate/20200326144443_add_labels_fk_to_jira_imports_table.rb b/db/migrate/20200326144443_add_labels_fk_to_jira_imports_table.rb
new file mode 100644
index 00000000000..ead04100a96
--- /dev/null
+++ b/db/migrate/20200326144443_add_labels_fk_to_jira_imports_table.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class AddLabelsFkToJiraImportsTable < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def up
+ with_lock_retries do
+ add_foreign_key :jira_imports, :labels, on_delete: :nullify # rubocop:disable Migration/AddConcurrentForeignKey
+ end
+ end
+
+ def down
+ with_lock_retries do
+ remove_foreign_key :jira_imports, :labels
+ end
+ end
+end
diff --git a/db/migrate/20200326145443_add_labels_fk_index_on_jira_imports_table.rb b/db/migrate/20200326145443_add_labels_fk_index_on_jira_imports_table.rb
new file mode 100644
index 00000000000..d71c6f07989
--- /dev/null
+++ b/db/migrate/20200326145443_add_labels_fk_index_on_jira_imports_table.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddLabelsFkIndexOnJiraImportsTable < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :jira_imports, :label_id
+ end
+
+ def down
+ remove_concurrent_index :jira_imports, :label_id
+ end
+end
diff --git a/db/structure.sql b/db/structure.sql
index 6c807ccc5df..1a4b8582ab0 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -3304,6 +3304,33 @@ CREATE SEQUENCE public.jira_connect_subscriptions_id_seq
ALTER SEQUENCE public.jira_connect_subscriptions_id_seq OWNED BY public.jira_connect_subscriptions.id;
+CREATE TABLE public.jira_imports (
+ id bigint NOT NULL,
+ project_id bigint NOT NULL,
+ user_id bigint,
+ label_id bigint,
+ created_at timestamp with time zone NOT NULL,
+ updated_at timestamp with time zone NOT NULL,
+ finished_at timestamp with time zone,
+ jira_project_xid bigint NOT NULL,
+ total_issue_count integer DEFAULT 0 NOT NULL,
+ imported_issues_count integer DEFAULT 0 NOT NULL,
+ failed_to_import_count integer DEFAULT 0 NOT NULL,
+ status smallint DEFAULT 0 NOT NULL,
+ jid character varying(255),
+ jira_project_key character varying(255) NOT NULL,
+ jira_project_name character varying(255) NOT NULL
+);
+
+CREATE SEQUENCE public.jira_imports_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE public.jira_imports_id_seq OWNED BY public.jira_imports.id;
+
CREATE TABLE public.jira_tracker_data (
id bigint NOT NULL,
service_id integer NOT NULL,
@@ -5558,7 +5585,8 @@ CREATE TABLE public.security_scans (
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
build_id bigint NOT NULL,
- scan_type smallint NOT NULL
+ scan_type smallint NOT NULL,
+ scanned_resources_count integer
);
CREATE SEQUENCE public.security_scans_id_seq
@@ -7119,6 +7147,8 @@ ALTER TABLE ONLY public.jira_connect_installations ALTER COLUMN id SET DEFAULT n
ALTER TABLE ONLY public.jira_connect_subscriptions ALTER COLUMN id SET DEFAULT nextval('public.jira_connect_subscriptions_id_seq'::regclass);
+ALTER TABLE ONLY public.jira_imports ALTER COLUMN id SET DEFAULT nextval('public.jira_imports_id_seq'::regclass);
+
ALTER TABLE ONLY public.jira_tracker_data ALTER COLUMN id SET DEFAULT nextval('public.jira_tracker_data_id_seq'::regclass);
ALTER TABLE ONLY public.keys ALTER COLUMN id SET DEFAULT nextval('public.keys_id_seq'::regclass);
@@ -7872,6 +7902,9 @@ ALTER TABLE ONLY public.jira_connect_installations
ALTER TABLE ONLY public.jira_connect_subscriptions
ADD CONSTRAINT jira_connect_subscriptions_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY public.jira_imports
+ ADD CONSTRAINT jira_imports_pkey PRIMARY KEY (id);
+
ALTER TABLE ONLY public.jira_tracker_data
ADD CONSTRAINT jira_tracker_data_pkey PRIMARY KEY (id);
@@ -9243,6 +9276,12 @@ CREATE UNIQUE INDEX index_jira_connect_installations_on_client_key ON public.jir
CREATE INDEX index_jira_connect_subscriptions_on_namespace_id ON public.jira_connect_subscriptions USING btree (namespace_id);
+CREATE INDEX index_jira_imports_on_label_id ON public.jira_imports USING btree (label_id);
+
+CREATE INDEX index_jira_imports_on_project_id_and_jira_project_key ON public.jira_imports USING btree (project_id, jira_project_key);
+
+CREATE INDEX index_jira_imports_on_user_id ON public.jira_imports USING btree (user_id);
+
CREATE INDEX index_jira_tracker_data_on_service_id ON public.jira_tracker_data USING btree (service_id);
CREATE UNIQUE INDEX index_keys_on_fingerprint ON public.keys USING btree (fingerprint);
@@ -11218,6 +11257,9 @@ ALTER TABLE ONLY public.deployment_clusters
ALTER TABLE ONLY public.evidences
ADD CONSTRAINT fk_rails_6388b435a6 FOREIGN KEY (release_id) REFERENCES public.releases(id) ON DELETE CASCADE;
+ALTER TABLE ONLY public.jira_imports
+ ADD CONSTRAINT fk_rails_63cbe52ada FOREIGN KEY (project_id) REFERENCES public.projects(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY public.vulnerability_occurrence_pipelines
ADD CONSTRAINT fk_rails_6421e35d7d FOREIGN KEY (pipeline_id) REFERENCES public.ci_pipelines(id) ON DELETE CASCADE;
@@ -11257,6 +11299,9 @@ ALTER TABLE ONLY public.operations_feature_flags_clients
ALTER TABLE ONLY public.web_hook_logs
ADD CONSTRAINT fk_rails_666826e111 FOREIGN KEY (web_hook_id) REFERENCES public.web_hooks(id) ON DELETE CASCADE;
+ALTER TABLE ONLY public.jira_imports
+ ADD CONSTRAINT fk_rails_675d38c03b FOREIGN KEY (label_id) REFERENCES public.labels(id) ON DELETE SET NULL;
+
ALTER TABLE ONLY public.geo_hashed_storage_migrated_events
ADD CONSTRAINT fk_rails_687ed7d7c5 FOREIGN KEY (project_id) REFERENCES public.projects(id) ON DELETE CASCADE;
@@ -11671,6 +11716,9 @@ ALTER TABLE ONLY public.vulnerability_issue_links
ALTER TABLE ONLY public.geo_hashed_storage_attachments_events
ADD CONSTRAINT fk_rails_d496b088e9 FOREIGN KEY (project_id) REFERENCES public.projects(id) ON DELETE CASCADE;
+ALTER TABLE ONLY public.jira_imports
+ ADD CONSTRAINT fk_rails_da617096ce FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE SET NULL;
+
ALTER TABLE ONLY public.dependency_proxy_blobs
ADD CONSTRAINT fk_rails_db58bbc5d7 FOREIGN KEY (group_id) REFERENCES public.namespaces(id) ON DELETE CASCADE;
@@ -12826,6 +12874,7 @@ COPY "schema_migrations" (version) FROM STDIN;
20200312163407
20200313101649
20200313123934
+20200314060834
20200316111759
20200316162648
20200316173312
@@ -12854,5 +12903,11 @@ COPY "schema_migrations" (version) FROM STDIN;
20200325152327
20200325160952
20200325183636
+20200326114443
+20200326124443
+20200326134443
+20200326135443
+20200326144443
+20200326145443
\.
diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql
index 3ebdd8d37dd..3a07bec7813 100644
--- a/doc/api/graphql/reference/gitlab_schema.graphql
+++ b/doc/api/graphql/reference/gitlab_schema.graphql
@@ -4155,6 +4155,51 @@ type JiraImportEdge {
node: JiraImport
}
+"""
+Autogenerated input type of JiraImportStart
+"""
+input JiraImportStartInput {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Project key of the importer Jira project
+ """
+ jiraProjectKey: String!
+
+ """
+ Project name of the importer Jira project
+ """
+ jiraProjectName: String
+
+ """
+ The project to import the Jira project into
+ """
+ projectPath: ID!
+}
+
+"""
+Autogenerated return type of JiraImportStart
+"""
+type JiraImportStartPayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Reasons why the mutation failed.
+ """
+ errors: [String!]!
+
+ """
+ The Jira import data after mutation
+ """
+ jiraImport: JiraImport
+}
+
type Label {
"""
Background color of the label
@@ -5180,6 +5225,7 @@ type Mutation {
issueSetConfidential(input: IssueSetConfidentialInput!): IssueSetConfidentialPayload
issueSetDueDate(input: IssueSetDueDateInput!): IssueSetDueDatePayload
issueSetWeight(input: IssueSetWeightInput!): IssueSetWeightPayload
+ jiraImportStart(input: JiraImportStartInput!): JiraImportStartPayload
markAsSpamSnippet(input: MarkAsSpamSnippetInput!): MarkAsSpamSnippetPayload
mergeRequestSetAssignees(input: MergeRequestSetAssigneesInput!): MergeRequestSetAssigneesPayload
mergeRequestSetLabels(input: MergeRequestSetLabelsInput!): MergeRequestSetLabelsPayload
diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json
index 735befc3459..9c854e064e7 100644
--- a/doc/api/graphql/reference/gitlab_schema.json
+++ b/doc/api/graphql/reference/gitlab_schema.json
@@ -11811,6 +11811,132 @@
"possibleTypes": null
},
{
+ "kind": "INPUT_OBJECT",
+ "name": "JiraImportStartInput",
+ "description": "Autogenerated input type of JiraImportStart",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "projectPath",
+ "description": "The project to import the Jira project into",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "jiraProjectKey",
+ "description": "Project key of the importer Jira project",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "jiraProjectName",
+ "description": "Project name of the importer Jira project",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "JiraImportStartPayload",
+ "description": "Autogenerated return type of JiraImportStart",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Reasons why the mutation failed.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "jiraImport",
+ "description": "The Jira import data after mutation",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "JiraImport",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "OBJECT",
"name": "Label",
"description": null,
@@ -15291,6 +15417,33 @@
"deprecationReason": null
},
{
+ "name": "jiraImportStart",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "JiraImportStartInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "JiraImportStartPayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "markAsSpamSnippet",
"description": null,
"args": [
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 995cf3a0073..2a1c501e785 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -614,6 +614,16 @@ Autogenerated return type of IssueSetWeight
| `scheduledAt` | Time | Timestamp of when the Jira import was created/started |
| `scheduledBy` | User | User that started the Jira import |
+## JiraImportStartPayload
+
+Autogenerated return type of JiraImportStart
+
+| Name | Type | Description |
+| --- | ---- | ---------- |
+| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
+| `errors` | String! => Array | Reasons why the mutation failed. |
+| `jiraImport` | JiraImport | The Jira import data after mutation |
+
## Label
| Name | Type | Description |
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 84cbc929c66..9523b67f1d6 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -303,6 +303,13 @@ use of extensions and concurrent index removal, you need at least PostgreSQL 9.2
sudo apt-get install -y postgresql postgresql-client libpq-dev postgresql-contrib
```
+1. Start the PostgreSQL service and confirm that the service is running:
+
+ ```shell
+ sudo service postgresql start
+ sudo service postgresql status
+ ```
+
1. Create a database user for GitLab:
```shell
diff --git a/doc/user/admin_area/settings/account_and_limit_settings.md b/doc/user/admin_area/settings/account_and_limit_settings.md
index de12157311d..50414d5c268 100644
--- a/doc/user/admin_area/settings/account_and_limit_settings.md
+++ b/doc/user/admin_area/settings/account_and_limit_settings.md
@@ -15,6 +15,19 @@ If you choose a size larger than what is currently configured for the web server
you will likely get errors. See the [troubleshooting section](#troubleshooting) for more
details.
+## Maximum namespace storage size
+
+This sets a maximum size limit on each namespace. The following are included in the namespace size:
+
+- repository
+- wiki
+- LFS objects
+- build artifacts
+- packages
+
+NOTE: **Note:**
+This limit is not currently enforced but will be in a future release.
+
## Repository size limit **(STARTER ONLY)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/740) in [GitLab Enterprise Edition 8.12](https://about.gitlab.com/releases/2016/09/22/gitlab-8-12-released/#limit-project-size-ee).
diff --git a/lib/gitlab/ci/pipeline/chain/config/content.rb b/lib/gitlab/ci/pipeline/chain/config/content.rb
index 66bead3a416..2008010b523 100644
--- a/lib/gitlab/ci/pipeline/chain/config/content.rb
+++ b/lib/gitlab/ci/pipeline/chain/config/content.rb
@@ -16,15 +16,9 @@ module Gitlab
Gitlab::Ci::Pipeline::Chain::Config::Content::AutoDevops
].freeze
- LEGACY_SOURCES = [
- Gitlab::Ci::Pipeline::Chain::Config::Content::Bridge,
- Gitlab::Ci::Pipeline::Chain::Config::Content::LegacyRepository,
- Gitlab::Ci::Pipeline::Chain::Config::Content::LegacyAutoDevops
- ].freeze
-
def perform!
if config = find_config
- @pipeline.build_pipeline_config(content: config.content) if ci_root_config_content_enabled?
+ @pipeline.build_pipeline_config(content: config.content)
@command.config_content = config.content
@pipeline.config_source = config.source
else
@@ -39,21 +33,13 @@ module Gitlab
private
def find_config
- sources.each do |source|
+ SOURCES.each do |source|
config = source.new(@pipeline, @command)
return config if config.exists?
end
nil
end
-
- def sources
- ci_root_config_content_enabled? ? SOURCES : LEGACY_SOURCES
- end
-
- def ci_root_config_content_enabled?
- Feature.enabled?(:ci_root_config_content, @command.project, default_enabled: true)
- end
end
end
end
diff --git a/lib/gitlab/ci/pipeline/chain/config/content/legacy_auto_devops.rb b/lib/gitlab/ci/pipeline/chain/config/content/legacy_auto_devops.rb
deleted file mode 100644
index 5e4bb84360c..00000000000
--- a/lib/gitlab/ci/pipeline/chain/config/content/legacy_auto_devops.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Ci
- module Pipeline
- module Chain
- module Config
- class Content
- class LegacyAutoDevops < Source
- def content
- strong_memoize(:content) do
- next unless project&.auto_devops_enabled?
-
- template = Gitlab::Template::GitlabCiYmlTemplate.find(template_name)
- template.content
- end
- end
-
- def source
- :auto_devops_source
- end
-
- private
-
- def template_name
- 'Auto-DevOps'
- end
- end
- end
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/ci/pipeline/chain/config/content/legacy_repository.rb b/lib/gitlab/ci/pipeline/chain/config/content/legacy_repository.rb
deleted file mode 100644
index fa4a97c6880..00000000000
--- a/lib/gitlab/ci/pipeline/chain/config/content/legacy_repository.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Ci
- module Pipeline
- module Chain
- module Config
- class Content
- class LegacyRepository < Source
- def content
- strong_memoize(:content) do
- next unless project
- next unless @pipeline.sha
- next unless ci_config_path
-
- project.repository.gitlab_ci_yml_for(@pipeline.sha, ci_config_path)
- rescue GRPC::NotFound, GRPC::Internal
- nil
- end
- end
-
- def source
- :repository_source
- end
- end
- end
- end
- end
- end
- end
-end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 3dda347772b..0b2ea946dfa 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -2270,6 +2270,9 @@ msgstr ""
msgid "April"
msgstr ""
+msgid "Archive"
+msgstr ""
+
msgid "Archive jobs"
msgstr ""
@@ -10942,6 +10945,9 @@ msgstr ""
msgid "Includes an MVC structure, mvnw and pom.xml to help you get started."
msgstr ""
+msgid "Includes repository storage, wiki storage, LFS objects, build artifacts and packages. 0 for unlimited."
+msgstr ""
+
msgid "Incoming email"
msgstr ""
@@ -12045,6 +12051,9 @@ msgstr ""
msgid "Live preview"
msgstr ""
+msgid "Loading"
+msgstr ""
+
msgid "Loading blob"
msgstr ""
@@ -12393,6 +12402,9 @@ msgstr ""
msgid "Maximum lifetime allowable for Personal Access Tokens is active, your expire date must be set before %{maximum_allowable_date}."
msgstr ""
+msgid "Maximum namespace storage (MB)"
+msgstr ""
+
msgid "Maximum number of %{name} (%{count}) exceeded"
msgstr ""
@@ -14075,6 +14087,9 @@ msgstr ""
msgid "PackageRegistry|Delete package"
msgstr ""
+msgid "PackageRegistry|Filter by name"
+msgstr ""
+
msgid "PackageRegistry|For more information on the Conan registry, %{linkStart}see the documentation%{linkEnd}."
msgstr ""
@@ -14123,6 +14138,9 @@ msgstr ""
msgid "PackageRegistry|Remove package"
msgstr ""
+msgid "PackageRegistry|Sorry, your filter produced no results"
+msgstr ""
+
msgid "PackageRegistry|There are no %{packageType} packages yet"
msgstr ""
@@ -14132,6 +14150,9 @@ msgstr ""
msgid "PackageRegistry|There was a problem fetching the details for this package."
msgstr ""
+msgid "PackageRegistry|To widen your search, change or remove the filters above."
+msgstr ""
+
msgid "PackageRegistry|Unable to load package"
msgstr ""
@@ -18645,6 +18666,9 @@ msgstr ""
msgid "Something went wrong while fetching related merge requests."
msgstr ""
+msgid "Something went wrong while fetching requirements list."
+msgstr ""
+
msgid "Something went wrong while fetching the environments for this merge request. Please try again."
msgstr ""
@@ -20136,6 +20160,9 @@ msgstr ""
msgid "There are no archived projects yet"
msgstr ""
+msgid "There are no archived requirements"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -20169,6 +20196,9 @@ msgstr ""
msgid "There are no open merge requests"
msgstr ""
+msgid "There are no open requirements"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -23916,6 +23946,9 @@ msgstr ""
msgid "created"
msgstr ""
+msgid "created %{timeAgo}"
+msgstr ""
+
msgid "customize"
msgstr ""
@@ -24784,6 +24817,9 @@ msgstr ""
msgid "updated"
msgstr ""
+msgid "updated %{timeAgo}"
+msgstr ""
+
msgid "updated %{time_ago}"
msgstr ""
diff --git a/spec/fixtures/api/schemas/entities/discussion.json b/spec/fixtures/api/schemas/entities/discussion.json
index 92863d2e084..9d7ca62435e 100644
--- a/spec/fixtures/api/schemas/entities/discussion.json
+++ b/spec/fixtures/api/schemas/entities/discussion.json
@@ -36,7 +36,7 @@
"updated_at": { "type": "date" },
"system": { "type": "boolean" },
"noteable_id": { "type": "integer" },
- "noteable_iid": { "type": "integer" },
+ "noteable_iid": { "type": ["integer", "null"] },
"noteable_type": { "type": "string" },
"resolved": { "type": "boolean" },
"resolvable": { "type": "boolean" },
diff --git a/spec/frontend/registry/explorer/pages/details_spec.js b/spec/frontend/registry/explorer/pages/details_spec.js
index 60e509e4a88..15aa5008413 100644
--- a/spec/frontend/registry/explorer/pages/details_spec.js
+++ b/spec/frontend/registry/explorer/pages/details_spec.js
@@ -29,10 +29,11 @@ describe('Details Page', () => {
const findAllDeleteButtons = () => wrapper.findAll('.js-delete-registry');
const findAllCheckboxes = () => wrapper.findAll('.js-row-checkbox');
const findCheckedCheckboxes = () => findAllCheckboxes().filter(c => c.attributes('checked'));
+ const findFirsTagColumn = () => wrapper.find('.js-tag-column');
const routeId = window.btoa(JSON.stringify({ name: 'foo', tags_path: 'bar' }));
- beforeEach(() => {
+ const mountComponent = options => {
wrapper = mount(component, {
store,
stubs: {
@@ -49,7 +50,11 @@ describe('Details Page', () => {
},
$toast,
},
+ ...options,
});
+ };
+
+ beforeEach(() => {
dispatchSpy = jest.spyOn(store, 'dispatch');
store.dispatch('receiveTagsListSuccess', tagsListResponse);
jest.spyOn(Tracking, 'event');
@@ -61,6 +66,7 @@ describe('Details Page', () => {
describe('when isLoading is true', () => {
beforeEach(() => {
+ mountComponent();
store.dispatch('receiveTagsListSuccess', { ...tagsListResponse, data: [] });
store.commit(SET_MAIN_LOADING, true);
});
@@ -81,6 +87,10 @@ describe('Details Page', () => {
});
describe('table', () => {
+ beforeEach(() => {
+ mountComponent();
+ });
+
it.each([
'rowCheckbox',
'rowName',
@@ -93,6 +103,10 @@ describe('Details Page', () => {
});
describe('header checkbox', () => {
+ beforeEach(() => {
+ mountComponent();
+ });
+
it('exists', () => {
expect(findMainCheckbox().exists()).toBe(true);
});
@@ -116,6 +130,10 @@ describe('Details Page', () => {
});
describe('row checkbox', () => {
+ beforeEach(() => {
+ mountComponent();
+ });
+
it('if selected adds item to selectedItems', () => {
findFirstRowItem('rowCheckbox').vm.$emit('change');
return wrapper.vm.$nextTick().then(() => {
@@ -135,6 +153,10 @@ describe('Details Page', () => {
});
describe('header delete button', () => {
+ beforeEach(() => {
+ mountComponent();
+ });
+
it('exists', () => {
expect(findBulkDeleteButton().exists()).toBe(true);
});
@@ -182,6 +204,10 @@ describe('Details Page', () => {
});
describe('row delete button', () => {
+ beforeEach(() => {
+ mountComponent();
+ });
+
it('exists', () => {
expect(
findAllDeleteButtons()
@@ -213,9 +239,39 @@ describe('Details Page', () => {
});
});
});
+
+ describe('tag cell', () => {
+ describe('on desktop viewport', () => {
+ beforeEach(() => {
+ mountComponent();
+ });
+
+ it('has class w-25', () => {
+ expect(findFirsTagColumn().classes()).toContain('w-25');
+ });
+ });
+
+ describe('on mobile viewport', () => {
+ beforeEach(() => {
+ mountComponent({
+ data() {
+ return { isDesktop: false };
+ },
+ });
+ });
+
+ it('does not has class w-25', () => {
+ expect(findFirsTagColumn().classes()).not.toContain('w-25');
+ });
+ });
+ });
});
describe('pagination', () => {
+ beforeEach(() => {
+ mountComponent();
+ });
+
it('exists', () => {
expect(findPagination().exists()).toBe(true);
});
@@ -238,6 +294,10 @@ describe('Details Page', () => {
});
describe('modal', () => {
+ beforeEach(() => {
+ mountComponent();
+ });
+
it('exists', () => {
expect(findDeleteModal().exists()).toBe(true);
});
diff --git a/spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb
index b5f0783cb42..fc95bb602c2 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb
@@ -10,146 +10,6 @@ describe Gitlab::Ci::Pipeline::Chain::Config::Content do
subject { described_class.new(pipeline, command) }
describe '#perform!' do
- context 'when feature flag is disabled' do
- before do
- stub_feature_flags(ci_root_config_content: false)
- end
-
- context 'when bridge job is passed in as parameter' do
- let(:ci_config_path) { nil }
- let(:bridge) { create(:ci_bridge) }
-
- before do
- command.bridge = bridge
- end
-
- context 'when bridge job has downstream yaml' do
- before do
- allow(bridge).to receive(:yaml_for_downstream).and_return('the-yaml')
- end
-
- it 'returns the content already available in command' do
- subject.perform!
-
- expect(pipeline.config_source).to eq 'bridge_source'
- expect(command.config_content).to eq 'the-yaml'
- end
- end
-
- context 'when bridge job does not have downstream yaml' do
- before do
- allow(bridge).to receive(:yaml_for_downstream).and_return(nil)
- end
-
- it 'returns the next available source' do
- subject.perform!
-
- expect(pipeline.config_source).to eq 'auto_devops_source'
- template = Gitlab::Template::GitlabCiYmlTemplate.find('Auto-DevOps')
- expect(command.config_content).to eq(template.content)
- end
- end
- end
-
- context 'when config is defined in a custom path in the repository' do
- let(:ci_config_path) { 'path/to/config.yml' }
-
- before do
- expect(project.repository)
- .to receive(:gitlab_ci_yml_for)
- .with(pipeline.sha, ci_config_path)
- .and_return('the-content')
- end
-
- it 'returns the content of the YAML file' do
- subject.perform!
-
- expect(pipeline.config_source).to eq 'repository_source'
- expect(pipeline.pipeline_config).to be_nil
- expect(command.config_content).to eq('the-content')
- end
- end
-
- context 'when config is defined remotely' do
- let(:ci_config_path) { 'http://example.com/path/to/ci/config.yml' }
-
- it 'does not support URLs and default to AutoDevops' do
- subject.perform!
-
- expect(pipeline.config_source).to eq 'auto_devops_source'
- expect(pipeline.pipeline_config).to be_nil
- template = Gitlab::Template::GitlabCiYmlTemplate.find('Auto-DevOps')
- expect(command.config_content).to eq(template.content)
- end
- end
-
- context 'when config is defined in a separate repository' do
- let(:ci_config_path) { 'path/to/.gitlab-ci.yml@another-group/another-repo' }
-
- it 'does not support YAML from external repository and default to AutoDevops' do
- subject.perform!
-
- expect(pipeline.config_source).to eq 'auto_devops_source'
- expect(pipeline.pipeline_config).to be_nil
- template = Gitlab::Template::GitlabCiYmlTemplate.find('Auto-DevOps')
- expect(command.config_content).to eq(template.content)
- end
- end
-
- context 'when config is defined in the default .gitlab-ci.yml' do
- let(:ci_config_path) { nil }
-
- before do
- expect(project.repository)
- .to receive(:gitlab_ci_yml_for)
- .with(pipeline.sha, '.gitlab-ci.yml')
- .and_return('the-content')
- end
-
- it 'returns the content of the canonical config file' do
- subject.perform!
-
- expect(pipeline.config_source).to eq 'repository_source'
- expect(pipeline.pipeline_config).to be_nil
- expect(command.config_content).to eq('the-content')
- end
- end
-
- context 'when config is the Auto-Devops template' do
- let(:ci_config_path) { nil }
-
- before do
- expect(project).to receive(:auto_devops_enabled?).and_return(true)
- end
-
- it 'returns the content of AutoDevops template' do
- subject.perform!
-
- expect(pipeline.config_source).to eq 'auto_devops_source'
- expect(pipeline.pipeline_config).to be_nil
- template = Gitlab::Template::GitlabCiYmlTemplate.find('Auto-DevOps')
- expect(command.config_content).to eq(template.content)
- end
- end
-
- context 'when config is not defined anywhere' do
- let(:ci_config_path) { nil }
-
- before do
- expect(project).to receive(:auto_devops_enabled?).and_return(false)
- end
-
- it 'builds root config including the auto-devops template' do
- subject.perform!
-
- expect(pipeline.config_source).to eq('unknown_source')
- expect(pipeline.pipeline_config).to be_nil
- expect(command.config_content).to be_nil
- expect(pipeline.errors.full_messages).to include('Missing CI config file')
- end
- end
- end
-
context 'when bridge job is passed in as parameter' do
let(:ci_config_path) { nil }
let(:bridge) { create(:ci_bridge) }
diff --git a/spec/models/ci/processable/dependencies_spec.rb b/spec/models/ci/build_dependencies_spec.rb
index f115ae51f9c..6db69d0f34c 100644
--- a/spec/models/ci/processable/dependencies_spec.rb
+++ b/spec/models/ci/build_dependencies_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Ci::Processable::Dependencies do
+describe Ci::BuildDependencies do
let_it_be(:user) { create(:user) }
let_it_be(:project, reload: true) { create(:project, :repository) }
diff --git a/spec/requests/api/graphql/mutations/jira_import/start_spec.rb b/spec/requests/api/graphql/mutations/jira_import/start_spec.rb
new file mode 100644
index 00000000000..3eb2ca6909b
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/jira_import/start_spec.rb
@@ -0,0 +1,130 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'Starting a Jira Import' do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project, reload: true) { create(:project) }
+ let(:jira_project_key) { 'AA' }
+ let(:project_path) { project.full_path }
+
+ let(:mutation) do
+ variables = {
+ jira_project_key: jira_project_key,
+ project_path: project_path
+ }
+
+ graphql_mutation(:jira_import_start, variables)
+ end
+
+ def mutation_response
+ graphql_mutation_response(:jira_import_start)
+ end
+
+ def jira_import
+ mutation_response['jiraImport']
+ end
+
+ context 'when the user does not have permission' do
+ before do
+ stub_feature_flags(jira_issue_import: true)
+ end
+
+ shared_examples 'Jira import does not start' do
+ it 'does not start the Jira import' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(project.reload.import_state).to be nil
+ expect(project.reload.import_data).to be nil
+ end
+ end
+
+ context 'with anonymous user' do
+ let(:current_user) { nil }
+
+ it_behaves_like 'Jira import does not start'
+ it_behaves_like 'a mutation that returns top-level errors',
+ errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
+ end
+
+ context 'with user without permissions' do
+ let(:current_user) { user }
+ let(:project_path) { project.full_path }
+
+ before do
+ project.add_developer(current_user)
+ end
+
+ it_behaves_like 'Jira import does not start'
+ it_behaves_like 'a mutation that returns top-level errors',
+ errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
+ end
+ end
+
+ context 'when the user has permission' do
+ let(:current_user) { user }
+
+ before do
+ project.add_maintainer(current_user)
+ end
+
+ context 'with project' do
+ context 'when the project path is invalid' do
+ let(:project_path) { 'foobar' }
+
+ it 'returns an an error' do
+ post_graphql_mutation(mutation, current_user: current_user)
+ errors = json_response['errors']
+
+ expect(errors.first['message']).to eq(Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR)
+ end
+ end
+
+ context 'when feature jira_issue_import feature flag is disabled' do
+ before do
+ stub_feature_flags(jira_issue_import: false)
+ end
+
+ it_behaves_like 'a mutation that returns errors in the response', errors: ['Jira import feature is disabled.']
+ end
+
+ context 'when feature jira_issue_import feature flag is enabled' do
+ before do
+ stub_feature_flags(jira_issue_import: true)
+ end
+
+ context 'when project has no Jira service' do
+ it_behaves_like 'a mutation that returns errors in the response', errors: ['Jira integration not configured.']
+ end
+
+ context 'when when project has Jira service' do
+ let!(:service) { create(:jira_service, project: project) }
+
+ before do
+ project.reload
+ end
+
+ context 'when jira_project_key not provided' do
+ let(:jira_project_key) { '' }
+
+ it_behaves_like 'a mutation that returns errors in the response', errors: ['Unable to find Jira project to import data from.']
+ end
+
+ context 'when jira import successfully scheduled' do
+ it 'schedules a Jira import' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(jira_import['jiraProjectKey']).to eq 'AA'
+ expect(jira_import['scheduledBy']['username']).to eq current_user.username
+ expect(project.import_state).not_to be nil
+ expect(project.import_state.status).to eq 'scheduled'
+ expect(project.import_data.becomes(JiraImportData).projects.last.scheduled_by['user_id']).to eq current_user.id
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/project_clusters_spec.rb b/spec/requests/api/project_clusters_spec.rb
index 7cef40ff3b5..648577dce8d 100644
--- a/spec/requests/api/project_clusters_spec.rb
+++ b/spec/requests/api/project_clusters_spec.rb
@@ -5,9 +5,9 @@ require 'spec_helper'
describe API::ProjectClusters do
include KubernetesHelpers
- let(:current_user) { create(:user) }
- let(:developer_user) { create(:user) }
- let(:project) { create(:project) }
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:developer_user) { create(:user) }
+ let_it_be(:project) { create(:project) }
before do
project.add_maintainer(current_user)
@@ -15,10 +15,10 @@ describe API::ProjectClusters do
end
describe 'GET /projects/:id/clusters' do
- let!(:extra_cluster) { create(:cluster, :provided_by_gcp, :project) }
+ let_it_be(:extra_cluster) { create(:cluster, :provided_by_gcp, :project) }
- let!(:clusters) do
- create_list(:cluster, 5, :provided_by_gcp, :project, :production_environment,
+ let_it_be(:clusters) do
+ create_list(:cluster, 2, :provided_by_gcp, :project, :production_environment,
projects: [project])
end
@@ -35,17 +35,15 @@ describe API::ProjectClusters do
get api("/projects/#{project.id}/clusters", current_user)
end
- it 'responds with 200' do
- expect(response).to have_gitlab_http_status(:ok)
- end
-
it 'includes pagination headers' do
+ expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
end
it 'onlies include authorized clusters' do
cluster_ids = json_response.map { |cluster| cluster['id'] }
+ expect(response).to have_gitlab_http_status(:ok)
expect(cluster_ids).to match_array(clusters.pluck(:id))
expect(cluster_ids).not_to include(extra_cluster.id)
end
@@ -139,7 +137,7 @@ describe API::ProjectClusters do
end
context 'with non-existing cluster' do
- let(:cluster_id) { 123 }
+ let(:cluster_id) { 0 }
it 'returns 404' do
expect(response).to have_gitlab_http_status(:not_found)
@@ -185,14 +183,11 @@ describe API::ProjectClusters do
end
context 'with valid params' do
- it 'responds with 201' do
- expect(response).to have_gitlab_http_status(:created)
- end
-
it 'creates a new Cluster::Cluster' do
cluster_result = Clusters::Cluster.find(json_response["id"])
platform_kubernetes = cluster_result.platform
+ expect(response).to have_gitlab_http_status(:created)
expect(cluster_result).to be_user
expect(cluster_result).to be_kubernetes
expect(cluster_result.project).to eq(project)
@@ -235,15 +230,9 @@ describe API::ProjectClusters do
context 'with invalid params' do
let(:namespace) { 'invalid_namespace' }
- it 'responds with 400' do
- expect(response).to have_gitlab_http_status(:bad_request)
- end
-
it 'does not create a new Clusters::Cluster' do
+ expect(response).to have_gitlab_http_status(:bad_request)
expect(project.reload.clusters).to be_empty
- end
-
- it 'returns validation errors' do
expect(json_response['message']['platform_kubernetes.namespace'].first).to be_present
end
end
@@ -259,8 +248,8 @@ describe API::ProjectClusters do
it 'responds with 400' do
expect(response).to have_gitlab_http_status(:bad_request)
-
- expect(json_response['message']['base'].first).to eq(_('Instance does not support multiple Kubernetes clusters'))
+ expect(json_response['message']['base'].first)
+ .to eq(_('Instance does not support multiple Kubernetes clusters'))
end
end
@@ -271,7 +260,6 @@ describe API::ProjectClusters do
it 'responds with 403' do
expect(response).to have_gitlab_http_status(:forbidden)
-
expect(json_response['message']).to eq('403 Forbidden')
end
end
@@ -281,7 +269,7 @@ describe API::ProjectClusters do
let(:api_url) { 'https://kubernetes.example.com' }
let(:namespace) { 'new-namespace' }
let(:platform_kubernetes_attributes) { { namespace: namespace } }
- let(:management_project) { create(:project, namespace: project.namespace) }
+ let_it_be(:management_project) { create(:project, namespace: project.namespace) }
let(:management_project_id) { management_project.id }
let(:update_params) do
@@ -321,11 +309,8 @@ describe API::ProjectClusters do
end
context 'with valid params' do
- it 'responds with 200' do
- expect(response).to have_gitlab_http_status(:ok)
- end
-
it 'updates cluster attributes' do
+ expect(response).to have_gitlab_http_status(:ok)
expect(cluster.domain).to eq('new-domain.com')
expect(cluster.platform_kubernetes.namespace).to eq('new-namespace')
expect(cluster.management_project).to eq(management_project)
@@ -335,29 +320,24 @@ describe API::ProjectClusters do
context 'with invalid params' do
let(:namespace) { 'invalid_namespace' }
- it 'responds with 400' do
- expect(response).to have_gitlab_http_status(:bad_request)
- end
-
it 'does not update cluster attributes' do
+ expect(response).to have_gitlab_http_status(:bad_request)
expect(cluster.domain).not_to eq('new_domain.com')
expect(cluster.platform_kubernetes.namespace).not_to eq('invalid_namespace')
expect(cluster.management_project).not_to eq(management_project)
end
it 'returns validation errors' do
- expect(json_response['message']['platform_kubernetes.namespace'].first).to match('can contain only lowercase letters')
+ expect(json_response['message']['platform_kubernetes.namespace'].first)
+ .to match('can contain only lowercase letters')
end
end
context 'current user does not have access to management_project_id' do
- let(:management_project_id) { create(:project).id }
-
- it 'responds with 400' do
- expect(response).to have_gitlab_http_status(:bad_request)
- end
+ let_it_be(:management_project_id) { create(:project).id }
it 'returns validation errors' do
+ expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['message']['management_project_id'].first).to match('don\'t have permission')
end
end
@@ -371,12 +351,10 @@ describe API::ProjectClusters do
}
end
- it 'responds with 400' do
- expect(response).to have_gitlab_http_status(:bad_request)
- end
-
it 'returns validation error' do
- expect(json_response['message']['platform_kubernetes.base'].first).to eq(_('Cannot modify managed Kubernetes cluster'))
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['message']['platform_kubernetes.base'].first)
+ .to eq(_('Cannot modify managed Kubernetes cluster'))
end
end
@@ -412,13 +390,10 @@ describe API::ProjectClusters do
}
end
- it 'responds with 200' do
- expect(response).to have_gitlab_http_status(:ok)
- end
-
it 'updates platform kubernetes attributes' do
platform_kubernetes = cluster.platform_kubernetes
+ expect(response).to have_gitlab_http_status(:ok)
expect(cluster.name).to eq('new-name')
expect(platform_kubernetes.namespace).to eq('new-namespace')
expect(platform_kubernetes.api_url).to eq('https://new-api-url.com')
@@ -439,7 +414,7 @@ describe API::ProjectClusters do
describe 'DELETE /projects/:id/clusters/:cluster_id' do
let(:cluster_params) { { cluster_id: cluster.id } }
- let(:cluster) do
+ let_it_be(:cluster) do
create(:cluster, :project, :provided_by_gcp,
projects: [project])
end
@@ -457,11 +432,8 @@ describe API::ProjectClusters do
delete api("/projects/#{project.id}/clusters/#{cluster.id}", current_user), params: cluster_params
end
- it 'responds with 204' do
- expect(response).to have_gitlab_http_status(:no_content)
- end
-
it 'deletes the cluster' do
+ expect(response).to have_gitlab_http_status(:no_content)
expect(Clusters::Cluster.exists?(id: cluster.id)).to be_falsy
end
diff --git a/spec/support/helpers/stub_gitlab_calls.rb b/spec/support/helpers/stub_gitlab_calls.rb
index ff4b9db8ad9..40f4151c0fb 100644
--- a/spec/support/helpers/stub_gitlab_calls.rb
+++ b/spec/support/helpers/stub_gitlab_calls.rb
@@ -30,11 +30,9 @@ module StubGitlabCalls
# Stub the first call to `include:[local: .gitlab-ci.yml]` when
# evaluating the CI root config content.
- if Feature.enabled?(:ci_root_config_content, default_enabled: true)
- allow_any_instance_of(Gitlab::Ci::Config::External::File::Local)
- .to receive(:content)
- .and_return(ci_yaml_content)
- end
+ allow_any_instance_of(Gitlab::Ci::Config::External::File::Local)
+ .to receive(:content)
+ .and_return(ci_yaml_content)
end
def stub_pipeline_modified_paths(pipeline, modified_paths)