summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab/ci/review.gitlab-ci.yml10
-rw-r--r--.gitlab/ci/rules.gitlab-ci.yml2
-rw-r--r--.rubocop_todo.yml7
-rw-r--r--CHANGELOG.md65
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.lock5
-rw-r--r--app/assets/javascripts/pages/admin/users/components/delete_user_modal.vue4
-rw-r--r--app/models/commit_status.rb1
-rw-r--r--app/models/concerns/issuable.rb2
-rw-r--r--app/models/members/group_member.rb2
-rw-r--r--app/models/members/project_member.rb2
-rw-r--r--app/models/merge_request.rb4
-rw-r--r--app/models/project.rb2
-rw-r--r--app/presenters/project_presenter.rb12
-rw-r--r--app/services/members/invite_service.rb14
-rw-r--r--app/services/projects/unlink_fork_service.rb2
-rw-r--r--app/views/projects/jobs/_table.html.haml2
-rw-r--r--app/views/shared/form_elements/_description.html.haml2
-rw-r--r--app/views/shared/issuable/_sidebar.html.haml2
-rw-r--r--app/workers/expire_job_cache_worker.rb2
-rw-r--r--changelogs/unreleased/322449-write-description.yml5
-rw-r--r--changelogs/unreleased/323078-combine-concepts-in-inviting-member-service-classes-3.yml5
-rw-r--r--changelogs/unreleased/326038-delete-user-modal.yml5
-rw-r--r--changelogs/unreleased/add-cloud-column-to-licenses.yml5
-rw-r--r--changelogs/unreleased/dz-redirect-deprecated-pipeline-routes.yml5
-rw-r--r--changelogs/unreleased/mimemagic_shim.yml5
-rw-r--r--changelogs/unreleased/pl-rubocop-todo-redundant-self-assignment.yml5
-rw-r--r--changelogs/unreleased/query_count_expire_job_cache_worker.yml5
-rw-r--r--changelogs/unreleased/redirect-cicd-quick-buttons-to-pipeline-editor.yml5
-rw-r--r--changelogs/unreleased/remove-direct-mimemagic-dependency-minimal.yml5
-rw-r--r--changelogs/unreleased/remove-direct-mimemagic-dependency.yml5
-rw-r--r--changelogs/unreleased/remove_hipchat_gem.yml5
-rw-r--r--changelogs/unreleased/sh-update-ruby-magic-static-0-3-5.yml5
-rw-r--r--config/initializers/asciidoctor_patch.rb20
-rw-r--r--config/routes/project.rb4
-rw-r--r--db/migrate/20210330015805_add_cloud_to_licenses.rb9
-rw-r--r--db/schema_migrations/202103300158051
-rw-r--r--db/structure.sql3
-rw-r--r--doc/administration/troubleshooting/postgresql.md2
-rw-r--r--doc/api/system_hooks.md4
-rw-r--r--doc/development/dangerbot.md23
-rw-r--r--doc/development/usage_ping/index.md54
-rw-r--r--doc/user/project/integrations/jira_integrations.md30
-rw-r--r--lib/api/invitations.rb6
-rw-r--r--lib/api/system_hooks.rb2
-rw-r--r--lib/gitlab/ci/pipeline/chain/validate/external.rb8
-rw-r--r--lib/gitlab/markdown_cache.rb2
-rw-r--r--lib/gitlab/user_access.rb7
-rw-r--r--locale/gitlab.pot3
-rw-r--r--qa/qa/page/base.rb20
-rw-r--r--qa/qa/page/project/settings/merge_request.rb4
-rw-r--r--qa/qa/support/page/logging.rb2
-rw-r--r--scripts/review_apps/base-config.yaml2
-rw-r--r--spec/db/schema_spec.rb2
-rw-r--r--spec/factories/pool_repositories.rb2
-rw-r--r--spec/features/issues/user_creates_issue_spec.rb2
-rw-r--r--spec/features/merge_request/user_views_open_merge_request_spec.rb17
-rw-r--r--spec/features/projects/jobs_spec.rb2
-rw-r--r--spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb5
-rw-r--r--spec/frontend/pages/admin/users/components/__snapshots__/delete_user_modal_spec.js.snap4
-rw-r--r--spec/frontend/pages/admin/users/components/delete_user_modal_spec.js8
-rw-r--r--spec/lib/gitlab/asciidoc_spec.rb43
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb15
-rw-r--r--spec/lib/gitlab/user_access_spec.rb9
-rw-r--r--spec/models/members/group_member_spec.rb6
-rw-r--r--spec/models/members/project_member_spec.rb4
-rw-r--r--spec/models/project_spec.rb58
-rw-r--r--spec/requests/api/system_hooks_spec.rb10
-rw-r--r--spec/routing/project_routing_spec.rb20
-rw-r--r--spec/services/members/invite_service_spec.rb70
-rw-r--r--spec/services/projects/fork_service_spec.rb2
-rw-r--r--spec/services/projects/unlink_fork_service_spec.rb11
-rw-r--r--spec/workers/expire_job_cache_worker_spec.rb21
-rwxr-xr-x[-rw-r--r--]vendor/gitignore/C++.gitignore0
-rwxr-xr-x[-rw-r--r--]vendor/gitignore/Java.gitignore0
75 files changed, 564 insertions, 162 deletions
diff --git a/.gitlab/ci/review.gitlab-ci.yml b/.gitlab/ci/review.gitlab-ci.yml
index fefadab16e4..1134a76a6b8 100644
--- a/.gitlab/ci/review.gitlab-ci.yml
+++ b/.gitlab/ci/review.gitlab-ci.yml
@@ -234,7 +234,15 @@ danger-review:
- run_timed_command "bundle install --jobs=$(nproc) --path=vendor --retry=3 --quiet --with danger"
- run_timed_command "retry yarn install --frozen-lockfile"
script:
- - run_timed_command "bundle exec danger --fail-on-errors=true --verbose"
+ - >
+ if [ -z "$DANGER_GITLAB_API_TOKEN" ]; then
+ # Force danger to skip CI source GitLab and fallback to "local only git repo".
+ unset GITLAB_CI
+ # We need to base SHA to help danger determine the base commit for this shallow clone.
+ run_timed_command "bundle exec danger dry_run --fail-on-errors=true --verbose --base='$CI_MERGE_REQUEST_DIFF_BASE_SHA'"
+ else
+ run_timed_command "bundle exec danger --fail-on-errors=true --verbose"
+ fi
update-danger-review-cache:
extends:
diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml
index 39522f7b60c..df2edd04809 100644
--- a/.gitlab/ci/rules.gitlab-ci.yml
+++ b/.gitlab/ci/rules.gitlab-ci.yml
@@ -1110,7 +1110,7 @@
.review:rules:danger:
rules:
- - if: '$DANGER_GITLAB_API_TOKEN && $CI_MERGE_REQUEST_IID'
+ - if: '$CI_MERGE_REQUEST_IID'
###############
# Setup rules #
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 218a002aa45..f01dedb40dd 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -927,13 +927,6 @@ Style/RedundantRegexpEscape:
Style/RedundantSelf:
Enabled: false
-# Offense count: 2
-# Cop supports --auto-correct.
-Style/RedundantSelfAssignment:
- Exclude:
- - 'app/models/concerns/issuable.rb'
- - 'spec/db/schema_spec.rb'
-
# Offense count: 213
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, AllowInnerSlashes.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 30fdc3cbaaf..b147b3c3a7f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,28 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
+## 13.10.1 (2021-03-31)
+
+### Security (6 changes)
+
+- Leave pool repository on fork unlinking.
+- Fixed XSS in merge requests sidebar.
+- Fix arbitrary read/write in AsciiDoctor and Kroki gems.
+- Prevent infinite loop when checking if collaboration is allowed.
+- Disable arbitrary URI and file reads in JSON validator.
+- Require POST request to trigger system hooks.
+
+### Removed (1 change)
+
+- Make HipChat project service do nothing. !57434
+
+### Other (3 changes)
+
+- Remove direct mimemagic dependency. !57387
+- Refactor MimeMagic calls to new MimeType class. !57421
+- Switch to using a fake mimemagic gem. !57443
+
+
## 13.10.0 (2021-03-22)
### Security (3 changes)
@@ -529,6 +551,28 @@ entry.
- Convert mattermost alert to pajamas. !56556
+## 13.9.5 (2021-03-31)
+
+### Security (6 changes)
+
+- Leave pool repository on fork unlinking.
+- Fixed XSS in merge requests sidebar.
+- Fix arbitrary read/write in AsciiDoctor and Kroki gems.
+- Prevent infinite loop when checking if collaboration is allowed.
+- Disable arbitrary URI and file reads in JSON validator.
+- Require POST request to trigger system hooks.
+
+### Removed (1 change)
+
+- Make HipChat project service do nothing. !57434
+
+### Other (3 changes)
+
+- Remove direct mimemagic dependency. !57387
+- Refactor MimeMagic calls to new MimeType class. !57421
+- Switch to using a fake mimemagic gem. !57443
+
+
## 13.9.4 (2021-03-17)
### Security (1 change)
@@ -1144,6 +1188,27 @@ entry.
- Apply new GitLab UI for buttons in pipeline schedules.
+## 13.8.7 (2021-03-31)
+
+### Security (5 changes)
+
+- Fixed XSS in merge requests sidebar.
+- Leave pool repository on fork unlinking.
+- Fix arbitrary read/write in AsciiDoctor and Kroki gems.
+- Prevent infinite loop when checking if collaboration is allowed.
+- Require POST request to trigger system hooks.
+
+### Removed (1 change)
+
+- Make HipChat project service do nothing. !57434
+
+### Other (3 changes)
+
+- Remove direct mimemagic dependency. !57387
+- Refactor MimeMagic calls to new MimeType class. !57421
+- Switch to using a fake mimemagic gem. !57443
+
+
## 13.8.6 (2021-03-17)
### Security (1 change)
diff --git a/Gemfile b/Gemfile
index 81cb65bd99b..a66edbc23ce 100644
--- a/Gemfile
+++ b/Gemfile
@@ -274,7 +274,7 @@ gem 'licensee', '~> 9.14.1'
gem 'charlock_holmes', '~> 0.7.7'
# Detect mime content type from content
-gem 'ruby-magic-static', '~> 0.3.4'
+gem 'ruby-magic-static', '~> 0.3.5'
# Fake version of the gem to trick bundler
gem 'mimemagic', '0.3.7', path: 'vendor/shims/mimemagic', require: false
diff --git a/Gemfile.lock b/Gemfile.lock
index 75dced890e5..1a14028230f 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1113,7 +1113,8 @@ GEM
i18n
ruby-fogbugz (0.2.1)
crack (~> 0.4)
- ruby-magic-static (0.3.4)
+ ruby-magic-static (0.3.5)
+ mini_portile2 (~> 2.5.0)
ruby-prof (1.3.1)
ruby-progressbar (1.11.0)
ruby-saml (1.7.2)
@@ -1559,7 +1560,7 @@ DEPENDENCIES
rspec_junit_formatter
rspec_profiling (~> 0.0.6)
ruby-fogbugz (~> 0.2.1)
- ruby-magic-static (~> 0.3.4)
+ ruby-magic-static (~> 0.3.5)
ruby-prof (~> 1.3.0)
ruby-progressbar (~> 1.10)
ruby_parser (~> 3.15)
diff --git a/app/assets/javascripts/pages/admin/users/components/delete_user_modal.vue b/app/assets/javascripts/pages/admin/users/components/delete_user_modal.vue
index d2b83f980d7..20407334b3f 100644
--- a/app/assets/javascripts/pages/admin/users/components/delete_user_modal.vue
+++ b/app/assets/javascripts/pages/admin/users/components/delete_user_modal.vue
@@ -119,8 +119,8 @@ export default {
<gl-button @click="onCancel">{{ s__('Cancel') }}</gl-button>
<gl-button
:disabled="!canSubmit"
- category="primary"
- variant="warning"
+ category="secondary"
+ variant="danger"
@click="onSecondaryAction"
>
{{ secondaryAction }}
diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb
index 9b08ca3718e..e64380f5d91 100644
--- a/app/models/commit_status.rb
+++ b/app/models/commit_status.rb
@@ -55,6 +55,7 @@ class CommitStatus < ApplicationRecord
scope :for_ref, -> (ref) { where(ref: ref) }
scope :by_name, -> (name) { where(name: name) }
scope :in_pipelines, ->(pipelines) { where(pipeline: pipelines) }
+ scope :eager_load_pipeline, -> { eager_load(:pipeline, project: { namespace: :route }) }
scope :for_project_paths, -> (paths) do
where(project: Project.where_full_path_in(Array(paths)))
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index e1be0665452..09859fda877 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -324,7 +324,7 @@ module Issuable
# This prevents errors when ignored columns are present in the database.
issuable_columns = with_cte ? issue_grouping_columns(use_cte: with_cte) : "#{table_name}.*"
- extra_select_columns = extra_select_columns.unshift("(#{highest_priority}) AS highest_priority")
+ extra_select_columns.unshift("(#{highest_priority}) AS highest_priority")
select(issuable_columns)
.select(extra_select_columns)
diff --git a/app/models/members/group_member.rb b/app/models/members/group_member.rb
index c30f6dc81ee..b63c2b84882 100644
--- a/app/models/members/group_member.rb
+++ b/app/models/members/group_member.rb
@@ -7,7 +7,7 @@ class GroupMember < Member
SOURCE_TYPE = 'Namespace'
belongs_to :group, foreign_key: 'source_id'
-
+ alias_attribute :namespace_id, :source_id
delegate :update_two_factor_requirement, to: :user
# Make sure group member points only to group as it source
diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb
index 833b27756ab..9a86b3a3fd9 100644
--- a/app/models/members/project_member.rb
+++ b/app/models/members/project_member.rb
@@ -5,6 +5,8 @@ class ProjectMember < Member
belongs_to :project, foreign_key: 'source_id'
+ delegate :namespace_id, to: :project
+
# Make sure project member points only to project as it source
default_value_for :source_type, SOURCE_TYPE
validates :source_type, format: { with: /\AProject\z/ }
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 4a3162c5aa6..7a63fba2835 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -1350,8 +1350,8 @@ class MergeRequest < ApplicationRecord
has_no_commits? || branch_missing? || cannot_be_merged?
end
- def can_be_merged_by?(user)
- access = ::Gitlab::UserAccess.new(user, container: project)
+ def can_be_merged_by?(user, skip_collaboration_check: false)
+ access = ::Gitlab::UserAccess.new(user, container: project, skip_collaboration_check: skip_collaboration_check)
access.can_update_branch?(target_branch)
end
diff --git a/app/models/project.rb b/app/models/project.rb
index 30741e117bf..eb0382414de 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -2711,7 +2711,7 @@ class Project < ApplicationRecord
# Issue for N+1: https://gitlab.com/gitlab-org/gitlab-foss/issues/49322
Gitlab::GitalyClient.allow_n_plus_1_calls do
merge_requests_allowing_collaboration(branch_name).any? do |merge_request|
- merge_request.can_be_merged_by?(user)
+ merge_request.can_be_merged_by?(user, skip_collaboration_check: true)
end
end
end
diff --git a/app/presenters/project_presenter.rb b/app/presenters/project_presenter.rb
index 71cbe28de25..51deb6cbd1d 100644
--- a/app/presenters/project_presenter.rb
+++ b/app/presenters/project_presenter.rb
@@ -93,10 +93,6 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
filename_path(repository.license_blob&.name)
end
- def ci_configuration_path
- filename_path(repository.gitlab_ci_yml&.name)
- end
-
def contribution_guide_path
if project && contribution_guide = repository.contribution_guide
project_blob_path(
@@ -131,10 +127,6 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
ide_edit_path(project, default_branch_or_master, 'CONTRIBUTING.md')
end
- def add_ci_yml_path
- add_special_file_path(file_name: ci_config_path_or_default)
- end
-
def add_readme_path
add_special_file_path(file_name: 'README.md')
end
@@ -384,11 +376,11 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
if cicd_missing?
AnchorData.new(false,
statistic_icon + _('Set up CI/CD'),
- add_ci_yml_path)
+ project_ci_pipeline_editor_path(project))
elsif repository.gitlab_ci_yml.present?
AnchorData.new(false,
statistic_icon('doc-text') + _('CI/CD configuration'),
- ci_configuration_path,
+ project_ci_pipeline_editor_path(project),
'btn-default')
end
end
diff --git a/app/services/members/invite_service.rb b/app/services/members/invite_service.rb
index db29f41d5f6..b865babdf3c 100644
--- a/app/services/members/invite_service.rb
+++ b/app/services/members/invite_service.rb
@@ -10,13 +10,14 @@ module Members
@errors = {}
@emails = params[:email]&.split(',')&.uniq&.flatten
+ @source = params[:source]
end
- def execute(source)
- @source = source
+ def execute
validate_emails!
emails.each(&method(:process_email))
+ enqueue_onboarding_progress_action
result
rescue BlankEmailsError, TooManyEmailsError => e
error(e.message)
@@ -24,7 +25,7 @@ module Members
private
- attr_reader :source, :errors, :emails
+ attr_reader :source, :errors, :emails, :member_created_namespace_id
def validate_emails!
raise BlankEmailsError, s_('AddMember|Email cannot be blank') if emails.blank?
@@ -88,6 +89,7 @@ module Members
errors[email] = new_member.errors.full_messages.to_sentence
else
after_execute(member: new_member)
+ @member_created_namespace_id ||= new_member.namespace_id
end
end
@@ -98,6 +100,12 @@ module Members
success
end
end
+
+ def enqueue_onboarding_progress_action
+ return unless member_created_namespace_id
+
+ Namespaces::OnboardingUserAddedWorker.perform_async(member_created_namespace_id)
+ end
end
end
diff --git a/app/services/projects/unlink_fork_service.rb b/app/services/projects/unlink_fork_service.rb
index 6ba3356d612..91632e50ba8 100644
--- a/app/services/projects/unlink_fork_service.rb
+++ b/app/services/projects/unlink_fork_service.rb
@@ -32,6 +32,8 @@ module Projects
if fork_network = @project.root_of_fork_network
fork_network.update(root_project: nil, deleted_root_project_name: @project.full_name)
end
+
+ @project.leave_pool_repository
end
# rubocop: disable Cop/InBatches
diff --git a/app/views/projects/jobs/_table.html.haml b/app/views/projects/jobs/_table.html.haml
index 402f7ddb38d..fc4b3260ab3 100644
--- a/app/views/projects/jobs/_table.html.haml
+++ b/app/views/projects/jobs/_table.html.haml
@@ -12,7 +12,7 @@
= s_('Jobs|Use jobs to automate your tasks')
%p
= s_('Jobs|Jobs are the building blocks of a GitLab CI/CD pipeline. Each job has a specific task, like testing code. To set up jobs in a CI/CD pipeline, add a CI/CD configuration file to your project.')
- = link_to s_('Jobs|Create CI/CD configuration file'), @project.present(current_user: current_user).add_ci_yml_path, class: 'btn gl-button btn-info js-empty-state-button'
+ = link_to s_('Jobs|Create CI/CD configuration file'), project_ci_pipeline_editor_path(project), class: 'btn gl-button btn-info js-empty-state-button'
- else
.nothing-here-block= s_('Jobs|No jobs to show')
- else
diff --git a/app/views/shared/form_elements/_description.html.haml b/app/views/shared/form_elements/_description.html.haml
index 77a304d9565..f8942dddfb4 100644
--- a/app/views/shared/form_elements/_description.html.haml
+++ b/app/views/shared/form_elements/_description.html.haml
@@ -1,7 +1,7 @@
- project = local_assigns.fetch(:project)
- model = local_assigns.fetch(:model)
- form = local_assigns.fetch(:form)
-- placeholder = model.is_a?(MergeRequest) ? _('Describe the goal of the changes and what reviewers should be aware of.') : _('Write a comment or drag your files here…')
+- placeholder = model.is_a?(MergeRequest) ? _('Describe the goal of the changes and what reviewers should be aware of.') : _('Write a description or drag your files here…')
- supports_quick_actions = true
- preview_url = preview_markdown_path(project, target_type: model.class.name)
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index 6a90698f1de..72ae7b22123 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -138,7 +138,7 @@
= clipboard_button(text: source_branch, title: _('Copy branch name'), placement: "left", boundary: 'viewport')
.gl-display-flex.gl-align-items-center.gl-justify-content-space-between.gl-mb-2.hide-collapsed
%span.gl-overflow-hidden.gl-text-overflow-ellipsis.gl-white-space-nowrap
- = _('Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}').html_safe % { source_branch_open: "<span class='gl-font-monospace' title='#{source_branch}'>".html_safe, source_branch_close: "</span>".html_safe, source_branch: source_branch }
+ = _('Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}').html_safe % { source_branch_open: "<span class='gl-font-monospace' data-testid='ref-name' title='#{html_escape(source_branch)}'>".html_safe, source_branch_close: "</span>".html_safe, source_branch: html_escape(source_branch) }
= clipboard_button(text: source_branch, title: _('Copy branch name'), placement: "left", boundary: 'viewport')
- if show_forwarding_email
diff --git a/app/workers/expire_job_cache_worker.rb b/app/workers/expire_job_cache_worker.rb
index 77b0edfd7de..48bb1160ae8 100644
--- a/app/workers/expire_job_cache_worker.rb
+++ b/app/workers/expire_job_cache_worker.rb
@@ -10,7 +10,7 @@ class ExpireJobCacheWorker
# rubocop: disable CodeReuse/ActiveRecord
def perform(job_id)
- job = CommitStatus.joins(:pipeline, :project).find_by(id: job_id)
+ job = CommitStatus.eager_load_pipeline.find_by(id: job_id)
return unless job
pipeline = job.pipeline
diff --git a/changelogs/unreleased/322449-write-description.yml b/changelogs/unreleased/322449-write-description.yml
new file mode 100644
index 00000000000..5c709a2a119
--- /dev/null
+++ b/changelogs/unreleased/322449-write-description.yml
@@ -0,0 +1,5 @@
+---
+title: Update New Issue form description copy from 'wite a comment' to 'wite a description'
+merge_request: 58068
+author:
+type: changed
diff --git a/changelogs/unreleased/323078-combine-concepts-in-inviting-member-service-classes-3.yml b/changelogs/unreleased/323078-combine-concepts-in-inviting-member-service-classes-3.yml
new file mode 100644
index 00000000000..246477a1e6e
--- /dev/null
+++ b/changelogs/unreleased/323078-combine-concepts-in-inviting-member-service-classes-3.yml
@@ -0,0 +1,5 @@
+---
+title: Add enqueueing of Onboarding Progress to the Invite Service
+merge_request: 57372
+author:
+type: other
diff --git a/changelogs/unreleased/326038-delete-user-modal.yml b/changelogs/unreleased/326038-delete-user-modal.yml
new file mode 100644
index 00000000000..e1c3a31d3aa
--- /dev/null
+++ b/changelogs/unreleased/326038-delete-user-modal.yml
@@ -0,0 +1,5 @@
+---
+title: Deprecate btn-warning on admin area delete user modal
+merge_request: 57761
+author:
+type: changed
diff --git a/changelogs/unreleased/add-cloud-column-to-licenses.yml b/changelogs/unreleased/add-cloud-column-to-licenses.yml
new file mode 100644
index 00000000000..21cd9c8addf
--- /dev/null
+++ b/changelogs/unreleased/add-cloud-column-to-licenses.yml
@@ -0,0 +1,5 @@
+---
+title: 'Migration: Add cloud column to licenses'
+merge_request: 57781
+author:
+type: added
diff --git a/changelogs/unreleased/dz-redirect-deprecated-pipeline-routes.yml b/changelogs/unreleased/dz-redirect-deprecated-pipeline-routes.yml
new file mode 100644
index 00000000000..3ed396213bd
--- /dev/null
+++ b/changelogs/unreleased/dz-redirect-deprecated-pipeline-routes.yml
@@ -0,0 +1,5 @@
+---
+title: Redirect deprecated pipeline routes
+merge_request: 53990
+author:
+type: removed
diff --git a/changelogs/unreleased/mimemagic_shim.yml b/changelogs/unreleased/mimemagic_shim.yml
deleted file mode 100644
index 0376122f0ce..00000000000
--- a/changelogs/unreleased/mimemagic_shim.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Switch to using a fake mimemagic gem
-merge_request: 57443
-author:
-type: other
diff --git a/changelogs/unreleased/pl-rubocop-todo-redundant-self-assignment.yml b/changelogs/unreleased/pl-rubocop-todo-redundant-self-assignment.yml
new file mode 100644
index 00000000000..ad20006b98f
--- /dev/null
+++ b/changelogs/unreleased/pl-rubocop-todo-redundant-self-assignment.yml
@@ -0,0 +1,5 @@
+---
+title: Fixes rubocop offenses Style/RedundantSelfAssignment
+merge_request: 57920
+author: Shubham Kumar (@imskr)
+type: fixed
diff --git a/changelogs/unreleased/query_count_expire_job_cache_worker.yml b/changelogs/unreleased/query_count_expire_job_cache_worker.yml
new file mode 100644
index 00000000000..8279aa4174a
--- /dev/null
+++ b/changelogs/unreleased/query_count_expire_job_cache_worker.yml
@@ -0,0 +1,5 @@
+---
+title: Reduce query count for popular worker ExpireJobCacheWorker
+merge_request: 57773
+author:
+type: performance
diff --git a/changelogs/unreleased/redirect-cicd-quick-buttons-to-pipeline-editor.yml b/changelogs/unreleased/redirect-cicd-quick-buttons-to-pipeline-editor.yml
new file mode 100644
index 00000000000..c04ef8baf23
--- /dev/null
+++ b/changelogs/unreleased/redirect-cicd-quick-buttons-to-pipeline-editor.yml
@@ -0,0 +1,5 @@
+---
+title: Redirect to the pipeline editor when clicking on CI/CD quick links
+merge_request: 57085
+author:
+type: changed
diff --git a/changelogs/unreleased/remove-direct-mimemagic-dependency-minimal.yml b/changelogs/unreleased/remove-direct-mimemagic-dependency-minimal.yml
deleted file mode 100644
index 727887f7e7b..00000000000
--- a/changelogs/unreleased/remove-direct-mimemagic-dependency-minimal.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Refactor MimeMagic calls to new MimeType class
-merge_request: 57421
-author:
-type: other
diff --git a/changelogs/unreleased/remove-direct-mimemagic-dependency.yml b/changelogs/unreleased/remove-direct-mimemagic-dependency.yml
deleted file mode 100644
index 5194dfdf751..00000000000
--- a/changelogs/unreleased/remove-direct-mimemagic-dependency.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Remove direct mimemagic dependency
-merge_request: 57387
-author:
-type: other
diff --git a/changelogs/unreleased/remove_hipchat_gem.yml b/changelogs/unreleased/remove_hipchat_gem.yml
deleted file mode 100644
index 21a5db3bb5a..00000000000
--- a/changelogs/unreleased/remove_hipchat_gem.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Make HipChat project service do nothing
-merge_request: 57434
-author:
-type: removed
diff --git a/changelogs/unreleased/sh-update-ruby-magic-static-0-3-5.yml b/changelogs/unreleased/sh-update-ruby-magic-static-0-3-5.yml
new file mode 100644
index 00000000000..1dc44618898
--- /dev/null
+++ b/changelogs/unreleased/sh-update-ruby-magic-static-0-3-5.yml
@@ -0,0 +1,5 @@
+---
+title: Update ruby-magic-static to v0.3.5
+merge_request: 57984
+author:
+type: changed
diff --git a/config/initializers/asciidoctor_patch.rb b/config/initializers/asciidoctor_patch.rb
new file mode 100644
index 00000000000..b7da50db77c
--- /dev/null
+++ b/config/initializers/asciidoctor_patch.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+# Ensure that locked attributes can not be changed using a counter.
+# TODO: this can be removed once `asciidoctor` gem is > 2.0.12
+# and https://github.com/asciidoctor/asciidoctor/issues/3939 is merged
+module Asciidoctor
+ module DocumentPatch
+ def counter(name, seed = nil)
+ return @parent_document.counter(name, seed) if @parent_document # rubocop: disable Gitlab/ModuleWithInstanceVariables
+
+ unless attribute_locked? name
+ super
+ end
+ end
+ end
+end
+
+class Asciidoctor::Document
+ prepend Asciidoctor::DocumentPatch
+end
diff --git a/config/routes/project.rb b/config/routes/project.rb
index bfe2a0a78f1..363d23590bf 100644
--- a/config/routes/project.rb
+++ b/config/routes/project.rb
@@ -553,7 +553,6 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
# Deprecated unscoped routing.
scope as: 'deprecated' do
# Issue https://gitlab.com/gitlab-org/gitlab/issues/118849
- draw :pipelines
draw :repository
# Issue https://gitlab.com/gitlab-org/gitlab/-/issues/29572
@@ -576,7 +575,8 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
:environments, :protected_environments, :error_tracking, :alert_management,
:tracing,
:serverless, :clusters, :audit_events, :wikis, :merge_requests,
- :vulnerability_feedback, :security, :dependencies, :issues)
+ :vulnerability_feedback, :security, :dependencies, :issues,
+ :pipelines, :pipeline_schedules)
end
# rubocop: disable Cop/PutProjectRoutesUnderScope
diff --git a/db/migrate/20210330015805_add_cloud_to_licenses.rb b/db/migrate/20210330015805_add_cloud_to_licenses.rb
new file mode 100644
index 00000000000..d0c7112d0b0
--- /dev/null
+++ b/db/migrate/20210330015805_add_cloud_to_licenses.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddCloudToLicenses < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ def change
+ add_column :licenses, :cloud, :boolean, default: false
+ end
+end
diff --git a/db/schema_migrations/20210330015805 b/db/schema_migrations/20210330015805
new file mode 100644
index 00000000000..14102a0a2d1
--- /dev/null
+++ b/db/schema_migrations/20210330015805
@@ -0,0 +1 @@
+a435a211d7e8b9a972323769299fc6e537fdeaa127f8db6ab53031901a51ec36 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 3ff4d895aa6..01bbd00bd44 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -14182,7 +14182,8 @@ CREATE TABLE licenses (
id integer NOT NULL,
data text NOT NULL,
created_at timestamp without time zone,
- updated_at timestamp without time zone
+ updated_at timestamp without time zone,
+ cloud boolean DEFAULT false
);
CREATE SEQUENCE licenses_id_seq
diff --git a/doc/administration/troubleshooting/postgresql.md b/doc/administration/troubleshooting/postgresql.md
index 1da52e461af..9565b7594d6 100644
--- a/doc/administration/troubleshooting/postgresql.md
+++ b/doc/administration/troubleshooting/postgresql.md
@@ -35,7 +35,7 @@ This section is for links to information elsewhere in the GitLab documentation.
- Storing data in another location.
- Destructively reseeding the GitLab database.
- Guidance around updating packaged PostgreSQL, including how to stop it
- happening automatically.
+ from happening automatically.
- [Information about external PostgreSQL](../postgresql/external.md).
diff --git a/doc/api/system_hooks.md b/doc/api/system_hooks.md
index 855436864cc..3348157129d 100644
--- a/doc/api/system_hooks.md
+++ b/doc/api/system_hooks.md
@@ -88,7 +88,7 @@ Example response:
## Test system hook
```plaintext
-GET /hooks/:id
+POST /hooks/:id
```
| Attribute | Type | Required | Description |
@@ -98,7 +98,7 @@ GET /hooks/:id
Example request:
```shell
-curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/hooks/2"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/hooks/1"
```
Example response:
diff --git a/doc/development/dangerbot.md b/doc/development/dangerbot.md
index 413c0a31eec..f6390d1c8ef 100644
--- a/doc/development/dangerbot.md
+++ b/doc/development/dangerbot.md
@@ -150,16 +150,13 @@ at GitLab so far:
## Limitations
-- Danger output is not added to a merge request comment if working on
- a fork. This happens because the secret variable from the canonical
- project is not shared to forks.
- To work around this, you can add an [environment
- variable](../ci/variables/README.md) called
- `DANGER_GITLAB_API_TOKEN` with a personal API token to your
- fork. That way the danger comments are made from CI using that
- API token instead.
- Making the variable
- [masked](../ci/variables/README.md#mask-a-custom-variable) makes sure
- it doesn't show up in the job logs. The variable cannot be
- [protected](../ci/variables/README.md#protect-a-custom-variable),
- as it needs to be present for all feature branches.
+Danger is run but its output is not added to a merge request comment if working
+on a fork. This happens because the secret variable from the canonical project
+is not shared to forks. To work around this, you can add an [environment
+variable](../ci/variables/README.md) called `DANGER_GITLAB_API_TOKEN` with a
+personal API token to your fork. That way the danger comments are made from CI
+using that API token instead. Making the variable
+[masked](../ci/variables/README.md#mask-a-custom-variable) makes sure it
+doesn't show up in the job logs. The variable cannot be
+[protected](../ci/variables/README.md#protect-a-custom-variable), as it needs
+to be present for all feature branches.
diff --git a/doc/development/usage_ping/index.md b/doc/development/usage_ping/index.md
index 91d5898d97f..c41510fa98a 100644
--- a/doc/development/usage_ping/index.md
+++ b/doc/development/usage_ping/index.md
@@ -896,18 +896,56 @@ On GitLab.com, we have DangerBot setup to monitor Product Intelligence related f
On GitLab.com, the Product Intelligence team regularly monitors Usage Ping. They may alert you that your metrics need further optimization to run quicker and with greater success. You may also use the [Usage Ping QA dashboard](https://app.periscopedata.com/app/gitlab/632033/Usage-Ping-QA) to check how well your metric performs. The dashboard allows filtering by GitLab version, by "Self-managed" & "SaaS" and shows you how many failures have occurred for each metric. Whenever you notice a high failure rate, you may re-optimize your metric.
-### Optional: Test Prometheus based Usage Ping
+### Usage Ping local setup
-If the data submitted includes metrics [queried from Prometheus](#prometheus-queries) that you would like to inspect and verify,
-then you need to ensure that a Prometheus server is running locally, and that furthermore the respective GitLab components
-are exporting metrics to it. If you do not need to test data coming from Prometheus, no further action
+To set up Usage Ping locally, you must:
+
+1. [Set up local repositories]#(set-up-local-repositories)
+1. [Test local setup](#test-local-setup)
+1. (Optional) [Test Prometheus-based usage ping](#test-prometheus-based-usage-ping)
+
+#### Set up local repositories
+
+1. Clone and start [GitLab](https://gitlab.com/gitlab-org/gitlab-development-kit).
+1. Clone and start [Versions Application](https://gitlab.com/gitlab-services/version-gitlab-com).
+ Make sure to run `docker-compose up` to start a PostgreSQL and Redis instance.
+1. Point GitLab to the Versions Application endpoint instead of the default endpoint:
+ 1. Open [submit_usage_ping_service.rb](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/services/submit_usage_ping_service.rb#L4) in your local and modified `PRODUCTION_URL`.
+ 1. Set it to the local Versions Application URL `http://localhost:3000/usage_data`.
+
+#### Test local setup
+
+1. Using the `gitlab` Rails console, manually trigger a usage ping:
+
+ ```ruby
+ SubmitUsagePingService.new.execute
+ ```
+
+1. Use the `versions` Rails console to check the usage ping was successfully received,
+ parsed, and stored in the Versions database:
+
+ ```ruby
+ UsageData.last
+ ```
+
+### Test Prometheus-based usage ping
+
+If the data submitted includes metrics [queried from Prometheus](#prometheus-queries)
+you want to inspect and verify, you must:
+
+- Ensure that a Prometheus server is running locally.
+- Ensure the respective GitLab components are exporting metrics to the Prometheus server.
+
+If you do not need to test data coming from Prometheus, no further action
is necessary. Usage Ping should degrade gracefully in the absence of a running Prometheus server.
-There are three kinds of components that may export data to Prometheus, and which are included in Usage Ping:
+Three kinds of components may export data to Prometheus, and are included in Usage Ping:
-- [`node_exporter`](https://github.com/prometheus/node_exporter) - Exports node metrics from the host machine
-- [`gitlab-exporter`](https://gitlab.com/gitlab-org/gitlab-exporter) - Exports process metrics from various GitLab components
-- various GitLab services such as Sidekiq and the Rails server that export their own metrics
+- [`node_exporter`](https://github.com/prometheus/node_exporter): Exports node metrics
+ from the host machine.
+- [`gitlab-exporter`](https://gitlab.com/gitlab-org/gitlab-exporter): Exports process metrics
+ from various GitLab components.
+- Other various GitLab services, such as Sidekiq and the Rails server, which export their own metrics.
#### Test with an Omnibus container
diff --git a/doc/user/project/integrations/jira_integrations.md b/doc/user/project/integrations/jira_integrations.md
index 7cc3be88f09..1f895a9e2fa 100644
--- a/doc/user/project/integrations/jira_integrations.md
+++ b/doc/user/project/integrations/jira_integrations.md
@@ -6,30 +6,18 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Jira integrations **(FREE)**
-GitLab can be integrated with [Jira](https://www.atlassian.com/software/jira).
+If your organization uses [Jira](https://www.atlassian.com/software/jira) issues,
+you can [migrate](../../../user/project/import/jira.md) your issues from Jira and work
+exclusively in GitLab.
-[Issues](../issues/index.md) are a tool for discussing ideas, and planning and tracking work.
-However, your organization may already use Jira for these purposes, with extensive, established data
-and business processes they rely on.
+However, if you'd like to continue to use Jira, you can integrate it with GitLab.
-Although you can [migrate](../../../user/project/import/jira.md) your Jira issues and work
-exclusively in GitLab, you can also continue to use Jira by using the GitLab Jira integrations.
+There are two ways to use GitLab with Jira:
-## Integration types
-
-There are two different Jira integrations that allow different types of cross-referencing between
-GitLab activity and Jira issues, with additional features:
-
-- [Jira integration](jira.md), built in to GitLab. In a given GitLab project, it can be configured
- to connect to any Jira instance, either hosted by you or hosted in
- [Atlassian cloud](https://www.atlassian.com/cloud).
-- [Jira development panel integration](../../../integration/jira/index.md). Connects all
- GitLab projects under a specified group or personal namespace.
-
-Jira development panel integration configuration depends on whether:
-
-- You're using GitLab.com or a self-managed GitLab instance.
-- You're using Jira on [Atlassian cloud](https://www.atlassian.com/cloud) or on your own server.
+- [Jira integration](jira.md). Connect a GitLab project
+ to a Jira instance. The Jira instance can be hosted by you or in [Atlassian cloud](https://www.atlassian.com/cloud).
+- [Jira Development panel integration](../../../integration/jira_development_panel.md).
+ Connect all GitLab projects under a group or personal namespace.
The integration you choose depends on the capabilities you require.
You can also install both at the same time.
diff --git a/lib/api/invitations.rb b/lib/api/invitations.rb
index 52c32b4d1cf..0d562cc18f8 100644
--- a/lib/api/invitations.rb
+++ b/lib/api/invitations.rb
@@ -25,11 +25,11 @@ module API
optional :expires_at, type: DateTime, desc: 'Date string in the format YEAR-MONTH-DAY'
end
post ":id/invitations" do
- source = find_source(source_type, params[:id])
+ params[:source] = find_source(source_type, params[:id])
- authorize_admin_source!(source_type, source)
+ authorize_admin_source!(source_type, params[:source])
- ::Members::InviteService.new(current_user, params).execute(source)
+ ::Members::InviteService.new(current_user, params).execute
end
desc 'Get a list of group or project invitations viewable by the authenticated user' do
diff --git a/lib/api/system_hooks.rb b/lib/api/system_hooks.rb
index 42e16d47a0b..fe23a111b7f 100644
--- a/lib/api/system_hooks.rb
+++ b/lib/api/system_hooks.rb
@@ -47,7 +47,7 @@ module API
params do
requires :id, type: Integer, desc: 'The ID of the system hook'
end
- get ":id" do
+ post ":id" do
hook = SystemHook.find(params[:id])
data = {
event_name: "project_create",
diff --git a/lib/gitlab/ci/pipeline/chain/validate/external.rb b/lib/gitlab/ci/pipeline/chain/validate/external.rb
index 70a5b3adcea..0212a8fcc6f 100644
--- a/lib/gitlab/ci/pipeline/chain/validate/external.rb
+++ b/lib/gitlab/ci/pipeline/chain/validate/external.rb
@@ -69,8 +69,12 @@ module Gitlab
end
def validate_service_request
+ headers = {}
+ headers['X-Gitlab-Token'] = validation_service_token if validation_service_token
+
Gitlab::HTTP.post(
validation_service_url, timeout: validation_service_timeout,
+ headers: headers,
body: validation_service_payload.to_json
)
end
@@ -86,6 +90,10 @@ module Gitlab
ENV['EXTERNAL_VALIDATION_SERVICE_URL']
end
+ def validation_service_token
+ ENV['EXTERNAL_VALIDATION_SERVICE_TOKEN']
+ end
+
def validation_service_payload
{
project: {
diff --git a/lib/gitlab/markdown_cache.rb b/lib/gitlab/markdown_cache.rb
index 36e9a6ccef6..3ec5f2339b5 100644
--- a/lib/gitlab/markdown_cache.rb
+++ b/lib/gitlab/markdown_cache.rb
@@ -3,7 +3,7 @@
module Gitlab
module MarkdownCache
# Increment this number every time the renderer changes its output
- CACHE_COMMONMARK_VERSION = 26
+ CACHE_COMMONMARK_VERSION = 27
CACHE_COMMONMARK_VERSION_START = 10
BaseError = Class.new(StandardError)
diff --git a/lib/gitlab/user_access.rb b/lib/gitlab/user_access.rb
index 0af7ad6ec17..a4a1cccf9d5 100644
--- a/lib/gitlab/user_access.rb
+++ b/lib/gitlab/user_access.rb
@@ -11,10 +11,11 @@ module Gitlab
attr_reader :user, :push_ability
attr_accessor :container
- def initialize(user, container: nil, push_ability: :push_code)
+ def initialize(user, container: nil, push_ability: :push_code, skip_collaboration_check: false)
@user = user
@container = container
@push_ability = push_ability
+ @skip_collaboration_check = skip_collaboration_check
end
def can_do_action?(action)
@@ -87,6 +88,8 @@ module Gitlab
private
+ attr_reader :skip_collaboration_check
+
def can_push?
user.can?(push_ability, container)
end
@@ -98,6 +101,8 @@ module Gitlab
end
def branch_allows_collaboration_for?(ref)
+ return false if skip_collaboration_check
+
# Checking for an internal project or group to prevent an infinite loop:
# https://gitlab.com/gitlab-org/gitlab/issues/36805
(!project.internal? && project.branch_allows_collaboration?(user, ref))
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index fce27db1a97..a197e17b164 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -34656,6 +34656,9 @@ msgstr ""
msgid "Write a comment…"
msgstr ""
+msgid "Write a description or drag your files here…"
+msgstr ""
+
msgid "Write milestone description..."
msgstr ""
diff --git a/qa/qa/page/base.rb b/qa/qa/page/base.rb
index a0b394562de..23502b2ee59 100644
--- a/qa/qa/page/base.rb
+++ b/qa/qa/page/base.rb
@@ -166,6 +166,26 @@ module QA
end
end
+ # Method for selecting radios
+ def choose_element(name, click_by_js = false)
+ if find_element(name, visible: false).checked?
+ QA::Runtime::Logger.debug("#{name} is already selected")
+
+ return
+ end
+
+ retry_until(sleep_interval: 1) do
+ radio = find_element(name, visible: false)
+ # Some radio buttons are hidden by their labels and cannot be clicked directly
+ click_by_js ? page.execute_script("arguments[0].click();", radio) : radio.click
+ selected = find_element(name, visible: false).checked?
+
+ QA::Runtime::Logger.debug(selected ? "#{name} was selected" : "#{name} was not selected")
+
+ selected
+ end
+ end
+
# Use this to simulate moving the pointer to an element's coordinate
# and sending a click event.
# This is a helpful workaround when there is a transparent element overlapping
diff --git a/qa/qa/page/project/settings/merge_request.rb b/qa/qa/page/project/settings/merge_request.rb
index fe5d629effe..0b4a12dbb2e 100644
--- a/qa/qa/page/project/settings/merge_request.rb
+++ b/qa/qa/page/project/settings/merge_request.rb
@@ -20,11 +20,11 @@ module QA
end
def click_save_changes
- click_element :save_merge_request_changes_button
+ click_element(:save_merge_request_changes_button)
end
def enable_ff_only
- click_element :merge_ff_radio_button
+ click_element(:merge_ff_radio_button)
click_save_changes
end
diff --git a/qa/qa/support/page/logging.rb b/qa/qa/support/page/logging.rb
index b27a8192a64..1dbbc052e11 100644
--- a/qa/qa/support/page/logging.rb
+++ b/qa/qa/support/page/logging.rb
@@ -81,7 +81,7 @@ module QA
end
def fill_element(name, content)
- masked_content = name.to_s.include?('password') ? '*****' : content
+ masked_content = name.to_s.match?(/token|key|password/) ? '*****' : content
log(%Q(filling :#{name} with "#{masked_content}"))
diff --git a/scripts/review_apps/base-config.yaml b/scripts/review_apps/base-config.yaml
index 01a94fcee21..7daf3f80efc 100644
--- a/scripts/review_apps/base-config.yaml
+++ b/scripts/review_apps/base-config.yaml
@@ -136,8 +136,10 @@ postgresql:
metrics:
enabled: false
resources:
+ requests:
cpu: 600m
memory: 1000M
+ limits:
cpu: 1300m
memory: 1500M
prometheus:
diff --git a/spec/db/schema_spec.rb b/spec/db/schema_spec.rb
index 0d8407dd7fa..0c44dc2a87a 100644
--- a/spec/db/schema_spec.rb
+++ b/spec/db/schema_spec.rb
@@ -114,7 +114,7 @@ RSpec.describe 'Database schema' do
# postgres and mysql both automatically create an index on the primary
# key. Also, the rails connection.indexes() method does not return
# automatically generated indexes (like the primary key index).
- first_indexed_column = first_indexed_column.push(primary_key_column)
+ first_indexed_column.push(primary_key_column)
expect(first_indexed_column.uniq).to include(*foreign_keys_columns)
end
diff --git a/spec/factories/pool_repositories.rb b/spec/factories/pool_repositories.rb
index f0905d28c70..f3f3e33189b 100644
--- a/spec/factories/pool_repositories.rb
+++ b/spec/factories/pool_repositories.rb
@@ -6,7 +6,7 @@ FactoryBot.define do
state { :none }
before(:create) do |pool|
- pool.source_project = create(:project, :repository)
+ pool.source_project ||= create(:project, :repository)
pool.source_project.update!(pool_repository: pool)
end
diff --git a/spec/features/issues/user_creates_issue_spec.rb b/spec/features/issues/user_creates_issue_spec.rb
index 6e380bdbc0a..e2e204f03db 100644
--- a/spec/features/issues/user_creates_issue_spec.rb
+++ b/spec/features/issues/user_creates_issue_spec.rb
@@ -45,7 +45,7 @@ RSpec.describe "User creates issue" do
.and have_no_content("Milestone")
expect(page.find('#issue_title')['placeholder']).to eq 'Title'
- expect(page.find('#issue_description')['placeholder']).to eq 'Write a comment or drag your files here…'
+ expect(page.find('#issue_description')['placeholder']).to eq 'Write a description or drag your files here…'
end
issue_title = "500 error on profile"
diff --git a/spec/features/merge_request/user_views_open_merge_request_spec.rb b/spec/features/merge_request/user_views_open_merge_request_spec.rb
index 9bda48a3ec5..f1b44010f63 100644
--- a/spec/features/merge_request/user_views_open_merge_request_spec.rb
+++ b/spec/features/merge_request/user_views_open_merge_request_spec.rb
@@ -111,4 +111,21 @@ RSpec.describe 'User views an open merge request' do
end
end
end
+
+ context 'XSS source branch' do
+ let(:project) { create(:project, :public, :repository) }
+ let(:source_branch) { "&#39;&gt;&lt;iframe/srcdoc=&#39;&#39;&gt;&lt;/iframe&gt;" }
+
+ before do
+ project.repository.create_branch(source_branch, "master")
+
+ mr = create(:merge_request, source_project: project, target_project: project, source_branch: source_branch)
+
+ visit(merge_request_path(mr))
+ end
+
+ it 'encodes branch name' do
+ expect(find("[data-testid='ref-name']")[:title]).to eq(source_branch)
+ end
+ end
end
diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb
index 7811394b541..35ca11cb02b 100644
--- a/spec/features/projects/jobs_spec.rb
+++ b/spec/features/projects/jobs_spec.rb
@@ -32,7 +32,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do
it 'shows the empty state page' do
expect(page).to have_content('Use jobs to automate your tasks')
- expect(page).to have_link('Create CI/CD configuration file', href: project.present(current_user: user).add_ci_yml_path)
+ expect(page).to have_link('Create CI/CD configuration file', href: project_ci_pipeline_editor_path(project))
end
end
diff --git a/spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb b/spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb
index 9b51e867156..dc551158895 100644
--- a/spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb
+++ b/spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb
@@ -226,11 +226,11 @@ RSpec.describe 'Projects > Show > User sees setup shortcut buttons' do
expect(project.repository.gitlab_ci_yml).to be_nil
page.within('.project-buttons') do
- expect(page).to have_link('Set up CI/CD', href: presenter.add_ci_yml_path)
+ expect(page).to have_link('Set up CI/CD', href: project_ci_pipeline_editor_path(project))
end
end
- it 'no "Set up CI/CD" button if the project already has a .gitlab-ci.yml' do
+ it '"Set up CI/CD" button is renamed if the project already has a .gitlab-ci.yml' do
Files::CreateService.new(
project,
project.creator,
@@ -247,6 +247,7 @@ RSpec.describe 'Projects > Show > User sees setup shortcut buttons' do
page.within('.project-buttons') do
expect(page).not_to have_link('Set up CI/CD')
+ expect(page).to have_link('CI/CD configuration')
end
end
end
diff --git a/spec/frontend/pages/admin/users/components/__snapshots__/delete_user_modal_spec.js.snap b/spec/frontend/pages/admin/users/components/__snapshots__/delete_user_modal_spec.js.snap
index ddeaa2a79db..9f02e5b9432 100644
--- a/spec/frontend/pages/admin/users/components/__snapshots__/delete_user_modal_spec.js.snap
+++ b/spec/frontend/pages/admin/users/components/__snapshots__/delete_user_modal_spec.js.snap
@@ -50,11 +50,11 @@ exports[`User Operation confirmation modal renders modal with form included 1`]
<gl-button-stub
buttontextclasses=""
- category="primary"
+ category="secondary"
disabled="true"
icon=""
size="medium"
- variant="warning"
+ variant="danger"
>
secondaryAction
diff --git a/spec/frontend/pages/admin/users/components/delete_user_modal_spec.js b/spec/frontend/pages/admin/users/components/delete_user_modal_spec.js
index c7293b00adf..318b6d16008 100644
--- a/spec/frontend/pages/admin/users/components/delete_user_modal_spec.js
+++ b/spec/frontend/pages/admin/users/components/delete_user_modal_spec.js
@@ -11,15 +11,15 @@ describe('User Operation confirmation modal', () => {
let wrapper;
let formSubmitSpy;
- const findButton = (variant) =>
+ const findButton = (variant, category) =>
wrapper
.findAll(GlButton)
- .filter((w) => w.attributes('variant') === variant)
+ .filter((w) => w.attributes('variant') === variant && w.attributes('category') === category)
.at(0);
const findForm = () => wrapper.find('form');
const findUsernameInput = () => wrapper.find(GlFormInput);
- const findPrimaryButton = () => findButton('danger');
- const findSecondaryButton = () => findButton('warning');
+ const findPrimaryButton = () => findButton('danger', 'primary');
+ const findSecondaryButton = () => findButton('danger', 'secondary');
const findAuthenticityToken = () => new FormData(findForm().element).get('authenticity_token');
const getUsername = () => findUsernameInput().attributes('value');
const getMethodParam = () => new FormData(findForm().element).get('_method');
diff --git a/spec/lib/gitlab/asciidoc_spec.rb b/spec/lib/gitlab/asciidoc_spec.rb
index 08510d4652b..3eb015a5a22 100644
--- a/spec/lib/gitlab/asciidoc_spec.rb
+++ b/spec/lib/gitlab/asciidoc_spec.rb
@@ -92,6 +92,15 @@ module Gitlab
expect(render(data[:input], context)).to include(data[:output])
end
end
+
+ it 'does not allow locked attributes to be overridden' do
+ input = <<~ADOC
+ {counter:max-include-depth:1234}
+ <|-- {max-include-depth}
+ ADOC
+
+ expect(render(input, {})).not_to include('1234')
+ end
end
context "images" do
@@ -543,6 +552,40 @@ module Gitlab
expect(render(input, context)).to include(output.strip)
end
+
+ it 'does not allow kroki-plantuml-include to be overridden' do
+ input = <<~ADOC
+ [plantuml, test="{counter:kroki-plantuml-include:/etc/passwd}", format="png"]
+ ....
+ class BlockProcessor
+
+ BlockProcessor <|-- {counter:kroki-plantuml-include}
+ ....
+ ADOC
+
+ output = <<~HTML
+ <div>
+ <div>
+ <a class=\"no-attachment-icon\" href=\"https://kroki.io/plantuml/png/eNpLzkksLlZwyslPzg4oyk9OLS7OL-LiQuUr2NTo6ipUJ-eX5pWkFlllF-VnZ-oW5CTmlZTm5uhm5iXnlKak1gIABQEb8A==\" target=\"_blank\" rel=\"noopener noreferrer\"><img src=\"data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Diagram\" class=\"lazy\" data-src=\"https://kroki.io/plantuml/png/eNpLzkksLlZwyslPzg4oyk9OLS7OL-LiQuUr2NTo6ipUJ-eX5pWkFlllF-VnZ-oW5CTmlZTm5uhm5iXnlKak1gIABQEb8A==\"></a>
+ </div>
+ </div>
+ HTML
+
+ expect(render(input, {})).to include(output.strip)
+ end
+
+ it 'does not allow kroki-server-url to be overridden' do
+ input = <<~ADOC
+ [plantuml, test="{counter:kroki-server-url:evilsite}", format="png"]
+ ....
+ class BlockProcessor
+
+ BlockProcessor
+ ....
+ ADOC
+
+ expect(render(input, {})).not_to include('evilsite')
+ end
end
context 'with Kroki and BlockDiag (additional format) enabled' do
diff --git a/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb
index cb0671f02c6..1fd40b454ff 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb
@@ -63,6 +63,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::External do
expect(::Gitlab::HTTP).to receive(:post) do |_url, params|
expect(params[:body]).to match_schema('/external_validation')
expect(params[:timeout]).to eq(described_class::DEFAULT_VALIDATION_REQUEST_TIMEOUT)
+ expect(params[:headers]).to eq({})
end
perform!
@@ -119,6 +120,20 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::External do
end
end
+ context 'when EXTERNAL_VALIDATION_SERVICE_TOKEN is set' do
+ before do
+ stub_env('EXTERNAL_VALIDATION_SERVICE_TOKEN', '123')
+ end
+
+ it 'passes token in X-Gitlab-Token header' do
+ expect(::Gitlab::HTTP).to receive(:post) do |_url, params|
+ expect(params[:headers]).to eq({ 'X-Gitlab-Token' => '123' })
+ end
+
+ perform!
+ end
+ end
+
context 'when validation returns 200 OK' do
before do
stub_request(:post, validation_service_url).to_return(status: 200, body: "{}")
diff --git a/spec/lib/gitlab/user_access_spec.rb b/spec/lib/gitlab/user_access_spec.rb
index 97fff030906..01890305df4 100644
--- a/spec/lib/gitlab/user_access_spec.rb
+++ b/spec/lib/gitlab/user_access_spec.rb
@@ -216,6 +216,15 @@ RSpec.describe Gitlab::UserAccess do
expect(access.can_merge_to_branch?(@branch.name)).to be_falsey
end
end
+
+ context 'when skip_collaboration_check is true' do
+ let(:access) { described_class.new(user, container: project, skip_collaboration_check: true) }
+
+ it 'does not call Project#branch_allows_collaboration?' do
+ expect(project).not_to receive(:branch_allows_collaboration?)
+ expect(access.can_push_to_branch?('master')).to be_falsey
+ end
+ end
end
describe '#can_create_tag?' do
diff --git a/spec/models/members/group_member_spec.rb b/spec/models/members/group_member_spec.rb
index 3d3ed6fc54a..908bb9f91a3 100644
--- a/spec/models/members/group_member_spec.rb
+++ b/spec/models/members/group_member_spec.rb
@@ -66,6 +66,12 @@ RSpec.describe GroupMember do
it_behaves_like 'members notifications', :group
+ describe '#namespace_id' do
+ subject { build(:group_member, source_id: 1).namespace_id }
+
+ it { is_expected.to eq 1 }
+ end
+
describe '#real_source_type' do
subject { create(:group_member).real_source_type }
diff --git a/spec/models/members/project_member_spec.rb b/spec/models/members/project_member_spec.rb
index 388d04c8012..ce3e86f964d 100644
--- a/spec/models/members/project_member_spec.rb
+++ b/spec/models/members/project_member_spec.rb
@@ -13,6 +13,10 @@ RSpec.describe ProjectMember do
it { is_expected.to validate_inclusion_of(:access_level).in_array(Gitlab::Access.values) }
end
+ describe 'delegations' do
+ it { is_expected.to delegate_method(:namespace_id).to(:project) }
+ end
+
describe '.access_level_roles' do
it 'returns Gitlab::Access.options' do
expect(described_class.access_level_roles).to eq(Gitlab::Access.options)
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 6c95fb6c52e..b99ae8f0642 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -5319,6 +5319,64 @@ RSpec.describe Project, factory_default: :keep do
end
end
+ describe '#branch_allows_collaboration?' do
+ context 'when there are open merge requests that have their source/target branches point to each other' do
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:reporter) { create(:user) }
+ let_it_be(:guest) { create(:user) }
+
+ before_all do
+ create(
+ :merge_request,
+ target_project: project,
+ target_branch: 'master',
+ source_project: project,
+ source_branch: 'merge-test',
+ allow_collaboration: true
+ )
+
+ create(
+ :merge_request,
+ target_project: project,
+ target_branch: 'merge-test',
+ source_project: project,
+ source_branch: 'master',
+ allow_collaboration: true
+ )
+
+ project.add_developer(developer)
+ project.add_reporter(reporter)
+ project.add_guest(guest)
+ end
+
+ shared_examples_for 'successful check' do
+ it 'does not go into an infinite loop' do
+ expect { project.branch_allows_collaboration?(user, 'master') }
+ .not_to raise_error
+ end
+ end
+
+ context 'when user is a developer' do
+ let(:user) { developer }
+
+ it_behaves_like 'successful check'
+ end
+
+ context 'when user is a reporter' do
+ let(:user) { reporter }
+
+ it_behaves_like 'successful check'
+ end
+
+ context 'when user is a guest' do
+ let(:user) { guest }
+
+ it_behaves_like 'successful check'
+ end
+ end
+ end
+
context 'with cross project merge requests' do
let(:user) { create(:user) }
let(:target_project) { create(:project, :repository) }
diff --git a/spec/requests/api/system_hooks_spec.rb b/spec/requests/api/system_hooks_spec.rb
index 01b46053d52..3cea1af686e 100644
--- a/spec/requests/api/system_hooks_spec.rb
+++ b/spec/requests/api/system_hooks_spec.rb
@@ -103,15 +103,15 @@ RSpec.describe API::SystemHooks do
end
end
- describe "GET /hooks/:id" do
- it "returns hook by id" do
- get api("/hooks/#{hook.id}", admin)
- expect(response).to have_gitlab_http_status(:ok)
+ describe 'POST /hooks/:id' do
+ it "returns and trigger hook by id" do
+ post api("/hooks/#{hook.id}", admin)
+ expect(response).to have_gitlab_http_status(:created)
expect(json_response['event_name']).to eq('project_create')
end
it "returns 404 on failure" do
- get api("/hooks/404", admin)
+ post api("/hooks/404", admin)
expect(response).to have_gitlab_http_status(:not_found)
end
end
diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb
index 80065eb97dd..056f4d30ea5 100644
--- a/spec/routing/project_routing_spec.rb
+++ b/spec/routing/project_routing_spec.rb
@@ -684,6 +684,26 @@ RSpec.describe 'project routing' do
end
end
+ describe Projects::PipelinesController, 'routing' do
+ it 'to #index' do
+ expect(get('/gitlab/gitlabhq/-/pipelines')).to route_to('projects/pipelines#index', namespace_id: 'gitlab', project_id: 'gitlabhq')
+ end
+
+ it 'to #show' do
+ expect(get('/gitlab/gitlabhq/-/pipelines/12')).to route_to('projects/pipelines#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '12')
+ end
+
+ it_behaves_like 'redirecting a legacy path', '/gitlab/gitlabhq/pipelines', '/gitlab/gitlabhq/-/pipelines'
+ end
+
+ describe Projects::PipelineSchedulesController, 'routing' do
+ it 'to #index' do
+ expect(get('/gitlab/gitlabhq/-/pipeline_schedules')).to route_to('projects/pipeline_schedules#index', namespace_id: 'gitlab', project_id: 'gitlabhq')
+ end
+
+ it_behaves_like 'redirecting a legacy path', '/gitlab/gitlabhq/pipeline_schedules', '/gitlab/gitlabhq/-/pipeline_schedules'
+ end
+
describe Projects::Settings::OperationsController, 'routing' do
it 'to #reset_alerting_token' do
expect(post('/gitlab/gitlabhq/-/settings/operations/reset_alerting_token')).to route_to('projects/settings/operations#reset_alerting_token', namespace_id: 'gitlab', project_id: 'gitlabhq')
diff --git a/spec/services/members/invite_service_spec.rb b/spec/services/members/invite_service_spec.rb
index cced93896a5..82793d2e73c 100644
--- a/spec/services/members/invite_service_spec.rb
+++ b/spec/services/members/invite_service_spec.rb
@@ -2,29 +2,43 @@
require 'spec_helper'
-RSpec.describe Members::InviteService, :aggregate_failures do
+RSpec.describe Members::InviteService, :aggregate_failures, :clean_gitlab_redis_shared_state, :sidekiq_inline do
let_it_be(:project) { create(:project) }
let_it_be(:user) { project.owner }
let_it_be(:project_user) { create(:user) }
+ let_it_be(:namespace) { project.namespace }
let(:params) { {} }
- let(:base_params) { { access_level: Gitlab::Access::GUEST } }
+ let(:base_params) { { access_level: Gitlab::Access::GUEST, source: project } }
- subject(:result) { described_class.new(user, base_params.merge(params)).execute(project) }
+ subject(:result) { described_class.new(user, base_params.merge(params) ).execute }
- context 'when email is previously unused by current members' do
+ context 'when there is a valid member invited' do
let(:params) { { email: 'email@example.org' } }
it 'successfully creates a member' do
- expect { result }.to change(ProjectMember, :count).by(1)
+ expect_to_create_members(count: 1)
expect(result[:status]).to eq(:success)
end
+
+ it_behaves_like 'records an onboarding progress action', :user_added
+ end
+
+ context 'when email is not a valid email' do
+ let(:params) { { email: '_bogus_' } }
+
+ it 'returns an error' do
+ expect_not_to_create_members
+ expect(result[:message]['_bogus_']).to eq("Invite email is invalid")
+ end
+
+ it_behaves_like 'does not record an onboarding progress action'
end
context 'when emails are passed as an array' do
let(:params) { { email: %w[email@example.org email2@example.org] } }
it 'successfully creates members' do
- expect { result }.to change(ProjectMember, :count).by(2)
+ expect_to_create_members(count: 2)
expect(result[:status]).to eq(:success)
end
end
@@ -33,33 +47,23 @@ RSpec.describe Members::InviteService, :aggregate_failures do
let(:params) { { email: '' } }
it 'returns an error' do
- expect(result[:status]).to eq(:error)
+ expect_not_to_create_members
expect(result[:message]).to eq('Email cannot be blank')
end
end
context 'when email param is not included' do
it 'returns an error' do
- expect(result[:status]).to eq(:error)
+ expect_not_to_create_members
expect(result[:message]).to eq('Email cannot be blank')
end
end
- context 'when email is not a valid email' do
- let(:params) { { email: '_bogus_' } }
-
- it 'returns an error' do
- expect { result }.not_to change(ProjectMember, :count)
- expect(result[:status]).to eq(:error)
- expect(result[:message]['_bogus_']).to eq("Invite email is invalid")
- end
- end
-
context 'when duplicate email addresses are passed' do
let(:params) { { email: 'email@example.org,email@example.org' } }
it 'only creates one member per unique address' do
- expect { result }.to change(ProjectMember, :count).by(1)
+ expect_to_create_members(count: 1)
expect(result[:status]).to eq(:success)
end
end
@@ -71,8 +75,7 @@ RSpec.describe Members::InviteService, :aggregate_failures do
let(:params) { { email: emails } }
it 'limits the number of emails to 100' do
- expect { result }.not_to change(ProjectMember, :count)
- expect(result[:status]).to eq(:error)
+ expect_not_to_create_members
expect(result[:message]).to eq('Too many users specified (limit is 100)')
end
end
@@ -81,8 +84,7 @@ RSpec.describe Members::InviteService, :aggregate_failures do
let(:params) { { email: 'email@example.org,email2@example.org', limit: 1 } }
it 'limits the number of emails to the limit supplied' do
- expect { result }.not_to change(ProjectMember, :count)
- expect(result[:status]).to eq(:error)
+ expect_not_to_create_members
expect(result[:message]).to eq('Too many users specified (limit is 1)')
end
end
@@ -91,7 +93,7 @@ RSpec.describe Members::InviteService, :aggregate_failures do
let(:params) { { email: emails, limit: -1 } }
it 'does not limit number of emails' do
- expect { result }.to change(ProjectMember, :count).by(101)
+ expect_to_create_members(count: 101)
expect(result[:status]).to eq(:success)
end
end
@@ -101,7 +103,7 @@ RSpec.describe Members::InviteService, :aggregate_failures do
let(:params) { { email: project_user.email } }
it 'adds an existing user to members' do
- expect { result }.to change(ProjectMember, :count).by(1)
+ expect_to_create_members(count: 1)
expect(result[:status]).to eq(:success)
expect(project.users).to include project_user
end
@@ -111,8 +113,7 @@ RSpec.describe Members::InviteService, :aggregate_failures do
let(:params) { { email: project_user.email, access_level: -1 } }
it 'returns an error' do
- expect { result }.not_to change(ProjectMember, :count)
- expect(result[:status]).to eq(:error)
+ expect_not_to_create_members
expect(result[:message][project_user.email]).to eq("Access level is not included in the list")
end
end
@@ -122,7 +123,7 @@ RSpec.describe Members::InviteService, :aggregate_failures do
let(:params) { { email: "#{invited_member.invite_email},#{project_user.email}" } }
it 'adds new email and returns an error for the already invited email' do
- expect { result }.to change(ProjectMember, :count).by(1)
+ expect_to_create_members(count: 1)
expect(result[:status]).to eq(:error)
expect(result[:message][invited_member.invite_email]).to eq("Member already invited to #{project.name}")
expect(project.users).to include project_user
@@ -134,7 +135,7 @@ RSpec.describe Members::InviteService, :aggregate_failures do
let(:params) { { email: "#{requested_member.user.email},#{project_user.email}" } }
it 'adds new email and returns an error for the already invited email' do
- expect { result }.to change(ProjectMember, :count).by(1)
+ expect_to_create_members(count: 1)
expect(result[:status]).to eq(:error)
expect(result[:message][requested_member.user.email])
.to eq("Member cannot be invited because they already requested to join #{project.name}")
@@ -147,10 +148,19 @@ RSpec.describe Members::InviteService, :aggregate_failures do
let(:params) { { email: "#{existing_member.user.email},#{project_user.email}" } }
it 'adds new email and returns an error for the already invited email' do
- expect { result }.to change(ProjectMember, :count).by(1)
+ expect_to_create_members(count: 1)
expect(result[:status]).to eq(:error)
expect(result[:message][existing_member.user.email]).to eq("Already a member of #{project.name}")
expect(project.users).to include project_user
end
end
+
+ def expect_to_create_members(count:)
+ expect { result }.to change(ProjectMember, :count).by(count)
+ end
+
+ def expect_not_to_create_members
+ expect { result }.not_to change(ProjectMember, :count)
+ expect(result[:status]).to eq(:error)
+ end
end
diff --git a/spec/services/projects/fork_service_spec.rb b/spec/services/projects/fork_service_spec.rb
index df02f8ea15d..276656656ec 100644
--- a/spec/services/projects/fork_service_spec.rb
+++ b/spec/services/projects/fork_service_spec.rb
@@ -403,7 +403,7 @@ RSpec.describe Projects::ForkService do
end
context 'when forking with object pools' do
- let(:fork_from_project) { create(:project, :public) }
+ let(:fork_from_project) { create(:project, :repository, :public) }
let(:forker) { create(:user) }
context 'when no pool exists' do
diff --git a/spec/services/projects/unlink_fork_service_spec.rb b/spec/services/projects/unlink_fork_service_spec.rb
index 2a8965e62ce..90def365fca 100644
--- a/spec/services/projects/unlink_fork_service_spec.rb
+++ b/spec/services/projects/unlink_fork_service_spec.rb
@@ -207,6 +207,17 @@ RSpec.describe Projects::UnlinkForkService, :use_clean_rails_memory_store_cachin
end
end
+ context 'a project with pool repository' do
+ let(:project) { create(:project, :public, :repository) }
+ let!(:pool_repository) { create(:pool_repository, :ready, source_project: project) }
+
+ subject { described_class.new(project, user) }
+
+ it 'when unlinked leaves pool repository' do
+ expect { subject.execute }.to change { project.reload.has_pool_repository? }.from(true).to(false)
+ end
+ end
+
context 'when given project is not part of a fork network' do
let!(:project_without_forks) { create(:project, :public) }
diff --git a/spec/workers/expire_job_cache_worker_spec.rb b/spec/workers/expire_job_cache_worker_spec.rb
index 95c54a762a4..8efead31a42 100644
--- a/spec/workers/expire_job_cache_worker_spec.rb
+++ b/spec/workers/expire_job_cache_worker_spec.rb
@@ -8,7 +8,8 @@ RSpec.describe ExpireJobCacheWorker do
describe '#perform' do
context 'with a job in the pipeline' do
- let(:job) { create(:ci_build, pipeline: pipeline) }
+ let_it_be(:job) { create(:ci_build, pipeline: pipeline) }
+
let(:job_args) { job.id }
include_examples 'an idempotent worker' do
@@ -31,6 +32,24 @@ RSpec.describe ExpireJobCacheWorker do
subject
end
end
+
+ it 'does not perform extra queries', :aggregate_failures do
+ worker = described_class.new
+ recorder = ActiveRecord::QueryRecorder.new { worker.perform(job.id) }
+
+ occurences = recorder.data.values.flat_map {|v| v[:occurrences]}
+ project_queries = occurences.select {|s| s.include?('FROM "projects"')}
+ namespace_queries = occurences.select {|s| s.include?('FROM "namespaces"')}
+ route_queries = occurences.select {|s| s.include?('FROM "routes"')}
+
+ # This worker is run 1 million times an hour, so we need to save as much
+ # queries as possible.
+ expect(recorder.count).to be <= 1
+
+ expect(project_queries.size).to eq(0)
+ expect(namespace_queries.size).to eq(0)
+ expect(route_queries.size).to eq(0)
+ end
end
context 'when there is no job in the pipeline' do
diff --git a/vendor/gitignore/C++.gitignore b/vendor/gitignore/C++.gitignore
index 259148fa18f..259148fa18f 100644..100755
--- a/vendor/gitignore/C++.gitignore
+++ b/vendor/gitignore/C++.gitignore
diff --git a/vendor/gitignore/Java.gitignore b/vendor/gitignore/Java.gitignore
index a1c2a238a96..a1c2a238a96 100644..100755
--- a/vendor/gitignore/Java.gitignore
+++ b/vendor/gitignore/Java.gitignore