diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-02-23 12:11:53 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-02-23 12:11:53 +0000 |
commit | 4a7ca716f68682c41889dc480c029d71dd121f4e (patch) | |
tree | 69b4d87c3e2fc35636e64d1eba0078ea0e1a60b2 | |
parent | 946a41d182e40dd37f73c44721edc9bc9c1a0f7c (diff) | |
download | gitlab-ce-4a7ca716f68682c41889dc480c029d71dd121f4e.tar.gz |
Add latest changes from gitlab-org/gitlab@master
67 files changed, 710 insertions, 443 deletions
diff --git a/.gitlab/ci/docs.gitlab-ci.yml b/.gitlab/ci/docs.gitlab-ci.yml index b404444f815..d65c4094cc8 100644 --- a/.gitlab/ci/docs.gitlab-ci.yml +++ b/.gitlab/ci/docs.gitlab-ci.yml @@ -42,7 +42,7 @@ review-docs-cleanup: docs-lint links: extends: - .docs:rules:docs-lint - image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-docs/lint-html:alpine-3.16-ruby-3.0.5-869cfc5d + image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-docs/lint-html:alpine-3.16-ruby-3.0.5-2a7e4d1c stage: lint needs: [] script: @@ -58,7 +58,7 @@ docs-lint links: .docs-markdown-lint-image: # When updating the image version here, update it in /scripts/lint-doc.sh too. - image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-docs/lint-markdown:alpine-3.16-vale-2.22.0-markdownlint-0.32.2-markdownlint2-0.6.0 + image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-docs/lint-markdown:alpine-3.16-vale-2.23.0-markdownlint-0.33.0-markdownlint2-0.6.0 docs-lint markdown: extends: diff --git a/.rubocop_todo/rspec/missing_feature_category.yml b/.rubocop_todo/rspec/missing_feature_category.yml index 289eeab505a..12e76e391ca 100644 --- a/.rubocop_todo/rspec/missing_feature_category.yml +++ b/.rubocop_todo/rspec/missing_feature_category.yml @@ -3866,7 +3866,6 @@ RSpec/MissingFeatureCategory: - 'spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_started_spec.rb' - 'spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_merged_spec.rb' - 'spec/lib/gitlab/analytics/cycle_analytics/stage_events/plan_stage_start_spec.rb' - - 'spec/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event_spec.rb' - 'spec/lib/gitlab/analytics/date_filler_spec.rb' - 'spec/lib/gitlab/analytics/usage_trends/workers_argument_builder_spec.rb' - 'spec/lib/gitlab/anonymous_session_spec.rb' diff --git a/app/assets/javascripts/diffs/components/diff_code_quality.vue b/app/assets/javascripts/diffs/components/diff_code_quality.vue index 11aa856619b..5392c631c14 100644 --- a/app/assets/javascripts/diffs/components/diff_code_quality.vue +++ b/app/assets/javascripts/diffs/components/diff_code_quality.vue @@ -28,7 +28,7 @@ export default { <template> <div data-testid="diff-codequality" - class="gl-relative codequality-findings-list gl-border-top-1 gl-border-bottom-1 gl-bg-gray-10 gl-pl-5 gl-pt-4 gl-pb-4" + class="gl-relative codequality-findings-list gl-border-top-1 gl-border-bottom-1 gl-bg-gray-10 gl-text-black-normal gl-pl-5 gl-pt-4 gl-pb-4" > <h4 data-testid="diff-codequality-findings-heading" diff --git a/app/assets/javascripts/pages/projects/blob/show/index.js b/app/assets/javascripts/pages/projects/blob/show/index.js index e45f9a10294..a0f391c912b 100644 --- a/app/assets/javascripts/pages/projects/blob/show/index.js +++ b/app/assets/javascripts/pages/projects/blob/show/index.js @@ -13,6 +13,9 @@ import CommitPipelineStatus from '~/projects/tree/components/commit_pipeline_sta import BlobContentViewer from '~/repository/components/blob_content_viewer.vue'; import '~/sourcegraph/load'; import createStore from '~/code_navigation/store'; +import { generateRefDestinationPath } from '~/repository/utils/ref_switcher_utils'; +import RefSelector from '~/ref/components/ref_selector.vue'; +import { visitUrl } from '~/lib/utils/url_utility'; Vue.use(Vuex); Vue.use(VueApollo); @@ -26,6 +29,33 @@ const router = new VueRouter({ mode: 'history' }); const viewBlobEl = document.querySelector('#js-view-blob-app'); +const initRefSwitcher = () => { + const refSwitcherEl = document.getElementById('js-tree-ref-switcher'); + + if (!refSwitcherEl) return false; + + const { projectId, projectRootPath, ref } = refSwitcherEl.dataset; + + return new Vue({ + el: refSwitcherEl, + render(createElement) { + return createElement(RefSelector, { + props: { + projectId, + value: ref, + }, + on: { + input(selectedRef) { + visitUrl(generateRefDestinationPath(projectRootPath, ref, selectedRef)); + }, + }, + }); + }, + }); +}; + +initRefSwitcher(); + if (viewBlobEl) { const { blobPath, projectPath, targetBranch, originalBranch } = viewBlobEl.dataset; diff --git a/app/controllers/projects/commits_controller.rb b/app/controllers/projects/commits_controller.rb index 3acc71d5dd3..fc26ba09c70 100644 --- a/app/controllers/projects/commits_controller.rb +++ b/app/controllers/projects/commits_controller.rb @@ -7,7 +7,6 @@ class Projects::CommitsController < Projects::ApplicationController include RendersCommits COMMITS_DEFAULT_LIMIT = 40 - prepend_before_action(only: [:show]) { authenticate_sessionless_user!(:rss) } around_action :allow_gitaly_ref_name_caching before_action :require_non_empty_project @@ -77,13 +76,24 @@ class Projects::CommitsController < Projects::ApplicationController # fully_qualified_ref is available in some situations from ExtractsRef ref = @fully_qualified_ref || @ref + + show_tags = Feature.enabled?(:show_tags_on_commits_view, @project) @commits = if search.present? - @repository.find_commits_by_message(search, ref, @path, @limit, @offset) - elsif author.present? - @repository.commits(ref, author: author, path: @path, limit: @limit, offset: @offset) + @repository.find_commits_by_message(search, ref, @path, @limit, @offset).tap do |collection| + collection.load_tags if show_tags + end else - @repository.commits(ref, path: @path, limit: @limit, offset: @offset) + options = { + path: @path, + limit: @limit, + offset: @offset + } + + options[:author] = author if author.present? + options[:include_referenced_by] = [Gitlab::Git::TAG_REF_PREFIX] if show_tags + + @repository.commits(ref, **options) end @commits.each(&:lazy_author) # preload authors diff --git a/app/graphql/types/commit_signatures/ssh_signature_type.rb b/app/graphql/types/commit_signatures/ssh_signature_type.rb index 92eb4f7949a..d5db98c39a0 100644 --- a/app/graphql/types/commit_signatures/ssh_signature_type.rb +++ b/app/graphql/types/commit_signatures/ssh_signature_type.rb @@ -10,14 +10,19 @@ module Types authorize :download_code - field :user, Types::UserType, null: true, - method: :signed_by_user, - calls_gitaly: true, - description: 'User associated with the key.' + field :user, Types::UserType, + null: true, + method: :signed_by_user, + calls_gitaly: true, + description: 'User associated with the key.' field :key, Types::KeyType, - null: true, - description: 'SSH key used for the signature.' + null: true, + description: 'SSH key used for the signature.' + + field :key_fingerprint_sha256, String, + null: true, + description: 'Fingerprint of the key.' end end end diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb index f75d3657986..f4893a83304 100644 --- a/app/helpers/commits_helper.rb +++ b/app/helpers/commits_helper.rb @@ -161,17 +161,23 @@ module CommitsHelper # This includes a keyed hash for values that can be nil, to prevent invalid cache entries # being served if the order should change in future. def commit_partial_cache_key(commit, ref:, merge_request:, request:) + keyed_hash = { + merge_request: merge_request&.cache_key, + pipeline_status: commit.detailed_status_for(ref)&.cache_key, + xhr: request.xhr?, + controller: controller.controller_path, + path: @path # referred to in #link_to_browse_code + } + + if Feature.enabled?(:show_tags_on_commits_view, commit.project) + keyed_hash[:referenced_by] = tag_checksum(commit.referenced_by) + end + [ commit, commit.author, ref, - { - merge_request: merge_request&.cache_key, - pipeline_status: commit.detailed_status_for(ref)&.cache_key, - xhr: request.xhr?, - controller: controller.controller_path, - path: @path # referred to in #link_to_browse_code - } + keyed_hash ] end @@ -198,6 +204,10 @@ module CommitsHelper protected + def tag_checksum(tags_array) + ::Zlib.crc32(tags_array.sort.join) + end + # Private: Returns a link to a person. If the person has a matching user and # is a member of the current @project it will link to the team member page. # Otherwise it will link to the person email as specified in the commit. diff --git a/app/models/commit_collection.rb b/app/models/commit_collection.rb index 47ecdfa8574..eb7db0fc9b4 100644 --- a/app/models/commit_collection.rb +++ b/app/models/commit_collection.rb @@ -118,4 +118,21 @@ class CommitCollection def next_page @pagination.next_page end + + def load_tags + oids = commits.map(&:id) + references = repository.list_refs([Gitlab::Git::TAG_REF_PREFIX], pointing_at_oids: oids, peel_tags: true) + oid_to_references = references.group_by { |reference| reference.peeled_target.presence || reference.target } + + return self if oid_to_references.empty? + + commits.each do |commit| + grouped_references = oid_to_references[commit.id] + next unless grouped_references + + commit.referenced_by = grouped_references.map(&:name) + end + + self + end end diff --git a/app/models/concerns/cached_commit.rb b/app/models/concerns/cached_commit.rb index 0fb72552dd5..8a53fec0612 100644 --- a/app/models/concerns/cached_commit.rb +++ b/app/models/concerns/cached_commit.rb @@ -14,4 +14,9 @@ module CachedCommit def parent_ids [] end + + # These are not saved + def referenced_by + [] + end end diff --git a/app/models/merge_request_diff_commit.rb b/app/models/merge_request_diff_commit.rb index 7e2efa2049b..fc08dd4d9c8 100644 --- a/app/models/merge_request_diff_commit.rb +++ b/app/models/merge_request_diff_commit.rb @@ -80,7 +80,7 @@ class MergeRequestDiffCommit < ApplicationRecord def self.prepare_commits_for_bulk_insert(commits) user_tuples = Set.new hashes = commits.map do |commit| - hash = commit.to_hash.except(:parent_ids) + hash = commit.to_hash.except(:parent_ids, :referenced_by) TRIM_USER_KEYS.each do |key| hash[key] = MergeRequest::DiffCommitUser.prepare(hash[key]) diff --git a/app/models/repository.rb b/app/models/repository.rb index d15f2a430fa..7a374bad921 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -161,7 +161,8 @@ class Repository first_parent: !!opts[:first_parent], order: opts[:order], literal_pathspec: opts.fetch(:literal_pathspec, true), - trailers: opts[:trailers] + trailers: opts[:trailers], + include_referenced_by: opts[:include_referenced_by] } commits = Gitlab::Git::Commit.where(options) diff --git a/app/presenters/commit_presenter.rb b/app/presenters/commit_presenter.rb index 2cb88179845..2f505901901 100644 --- a/app/presenters/commit_presenter.rb +++ b/app/presenters/commit_presenter.rb @@ -25,6 +25,10 @@ class CommitPresenter < Gitlab::View::Presenter::Delegated commit.pipelines.any? end + def tags_for_display + commit.referenced_by&.map { |tag| tag.delete_prefix(Gitlab::Git::TAG_REF_PREFIX) } + end + def signature_html return unless commit.has_signature? diff --git a/app/services/merge_requests/add_context_service.rb b/app/services/merge_requests/add_context_service.rb index 2ce6073050e..a9ef3e85911 100644 --- a/app/services/merge_requests/add_context_service.rb +++ b/app/services/merge_requests/add_context_service.rb @@ -57,7 +57,7 @@ module MergeRequests def build_context_commit_rows(merge_request_id, commits) commits.map.with_index do |commit, index| # generate context commit information for given commit - commit_hash = commit.to_hash.except(:parent_ids) + commit_hash = commit.to_hash.except(:parent_ids, :referenced_by) sha = Gitlab::Database::ShaAttribute.serialize(commit_hash.delete(:id)) commit_hash.merge( merge_request_id: merge_request_id, @@ -75,7 +75,7 @@ module MergeRequests diff_order = 0 commits.flat_map.with_index do |commit, index| - commit_hash = commit.to_hash.except(:parent_ids) + commit_hash = commit.to_hash.except(:parent_ids, :referenced_by) sha = Gitlab::Database::ShaAttribute.serialize(commit_hash.delete(:id)) # generate context commit diff information for given commit diffs = commit.diffs diff --git a/app/views/projects/blob/_breadcrumb.html.haml b/app/views/projects/blob/_breadcrumb.html.haml index 7c2caf34fd1..e77367a7b42 100644 --- a/app/views/projects/blob/_breadcrumb.html.haml +++ b/app/views/projects/blob/_breadcrumb.html.haml @@ -2,7 +2,7 @@ .nav-block .tree-ref-container .tree-ref-holder - = render 'shared/ref_switcher', destination: 'blob' + #js-tree-ref-switcher{ data: { project_id: @project.id, project_root_path: project_path(@project), ref: current_ref } } %ul.breadcrumb.repo-breadcrumb %li.breadcrumb-item diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml index b5481f19352..6209ef48f96 100644 --- a/app/views/projects/commits/_commit.html.haml +++ b/app/views/projects/commits/_commit.html.haml @@ -15,6 +15,7 @@ - ref = local_assigns.fetch(:ref) { merge_request&.source_branch } - commit = commit.present(current_user: current_user) - commit_status = commit.detailed_status_for(ref) +- tags = commit.tags_for_display - collapsible = local_assigns.fetch(:collapsible, true) - link_data_attrs = local_assigns.fetch(:link_data_attrs, {}) - link = commit_path(project, commit, merge_request: merge_request) @@ -55,6 +56,13 @@ = preserve(markdown_field(commit, :description)) .commit-actions.flex-row + - if tags.present? + = gl_badge_tag(variant: :neutral, icon: 'tag', class: 'gl-font-monospace') do + - if tags.size > 1 + = link_to _('%{count} tags') % { count: tags.size } , project_commit_path(project, commit.id) + - else + = link_to tags.first, project_commits_path(project, tags.first, ref_type: 'tags'), class: 'gl-text-truncate gl-max-w-15' + - if request.xhr? = render partial: 'projects/commit/signature', object: commit.signature - else diff --git a/config/feature_flags/development/show_tags_on_commits_view.yml b/config/feature_flags/development/show_tags_on_commits_view.yml new file mode 100644 index 00000000000..834179d1636 --- /dev/null +++ b/config/feature_flags/development/show_tags_on_commits_view.yml @@ -0,0 +1,8 @@ +--- +name: show_tags_on_commits_view +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111493 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/392003 +milestone: '15.10' +type: development +group: group::source code +default_enabled: false diff --git a/config/initializers_before_autoloader/004_zeitwerk.rb b/config/initializers_before_autoloader/004_zeitwerk.rb index 8b3cdf1a80c..72e471d25f2 100644 --- a/config/initializers_before_autoloader/004_zeitwerk.rb +++ b/config/initializers_before_autoloader/004_zeitwerk.rb @@ -65,7 +65,6 @@ Rails.autoloaders.each do |autoloader| 'function_uri' => 'FunctionURI', 'uuid' => 'UUID', 'occurrence_uuid' => 'OccurrenceUUID', - 'vulnerability_uuid' => 'VulnerabilityUUID', - 'vs_code_extension_activity_unique_counter' => 'VSCodeExtensionActivityUniqueCounter' + 'vulnerability_uuid' => 'VulnerabilityUUID' ) end diff --git a/db/post_migrate/20230220132409_validate_fk_on_ci_build_report_results_partition_id_and_build_id.rb b/db/post_migrate/20230220132409_validate_fk_on_ci_build_report_results_partition_id_and_build_id.rb new file mode 100644 index 00000000000..5186f5f397e --- /dev/null +++ b/db/post_migrate/20230220132409_validate_fk_on_ci_build_report_results_partition_id_and_build_id.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class ValidateFkOnCiBuildReportResultsPartitionIdAndBuildId < Gitlab::Database::Migration[2.1] + TABLE_NAME = :ci_build_report_results + FK_NAME = :fk_rails_16cb1ff064_p + COLUMNS = [:partition_id, :build_id] + + def up + validate_foreign_key(TABLE_NAME, COLUMNS, name: FK_NAME) + end + + def down + # no-op + end +end diff --git a/db/post_migrate/20230220132410_remove_fk_to_ci_builds_ci_build_report_results_on_build_id.rb b/db/post_migrate/20230220132410_remove_fk_to_ci_builds_ci_build_report_results_on_build_id.rb new file mode 100644 index 00000000000..8cbcdf27374 --- /dev/null +++ b/db/post_migrate/20230220132410_remove_fk_to_ci_builds_ci_build_report_results_on_build_id.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +class RemoveFkToCiBuildsCiBuildReportResultsOnBuildId < Gitlab::Database::Migration[2.1] + disable_ddl_transaction! + + SOURCE_TABLE_NAME = :ci_build_report_results + TARGET_TABLE_NAME = :ci_builds + COLUMN = :build_id + TARGET_COLUMN = :id + FK_NAME = :fk_rails_16cb1ff064 + + def up + with_lock_retries do + remove_foreign_key_if_exists( + SOURCE_TABLE_NAME, + TARGET_TABLE_NAME, + name: FK_NAME, + reverse_lock_order: true + ) + end + end + + def down + add_concurrent_foreign_key( + SOURCE_TABLE_NAME, + TARGET_TABLE_NAME, + column: COLUMN, + target_column: TARGET_COLUMN, + validate: true, + reverse_lock_order: true, + on_delete: :cascade, + name: FK_NAME + ) + end +end diff --git a/db/post_migrate/20230220165240_add_index_to_approval_rules_on_scan_result_policy_id.rb b/db/post_migrate/20230220165240_add_index_to_approval_rules_on_scan_result_policy_id.rb new file mode 100644 index 00000000000..b510fdb0f86 --- /dev/null +++ b/db/post_migrate/20230220165240_add_index_to_approval_rules_on_scan_result_policy_id.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class AddIndexToApprovalRulesOnScanResultPolicyId < Gitlab::Database::Migration[2.1] + PROJECT_INDEX_NAME = 'idx_approval_project_rules_on_scan_result_policy_id' + MERGE_REQUEST_INDEX_NAME = 'idx_approval_merge_request_rules_on_scan_result_policy_id' + + disable_ddl_transaction! + + def up + add_concurrent_index :approval_project_rules, :scan_result_policy_id, name: PROJECT_INDEX_NAME + add_concurrent_index :approval_merge_request_rules, :scan_result_policy_id, name: MERGE_REQUEST_INDEX_NAME + end + + def down + remove_concurrent_index_by_name :approval_project_rules, :scan_result_policy_id, name: PROJECT_INDEX_NAME + remove_concurrent_index_by_name :approval_merge_request_rules, :scan_result_policy_id, + name: MERGE_REQUEST_INDEX_NAME + end +end diff --git a/db/post_migrate/20230221162222_raise_ci_variable_limits_on_gitlab_com.rb b/db/post_migrate/20230221162222_raise_ci_variable_limits_on_gitlab_com.rb new file mode 100644 index 00000000000..084f89b2a5d --- /dev/null +++ b/db/post_migrate/20230221162222_raise_ci_variable_limits_on_gitlab_com.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +class RaiseCiVariableLimitsOnGitlabCom < Gitlab::Database::Migration[2.1] + restrict_gitlab_migration gitlab_schema: :gitlab_main + + def up + create_or_update_plan_limit('project_ci_variables', 'free', 8000) + create_or_update_plan_limit('project_ci_variables', 'bronze', 8000) + create_or_update_plan_limit('project_ci_variables', 'silver', 8000) + create_or_update_plan_limit('project_ci_variables', 'premium', 8000) + create_or_update_plan_limit('project_ci_variables', 'premium_trial', 8000) + create_or_update_plan_limit('project_ci_variables', 'gold', 8000) + create_or_update_plan_limit('project_ci_variables', 'ultimate', 8000) + create_or_update_plan_limit('project_ci_variables', 'ultimate_trial', 8000) + create_or_update_plan_limit('project_ci_variables', 'early_adopter', 8000) + create_or_update_plan_limit('project_ci_variables', 'opensource', 8000) + + create_or_update_plan_limit('group_ci_variables', 'free', 30000) + create_or_update_plan_limit('group_ci_variables', 'bronze', 30000) + create_or_update_plan_limit('group_ci_variables', 'silver', 30000) + create_or_update_plan_limit('group_ci_variables', 'premium', 30000) + create_or_update_plan_limit('group_ci_variables', 'premium_trial', 30000) + create_or_update_plan_limit('group_ci_variables', 'gold', 30000) + create_or_update_plan_limit('group_ci_variables', 'ultimate', 30000) + create_or_update_plan_limit('group_ci_variables', 'ultimate_trial', 30000) + create_or_update_plan_limit('group_ci_variables', 'early_adopter', 30000) + create_or_update_plan_limit('group_ci_variables', 'opensource', 30000) + end + + def down + create_or_update_plan_limit('project_ci_variables', 'free', 200) + create_or_update_plan_limit('project_ci_variables', 'bronze', 200) + create_or_update_plan_limit('project_ci_variables', 'silver', 200) + create_or_update_plan_limit('project_ci_variables', 'premium', 200) + create_or_update_plan_limit('project_ci_variables', 'premium_trial', 200) + create_or_update_plan_limit('project_ci_variables', 'gold', 200) + create_or_update_plan_limit('project_ci_variables', 'ultimate', 200) + create_or_update_plan_limit('project_ci_variables', 'ultimate_trial', 200) + create_or_update_plan_limit('project_ci_variables', 'early_adopter', 200) + create_or_update_plan_limit('project_ci_variables', 'opensource', 200) + + create_or_update_plan_limit('group_ci_variables', 'free', 200) + create_or_update_plan_limit('group_ci_variables', 'bronze', 200) + create_or_update_plan_limit('group_ci_variables', 'silver', 200) + create_or_update_plan_limit('group_ci_variables', 'premium', 200) + create_or_update_plan_limit('group_ci_variables', 'premium_trial', 200) + create_or_update_plan_limit('group_ci_variables', 'gold', 200) + create_or_update_plan_limit('group_ci_variables', 'ultimate', 200) + create_or_update_plan_limit('group_ci_variables', 'ultimate_trial', 200) + create_or_update_plan_limit('group_ci_variables', 'early_adopter', 200) + create_or_update_plan_limit('group_ci_variables', 'opensource', 200) + end +end diff --git a/db/schema_migrations/20230220132409 b/db/schema_migrations/20230220132409 new file mode 100644 index 00000000000..417675aaf27 --- /dev/null +++ b/db/schema_migrations/20230220132409 @@ -0,0 +1 @@ +b2aee06140d97dd9cd5d694b5d8538db92279aeba9e0e64375052ff455246647
\ No newline at end of file diff --git a/db/schema_migrations/20230220132410 b/db/schema_migrations/20230220132410 new file mode 100644 index 00000000000..39ee3040802 --- /dev/null +++ b/db/schema_migrations/20230220132410 @@ -0,0 +1 @@ +42814e8ab1b2ebb197f877736f8c9dddf5b9416c22f9c800c7a9d33cde164dd6
\ No newline at end of file diff --git a/db/schema_migrations/20230220165240 b/db/schema_migrations/20230220165240 new file mode 100644 index 00000000000..14cd3554464 --- /dev/null +++ b/db/schema_migrations/20230220165240 @@ -0,0 +1 @@ +754b55e9465719edb5058c97cacf1f369347e15c7e6d7fa30dcbe5abd8addcae
\ No newline at end of file diff --git a/db/schema_migrations/20230221162222 b/db/schema_migrations/20230221162222 new file mode 100644 index 00000000000..be6d9c407b1 --- /dev/null +++ b/db/schema_migrations/20230221162222 @@ -0,0 +1 @@ +f0fd872c7999879be5d433881e20855cc8e2418625374fc095cc74172b9f08c5
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 364f697dceb..34b480a90ed 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -28848,8 +28848,12 @@ CREATE INDEX idx_analytics_devops_adoption_segments_on_namespace_id ON analytics CREATE INDEX idx_analytics_devops_adoption_snapshots_finalized ON analytics_devops_adoption_snapshots USING btree (namespace_id, end_time) WHERE (recorded_at >= end_time); +CREATE INDEX idx_approval_merge_request_rules_on_scan_result_policy_id ON approval_merge_request_rules USING btree (scan_result_policy_id); + CREATE INDEX idx_approval_merge_request_rules_on_sec_orchestration_config_id ON approval_merge_request_rules USING btree (security_orchestration_policy_configuration_id); +CREATE INDEX idx_approval_project_rules_on_scan_result_policy_id ON approval_project_rules USING btree (scan_result_policy_id); + CREATE INDEX idx_approval_project_rules_on_sec_orchestration_config_id ON approval_project_rules USING btree (security_orchestration_policy_configuration_id); CREATE INDEX idx_audit_events_part_on_entity_id_desc_author_id_created_at ON ONLY audit_events USING btree (entity_id, entity_type, id DESC, author_id, created_at); @@ -35021,10 +35025,7 @@ ALTER TABLE ONLY users_security_dashboard_projects ADD CONSTRAINT fk_rails_150cd5682c FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; ALTER TABLE ONLY ci_build_report_results - ADD CONSTRAINT fk_rails_16cb1ff064 FOREIGN KEY (build_id) REFERENCES ci_builds(id) ON DELETE CASCADE; - -ALTER TABLE ONLY ci_build_report_results - ADD CONSTRAINT fk_rails_16cb1ff064_p FOREIGN KEY (partition_id, build_id) REFERENCES ci_builds(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE NOT VALID; + ADD CONSTRAINT fk_rails_16cb1ff064_p FOREIGN KEY (partition_id, build_id) REFERENCES ci_builds(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE; ALTER TABLE ONLY project_deploy_tokens ADD CONSTRAINT fk_rails_170e03cbaf FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; diff --git a/doc/administration/geo/setup/database.md b/doc/administration/geo/setup/database.md index 99f7b32be59..6ce44b135f5 100644 --- a/doc/administration/geo/setup/database.md +++ b/doc/administration/geo/setup/database.md @@ -151,6 +151,15 @@ There is an [issue where support is being discussed](https://gitlab.com/gitlab-o ALTER USER gitlab_replicator WITH REPLICATION ENCRYPTED PASSWORD '<replication_password>'; ``` +1. Edit `/etc/gitlab/gitlab.rb`: + + ```ruby + ## Set this node to have the primary role + roles(['geo_primary_role']) + + ## Disable automatic database migrations temporarily + gitlab_rails['auto_migrate'] = false + 1. Configure PostgreSQL to listen on network interfaces: For security reasons, PostgreSQL does not listen on any network interfaces diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index b46c111ff43..3205fe8f7b4 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -20353,6 +20353,7 @@ SSH signature for a signed commit. | ---- | ---- | ----------- | | <a id="sshsignaturecommitsha"></a>`commitSha` | [`String`](#string) | SHA of the associated commit. | | <a id="sshsignaturekey"></a>`key` | [`Key`](#key) | SSH key used for the signature. | +| <a id="sshsignaturekeyfingerprintsha256"></a>`keyFingerprintSha256` | [`String`](#string) | Fingerprint of the key. | | <a id="sshsignatureproject"></a>`project` | [`Project`](#project) | Project of the associated commit. | | <a id="sshsignatureuser"></a>`user` | [`UserCore`](#usercore) | User associated with the key. | | <a id="sshsignatureverificationstatus"></a>`verificationStatus` | [`VerificationStatus`](#verificationstatus) | Indicates verification status of the associated key or certificate. | diff --git a/doc/integration/partner_marketplace.md b/doc/integration/partner_marketplace.md index a1e55561a7a..987ae7e21b3 100644 --- a/doc/integration/partner_marketplace.md +++ b/doc/integration/partner_marketplace.md @@ -61,4 +61,4 @@ Interested GitLab Partners should contact their GitLab Partner Manager or email ## Marketplace API Specification -OpenAPI specs for the Marketplace APIs are available upon request. The specs will be made public before the end of Q1 2023. +OpenAPI specs for the Marketplace APIs are available at [Marketplace interactive API documentation](https://customers.staging.gitlab.com/openapi_docs/marketplace). diff --git a/doc/operations/index.md b/doc/operations/index.md index ff13c617ea7..24a0181245b 100644 --- a/doc/operations/index.md +++ b/doc/operations/index.md @@ -35,7 +35,7 @@ performance degrades, and manage those alerts - all within GitLab. GitLab helps reduce alert fatigue for IT responders by providing tools to identify issues across multiple systems and aggregate alerts in a centralized place. Your -team needs a single, central interface where they can easily investigate alerts +team needs a single, central interface where they can investigate alerts and promote the critical alerts to incidents. Are your alerts too noisy? Alerts configured on GitLab metrics can configured diff --git a/doc/update/zero_downtime.md b/doc/update/zero_downtime.md index bb5cd195e5d..a85ae79a61c 100644 --- a/doc/update/zero_downtime.md +++ b/doc/update/zero_downtime.md @@ -465,6 +465,8 @@ Log in to your **primary** node, executing the following: sudo SKIP_POST_DEPLOYMENT_MIGRATIONS=true gitlab-rake db:migrate ``` +1. Copy the `/etc/gitlab/gitlab-secrets.json` file from the primary site to the secondary site if they're different. The file must be the same on all of a site’s nodes. + ### Update the Geo secondary site On each **secondary** node, executing the following: @@ -665,6 +667,8 @@ sudo gitlab-ctl hup puma sudo gitlab-ctl restart sidekiq ``` +1. Copy the `/etc/gitlab/gitlab-secrets.json` file from the primary site to the secondary site if they're different. The file must be the same on all of a site’s nodes. + ### Step 3: Update each Geo secondary multi-node deployment Only proceed if you have successfully completed all steps on the Geo **primary** multi-node deployment. diff --git a/doc/user/analytics/value_streams_dashboard.md b/doc/user/analytics/value_streams_dashboard.md index f8cfb1bf06b..49c249117d8 100644 --- a/doc/user/analytics/value_streams_dashboard.md +++ b/doc/user/analytics/value_streams_dashboard.md @@ -12,7 +12,8 @@ You can leave feedback on dashboard bugs or functionality in [issue 381787](http This feature is not ready for production use. -The Value Streams Dashboard is a customizable dashboard to enable decision-makers to identify trends, patterns, and opportunities for digital transformation improvements. +The Value Streams Dashboard is a customizable dashboard that enables decision-makers to identify trends, patterns, and opportunities for digital transformation improvements. +The dashboard's basic functionality is available on the Premium tier, but most of the dashboard features (for example DORA metrics) are available only on the Ultimate tier. This page is a work in progress, and we're updating the information as we add more features. For more information, see the [Value Stream Management category direction page](https://about.gitlab.com/direction/plan/value_stream_management/). @@ -27,7 +28,7 @@ This comparison can help decision-makers understand whether projects and groups The beta version of the Value Streams Dashboard includes the following metrics: - [DORA metrics](dora_metrics.md) -- [Value Stream Analytics (VSA) - flow metrics](value_stream_analytics.md) +- [Value Stream Analytics (VSA) - flow metrics](../group/value_stream_analytics/index.md) The Value Streams Dashboard allows you to: diff --git a/doc/user/search/advanced_search.md b/doc/user/search/advanced_search.md index ed1d3b1d290..ae9722bca9b 100644 --- a/doc/user/search/advanced_search.md +++ b/doc/user/search/advanced_search.md @@ -29,22 +29,6 @@ You can use Advanced Search in: - Commits - Project wikis (not [group wikis](../project/wiki/group.md)) -For Advanced Search: - -- You can only search files smaller than 1 MB. - For self-managed GitLab instances, an administrator can - [change this limit](../../integration/advanced_search/elasticsearch.md#advanced-search-configuration). -- You can't use any of the following characters in the search query: - - ```plaintext - . , : ; / ` ' = ? $ & ^ | ~ < > ( ) { } [ ] @ - ``` - -- Only the default branch of a project is indexed for code search. - In a non-default branch, basic search is used. -- Search results show only the first match in a file, - but there might be more results in that file. - ## Enable Advanced Search - On GitLab.com, Advanced Search is enabled for groups with paid subscriptions. @@ -89,3 +73,17 @@ Advanced Search uses [Elasticsearch syntax](https://www.elastic.co/guide/en/elas | [<code>helper -extension:yml -extension:js</code>](https://gitlab.com/search?group_id=9970&project_id=278964&repository_ref=&scope=blobs&search=helper+-extension%3Ayml+-extension%3Ajs&snippets=) | Returns `helper` in all files except files with a `.yml` or `.js` extension. | <!-- markdownlint-enable --> + +## Known issues + +- You can only search files smaller than 1 MB. + For self-managed GitLab instances, an administrator can + [change this limit](../../integration/advanced_search/elasticsearch.md#advanced-search-configuration). +- You can only use Advanced Search on the default branch of a project. +- The search query must not contain any of the following characters: + + ```plaintext + . , : ; / ` ' = ? $ & ^ | ~ < > ( ) { } [ ] @ + ``` + +- Search results show only the first match in a file. diff --git a/lib/gitlab/git.rb b/lib/gitlab/git.rb index 8e1b51fcec5..eb204a7dd8e 100644 --- a/lib/gitlab/git.rb +++ b/lib/gitlab/git.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require_dependency 'gitlab/encoding_helper' +require_relative 'encoding_helper' module Gitlab module Git diff --git a/lib/gitlab/git/commit.rb b/lib/gitlab/git/commit.rb index 267107e04e6..3a65c7c334d 100644 --- a/lib/gitlab/git/commit.rb +++ b/lib/gitlab/git/commit.rb @@ -16,7 +16,7 @@ module Gitlab SERIALIZE_KEYS = [ :id, :message, :parent_ids, :authored_date, :author_name, :author_email, - :committed_date, :committer_name, :committer_email, :trailers + :committed_date, :committer_name, :committer_email, :trailers, :referenced_by ].freeze attr_accessor(*SERIALIZE_KEYS) @@ -414,6 +414,7 @@ module Gitlab @committer_email = commit.committer.email.dup @parent_ids = Array(commit.parent_ids) @trailers = commit.trailers.to_h { |t| [t.key, t.value] } + @referenced_by = Array(commit.referenced_by) end # Gitaly provides a UNIX timestamp in author.date.seconds, and a timezone diff --git a/lib/gitlab/gitaly_client/commit_service.rb b/lib/gitlab/gitaly_client/commit_service.rb index 4df9d800ea6..cf346834486 100644 --- a/lib/gitlab/gitaly_client/commit_service.rb +++ b/lib/gitlab/gitaly_client/commit_service.rb @@ -423,7 +423,8 @@ module Gitlab first_parent: !!options[:first_parent], global_options: parse_global_options!(options), disable_walk: true, # This option is deprecated. The 'walk' implementation is being removed. - trailers: options[:trailers] + trailers: options[:trailers], + include_referenced_by: options[:include_referenced_by] ) request.after = GitalyClient.timestamp(options[:after]) if options[:after] request.before = GitalyClient.timestamp(options[:before]) if options[:before] diff --git a/lib/gitlab/seeders/ci/runner/runner_fleet_seeder.rb b/lib/gitlab/seeders/ci/runner/runner_fleet_seeder.rb index 71f055ce7e9..9340f67f73e 100644 --- a/lib/gitlab/seeders/ci/runner/runner_fleet_seeder.rb +++ b/lib/gitlab/seeders/ci/runner/runner_fleet_seeder.rb @@ -68,16 +68,16 @@ module Gitlab if plan_limits.ci_registered_group_runners < @runner_count warn 'The plan limits for group runners is set to ' \ "#{plan_limits.ci_registered_group_runners} runners. " \ - 'You should raise the plan limits to avoid errors during runner creation by running ' \ - 'the following command in the Rails console:' - warn "Plan.default.actual_limits.update!(ci_registered_group_runners: #{@runner_count})" + "You should raise the plan limits to avoid errors during runner creation by running " \ + "the following command in the Rails console:\n" \ + "Plan.default.actual_limits.update!(ci_registered_group_runners: #{@runner_count})" return false elsif plan_limits.ci_registered_project_runners < @runner_count warn 'The plan limits for project runners is set to ' \ "#{plan_limits.ci_registered_project_runners} runners. " \ - 'You should raise the plan limits to avoid errors during runner creation by running ' \ - 'the following command in the Rails console:' - warn "Plan.default.actual_limits.update!(ci_registered_project_runners: #{@runner_count})" + "You should raise the plan limits to avoid errors during runner creation by running " \ + "the following command in the Rails console:\n" \ + "Plan.default.actual_limits.update!(ci_registered_project_runners: #{@runner_count})" return false end diff --git a/lib/gitlab/task_helpers.rb b/lib/gitlab/task_helpers.rb index 9dba8c99b99..b9800a4db73 100644 --- a/lib/gitlab/task_helpers.rb +++ b/lib/gitlab/task_helpers.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'rainbow/ext/string' -require_dependency 'gitlab/utils/strong_memoize' +require_relative 'utils/strong_memoize' # rubocop:disable Rails/Output module Gitlab diff --git a/lib/gitlab/utils/override.rb b/lib/gitlab/utils/override.rb index 7f43e25e50d..1d02bcbb2d2 100644 --- a/lib/gitlab/utils/override.rb +++ b/lib/gitlab/utils/override.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true -require_dependency 'gitlab/utils' -require_dependency 'gitlab/environment' +require_relative '../utils' +require_relative '../environment' module Gitlab module Utils diff --git a/locale/gitlab.pot b/locale/gitlab.pot index c215985ce9e..53fd5ef720f 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -635,6 +635,9 @@ msgstr "" msgid "%{count} selected" msgstr "" +msgid "%{count} tags" +msgstr "" + msgid "%{count} total weight" msgstr "" diff --git a/scripts/setup-test-env b/scripts/setup-test-env index 97762e1cafa..ae00b569ce3 100755 --- a/scripts/setup-test-env +++ b/scripts/setup-test-env @@ -4,66 +4,49 @@ require_relative '../config/bundler_setup' +require_relative '../spec/rails_autoload' + require 'request_store' require 'rake' -require 'active_support/dependencies' -require 'active_support/dependencies/autoload' -require 'active_support/core_ext/numeric' -require 'active_support/string_inquirer' +require 'active_support/all' ENV['SKIP_RAILS_ENV_IN_RAKE'] = 'true' -module Rails - extend self - - def root - Pathname.new(File.expand_path('..', __dir__)) - end - - def env - @_env ||= ActiveSupport::StringInquirer.new(ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "test") - end -end - -ActiveSupport::Dependencies.autoload_paths << 'lib' - load File.expand_path('../lib/tasks/gitlab/helpers.rake', __dir__) load File.expand_path('../lib/tasks/gitlab/gitaly.rake', __dir__) -# Required for config/0_inject_enterprise_edition_module.rb, lib/gitlab/access.rb -require_dependency File.expand_path('../lib/gitlab', __dir__) - -require_dependency File.expand_path('../config/initializers/0_inject_enterprise_edition_module', __dir__) - -# Require for lib/gitlab/gitaly_client/storage_settings.rb and config/initializers/1_settings.rb -require 'active_support/hash_with_indifferent_access' - -# Required for lib/gitlab/visibility_level.rb and lib/gitlab/safe_request_store.rb -require 'active_support/concern' -require 'active_support/core_ext/module/delegation' - # Required for lib/system_check/helpers.rb -require_dependency File.expand_path('../lib/gitlab/task_helpers', __dir__) +require_relative '../lib/gitlab/task_helpers' # Required for lib/tasks/gitlab/helpers.rake -require_dependency File.expand_path('../lib/system_check/helpers', __dir__) +require_relative '../lib/system_check/helpers' # Required for config/initializers/1_settings.rb require 'omniauth' require 'omniauth-github' require 'etc' -require_dependency File.expand_path('../lib/gitlab/access', __dir__) -require_dependency File.expand_path('../lib/gitlab/utils', __dir__) +require_relative '../lib/gitlab/access' +require_relative '../lib/gitlab/utils' + +unless defined?(License) + # This is needed to allow use of `Gitlab::ImportSources.values` in `1_settings.rb`. + # See ee/lib/ee/gitlab/import_sources.rb + class License + def self.database + Struct.new(:cached_table_exists?).new(false) + end + end +end -require_dependency File.expand_path('../config/initializers/1_settings', __dir__) +require_relative '../config/initializers/1_settings' Gitlab.ee do load File.expand_path('../ee/lib/tasks/gitlab/indexer.rake', __dir__) - require_dependency File.expand_path('../ee/lib/gitlab/elastic/indexer', __dir__) - require_dependency File.expand_path('../lib/gitlab/utils/override', __dir__) + require_relative '../ee/lib/gitlab/elastic/indexer' + require_relative '../lib/gitlab/utils/override' end -require_dependency File.expand_path('../spec/support/helpers/test_env', __dir__) +require_relative '../spec/support/helpers/test_env' TestEnv.init diff --git a/spec/controllers/projects/commits_controller_spec.rb b/spec/controllers/projects/commits_controller_spec.rb index 233f1044ed9..e686419a966 100644 --- a/spec/controllers/projects/commits_controller_spec.rb +++ b/spec/controllers/projects/commits_controller_spec.rb @@ -66,7 +66,8 @@ RSpec.describe Projects::CommitsController, feature_category: :source_code_manag "master", path: "README.md", limit: described_class::COMMITS_DEFAULT_LIMIT, - offset: 0 + offset: 0, + include_referenced_by: ["refs/tags/"] ).and_call_original get :show, params: { namespace_id: project.namespace, project_id: project, id: id, limit: "foo" } @@ -80,7 +81,8 @@ RSpec.describe Projects::CommitsController, feature_category: :source_code_manag "master", path: "README.md", limit: described_class::COMMITS_DEFAULT_LIMIT, - offset: 0 + offset: 0, + include_referenced_by: ['refs/tags/'] ).and_call_original get :show, params: { @@ -95,6 +97,22 @@ RSpec.describe Projects::CommitsController, feature_category: :source_code_manag end end + context 'when the show_tags_on_commits_view flag is disabled' do + let(:id) { "master/README.md" } + + before do + stub_feature_flags(show_tags_on_commits_view: false) + end + + it 'does not use the include_referenced_by option' do + allow_any_instance_of(Repository).to receive(:commits).and_call_original + expect_any_instance_of(Repository).not_to receive(:commits).with( + a_hash_including(include_referenced_by: any_args)).and_call_original + + get :show, params: { namespace_id: project.namespace, project_id: project, id: id } + end + end + context "when the ref name ends in .atom" do context "when the ref does not exist with the suffix" do before do diff --git a/spec/db/schema_spec.rb b/spec/db/schema_spec.rb index ab858f3b999..45b2d259bfd 100644 --- a/spec/db/schema_spec.rb +++ b/spec/db/schema_spec.rb @@ -10,10 +10,7 @@ RSpec.describe 'Database schema', feature_category: :database do let(:columns_name_with_jsonb) { retrieve_columns_name_with_jsonb } IGNORED_INDEXES_ON_FKS = { - slack_integrations_scopes: %w[slack_api_scope_id], - # Will be removed in https://gitlab.com/gitlab-org/gitlab/-/issues/391312 - approval_project_rules: %w[scan_result_policy_id], - approval_merge_request_rules: %w[scan_result_policy_id] + slack_integrations_scopes: %w[slack_api_scope_id] }.with_indifferent_access.freeze TABLE_PARTITIONS = %w[ci_builds_metadata].freeze @@ -37,7 +34,7 @@ RSpec.describe 'Database schema', feature_category: :database do chat_teams: %w[team_id], ci_build_needs: %w[partition_id build_id], ci_build_pending_states: %w[partition_id build_id], - ci_build_report_results: %w[partition_id], + ci_build_report_results: %w[partition_id build_id], ci_build_trace_chunks: %w[partition_id build_id], ci_build_trace_metadata: %w[partition_id], ci_builds: %w[erased_by_id trigger_request_id partition_id], diff --git a/spec/fast_spec_helper.rb b/spec/fast_spec_helper.rb index e53f0cd936f..e8d58656178 100644 --- a/spec/fast_spec_helper.rb +++ b/spec/fast_spec_helper.rb @@ -14,8 +14,8 @@ ENV['IN_MEMORY_APPLICATION_SETTINGS'] = 'true' # Enable zero monkey patching mode before loading any other RSpec code. RSpec.configure(&:disable_monkey_patching!) -require 'active_support/dependencies' -require_relative '../config/initializers/0_inject_enterprise_edition_module' +require_relative 'rails_autoload' + require_relative '../config/settings' require_relative 'support/rspec' require_relative '../lib/gitlab/utils' @@ -25,12 +25,6 @@ require 'active_support/all' require_relative 'simplecov_env' SimpleCovEnv.start! -unless ActiveSupport::Dependencies.autoload_paths.frozen? - ActiveSupport::Dependencies.autoload_paths << 'lib' - ActiveSupport::Dependencies.autoload_paths << 'ee/lib' - ActiveSupport::Dependencies.autoload_paths << 'jh/lib' -end - ActiveSupport::XmlMini.backend = 'Nokogiri' RSpec.configure do |config| diff --git a/spec/features/projects/blobs/blob_show_spec.rb b/spec/features/projects/blobs/blob_show_spec.rb index 7faf0e1a6b1..f9e3ff1670c 100644 --- a/spec/features/projects/blobs/blob_show_spec.rb +++ b/spec/features/projects/blobs/blob_show_spec.rb @@ -137,11 +137,13 @@ RSpec.describe 'File blob', :js, feature_category: :projects do context 'when ref switch' do def switch_ref_to(ref_name) - first('[data-testid="branches-select"]').click + find('.ref-selector').click + wait_for_requests - page.within '.project-refs-form' do - click_link ref_name + page.within('.ref-selector') do + fill_in 'Search by Git revision', with: ref_name wait_for_requests + find('li', text: ref_name, match: :prefer_exact).click end end diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb index 67389fdda8a..a57476f8b88 100644 --- a/spec/features/projects/jobs_spec.rb +++ b/spec/features/projects/jobs_spec.rb @@ -1065,16 +1065,19 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state, feature_category: :proj end context "Build from other project" do + let(:other_job_download_path) { download_project_job_artifacts_path(project, job2) } + before do create(:ci_job_artifact, :archive, file: artifacts_file, job: job2) end it do - requests = inspect_requests do - visit download_project_job_artifacts_path(project, job2) - end + requests = inspect_requests { visit other_job_download_path } + + request = requests.find { |request| request.url == other_job_download_path } - expect(requests.first.status_code).to eq(404) + expect(request).to be_present + expect(request.status_code).to eq(404) end end end diff --git a/spec/frontend/fixtures/api_deploy_keys.rb b/spec/frontend/fixtures/api_deploy_keys.rb index 5ffc726f086..8c926296817 100644 --- a/spec/frontend/fixtures/api_deploy_keys.rb +++ b/spec/frontend/fixtures/api_deploy_keys.rb @@ -7,6 +7,7 @@ RSpec.describe API::DeployKeys, '(JavaScript fixtures)', type: :request do include JavaScriptFixturesHelpers let_it_be(:admin) { create(:admin) } + let_it_be(:path) { "/deploy_keys" } let_it_be(:project) { create(:project) } let_it_be(:project2) { create(:project) } let_it_be(:deploy_key) { create(:deploy_key, public: true) } @@ -17,8 +18,10 @@ RSpec.describe API::DeployKeys, '(JavaScript fixtures)', type: :request do let_it_be(:deploy_keys_project3) { create(:deploy_keys_project, :write_access, project: project, deploy_key: deploy_key2) } let_it_be(:deploy_keys_project4) { create(:deploy_keys_project, :write_access, project: project2, deploy_key: deploy_key2) } + it_behaves_like 'GET request permissions for admin mode' + it 'api/deploy_keys/index.json' do - get api("/deploy_keys", admin) + get api("/deploy_keys", admin, admin_mode: true) expect(response).to be_successful end diff --git a/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js b/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js index 86a63db0d9e..25bfa688e5b 100644 --- a/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js +++ b/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js @@ -108,16 +108,23 @@ describe('AlertManagementEmptyState', () => { const findStatusTabs = () => wrapper.findComponent(GlTabs); const findStatusFilterBadge = () => wrapper.findAllComponents(GlBadge); + const handleFilterItems = (filters) => { + Filters().vm.$emit('onFilter', filters); + return nextTick(); + }; + describe('Snowplow tracking', () => { + const category = 'category'; + const action = 'action'; + beforeEach(() => { jest.spyOn(Tracking, 'event'); mountComponent({ - props: { trackViewsOptions: { category: 'category', action: 'action' } }, + props: { trackViewsOptions: { category, action } }, }); }); it('should track the items list page views', () => { - const { category, action } = wrapper.vm.trackViewsOptions; expect(Tracking.event).toHaveBeenCalledWith(category, action); }); }); @@ -234,14 +241,14 @@ describe('AlertManagementEmptyState', () => { findPagination().vm.$emit('input', 3); await nextTick(); - expect(wrapper.vm.previousPage).toBe(2); + expect(findPagination().props('prevPage')).toBe(2); }); it('returns 0 when it is the first page', async () => { findPagination().vm.$emit('input', 1); await nextTick(); - expect(wrapper.vm.previousPage).toBe(0); + expect(findPagination().props('prevPage')).toBe(0); }); }); @@ -265,14 +272,14 @@ describe('AlertManagementEmptyState', () => { findPagination().vm.$emit('input', 1); await nextTick(); - expect(wrapper.vm.nextPage).toBe(2); + expect(findPagination().props('nextPage')).toBe(2); }); it('returns `null` when currentPage is already last page', async () => { findStatusTabs().vm.$emit('input', 1); findPagination().vm.$emit('input', 1); await nextTick(); - expect(wrapper.vm.nextPage).toBeNull(); + expect(findPagination().props('nextPage')).toBeNull(); }); }); }); @@ -320,36 +327,32 @@ describe('AlertManagementEmptyState', () => { it('returns correctly applied filter search values', async () => { const searchTerm = 'foo'; - // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details - // eslint-disable-next-line no-restricted-syntax - wrapper.setData({ - searchTerm, - }); - + await handleFilterItems([{ type: 'filtered-search-term', value: { data: searchTerm } }]); await nextTick(); - expect(wrapper.vm.filteredSearchValue).toEqual([searchTerm]); + expect(Filters().props('initialFilterValue')).toEqual([searchTerm]); }); - it('updates props tied to getIncidents GraphQL query', () => { - wrapper.vm.handleFilterItems(mockFilters); - - expect(wrapper.vm.authorUsername).toBe('root'); - expect(wrapper.vm.assigneeUsername).toEqual('root2'); - expect(wrapper.vm.searchTerm).toBe(mockFilters[2].value.data); - }); + it('updates props tied to getIncidents GraphQL query', async () => { + await handleFilterItems(mockFilters); - it('updates props `searchTerm` and `authorUsername` with empty values when passed filters param is empty', () => { - // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details - // eslint-disable-next-line no-restricted-syntax - wrapper.setData({ - authorUsername: 'foo', - searchTerm: 'bar', - }); + const [ + { + value: { data: authorUsername }, + }, + { + value: { data: assigneeUsername }, + }, + searchTerm, + ] = Filters().props('initialFilterValue'); - wrapper.vm.handleFilterItems([]); + expect(authorUsername).toBe('root'); + expect(assigneeUsername).toEqual('root2'); + expect(searchTerm).toBe(mockFilters[2].value.data); + }); - expect(wrapper.vm.authorUsername).toBe(''); - expect(wrapper.vm.searchTerm).toBe(''); + it('updates props `searchTerm` and `authorUsername` with empty values when passed filters param is empty', async () => { + await handleFilterItems([]); + expect(Filters().props('initialFilterValue')).toEqual([]); }); }); }); diff --git a/spec/graphql/types/commit_signature_interface_spec.rb b/spec/graphql/types/commit_signature_interface_spec.rb index 4962131d9b5..d37c0d1b4fa 100644 --- a/spec/graphql/types/commit_signature_interface_spec.rb +++ b/spec/graphql/types/commit_signature_interface_spec.rb @@ -18,6 +18,11 @@ RSpec.describe GitlabSchema.types['CommitSignature'] do Types::CommitSignatures::X509SignatureType) end + it 'resolves SSH signatures' do + expect(described_class.resolve_type(build(:ssh_signature), {})).to eq( + Types::CommitSignatures::SshSignatureType) + end + it 'raises an error when type is not known' do expect { described_class.resolve_type(Class, {}) }.to raise_error('Unsupported commit signature type') end diff --git a/spec/graphql/types/commit_signatures/ssh_signature_type_spec.rb b/spec/graphql/types/commit_signatures/ssh_signature_type_spec.rb index 4ffb70a0b22..c16e29312a3 100644 --- a/spec/graphql/types/commit_signatures/ssh_signature_type_spec.rb +++ b/spec/graphql/types/commit_signatures/ssh_signature_type_spec.rb @@ -11,7 +11,7 @@ RSpec.describe GitlabSchema.types['SshSignature'], feature_category: :source_cod it 'contains attributes related to SSH signatures' do expect(described_class).to have_graphql_fields( - :user, :verification_status, :commit_sha, :project, :key + :user, :verification_status, :commit_sha, :project, :key, :key_fingerprint_sha256 ) end end diff --git a/spec/helpers/commits_helper_spec.rb b/spec/helpers/commits_helper_spec.rb index 27738f73ea5..c947d11e9de 100644 --- a/spec/helpers/commits_helper_spec.rb +++ b/spec/helpers/commits_helper_spec.rb @@ -325,21 +325,41 @@ RSpec.describe CommitsHelper do assign(:path, current_path) end - it { is_expected.to be_an(Array) } - it { is_expected.to include(commit) } - it { is_expected.to include(commit.author) } - it { is_expected.to include(ref) } - specify do - is_expected.to include( + expect(subject).to eq([ + commit, + commit.author, + ref, { merge_request: merge_request.cache_key, pipeline_status: pipeline.cache_key, xhr: true, controller: "commits", - path: current_path + path: current_path, + referenced_by: helper.tag_checksum(commit.referenced_by) } - ) + ]) + end + + context 'when the show_tags_on_commits_view flag is disabled' do + before do + stub_feature_flags(show_tags_on_commits_view: false) + end + + specify do + expect(subject).to eq([ + commit, + commit.author, + ref, + { + merge_request: merge_request.cache_key, + pipeline_status: pipeline.cache_key, + xhr: true, + controller: "commits", + path: current_path + } + ]) + end end describe "final cache key output" do diff --git a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event_spec.rb index 1e0034e386e..24248c557bd 100644 --- a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event_spec.rb +++ b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event_spec.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -require 'fast_spec_helper' +require 'spec_helper' -RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::StageEvent do +RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::StageEvent, feature_category: :product_analytics do let(:instance) { described_class.new({}) } it { expect(described_class).to respond_to(:name) } diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb index d873151421d..26af9d5d5b8 100644 --- a/spec/lib/gitlab/git/commit_spec.rb +++ b/spec/lib/gitlab/git/commit_spec.rb @@ -660,7 +660,8 @@ RSpec.describe Gitlab::Git::Commit do id: SeedRepo::Commit::ID, message: "tree css fixes", parent_ids: ["874797c3a73b60d2187ed6e2fcabd289ff75171e"], - trailers: {} + trailers: {}, + referenced_by: [] } end end diff --git a/spec/lib/gitlab/seeders/ci/runner/runner_fleet_seeder_spec.rb b/spec/lib/gitlab/seeders/ci/runner/runner_fleet_seeder_spec.rb index fc16e889636..4597cc6b315 100644 --- a/spec/lib/gitlab/seeders/ci/runner/runner_fleet_seeder_spec.rb +++ b/spec/lib/gitlab/seeders/ci/runner/runner_fleet_seeder_spec.rb @@ -75,7 +75,7 @@ RSpec.describe ::Gitlab::Seeders::Ci::Runner::RunnerFleetSeeder, feature_categor it { is_expected.to be_nil } - it 'creates expected hierarchy', :aggregate_failures do + it 'does not change runner count' do expect { seed }.not_to change { Ci::Runner.count } end end @@ -87,7 +87,7 @@ RSpec.describe ::Gitlab::Seeders::Ci::Runner::RunnerFleetSeeder, feature_categor it { is_expected.to be_nil } - it 'creates expected hierarchy', :aggregate_failures do + it 'does not change runner count' do expect { seed }.not_to change { Ci::Runner.count } end end diff --git a/spec/models/commit_collection_spec.rb b/spec/models/commit_collection_spec.rb index 6dd34c3e21f..706f18a5337 100644 --- a/spec/models/commit_collection_spec.rb +++ b/spec/models/commit_collection_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe CommitCollection do +RSpec.describe CommitCollection, feature_category: :source_code_management do let(:project) { create(:project, :repository) } let(:commit) { project.commit("c1c67abbaf91f624347bb3ae96eabe3a1b742478") } @@ -191,6 +191,19 @@ RSpec.describe CommitCollection do end end + describe '#load_tags' do + let(:gitaly_commit_with_tags) { project.commit('5937ac0a7beb003549fc5fd26fc247adbce4a52e') } + let(:collection) { described_class.new(project, [gitaly_commit_with_tags]) } + + subject { collection.load_tags } + + it 'loads tags' do + subject + + expect(collection.commits[0].referenced_by).to contain_exactly('refs/tags/v1.1.0') + end + end + describe '#respond_to_missing?' do it 'returns true when the underlying Array responds to the message' do collection = described_class.new(project, []) diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index b8780b3faae..60610fc8b55 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -413,6 +413,27 @@ RSpec.describe Repository, feature_category: :source_code_management do repository.commits('master', limit: 1) end end + + context 'when include_referenced_by is passed' do + context 'when commit has references' do + let(:ref) { '5937ac0a7beb003549fc5fd26fc247adbce4a52e' } + let(:include_referenced_by) { ['refs/tags'] } + + subject { repository.commits(ref, limit: 1, include_referenced_by: include_referenced_by).first } + + it 'returns commits with referenced_by excluding that match the patterns' do + expect(subject.referenced_by).to match_array(['refs/tags/v1.1.0']) + end + + context 'when matching multiple references' do + let(:include_referenced_by) { ['refs/tags', 'refs/heads'] } + + it 'returns commits with referenced_by that match the patterns' do + expect(subject.referenced_by).to match_array(['refs/tags/v1.1.0', 'refs/heads/improve/awesome', 'refs/heads/merge-test']) + end + end + end + end end context "when 'author' is set" do diff --git a/spec/presenters/commit_presenter_spec.rb b/spec/presenters/commit_presenter_spec.rb index eba393da2b7..5ac270a8df8 100644 --- a/spec/presenters/commit_presenter_spec.rb +++ b/spec/presenters/commit_presenter_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe CommitPresenter do +RSpec.describe CommitPresenter, feature_category: :source_code_management do let(:commit) { project.commit } let(:presenter) { described_class.new(commit, current_user: user) } @@ -95,4 +95,15 @@ RSpec.describe CommitPresenter do expect(presenter.signature_html).to eq(signature) end end + + describe '#tags_for_display' do + subject { presenter.tags_for_display } + + let(:stubbed_tags) { %w[refs/tags/v1.0 refs/tags/v1.1] } + + it 'removes the refs prefix from tags' do + allow(commit).to receive(:referenced_by).and_return(stubbed_tags) + expect(subject).to eq(%w[v1.0 v1.1]) + end + end end diff --git a/spec/rails_autoload.rb b/spec/rails_autoload.rb new file mode 100644 index 00000000000..d3518acf8b2 --- /dev/null +++ b/spec/rails_autoload.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +# Mimics Rails autoloading with zeitwerk when used outside of Rails. +# This is used in: +# * fast_spec_helper +# * scripts/setup-test-env + +require 'zeitwerk' +require 'active_support/string_inquirer' + +module Rails + extend self + + def root + Pathname.new(File.expand_path('..', __dir__)) + end + + def env + @_env ||= ActiveSupport::StringInquirer.new(ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "test") + end + + def autoloaders + @autoloaders ||= [ + Zeitwerk::Loader.new.tap do |loader| + loader.inflector = _autoloader_inflector + end + ] + end + + private + + def _autoloader_inflector + # Try Rails 7 first. + require 'rails/autoloaders/inflector' + + Rails::Autoloaders::Inflector + rescue LoadError + # Fallback to Rails 6. + require 'active_support/dependencies' + require 'active_support/dependencies/zeitwerk_integration' + + ActiveSupport::Dependencies::ZeitwerkIntegration::Inflector + end +end + +require_relative '../lib/gitlab' +require_relative '../config/initializers/0_inject_enterprise_edition_module' +require_relative '../config/initializers_before_autoloader/000_inflections' +require_relative '../config/initializers_before_autoloader/004_zeitwerk' + +Rails.autoloaders.each do |autoloader| + autoloader.push_dir('lib') + autoloader.push_dir('ee/lib') if Gitlab.ee? + autoloader.push_dir('jh/lib') if Gitlab.jh? + autoloader.setup +end diff --git a/spec/requests/api/admin/batched_background_migrations_spec.rb b/spec/requests/api/admin/batched_background_migrations_spec.rb index d946ac17f3f..e88fba3fbe7 100644 --- a/spec/requests/api/admin/batched_background_migrations_spec.rb +++ b/spec/requests/api/admin/batched_background_migrations_spec.rb @@ -4,22 +4,23 @@ require 'spec_helper' RSpec.describe API::Admin::BatchedBackgroundMigrations, feature_category: :database do let(:admin) { create(:admin) } - let(:unauthorized_user) { create(:user) } describe 'GET /admin/batched_background_migrations/:id' do let!(:migration) { create(:batched_background_migration, :paused) } let(:database) { :main } let(:params) { { database: database } } + let(:path) { "/admin/batched_background_migrations/#{migration.id}" } + + it_behaves_like "GET request permissions for admin mode" subject(:show_migration) do - get api("/admin/batched_background_migrations/#{migration.id}", admin), params: { database: database } + get api(path, admin, admin_mode: true), params: { database: database } end it 'fetches the batched background migration' do show_migration aggregate_failures "testing response" do - expect(response).to have_gitlab_http_status(:ok) expect(json_response['id']).to eq(migration.id) expect(json_response['status']).to eq('paused') expect(json_response['job_class_name']).to eq(migration.job_class_name) @@ -29,7 +30,8 @@ RSpec.describe API::Admin::BatchedBackgroundMigrations, feature_category: :datab context 'when the batched background migration does not exist' do it 'returns 404' do - get api("/admin/batched_background_migrations/#{non_existing_record_id}", admin), params: params + get api("/admin/batched_background_migrations/#{non_existing_record_id}", admin, admin_mode: true), + params: params expect(response).to have_gitlab_http_status(:not_found) end @@ -50,19 +52,11 @@ RSpec.describe API::Admin::BatchedBackgroundMigrations, feature_category: :datab end end - context 'when authenticated as a non-admin user' do - it 'returns 403' do - get api("/admin/batched_background_migrations/#{migration.id}", unauthorized_user) - - expect(response).to have_gitlab_http_status(:forbidden) - end - end - context 'when the database name does not exist' do let(:database) { :wrong_database } - it 'returns bad request' do - get api("/admin/batched_background_migrations/#{migration.id}", admin), params: params + it 'returns bad request', :aggregate_failures do + get api(path, admin, admin_mode: true), params: params expect(response).to have_gitlab_http_status(:bad_request) expect(response.body).to include('database does not have a valid value') @@ -72,13 +66,15 @@ RSpec.describe API::Admin::BatchedBackgroundMigrations, feature_category: :datab describe 'GET /admin/batched_background_migrations' do let!(:migration) { create(:batched_background_migration) } + let(:path) { '/admin/batched_background_migrations' } + + it_behaves_like "GET request permissions for admin mode" context 'when is an admin user' do it 'returns batched background migrations' do - get api('/admin/batched_background_migrations', admin) + get api(path, admin, admin_mode: true) aggregate_failures "testing response" do - expect(response).to have_gitlab_http_status(:ok) expect(json_response.count).to eq(1) expect(json_response.first['id']).to eq(migration.id) expect(json_response.first['job_class_name']).to eq(migration.job_class_name) @@ -105,14 +101,14 @@ RSpec.describe API::Admin::BatchedBackgroundMigrations, feature_category: :datab expect(Gitlab::Database::SharedModel).to receive(:using_connection).with(ci_model.connection).and_yield - get api('/admin/batched_background_migrations', admin), params: params + get api(path, admin, admin_mode: true), params: params end context 'when the database name does not exist' do let(:database) { :wrong_database } - it 'returns bad request' do - get api("/admin/batched_background_migrations", admin), params: params + it 'returns bad request', :aggregate_failures do + get api(path, admin, admin_mode: true), params: params expect(response).to have_gitlab_http_status(:bad_request) expect(response.body).to include('database does not have a valid value') @@ -127,10 +123,9 @@ RSpec.describe API::Admin::BatchedBackgroundMigrations, feature_category: :datab create(:batched_background_migration, :active, gitlab_schema: schema) end - get api('/admin/batched_background_migrations', admin), params: params + get api(path, admin, admin_mode: true), params: params aggregate_failures "testing response" do - expect(response).to have_gitlab_http_status(:ok) expect(json_response.count).to eq(1) expect(json_response.first['id']).to eq(ci_database_migration.id) expect(json_response.first['job_class_name']).to eq(ci_database_migration.job_class_name) @@ -142,30 +137,24 @@ RSpec.describe API::Admin::BatchedBackgroundMigrations, feature_category: :datab end end end - - context 'when authenticated as a non-admin user' do - it 'returns 403' do - get api('/admin/batched_background_migrations', unauthorized_user) - - expect(response).to have_gitlab_http_status(:forbidden) - end - end end describe 'PUT /admin/batched_background_migrations/:id/resume' do let!(:migration) { create(:batched_background_migration, :paused) } let(:database) { :main } let(:params) { { database: database } } + let(:path) { "/admin/batched_background_migrations/#{migration.id}/resume" } + + it_behaves_like "PUT request permissions for admin mode" subject(:resume) do - put api("/admin/batched_background_migrations/#{migration.id}/resume", admin), params: params + put api(path, admin, admin_mode: true), params: params end it 'pauses the batched background migration' do resume aggregate_failures "testing response" do - expect(response).to have_gitlab_http_status(:ok) expect(json_response['id']).to eq(migration.id) expect(json_response['status']).to eq('active') end @@ -173,7 +162,8 @@ RSpec.describe API::Admin::BatchedBackgroundMigrations, feature_category: :datab context 'when the batched background migration does not exist' do it 'returns 404' do - put api("/admin/batched_background_migrations/#{non_existing_record_id}/resume", admin), params: params + put api("/admin/batched_background_migrations/#{non_existing_record_id}/resume", admin, admin_mode: true), + params: params expect(response).to have_gitlab_http_status(:not_found) end @@ -183,7 +173,7 @@ RSpec.describe API::Admin::BatchedBackgroundMigrations, feature_category: :datab let!(:migration) { create(:batched_background_migration, :failed) } it 'returns 422' do - put api("/admin/batched_background_migrations/#{migration.id}/resume", admin), params: params + put api(path, admin, admin_mode: true), params: params expect(response).to have_gitlab_http_status(:unprocessable_entity) end @@ -206,34 +196,28 @@ RSpec.describe API::Admin::BatchedBackgroundMigrations, feature_category: :datab context 'when the database name does not exist' do let(:database) { :wrong_database } - it 'returns bad request' do - put api("/admin/batched_background_migrations/#{migration.id}/resume", admin), params: params + it 'returns bad request', :aggregate_failures do + put api(path, admin, admin_mode: true), params: params expect(response).to have_gitlab_http_status(:bad_request) expect(response.body).to include('database does not have a valid value') end end end - - context 'when authenticated as a non-admin user' do - it 'returns 403' do - put api("/admin/batched_background_migrations/#{migration.id}/resume", unauthorized_user) - - expect(response).to have_gitlab_http_status(:forbidden) - end - end end describe 'PUT /admin/batched_background_migrations/:id/pause' do let!(:migration) { create(:batched_background_migration, :active) } let(:database) { :main } let(:params) { { database: database } } + let(:path) { "/admin/batched_background_migrations/#{migration.id}/pause" } + + it_behaves_like "PUT request permissions for admin mode" it 'pauses the batched background migration' do - put api("/admin/batched_background_migrations/#{migration.id}/pause", admin), params: params + put api(path, admin, admin_mode: true), params: params aggregate_failures "testing response" do - expect(response).to have_gitlab_http_status(:ok) expect(json_response['id']).to eq(migration.id) expect(json_response['status']).to eq('paused') end @@ -241,7 +225,8 @@ RSpec.describe API::Admin::BatchedBackgroundMigrations, feature_category: :datab context 'when the batched background migration does not exist' do it 'returns 404' do - put api("/admin/batched_background_migrations/#{non_existing_record_id}/pause", admin), params: params + put api("/admin/batched_background_migrations/#{non_existing_record_id}/pause", admin, admin_mode: true), + params: params expect(response).to have_gitlab_http_status(:not_found) end @@ -251,7 +236,7 @@ RSpec.describe API::Admin::BatchedBackgroundMigrations, feature_category: :datab let!(:migration) { create(:batched_background_migration, :failed) } it 'returns 422' do - put api("/admin/batched_background_migrations/#{migration.id}/pause", admin), params: params + put api(path, admin, admin_mode: true), params: params expect(response).to have_gitlab_http_status(:unprocessable_entity) end @@ -268,27 +253,19 @@ RSpec.describe API::Admin::BatchedBackgroundMigrations, feature_category: :datab it 'uses the correct connection' do expect(Gitlab::Database::SharedModel).to receive(:using_connection).with(ci_model.connection).and_yield - put api("/admin/batched_background_migrations/#{migration.id}/pause", admin), params: params + put api(path, admin, admin_mode: true), params: params end context 'when the database name does not exist' do let(:database) { :wrong_database } - it 'returns bad request' do - put api("/admin/batched_background_migrations/#{migration.id}/pause", admin), params: params + it 'returns bad request', :aggregate_failures do + put api(path, admin, admin_mode: true), params: params expect(response).to have_gitlab_http_status(:bad_request) expect(response.body).to include('database does not have a valid value') end end end - - context 'when authenticated as a non-admin user' do - it 'returns 403' do - put api("/admin/batched_background_migrations/#{non_existing_record_id}/pause", unauthorized_user) - - expect(response).to have_gitlab_http_status(:forbidden) - end - end end end diff --git a/spec/requests/api/admin/ci/variables_spec.rb b/spec/requests/api/admin/ci/variables_spec.rb index 4bdc44cb583..1ecd1edd99e 100644 --- a/spec/requests/api/admin/ci/variables_spec.rb +++ b/spec/requests/api/admin/ci/variables_spec.rb @@ -5,68 +5,58 @@ require 'spec_helper' RSpec.describe ::API::Admin::Ci::Variables do let_it_be(:admin) { create(:admin) } let_it_be(:user) { create(:user) } + let_it_be(:variable) { create(:ci_instance_variable) } + let_it_be(:path) { '/admin/ci/variables' } describe 'GET /admin/ci/variables' do - let!(:variable) { create(:ci_instance_variable) } + it_behaves_like 'GET request permissions for admin mode' it 'returns instance-level variables for admins', :aggregate_failures do - get api('/admin/ci/variables', admin) + get api(path, admin, admin_mode: true) - expect(response).to have_gitlab_http_status(:ok) expect(json_response).to be_a(Array) end - it 'does not return instance-level variables for regular users' do - get api('/admin/ci/variables', user) - - expect(response).to have_gitlab_http_status(:forbidden) - end - it 'does not return instance-level variables for unauthorized users' do - get api('/admin/ci/variables') + get api(path, admin_mode: true) expect(response).to have_gitlab_http_status(:unauthorized) end end describe 'GET /admin/ci/variables/:key' do - let!(:variable) { create(:ci_instance_variable) } + let_it_be(:path) { "/admin/ci/variables/#{variable.key}" } + + it_behaves_like 'GET request permissions for admin mode' it 'returns instance-level variable details for admins', :aggregate_failures do - get api("/admin/ci/variables/#{variable.key}", admin) + get api(path, admin, admin_mode: true) - expect(response).to have_gitlab_http_status(:ok) expect(json_response['value']).to eq(variable.value) expect(json_response['protected']).to eq(variable.protected?) expect(json_response['variable_type']).to eq(variable.variable_type) end it 'responds with 404 Not Found if requesting non-existing variable' do - get api('/admin/ci/variables/non_existing_variable', admin) + get api('/admin/ci/variables/non_existing_variable', admin, admin_mode: true) expect(response).to have_gitlab_http_status(:not_found) end - it 'does not return instance-level variable details for regular users' do - get api("/admin/ci/variables/#{variable.key}", user) - - expect(response).to have_gitlab_http_status(:forbidden) - end - it 'does not return instance-level variable details for unauthorized users' do - get api("/admin/ci/variables/#{variable.key}") + get api(path, admin_mode: true) expect(response).to have_gitlab_http_status(:unauthorized) end end describe 'POST /admin/ci/variables' do - context 'authorized user with proper permissions' do - let!(:variable) { create(:ci_instance_variable) } + it_behaves_like 'POST request permissions for admin mode', { key: 'KEY', value: 'VALUE' } + context 'authorized user with proper permissions' do it 'creates variable for admins', :aggregate_failures do expect do - post api('/admin/ci/variables', admin), + post api(path, admin, admin_mode: true), params: { key: 'TEST_VARIABLE_2', value: 'PROTECTED_VALUE_2', @@ -76,7 +66,6 @@ RSpec.describe ::API::Admin::Ci::Variables do } end.to change { ::Ci::InstanceVariable.count }.by(1) - expect(response).to have_gitlab_http_status(:created) expect(json_response['key']).to eq('TEST_VARIABLE_2') expect(json_response['value']).to eq('PROTECTED_VALUE_2') expect(json_response['protected']).to be_truthy @@ -90,13 +79,13 @@ RSpec.describe ::API::Admin::Ci::Variables do expect(::API::API::LOGGER).to receive(:info).with(include(params: include(masked_params))) - post api("/admin/ci/variables", user), + post api(path, user, admin_mode: true), params: { key: 'VAR_KEY', value: 'SENSITIVE', protected: true, masked: true } end it 'creates variable with optional attributes', :aggregate_failures do expect do - post api('/admin/ci/variables', admin), + post api(path, admin, admin_mode: true), params: { variable_type: 'file', key: 'TEST_VARIABLE_2', @@ -104,7 +93,6 @@ RSpec.describe ::API::Admin::Ci::Variables do } end.to change { ::Ci::InstanceVariable.count }.by(1) - expect(response).to have_gitlab_http_status(:created) expect(json_response['key']).to eq('TEST_VARIABLE_2') expect(json_response['value']).to eq('VALUE_2') expect(json_response['protected']).to be_falsey @@ -115,20 +103,20 @@ RSpec.describe ::API::Admin::Ci::Variables do it 'does not allow to duplicate variable key' do expect do - post api('/admin/ci/variables', admin), + post api(path, admin, admin_mode: true), params: { key: variable.key, value: 'VALUE_2' } end.not_to change { ::Ci::InstanceVariable.count } expect(response).to have_gitlab_http_status(:bad_request) end - it 'does not allow values above 10,000 characters' do + it 'does not allow values above 10,000 characters', :aggregate_failures do too_long_message = <<~MESSAGE.strip The value of the provided variable exceeds the 10000 character limit MESSAGE expect do - post api('/admin/ci/variables', admin), + post api(path, admin, admin_mode: true), params: { key: 'too_long', value: SecureRandom.hex(10_001) } end.not_to change { ::Ci::InstanceVariable.count } @@ -138,17 +126,9 @@ RSpec.describe ::API::Admin::Ci::Variables do end end - context 'authorized user with invalid permissions' do - it 'does not create variable' do - post api('/admin/ci/variables', user) - - expect(response).to have_gitlab_http_status(:forbidden) - end - end - context 'unauthorized user' do it 'does not create variable' do - post api('/admin/ci/variables') + post api(path, admin_mode: true) expect(response).to have_gitlab_http_status(:unauthorized) end @@ -156,11 +136,13 @@ RSpec.describe ::API::Admin::Ci::Variables do end describe 'PUT /admin/ci/variables/:key' do - let!(:variable) { create(:ci_instance_variable) } + let_it_be(:path) { "/admin/ci/variables/#{variable.key}" } + + it_behaves_like 'PUT request permissions for admin mode' context 'authorized user with proper permissions' do it 'updates variable data', :aggregate_failures do - put api("/admin/ci/variables/#{variable.key}", admin), + put api(path, admin, admin_mode: true), params: { variable_type: 'file', value: 'VALUE_1_UP', @@ -169,7 +151,6 @@ RSpec.describe ::API::Admin::Ci::Variables do raw: true } - expect(response).to have_gitlab_http_status(:ok) expect(variable.reload.value).to eq('VALUE_1_UP') expect(variable.reload).to be_protected expect(json_response['variable_type']).to eq('file') @@ -182,28 +163,20 @@ RSpec.describe ::API::Admin::Ci::Variables do expect(::API::API::LOGGER).to receive(:info).with(include(params: include(masked_params))) - put api("/admin/ci/variables/#{variable.key}", admin), + put api(path, admin, admin_mode: true), params: { value: 'SENSITIVE', protected: true, masked: true } end it 'responds with 404 Not Found if requesting non-existing variable' do - put api('/admin/ci/variables/non_existing_variable', admin) + put api('/admin/ci/variables/non_existing_variable', admin, admin_mode: true) expect(response).to have_gitlab_http_status(:not_found) end end - context 'authorized user with invalid permissions' do - it 'does not update variable' do - put api("/admin/ci/variables/#{variable.key}", user) - - expect(response).to have_gitlab_http_status(:forbidden) - end - end - context 'unauthorized user' do it 'does not update variable' do - put api("/admin/ci/variables/#{variable.key}") + put api(path, admin_mode: true) expect(response).to have_gitlab_http_status(:unauthorized) end @@ -211,35 +184,27 @@ RSpec.describe ::API::Admin::Ci::Variables do end describe 'DELETE /admin/ci/variables/:key' do - let!(:variable) { create(:ci_instance_variable) } + let_it_be(:path) { "/admin/ci/variables/#{variable.key}" } + + it_behaves_like 'DELETE request permissions for admin mode' context 'authorized user with proper permissions' do it 'deletes variable' do expect do - delete api("/admin/ci/variables/#{variable.key}", admin) - - expect(response).to have_gitlab_http_status(:no_content) + delete api(path, admin, admin_mode: true) end.to change { ::Ci::InstanceVariable.count }.by(-1) end it 'responds with 404 Not Found if requesting non-existing variable' do - delete api('/admin/ci/variables/non_existing_variable', admin) + delete api('/admin/ci/variables/non_existing_variable', admin, admin_mode: true) expect(response).to have_gitlab_http_status(:not_found) end end - context 'authorized user with invalid permissions' do - it 'does not delete variable' do - delete api("/admin/ci/variables/#{variable.key}", user) - - expect(response).to have_gitlab_http_status(:forbidden) - end - end - context 'unauthorized user' do it 'does not delete variable' do - delete api("/admin/ci/variables/#{variable.key}") + delete api(path, admin_mode: true) expect(response).to have_gitlab_http_status(:unauthorized) end diff --git a/spec/requests/api/admin/instance_clusters_spec.rb b/spec/requests/api/admin/instance_clusters_spec.rb index 7b510f74fd4..84ebe68b732 100644 --- a/spec/requests/api/admin/instance_clusters_spec.rb +++ b/spec/requests/api/admin/instance_clusters_spec.rb @@ -5,7 +5,6 @@ require 'spec_helper' RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_management do include KubernetesHelpers - let_it_be(:regular_user) { create(:user) } let_it_be(:admin_user) { create(:admin) } let_it_be(:project) { create(:project) } let_it_be(:project_cluster) do @@ -17,35 +16,27 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man let(:project_cluster_id) { project_cluster.id } describe "GET /admin/clusters" do + let_it_be(:path) { "/admin/clusters" } let_it_be(:clusters) do create_list(:cluster, 3, :provided_by_gcp, :instance, :production_environment) end - include_examples ':certificate_based_clusters feature flag API responses' do - let(:subject) { get api("/admin/clusters", admin_user) } - end + it_behaves_like 'GET request permissions for admin mode' - context "when authenticated as a non-admin user" do - it 'returns 403' do - get api('/admin/clusters', regular_user) - expect(response).to have_gitlab_http_status(:forbidden) - end + include_examples ':certificate_based_clusters feature flag API responses' do + let(:subject) { get api(path, admin_user, admin_mode: true) } end context "when authenticated as admin" do before do - get api("/admin/clusters", admin_user) - end - - it 'returns 200' do - expect(response).to have_gitlab_http_status(:ok) + get api(path, admin_user, admin_mode: true) end it 'includes pagination headers' do expect(response).to include_pagination_headers end - it 'only returns the instance clusters' do + it 'only returns the instance clusters', :aggregate_failures do cluster_ids = json_response.map { |cluster| cluster['id'] } expect(cluster_ids).to match_array(clusters.pluck(:id)) expect(cluster_ids).not_to include(project_cluster_id) @@ -60,19 +51,23 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man let_it_be(:cluster) do create(:cluster, :instance, :provided_by_gcp, :with_domain, - platform_kubernetes: platform_kubernetes, - user: admin_user) + { platform_kubernetes: platform_kubernetes, + user: admin_user }) end let(:cluster_id) { cluster.id } + let(:path) { "/admin/clusters/#{cluster_id}" } + + it_behaves_like 'GET request permissions for admin mode' + include_examples ':certificate_based_clusters feature flag API responses' do - let(:subject) { get api("/admin/clusters/#{cluster_id}", admin_user) } + let(:subject) { get api(path, admin_user, admin_mode: true) } end context "when authenticated as admin" do before do - get api("/admin/clusters/#{cluster_id}", admin_user) + get api(path, admin_user, admin_mode: true) end context "when no cluster associated to the ID" do @@ -84,15 +79,11 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man end context "when cluster with cluster_id exists" do - it 'returns 200' do - expect(response).to have_gitlab_http_status(:ok) - end - it 'returns the cluster with cluster_id' do expect(json_response['id']).to eq(cluster.id) end - it 'returns the cluster information' do + it 'returns the cluster information', :aggregate_failures do expect(json_response['provider_type']).to eq('gcp') expect(json_response['platform_type']).to eq('kubernetes') expect(json_response['environment_scope']).to eq('*') @@ -102,21 +93,21 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man expect(json_response['managed']).to be_truthy end - it 'returns kubernetes platform information' do + it 'returns kubernetes platform information', :aggregate_failures do platform = json_response['platform_kubernetes'] expect(platform['api_url']).to eq('https://kubernetes.example.com') expect(platform['ca_cert']).to be_present end - it 'returns user information' do + it 'returns user information', :aggregate_failures do user = json_response['user'] expect(user['id']).to eq(admin_user.id) expect(user['username']).to eq(admin_user.username) end - it 'returns GCP provider information' do + it 'returns GCP provider information', :aggregate_failures do gcp_provider = json_response['provider_gcp'] expect(gcp_provider['cluster_id']).to eq(cluster.id) @@ -140,18 +131,11 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man context 'when trying to get a project cluster via the instance cluster endpoint' do it 'returns 404' do - get api("/admin/clusters/#{project_cluster_id}", admin_user) + get api("/admin/clusters/#{project_cluster_id}", admin_user, admin_mode: true) expect(response).to have_gitlab_http_status(:not_found) end end end - - context "when authenticated as a non-admin user" do - it 'returns 403' do - get api("/admin/clusters/#{cluster_id}", regular_user) - expect(response).to have_gitlab_http_status(:forbidden) - end - end end end @@ -159,6 +143,7 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man let(:api_url) { 'https://example.com' } let(:authorization_type) { 'rbac' } let(:clusterable) { Clusters::Instance.new } + let_it_be(:path) { '/admin/clusters/add' } let(:platform_kubernetes_attributes) do { @@ -196,20 +181,31 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man } end + it_behaves_like 'POST request permissions for admin mode', + { + name: 'test-instance-cluster', + domain: 'domain.example.com', + managed: false, + enabled: false, + namespace_per_environment: false, + clusterable: Clusters::Instance.new, + platform_kubernetes_attributes: { + api_url: 'https://example.com', + token: 'sample-token', + authorization_type: 'rbac' + } + } + include_examples ':certificate_based_clusters feature flag API responses' do - let(:subject) { post api('/admin/clusters/add', admin_user), params: cluster_params } + let(:subject) { post api(path, admin_user, admin_mode: true), params: cluster_params } end context 'authorized user' do before do - post api('/admin/clusters/add', admin_user), params: cluster_params + post api(path, admin_user, admin_mode: true), params: cluster_params end context 'with valid params' do - it 'responds with 201' do - expect(response).to have_gitlab_http_status(:created) - end - it 'creates a new Clusters::Cluster', :aggregate_failures do cluster_result = Clusters::Cluster.find(json_response["id"]) platform_kubernetes = cluster_result.platform @@ -271,7 +267,7 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man context 'when an instance cluster already exists' do it 'allows user to add multiple clusters' do - post api('/admin/clusters/add', admin_user), params: multiple_cluster_params + post api(path, admin_user, admin_mode: true), params: multiple_cluster_params expect(Clusters::Instance.new.clusters.count).to eq(2) end @@ -280,8 +276,8 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man context 'with invalid params' do context 'when missing a required parameter' do - it 'responds with 400' do - post api('/admin/clusters/add', admin_user), params: invalid_cluster_params + it 'responds with 400', :aggregate_failures do + post api(path, admin_user, admin_mode: true), params: invalid_cluster_params expect(response).to have_gitlab_http_status(:bad_request) expect(json_response['error']).to eql('name is missing') end @@ -300,14 +296,6 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man end end end - - context 'non-authorized user' do - it 'responds with 403' do - post api('/admin/clusters/add', regular_user), params: cluster_params - - expect(response).to have_gitlab_http_status(:forbidden) - end - end end describe 'PUT /admin/clusters/:cluster_id' do @@ -329,23 +317,23 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man create(:cluster, :instance, :provided_by_gcp, domain: 'old-domain.com') end + let(:path) { "/admin/clusters/#{cluster.id}" } + + it_behaves_like 'PUT request permissions for admin mode' + include_examples ':certificate_based_clusters feature flag API responses' do - let(:subject) { put api("/admin/clusters/#{cluster.id}", admin_user), params: update_params } + let(:subject) { put api(path, admin_user, admin_mode: true), params: update_params } end context 'authorized user' do before do - put api("/admin/clusters/#{cluster.id}", admin_user), params: update_params + put api(path, admin_user, admin_mode: true), params: update_params cluster.reload 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 + it 'updates cluster attributes', :aggregate_failures do expect(cluster.domain).to eq('new-domain.com') expect(cluster.managed).to be_falsy expect(cluster.enabled).to be_falsy @@ -359,7 +347,7 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man expect(response).to have_gitlab_http_status(:bad_request) end - it 'does not update cluster attributes' do + it 'does not update cluster attributes', :aggregate_failures do expect(cluster.domain).to eq('old-domain.com') expect(cluster.managed).to be_truthy expect(cluster.enabled).to be_truthy @@ -422,7 +410,7 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man expect(response).to have_gitlab_http_status(:ok) end - it 'updates platform kubernetes attributes' do + it 'updates platform kubernetes attributes', :aggregate_failures do platform_kubernetes = cluster.platform_kubernetes expect(cluster.name).to eq('new-name') @@ -435,26 +423,18 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man let(:cluster_id) { 1337 } it 'returns 404' do - put api("/admin/clusters/#{cluster_id}", admin_user), params: update_params + put api("/admin/clusters/#{cluster_id}", admin_user, admin_mode: true), params: update_params expect(response).to have_gitlab_http_status(:not_found) end end context 'when trying to update a project cluster via the instance cluster endpoint' do it 'returns 404' do - put api("/admin/clusters/#{project_cluster_id}", admin_user), params: update_params + put api("/admin/clusters/#{project_cluster_id}", admin_user, admin_mode: true), params: update_params expect(response).to have_gitlab_http_status(:not_found) end end end - - context 'non-authorized user' do - it 'responds with 403' do - put api("/admin/clusters/#{cluster.id}", regular_user), params: update_params - - expect(response).to have_gitlab_http_status(:forbidden) - end - end end describe 'DELETE /admin/clusters/:cluster_id' do @@ -464,17 +444,17 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man create(:cluster, :instance, :provided_by_gcp) end + let_it_be(:path) { "/admin/clusters/#{cluster.id}" } + + it_behaves_like 'DELETE request permissions for admin mode' + include_examples ':certificate_based_clusters feature flag API responses' do - let(:subject) { delete api("/admin/clusters/#{cluster.id}", admin_user), params: cluster_params } + let(:subject) { delete api(path, admin_user, admin_mode: true), params: cluster_params } end context 'authorized user' do before do - delete api("/admin/clusters/#{cluster.id}", admin_user), params: cluster_params - end - - it 'responds with 204' do - expect(response).to have_gitlab_http_status(:no_content) + delete api(path, admin_user, admin_mode: true), params: cluster_params end it 'deletes the cluster' do @@ -485,25 +465,17 @@ RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_man let(:cluster_id) { 1337 } it 'returns 404' do - delete api("/admin/clusters/#{cluster_id}", admin_user) + delete api(path, admin_user, admin_mode: true) expect(response).to have_gitlab_http_status(:not_found) end end context 'when trying to update a project cluster via the instance cluster endpoint' do it 'returns 404' do - delete api("/admin/clusters/#{project_cluster_id}", admin_user) + delete api("/admin/clusters/#{project_cluster_id}", admin_user, admin_mode: true) expect(response).to have_gitlab_http_status(:not_found) end end end - - context 'non-authorized user' do - it 'responds with 403' do - delete api("/admin/clusters/#{cluster.id}", regular_user), params: cluster_params - - expect(response).to have_gitlab_http_status(:forbidden) - end - end end end diff --git a/spec/requests/api/admin/plan_limits_spec.rb b/spec/requests/api/admin/plan_limits_spec.rb index 2de7a66d803..ea248cb4f95 100644 --- a/spec/requests/api/admin/plan_limits_spec.rb +++ b/spec/requests/api/admin/plan_limits_spec.rb @@ -3,25 +3,18 @@ require 'spec_helper' RSpec.describe API::Admin::PlanLimits, 'PlanLimits', feature_category: :not_owned do - let_it_be(:user) { create(:user) } let_it_be(:admin) { create(:admin) } let_it_be(:plan) { create(:plan, name: 'default') } + let_it_be(:path) { '/application/plan_limits' } describe 'GET /application/plan_limits' do - context 'as a non-admin user' do - it 'returns 403' do - get api('/application/plan_limits', user) - - expect(response).to have_gitlab_http_status(:forbidden) - end - end + it_behaves_like 'GET request permissions for admin mode' context 'as an admin user' do context 'no params' do - it 'returns plan limits' do - get api('/application/plan_limits', admin) + it 'returns plan limits', :aggregate_failures do + get api(path, admin, admin_mode: true) - expect(response).to have_gitlab_http_status(:ok) expect(json_response).to be_an Hash expect(json_response['ci_pipeline_size']).to eq(Plan.default.actual_limits.ci_pipeline_size) expect(json_response['ci_active_jobs']).to eq(Plan.default.actual_limits.ci_active_jobs) @@ -49,8 +42,8 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits', feature_category: :not_owne @params = { plan_name: 'default' } end - it 'returns plan limits' do - get api('/application/plan_limits', admin), params: @params + it 'returns plan limits', :aggregate_failures do + get api(path, admin, admin_mode: true), params: @params expect(response).to have_gitlab_http_status(:ok) expect(json_response).to be_an Hash @@ -80,8 +73,8 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits', feature_category: :not_owne @params = { plan_name: 'my-plan' } end - it 'returns validation error' do - get api('/application/plan_limits', admin), params: @params + it 'returns validation error', :aggregate_failures do + get api(path, admin, admin_mode: true), params: @params expect(response).to have_gitlab_http_status(:bad_request) expect(json_response['error']).to eq('plan_name does not have a valid value') @@ -91,18 +84,12 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits', feature_category: :not_owne end describe 'PUT /application/plan_limits' do - context 'as a non-admin user' do - it 'returns 403' do - put api('/application/plan_limits', user), params: { plan_name: 'default' } - - expect(response).to have_gitlab_http_status(:forbidden) - end - end + it_behaves_like 'PUT request permissions for admin mode', { 'plan_name': 'default' } context 'as an admin user' do context 'correct params' do - it 'updates multiple plan limits' do - put api('/application/plan_limits', admin), params: { + it 'updates multiple plan limits', :aggregate_failures do + put api(path, admin, admin_mode: true), params: { 'plan_name': 'default', 'ci_pipeline_size': 101, 'ci_active_jobs': 102, @@ -124,7 +111,6 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits', feature_category: :not_owne 'pipeline_hierarchy_size': 250 } - expect(response).to have_gitlab_http_status(:ok) expect(json_response).to be_an Hash expect(json_response['ci_pipeline_size']).to eq(101) expect(json_response['ci_active_jobs']).to eq(102) @@ -146,8 +132,8 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits', feature_category: :not_owne expect(json_response['pipeline_hierarchy_size']).to eq(250) end - it 'updates single plan limits' do - put api('/application/plan_limits', admin), params: { + it 'updates single plan limits', :aggregate_failures do + put api(path, admin, admin_mode: true), params: { 'plan_name': 'default', 'maven_max_file_size': 100 } @@ -159,8 +145,8 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits', feature_category: :not_owne end context 'empty params' do - it 'fails to update plan limits' do - put api('/application/plan_limits', admin), params: {} + it 'fails to update plan limits', :aggregate_failures do + put api(path, admin, admin_mode: true), params: {} expect(response).to have_gitlab_http_status(:bad_request) expect(json_response['error']).to match('plan_name is missing') @@ -168,8 +154,8 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits', feature_category: :not_owne end context 'params with wrong type' do - it 'fails to update plan limits' do - put api('/application/plan_limits', admin), params: { + it 'fails to update plan limits', :aggregate_failures do + put api(path, admin, admin_mode: true), params: { 'plan_name': 'default', 'ci_pipeline_size': 'z', 'ci_active_jobs': 'y', @@ -216,8 +202,8 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits', feature_category: :not_owne end context 'missing plan_name in params' do - it 'fails to update plan limits' do - put api('/application/plan_limits', admin), params: { 'conan_max_file_size': 0 } + it 'fails to update plan limits', :aggregate_failures do + put api(path, admin, admin_mode: true), params: { 'conan_max_file_size': 0 } expect(response).to have_gitlab_http_status(:bad_request) expect(json_response['error']).to match('plan_name is missing') @@ -229,8 +215,8 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits', feature_category: :not_owne Plan.default.actual_limits.update!({ 'golang_max_file_size': 1000 }) end - it 'updates only declared plan limits' do - put api('/application/plan_limits', admin), params: { + it 'updates only declared plan limits', :aggregate_failures do + put api(path, admin, admin_mode: true), params: { 'plan_name': 'default', 'pypi_max_file_size': 200, 'golang_max_file_size': 999 diff --git a/spec/requests/api/admin/sidekiq_spec.rb b/spec/requests/api/admin/sidekiq_spec.rb index 0b456721d4f..5ae7f45a069 100644 --- a/spec/requests/api/admin/sidekiq_spec.rb +++ b/spec/requests/api/admin/sidekiq_spec.rb @@ -6,14 +6,6 @@ RSpec.describe API::Admin::Sidekiq, :clean_gitlab_redis_queues, feature_category let_it_be(:admin) { create(:admin) } describe 'DELETE /admin/sidekiq/queues/:queue_name' do - context 'when the user is not an admin' do - it 'returns a 403' do - delete api("/admin/sidekiq/queues/authorized_projects?user=#{admin.username}", create(:user)) - - expect(response).to have_gitlab_http_status(:forbidden) - end - end - context 'when the user is an admin' do around do |example| Sidekiq::Queue.new('authorized_projects').clear @@ -31,14 +23,19 @@ RSpec.describe API::Admin::Sidekiq, :clean_gitlab_redis_queues, feature_category end context 'valid request' do - it 'returns info about the deleted jobs' do + before do add_job(admin, [1]) add_job(admin, [2]) add_job(create(:user), [3]) + end + + let_it_be(:path) { "/admin/sidekiq/queues/authorized_projects?user=#{admin.username}&worker_class=AuthorizedProjectsWorker" } - delete api("/admin/sidekiq/queues/authorized_projects?user=#{admin.username}&worker_class=AuthorizedProjectsWorker", admin) + it_behaves_like 'DELETE request permissions for admin mode', :ok + + it 'returns info about the deleted jobs' do + delete api(path, admin, admin_mode: true) - expect(response).to have_gitlab_http_status(:ok) expect(json_response).to eq('completed' => true, 'deleted_jobs' => 2, 'queue_size' => 1) @@ -47,7 +44,7 @@ RSpec.describe API::Admin::Sidekiq, :clean_gitlab_redis_queues, feature_category context 'when no required params are provided' do it 'returns a 400' do - delete api("/admin/sidekiq/queues/authorized_projects?user_2=#{admin.username}", admin) + delete api("/admin/sidekiq/queues/authorized_projects?user_2=#{admin.username}", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:bad_request) end @@ -55,7 +52,7 @@ RSpec.describe API::Admin::Sidekiq, :clean_gitlab_redis_queues, feature_category context 'when the queue does not exist' do it 'returns a 404' do - delete api("/admin/sidekiq/queues/authorized_projects_2?user=#{admin.username}", admin) + delete api("/admin/sidekiq/queues/authorized_projects_2?user=#{admin.username}", admin, admin_mode: true) expect(response).to have_gitlab_http_status(:not_found) end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 4e8f990fc10..3f0900886eb 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -356,12 +356,6 @@ RSpec.configure do |config| # All API specs will be adapted continuously. The following list contains the specs that have not yet been adapted. # The feature flag is disabled for these specs as long as they are not yet adapted. admin_mode_for_api_feature_flag_paths = %w[ - ./spec/frontend/fixtures/api_deploy_keys.rb - ./spec/requests/api/admin/batched_background_migrations_spec.rb - ./spec/requests/api/admin/ci/variables_spec.rb - ./spec/requests/api/admin/instance_clusters_spec.rb - ./spec/requests/api/admin/plan_limits_spec.rb - ./spec/requests/api/admin/sidekiq_spec.rb ./spec/requests/api/broadcast_messages_spec.rb ./spec/requests/api/ci/pipelines_spec.rb ./spec/requests/api/ci/runners_reset_registration_token_spec.rb diff --git a/spec/support/helpers/repo_helpers.rb b/spec/support/helpers/repo_helpers.rb index 9f37cf61cc9..45467fb7099 100644 --- a/spec/support/helpers/repo_helpers.rb +++ b/spec/support/helpers/repo_helpers.rb @@ -41,6 +41,7 @@ eos line_code: '2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_14', line_code_path: 'files/ruby/popen.rb', del_line_code: '2f6fcd96b88b36ce98c38da085c795a27d92a3dd_13_13', + referenced_by: [], message: <<eos Change some files Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> @@ -56,6 +57,7 @@ eos author_full_name: "Sytse Sijbrandij", author_email: "sytse@gitlab.com", files_changed_count: 1, + referenced_by: [], message: <<eos Add directory structure for tree_helper spec @@ -74,6 +76,7 @@ eos sha: "913c66a37b4a45b9769037c55c2d238bd0942d2e", author_full_name: "Dmitriy Zaporozhets", author_email: "dmitriy.zaporozhets@gmail.com", + referenced_by: [], message: <<eos Files, encoding and much more Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> @@ -89,6 +92,7 @@ eos author_email: "dmitriy.zaporozhets@gmail.com", old_blob_id: '33f3729a45c02fc67d00adb1b8bca394b0e761d9', new_blob_id: '2f63565e7aac07bcdadb654e253078b727143ec4', + referenced_by: [], message: <<eos Modified image Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> diff --git a/spec/support/helpers/test_env.rb b/spec/support/helpers/test_env.rb index 3403064bf0b..727b8a6b880 100644 --- a/spec/support/helpers/test_env.rb +++ b/spec/support/helpers/test_env.rb @@ -2,6 +2,7 @@ require 'parallel' require_relative 'gitaly_setup' +require_relative '../../../lib/gitlab/setup_helper' module TestEnv extend self diff --git a/spec/support/shared_examples/requests/admin_mode_shared_examples.rb b/spec/support/shared_examples/requests/admin_mode_shared_examples.rb index 07fde7d3f35..7e5ad751247 100644 --- a/spec/support/shared_examples/requests/admin_mode_shared_examples.rb +++ b/spec/support/shared_examples/requests/admin_mode_shared_examples.rb @@ -14,9 +14,9 @@ RSpec.shared_examples 'POST request permissions for admin mode' do |params| it_behaves_like 'POST request permissions for admin mode when admin', params end -RSpec.shared_examples 'DELETE request permissions for admin mode' do +RSpec.shared_examples 'DELETE request permissions for admin mode' do |success_status_code = :no_content| it_behaves_like 'DELETE request permissions for admin mode when user' - it_behaves_like 'DELETE request permissions for admin mode when admin' + it_behaves_like 'DELETE request permissions for admin mode when admin', success_status_code end RSpec.shared_examples 'GET request permissions for admin mode when user' do @@ -82,12 +82,12 @@ RSpec.shared_examples 'DELETE request permissions for admin mode when user' do it_behaves_like 'admin mode on', false, :forbidden end -RSpec.shared_examples 'DELETE request permissions for admin mode when admin' do +RSpec.shared_examples 'DELETE request permissions for admin mode when admin' do |success_status_code| subject { delete api(path, current_user, admin_mode: admin_mode) } let_it_be(:current_user) { create(:admin) } - it_behaves_like 'admin mode on', true, :no_content + it_behaves_like 'admin mode on', true, success_status_code it_behaves_like 'admin mode on', false, :forbidden end |