From a99c04f0185d6a6b398c37630c392ca84494c0a5 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Wed, 12 Oct 2022 12:09:35 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .gitlab/ci/caching.gitlab-ci.yml | 2 +- .gitlab/ci/frontend.gitlab-ci.yml | 2 +- .gitlab/ci/global.gitlab-ci.yml | 24 ++++++-- .haml-lint.yml | 1 + .rubocop_todo/rails/index_with.yml | 11 ++-- .rubocop_todo/rails/redundant_foreign_key.yml | 12 ++-- .../style/sole_nested_conditional.yml | 13 +++-- .../notes/components/comment_form.vue | 5 +- app/assets/javascripts/notes/i18n.js | 2 +- .../package_registry/constants.js | 11 ++++ .../package_registry/pages/details.vue | 46 +++++++++------ .../components/runner_list_empty_state.vue | 9 ++- .../components/widget/widget.vue | 8 +-- .../components/widget/widget_content_row.vue | 33 ++++++----- app/policies/issue_policy.rb | 4 ++ app/serializers/issue_entity.rb | 4 ++ app/views/projects/tags/new.html.haml | 20 ++----- ...39_ide_edit_total_unique_counts_weekly.yml | 5 +- doc/api/dependencies.md | 36 ++++++++---- doc/development/pipelines.md | 3 +- lib/gitlab/git/repository.rb | 2 + lib/tasks/gitlab/usage_data.rake | 3 +- locale/gitlab.pot | 26 +++++---- qa/qa/fixtures/software_licenses/other | 7 +++ qa/qa/page/project/tag/new.rb | 12 ---- qa/qa/resource/user.rb | 2 +- .../repository/license_detection_spec.rb | 6 +- .../repository/protected_tags_spec.rb | 2 - qa/spec/resource/user_spec.rb | 4 +- scripts/gitlab_component_helpers.sh | 5 +- scripts/rspec_helpers.sh | 6 ++ .../tags/developer_creates_tag_spec.rb | 25 -------- .../notes/components/comment_form_spec.js | 23 +++++++- spec/frontend/notes/mock_data.js | 1 + .../package_registry/pages/details_spec.js | 26 ++++++++- .../runner_list_empty_state_spec.js | 57 ++++++++++++++----- .../widget/widget_content_row_spec.js | 2 + spec/lib/gitlab/git/repository_spec.rb | 20 ++++++- .../metrics/aggregates/aggregate_spec.rb | 23 +++++++- spec/policies/issue_policy_spec.rb | 6 +- spec/serializers/issue_entity_spec.rb | 2 + ...current_user_properties_shared_examples.rb | 22 +++++++ 42 files changed, 358 insertions(+), 175 deletions(-) create mode 100644 qa/qa/fixtures/software_licenses/other create mode 100644 spec/support/shared_examples/serializers/issuable_current_user_properties_shared_examples.rb diff --git a/.gitlab/ci/caching.gitlab-ci.yml b/.gitlab/ci/caching.gitlab-ci.yml index 4a7a843b514..589032e66ea 100644 --- a/.gitlab/ci/caching.gitlab-ci.yml +++ b/.gitlab/ci/caching.gitlab-ci.yml @@ -23,7 +23,7 @@ cache-workhorse: .cache-assets-base: extends: - .compile-assets-base - - .ruby-node-cache + - .assets-compile-cache - .caching:rules:cache-assets stage: prepare variables: diff --git a/.gitlab/ci/frontend.gitlab-ci.yml b/.gitlab/ci/frontend.gitlab-ci.yml index d7d27b91b13..c64704d5d49 100644 --- a/.gitlab/ci/frontend.gitlab-ci.yml +++ b/.gitlab/ci/frontend.gitlab-ci.yml @@ -291,7 +291,7 @@ coverage-frontend: .qa-frontend-node: extends: - .default-retry - - .yarn-cache + - .qa-frontend-node-cache - .frontend:rules:qa-frontend-node stage: test needs: [] diff --git a/.gitlab/ci/global.gitlab-ci.yml b/.gitlab/ci/global.gitlab-ci.yml index e3b41dcfe4a..77e17b2147f 100644 --- a/.gitlab/ci/global.gitlab-ci.yml +++ b/.gitlab/ci/global.gitlab-ci.yml @@ -79,21 +79,30 @@ policy: push # We want to rebuild the cache from scratch to ensure stale dependencies are cleaned up. .assets-cache: &assets-cache - key: "assets-debian-${DEBIAN_VERSION}-ruby-${RUBY_VERSION}-node-${NODE_ENV}-v4" + key: "assets-debian-${DEBIAN_VERSION}-ruby-${RUBY_VERSION}-node-${NODE_ENV}-v5" # This list should match GITLAB_ASSETS_PATHS_LIST from scripts/gitlab_component_helpers.sh paths: - cached-assets-hash.txt - app/assets/javascripts/locale/**/app.js - public/assets/ - - tmp/cache/assets/sprockets/ - - tmp/cache/babel-loader/ - - tmp/cache/vue-loader/ policy: pull .assets-cache-push: &assets-cache-push <<: *assets-cache policy: push # We want to rebuild the cache from scratch to ensure stale dependencies are cleaned up. +.assets-tmp-cache: &assets-tmp-cache + key: "assets-tmp-debian-${DEBIAN_VERSION}-ruby-${RUBY_VERSION}-node-${NODE_ENV}-v1" + paths: + - tmp/cache/assets/sprockets/ + - tmp/cache/babel-loader/ + - tmp/cache/vue-loader/ + policy: pull + +.assets-tmp-cache-push: &assets-tmp-cache-push + <<: *assets-tmp-cache + policy: push # We want to rebuild the cache from scratch to ensure we don't pile up outdated cache files. + .storybook-node-modules-cache: &storybook-node-modules-cache key: "storybook-node-modules-${DEBIAN_VERSION}-${NODE_ENV}" paths: @@ -201,6 +210,11 @@ cache: - *node-modules-cache +.qa-frontend-node-cache: + cache: + - *node-modules-cache + - *assets-tmp-cache + # TODO: Remove this as it's duplicating .assets-compile-cache-push .yarn-cache-push: cache: @@ -211,12 +225,14 @@ - *ruby-gems-cache - *node-modules-cache - *assets-cache + - *assets-tmp-cache .assets-compile-cache-push: cache: - *ruby-gems-cache # We don't push this cache as it's already rebuilt by `update-setup-test-env-cache` - *node-modules-cache-push - *assets-cache-push + - *assets-tmp-cache-push .storybook-yarn-cache: cache: diff --git a/.haml-lint.yml b/.haml-lint.yml index 7d772831b2c..60f86eb4158 100644 --- a/.haml-lint.yml +++ b/.haml-lint.yml @@ -101,6 +101,7 @@ linters: - Style/IfUnlessModifier - Style/IndentationWidth - Style/Next + - Style/SoleNestedConditional - Style/TrailingWhitespace - Style/WhileUntilModifier - Cop/StaticTranslationDefinition diff --git a/.rubocop_todo/rails/index_with.yml b/.rubocop_todo/rails/index_with.yml index d8ccbd97f7c..91a75e198f5 100644 --- a/.rubocop_todo/rails/index_with.yml +++ b/.rubocop_todo/rails/index_with.yml @@ -1,29 +1,30 @@ --- # Cop supports --auto-correct. Rails/IndexWith: - # Offense count: 54 - # Temporarily disabled due to too many offenses - Enabled: false + Details: grace period Exclude: - 'app/helpers/ci/jobs_helper.rb' - 'app/models/ci/build_trace_chunk.rb' - 'app/models/ci/processable.rb' - 'app/models/concerns/cached_commit.rb' + - 'app/models/customer_relations/organization.rb' - 'app/models/environment.rb' - 'app/services/concerns/rate_limited_service.rb' + - 'app/services/packages/rpm/parse_package_service.rb' - 'db/post_migrate/20210731132939_backfill_stage_event_hash.rb' + - 'ee/app/models/concerns/identity_verifiable.rb' - 'ee/app/models/vulnerabilities/projects_grade.rb' - 'ee/lib/ee/gitlab/usage_data.rb' - 'ee/lib/gitlab/auth/group_saml/auth_hash.rb' - 'ee/lib/gitlab/custom_file_templates.rb' - 'ee/lib/gitlab/insights/reducers/count_per_label_reducer.rb' - 'ee/spec/lib/ee/gitlab/application_context_spec.rb' - - 'ee/spec/models/ee/namespace_spec.rb' - 'ee/spec/models/sca/license_compliance_spec.rb' - 'ee/spec/views/admin/dashboard/index.html.haml_spec.rb' - 'lib/api/entities/project_integration.rb' - 'lib/api/helpers/packages/conan/api_helpers.rb' - 'lib/banzai/filter/repository_link_filter.rb' + - 'lib/gitlab/background_migration/backfill_note_discussion_id.rb' - 'lib/gitlab/background_migration/update_jira_tracker_data_deployment_type_based_on_url.rb' - 'lib/gitlab/ci/ansi2html.rb' - 'lib/gitlab/ci/reports/security/finding.rb' @@ -32,10 +33,12 @@ Rails/IndexWith: - 'lib/gitlab/database/count/exact_count_strategy.rb' - 'lib/gitlab/database/migration_helpers.rb' - 'lib/gitlab/database/obsolete_ignored_columns.rb' + - 'lib/gitlab/database/tables_sorted_by_foreign_keys.rb' - 'lib/gitlab/issuable_metadata.rb' - 'lib/gitlab/template/base_template.rb' - 'lib/gitlab/usage_data.rb' - 'lib/google_api/cloud_platform/client.rb' + - 'lib/tasks/gitlab/db.rake' - 'qa/qa/resource/reusable.rb' - 'scripts/trigger-build.rb' - 'spec/lib/gitlab/api_authentication/sent_through_builder_spec.rb' diff --git a/.rubocop_todo/rails/redundant_foreign_key.yml b/.rubocop_todo/rails/redundant_foreign_key.yml index 7e394849670..22af6131b33 100644 --- a/.rubocop_todo/rails/redundant_foreign_key.yml +++ b/.rubocop_todo/rails/redundant_foreign_key.yml @@ -1,9 +1,7 @@ --- # Cop supports --auto-correct. Rails/RedundantForeignKey: - # Offense count: 90 - # Temporarily disabled due to too many offenses - Enabled: false + Details: grace period Exclude: - 'app/models/alert_management/metric_image.rb' - 'app/models/ci/build.rb' @@ -23,9 +21,11 @@ Rails/RedundantForeignKey: - 'app/models/commit_signatures/x509_commit_signature.rb' - 'app/models/concerns/analytics/cycle_analytics/stage.rb' - 'app/models/concerns/commit_signature.rb' + - 'app/models/concerns/integrations/base_data_fields.rb' - 'app/models/group.rb' - 'app/models/group_group_link.rb' - - 'app/models/integrations/zentao_tracker_data.rb' + - 'app/models/incident_management/timeline_event.rb' + - 'app/models/issue.rb' - 'app/models/member.rb' - 'app/models/merge_request.rb' - 'app/models/merge_request/metrics.rb' @@ -35,9 +35,13 @@ Rails/RedundantForeignKey: - 'app/models/project.rb' - 'app/models/resource_state_event.rb' - 'app/models/review.rb' + - 'app/models/time_tracking/timelog_category.rb' - 'app/models/user.rb' + - 'app/models/users/phone_number_validation.rb' + - 'app/models/work_item.rb' - 'app/models/x509_certificate.rb' - 'ee/app/models/allowed_email_domain.rb' + - 'ee/app/models/audit_events/streaming/header.rb' - 'ee/app/models/boards/epic_board.rb' - 'ee/app/models/boards/epic_list_user_preference.rb' - 'ee/app/models/ci/sources/project.rb' diff --git a/.rubocop_todo/style/sole_nested_conditional.yml b/.rubocop_todo/style/sole_nested_conditional.yml index 620d66a272c..535b8d20765 100644 --- a/.rubocop_todo/style/sole_nested_conditional.yml +++ b/.rubocop_todo/style/sole_nested_conditional.yml @@ -1,8 +1,7 @@ --- +# Cop supports --auto-correct. Style/SoleNestedConditional: - # Offense count: 64 - # Temporarily disabled due to too many offenses - Enabled: false + Details: grace period Exclude: - 'app/controllers/admin/application_settings_controller.rb' - 'app/controllers/ldap/omniauth_callbacks_controller.rb' @@ -17,7 +16,6 @@ Style/SoleNestedConditional: - 'app/models/network/graph.rb' - 'app/models/packages/package.rb' - 'app/models/protected_branch.rb' - - 'app/services/ci/register_job_service.rb' - 'app/services/concerns/update_visibility_level.rb' - 'app/services/incident_management/incidents/create_service.rb' - 'app/services/merge_requests/update_service.rb' @@ -27,9 +25,11 @@ Style/SoleNestedConditional: - 'app/services/projects/create_service.rb' - 'app/services/projects/hashed_storage/migration_service.rb' - 'app/services/projects/hashed_storage/rollback_service.rb' + - 'app/workers/merge_requests/delete_source_branch_worker.rb' - 'ee/app/finders/ee/snippets_finder.rb' - 'ee/app/services/ee/issue_links/create_service.rb' - 'ee/app/services/ee/lfs/unlock_file_service.rb' + - 'ee/app/services/ee/merge_requests/create_pipeline_service.rb' - 'ee/app/services/epics/tree_reorder_service.rb' - 'ee/app/services/geo/framework_repository_sync_service.rb' - 'ee/app/services/geo/repository_base_sync_service.rb' @@ -43,6 +43,7 @@ Style/SoleNestedConditional: - 'lib/api/ci/helpers/runner.rb' - 'lib/api/deploy_keys.rb' - 'lib/api/helpers/label_helpers.rb' + - 'lib/api/maven_packages.rb' - 'lib/api/users.rb' - 'lib/banzai/filter/ascii_doc_sanitization_filter.rb' - 'lib/banzai/filter/base_sanitization_filter.rb' @@ -52,7 +53,9 @@ Style/SoleNestedConditional: - 'lib/gitlab/config/entry/configurable.rb' - 'lib/gitlab/config/entry/validators.rb' - 'lib/gitlab/database/each_database.rb' + - 'lib/gitlab/database/load_balancing/load_balancer.rb' - 'lib/gitlab/email/handler/reply_processing.rb' + - 'lib/gitlab/patch/database_config.rb' - 'lib/gitlab/user_access.rb' - 'lib/gitlab/utils.rb' - 'lib/gitlab/x509/signature.rb' @@ -60,5 +63,5 @@ Style/SoleNestedConditional: - 'lib/mattermost/session.rb' - 'lib/object_storage/direct_upload.rb' - 'qa/qa/flow/login.rb' - - 'qa/qa/support/page_error_checker.rb' + - 'qa/qa/page/project/web_ide/edit.rb' - 'spec/spec_helper.rb' diff --git a/app/assets/javascripts/notes/components/comment_form.vue b/app/assets/javascripts/notes/components/comment_form.vue index 56f9e0d1c25..0d7ff022f8f 100644 --- a/app/assets/javascripts/notes/components/comment_form.vue +++ b/app/assets/javascripts/notes/components/comment_form.vue @@ -111,7 +111,10 @@ export default { return this.getNoteableData.current_user.can_create_note; }, canSetInternalNote() { - return this.getNoteableData.current_user.can_update && (this.isIssue || this.isEpic); + return ( + this.getNoteableData.current_user.can_create_confidential_note && + (this.isIssue || this.isEpic) + ); }, issueActionButtonTitle() { const openOrClose = this.isOpen ? 'close' : 'reopen'; diff --git a/app/assets/javascripts/notes/i18n.js b/app/assets/javascripts/notes/i18n.js index 08792fd1a3f..9b5fd69f816 100644 --- a/app/assets/javascripts/notes/i18n.js +++ b/app/assets/javascripts/notes/i18n.js @@ -16,7 +16,7 @@ export const COMMENT_FORM = { bodyPlaceholderInternal: __('Write an internal note or drag your files here…'), internal: s__('Notes|Make this an internal note'), internalVisibility: s__( - 'Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher', + 'Notes|Internal notes are only visible to members with the role of Reporter or higher', ), discussionThatNeedsResolution: __( 'Discuss a specific suggestion or question that needs to be resolved.', diff --git a/app/assets/javascripts/packages_and_registries/package_registry/constants.js b/app/assets/javascripts/packages_and_registries/package_registry/constants.js index 06a04ee248a..4e35176c757 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/constants.js +++ b/app/assets/javascripts/packages_and_registries/package_registry/constants.js @@ -78,6 +78,17 @@ export const TRACKING_ACTION_CLICK_COMMIT_LINK = 'click_commit_link_from_package export const TRACKING_LABEL_PACKAGE_HISTORY = 'package_history'; export const SHOW_DELETE_SUCCESS_ALERT = 'showSuccessDeleteAlert'; + +export const DELETE_MODAL_TITLE = s__('PackageRegistry|Delete package version'); +export const DELETE_MODAL_CONTENT = s__( + `PackageRegistry|You are about to delete version %{version} of %{name}. Are you sure?`, +); +export const DELETE_ALL_PACKAGE_FILES_MODAL_CONTENT = s__( + `PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?`, +); +export const DELETE_LAST_PACKAGE_FILE_MODAL_CONTENT = s__( + `PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?`, +); export const DELETE_PACKAGE_FILE_ERROR_MESSAGE = s__( 'PackageRegistry|Something went wrong while deleting the package asset.', ); diff --git a/app/assets/javascripts/packages_and_registries/package_registry/pages/details.vue b/app/assets/javascripts/packages_and_registries/package_registry/pages/details.vue index e5420dbdccf..eeed56b77c3 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/pages/details.vue +++ b/app/assets/javascripts/packages_and_registries/package_registry/pages/details.vue @@ -44,6 +44,10 @@ import { DELETE_PACKAGE_FILES_ERROR_MESSAGE, DELETE_PACKAGE_FILES_SUCCESS_MESSAGE, DOWNLOAD_PACKAGE_ASSET_TRACKING_ACTION, + DELETE_MODAL_TITLE, + DELETE_MODAL_CONTENT, + DELETE_ALL_PACKAGE_FILES_MODAL_CONTENT, + DELETE_LAST_PACKAGE_FILE_MODAL_CONTENT, } from '~/packages_and_registries/package_registry/constants'; import destroyPackageFilesMutation from '~/packages_and_registries/package_registry/graphql/mutations/destroy_package_files.mutation.graphql'; @@ -86,6 +90,7 @@ export default { }, data() { return { + deletePackageModalContent: DELETE_MODAL_CONTENT, filesToDelete: [], mutationLoading: false, packageEntity: {}, @@ -206,18 +211,16 @@ export default { throw data.destroyPackageFiles.errors[0]; } createAlert({ - message: - ids.length === 1 - ? DELETE_PACKAGE_FILE_SUCCESS_MESSAGE - : DELETE_PACKAGE_FILES_SUCCESS_MESSAGE, + message: this.isLastItem(ids) + ? DELETE_PACKAGE_FILE_SUCCESS_MESSAGE + : DELETE_PACKAGE_FILES_SUCCESS_MESSAGE, variant: VARIANT_SUCCESS, }); } catch (error) { createAlert({ - message: - ids.length === 1 - ? DELETE_PACKAGE_FILE_ERROR_MESSAGE - : DELETE_PACKAGE_FILES_ERROR_MESSAGE, + message: this.isLastItem(ids) + ? DELETE_PACKAGE_FILE_ERROR_MESSAGE + : DELETE_PACKAGE_FILES_ERROR_MESSAGE, variant: VARIANT_WARNING, captureError: true, error, @@ -231,18 +234,26 @@ export default { files.length === this.packageFiles.length && !this.packageEntity.packageFiles?.pageInfo?.hasNextPage ) { + if (this.isLastItem(files)) { + this.deletePackageModalContent = DELETE_LAST_PACKAGE_FILE_MODAL_CONTENT; + } else { + this.deletePackageModalContent = DELETE_ALL_PACKAGE_FILES_MODAL_CONTENT; + } this.$refs.deleteModal.show(); } else { this.filesToDelete = files; - if (files.length === 1) { + if (this.isLastItem(files)) { this.$refs.deleteFileModal.show(); } else if (files.length > 1) { this.$refs.deleteFilesModal.show(); } } }, + isLastItem(items) { + return items.length === 1; + }, confirmFilesDelete() { - if (this.filesToDelete.length === 1) { + if (this.isLastItem(this.filesToDelete)) { this.track(DELETE_PACKAGE_FILE_TRACKING_ACTION); } else { this.track(DELETE_PACKAGE_FILES_TRACKING_ACTION); @@ -250,12 +261,12 @@ export default { this.deletePackageFiles(this.filesToDelete.map((file) => file.id)); this.filesToDelete = []; }, + resetDeleteModalContent() { + this.deletePackageModalContent = DELETE_MODAL_CONTENT; + }, }, i18n: { - deleteModalTitle: s__(`PackageRegistry|Delete Package Version`), - deleteModalContent: s__( - `PackageRegistry|You are about to delete version %{version} of %{name}. Are you sure?`, - ), + DELETE_MODAL_TITLE, deleteFileModalTitle: s__(`PackageRegistry|Delete package asset`), deleteFileModalContent: s__( `PackageRegistry|You are about to delete %{filename}. This is a destructive action that may render your package unusable. Are you sure?`, @@ -371,10 +382,11 @@ export default { :action-primary="$options.modal.packageDeletePrimaryAction" :action-cancel="$options.modal.cancelAction" @primary="deletePackage(packageEntity)" + @hidden="resetDeleteModalContent" @canceled="track($options.trackingActions.CANCEL_DELETE_PACKAGE)" > - - + + @@ -398,7 +410,7 @@ export default { @canceled="track($options.trackingActions.CANCEL_DELETE_PACKAGE_FILE)" > - + diff --git a/app/assets/javascripts/runner/components/runner_list_empty_state.vue b/app/assets/javascripts/runner/components/runner_list_empty_state.vue index ab9cde6a401..e6576c83e69 100644 --- a/app/assets/javascripts/runner/components/runner_list_empty_state.vue +++ b/app/assets/javascripts/runner/components/runner_list_empty_state.vue @@ -53,7 +53,7 @@ export default { :svg-path="svgPath" :svg-height="$options.svgHeight" > - diff --git a/app/assets/javascripts/vue_merge_request_widget/components/widget/widget.vue b/app/assets/javascripts/vue_merge_request_widget/components/widget/widget.vue index 9cdb32892db..94359d7d6ac 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/widget/widget.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/widget/widget.vue @@ -246,16 +246,16 @@ export default { {{ contentError }} - -
+
+ -
- + +
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/widget/widget_content_row.vue b/app/assets/javascripts/vue_merge_request_widget/components/widget/widget_content_row.vue index 627a4835e57..ee81f0950a8 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/widget/widget_content_row.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/widget/widget_content_row.vue @@ -45,25 +45,24 @@ export default { diff --git a/app/policies/issue_policy.rb b/app/policies/issue_policy.rb index 0a0a35d41cc..87db228a698 100644 --- a/app/policies/issue_policy.rb +++ b/app/policies/issue_policy.rb @@ -81,6 +81,10 @@ class IssuePolicy < IssuablePolicy rule { can?(:set_issue_metadata) & can_read_crm_contacts }.policy do enable :set_issue_crm_contacts end + + rule { can?(:reporter_access) }.policy do + enable :mark_note_as_confidential + end end IssuePolicy.prepend_mod_with('IssuePolicy') diff --git a/app/serializers/issue_entity.rb b/app/serializers/issue_entity.rb index 7ff75927fcd..3d94d2e2e9d 100644 --- a/app/serializers/issue_entity.rb +++ b/app/serializers/issue_entity.rb @@ -43,6 +43,10 @@ class IssueEntity < IssuableEntity can?(request.current_user, :create_note, issue) end + expose :can_create_confidential_note do |issue| + can?(request.current_user, :mark_note_as_confidential, issue) + end + expose :can_update do |issue| can?(request.current_user, :update_issue, issue) end diff --git a/app/views/projects/tags/new.html.haml b/app/views/projects/tags/new.html.haml index 79fc1a64790..ed06c90efa8 100644 --- a/app/views/projects/tags/new.html.haml +++ b/app/views/projects/tags/new.html.haml @@ -9,6 +9,11 @@ %h1.page-title.gl-font-size-h-display = s_('TagsPage|New Tag') +%p.gl-text-secondary + - link_start = ''.html_safe % { url: new_namespace_project_release_path } + - link_end = ''.html_safe + = s_('TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}.').html_safe % { link_start: link_start, link_end: link_end } + = form_tag namespace_project_tags_path, method: :post, id: "new-tag-form", class: "common-note-form tag-form js-quick-submit js-requires-input" do .form-group.row .col-sm-12 @@ -31,22 +36,7 @@ = text_area_tag :message, @message, required: false, class: 'form-control', rows: 5, data: { qa_selector: "tag_message_field" } .form-text.text-muted = tag_description_help_text - .form-group.row - .col-sm-12 - = label_tag :release_description, s_('TagsPage|Release notes'), class: 'gl-mb-0' - .form-text.mb-3 - - link_start = ''.html_safe - - releases_page_path = project_releases_path(@project) - - releases_page_link_start = link_start % { url: releases_page_path } - - docs_url = help_page_path('user/project/releases/index.md', anchor: 'create-a-release') - - docs_link_start = link_start % { url: docs_url } - - link_end = ''.html_safe - - replacements = { releases_page_link_start: releases_page_link_start, docs_link_start: docs_link_start, link_end: link_end } - = s_('TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}').html_safe % replacements - = render layout: 'shared/md_preview', locals: { url: preview_markdown_path(@project), referenced_users: true } do - = render 'shared/zen', attr: :release_description, classes: 'note-textarea', placeholder: s_('TagsPage|Write your release notes or drag files here…'), current_text: @release_description, qa_selector: 'release_notes_field' - = render 'shared/notes/hints' .gl-display-flex = render Pajamas::ButtonComponent.new(variant: :confirm, button_options: { class: 'gl-mr-3', data: { qa_selector: "create_tag_button" }, type: 'submit' }) do = s_('TagsPage|Create tag') diff --git a/config/metrics/counts_7d/20210216180339_ide_edit_total_unique_counts_weekly.yml b/config/metrics/counts_7d/20210216180339_ide_edit_total_unique_counts_weekly.yml index ef67ab7f11e..2b136ef96dd 100644 --- a/config/metrics/counts_7d/20210216180339_ide_edit_total_unique_counts_weekly.yml +++ b/config/metrics/counts_7d/20210216180339_ide_edit_total_unique_counts_weekly.yml @@ -9,9 +9,12 @@ product_category: web_ide value_type: number status: active time_frame: 7d +instrumentation_class: AggregatedMetric data_source: redis_hll -instrumentation_class: RedisHLLMetric options: + aggregate: + operator: OR + attribute: user_id events: - g_edit_by_web_ide - g_edit_by_sfe diff --git a/doc/api/dependencies.md b/doc/api/dependencies.md index e9eefa9ae5f..dce928046bc 100644 --- a/doc/api/dependencies.md +++ b/doc/api/dependencies.md @@ -49,18 +49,34 @@ Example response: "version": "5.0.1", "package_manager": "bundler", "dependency_file_path": "Gemfile.lock", - "vulnerabilities": [{ - "name": "DDoS", - "severity": "unknown" - }] + "vulnerabilities": [ + { + "name": "DDoS", + "severity": "unknown", + "id": 144827, + "url": "https://gitlab.example.com/group/project/-/security/vulnerabilities/144827" + } + ], + "licenses": [ + { + "name": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + ] }, { - "name": "hanami", - "version": "1.3.1", - "package_manager": "bundler", - "dependency_file_path": "Gemfile.lock", - "vulnerabilities": [] - } + "name": "hanami", + "version": "1.3.1", + "package_manager": "bundler", + "dependency_file_path": "Gemfile.lock", + "vulnerabilities": [], + "licenses": [ + { + "name": "MIT", + "url": "https://opensource.org/licenses/MIT" + } + ] + } ] ``` diff --git a/doc/development/pipelines.md b/doc/development/pipelines.md index 360ebcc3e52..130fa17c73f 100644 --- a/doc/development/pipelines.md +++ b/doc/development/pipelines.md @@ -800,8 +800,7 @@ and `cache-assets:production` jobs that: This job tries to download a generic package that contains GitLab compiled assets needed in the GitLab test suite (under `app/assets/javascripts/locale/**/app.js`, -`public/assets`, `tmp/cache/assets/sprockets/`, `tmp/cache/babel-loader/`, -and `tmp/cache/vue-loader/`). +and `public/assets`). - If the package URL returns a 404: 1. It runs `bin/rake gitlab:assets:compile`, so that the GitLab assets are compiled. diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index 078b8a7ff89..9bbe17dcad1 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -801,6 +801,8 @@ module Gitlab break nil if licensee_object.name.blank? + licensee_object.meta.nickname = "LICENSE" if licensee_object.key == "other" + licensee_object end rescue Licensee::InvalidLicense => e diff --git a/lib/tasks/gitlab/usage_data.rake b/lib/tasks/gitlab/usage_data.rake index d5bc2beeb16..822df83ede5 100644 --- a/lib/tasks/gitlab/usage_data.rake +++ b/lib/tasks/gitlab/usage_data.rake @@ -58,8 +58,7 @@ namespace :gitlab do end FileUtils.mkdir_p(path) - FileUtils.chdir(path) - File.write('sql_metrics_queries.json', Gitlab::Json.pretty_generate(queries)) + File.write(File.join(path, 'sql_metrics_queries.json'), Gitlab::Json.pretty_generate(queries)) end # Events for templates included via YAML-less Auto-DevOps diff --git a/locale/gitlab.pot b/locale/gitlab.pot index f5194a421f9..cb04770f9c5 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -27165,7 +27165,7 @@ msgstr "" msgid "Notes|Expand replies" msgstr "" -msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher" +msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher" msgstr "" msgid "Notes|Last reply by %{name}" @@ -28622,12 +28622,21 @@ msgstr "" msgid "PackageRegistry|Delete package asset" msgstr "" +msgid "PackageRegistry|Delete package version" +msgstr "" + msgid "PackageRegistry|Delete selected" msgstr "" msgid "PackageRegistry|Delete this package" msgstr "" +msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?" +msgstr "" + +msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?" +msgstr "" + msgid "PackageRegistry|Duplicate packages" msgstr "" @@ -34894,6 +34903,9 @@ msgstr "" msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner." msgstr "" +msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator." +msgstr "" + msgid "Runners|Runs untagged jobs" msgstr "" @@ -39460,6 +39472,9 @@ msgstr "" msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?" msgstr "" +msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}." +msgstr "" + msgid "TagsPage|Edit release" msgstr "" @@ -39481,15 +39496,9 @@ msgstr "" msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}" msgstr "" -msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}" -msgstr "" - msgid "TagsPage|Please type the following to confirm:" msgstr "" -msgid "TagsPage|Release notes" -msgstr "" - msgid "TagsPage|Repository has no tags yet." msgstr "" @@ -39511,9 +39520,6 @@ msgstr "" msgid "TagsPage|Use git tag command to add a new one:" msgstr "" -msgid "TagsPage|Write your release notes or drag files here…" -msgstr "" - msgid "TagsPage|Yes, delete protected tag" msgstr "" diff --git a/qa/qa/fixtures/software_licenses/other b/qa/qa/fixtures/software_licenses/other new file mode 100644 index 00000000000..b6652f05dab --- /dev/null +++ b/qa/qa/fixtures/software_licenses/other @@ -0,0 +1,7 @@ +This software is licensed under the Other license +======= + +This Other license isn't a real license and won't be used by any real project. +This license does not come with any guarantees. The author cannot be hold liable +in any way, and users are permitted to do anything they want with the provided +code. \ No newline at end of file diff --git a/qa/qa/page/project/tag/new.rb b/qa/qa/page/project/tag/new.rb index dc59c07ec98..50e11acd94a 100644 --- a/qa/qa/page/project/tag/new.rb +++ b/qa/qa/page/project/tag/new.rb @@ -8,17 +8,9 @@ module QA view 'app/views/projects/tags/new.html.haml' do element :tag_name_field element :tag_message_field - element :release_notes_field element :create_tag_button end - view 'app/views/shared/_zen.html.haml' do - # This partial adds the `release_notes_field` selector passed from 'app/views/projects/tags/new.html.haml' - # The checks below ensure that required lines are not removed without updating this page object - element :_, "qa_selector = local_assigns.fetch(:qa_selector, '')" # rubocop:disable QA/ElementWithPattern - element :_, "text_area_tag attr, current_text, data: { qa_selector: qa_selector }" # rubocop:disable QA/ElementWithPattern - end - def fill_tag_name(text) fill_element(:tag_name_field, text) end @@ -27,10 +19,6 @@ module QA fill_element(:tag_message_field, text) end - def fill_release_notes(text) - fill_element(:release_notes_field, text) - end - def click_create_tag_button click_element :create_tag_button end diff --git a/qa/qa/resource/user.rb b/qa/qa/resource/user.rb index a974446b3cb..71a5e1c8930 100644 --- a/qa/qa/resource/user.rb +++ b/qa/qa/resource/user.rb @@ -44,7 +44,7 @@ module QA alias_method :ldap_username, :username def password - @password ||= SecureRandom.hex(8) + @password ||= "Pa$$w0rd" end alias_method :ldap_password, :password diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/license_detection_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/license_detection_spec.rb index 24b690b75e7..1005f168098 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/license_detection_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/license_detection_spec.rb @@ -36,11 +36,11 @@ module QA end end - context 'on a project with a less commonly used LICENSE', + context 'on a project with an unrecognized LICENSE', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/366843' do it_behaves_like 'project license detection' do - let(:license_file_name) { 'GFDL-1.2-only' } - let(:rendered_license_name) { 'Other' } + let(:license_file_name) { 'other' } + let(:rendered_license_name) { 'LICENSE' } end end end diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/protected_tags_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/protected_tags_spec.rb index 65a15ce96a5..f4ca7955a0f 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/protected_tags_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/protected_tags_spec.rb @@ -31,7 +31,6 @@ module QA Page::Project::Tag::Show.perform do |show| expect(show).to have_tag_name(tag_name) expect(show).to have_tag_message(tag_message) - expect(show).to have_tag_release_notes(tag_release_notes) expect(show).not_to have_element(:create_tag_button) end end @@ -83,7 +82,6 @@ module QA Page::Project::Tag::New.perform do |new_tag| new_tag.fill_tag_name(name) new_tag.fill_tag_message(message) - new_tag.fill_release_notes(release_notes) new_tag.click_create_tag_button end end diff --git a/qa/spec/resource/user_spec.rb b/qa/spec/resource/user_spec.rb index c0140abf298..d82dcc3b21e 100644 --- a/qa/spec/resource/user_spec.rb +++ b/qa/spec/resource/user_spec.rb @@ -23,8 +23,8 @@ RSpec.describe QA::Resource::User do end describe '#password' do - it 'generates a random 16 character password by default' do - expect(subject.password).to match(/\w{16}/) + it 'generates a default password' do + expect(subject.password).to match('Pa$$w0rd') end it 'is possible to set the password' do diff --git a/scripts/gitlab_component_helpers.sh b/scripts/gitlab_component_helpers.sh index d5e63aa162b..0d72f940036 100644 --- a/scripts/gitlab_component_helpers.sh +++ b/scripts/gitlab_component_helpers.sh @@ -39,7 +39,8 @@ export GITLAB_WORKHORSE_PACKAGE="workhorse-${GITLAB_WORKHORSE_TREE}.tar.gz" export GITLAB_WORKHORSE_PACKAGE_URL="${API_PACKAGES_BASE_URL}/${GITLAB_WORKHORSE_FOLDER}/${GITLAB_WORKHORSE_TREE}/${GITLAB_WORKHORSE_PACKAGE}" # Assets constants -export GITLAB_ASSETS_PATHS_LIST="cached-assets-hash.txt app/assets/javascripts/locale/**/app.js public/assets/ tmp/cache/assets/sprockets/ tmp/cache/babel-loader/ tmp/cache/vue-loader/" +export GITLAB_ASSETS_PATHS_LIST="cached-assets-hash.txt app/assets/javascripts/locale/**/app.js public/assets/" +export GITLAB_ASSETS_PACKAGE_VERSION="v2" # bump this version each time GITLAB_ASSETS_PATHS_LIST is changed export GITLAB_EDITION="ee" if [[ "${FOSS_ONLY:-no}" = "1" ]] || [[ "${CI_PROJECT_NAME}" = "gitlab-foss" ]]; then @@ -47,7 +48,7 @@ if [[ "${FOSS_ONLY:-no}" = "1" ]] || [[ "${CI_PROJECT_NAME}" = "gitlab-foss" ]]; fi export GITLAB_ASSETS_HASH="${GITLAB_ASSETS_HASH:-"NO_HASH"}" -export GITLAB_ASSETS_PACKAGE="assets-${NODE_ENV}-${GITLAB_EDITION}-${GITLAB_ASSETS_HASH}.tar.gz" +export GITLAB_ASSETS_PACKAGE="assets-${NODE_ENV}-${GITLAB_EDITION}-${GITLAB_ASSETS_HASH}-${GITLAB_ASSETS_PACKAGE_VERSION}.tar.gz" export GITLAB_ASSETS_PACKAGE_URL="${API_PACKAGES_BASE_URL}/assets/${NODE_ENV}-${GITLAB_EDITION}-${GITLAB_ASSETS_HASH}/${GITLAB_ASSETS_PACKAGE}" # Generic helper functions diff --git a/scripts/rspec_helpers.sh b/scripts/rspec_helpers.sh index fb45f6d80c2..73030d2ad6c 100644 --- a/scripts/rspec_helpers.sh +++ b/scripts/rspec_helpers.sh @@ -297,6 +297,12 @@ function rspec_paralellized_job() { function retry_failed_rspec_examples() { local rspec_run_status=0 + # Sometimes the file isn't created or is empty. In that case we exit(1) ourselves, otherwise, RSpec would + # not run any examples an exit successfully, actually hiding failed tests! + if [[ ! -f "${RSPEC_LAST_RUN_RESULTS_FILE}" ]] || [[ ! -s "${RSPEC_LAST_RUN_RESULTS_FILE}" ]]; then + exit 1 + fi + # Keep track of the tests that are retried, later consolidated in a single file by the `rspec:flaky-tests-report` job local failed_examples=$(grep " failed" ${RSPEC_LAST_RUN_RESULTS_FILE}) echo "${CI_JOB_URL}" > "${RETRIED_TESTS_REPORT_PATH}" diff --git a/spec/features/tags/developer_creates_tag_spec.rb b/spec/features/tags/developer_creates_tag_spec.rb index ca76a94092e..5657115fb3c 100644 --- a/spec/features/tags/developer_creates_tag_spec.rb +++ b/spec/features/tags/developer_creates_tag_spec.rb @@ -46,18 +46,6 @@ RSpec.describe 'Developer creates tag' do end end - it 'with multiline release notes parses the release note as Markdown' do - create_tag_in_form(tag: 'v4.0', ref: 'master', desc: "Awesome release notes\n\n- hello\n- world") - - expect(page).to have_current_path( - project_tag_path(project, 'v4.0'), ignore_query: true) - expect(page).to have_content 'v4.0' - page.within '.description' do - expect(page).to have_content 'Awesome release notes' - expect(page).to have_selector('ul li', count: 2) - end - end - it 'opens dropdown for ref', :js do click_link 'New tag' ref_row = find('.form-group:nth-of-type(2) .col-sm-12') @@ -73,19 +61,6 @@ RSpec.describe 'Developer creates tag' do end end - context 'from new tag page' do - before do - visit new_project_tag_path(project) - end - - it 'description has emoji autocomplete', :js do - find('#release_description').native.send_keys('') - fill_in 'release_description', with: ':' - - expect(page).to have_selector('.atwho-view') - end - end - def create_tag_in_form(tag:, ref:, message: nil, desc: nil) click_link 'New tag' fill_in 'tag_name', with: tag diff --git a/spec/frontend/notes/components/comment_form_spec.js b/spec/frontend/notes/components/comment_form_spec.js index 748cfdf0fb4..701ff492702 100644 --- a/spec/frontend/notes/components/comment_form_spec.js +++ b/spec/frontend/notes/components/comment_form_spec.js @@ -71,11 +71,19 @@ describe('issue_comment_form component', () => { }; const notableDataMockCanUpdateIssuable = createNotableDataMock({ - current_user: { can_update: true, can_create_note: true }, + current_user: { can_update: true, can_create_note: true, can_create_confidential_note: true }, }); const notableDataMockCannotUpdateIssuable = createNotableDataMock({ - current_user: { can_update: false, can_create_note: true }, + current_user: { + can_update: false, + can_create_note: false, + can_create_confidential_note: false, + }, + }); + + const notableDataMockCannotCreateConfidentialNote = createNotableDataMock({ + current_user: { can_update: false, can_create_note: true, can_create_confidential_note: false }, }); const mountComponent = ({ @@ -562,6 +570,17 @@ describe('issue_comment_form component', () => { expect(checkbox.element.checked).toBe(false); }); + it('should not render checkbox if user is not at least a reporter', () => { + mountComponent({ + mountFunction: mount, + initialData: { note: 'confidential note' }, + noteableData: { ...notableDataMockCannotCreateConfidentialNote }, + }); + + const checkbox = findConfidentialNoteCheckbox(); + expect(checkbox.exists()).toBe(false); + }); + it.each` noteableType | rendered | message ${'Issue'} | ${true} | ${'render'} diff --git a/spec/frontend/notes/mock_data.js b/spec/frontend/notes/mock_data.js index 882e466dd05..286f2adc1d8 100644 --- a/spec/frontend/notes/mock_data.js +++ b/spec/frontend/notes/mock_data.js @@ -36,6 +36,7 @@ export const noteableDataMock = { can_create_note: true, can_update: true, can_award_emoji: true, + can_create_confidential_note: true, }, description: '', due_date: null, diff --git a/spec/frontend/packages_and_registries/package_registry/pages/details_spec.js b/spec/frontend/packages_and_registries/package_registry/pages/details_spec.js index 0ff49d62b03..a32e76a132e 100644 --- a/spec/frontend/packages_and_registries/package_registry/pages/details_spec.js +++ b/spec/frontend/packages_and_registries/package_registry/pages/details_spec.js @@ -1,4 +1,4 @@ -import { GlEmptyState, GlBadge, GlTabs, GlTab } from '@gitlab/ui'; +import { GlEmptyState, GlBadge, GlTabs, GlTab, GlSprintf } from '@gitlab/ui'; import Vue, { nextTick } from 'vue'; import VueApollo from 'vue-apollo'; @@ -86,11 +86,17 @@ describe('PackagesApp', () => { PackageTitle, DeletePackage, GlModal: { - template: '
', + template: ` +
+ +

+
+ `, methods: { show: jest.fn(), }, }, + GlSprintf, GlTabs, GlTab, }, @@ -245,7 +251,9 @@ describe('PackagesApp', () => { await findDeleteButton().trigger('click'); - expect(findDeleteModal().exists()).toBe(true); + expect(findDeleteModal().find('p').text()).toBe( + 'You are about to delete version 1.0.0 of @gitlab-org/package-15. Are you sure?', + ); }); describe('successful request', () => { @@ -359,6 +367,12 @@ describe('PackagesApp', () => { expect(showDeletePackageSpy).toHaveBeenCalled(); expect(showDeleteFileSpy).not.toHaveBeenCalled(); + + await waitForPromises(); + + expect(findDeleteModal().find('p').text()).toBe( + 'Deleting the last package asset will remove version 1.0.0 of @gitlab-org/package-15. Are you sure?', + ); }); it('confirming on the modal sets the loading state', async () => { @@ -533,6 +547,12 @@ describe('PackagesApp', () => { findPackageFiles().vm.$emit('delete-files', packageFiles()); expect(showDeletePackageSpy).toHaveBeenCalled(); + + await waitForPromises(); + + expect(findDeleteModal().find('p').text()).toBe( + 'Deleting all package assets will remove version 1.0.0 of @gitlab-org/package-15. Are you sure?', + ); }); }); }); diff --git a/spec/frontend/runner/components/runner_list_empty_state_spec.js b/spec/frontend/runner/components/runner_list_empty_state_spec.js index 59cff863106..038162b889e 100644 --- a/spec/frontend/runner/components/runner_list_empty_state_spec.js +++ b/spec/frontend/runner/components/runner_list_empty_state_spec.js @@ -8,6 +8,7 @@ import RunnerListEmptyState from '~/runner/components/runner_list_empty_state.vu const mockSvgPath = 'mock-svg-path.svg'; const mockFilteredSvgPath = 'mock-filtered-svg-path.svg'; +const mockRegistrationToken = 'REGISTRATION_TOKEN'; describe('RunnerListEmptyState', () => { let wrapper; @@ -21,6 +22,7 @@ describe('RunnerListEmptyState', () => { propsData: { svgPath: mockSvgPath, filteredSvgPath: mockFilteredSvgPath, + registrationToken: mockRegistrationToken, ...props, }, directives: { @@ -35,27 +37,52 @@ describe('RunnerListEmptyState', () => { }; describe('when search is not filtered', () => { - beforeEach(() => { - createComponent(); + const title = s__('Runners|Get started with runners'); + + describe('when there is a registration token', () => { + beforeEach(() => { + createComponent(); + }); + + it('renders an illustration', () => { + expect(findEmptyState().props('svgPath')).toBe(mockSvgPath); + }); + + it('displays "no results" text with instructions', () => { + const desc = s__( + 'Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner.', + ); + + expect(findEmptyState().text()).toMatchInterpolatedText(`${title} ${desc}`); + }); + + it('opens a runner registration instructions modal with a link', () => { + const { value } = getBinding(findLink().element, 'gl-modal'); + + expect(findRunnerInstructionsModal().props('modalId')).toEqual(value); + }); }); - it('renders an illustration', () => { - expect(findEmptyState().props('svgPath')).toBe(mockSvgPath); - }); + describe('when there is no registration token', () => { + beforeEach(() => { + createComponent({ props: { registrationToken: null } }); + }); - it('displays "no results" text', () => { - const title = s__('Runners|Get started with runners'); - const desc = s__( - 'Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner.', - ); + it('renders an illustration', () => { + expect(findEmptyState().props('svgPath')).toBe(mockSvgPath); + }); - expect(findEmptyState().text()).toMatchInterpolatedText(`${title} ${desc}`); - }); + it('displays "no results" text', () => { + const desc = s__( + 'Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator.', + ); - it('opens a runner registration instructions modal with a link', () => { - const { value } = getBinding(findLink().element, 'gl-modal'); + expect(findEmptyState().text()).toMatchInterpolatedText(`${title} ${desc}`); + }); - expect(findRunnerInstructionsModal().props('modalId')).toEqual(value); + it('has no registration instructions link', () => { + expect(findLink().exists()).toBe(false); + }); }); }); diff --git a/spec/frontend/vue_merge_request_widget/components/widget/widget_content_row_spec.js b/spec/frontend/vue_merge_request_widget/components/widget/widget_content_row_spec.js index 4c2578ff590..9eddd091ad0 100644 --- a/spec/frontend/vue_merge_request_widget/components/widget/widget_content_row_spec.js +++ b/spec/frontend/vue_merge_request_widget/components/widget/widget_content_row_spec.js @@ -35,11 +35,13 @@ describe('~/vue_merge_request_widget/components/widget/widget_content_row.vue', statusIconName: 'success', }, slots: { + header: 'this is a header', body: 'this is a body', }, }); expect(wrapper.findByText('this is a body').exists()).toBe(true); + expect(wrapper.findByText('this is a header').exists()).toBe(true); }); }); diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index 6f1f0a854cd..f3d3fd2034c 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -1801,7 +1801,7 @@ RSpec.describe Gitlab::Git::Repository do subject(:license) { repository.license(from_gitaly) } context 'when no license file can be found' do - let(:project) { create(:project, :repository) } + let_it_be(:project) { create(:project, :repository) } let(:repository) { project.repository.raw_repository } before do @@ -1814,9 +1814,25 @@ RSpec.describe Gitlab::Git::Repository do context 'when an mit license is found' do it { is_expected.to have_attributes(key: 'mit') } end + + context 'when license is not recognized ' do + let_it_be(:project) { create(:project, :repository) } + let(:repository) { project.repository.raw_repository } + + before do + project.repository.update_file( + project.owner, + 'LICENSE', + 'This software is licensed under the Dummy license.', + message: 'Update license', + branch_name: 'master') + end + + it { is_expected.to have_attributes(key: 'other', nickname: 'LICENSE') } + end end - it 'does not crash when license is not recognized' do + it 'does not crash when license is invalid' do expect(Licensee::License).to receive(:new) .and_raise(Licensee::InvalidLicense) diff --git a/spec/lib/gitlab/usage/metrics/aggregates/aggregate_spec.rb b/spec/lib/gitlab/usage/metrics/aggregates/aggregate_spec.rb index be50685a4f1..76eec2755df 100644 --- a/spec/lib/gitlab/usage/metrics/aggregates/aggregate_spec.rb +++ b/spec/lib/gitlab/usage/metrics/aggregates/aggregate_spec.rb @@ -235,10 +235,27 @@ RSpec.describe Gitlab::Usage::Metrics::Aggregates::Aggregate, :clean_gitlab_redi end end - it 'allows for YAML aliases in aggregated metrics configs' do - expect(YAML).to receive(:safe_load).with(kind_of(String), aliases: true).at_least(:once) + context 'legacy aggregated metrics configuration' do + let(:temp_dir) { Dir.mktmpdir } + let(:temp_file) { Tempfile.new(%w[common .yml], temp_dir) } - described_class.new(recorded_at) + before do + stub_const("#{namespace}::AGGREGATED_METRICS_PATH", File.expand_path('*.yml', temp_dir)) + File.open(temp_file.path, "w+b") do |file| + file.write [aggregated_metric(name: "gmau_1", time_frame: '7d')].to_yaml + end + end + + after do + temp_file.unlink + FileUtils.remove_entry(temp_dir) if Dir.exist?(temp_dir) + end + + it 'allows for YAML aliases in aggregated metrics configs' do + expect(YAML).to receive(:safe_load).with(kind_of(String), aliases: true).at_least(:once) + + described_class.new(recorded_at) + end end describe '.aggregated_metrics_weekly_data' do diff --git a/spec/policies/issue_policy_spec.rb b/spec/policies/issue_policy_spec.rb index 49c0fd004bc..c110ca705bd 100644 --- a/spec/policies/issue_policy_spec.rb +++ b/spec/policies/issue_policy_spec.rb @@ -85,7 +85,7 @@ RSpec.describe IssuePolicy do it 'allows guests to read issues' do expect(permissions(guest, issue)).to be_allowed(:read_issue, :read_issue_iid) - expect(permissions(guest, issue)).to be_disallowed(:update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality) + expect(permissions(guest, issue)).to be_disallowed(:update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality, :mark_note_as_confidential) expect(permissions(guest, issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid) expect(permissions(guest, issue_no_assignee)).to be_disallowed(:update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality) @@ -93,10 +93,10 @@ RSpec.describe IssuePolicy do expect(permissions(guest, new_issue)).to be_allowed(:create_issue, :set_issue_metadata, :set_confidentiality) end - it 'allows reporters to read, update, and admin issues' do + it 'allows reporters to read, update, admin and create confidential notes' do expect(permissions(reporter, issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality) expect(permissions(reporter, issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality) - expect(permissions(reporter, new_issue)).to be_allowed(:create_issue, :set_issue_metadata, :set_confidentiality) + expect(permissions(reporter, new_issue)).to be_allowed(:create_issue, :set_issue_metadata, :set_confidentiality, :mark_note_as_confidential) end it 'allows reporters from group links to read, update, and admin issues' do diff --git a/spec/serializers/issue_entity_spec.rb b/spec/serializers/issue_entity_spec.rb index 9335ca61b7d..25e9e8c17e2 100644 --- a/spec/serializers/issue_entity_spec.rb +++ b/spec/serializers/issue_entity_spec.rb @@ -150,4 +150,6 @@ RSpec.describe IssueEntity do end end end + + it_behaves_like 'issuable entity current_user properties' end diff --git a/spec/support/shared_examples/serializers/issuable_current_user_properties_shared_examples.rb b/spec/support/shared_examples/serializers/issuable_current_user_properties_shared_examples.rb new file mode 100644 index 00000000000..6c285bfba91 --- /dev/null +++ b/spec/support/shared_examples/serializers/issuable_current_user_properties_shared_examples.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'issuable entity current_user properties' do + describe 'can_create_confidential_note' do + subject do + described_class.new(resource, request: request) + .as_json[:current_user][:can_create_confidential_note] + end + + context 'when user can create confidential notes' do + before do + resource.resource_parent.add_reporter(user) + end + + it { is_expected.to be(true) } + end + + context 'when user cannot create confidential notes' do + it { is_expected.to eq(false) } + end + end +end