From 55bd6d19a7f18f744ba48a9e8f33b5a3ee209a43 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Fri, 10 Jun 2022 03:08:14 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .rubocop_todo/fips/md5.yml | 25 ++ .rubocop_todo/fips/open_ssl.yml | 222 ++++++++++++++++++ .rubocop_todo/fips/sha1.yml | 111 +++++++++ Gemfile | 4 +- Gemfile.lock | 24 +- .../javascripts/editor/source_editor.js | 5 +- .../javascripts/groups/components/app.vue | 38 ++- .../groups/components/empty_state.vue | 91 +++++++ app/assets/javascripts/groups/index.js | 25 ++ app/helpers/groups_helper.rb | 14 ++ app/models/merge_request.rb | 4 + .../groups/_subgroups_and_projects.html.haml | 5 +- ...23501_add_vulnerability_related_columns.rb | 30 +++ db/schema_migrations/20220601223501 | 1 + db/structure.sql | 4 + .../secret_detection/index.md | 2 +- doc/user/profile/index.md | 9 +- locale/gitlab.pot | 18 ++ spec/features/groups/show_spec.rb | 52 ++++ spec/frontend/editor/source_editor_spec.js | 29 ++- spec/frontend/groups/components/app_spec.js | 68 +++++- .../groups/components/empty_state_spec.js | 78 ++++++ spec/helpers/groups_helper_spec.rb | 26 ++ spec/models/merge_request_spec.rb | 18 ++ 24 files changed, 865 insertions(+), 38 deletions(-) create mode 100644 .rubocop_todo/fips/md5.yml create mode 100644 .rubocop_todo/fips/open_ssl.yml create mode 100644 .rubocop_todo/fips/sha1.yml create mode 100644 app/assets/javascripts/groups/components/empty_state.vue create mode 100644 db/migrate/20220601223501_add_vulnerability_related_columns.rb create mode 100644 db/schema_migrations/20220601223501 create mode 100644 spec/frontend/groups/components/empty_state_spec.js diff --git a/.rubocop_todo/fips/md5.yml b/.rubocop_todo/fips/md5.yml new file mode 100644 index 00000000000..ef9e8fdde62 --- /dev/null +++ b/.rubocop_todo/fips/md5.yml @@ -0,0 +1,25 @@ +--- +Fips/MD5: + Exclude: + - 'app/experiments/application_experiment.rb' + - 'app/models/concerns/checksummable.rb' + - 'app/services/gravatar_service.rb' + - 'app/services/packages/debian/generate_distribution_service.rb' + - 'app/services/packages/go/create_package_service.rb' + - 'app/services/packages/maven/metadata/append_package_file_service.rb' + - 'app/services/packages/rubygems/create_gemspec_service.rb' + - 'config/application.rb' + - 'config/initializers/wikicloth_redos_patch.rb' + - 'ee/app/models/license.rb' + - 'ee/spec/lib/ee/gitlab/usage_data_spec.rb' + - 'lib/tasks/migrate/setup_postgresql.rake' + - 'qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb' + - 'spec/controllers/invites_controller_spec.rb' + - 'spec/lib/gitlab/ci/trace/archive_spec.rb' + - 'spec/lib/gitlab/ci/trace/remote_checksum_spec.rb' + - 'spec/models/concerns/checksummable_spec.rb' + - 'spec/services/gravatar_service_spec.rb' + - 'spec/support/matchers/match_file.rb' + - 'spec/support/shared_examples/services/packages/debian/generate_distribution_shared_examples.rb' + - 'spec/tooling/rspec_flaky/example_spec.rb' + - 'tooling/rspec_flaky/example.rb' diff --git a/.rubocop_todo/fips/open_ssl.yml b/.rubocop_todo/fips/open_ssl.yml new file mode 100644 index 00000000000..03a551112ab --- /dev/null +++ b/.rubocop_todo/fips/open_ssl.yml @@ -0,0 +1,222 @@ +--- +# Cop supports --auto-correct. +Fips/OpenSSL: + Exclude: + - 'app/controllers/application_controller.rb' + - 'app/controllers/concerns/authenticates_with_two_factor.rb' + - 'app/controllers/projects/merge_requests/diffs_controller.rb' + - 'app/controllers/projects/merge_requests_controller.rb' + - 'app/helpers/application_helper.rb' + - 'app/models/ci/artifact_blob.rb' + - 'app/models/concerns/analytics/cycle_analytics/stage.rb' + - 'app/models/concerns/checksummable.rb' + - 'app/models/concerns/token_authenticatable_strategies/encryption_helper.rb' + - 'app/models/diff_discussion.rb' + - 'app/models/discussion.rb' + - 'app/models/legacy_diff_note.rb' + - 'app/models/namespace.rb' + - 'app/models/note.rb' + - 'app/models/performance_monitoring/prometheus_panel.rb' + - 'app/models/protected_branch.rb' + - 'app/models/release_highlight.rb' + - 'app/models/repository.rb' + - 'app/models/resource_event.rb' + - 'app/models/snippet.rb' + - 'app/models/storage/hashed.rb' + - 'app/models/token_with_iv.rb' + - 'app/presenters/packages/composer/packages_presenter.rb' + - 'app/services/ci/build_report_result_service.rb' + - 'app/services/metrics/dashboard/transient_embed_service.rb' + - 'app/services/packages/debian/generate_distribution_service.rb' + - 'app/services/packages/go/create_package_service.rb' + - 'app/services/packages/maven/metadata/append_package_file_service.rb' + - 'app/services/packages/rubygems/create_gemspec_service.rb' + - 'app/services/pages/migrate_legacy_storage_to_deployment_service.rb' + - 'app/services/projects/lfs_pointers/lfs_download_service.rb' + - 'app/uploaders/ci/secure_file_uploader.rb' + - 'config/initializers/doorkeeper_openid_connect.rb' + - 'config/initializers/session_store.rb' + - 'config/settings.rb' + - 'db/post_migrate/20210731132939_backfill_stage_event_hash.rb' + - 'ee/app/models/storage_shard.rb' + - 'ee/app/services/elastic/bookkeeping_shard_service.rb' + - 'ee/app/services/security/track_scan_service.rb' + - 'ee/app/services/vulnerabilities/create_service_base.rb' + - 'ee/app/services/vulnerabilities/manually_create_service.rb' + - 'ee/app/services/vulnerabilities/starboard_vulnerability_create_service.rb' + - 'ee/lib/ee/gitlab/background_migration/populate_latest_pipeline_ids.rb' + - 'ee/lib/ee/gitlab/background_migration/populate_resolved_on_default_branch_column.rb' + - 'ee/lib/ee/gitlab/background_migration/recalculate_vulnerability_finding_signatures_for_findings.rb' + - 'ee/lib/gitlab/analytics/cycle_analytics/stage_events/label_based_stage_event.rb' + - 'ee/lib/gitlab/ci/reports/dependency_list/dependency.rb' + - 'ee/lib/gitlab/ci/reports/security/remediation.rb' + - 'ee/lib/gitlab/geo/replication/blob_downloader.rb' + - 'ee/spec/factories/vulnerabilities/feedback.rb' + - 'ee/spec/factories/vulnerabilities/finding_signatures.rb' + - 'ee/spec/factories/vulnerabilities/remediations.rb' + - 'ee/spec/finders/security/pipeline_vulnerabilities_finder_spec.rb' + - 'ee/spec/lib/ee/gitlab/alert_management/payload/generic_spec.rb' + - 'ee/spec/lib/ee/gitlab/background_migration/populate_uuids_for_security_findings_spec.rb' + - 'ee/spec/lib/ee/gitlab/background_migration/recalculate_vulnerability_finding_signatures_for_findings_spec.rb' + - 'ee/spec/lib/ee/gitlab/background_migration/update_vulnerability_occurrences_location_spec.rb' + - 'ee/spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_label_added_spec.rb' + - 'ee/spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_label_removed_spec.rb' + - 'ee/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_label_added_spec.rb' + - 'ee/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_label_removed_spec.rb' + - 'ee/spec/lib/gitlab/ci/reports/security/locations/cluster_image_scanning_spec.rb' + - 'ee/spec/lib/gitlab/ci/reports/security/locations/container_scanning_spec.rb' + - 'ee/spec/lib/gitlab/ci/reports/security/locations/dast_spec.rb' + - 'ee/spec/lib/gitlab/ci/reports/security/locations/dependency_scanning_spec.rb' + - 'ee/spec/migrations/update_vulnerability_occurrences_location_spec.rb' + - 'ee/spec/models/merge_train_spec.rb' + - 'ee/spec/models/resource_weight_event_spec.rb' + - 'ee/spec/models/vulnerabilities/finding_signature_spec.rb' + - 'ee/spec/models/vulnerabilities/finding_spec.rb' + - 'ee/spec/services/alert_management/process_prometheus_alert_service_spec.rb' + - 'ee/spec/services/merge_trains/check_status_service_spec.rb' + - 'ee/spec/services/projects/alerting/notify_service_spec.rb' + - 'ee/spec/services/security/ingestion/tasks/ingest_identifiers_spec.rb' + - 'ee/spec/services/security/ingestion/tasks/ingest_remediations_spec.rb' + - 'ee/spec/services/security/override_uuids_service_spec.rb' + - 'ee/spec/services/security/track_scan_service_spec.rb' + - 'ee/spec/services/vulnerabilities/manually_create_service_spec.rb' + - 'ee/spec/support/matchers/locked_schema.rb' + - 'lib/api/files.rb' + - 'lib/api/maven_packages.rb' + - 'lib/atlassian/jira_connect/serializers/branch_entity.rb' + - 'lib/container_registry/client.rb' + - 'lib/extracts_path.rb' + - 'lib/gitlab/alert_management/fingerprint.rb' + - 'lib/gitlab/analytics/cycle_analytics/stage_events/stage_event.rb' + - 'lib/gitlab/background_migration/backfill_note_discussion_id.rb' + - 'lib/gitlab/background_migration/backfill_project_repositories.rb' + - 'lib/gitlab/ci/pipeline/seed/build/cache.rb' + - 'lib/gitlab/ci/reports/security/finding.rb' + - 'lib/gitlab/ci/reports/security/finding_signature.rb' + - 'lib/gitlab/ci/reports/security/identifier.rb' + - 'lib/gitlab/ci/reports/security/locations/base.rb' + - 'lib/gitlab/ci/reports/test_case.rb' + - 'lib/gitlab/color.rb' + - 'lib/gitlab/composer/version_index.rb' + - 'lib/gitlab/crypto_helper.rb' + - 'lib/gitlab/database/migration_helpers.rb' + - 'lib/gitlab/database/migration_helpers/v2.rb' + - 'lib/gitlab/database/partitioning_migration_helpers/foreign_key_helpers.rb' + - 'lib/gitlab/database/schema_helpers.rb' + - 'lib/gitlab/database/schema_migrations/migrations.rb' + - 'lib/gitlab/database/unidirectional_copy_trigger.rb' + - 'lib/gitlab/diff/file.rb' + - 'lib/gitlab/diff/formatters/base_formatter.rb' + - 'lib/gitlab/diff/position.rb' + - 'lib/gitlab/experimentation/controller_concern.rb' + - 'lib/gitlab/git.rb' + - 'lib/gitlab/git/branch.rb' + - 'lib/gitlab/git/lfs_pointer_file.rb' + - 'lib/gitlab/git/tag.rb' + - 'lib/gitlab/hashed_path.rb' + - 'lib/gitlab/insecure_key_fingerprint.rb' + - 'lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job.rb' + - 'lib/gitlab/slug/environment.rb' + - 'lib/gitlab/verify/job_artifacts.rb' + - 'lib/json_web_token/rsa_token.rb' + - 'lib/tasks/gitlab/assets.rake' + - 'lib/tasks/tanuki_emoji.rake' + - 'qa/qa/service/praefect_manager.rb' + - 'qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb' + - 'qa/qa/specs/features/ee/browser_ui/1_manage/group/group_saml_non_enforced_sso_spec.rb' + - 'scripts/security-harness' + - 'spec/components/diffs/stats_component_spec.rb' + - 'spec/controllers/projects/blob_controller_spec.rb' + - 'spec/factories/ci/job_artifacts.rb' + - 'spec/factories/ci/reports/security/finding_keys.rb' + - 'spec/factories/ci/unit_test.rb' + - 'spec/factories/commit_signature/gpg_signature.rb' + - 'spec/factories/commit_signature/ssh_signature.rb' + - 'spec/factories/commit_signature/x509_commit_signature.rb' + - 'spec/factories/design_management/designs.rb' + - 'spec/factories/diff_position.rb' + - 'spec/factories/gitaly/commit.rb' + - 'spec/factories/merge_request_context_commit.rb' + - 'spec/factories/merge_request_context_commit_diff_file.rb' + - 'spec/factories/merge_request_diff_commits.rb' + - 'spec/factories/merge_request_diffs.rb' + - 'spec/factories/pages_deployments.rb' + - 'spec/factories/sequences.rb' + - 'spec/factories/token_with_ivs.rb' + - 'spec/features/file_uploads/git_lfs_spec.rb' + - 'spec/features/merge_request/user_sees_diff_spec.rb' + - 'spec/features/merge_request/user_suggests_changes_on_diff_spec.rb' + - 'spec/finders/merge_requests/oldest_per_commit_finder_spec.rb' + - 'spec/lib/gitlab/alert_management/fingerprint_spec.rb' + - 'spec/lib/gitlab/alert_management/payload/base_spec.rb' + - 'spec/lib/gitlab/alert_management/payload/generic_spec.rb' + - 'spec/lib/gitlab/alert_management/payload/prometheus_spec.rb' + - 'spec/lib/gitlab/background_migration/backfill_note_discussion_id_spec.rb' + - 'spec/lib/gitlab/background_migration/populate_vulnerability_reads_spec.rb' + - 'spec/lib/gitlab/ci/reports/security/finding_signature_spec.rb' + - 'spec/lib/gitlab/ci/reports/security/locations/sast_spec.rb' + - 'spec/lib/gitlab/ci/reports/security/locations/secret_detection_spec.rb' + - 'spec/lib/gitlab/ci/reports/test_case_spec.rb' + - 'spec/lib/gitlab/crypto_helper_spec.rb' + - 'spec/lib/gitlab/database/migration_helpers_spec.rb' + - 'spec/lib/gitlab/database/schema_migrations/migrations_spec.rb' + - 'spec/lib/gitlab/diff/file_spec.rb' + - 'spec/lib/gitlab/diff/position_spec.rb' + - 'spec/lib/gitlab/diff/position_tracer/image_strategy_spec.rb' + - 'spec/lib/gitlab/diff/position_tracer/line_strategy_spec.rb' + - 'spec/lib/gitlab/experimentation/controller_concern_spec.rb' + - 'spec/lib/gitlab/git/branch_spec.rb' + - 'spec/lib/gitlab/git/tag_spec.rb' + - 'spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job_spec.rb' + - 'spec/lib/gitlab/slug/environment_spec.rb' + - 'spec/migrations/20220107064845_populate_vulnerability_reads_spec.rb' + - 'spec/migrations/20220524074947_finalize_backfill_null_note_discussion_ids_spec.rb' + - 'spec/migrations/delete_security_findings_without_uuid_spec.rb' + - 'spec/migrations/schedule_recalculate_vulnerability_finding_signatures_for_findings_spec.rb' + - 'spec/models/ci/artifact_blob_spec.rb' + - 'spec/models/ci/job_artifact_spec.rb' + - 'spec/models/ci/pipeline_spec.rb' + - 'spec/models/ci/secure_file_spec.rb' + - 'spec/models/ci/unit_test_spec.rb' + - 'spec/models/concerns/checksummable_spec.rb' + - 'spec/models/concerns/token_authenticatable_strategies/encryption_helper_spec.rb' + - 'spec/models/design_management/version_spec.rb' + - 'spec/models/diff_discussion_spec.rb' + - 'spec/models/discussion_spec.rb' + - 'spec/models/lfs_object_spec.rb' + - 'spec/models/merge_request_diff_spec.rb' + - 'spec/models/merge_request_spec.rb' + - 'spec/models/note_spec.rb' + - 'spec/models/pages_deployment_spec.rb' + - 'spec/models/performance_monitoring/prometheus_panel_spec.rb' + - 'spec/models/project_spec.rb' + - 'spec/models/release_highlight_spec.rb' + - 'spec/models/repository_spec.rb' + - 'spec/models/token_with_iv_spec.rb' + - 'spec/models/upload_spec.rb' + - 'spec/requests/api/ci/runner/jobs_artifacts_spec.rb' + - 'spec/requests/api/ci/secure_files_spec.rb' + - 'spec/requests/openid_connect_spec.rb' + - 'spec/services/dependency_proxy/find_cached_manifest_service_spec.rb' + - 'spec/services/dependency_proxy/head_manifest_service_spec.rb' + - 'spec/services/dependency_proxy/request_token_service_spec.rb' + - 'spec/services/import_export_clean_up_service_spec.rb' + - 'spec/services/pages/migrate_legacy_storage_to_deployment_service_spec.rb' + - 'spec/services/projects/after_rename_service_spec.rb' + - 'spec/services/projects/create_service_spec.rb' + - 'spec/services/projects/lfs_pointers/lfs_download_service_spec.rb' + - 'spec/support/helpers/workhorse_helpers.rb' + - 'spec/support/migrations_helpers/vulnerabilities_findings_helper.rb' + - 'spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb' + - 'spec/support/shared_examples/lib/gitlab/cycle_analytics/event_shared_examples.rb' + - 'spec/support/shared_examples/lib/gitlab/position_formatters_shared_examples.rb' + - 'spec/support/shared_examples/services/alert_management/alert_processing/alert_firing_shared_examples.rb' + - 'spec/support/shared_examples/services/alert_management/alert_processing/alert_recovery_shared_examples.rb' + - 'spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb' + - 'spec/support/shared_examples/services/packages/debian/generate_distribution_shared_examples.rb' + - 'spec/support/shared_examples/uploaders/object_storage_shared_examples.rb' + - 'spec/support/trace/trace_helpers.rb' + - 'spec/uploaders/ci/secure_file_uploader_spec.rb' + - 'spec/uploaders/job_artifact_uploader_spec.rb' + - 'spec/validators/sha_validator_spec.rb' + - 'spec/workers/update_head_pipeline_for_merge_request_worker_spec.rb' diff --git a/.rubocop_todo/fips/sha1.yml b/.rubocop_todo/fips/sha1.yml new file mode 100644 index 00000000000..934805c86d4 --- /dev/null +++ b/.rubocop_todo/fips/sha1.yml @@ -0,0 +1,111 @@ +--- +Fips/SHA1: + Exclude: + - 'app/controllers/application_controller.rb' + - 'app/helpers/application_helper.rb' + - 'app/models/ci/artifact_blob.rb' + - 'app/models/diff_discussion.rb' + - 'app/models/discussion.rb' + - 'app/models/legacy_diff_note.rb' + - 'app/models/note.rb' + - 'app/models/protected_branch.rb' + - 'app/models/repository.rb' + - 'app/models/resource_event.rb' + - 'app/services/packages/go/create_package_service.rb' + - 'app/services/packages/maven/metadata/append_package_file_service.rb' + - 'app/services/packages/rubygems/create_gemspec_service.rb' + - 'ee/app/models/storage_shard.rb' + - 'ee/app/services/vulnerabilities/create_service_base.rb' + - 'ee/app/services/vulnerabilities/manually_create_service.rb' + - 'ee/app/services/vulnerabilities/starboard_vulnerability_create_service.rb' + - 'ee/lib/ee/gitlab/background_migration/recalculate_vulnerability_finding_signatures_for_findings.rb' + - 'ee/spec/factories/vulnerabilities/feedback.rb' + - 'ee/spec/factories/vulnerabilities/finding_signatures.rb' + - 'ee/spec/finders/security/pipeline_vulnerabilities_finder_spec.rb' + - 'ee/spec/lib/ee/gitlab/alert_management/payload/generic_spec.rb' + - 'ee/spec/lib/ee/gitlab/background_migration/populate_uuids_for_security_findings_spec.rb' + - 'ee/spec/lib/ee/gitlab/background_migration/recalculate_vulnerability_finding_signatures_for_findings_spec.rb' + - 'ee/spec/lib/ee/gitlab/background_migration/update_vulnerability_occurrences_location_spec.rb' + - 'ee/spec/lib/gitlab/ci/reports/security/locations/cluster_image_scanning_spec.rb' + - 'ee/spec/lib/gitlab/ci/reports/security/locations/container_scanning_spec.rb' + - 'ee/spec/lib/gitlab/ci/reports/security/locations/dast_spec.rb' + - 'ee/spec/lib/gitlab/ci/reports/security/locations/dependency_scanning_spec.rb' + - 'ee/spec/migrations/update_vulnerability_occurrences_location_spec.rb' + - 'ee/spec/models/merge_train_spec.rb' + - 'ee/spec/models/resource_weight_event_spec.rb' + - 'ee/spec/models/vulnerabilities/finding_signature_spec.rb' + - 'ee/spec/models/vulnerabilities/finding_spec.rb' + - 'ee/spec/services/alert_management/process_prometheus_alert_service_spec.rb' + - 'ee/spec/services/merge_trains/check_status_service_spec.rb' + - 'ee/spec/services/projects/alerting/notify_service_spec.rb' + - 'ee/spec/services/security/ingestion/tasks/ingest_identifiers_spec.rb' + - 'ee/spec/services/security/override_uuids_service_spec.rb' + - 'ee/spec/services/vulnerabilities/manually_create_service_spec.rb' + - 'lib/extracts_path.rb' + - 'lib/gitlab/alert_management/fingerprint.rb' + - 'lib/gitlab/background_migration/backfill_note_discussion_id.rb' + - 'lib/gitlab/ci/pipeline/seed/build/cache.rb' + - 'lib/gitlab/ci/reports/security/finding.rb' + - 'lib/gitlab/ci/reports/security/finding_signature.rb' + - 'lib/gitlab/ci/reports/security/identifier.rb' + - 'lib/gitlab/ci/reports/security/locations/base.rb' + - 'lib/gitlab/diff/file.rb' + - 'lib/gitlab/diff/formatters/base_formatter.rb' + - 'lib/gitlab/diff/position.rb' + - 'lib/gitlab/git.rb' + - 'lib/gitlab/git/branch.rb' + - 'lib/gitlab/git/tag.rb' + - 'qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb' + - 'qa/qa/specs/features/ee/browser_ui/1_manage/group/group_saml_non_enforced_sso_spec.rb' + - 'spec/components/diffs/stats_component_spec.rb' + - 'spec/controllers/projects/blob_controller_spec.rb' + - 'spec/factories/ci/reports/security/finding_keys.rb' + - 'spec/factories/commit_signature/gpg_signature.rb' + - 'spec/factories/commit_signature/ssh_signature.rb' + - 'spec/factories/commit_signature/x509_commit_signature.rb' + - 'spec/factories/design_management/designs.rb' + - 'spec/factories/diff_position.rb' + - 'spec/factories/gitaly/commit.rb' + - 'spec/factories/merge_request_context_commit.rb' + - 'spec/factories/merge_request_context_commit_diff_file.rb' + - 'spec/factories/merge_request_diff_commits.rb' + - 'spec/factories/merge_request_diffs.rb' + - 'spec/factories/sequences.rb' + - 'spec/features/merge_request/user_sees_diff_spec.rb' + - 'spec/features/merge_request/user_suggests_changes_on_diff_spec.rb' + - 'spec/finders/merge_requests/oldest_per_commit_finder_spec.rb' + - 'spec/lib/gitlab/alert_management/fingerprint_spec.rb' + - 'spec/lib/gitlab/alert_management/payload/base_spec.rb' + - 'spec/lib/gitlab/alert_management/payload/generic_spec.rb' + - 'spec/lib/gitlab/alert_management/payload/prometheus_spec.rb' + - 'spec/lib/gitlab/background_migration/backfill_note_discussion_id_spec.rb' + - 'spec/lib/gitlab/background_migration/populate_vulnerability_reads_spec.rb' + - 'spec/lib/gitlab/ci/reports/security/finding_signature_spec.rb' + - 'spec/lib/gitlab/ci/reports/security/locations/sast_spec.rb' + - 'spec/lib/gitlab/ci/reports/security/locations/secret_detection_spec.rb' + - 'spec/lib/gitlab/diff/file_spec.rb' + - 'spec/lib/gitlab/diff/position_spec.rb' + - 'spec/lib/gitlab/diff/position_tracer/image_strategy_spec.rb' + - 'spec/lib/gitlab/diff/position_tracer/line_strategy_spec.rb' + - 'spec/lib/gitlab/git/branch_spec.rb' + - 'spec/lib/gitlab/git/tag_spec.rb' + - 'spec/migrations/20220107064845_populate_vulnerability_reads_spec.rb' + - 'spec/migrations/20220524074947_finalize_backfill_null_note_discussion_ids_spec.rb' + - 'spec/migrations/delete_security_findings_without_uuid_spec.rb' + - 'spec/migrations/schedule_recalculate_vulnerability_finding_signatures_for_findings_spec.rb' + - 'spec/models/ci/artifact_blob_spec.rb' + - 'spec/models/ci/job_artifact_spec.rb' + - 'spec/models/ci/pipeline_spec.rb' + - 'spec/models/design_management/version_spec.rb' + - 'spec/models/diff_discussion_spec.rb' + - 'spec/models/discussion_spec.rb' + - 'spec/models/merge_request_diff_spec.rb' + - 'spec/models/merge_request_spec.rb' + - 'spec/models/note_spec.rb' + - 'spec/models/repository_spec.rb' + - 'spec/support/migrations_helpers/vulnerabilities_findings_helper.rb' + - 'spec/support/shared_examples/lib/gitlab/position_formatters_shared_examples.rb' + - 'spec/support/shared_examples/services/alert_management/alert_processing/alert_firing_shared_examples.rb' + - 'spec/support/shared_examples/services/alert_management/alert_processing/alert_recovery_shared_examples.rb' + - 'spec/validators/sha_validator_spec.rb' + - 'spec/workers/update_head_pipeline_for_merge_request_worker_spec.rb' diff --git a/Gemfile b/Gemfile index d472cc83ec1..5915e0384d1 100644 --- a/Gemfile +++ b/Gemfile @@ -381,7 +381,7 @@ group :development, :test do gem 'spring', '~> 2.1.0' gem 'spring-commands-rspec', '~> 1.0.4' - gem 'gitlab-styles', '~> 7.0.0', require: false + gem 'gitlab-styles', '~> 7.1.0', require: false gem 'haml_lint', '~> 0.36.0', require: false gem 'bundler-audit', '~> 0.7.0.1', require: false @@ -407,7 +407,7 @@ group :development, :test do end group :development, :test, :danger do - gem 'gitlab-dangerfiles', '~> 3.0', require: false + gem 'gitlab-dangerfiles', '~> 3.1.0', require: false end group :development, :test, :coverage do diff --git a/Gemfile.lock b/Gemfile.lock index 53e8c321d22..f5323c0744e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -224,7 +224,7 @@ GEM css_parser (1.11.0) addressable daemons (1.3.1) - danger (8.5.0) + danger (8.6.1) claide (~> 1.0) claide-plugins (>= 0.9.2) colored2 (~> 3.1) @@ -474,7 +474,7 @@ GEM terminal-table (~> 1.5, >= 1.5.1) gitlab-chronic (0.10.5) numerizer (~> 0.2) - gitlab-dangerfiles (3.0.0) + gitlab-dangerfiles (3.1.0) danger (>= 8.4.5) danger-gitlab (>= 8.0.0) rake @@ -513,7 +513,7 @@ GEM openid_connect (~> 1.2) gitlab-sidekiq-fetcher (0.8.0) sidekiq (~> 6.1) - gitlab-styles (7.0.0) + gitlab-styles (7.1.0) rubocop (~> 0.91, >= 0.91.1) rubocop-gitlab-security (~> 0.1.1) rubocop-graphql (~> 0.10) @@ -939,7 +939,7 @@ GEM randexp (~> 0.1.7) rspec (>= 2.14) term-ansicolor (~> 1.0) - parallel (1.20.1) + parallel (1.22.1) parser (3.1.2.0) ast (~> 2.4.1) parslet (1.8.2) @@ -1038,7 +1038,7 @@ GEM method_source rake (>= 0.13) thor (~> 1.0) - rainbow (3.0.0) + rainbow (3.1.1) rake (13.0.6) randexp (0.1.7) rb-fsevent (0.10.4) @@ -1067,7 +1067,7 @@ GEM redis-store (>= 1.2, < 2) redis-store (1.9.0) redis (>= 4, < 5) - regexp_parser (2.2.1) + regexp_parser (2.5.0) regexp_property_values (1.0.0) representable (3.0.4) declarative (< 0.1.0) @@ -1144,11 +1144,11 @@ GEM rubocop-ast (>= 0.6.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 1.4.0, < 2.0) - rubocop-ast (1.4.1) - parser (>= 2.7.1.5) + rubocop-ast (1.18.0) + parser (>= 3.1.1.0) rubocop-gitlab-security (0.1.1) rubocop (>= 0.51) - rubocop-graphql (0.13.0) + rubocop-graphql (0.14.3) rubocop (>= 0.87, < 2) rubocop-performance (1.9.2) rubocop (>= 0.90.0, < 2.0) @@ -1378,7 +1378,7 @@ GEM unf (0.1.4) unf_ext unf_ext (0.0.8) - unicode-display_width (1.7.0) + unicode-display_width (1.8.0) unicode_utils (1.4.0) uniform_notifier (1.13.0) unleash (3.2.2) @@ -1532,7 +1532,7 @@ DEPENDENCIES gitaly (~> 15.0.0.pre.rc3) github-markup (~> 1.7.0) gitlab-chronic (~> 0.10.5) - gitlab-dangerfiles (~> 3.0) + gitlab-dangerfiles (~> 3.1.0) gitlab-experiment (~> 0.7.1) gitlab-fog-azure-rm (~> 1.3.0) gitlab-labkit (~> 0.22.0) @@ -1543,7 +1543,7 @@ DEPENDENCIES gitlab-net-dns (~> 0.9.1) gitlab-omniauth-openid-connect (~> 0.9.0) gitlab-sidekiq-fetcher (= 0.8.0) - gitlab-styles (~> 7.0.0) + gitlab-styles (~> 7.1.0) gitlab_chronic_duration (~> 0.10.6.2) gitlab_omniauth-ldap (~> 2.1.1) gon (~> 6.4.0) diff --git a/app/assets/javascripts/editor/source_editor.js b/app/assets/javascripts/editor/source_editor.js index fa749112ab5..d585dc009e6 100644 --- a/app/assets/javascripts/editor/source_editor.js +++ b/app/assets/javascripts/editor/source_editor.js @@ -75,6 +75,7 @@ export default class SourceEditor { blobGlobalId, instance, isDiff, + language, } = {}) { if (!instance) { return null; @@ -82,7 +83,7 @@ export default class SourceEditor { const uriFilePath = joinPaths(URI_PREFIX, blobGlobalId, blobPath); const uri = Uri.file(uriFilePath); const existingModel = monacoEditor.getModel(uri); - const model = existingModel || monacoEditor.createModel(blobContent, undefined, uri); + const model = existingModel || monacoEditor.createModel(blobContent, language, uri); if (!isDiff) { instance.setModel(model); return model; @@ -132,6 +133,7 @@ export default class SourceEditor { }); let model; + const language = instanceOptions.language || getBlobLanguage(blobPath); if (instanceOptions.model !== null) { model = SourceEditor.createEditorModel({ blobGlobalId, @@ -140,6 +142,7 @@ export default class SourceEditor { blobContent, instance, isDiff, + language, }); } diff --git a/app/assets/javascripts/groups/components/app.vue b/app/assets/javascripts/groups/components/app.vue index 871cbaf0d1a..cd5521c599e 100644 --- a/app/assets/javascripts/groups/components/app.vue +++ b/app/assets/javascripts/groups/components/app.vue @@ -1,19 +1,26 @@ + + diff --git a/app/assets/javascripts/groups/index.js b/app/assets/javascripts/groups/index.js index c34810954a3..dfcee80aec7 100644 --- a/app/assets/javascripts/groups/index.js +++ b/app/assets/javascripts/groups/index.js @@ -44,6 +44,31 @@ export default (containerId = 'js-groups-tree', endpoint, action = '') => { components: { groupsApp, }, + provide() { + const { + dataset: { + newSubgroupPath, + newProjectPath, + newSubgroupIllustration, + newProjectIllustration, + emptySubgroupIllustration, + renderEmptyState, + canCreateSubgroups, + canCreateProjects, + }, + } = this.$options.el; + + return { + newSubgroupPath, + newProjectPath, + newSubgroupIllustration, + newProjectIllustration, + emptySubgroupIllustration, + renderEmptyState: parseBoolean(renderEmptyState), + canCreateSubgroups: parseBoolean(canCreateSubgroups), + canCreateProjects: parseBoolean(canCreateProjects), + }; + }, data() { const { dataset } = dataEl || this.$options.el; const hideProjects = parseBoolean(dataset.hideProjects); diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb index d491e222665..348a5af699d 100644 --- a/app/helpers/groups_helper.rb +++ b/app/helpers/groups_helper.rb @@ -153,6 +153,20 @@ module GroupsHelper } end + def subgroups_and_projects_list_app_data(group) + { + show_schema_markup: 'true', + new_subgroup_path: new_group_path(parent_id: group.id), + new_project_path: new_project_path(namespace_id: group.id), + new_subgroup_illustration: image_path('illustrations/subgroup-create-new-sm.svg'), + new_project_illustration: image_path('illustrations/project-create-new-sm.svg'), + empty_subgroup_illustration: image_path('illustrations/empty-state/empty-subgroup-md.svg'), + render_empty_state: 'true', + can_create_subgroups: can?(current_user, :create_subgroup, group).to_s, + can_create_projects: can?(current_user, :create_projects, group).to_s + } + end + private def group_title_link(group, hidable: false, show_avatar: false, for_dropdown: false) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 9f08ff9d66d..7b2ad843920 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -1963,6 +1963,10 @@ class MergeRequest < ApplicationRecord end end + def target_default_branch? + target_branch == project.default_branch + end + private attr_accessor :skip_fetch_ref diff --git a/app/views/groups/_subgroups_and_projects.html.haml b/app/views/groups/_subgroups_and_projects.html.haml index 427a36aaec4..dc749af3c0c 100644 --- a/app/views/groups/_subgroups_and_projects.html.haml +++ b/app/views/groups/_subgroups_and_projects.html.haml @@ -1,7 +1,4 @@ #js-groups-subgroups_and_projects-tree - .empty-state.hidden - = render "shared/groups/empty_state" - %section{ data: { hide_projects: 'false', group_id: group.id, path: group_path(group) } } - .js-groups-list-holder{ data: { show_schema_markup: 'true'} } + .js-groups-list-holder{ data: subgroups_and_projects_list_app_data(group) } = gl_loading_icon(size: 'md', css_class: 'gl-mt-6') diff --git a/db/migrate/20220601223501_add_vulnerability_related_columns.rb b/db/migrate/20220601223501_add_vulnerability_related_columns.rb new file mode 100644 index 00000000000..be310b02467 --- /dev/null +++ b/db/migrate/20220601223501_add_vulnerability_related_columns.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +class AddVulnerabilityRelatedColumns < Gitlab::Database::Migration[2.0] + def change + add_column :approval_merge_request_rules, + :vulnerabilities_allowed, + :integer, + limit: 2, + null: false, + default: 0 + add_column :approval_merge_request_rules, + :scanners, + :text, + array: true, + null: false, + default: [] + add_column :approval_merge_request_rules, + :severity_levels, + :text, + array: true, + null: false, + default: [] + add_column :approval_merge_request_rules, + :vulnerability_states, + :text, + array: true, + null: false, + default: ['newly_detected'] + end +end diff --git a/db/schema_migrations/20220601223501 b/db/schema_migrations/20220601223501 new file mode 100644 index 00000000000..86abed4fa45 --- /dev/null +++ b/db/schema_migrations/20220601223501 @@ -0,0 +1 @@ +5012f2becb04485a67df5fa0acdf7c73a9410368493256f4774af297de5f86e8 \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 3f450b61b27..49c72599585 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -11419,6 +11419,10 @@ CREATE TABLE approval_merge_request_rules ( section text, modified_from_project_rule boolean DEFAULT false NOT NULL, orchestration_policy_idx smallint, + vulnerabilities_allowed smallint DEFAULT 0 NOT NULL, + scanners text[] DEFAULT '{}'::text[] NOT NULL, + severity_levels text[] DEFAULT '{}'::text[] NOT NULL, + vulnerability_states text[] DEFAULT '{newly_detected}'::text[] NOT NULL, CONSTRAINT check_6fca5928b2 CHECK ((char_length(section) <= 255)) ); diff --git a/doc/user/application_security/secret_detection/index.md b/doc/user/application_security/secret_detection/index.md index 034188c682a..8dfb077fd06 100644 --- a/doc/user/application_security/secret_detection/index.md +++ b/doc/user/application_security/secret_detection/index.md @@ -198,7 +198,7 @@ Secret Detection can be customized by defining available CI/CD variables: | `SECRET_DETECTION_EXCLUDED_PATHS` | "" | Exclude vulnerabilities from output based on the paths. This is a comma-separated list of patterns. Patterns can be globs, or file or folder paths (for example, `doc,spec` ). Parent directories also match patterns. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/225273) in GitLab 13.3. | | `SECRET_DETECTION_HISTORIC_SCAN` | false | Flag to enable a historic Gitleaks scan. | | `SECRET_DETECTION_IMAGE_SUFFIX` | "" | Suffix added to the image name. If set to `-fips`, `FIPS-enabled` images are used for scan. See [FIPS-enabled images](#fips-enabled-images) for more details. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/355519) in GitLab 14.10. | -| `SECRET_DETECTION_LOG_OPTS` | "" | [`git log`](https://git-scm.com/docs/git-log) options used to define commit ranges. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/350660) in GitLab 15.1.| +| `SECRET_DETECTION_LOG_OPTIONS` | "" | [`git log`](https://git-scm.com/docs/git-log) options used to define commit ranges. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/350660) in GitLab 15.1.| In previous GitLab versions, the following variables were also available: diff --git a/doc/user/profile/index.md b/doc/user/profile/index.md index 1ec89750c0b..07f21da3099 100644 --- a/doc/user/profile/index.md +++ b/doc/user/profile/index.md @@ -419,8 +419,13 @@ A new token is generated. When you sign in to the main GitLab application, a `_gitlab_session` cookie is set. When you close your browser, the cookie is cleared client-side -and it expires after "Application settings > Session duration (minutes)"/`session_expire_delay` -(defaults to `10080` minutes = 7 days) of no activity. +and it expires after a set duration. GitLab administrators can determine the duration: + +1. On the top bar, select **Menu > Admin**. +1. On the left sidebar, select **Settings > General**. +1. Expand **Account and limit**. The set duration is in **Session duration (minutes)**. + +The default is `10080`, which equals 7 days. When you sign in to the main GitLab application, you can also check the **Remember me** option. This sets the `remember_user_token` diff --git a/locale/gitlab.pot b/locale/gitlab.pot index fd4d25fd605..7f57a99e6a6 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -18414,15 +18414,33 @@ msgstr "" msgid "GroupsEmptyState|A group is a collection of several projects." msgstr "" +msgid "GroupsEmptyState|Create new project" +msgstr "" + +msgid "GroupsEmptyState|Create new subgroup" +msgstr "" + +msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members." +msgstr "" + msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder." msgstr "" msgid "GroupsEmptyState|No groups found" msgstr "" +msgid "GroupsEmptyState|No subgroups or projects." +msgstr "" + +msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab." +msgstr "" + msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group." msgstr "" +msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project." +msgstr "" + msgid "GroupsNew|%{linkStart}Groups%{linkEnd} allow you to manage and collaborate across multiple projects. Members of a group have access to all of its projects." msgstr "" diff --git a/spec/features/groups/show_spec.rb b/spec/features/groups/show_spec.rb index eb62b6fa8ee..fa8db1befb5 100644 --- a/spec/features/groups/show_spec.rb +++ b/spec/features/groups/show_spec.rb @@ -72,6 +72,58 @@ RSpec.describe 'Group show page' do end end end + + context 'subgroups and projects empty state', :js do + context 'when user has permissions to create new subgroups or projects' do + before do + group.add_owner(user) + sign_in(user) + visit path + end + + it 'shows `Create new subgroup` link' do + expect(page).to have_link( + s_('GroupsEmptyState|Create new subgroup'), + href: new_group_path(parent_id: group.id) + ) + end + + it 'shows `Create new project` link' do + expect(page).to have_link( + s_('GroupsEmptyState|Create new project'), + href: new_project_path(namespace_id: group.id) + ) + end + end + end + + context 'when user does not have permissions to create new subgroups or projects', :js do + before do + group.add_reporter(user) + sign_in(user) + visit path + end + + it 'does not show `Create new subgroup` link' do + expect(page).not_to have_link( + s_('GroupsEmptyState|Create new subgroup'), + href: new_group_path(parent_id: group.id) + ) + end + + it 'does not show `Create new project` link' do + expect(page).not_to have_link( + s_('GroupsEmptyState|Create new project'), + href: new_project_path(namespace_id: group.id) + ) + end + + it 'shows empty state' do + expect(page).to have_content(s_('GroupsEmptyState|No subgroups or projects.')) + expect(page).to have_content(s_('GroupsEmptyState|You do not have necessary permissions to create a subgroup' \ + ' or project in this group. Please contact an owner of this group to create a new subgroup or project.')) + end + end end context 'when signed out' do diff --git a/spec/frontend/editor/source_editor_spec.js b/spec/frontend/editor/source_editor_spec.js index b3d914e6755..74aae7b899b 100644 --- a/spec/frontend/editor/source_editor_spec.js +++ b/spec/frontend/editor/source_editor_spec.js @@ -92,7 +92,7 @@ describe('Base editor', () => { expect(monacoEditor.createModel).toHaveBeenCalledWith( blobContent, - undefined, + 'markdown', expect.objectContaining({ path: uriFilePath, }), @@ -117,7 +117,7 @@ describe('Base editor', () => { expect(modelSpy).toHaveBeenCalledWith( blobContent, - undefined, + 'markdown', expect.objectContaining({ path: uriFilePath, }), @@ -177,6 +177,29 @@ describe('Base editor', () => { expect(layoutSpy).toHaveBeenCalled(); }); + + it.each` + params | expectedLanguage + ${{}} | ${'markdown'} + ${{ blobPath: undefined }} | ${'plaintext'} + ${{ blobPath: undefined, language: 'ruby' }} | ${'ruby'} + ${{ language: 'go' }} | ${'go'} + ${{ blobPath: undefined, language: undefined }} | ${'plaintext'} + `( + 'correctly sets $expectedLanguage on the model when $params are passed', + ({ params, expectedLanguage }) => { + jest.spyOn(monacoEditor, 'createModel'); + editor.createInstance({ + ...defaultArguments, + ...params, + }); + expect(monacoEditor.createModel).toHaveBeenCalledWith( + expect.anything(), + expectedLanguage, + expect.anything(), + ); + }, + ); }); describe('instance of the Diff Editor', () => { @@ -210,7 +233,7 @@ describe('Base editor', () => { expect(modelSpy).toHaveBeenCalledTimes(2); expect(modelSpy.mock.calls[0]).toEqual([ blobContent, - undefined, + 'markdown', expect.objectContaining({ path: uriFilePath, }), diff --git a/spec/frontend/groups/components/app_spec.js b/spec/frontend/groups/components/app_spec.js index 848e50c86ba..9e4666ffc70 100644 --- a/spec/frontend/groups/components/app_spec.js +++ b/spec/frontend/groups/components/app_spec.js @@ -10,8 +10,10 @@ import groupItemComponent from '~/groups/components/group_item.vue'; import eventHub from '~/groups/event_hub'; import GroupsService from '~/groups/service/groups_service'; import GroupsStore from '~/groups/store/groups_store'; +import EmptyState from '~/groups/components/empty_state.vue'; import axios from '~/lib/utils/axios_utils'; import * as urlUtilities from '~/lib/utils/url_utility'; +import setWindowLocation from 'helpers/set_window_location_helper'; import { mockEndpoint, @@ -38,17 +40,23 @@ describe('AppComponent', () => { const store = new GroupsStore({ hideProjects: false }); const service = new GroupsService(mockEndpoint); - const createShallowComponent = (hideProjects = false) => { + const createShallowComponent = ({ propsData = {}, provide = {} } = {}) => { store.state.pageInfo = mockPageInfo; wrapper = shallowMount(appComponent, { propsData: { store, service, - hideProjects, + hideProjects: false, + containerId: 'js-groups-tree', + ...propsData, }, mocks: { $toast, }, + provide: { + renderEmptyState: false, + ...provide, + }, }); vm = wrapper.vm; }; @@ -64,6 +72,14 @@ describe('AppComponent', () => { Vue.component('GroupFolder', groupFolderComponent); Vue.component('GroupItem', groupItemComponent); + document.body.innerHTML = ` +
+ +
+ `; + createShallowComponent(); getGroupsSpy = jest.spyOn(vm.service, 'getGroups'); await nextTick(); @@ -386,7 +402,10 @@ describe('AppComponent', () => { expect(vm.store.setSearchedGroups).toHaveBeenCalledWith(mockGroups); }); - it('should set `isSearchEmpty` prop based on groups count', () => { + it('should set `isSearchEmpty` prop based on groups count and `filter` query param', () => { + setWindowLocation('?filter=foobar'); + createShallowComponent(); + vm.updateGroups(mockGroups); expect(vm.isSearchEmpty).toBe(false); @@ -395,6 +414,47 @@ describe('AppComponent', () => { expect(vm.isSearchEmpty).toBe(true); }); + + describe.each` + action | groups | fromSearch | renderEmptyState | expected + ${'subgroups_and_projects'} | ${[]} | ${false} | ${true} | ${true} + ${''} | ${[]} | ${false} | ${true} | ${false} + ${'subgroups_and_projects'} | ${mockGroups} | ${false} | ${true} | ${false} + ${'subgroups_and_projects'} | ${[]} | ${true} | ${true} | ${false} + `( + 'when `action` is $action, `groups` is $groups, `fromSearch` is $fromSearch, and `renderEmptyState` is $renderEmptyState', + ({ action, groups, fromSearch, renderEmptyState, expected }) => { + it(expected ? 'renders empty state' : 'does not render empty state', async () => { + createShallowComponent({ + propsData: { action }, + provide: { renderEmptyState }, + }); + + vm.updateGroups(groups, fromSearch); + + await nextTick(); + + expect(wrapper.findComponent(EmptyState).exists()).toBe(expected); + }); + }, + ); + }); + + describe('when `action` is subgroups_and_projects, `groups` is [], `fromSearch` is `false`, and `renderEmptyState` is `false`', () => { + it('renders legacy empty state', async () => { + createShallowComponent({ + propsData: { action: 'subgroups_and_projects' }, + provide: { renderEmptyState: false }, + }); + + vm.updateGroups([], false); + + await nextTick(); + + expect( + document.querySelector('[data-testid="legacy-empty-state"]').classList.contains('hidden'), + ).toBe(false); + }); }); }); @@ -419,7 +479,7 @@ describe('AppComponent', () => { }); it('should initialize `searchEmptyMessage` prop with correct string when `hideProjects` is `true`', async () => { - createShallowComponent(true); + createShallowComponent({ propsData: { hideProjects: true } }); await nextTick(); expect(vm.searchEmptyMessage).toBe('No groups matched your search'); }); diff --git a/spec/frontend/groups/components/empty_state_spec.js b/spec/frontend/groups/components/empty_state_spec.js new file mode 100644 index 00000000000..c0e71e814d0 --- /dev/null +++ b/spec/frontend/groups/components/empty_state_spec.js @@ -0,0 +1,78 @@ +import { GlEmptyState } from '@gitlab/ui'; + +import { mountExtended } from 'jest/__helpers__/vue_test_utils_helper'; +import EmptyState from '~/groups/components/empty_state.vue'; + +let wrapper; + +const defaultProvide = { + newProjectIllustration: '/assets/illustrations/project-create-new-sm.svg', + newProjectPath: '/projects/new?namespace_id=231', + newSubgroupIllustration: '/assets/illustrations/group-new.svg', + newSubgroupPath: '/groups/new?parent_id=231', + emptySubgroupIllustration: '/assets/illustrations/empty-state/empty-subgroup-md.svg', + canCreateSubgroups: true, + canCreateProjects: true, +}; + +const createComponent = ({ provide = {} } = {}) => { + wrapper = mountExtended(EmptyState, { + provide: { + ...defaultProvide, + ...provide, + }, + }); +}; + +afterEach(() => { + wrapper.destroy(); +}); + +const findNewSubgroupLink = () => + wrapper.findByRole('link', { + name: new RegExp(EmptyState.i18n.withLinks.subgroup.title), + }); +const findNewProjectLink = () => + wrapper.findByRole('link', { + name: new RegExp(EmptyState.i18n.withLinks.project.title), + }); +const findNewSubgroupIllustration = () => + wrapper.findByRole('img', { name: EmptyState.i18n.withLinks.subgroup.title }); +const findNewProjectIllustration = () => + wrapper.findByRole('img', { name: EmptyState.i18n.withLinks.project.title }); + +describe('EmptyState', () => { + describe('when user has permission to create a subgroup', () => { + it('renders `Create new subgroup` link', () => { + createComponent(); + + expect(findNewSubgroupLink().attributes('href')).toBe(defaultProvide.newSubgroupPath); + expect(findNewSubgroupIllustration().attributes('src')).toBe( + defaultProvide.newSubgroupIllustration, + ); + }); + }); + + describe('when user has permission to create a project', () => { + it('renders `Create new project` link', () => { + createComponent(); + + expect(findNewProjectLink().attributes('href')).toBe(defaultProvide.newProjectPath); + expect(findNewProjectIllustration().attributes('src')).toBe( + defaultProvide.newProjectIllustration, + ); + }); + }); + + describe('when user does not have permissions to create a project or a subgroup', () => { + it('renders empty state', () => { + createComponent({ provide: { canCreateSubgroups: false, canCreateProjects: false } }); + + expect(wrapper.find(GlEmptyState).props()).toMatchObject({ + title: EmptyState.i18n.withoutLinks.title, + description: EmptyState.i18n.withoutLinks.description, + svgPath: defaultProvide.emptySubgroupIllustration, + }); + }); + }); +}); diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb index 0fb17fb8922..3ea5701c134 100644 --- a/spec/helpers/groups_helper_spec.rb +++ b/spec/helpers/groups_helper_spec.rb @@ -446,4 +446,30 @@ RSpec.describe GroupsHelper do end end end + + describe '#subgroups_and_projects_list_app_data' do + let_it_be(:group) { create(:group) } + let_it_be(:user) { create(:user) } + + before do + allow(helper).to receive(:current_user).and_return(user) + + allow(helper).to receive(:can?).with(user, :create_subgroup, group) { true } + allow(helper).to receive(:can?).with(user, :create_projects, group) { true } + end + + it 'returns expected hash' do + expect(helper.subgroups_and_projects_list_app_data(group)).to match({ + show_schema_markup: 'true', + new_subgroup_path: including("groups/new?parent_id=#{group.id}"), + new_project_path: including("/projects/new?namespace_id=#{group.id}"), + new_subgroup_illustration: including('illustrations/subgroup-create-new-sm'), + new_project_illustration: including('illustrations/project-create-new-sm'), + empty_subgroup_illustration: including('illustrations/empty-state/empty-subgroup-md'), + render_empty_state: 'true', + can_create_subgroups: 'true', + can_create_projects: 'true' + }) + end + end end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 4136e98780b..381eccf2376 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -5117,4 +5117,22 @@ RSpec.describe MergeRequest, factory_default: :keep do end end end + + describe '#target_default_branch?' do + let_it_be(:merge_request) { build(:merge_request, project: project) } + + it 'returns false' do + expect(merge_request.target_default_branch?).to be false + end + + context 'with target_branch equal project default branch' do + before do + merge_request.target_branch = "master" + end + + it 'returns false' do + expect(merge_request.target_default_branch?).to be true + end + end + end end