diff options
37 files changed, 363 insertions, 97 deletions
diff --git a/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue b/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue index 4e7d77863b9..82335e71403 100644 --- a/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue +++ b/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue @@ -42,7 +42,6 @@ export default { <template> <li class="linked-pipeline build"> - <div class="curve"></div> <gl-button :id="buttonId" v-gl-tooltip diff --git a/app/helpers/clusters_helper.rb b/app/helpers/clusters_helper.rb index 0037c49f134..f55acad8517 100644 --- a/app/helpers/clusters_helper.rb +++ b/app/helpers/clusters_helper.rb @@ -9,11 +9,11 @@ module ClustersHelper def create_new_cluster_label(provider: nil) case provider when 'aws' - s_('ClusterIntegration|Create new Cluster on EKS') + s_('ClusterIntegration|Create new cluster on EKS') when 'gcp' - s_('ClusterIntegration|Create new Cluster on GKE') + s_('ClusterIntegration|Create new cluster on GKE') else - s_('ClusterIntegration|Create new Cluster') + s_('ClusterIntegration|Create new cluster') end end diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index dce0842060d..0211a22a8c4 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -205,4 +205,4 @@ module TodosHelper end end -TodosHelper.prepend_if_ee('EE::NotesHelper'); TodosHelper.prepend_if_ee('EE::TodosHelper') # rubocop: disable Style/Semicolon +TodosHelper.prepend_if_ee('EE::TodosHelper') diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index ba87369f30b..7e7c580a48e 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -762,6 +762,10 @@ module Ci Gitlab::Ci::Build::Credentials::Factory.new(self).create! end + def all_dependencies + (dependencies + cross_dependencies).uniq + end + def dependencies return [] if empty_dependencies? @@ -782,6 +786,10 @@ module Ci depended_jobs end + def cross_dependencies + [] + end + def empty_dependencies? options[:dependencies]&.empty? end diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb index 4929c773eb8..8d38835fb3b 100644 --- a/app/models/commit_status.rb +++ b/app/models/commit_status.rb @@ -47,6 +47,12 @@ class CommitStatus < ApplicationRecord scope :after_stage, -> (index) { where('stage_idx > ?', index) } scope :processables, -> { where(type: %w[Ci::Build Ci::Bridge]) } scope :for_ids, -> (ids) { where(id: ids) } + scope :for_ref, -> (ref) { where(ref: ref) } + scope :by_name, -> (name) { where(name: name) } + + scope :for_project_paths, -> (paths) do + where(project: Project.where_full_path_in(Array(paths))) + end scope :with_preloads, -> do preload(:project, :user) diff --git a/changelogs/unreleased/eread-harmonize-capitalization-in-ui.yml b/changelogs/unreleased/eread-harmonize-capitalization-in-ui.yml new file mode 100644 index 00000000000..a34b7884f70 --- /dev/null +++ b/changelogs/unreleased/eread-harmonize-capitalization-in-ui.yml @@ -0,0 +1,5 @@ +--- +title: Harmonize capitalization on cluster UI +merge_request: 21878 +author: Evan Read +type: other diff --git a/changelogs/unreleased/strong-validate-import-export-references.yml b/changelogs/unreleased/strong-validate-import-export-references.yml new file mode 100644 index 00000000000..3ea69a6c59d --- /dev/null +++ b/changelogs/unreleased/strong-validate-import-export-references.yml @@ -0,0 +1,5 @@ +--- +title: Strong validate import export references +merge_request: 19682 +author: +type: added diff --git a/config/initializers/zz_metrics.rb b/config/initializers/zz_metrics.rb index 416611ef46c..5bbfb97277c 100644 --- a/config/initializers/zz_metrics.rb +++ b/config/initializers/zz_metrics.rb @@ -8,6 +8,8 @@ # # rubocop:disable Metrics/AbcSize def instrument_classes(instrumentation) + return if ENV['STATIC_VERIFICATION'] + instrumentation.instrument_instance_methods(Gitlab::Shell) instrumentation.instrument_methods(Gitlab::Git) diff --git a/db/migrate/20191205094702_add_index_for_cross_projects_dependencies_to_ci_builds.rb b/db/migrate/20191205094702_add_index_for_cross_projects_dependencies_to_ci_builds.rb new file mode 100644 index 00000000000..023414fb4bb --- /dev/null +++ b/db/migrate/20191205094702_add_index_for_cross_projects_dependencies_to_ci_builds.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class AddIndexForCrossProjectsDependenciesToCiBuilds < ActiveRecord::Migration[5.2] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_concurrent_index :ci_builds, [:project_id, :name, :ref], + where: "type = 'Ci::Build' AND status = 'success' AND (retried = FALSE OR retried IS NULL)" + end + + def down + remove_concurrent_index :ci_builds, [:project_id, :name, :ref], + where: "type = 'Ci::Build' AND status = 'success' AND (retried = FALSE OR retried IS NULL)" + end +end diff --git a/db/schema.rb b/db/schema.rb index 2422bb35cbd..acf51164e0b 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -693,6 +693,7 @@ ActiveRecord::Schema.define(version: 2019_12_16_183532) do t.index ["commit_id", "type", "ref"], name: "index_ci_builds_on_commit_id_and_type_and_ref" t.index ["name"], name: "index_ci_builds_on_name_for_security_products_values", where: "((name)::text = ANY (ARRAY[('container_scanning'::character varying)::text, ('dast'::character varying)::text, ('dependency_scanning'::character varying)::text, ('license_management'::character varying)::text, ('sast'::character varying)::text]))" t.index ["project_id", "id"], name: "index_ci_builds_on_project_id_and_id" + t.index ["project_id", "name", "ref"], name: "index_ci_builds_on_project_id_and_name_and_ref", where: "(((type)::text = 'Ci::Build'::text) AND ((status)::text = 'success'::text) AND ((retried = false) OR (retried IS NULL)))" t.index ["project_id", "status"], name: "index_ci_builds_project_id_and_status_for_live_jobs_partial2", where: "(((type)::text = 'Ci::Build'::text) AND ((status)::text = ANY (ARRAY[('running'::character varying)::text, ('pending'::character varying)::text, ('created'::character varying)::text])))" t.index ["project_id"], name: "index_ci_builds_on_project_id_for_successfull_pages_deploy", where: "(((type)::text = 'GenericCommitStatus'::text) AND ((stage)::text = 'deploy'::text) AND ((name)::text = 'pages:deploy'::text) AND ((status)::text = 'success'::text))" t.index ["protected"], name: "index_ci_builds_on_protected" diff --git a/doc/development/utilities.md b/doc/development/utilities.md index 25869a0d2b5..68851f4d550 100644 --- a/doc/development/utilities.md +++ b/doc/development/utilities.md @@ -53,7 +53,7 @@ Refer to <https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/utils/over - This utility can help you check if one method would override another or not. It is the same concept as Java's `@Override` annotation - or Scala's `override` keyword. However, you should only do this check when + or Scala's `override` keyword. However, we only run this check when `ENV['STATIC_VERIFICATION']` is set to avoid production runtime overhead. This is useful for checking: @@ -94,6 +94,15 @@ Refer to <https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/utils/over end ``` + Note that the check will only happen when either: + + - The overriding method is defined in a class, or: + - The overriding method is defined in a module, and it's prepended to + a class or a module. + + Because only a class or prepended module can actually override a method. + Including or extending a module into another cannot override anything. + ## `StrongMemoize` Refer to <https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/utils/strong_memoize.rb>: diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 6d33cb214ee..cc95be5e3be 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -1672,7 +1672,7 @@ module API expose :artifacts, using: Artifacts expose :cache, using: Cache expose :credentials, using: Credentials - expose :dependencies, using: Dependency + expose :all_dependencies, as: :dependencies, using: Dependency expose :features end end diff --git a/lib/gitlab/ci/config/entry/job.rb b/lib/gitlab/ci/config/entry/job.rb index 517caabc79e..6a55b8cda57 100644 --- a/lib/gitlab/ci/config/entry/job.rb +++ b/lib/gitlab/ci/config/entry/job.rb @@ -134,7 +134,7 @@ module Gitlab entry :needs, Entry::Needs, description: 'Needs configuration for this job.', - metadata: { allowed_needs: %i[job] }, + metadata: { allowed_needs: %i[job cross_dependency] }, inherit: false entry :variables, Entry::Variables, diff --git a/lib/gitlab/ci/config/entry/need.rb b/lib/gitlab/ci/config/entry/need.rb index 61bd09fd5f3..abfffb7a5ed 100644 --- a/lib/gitlab/ci/config/entry/need.rb +++ b/lib/gitlab/ci/config/entry/need.rb @@ -6,7 +6,9 @@ module Gitlab module Entry class Need < ::Gitlab::Config::Entry::Simplifiable strategy :JobString, if: -> (config) { config.is_a?(String) } - strategy :JobHash, if: -> (config) { config.is_a?(Hash) && config.key?(:job) } + + strategy :JobHash, + if: -> (config) { config.is_a?(Hash) && config.key?(:job) && !(config.key?(:project) || config.key?(:ref)) } class JobString < ::Gitlab::Config::Entry::Node include ::Gitlab::Config::Entry::Validatable diff --git a/lib/gitlab/ci/config/entry/needs.rb b/lib/gitlab/ci/config/entry/needs.rb index 28452aaaa16..5301c453ed4 100644 --- a/lib/gitlab/ci/config/entry/needs.rb +++ b/lib/gitlab/ci/config/entry/needs.rb @@ -53,3 +53,5 @@ module Gitlab end end end + +::Gitlab::Ci::Config::Entry::Needs.prepend_if_ee('::EE::Gitlab::Ci::Config::Entry::Needs') diff --git a/lib/gitlab/ci/yaml_processor.rb b/lib/gitlab/ci/yaml_processor.rb index 8ac864eb5cf..27cd4f5fd6b 100644 --- a/lib/gitlab/ci/yaml_processor.rb +++ b/lib/gitlab/ci/yaml_processor.rb @@ -69,6 +69,7 @@ module Gitlab services: job[:services], artifacts: job[:artifacts], dependencies: job[:dependencies], + cross_dependencies: job.dig(:needs, :cross_dependency), job_timeout: job[:timeout], before_script: job[:before_script], script: job[:script], diff --git a/lib/gitlab/import_export/attribute_cleaner.rb b/lib/gitlab/import_export/attribute_cleaner.rb index 50fec9f3eb9..c8dbec7bcba 100644 --- a/lib/gitlab/import_export/attribute_cleaner.rb +++ b/lib/gitlab/import_export/attribute_cleaner.rb @@ -3,7 +3,7 @@ module Gitlab module ImportExport class AttributeCleaner - ALLOWED_REFERENCES = RelationFactory::PROJECT_REFERENCES + RelationFactory::USER_REFERENCES + %w[group_id commit_id] + ALLOWED_REFERENCES = RelationFactory::PROJECT_REFERENCES + RelationFactory::USER_REFERENCES + %w[group_id commit_id discussion_id] PROHIBITED_REFERENCES = Regexp.union(/\Acached_markdown_version\Z/, /_id\Z/, /_ids\Z/, /_html\Z/).freeze def self.clean(*args) diff --git a/lib/gitlab/import_export/import_export.yml b/lib/gitlab/import_export/import_export.yml index ba1ccd77604..4f4b4c02eb9 100644 --- a/lib/gitlab/import_export/import_export.yml +++ b/lib/gitlab/import_export/import_export.yml @@ -172,24 +172,36 @@ excluded_attributes: - :external_diff - :stored_externally - :external_diff_store + - :merge_request_id + merge_request_diff_commits: + - :merge_request_diff_id merge_request_diff_files: - :diff - :external_diff_offset - :external_diff_size + - :merge_request_diff_id issues: - :milestone_id + - :moved_to_id + - :state_id + - :duplicated_to_id + - :promoted_to_epic_id merge_request: - :milestone_id - :ref_fetched - :merge_jid - :rebase_jid - :latest_merge_request_diff_id + - :head_pipeline_id + - :state_id merge_requests: - :milestone_id - :ref_fetched - :merge_jid - :rebase_jid - :latest_merge_request_diff_id + - :head_pipeline_id + - :state_id award_emoji: - :awardable_id statuses: @@ -203,6 +215,16 @@ excluded_attributes: - :artifacts_metadata_store - :artifacts_size - :commands + - :runner_id + - :trigger_request_id + - :erased_by_id + - :auto_canceled_by_id + - :stage_id + - :upstream_pipeline_id + - :resource_group_id + - :waiting_for_resource_at + sentry_issue: + - :issue_id push_event_payload: - :event_id project_badges: @@ -211,6 +233,9 @@ excluded_attributes: - :reference - :reference_html - :epic_id + - :issue_id + - :merge_request_id + - :label_id runners: - :token - :token_encrypted @@ -222,7 +247,64 @@ excluded_attributes: - :enabled service_desk_setting: - :outgoing_name - + priorities: + - :label_id + events: + - :target_id + timelogs: + - :issue_id + - :merge_request_id + notes: + - :noteable_id + - :review_id + label_links: + - :label_id + - :target_id + issue_assignees: + - :issue_id + zoom_meetings: + - :issue_id + design: + - :issue_id + designs: + - :issue_id + design_versions: + - :issue_id + actions: + - :design_id + - :version_id + links: + - :release_id + project_members: + - :source_id + metrics: + - :merge_request_id + - :pipeline_id + suggestions: + - :note_id + ci_pipelines: + - :auto_canceled_by_id + - :pipeline_schedule_id + - :merge_request_id + - :external_pull_request_id + stages: + - :pipeline_id + merge_access_levels: + - :protected_branch_id + push_access_levels: + - :protected_branch_id + unprotect_access_levels: + - :protected_branch_id + create_access_levels: + - :protected_tag_id + deploy_access_levels: + - :protected_environment_id + boards: + - :milestone_id + lists: + - :board_id + - :label_id + - :milestone_id methods: notes: - :type diff --git a/lib/gitlab/utils/override.rb b/lib/gitlab/utils/override.rb index 35aea209cb9..784a6686962 100644 --- a/lib/gitlab/utils/override.rb +++ b/lib/gitlab/utils/override.rb @@ -146,7 +146,8 @@ module Gitlab def prepended(base = nil) super - queue_verification(base) if base + # prepend can override methods, thus we need to verify it like classes + queue_verification(base, verify: true) if base end def extended(mod = nil) @@ -155,11 +156,15 @@ module Gitlab queue_verification(mod.singleton_class) if mod end - def queue_verification(base) + def queue_verification(base, verify: false) return unless ENV['STATIC_VERIFICATION'] - if base.is_a?(Class) # We could check for Class in `override` - # This could be `nil` if `override` was never called + # We could check for Class in `override` + # This could be `nil` if `override` was never called. + # We also force verification for prepend because it can also override + # a method like a class, but not the cases for include or extend. + # This includes Rails helpers but not limited to. + if base.is_a?(Class) || verify Override.extensions[self]&.add_class(base) end end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index be2ba9d22fb..9044dcc2ff8 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -3790,13 +3790,13 @@ msgstr "" msgid "ClusterIntegration|Create cluster on" msgstr "" -msgid "ClusterIntegration|Create new Cluster" +msgid "ClusterIntegration|Create new cluster" msgstr "" -msgid "ClusterIntegration|Create new Cluster on EKS" +msgid "ClusterIntegration|Create new cluster on EKS" msgstr "" -msgid "ClusterIntegration|Create new Cluster on GKE" +msgid "ClusterIntegration|Create new cluster on GKE" msgstr "" msgid "ClusterIntegration|Creating Kubernetes cluster" diff --git a/package.json b/package.json index 098cdd534a0..a4b6f55365e 100644 --- a/package.json +++ b/package.json @@ -39,9 +39,9 @@ "@babel/plugin-syntax-dynamic-import": "^7.2.0", "@babel/plugin-syntax-import-meta": "^7.2.0", "@babel/preset-env": "^7.6.2", - "@gitlab/svgs": "^1.85.0", - "@gitlab/ui": "8.2.0", - "@gitlab/visual-review-tools": "1.2.0", + "@gitlab/svgs": "^1.88.0", + "@gitlab/ui": "8.8.0", + "@gitlab/visual-review-tools": "1.5.1", "@sentry/browser": "^5.10.2", "@sourcegraph/code-host-integration": "^0.0.14", "apollo-cache-inmemory": "^1.6.3", diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb index 400679365be..9a1d13cf677 100644 --- a/qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb +++ b/qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb @@ -8,17 +8,9 @@ module QA before do Flow::Login.sign_in - project = Resource::Project.fabricate_via_api! do |resource| - resource.name = 'project-for-issue-suggestions' - resource.description = 'project for issue suggestions' - end - Resource::Issue.fabricate_via_api! do |issue| issue.title = issue_title - issue.project = project - end - - project.visit! + end.project.visit! end it 'user sees issue suggestions when creating a new issue' do diff --git a/spec/features/admin/clusters/eks_spec.rb b/spec/features/admin/clusters/eks_spec.rb index b262db1ad7c..40561aa508c 100644 --- a/spec/features/admin/clusters/eks_spec.rb +++ b/spec/features/admin/clusters/eks_spec.rb @@ -22,7 +22,7 @@ describe 'Instance-level AWS EKS Cluster', :js do end it 'user sees a form to create an EKS cluster' do - expect(page).to have_content('Create new Cluster on EKS') + expect(page).to have_content('Create new cluster on EKS') end end end diff --git a/spec/features/groups/clusters/eks_spec.rb b/spec/features/groups/clusters/eks_spec.rb index b6942304c22..a9267d58739 100644 --- a/spec/features/groups/clusters/eks_spec.rb +++ b/spec/features/groups/clusters/eks_spec.rb @@ -28,7 +28,7 @@ describe 'Group AWS EKS Cluster', :js do end it 'user sees a form to create an EKS cluster' do - expect(page).to have_content('Create new Cluster on EKS') + expect(page).to have_content('Create new cluster on EKS') end end end diff --git a/spec/features/projects/clusters/eks_spec.rb b/spec/features/projects/clusters/eks_spec.rb index e0ebccd85ac..bb0072fc8dd 100644 --- a/spec/features/projects/clusters/eks_spec.rb +++ b/spec/features/projects/clusters/eks_spec.rb @@ -28,7 +28,7 @@ describe 'AWS EKS Cluster', :js do end it 'user sees a form to create an EKS cluster' do - expect(page).to have_content('Create new Cluster on EKS') + expect(page).to have_content('Create new cluster on EKS') end end end diff --git a/spec/features/projects/clusters/gcp_spec.rb b/spec/features/projects/clusters/gcp_spec.rb index 142aaaffb7d..4bc0aef0cd4 100644 --- a/spec/features/projects/clusters/gcp_spec.rb +++ b/spec/features/projects/clusters/gcp_spec.rb @@ -29,7 +29,7 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do visit project_clusters_path(project) click_link 'Add Kubernetes cluster' - click_link 'Create new Cluster' + click_link 'Create new cluster' click_link 'Google GKE' end diff --git a/spec/features/projects/clusters_spec.rb b/spec/features/projects/clusters_spec.rb index 9b02991cd53..ad51533c42c 100644 --- a/spec/features/projects/clusters_spec.rb +++ b/spec/features/projects/clusters_spec.rb @@ -54,7 +54,7 @@ describe 'Clusters', :js do visit project_clusters_path(project) click_link 'Add Kubernetes cluster' - click_link 'Create new Cluster' + click_link 'Create new cluster' end it 'user sees a link to create a GKE cluster' do diff --git a/spec/features/projects/import_export/export_file_spec.rb b/spec/features/projects/import_export/export_file_spec.rb index c15a3250221..54a6ac1551b 100644 --- a/spec/features/projects/import_export/export_file_spec.rb +++ b/spec/features/projects/import_export/export_file_spec.rb @@ -12,8 +12,6 @@ describe 'Import/Export - project export integration test', :js do let(:user) { create(:admin) } let(:export_path) { "#{Dir.tmpdir}/import_file_spec" } - let(:config_hash) { Gitlab::ImportExport::Config.new.to_h.deep_stringify_keys } - let(:sensitive_words) { %w[pass secret token key encrypted html] } let(:safe_list) do { diff --git a/spec/helpers/clusters_helper_spec.rb b/spec/helpers/clusters_helper_spec.rb index 1ee638ddf04..ff8394b9475 100644 --- a/spec/helpers/clusters_helper_spec.rb +++ b/spec/helpers/clusters_helper_spec.rb @@ -37,25 +37,25 @@ describe ClustersHelper do context 'GCP provider' do let(:provider) { 'gcp' } - it { is_expected.to eq('Create new Cluster on GKE') } + it { is_expected.to eq('Create new cluster on GKE') } end context 'AWS provider' do let(:provider) { 'aws' } - it { is_expected.to eq('Create new Cluster on EKS') } + it { is_expected.to eq('Create new cluster on EKS') } end context 'other provider' do let(:provider) { 'other' } - it { is_expected.to eq('Create new Cluster') } + it { is_expected.to eq('Create new cluster') } end context 'no provider' do let(:provider) { nil } - it { is_expected.to eq('Create new Cluster') } + it { is_expected.to eq('Create new cluster') } end end diff --git a/spec/lib/gitlab/import_export/attribute_configuration_spec.rb b/spec/lib/gitlab/import_export/attribute_configuration_spec.rb index 41da1383f74..58da25bbedb 100644 --- a/spec/lib/gitlab/import_export/attribute_configuration_spec.rb +++ b/spec/lib/gitlab/import_export/attribute_configuration_spec.rb @@ -12,21 +12,11 @@ require 'spec_helper' describe 'Import/Export attribute configuration' do include ConfigurationHelper - let(:config_hash) { Gitlab::ImportExport::Config.new.to_h.deep_stringify_keys } - let(:relation_names) do - names = names_from_tree(config_hash.dig('tree', 'project')) - - # Remove duplicated or add missing models - # - project is not part of the tree, so it has to be added manually. - # - milestone, labels have both singular and plural versions in the tree, so remove the duplicates. - names.flatten.uniq - %w(milestones labels) + ['project'] - end - let(:safe_attributes_file) { 'spec/lib/gitlab/import_export/safe_model_attributes.yml' } let(:safe_model_attributes) { YAML.load_file(safe_attributes_file) } it 'has no new columns' do - relation_names.each do |relation_name| + relation_names_for(:project).each do |relation_name| relation_class = relation_class_for_name(relation_name) relation_attributes = relation_class.new.attributes.keys - relation_class.encrypted_attributes.keys.map(&:to_s) diff --git a/spec/lib/gitlab/import_export/model_configuration_spec.rb b/spec/lib/gitlab/import_export/model_configuration_spec.rb index d97e76f3cbd..cfbfe244988 100644 --- a/spec/lib/gitlab/import_export/model_configuration_spec.rb +++ b/spec/lib/gitlab/import_export/model_configuration_spec.rb @@ -8,19 +8,10 @@ require 'spec_helper' describe 'Import/Export model configuration' do include ConfigurationHelper - let(:config_hash) { Gitlab::ImportExport::Config.new.to_h.deep_stringify_keys } - let(:model_names) do - names = names_from_tree(config_hash.dig('tree', 'project')) - - # Remove duplicated or add missing models - # - project is not part of the tree, so it has to be added manually. - # - milestone, labels, merge_request have both singular and plural versions in the tree, so remove the duplicates. - # - User, Author... Models we do not care about for checking models - names.flatten.uniq - %w(milestones labels user author merge_request) + ['project'] - end let(:all_models_yml) { 'spec/lib/gitlab/import_export/all_models.yml' } let(:all_models_hash) { YAML.load_file(all_models_yml) } let(:current_models) { setup_models } + let(:model_names) { relation_names_for(:project) } it 'has no new models' do model_names.each do |model_name| diff --git a/spec/lib/gitlab/import_export/references_configuration_spec.rb b/spec/lib/gitlab/import_export/references_configuration_spec.rb new file mode 100644 index 00000000000..91cf9f964c0 --- /dev/null +++ b/spec/lib/gitlab/import_export/references_configuration_spec.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +require 'spec_helper' + +# Part of the test security suite for the Import/Export feature +# Checks whether there are new reference attributes ending with _id in models that are currently being exported as part of the +# project Import/Export feature. +# If there are new references (foreign keys), these will have to either be replaced with actual relation +# or to be blacklisted by using the import_export.yml configuration file. +# Likewise, new models added to import_export.yml, will need to be added with their correspondent relations +# to this spec. +describe 'Import/Export Project configuration' do + include ConfigurationHelper + + where(:relation_path, :relation_name) do + relation_paths_for(:project).map do |relation_names| + next if relation_names.last == :author + + [relation_names.join("."), relation_names.last] + end.compact + end + + with_them do + context "where relation #{params[:relation_path]}" do + it 'does not have prohibited keys' do + relation_class = relation_class_for_name(relation_name) + relation_attributes = relation_class.new.attributes.keys - relation_class.encrypted_attributes.keys.map(&:to_s) + current_attributes = parsed_attributes(relation_name, relation_attributes) + prohibited_keys = current_attributes.select do |attribute| + prohibited_key?(attribute) || !relation_class.attribute_method?(attribute) + end + expect(prohibited_keys).to be_empty, failure_message(relation_class.to_s, prohibited_keys) + end + end + end + + def failure_message(relation_class, prohibited_keys) + <<-MSG + It looks like #{relation_class}, which is exported using the project Import/Export, has references: #{prohibited_keys.join(',')} + + Please replace it with actual relation in IMPORT_EXPORT_CONFIG if you consider this can be exported. + Please blacklist the attribute(s) in IMPORT_EXPORT_CONFIG by adding it to its correspondent + model in the +excluded_attributes+ section. + + IMPORT_EXPORT_CONFIG: #{Gitlab::ImportExport.config_file} + MSG + end +end diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index bf8c079f027..79442c35797 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -33,7 +33,6 @@ Issue: Event: - id - target_type -- target_id - project_id - group_id - created_at @@ -60,7 +59,6 @@ Note: - attachment - line_code - commit_id -- noteable_id - system - st_diff - updated_by_id @@ -73,11 +71,8 @@ Note: - resolved_by_push - discussion_id - original_discussion_id -- review_id LabelLink: - id -- label_id -- target_id - target_type - created_at - updated_at @@ -130,13 +125,11 @@ Release: - released_at Evidence: - id -- release_id - summary - created_at - updated_at Releases::Link: - id -- release_id - url - name - created_at @@ -144,7 +137,6 @@ Releases::Link: ProjectMember: - id - access_level -- source_id - source_type - user_id - notification_level @@ -600,7 +592,6 @@ AwardEmoji: LabelPriority: - id - project_id -- label_id - priority - created_at - updated_at @@ -608,7 +599,6 @@ Timelog: - id - time_spent - merge_request_id -- issue_id - user_id - spent_at - created_at @@ -623,7 +613,6 @@ ProjectAutoDevops: - updated_at IssueAssignee: - user_id -- issue_id ProjectCustomAttribute: - id - created_at @@ -679,7 +668,6 @@ ProtectedEnvironment::DeployAccessLevel: ResourceLabelEvent: - id - action -- issue_id - merge_request_id - label_id - user_id @@ -691,11 +679,9 @@ ErrorTracking::ProjectErrorTrackingSetting: - organization_name SentryIssue: - id -- issue_id - sentry_issue_identifier Suggestion: - id -- note_id - relative_order - applied - commit_id @@ -750,21 +736,16 @@ ExternalPullRequest: DesignManagement::Design: - id - project_id -- issue_id - filename DesignManagement::Action: -- design_id - event -- version_id DesignManagement::Version: - id - created_at - sha -- issue_id - author_id ZoomMeeting: - id -- issue_id - project_id - issue_status - url diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 8a701a461c0..900e0feaccc 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -815,6 +815,27 @@ describe Ci::Build do it { is_expected.to contain_exactly(build, rspec_test, rubocop_test, staging) } end end + + describe '#all_dependencies' do + let!(:final_build) do + create(:ci_build, + pipeline: pipeline, name: 'deploy', + stage_idx: 3, stage: 'deploy' + ) + end + + subject { final_build.all_dependencies } + + it 'returns dependencies and cross_dependencies' do + dependencies = [1, 2, 3] + cross_dependencies = [3, 4] + + allow(final_build).to receive(:dependencies).and_return(dependencies) + allow(final_build).to receive(:cross_dependencies).and_return(cross_dependencies) + + is_expected.to match(a_collection_containing_exactly(1, 2, 3, 4)) + end + end end describe '#triggered_by?' do diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb index 1e1b679a32c..31aebac54e1 100644 --- a/spec/models/commit_status_spec.rb +++ b/spec/models/commit_status_spec.rb @@ -312,6 +312,72 @@ describe CommitStatus do end end + describe '.for_ref' do + subject { described_class.for_ref('bb').order(:id) } + + let(:statuses) do + [create_status(ref: 'aa'), + create_status(ref: 'bb'), + create_status(ref: 'cc')] + end + + it 'returns statuses with the specified ref' do + is_expected.to eq(statuses.values_at(1)) + end + end + + describe '.by_name' do + subject { described_class.by_name('bb').order(:id) } + + let(:statuses) do + [create_status(name: 'aa'), + create_status(name: 'bb'), + create_status(name: 'cc')] + end + + it 'returns statuses with the specified name' do + is_expected.to eq(statuses.values_at(1)) + end + end + + describe '.for_project_paths' do + subject do + described_class + .for_project_paths(paths) + .order(:id) + end + + context 'with a single path' do + let(:other_project) { create(:project, :repository) } + let(:paths) { other_project.full_path } + + let(:other_pipeline) do + create(:ci_pipeline, project: other_project, sha: other_project.commit.id) + end + + let(:statuses) do + [create_status(pipeline: pipeline), + create_status(pipeline: other_pipeline)] + end + + it 'returns statuses for other_project' do + is_expected.to eq(statuses.values_at(1)) + end + end + + context 'with array of paths' do + let(:paths) { [project.full_path] } + + let(:statuses) do + [create_status(pipeline: pipeline)] + end + + it 'returns statuses for project' do + is_expected.to eq(statuses.values_at(0)) + end + end + end + describe '.status' do context 'when there are multiple statuses present' do before do diff --git a/spec/support/import_export/configuration_helper.rb b/spec/support/import_export/configuration_helper.rb index 122df7f27f0..2e5a99bb8b2 100644 --- a/spec/support/import_export/configuration_helper.rb +++ b/spec/support/import_export/configuration_helper.rb @@ -10,21 +10,54 @@ module ConfigurationHelper end end + def all_relations(tree, tree_path = []) + tree.flat_map do |relation_name, relations| + relation_path = tree_path + [relation_name] + [relation_path] + all_relations(relations, relation_path) + end + end + + def config_hash(config = Gitlab::ImportExport.config_file) + Gitlab::ImportExport::Config.new(config: config).to_h + end + + def relation_paths_for(key, config: Gitlab::ImportExport.config_file) + # - project is not part of the tree, so it has to be added manually. + all_relations({ project: config_hash(config).dig(:tree, key) }) + end + + def relation_names_for(key, config: Gitlab::ImportExport.config_file) + names = names_from_tree(config_hash(config).dig(:tree, key)) + # Remove duplicated or add missing models + # - project is not part of the tree, so it has to be added manually. + # - milestone, labels, merge_request have both singular and plural versions in the tree, so remove the duplicates. + # - User, Author... Models we do not care about for checking models + names.flatten.uniq - %w(milestones labels user author merge_request design) + [key.to_s] + end + def relation_class_for_name(relation_name) relation_name = Gitlab::ImportExport::RelationFactory.overrides[relation_name.to_sym] || relation_name Gitlab::ImportExport::RelationFactory.relation_class(relation_name) end - def parsed_attributes(relation_name, attributes) - excluded_attributes = config_hash['excluded_attributes'][relation_name] - included_attributes = config_hash['included_attributes'][relation_name] - + def parsed_attributes(relation_name, attributes, config: Gitlab::ImportExport.config_file) + import_export_config = config_hash(config) + excluded_attributes = import_export_config[:excluded_attributes][relation_name.to_sym] + included_attributes = import_export_config[:included_attributes][relation_name.to_sym] attributes = attributes - JSON[excluded_attributes.to_json] if excluded_attributes attributes = attributes & JSON[included_attributes.to_json] if included_attributes attributes end + def prohibited_key?(key) + key =~ Gitlab::ImportExport::AttributeCleaner::PROHIBITED_REFERENCES && !permitted_key?(key) + end + + def permitted_key?(key) + Gitlab::ImportExport::AttributeCleaner::ALLOWED_REFERENCES.include?(key) + end + def associations_for(safe_model) safe_model.reflect_on_all_associations.map { |assoc| assoc.name.to_s } end diff --git a/yarn.lock b/yarn.lock index aa45c5dc6b2..bb62ffa1bb3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -732,15 +732,15 @@ dependencies: vue-eslint-parser "^6.0.4" -"@gitlab/svgs@^1.85.0": - version "1.85.0" - resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.85.0.tgz#c80247ec4764824385df2837136a0d4a84f881dc" - integrity sha512-yzvKut0MPJEbSx/LExopCLpF5KEZsckF+d/Blbji1VqODVanH85oIVuJNmdECUlc7qxye9Or3evpFjW9Pkshmg== +"@gitlab/svgs@^1.88.0": + version "1.88.0" + resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.88.0.tgz#0a9b72e9591264fcac592ebf9944665c70f48de2" + integrity sha512-ZgepCvZoB/lFdgttHtu8+9YlRZlVc9MnHDbbqcQCFBvrfOjY1wq12ikxnNbwKj8QNA47TRJvSS0TkHgMWYnbsA== -"@gitlab/ui@8.2.0": - version "8.2.0" - resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-8.2.0.tgz#82cf512407f8a774878969c72c4227d08ce49aa6" - integrity sha512-ZzxA3XwmwZpol6QJjqBf3Oblb1wSFbDJ4QENvPiE9lAUHvhbe8wfKBK++RtgOtd6aXtLvoY1o1Du9qill07Jvg== +"@gitlab/ui@8.8.0": + version "8.8.0" + resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-8.8.0.tgz#c22b4dece89d224c525b3510970f3c61321a6765" + integrity sha512-fjAGSgfau28iq+Uhivc5OPwu3ZLUL25gFuW1rKeQFgnkVEaQ9IRvdM8RD9+kgXWUsccsrafQkz/nOUmp85o8yQ== dependencies: "@babel/standalone" "^7.0.0" "@gitlab/vue-toasted" "^1.3.0" @@ -755,10 +755,10 @@ vue "^2.6.10" vue-loader "^15.4.2" -"@gitlab/visual-review-tools@1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@gitlab/visual-review-tools/-/visual-review-tools-1.2.0.tgz#8d6757917193c1023012bb4a316dc1a97309a27a" - integrity sha512-GaV/lYLmOF0hWtv8K8MLWGaCZ7PL1LF4D0/gargXYf9HO0Cw4wtz4oWyaLS15wFposJIYdPIHSNfrLVk4Dk9sQ== +"@gitlab/visual-review-tools@1.5.1": + version "1.5.1" + resolved "https://registry.yarnpkg.com/@gitlab/visual-review-tools/-/visual-review-tools-1.5.1.tgz#2552927cd7a376f1f06ef3293a69fe2ffcdddb52" + integrity sha512-8d6xgK4TsLA5gucd78jzaMyginAMJ8cbu/6ghUGws84zzAEsyJsMTstyt/fA5l4toQXVxtOh90BvDzwxSjZ6hQ== "@gitlab/vue-toasted@^1.3.0": version "1.3.0" |