diff options
52 files changed, 360 insertions, 124 deletions
diff --git a/.gitlab/issue_templates/Feature proposal.md b/.gitlab/issue_templates/Feature proposal.md index 2bbef723b21..4b98b4e7ac6 100644 --- a/.gitlab/issue_templates/Feature proposal.md +++ b/.gitlab/issue_templates/Feature proposal.md @@ -1,11 +1,15 @@ +<!-- The first three sections: "Problem to solve", "Intended users" and "Proposal", are strongly recommended, while the rest of the sections can be filled out during the problem validation or breakdown phase. However, keep in mind that providing complete and relevant information early helps our product team validate the problem and start working on a solution. --> + ### Problem to solve -<!-- What problem do we solve? --> +<!-- What problem do we solve? Try to define the who/what/why of the opportunity as a user story. For example, "As a (who), I want (what), so I can (why/value)." --> ### Intended users <!-- Who will use this feature? If known, include any of the following: types of users (e.g. Developer), personas, or specific company roles (e.g. Release Manager). It's okay to write "Unknown" and fill this field in later. +Personas are described at https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/ + * [Rachel (Release Manager)](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#rachel-release-manager) * [Parker (Product Manager)](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#parker-product-manager) * [Delaney (Development Team Lead)](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#delaney-development-team-lead) @@ -16,13 +20,11 @@ * [Sam (Security Analyst)](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#sam-security-analyst) * [Dana (Data Analyst)](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#dana-data-analyst) * [Simone (Software Engineer in Test)](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#simone-software-engineer-in-test) -* [Allison (Application Ops)](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#allison-application-ops) - -Personas are described at https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/ --> +* [Allison (Application Ops)](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#allison-application-ops) --> ### Further details -<!-- Include use cases, benefits, and/or goals (contributes to our vision?) --> +<!-- Include use cases, benefits, goals, or any other details that will help us understand the problem better. --> ### Proposal @@ -35,14 +37,15 @@ Personas are described at https://about.gitlab.com/handbook/marketing/product-ma ### Documentation <!-- See the Feature Change Documentation Workflow https://docs.gitlab.com/ee/development/documentation/feature-change-workflow.html -Add all known Documentation Requirements here, per https://docs.gitlab.com/ee/development/documentation/feature-change-workflow.html#documentation-requirements -If this feature requires changing permissions, this document https://docs.gitlab.com/ee/user/permissions.html must be updated accordingly. --> + +* Add all known Documentation Requirements in this section. See https://docs.gitlab.com/ee/development/documentation/feature-change-workflow.html#documentation-requirements +* If this feature requires changing permissions, update the permissions document. See https://docs.gitlab.com/ee/user/permissions.html --> ### Availability & Testing <!-- This section needs to be retained and filled in during the workflow planning breakdown phase of this feature proposal, if not earlier. - What risks does this change pose to our availability? How might it affect the quality of the product? What additional test coverage or changes to tests will be needed? Will it require cross-browser testing? +What risks does this change pose to our availability? How might it affect the quality of the product? What additional test coverage or changes to tests will be needed? Will it require cross-browser testing? Please list the test areas (unit, integration and end-to-end) that needs to be added or updated to ensure that this feature will work as intended. Please use the list below as guidance. * Unit test changes @@ -57,7 +60,8 @@ See the test engineering planning process and reach out to your counterpart Soft ### What is the type of buyer? -<!-- Which leads to: in which enterprise tier should this feature go? See https://about.gitlab.com/handbook/product/pricing/#four-tiers --> +<!-- What is the buyer persona for this feature? See https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/buyer-persona/ +In which enterprise tier should this feature go? See https://about.gitlab.com/handbook/product/pricing/#four-tiers --> ### Is this a cross-stage feature? diff --git a/.rubocop.yml b/.rubocop.yml index 4262fd9ca74..830503a1497 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -217,12 +217,10 @@ Gitlab/DuplicateSpecLocation: - ee/spec/helpers/auth_helper_spec.rb - ee/spec/lib/gitlab/gl_repository_spec.rb - ee/spec/models/namespace_spec.rb - - ee/spec/services/merge_requests/create_service_spec.rb - ee/spec/services/merge_requests/refresh_service_spec.rb - ee/spec/services/merge_requests/update_service_spec.rb - ee/spec/helpers/ee/auth_helper_spec.rb - ee/spec/models/ee/namespace_spec.rb - - ee/spec/services/ee/merge_requests/create_service_spec.rb - ee/spec/services/ee/merge_requests/refresh_service_spec.rb - ee/spec/services/ee/merge_requests/update_service_spec.rb @@ -398,7 +396,6 @@ RSpec/RepeatedExample: - 'spec/graphql/gitlab_schema_spec.rb' - 'spec/helpers/users_helper_spec.rb' - 'spec/lib/gitlab/closing_issue_extractor_spec.rb' - - 'spec/lib/gitlab/danger/changelog_spec.rb' - 'spec/lib/gitlab/import_export/project/relation_factory_spec.rb' - 'spec/rubocop/cop/migration/update_large_table_spec.rb' - 'spec/services/notification_service_spec.rb' diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue index 2229b6d8292..9db29f327da 100644 --- a/app/assets/javascripts/monitoring/components/dashboard.vue +++ b/app/assets/javascripts/monitoring/components/dashboard.vue @@ -478,7 +478,7 @@ export default { :title="s__('Metrics|Reload this page')" @click="refreshDashboard" > - <icon name="repeat" /> + <icon name="retry" /> </gl-deprecated-button> </gl-form-group> diff --git a/app/assets/stylesheets/utilities.scss b/app/assets/stylesheets/utilities.scss index 925c15262e9..0a1e97d1252 100644 --- a/app/assets/stylesheets/utilities.scss +++ b/app/assets/stylesheets/utilities.scss @@ -76,10 +76,16 @@ .gl-bg-green-100 { @include gl-bg-green-100;} .gl-text-blue-500 { @include gl-text-blue-500; } +.gl-text-gray-500 { @include gl-text-gray-500; } .gl-text-gray-700 { @include gl-text-gray-700; } .gl-text-gray-900 { @include gl-text-gray-900; } .gl-text-red-700 { @include gl-text-red-700; } +.gl-text-red-900 { @include gl-text-red-900; } +.gl-text-orange-400 { @include gl-text-orange-400; } +.gl-text-orange-500 { @include gl-text-orange-500; } +.gl-text-orange-600 { @include gl-text-orange-600; } .gl-text-orange-700 { @include gl-text-orange-700; } +.gl-text-green-500 { @include gl-text-green-500; } .gl-text-green-700 { @include gl-text-green-700; } .gl-align-items-center { @include gl-align-items-center; } diff --git a/app/graphql/types/snippet_type.rb b/app/graphql/types/snippet_type.rb index 7affcae9f8f..4ebdbd5766c 100644 --- a/app/graphql/types/snippet_type.rb +++ b/app/graphql/types/snippet_type.rb @@ -67,10 +67,12 @@ module Types field :ssh_url_to_repo, type: GraphQL::STRING_TYPE, description: 'SSH URL to the snippet repository', + calls_gitaly: true, null: true field :http_url_to_repo, type: GraphQL::STRING_TYPE, description: 'HTTP URL to the snippet repository', + calls_gitaly: true, null: true markdown_field :description_html, null: true, method: :description diff --git a/app/models/project_wiki.rb b/app/models/project_wiki.rb index 50ce1c67453..f0967b87345 100644 --- a/app/models/project_wiki.rb +++ b/app/models/project_wiki.rb @@ -39,6 +39,7 @@ class ProjectWiki def full_path @project.full_path + '.wiki' end + alias_method :id, :full_path # @deprecated use full_path when you need it for an URL route or disk_path when you want to point to the filesystem alias_method :path_with_namespace, :full_path diff --git a/app/models/snippet.rb b/app/models/snippet.rb index edf524190e4..973bdc54111 100644 --- a/app/models/snippet.rb +++ b/app/models/snippet.rb @@ -310,7 +310,7 @@ class Snippet < ApplicationRecord end def versioned_enabled_for?(user) - repository_exists? && ::Feature.enabled?(:version_snippets, user) + ::Feature.enabled?(:version_snippets, user) && repository_exists? end class << self diff --git a/app/models/user.rb b/app/models/user.rb index 4d450f9305f..343edfae799 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -58,6 +58,8 @@ class User < ApplicationRecord BLOCKED_MESSAGE = "Your account has been blocked. Please contact your GitLab " \ "administrator if you think this is an error." + LOGIN_FORBIDDEN = "Your account does not have the required permission to login. Please contact your GitLab " \ + "administrator if you think this is an error." MINIMUM_INACTIVE_DAYS = 180 @@ -299,14 +301,6 @@ class User < ApplicationRecord def blocked? true end - - def active_for_authentication? - false - end - - def inactive_message - BLOCKED_MESSAGE - end end before_transition do @@ -354,6 +348,20 @@ class User < ApplicationRecord .expiring_and_not_notified(at).select(1)) end + def active_for_authentication? + super && can?(:log_in) + end + + def inactive_message + if blocked? + BLOCKED_MESSAGE + elsif internal? + LOGIN_FORBIDDEN + else + super + end + end + def self.with_visible_profile(user) return with_public_profile if user.nil? @@ -1701,6 +1709,10 @@ class User < ApplicationRecord members.non_request.maximum(:access_level) end + def confirmation_required_on_sign_in? + !confirmed? && !confirmation_period_valid? + end + protected # override, from Devise::Validatable diff --git a/app/policies/base_policy.rb b/app/policies/base_policy.rb index ce3e5b0195c..2c26ba565ab 100644 --- a/app/policies/base_policy.rb +++ b/app/policies/base_policy.rb @@ -25,8 +25,7 @@ class BasePolicy < DeclarativePolicy::Base with_options scope: :user, score: 0 condition(:inactive) do Feature.enabled?(:inactive_policy_condition, default_enabled: true) && - @user && - !@user&.active_for_authentication? + @user&.confirmation_required_on_sign_in? || @user&.access_locked? end with_options scope: :user, score: 0 diff --git a/changelogs/unreleased/213136-move-features-to-core-design-management.yml b/changelogs/unreleased/213136-move-features-to-core-design-management.yml new file mode 100644 index 00000000000..4f66561b0c3 --- /dev/null +++ b/changelogs/unreleased/213136-move-features-to-core-design-management.yml @@ -0,0 +1,5 @@ +--- +title: Remove design management as a license feature +merge_request: 28589 +author: +type: added diff --git a/changelogs/unreleased/changelog-spec.yml b/changelogs/unreleased/changelog-spec.yml new file mode 100644 index 00000000000..dd846b4360f --- /dev/null +++ b/changelogs/unreleased/changelog-spec.yml @@ -0,0 +1,5 @@ +--- +title: Remove duplicate spec from changelog spec +merge_request: 28801 +author: Rajendra Kadam +type: added diff --git a/changelogs/unreleased/feat-x509-signatures-api-endpoint.yml b/changelogs/unreleased/feat-x509-signatures-api-endpoint.yml new file mode 100644 index 00000000000..54741da3c5f --- /dev/null +++ b/changelogs/unreleased/feat-x509-signatures-api-endpoint.yml @@ -0,0 +1,5 @@ +--- +title: Add api endpoint to get x509 signature +merge_request: 28590 +author: Roger Meier +type: added diff --git a/changelogs/unreleased/jivanvl-replace-refresh-icon-monitoring-dashboard.yml b/changelogs/unreleased/jivanvl-replace-refresh-icon-monitoring-dashboard.yml new file mode 100644 index 00000000000..1130cceec2d --- /dev/null +++ b/changelogs/unreleased/jivanvl-replace-refresh-icon-monitoring-dashboard.yml @@ -0,0 +1,5 @@ +--- +title: Change redo for retry icon in metrics dashboard +merge_request: 28670 +author: +type: other diff --git a/changelogs/unreleased/vij-snippet-repo-urls-fix.yml b/changelogs/unreleased/vij-snippet-repo-urls-fix.yml new file mode 100644 index 00000000000..167f0bf5b8e --- /dev/null +++ b/changelogs/unreleased/vij-snippet-repo-urls-fix.yml @@ -0,0 +1,5 @@ +--- +title: Fix GraphQL SnippetType repo urls +merge_request: 28673 +author: +type: fixed diff --git a/doc/api/commits.md b/doc/api/commits.md index 02fb260d010..356f090f0ff 100644 --- a/doc/api/commits.md +++ b/doc/api/commits.md @@ -741,19 +741,43 @@ Parameters: curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/repository/commits/da738facbc19eb2fc2cef57c49be0e6038570352/signature" ``` -Example response if commit is signed: +Example response if commit is GPG signed: ```json { + "signature_type": "PGP", + "verification_status": "verified", "gpg_key_id": 1, "gpg_key_primary_keyid": "8254AAB3FBD54AC9", "gpg_key_user_name": "John Doe", "gpg_key_user_email": "johndoe@example.com", - "verification_status": "verified", "gpg_key_subkey_id": null } ``` +Example response if commit is x509 signed: + +```json +{ + "signature_type": "X509", + "verification_status": "unverified", + "x509_certificate": { + "id": 1, + "subject": "CN=gitlab@example.org,OU=Example,O=World", + "subject_key_identifier": "BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC", + "email": "gitlab@example.org", + "serial_number": 278969561018901340486471282831158785578, + "certificate_status": "good", + "x509_issuer": { + "id": 1, + "subject": "CN=PKI,OU=Example,O=World", + "subject_key_identifier": "AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB", + "crl_url": "http://example.com/pki.crl" + } + } +} +``` + Example response if commit is unsigned: ```json diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md index 1ec4c154039..81b9cd8bece 100644 --- a/doc/ci/variables/README.md +++ b/doc/ci/variables/README.md @@ -4,7 +4,7 @@ type: reference # GitLab CI/CD environment variables -After a brief overview over the use of environment +After a brief overview of the use of environment variables, this document teaches you how to use GitLab CI/CD's variables, presents the full reference for predefined variables, and dives into more advanced applications. @@ -715,8 +715,8 @@ if [[ -d "/builds/gitlab-examples/ci-debug-trace/.git" ]]; then ++ CI_SERVER_VERSION_PATCH=0 ++ export CI_SERVER_REVISION=f4cc00ae823 ++ CI_SERVER_REVISION=f4cc00ae823 -++ export GITLAB_FEATURES=audit_events,burndown_charts,code_owners,contribution_analytics,description_diffs,elastic_search,export_issues,group_bulk_edit,group_burndown_charts,group_webhooks,issuable_default_templates,issue_board_focus_mode,issue_weights,jenkins_integration,ldap_group_sync,member_lock,merge_request_approvers,multiple_issue_assignees,multiple_ldap_servers,multiple_merge_request_assignees,protected_refs_for_users,push_rules,related_issues,repository_mirrors,repository_size_limit,scoped_issue_board,usage_quotas,visual_review_app,wip_limits,adjourned_deletion_for_projects_and_groups,admin_audit_log,auditor_user,batch_comments,blocking_merge_requests,board_assignee_lists,board_milestone_lists,ci_cd_projects,cluster_deployments,code_analytics,code_owner_approval_required,commit_committer_check,cross_project_pipelines,custom_file_templates,custom_file_templates_for_namespace,custom_project_templates,custom_prometheus_metrics,cycle_analytics_for_groups,db_load_balancing,default_project_deletion_protection,dependency_proxy,deploy_board,design_management,email_additional_text,extended_audit_events,external_authorization_service_api_management,feature_flags,file_locks,geo,github_project_service_integration,group_allowed_email_domains,group_project_templates,group_saml,issues_analytics,jira_dev_panel_integration,ldap_group_sync_filter,merge_pipelines,merge_request_performance_metrics,merge_trains,metrics_reports,multiple_approval_rules,multiple_clusters,multiple_group_issue_boards,object_storage,operations_dashboard,packages,productivity_analytics,project_aliases,protected_environments,reject_unsigned_commits,required_ci_templates,scoped_labels,service_desk,smartcard_auth,group_timelogs,type_of_work_analytics,unprotection_restrictions,ci_project_subscriptions,cluster_health,container_scanning,dast,dependency_scanning,epics,group_ip_restriction,incident_management,insights,license_management,personal_access_token_expiration_policy,pod_logs,prometheus_alerts,pseudonymizer,report_approver_rules,sast,security_dashboard,tracing,web_ide_terminal -++ GITLAB_FEATURES=audit_events,burndown_charts,code_owners,contribution_analytics,description_diffs,elastic_search,export_issues,group_bulk_edit,group_burndown_charts,group_webhooks,issuable_default_templates,issue_board_focus_mode,issue_weights,jenkins_integration,ldap_group_sync,member_lock,merge_request_approvers,multiple_issue_assignees,multiple_ldap_servers,multiple_merge_request_assignees,protected_refs_for_users,push_rules,related_issues,repository_mirrors,repository_size_limit,scoped_issue_board,usage_quotas,visual_review_app,wip_limits,adjourned_deletion_for_projects_and_groups,admin_audit_log,auditor_user,batch_comments,blocking_merge_requests,board_assignee_lists,board_milestone_lists,ci_cd_projects,cluster_deployments,code_analytics,code_owner_approval_required,commit_committer_check,cross_project_pipelines,custom_file_templates,custom_file_templates_for_namespace,custom_project_templates,custom_prometheus_metrics,cycle_analytics_for_groups,db_load_balancing,default_project_deletion_protection,dependency_proxy,deploy_board,design_management,email_additional_text,extended_audit_events,external_authorization_service_api_management,feature_flags,file_locks,geo,github_project_service_integration,group_allowed_email_domains,group_project_templates,group_saml,issues_analytics,jira_dev_panel_integration,ldap_group_sync_filter,merge_pipelines,merge_request_performance_metrics,merge_trains,metrics_reports,multiple_approval_rules,multiple_clusters,multiple_group_issue_boards,object_storage,operations_dashboard,packages,productivity_analytics,project_aliases,protected_environments,reject_unsigned_commits,required_ci_templates,scoped_labels,service_desk,smartcard_auth,group_timelogs,type_of_work_analytics,unprotection_restrictions,ci_project_subscriptions,cluster_health,container_scanning,dast,dependency_scanning,epics,group_ip_restriction,incident_management,insights,license_management,personal_access_token_expiration_policy,pod_logs,prometheus_alerts,pseudonymizer,report_approver_rules,sast,security_dashboard,tracing,web_ide_terminal +++ export GITLAB_FEATURES=audit_events,burndown_charts,code_owners,contribution_analytics,description_diffs,elastic_search,export_issues,group_bulk_edit,group_burndown_charts,group_webhooks,issuable_default_templates,issue_weights,jenkins_integration,ldap_group_sync,member_lock,merge_request_approvers,multiple_issue_assignees,multiple_ldap_servers,multiple_merge_request_assignees,protected_refs_for_users,push_rules,related_issues,repository_mirrors,repository_size_limit,scoped_issue_board,usage_quotas,visual_review_app,wip_limits,adjourned_deletion_for_projects_and_groups,admin_audit_log,auditor_user,batch_comments,blocking_merge_requests,board_assignee_lists,board_milestone_lists,ci_cd_projects,cluster_deployments,code_analytics,code_owner_approval_required,commit_committer_check,cross_project_pipelines,custom_file_templates,custom_file_templates_for_namespace,custom_project_templates,custom_prometheus_metrics,cycle_analytics_for_groups,db_load_balancing,default_project_deletion_protection,dependency_proxy,deploy_board,design_management,email_additional_text,extended_audit_events,external_authorization_service_api_management,feature_flags,file_locks,geo,github_project_service_integration,group_allowed_email_domains,group_project_templates,group_saml,issues_analytics,jira_dev_panel_integration,ldap_group_sync_filter,merge_pipelines,merge_request_performance_metrics,merge_trains,metrics_reports,multiple_approval_rules,multiple_clusters,multiple_group_issue_boards,object_storage,operations_dashboard,packages,productivity_analytics,project_aliases,protected_environments,reject_unsigned_commits,required_ci_templates,scoped_labels,service_desk,smartcard_auth,group_timelogs,type_of_work_analytics,unprotection_restrictions,ci_project_subscriptions,cluster_health,container_scanning,dast,dependency_scanning,epics,group_ip_restriction,incident_management,insights,license_management,personal_access_token_expiration_policy,pod_logs,prometheus_alerts,pseudonymizer,report_approver_rules,sast,security_dashboard,tracing,web_ide_terminal +++ GITLAB_FEATURES=audit_events,burndown_charts,code_owners,contribution_analytics,description_diffs,elastic_search,export_issues,group_bulk_edit,group_burndown_charts,group_webhooks,issuable_default_templates,issue_weights,jenkins_integration,ldap_group_sync,member_lock,merge_request_approvers,multiple_issue_assignees,multiple_ldap_servers,multiple_merge_request_assignees,protected_refs_for_users,push_rules,related_issues,repository_mirrors,repository_size_limit,scoped_issue_board,usage_quotas,visual_review_app,wip_limits,adjourned_deletion_for_projects_and_groups,admin_audit_log,auditor_user,batch_comments,blocking_merge_requests,board_assignee_lists,board_milestone_lists,ci_cd_projects,cluster_deployments,code_analytics,code_owner_approval_required,commit_committer_check,cross_project_pipelines,custom_file_templates,custom_file_templates_for_namespace,custom_project_templates,custom_prometheus_metrics,cycle_analytics_for_groups,db_load_balancing,default_project_deletion_protection,dependency_proxy,deploy_board,design_management,email_additional_text,extended_audit_events,external_authorization_service_api_management,feature_flags,file_locks,geo,github_project_service_integration,group_allowed_email_domains,group_project_templates,group_saml,issues_analytics,jira_dev_panel_integration,ldap_group_sync_filter,merge_pipelines,merge_request_performance_metrics,merge_trains,metrics_reports,multiple_approval_rules,multiple_clusters,multiple_group_issue_boards,object_storage,operations_dashboard,packages,productivity_analytics,project_aliases,protected_environments,reject_unsigned_commits,required_ci_templates,scoped_labels,service_desk,smartcard_auth,group_timelogs,type_of_work_analytics,unprotection_restrictions,ci_project_subscriptions,cluster_health,container_scanning,dast,dependency_scanning,epics,group_ip_restriction,incident_management,insights,license_management,personal_access_token_expiration_policy,pod_logs,prometheus_alerts,pseudonymizer,report_approver_rules,sast,security_dashboard,tracing,web_ide_terminal ++ export CI_PROJECT_ID=17893 ++ CI_PROJECT_ID=17893 ++ export CI_PROJECT_NAME=ci-debug-trace diff --git a/doc/development/testing_guide/frontend_testing.md b/doc/development/testing_guide/frontend_testing.md index 141d1db1bf6..429ec262250 100644 --- a/doc/development/testing_guide/frontend_testing.md +++ b/doc/development/testing_guide/frontend_testing.md @@ -550,8 +550,9 @@ The more challenging part are mocks, which can be used for functions or even dep Manual mocks are used to mock modules across the entire Jest environment. This is a very powerful testing tool that helps simplify unit testing by mocking out modules which cannot be easily consumned in our test environment. -> NOTE: Do not use manual mocks if a mock should not be consistently applied (i.e. it's only needed by a few specs). -> Instead, consider using `jest.mock` in the relevant spec file. +> **WARNING:** Do not use manual mocks if a mock should not be consistently applied in every spec (i.e. it's only needed by a few specs). +> Instead, consider using [`jest.mock(..)`](https://jestjs.io/docs/en/jest-object#jestmockmodulename-factory-options) +> (or a similar mocking function) in the relevant spec file. #### Where should I put manual mocks? @@ -568,23 +569,27 @@ If a manual mock is needed for a CE module, please place it in `spec/frontend/mo - We don't support mocking EE modules yet. - If a mock is found for which a source module doesn't exist, the test suite will fail. 'Virtual' mocks, or mocks that don't have a 1-to-1 association with a source module, are not supported yet. -### Writing a mock +#### Manual mock examples -Create a JS module in the appropriate place in `spec/frontend/mocks/`. That's it. It will automatically mock its source package in all tests. +- [`mocks/axios_utils`](https://gitlab.com/gitlab-org/gitlab/blob/bd20aeb64c4eed117831556c54b40ff4aee9bfd1/spec/frontend/mocks/ce/lib/utils/axios_utils.js#L1) - + This mock is helpful because we don't want any unmocked requests to pass any tests. Also, we are able to inject some test helpers such as `axios.waitForAll`. +- [`__mocks__/mousetrap/index.js`](https://gitlab.com/gitlab-org/gitlab/blob/cd4c086d894226445be9d18294a060ba46572435/spec/frontend/__mocks__/mousetrap/index.js#L1) - + This mock is helpful because the module itself uses amd format which webpack understands, but is incompatible with the jest environment. This mock doesn't remove + any behavior, only provides a nice es6 compatible wrapper. +- [`__mocks__/monaco-editor/index.js`](https://gitlab.com/gitlab-org/gitlab/blob/b7f914cddec9fc5971238cdf12766e79fa1629d7/spec/frontend/__mocks__/monaco-editor/index.js) - + This mock is helpful because the monaco package is completely incompatible in a Jest environment. In fact, webpack requires a special loader to make it work. This mock + simply makes this package consumable by Jest. -Make sure that your mock's export has the same format as the mocked module. So, if you're mocking a CommonJS module, you'll need to use `module.exports` instead of the ES6 `export`. - -It might be useful for a mock to expose a property that indicates if the mock was loaded. This way, tests can assert the presence of a mock without calling any logic and causing side-effects. The `~/lib/utils/axios_utils` module mock has such a property, `isMock`, that is `true` in the mock and undefined in the original class. Jest's mock functions also have a `mock` property that you can test. - -### Bypassing mocks +### Keep mocks light -If you ever need to import the original module in your tests, use [`jest.requireActual()`](https://jestjs.io/docs/en/jest-object#jestrequireactualmodulename) (or `jest.requireActual().default` for the default export). The `jest.mock()` and `jest.unmock()` won't have an effect on modules that have a manual mock, because mocks are imported and cached before any tests are run. +Global mocks introduce magic and technically can reduce test coverage. When mocking is deemed profitable: -### Keep mocks light +- Keep the mock short and focused. +- Please leave a top-level comment in the mock on why it is necessary. -Global mocks introduce magic and can affect how modules are imported in your tests. Try to keep them as light as possible and dependency-free. A global mock should be useful for any unit test. For example, the `axios_utils` and `jquery` module mocks throw an error when an HTTP request is attempted, since this is useful behaviour in >99% of tests. +### Additional mocking techniques -When in doubt, construct mocks in your test file using [`jest.mock()`](https://jestjs.io/docs/en/jest-object#jestmockmodulename-factory-options), [`jest.spyOn()`](https://jestjs.io/docs/en/jest-object#jestspyonobject-methodname), etc. +Please consult the [official Jest docs](https://jestjs.io/docs/en/jest-object#mock-modules) for a full overview of the available mocking features. ## Running Frontend Tests diff --git a/doc/user/permissions.md b/doc/user/permissions.md index 55f2e3bbd6c..76a33559666 100644 --- a/doc/user/permissions.md +++ b/doc/user/permissions.md @@ -57,7 +57,7 @@ The following table depicts the various user permission levels in a project. | View Dependency list **(ULTIMATE)** | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | | View License list **(ULTIMATE)** | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | | View licenses in Dependency list **(ULTIMATE)** | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | -| View [Design Management](project/issues/design_management.md) pages **(PREMIUM)** | ✓ | ✓ | ✓ | ✓ | ✓ | +| View [Design Management](project/issues/design_management.md) pages | ✓ | ✓ | ✓ | ✓ | ✓ | | View project code | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | | Pull project code | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | | View GitLab Pages protected by [access control](project/pages/introduction.md#gitlab-pages-access-control-core) | ✓ | ✓ | ✓ | ✓ | ✓ | @@ -87,7 +87,7 @@ The following table depicts the various user permission levels in a project. | Create/edit/delete [Releases](project/releases/index.md)| | | ✓ | ✓ | ✓ | | Pull from [Conan repository](packages/conan_repository/index.md), [Maven repository](packages/maven_repository/index.md), or [NPM registry](packages/npm_registry/index.md) **(PREMIUM)** | | ✓ | ✓ | ✓ | ✓ | | Publish to [Conan repository](packages/conan_repository/index.md), [Maven repository](packages/maven_repository/index.md), or [NPM registry](packages/npm_registry/index.md) **(PREMIUM)** | | | ✓ | ✓ | ✓ | -| Upload [Design Management](project/issues/design_management.md) files **(PREMIUM)** | | | ✓ | ✓ | ✓ | +| Upload [Design Management](project/issues/design_management.md) files | | | ✓ | ✓ | ✓ | | Create new branches | | | ✓ | ✓ | ✓ | | Push to non-protected branches | | | ✓ | ✓ | ✓ | | Force push to non-protected branches | | | ✓ | ✓ | ✓ | diff --git a/doc/user/project/issue_board.md b/doc/user/project/issue_board.md index 1b9077299d7..2f4f3dd5392 100644 --- a/doc/user/project/issue_board.md +++ b/doc/user/project/issue_board.md @@ -203,9 +203,10 @@ If you don't have editing permission in a board, you're still able to see the co ![Viewing board configuration](img/issue_board_view_scope.png) -### Focus mode **(STARTER)** +### Focus mode -> Introduced in [GitLab Starter 9.1](https://about.gitlab.com/releases/2017/04/22/gitlab-9-1-released/#issue-boards-focus-mode-ees-eep). +> - Introduced in [GitLab Starter 9.1](https://about.gitlab.com/releases/2017/04/22/gitlab-9-1-released/#issue-boards-focus-mode-ees-eep). +> - Focus mode moved to GitLab Core in GitLab 12.10. Click the button at the top right to toggle focus mode on and off. In focus mode, the navigation UI is hidden, allowing you to focus on issues in the board. diff --git a/doc/user/project/issues/design_management.md b/doc/user/project/issues/design_management.md index 40771c14ea4..0fbf5ec6f4b 100644 --- a/doc/user/project/issues/design_management.md +++ b/doc/user/project/issues/design_management.md @@ -1,4 +1,4 @@ -# Design Management **(PREMIUM)** +# Design Management > [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/660) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.2. diff --git a/doc/user/project/issues/index.md b/doc/user/project/issues/index.md index af19c7f2b4a..4da65793dbb 100644 --- a/doc/user/project/issues/index.md +++ b/doc/user/project/issues/index.md @@ -126,7 +126,7 @@ associated label or assignee will change to match that of the new column. The en board can also be filtered to only include issues from a certain milestone or an overarching label. -### Design Management **(PREMIUM)** +### Design Management With [Design Management](design_management.md), you can upload design assets to issues and view them all together to easily share and diff --git a/doc/user/project/settings/import_export.md b/doc/user/project/settings/import_export.md index 04ad7b30aec..f454144b623 100644 --- a/doc/user/project/settings/import_export.md +++ b/doc/user/project/settings/import_export.md @@ -75,7 +75,7 @@ The following items will be exported: - Project configuration, including services - Issues with comments, merge requests with diffs and comments, labels, milestones, snippets, and other project entities -- Design Management files and data **(PREMIUM)** +- Design Management files and data - LFS objects - Issue boards - Pipelines history diff --git a/lib/api/commits.rb b/lib/api/commits.rb index dfb0066ceb0..086a1b7c402 100644 --- a/lib/api/commits.rb +++ b/lib/api/commits.rb @@ -356,7 +356,7 @@ module API present paginate(commit_merge_requests), with: Entities::MergeRequestBasic end - desc "Get a commit's GPG signature" do + desc "Get a commit's signature" do success Entities::CommitSignature end params do @@ -365,11 +365,9 @@ module API get ':id/repository/commits/:sha/signature', requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do commit = user_project.commit(params[:sha]) not_found! 'Commit' unless commit + not_found! 'Signature' unless commit.has_signature? - signature = commit.signature - not_found! 'GPG Signature' unless signature - - present signature, with: Entities::CommitSignature + present commit, with: Entities::CommitSignature end end end diff --git a/lib/api/entities/commit_signature.rb b/lib/api/entities/commit_signature.rb index 8e86d4c1aa6..b5232273521 100644 --- a/lib/api/entities/commit_signature.rb +++ b/lib/api/entities/commit_signature.rb @@ -3,10 +3,14 @@ module API module Entities class CommitSignature < Grape::Entity - expose :gpg_key_id - expose :gpg_key_primary_keyid, :gpg_key_user_name, :gpg_key_user_email - expose :verification_status - expose :gpg_key_subkey_id + expose :signature_type + expose :signature, merge: true do |commit, options| + if commit.signature.is_a?(GpgSignature) + ::API::Entities::GpgCommitSignature.represent commit.signature, options + elsif commit.signature.is_a?(X509CommitSignature) + ::API::Entities::X509Signature.represent commit.signature, options + end + end end end end diff --git a/lib/api/entities/gpg_commit_signature.rb b/lib/api/entities/gpg_commit_signature.rb new file mode 100644 index 00000000000..03466452b50 --- /dev/null +++ b/lib/api/entities/gpg_commit_signature.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module API + module Entities + class GpgCommitSignature < Grape::Entity + expose :verification_status + expose :gpg_key_id + expose :gpg_key_primary_keyid, :gpg_key_user_name, :gpg_key_user_email + expose :gpg_key_subkey_id + end + end +end diff --git a/lib/api/entities/x509_certificate.rb b/lib/api/entities/x509_certificate.rb new file mode 100644 index 00000000000..aad11339148 --- /dev/null +++ b/lib/api/entities/x509_certificate.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module API + module Entities + class X509Certificate < Grape::Entity + expose :id + expose :subject + expose :subject_key_identifier + expose :email + expose :serial_number + expose :certificate_status + expose :x509_issuer, using: 'API::Entities::X509Issuer' + end + end +end diff --git a/lib/api/entities/x509_issuer.rb b/lib/api/entities/x509_issuer.rb new file mode 100644 index 00000000000..b480bc107bc --- /dev/null +++ b/lib/api/entities/x509_issuer.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module API + module Entities + class X509Issuer < Grape::Entity + expose :id + expose :subject + expose :subject_key_identifier + expose :crl_url + end + end +end diff --git a/lib/api/entities/x509_signature.rb b/lib/api/entities/x509_signature.rb new file mode 100644 index 00000000000..909b630288c --- /dev/null +++ b/lib/api/entities/x509_signature.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +module API + module Entities + class X509Signature < Grape::Entity + expose :verification_status + expose :x509_certificate, using: 'API::Entities::X509Certificate' + end + end +end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index b9f0e1f7b8b..a56d4cc2e6e 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -11228,9 +11228,6 @@ msgstr "" msgid "Issue already promoted to epic." msgstr "" -msgid "Issue board focus mode" -msgstr "" - msgid "Issue cannot be found." msgstr "" @@ -22708,6 +22705,9 @@ msgstr "" msgid "Vulnerability|Description" msgstr "" +msgid "Vulnerability|Evidence" +msgstr "" + msgid "Vulnerability|File" msgstr "" diff --git a/package.json b/package.json index e0c0bf3161b..350d63d9296 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "@babel/plugin-syntax-import-meta": "^7.8.3", "@babel/preset-env": "^7.8.4", "@gitlab/at.js": "1.5.5", - "@gitlab/svgs": "1.116.0", + "@gitlab/svgs": "1.117.0", "@gitlab/ui": "11.0.0", "@gitlab/visual-review-tools": "1.5.1", "@sentry/browser": "^5.10.2", diff --git a/spec/controllers/concerns/controller_with_cross_project_access_check_spec.rb b/spec/controllers/concerns/controller_with_cross_project_access_check_spec.rb index 85989ea3e92..3f9d690837b 100644 --- a/spec/controllers/concerns/controller_with_cross_project_access_check_spec.rb +++ b/spec/controllers/concerns/controller_with_cross_project_access_check_spec.rb @@ -14,6 +14,7 @@ describe ControllerWithCrossProjectAccessCheck do context 'When reading cross project is not allowed' do before do allow(Ability).to receive(:allowed).and_call_original + expect(Ability).to receive(:allowed?).with(user, :log_in, :global).and_call_original allow(Ability).to receive(:allowed?) .with(user, :read_cross_project, :global) .and_return(false) diff --git a/spec/controllers/graphql_controller_spec.rb b/spec/controllers/graphql_controller_spec.rb index a8e78524910..06a949471a7 100644 --- a/spec/controllers/graphql_controller_spec.rb +++ b/spec/controllers/graphql_controller_spec.rb @@ -46,6 +46,7 @@ describe GraphqlController do # User cannot access API in a couple of cases # * When user is internal(like ghost users) # * When user is blocked + expect(Ability).to receive(:allowed?).with(user, :log_in, :global).and_call_original expect(Ability).to receive(:allowed?).with(user, :access_api, :global).and_return(false) post :execute diff --git a/spec/controllers/groups/boards_controller_spec.rb b/spec/controllers/groups/boards_controller_spec.rb index acfa8bc9354..b556af0eedc 100644 --- a/spec/controllers/groups/boards_controller_spec.rb +++ b/spec/controllers/groups/boards_controller_spec.rb @@ -26,6 +26,7 @@ describe Groups::BoardsController do context 'with unauthorized user' do before do + expect(Ability).to receive(:allowed?).with(user, :log_in, :global).and_call_original allow(Ability).to receive(:allowed?).with(user, :read_cross_project, :global).and_return(true) allow(Ability).to receive(:allowed?).with(user, :read_group, group).and_return(true) allow(Ability).to receive(:allowed?).with(user, :read_board, group).and_return(false) @@ -70,6 +71,7 @@ describe Groups::BoardsController do context 'with unauthorized user' do before do + expect(Ability).to receive(:allowed?).with(user, :log_in, :global).and_call_original allow(Ability).to receive(:allowed?).with(user, :read_cross_project, :global).and_return(true) allow(Ability).to receive(:allowed?).with(user, :read_group, group).and_return(true) allow(Ability).to receive(:allowed?).with(user, :read_board, group).and_return(false) @@ -106,6 +108,7 @@ describe Groups::BoardsController do context 'with unauthorized user' do before do + expect(Ability).to receive(:allowed?).with(user, :log_in, :global).and_call_original allow(Ability).to receive(:allowed?).with(user, :read_cross_project, :global).and_return(true) allow(Ability).to receive(:allowed?).with(user, :read_group, group).and_return(true) allow(Ability).to receive(:allowed?).with(user, :read_board, group).and_return(false) @@ -144,6 +147,7 @@ describe Groups::BoardsController do context 'with unauthorized user' do before do + expect(Ability).to receive(:allowed?).with(user, :log_in, :global).and_call_original allow(Ability).to receive(:allowed?).with(user, :read_cross_project, :global).and_return(true) allow(Ability).to receive(:allowed?).with(user, :read_group, group).and_return(true) allow(Ability).to receive(:allowed?).with(user, :read_group, group).and_return(false) diff --git a/spec/controllers/projects/boards_controller_spec.rb b/spec/controllers/projects/boards_controller_spec.rb index ebfdb997974..6634801939b 100644 --- a/spec/controllers/projects/boards_controller_spec.rb +++ b/spec/controllers/projects/boards_controller_spec.rb @@ -32,6 +32,7 @@ describe Projects::BoardsController do context 'with unauthorized user' do before do + expect(Ability).to receive(:allowed?).with(user, :log_in, :global).and_call_original allow(Ability).to receive(:allowed?).with(user, :read_project, project).and_return(true) allow(Ability).to receive(:allowed?).with(user, :read_board, project).and_return(false) end @@ -75,6 +76,7 @@ describe Projects::BoardsController do context 'with unauthorized user' do before do + expect(Ability).to receive(:allowed?).with(user, :log_in, :global).and_call_original allow(Ability).to receive(:allowed?).with(user, :read_project, project).and_return(true) allow(Ability).to receive(:allowed?).with(user, :read_board, project).and_return(false) end @@ -130,6 +132,7 @@ describe Projects::BoardsController do context 'with unauthorized user' do before do + expect(Ability).to receive(:allowed?).with(user, :log_in, :global).and_call_original allow(Ability).to receive(:allowed?).with(user, :read_project, project).and_return(true) allow(Ability).to receive(:allowed?).with(user, :read_board, project).and_return(false) end @@ -167,6 +170,7 @@ describe Projects::BoardsController do context 'with unauthorized user' do before do + expect(Ability).to receive(:allowed?).with(user, :log_in, :global).and_call_original allow(Ability).to receive(:allowed?).with(user, :read_project, project).and_return(true) allow(Ability).to receive(:allowed?).with(user, :read_board, project).and_return(false) end diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb index ccaf0dd997b..fb3c163dff1 100644 --- a/spec/factories/ci/builds.rb +++ b/spec/factories/ci/builds.rb @@ -29,6 +29,7 @@ FactoryBot.define do end pipeline factory: :ci_pipeline + project { pipeline.project } trait :degenerated do options { nil } @@ -220,10 +221,6 @@ FactoryBot.define do end end - after(:build) do |build, evaluator| - build.project ||= build.pipeline.project - end - trait :with_deployment do after(:build) do |build, evaluator| ## diff --git a/spec/factories/internal_ids.rb b/spec/factories/internal_ids.rb index bc6ea41ec06..02baaedb996 100644 --- a/spec/factories/internal_ids.rb +++ b/spec/factories/internal_ids.rb @@ -6,4 +6,10 @@ FactoryBot.define do usage { :issues } last_value { project.issues.maximum(:iid) || 0 } end + + trait :has_internal_id do + after(:stub) do |record| + record.iid ||= generate(:iid) + end + end end diff --git a/spec/factories/issues.rb b/spec/factories/issues.rb index 24c12a66599..4d0924a9412 100644 --- a/spec/factories/issues.rb +++ b/spec/factories/issues.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true FactoryBot.define do - factory :issue do + factory :issue, traits: [:has_internal_id] do title { generate(:title) } project author { project.creator } diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb index 08a8ede61b1..abccd775c8a 100644 --- a/spec/factories/merge_requests.rb +++ b/spec/factories/merge_requests.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true FactoryBot.define do - factory :merge_request do + factory :merge_request, traits: [:has_internal_id] do title { generate(:title) } association :source_project, :repository, factory: :project target_project { source_project } diff --git a/spec/factories/milestones.rb b/spec/factories/milestones.rb index 32eee645f6a..151d286cc29 100644 --- a/spec/factories/milestones.rb +++ b/spec/factories/milestones.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true FactoryBot.define do - factory :milestone do + factory :milestone, traits: [:has_internal_id] do title transient do diff --git a/spec/factories/notes.rb b/spec/factories/notes.rb index a15c7625500..fdd1a9a18b2 100644 --- a/spec/factories/notes.rb +++ b/spec/factories/notes.rb @@ -40,7 +40,7 @@ FactoryBot.define do factory :discussion_note_on_personal_snippet, traits: [:on_personal_snippet], class: 'DiscussionNote' - factory :discussion_note_on_snippet, traits: [:on_snippet], class: 'DiscussionNote' + factory :discussion_note_on_project_snippet, traits: [:on_project_snippet], class: 'DiscussionNote' factory :legacy_diff_note_on_commit, traits: [:on_commit, :legacy_diff_note], class: 'LegacyDiffNote' @@ -120,23 +120,19 @@ FactoryBot.define do end trait :on_issue do - noteable { create(:issue, project: project) } - end - - trait :on_snippet do - noteable { create(:snippet, project: project) } + noteable { association(:issue, project: project) } end trait :on_merge_request do - noteable { create(:merge_request, source_project: project) } + noteable { association(:merge_request, source_project: project) } end trait :on_project_snippet do - noteable { create(:project_snippet, project: project) } + noteable { association(:project_snippet, project: project) } end trait :on_personal_snippet do - noteable { create(:personal_snippet) } + noteable { association(:personal_snippet) } project { nil } end diff --git a/spec/factories/sequences.rb b/spec/factories/sequences.rb index 17b54d69372..cdc64a8502e 100644 --- a/spec/factories/sequences.rb +++ b/spec/factories/sequences.rb @@ -11,4 +11,5 @@ FactoryBot.define do sequence(:label_title) { |n| "label#{n}" } sequence(:branch) { |n| "my-branch-#{n}" } sequence(:past_time) { |n| 4.hours.ago + (2 * n).seconds } + sequence(:iid) end diff --git a/spec/frontend/fixtures/snippet.rb b/spec/frontend/fixtures/snippet.rb index e91050cd2c5..d27c2fbe68b 100644 --- a/spec/frontend/fixtures/snippet.rb +++ b/spec/frontend/fixtures/snippet.rb @@ -27,7 +27,7 @@ describe SnippetsController, '(JavaScript fixtures)', type: :controller do end it 'snippets/show.html' do - create(:discussion_note_on_snippet, noteable: snippet, project: project, author: admin, note: '- [ ] Task List Item') + create(:discussion_note_on_project_snippet, noteable: snippet, project: project, author: admin, note: '- [ ] Task List Item') get(:show, params: { id: snippet.to_param }) diff --git a/spec/frontend/monitoring/components/__snapshots__/dashboard_template_spec.js.snap b/spec/frontend/monitoring/components/__snapshots__/dashboard_template_spec.js.snap index f7e15d4a5c4..88710b23bc9 100644 --- a/spec/frontend/monitoring/components/__snapshots__/dashboard_template_spec.js.snap +++ b/spec/frontend/monitoring/components/__snapshots__/dashboard_template_spec.js.snap @@ -96,7 +96,7 @@ exports[`Dashboard template matches the default snapshot 1`] = ` variant="default" > <icon-stub - name="repeat" + name="retry" size="16" /> </gl-deprecated-button-stub> diff --git a/spec/graphql/types/snippet_type_spec.rb b/spec/graphql/types/snippet_type_spec.rb index ba0152ae983..6e580711fda 100644 --- a/spec/graphql/types/snippet_type_spec.rb +++ b/spec/graphql/types/snippet_type_spec.rb @@ -27,25 +27,9 @@ describe GitlabSchema.types['Snippet'] do end end - describe 'Repository URLs' do - let(:query) do - %( - { - snippets { - nodes { - sshUrlToRepo - httpUrlToRepo - } - } - } - ) - end - let(:response) { subject.dig('data', 'snippets', 'nodes')[0] } - - subject { GitlabSchema.execute(query, context: { current_user: user }).as_json } - + shared_examples 'snippets with repositories' do context 'when snippet has repository' do - let!(:snippet) { create(:personal_snippet, :repository, :public, author: user) } + let_it_be(:snippet) { create(:personal_snippet, :repository, :public, author: user) } it 'responds with repository URLs' do expect(response['sshUrlToRepo']).to eq(snippet.ssh_url_to_repo) @@ -60,14 +44,44 @@ describe GitlabSchema.types['Snippet'] do it_behaves_like 'response without repository URLs' end end + end + shared_examples 'snippets without repositories' do context 'when snippet does not have a repository' do - let!(:snippet) { create(:personal_snippet, :public, author: user) } + let_it_be(:snippet) { create(:personal_snippet, :public, author: user) } it_behaves_like 'response without repository URLs' end end + describe 'Repository URLs' do + let(:query) do + %( + { + snippets { + nodes { + sshUrlToRepo + httpUrlToRepo + } + } + } + ) + end + let(:response) { subject.dig('data', 'snippets', 'nodes')[0] } + + subject { GitlabSchema.execute(query, context: { current_user: user }).as_json } + + context 'when RequestStore is disabled' do + it_behaves_like 'snippets with repositories' + it_behaves_like 'snippets without repositories' + end + + context 'when RequestStore is enabled', :request_store do + it_behaves_like 'snippets with repositories' + it_behaves_like 'snippets without repositories' + end + end + describe '#blob' do let(:query_blob) { subject.dig('data', 'snippets', 'edges')[0]['node']['blob'] } let(:query) do diff --git a/spec/helpers/events_helper_spec.rb b/spec/helpers/events_helper_spec.rb index 0109525bcac..ff99f76eb4d 100644 --- a/spec/helpers/events_helper_spec.rb +++ b/spec/helpers/events_helper_spec.rb @@ -181,7 +181,7 @@ describe EventsHelper do end it 'returns a project snippet note url' do - event.target = create(:note, :on_snippet, note: 'keep going') + event.target = create(:note_on_project_snippet, note: 'keep going') expect(subject).to eq("#{project_base_url}/snippets/#{event.note_target.id}#note_#{event.target.id}") end diff --git a/spec/lib/gitlab/danger/changelog_spec.rb b/spec/lib/gitlab/danger/changelog_spec.rb index c61e47f80d9..ba23c3828de 100644 --- a/spec/lib/gitlab/danger/changelog_spec.rb +++ b/spec/lib/gitlab/danger/changelog_spec.rb @@ -28,18 +28,6 @@ describe Gitlab::Danger::Changelog do describe '#needed?' do subject { changelog.needed? } - [ - { docs: nil }, - { none: nil }, - { docs: nil, none: nil } - ].each do |categories| - let(:changes_by_category) { categories } - - it "is falsy when categories don't require a changelog" do - is_expected.to be_falsy - end - end - where(:categories, :labels) do { backend: nil } | %w[backend backstage] { frontend: nil, docs: nil } | ['ci-build'] @@ -50,7 +38,7 @@ describe Gitlab::Danger::Changelog do let(:changes_by_category) { categories } let(:mr_labels) { labels } - it "is falsy when labels require no changelog" do + it "is falsy when categories and labels require no changelog" do is_expected.to be_falsy end end diff --git a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb index a3904f4a97c..084dde1f93f 100644 --- a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb +++ b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb @@ -3,11 +3,11 @@ require 'spec_helper' describe Gitlab::Gfm::ReferenceRewriter do - let(:group) { create(:group) } - let(:old_project) { create(:project, name: 'old-project', group: group) } - let(:new_project) { create(:project, name: 'new-project', group: group) } - let(:user) { create(:user) } + let_it_be(:group) { create(:group) } + let_it_be(:user) { create(:user) } + let(:new_project) { create(:project, name: 'new-project', group: group) } + let(:old_project) { create(:project, name: 'old-project', group: group) } let(:old_project_ref) { old_project.to_reference_base(new_project) } let(:text) { 'some text' } diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 291c628bfde..12f83e6d8c6 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -4475,4 +4475,73 @@ describe User, :do_not_mock_admin_mode do end end end + + describe '#active_for_authentication?' do + subject { user.active_for_authentication? } + + let(:user) { create(:user) } + + context 'when user is blocked' do + before do + user.block + end + + it { is_expected.to be false } + end + + context 'when user is a ghost user' do + before do + user.update(ghost: true) + end + + it { is_expected.to be false } + end + + context 'based on user type' do + using RSpec::Parameterized::TableSyntax + + where(:user_type, :expected_result) do + 'human' | true + 'alert_bot' | false + end + + with_them do + before do + user.update(user_type: user_type) + end + + it { is_expected.to be expected_result } + end + end + end + + describe '#inactive_message' do + subject { user.inactive_message } + + let(:user) { create(:user) } + + context 'when user is blocked' do + before do + user.block + end + + it { is_expected.to eq User::BLOCKED_MESSAGE } + end + + context 'when user is an internal user' do + before do + user.update(ghost: true) + end + + it { is_expected.to be User::LOGIN_FORBIDDEN } + end + + context 'when user is locked' do + before do + user.lock_access! + end + + it { is_expected.to be :locked } + end + end end diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb index 4b110874df0..86b3dd4095f 100644 --- a/spec/requests/api/commits_spec.rb +++ b/spec/requests/api/commits_spec.rb @@ -1889,11 +1889,11 @@ describe API::Commits do context 'unsigned commit' do it_behaves_like '404 response' do let(:request) { get api(route, current_user) } - let(:message) { '404 GPG Signature Not Found'} + let(:message) { '404 Signature Not Found'} end end - context 'signed commit' do + context 'gpg signed commit' do let(:commit) { project.repository.commit(GpgHelpers::SIGNED_COMMIT_SHA) } let(:commit_id) { commit.id } @@ -1901,11 +1901,35 @@ describe API::Commits do get api(route, current_user) expect(response).to have_gitlab_http_status(:ok) + expect(json_response['signature_type']).to eq('PGP') expect(json_response['gpg_key_id']).to eq(commit.signature.gpg_key_id) expect(json_response['gpg_key_subkey_id']).to eq(commit.signature.gpg_key_subkey_id) expect(json_response['gpg_key_primary_keyid']).to eq(commit.signature.gpg_key_primary_keyid) expect(json_response['verification_status']).to eq(commit.signature.verification_status) end end + + context 'x509 signed commit' do + let(:commit) { project.repository.commit_by(oid: '189a6c924013fc3fe40d6f1ec1dc20214183bc97') } + let(:commit_id) { commit.id } + + it 'returns correct JSON' do + get api(route, current_user) + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['signature_type']).to eq('X509') + expect(json_response['verification_status']).to eq(commit.signature.verification_status) + expect(json_response['x509_certificate']['id']).to eq(commit.signature.x509_certificate.id) + expect(json_response['x509_certificate']['subject']).to eq(commit.signature.x509_certificate.subject) + expect(json_response['x509_certificate']['subject_key_identifier']).to eq(commit.signature.x509_certificate.subject_key_identifier) + expect(json_response['x509_certificate']['email']).to eq(commit.signature.x509_certificate.email) + expect(json_response['x509_certificate']['serial_number']).to eq(commit.signature.x509_certificate.serial_number) + expect(json_response['x509_certificate']['certificate_status']).to eq(commit.signature.x509_certificate.certificate_status) + expect(json_response['x509_certificate']['x509_issuer']['id']).to eq(commit.signature.x509_certificate.x509_issuer.id) + expect(json_response['x509_certificate']['x509_issuer']['subject']).to eq(commit.signature.x509_certificate.x509_issuer.subject) + expect(json_response['x509_certificate']['x509_issuer']['subject_key_identifier']).to eq(commit.signature.x509_certificate.x509_issuer.subject_key_identifier) + expect(json_response['x509_certificate']['x509_issuer']['crl_url']).to eq(commit.signature.x509_certificate.x509_issuer.crl_url) + end + end end end diff --git a/spec/requests/api/discussions_spec.rb b/spec/requests/api/discussions_spec.rb index e4dd6dfbeff..cb3efb2cf5f 100644 --- a/spec/requests/api/discussions_spec.rb +++ b/spec/requests/api/discussions_spec.rb @@ -31,7 +31,7 @@ describe API::Discussions do context 'when noteable is a Snippet' do let!(:snippet) { create(:project_snippet, project: project, author: user) } - let!(:snippet_note) { create(:discussion_note_on_snippet, noteable: snippet, project: project, author: user) } + let!(:snippet_note) { create(:discussion_note_on_project_snippet, noteable: snippet, project: project, author: user) } it_behaves_like 'discussions API', 'projects', 'snippets', 'id' do let(:parent) { project } diff --git a/spec/support/helpers/repo_helpers.rb b/spec/support/helpers/repo_helpers.rb index 255a15b1ab0..7741c805b37 100644 --- a/spec/support/helpers/repo_helpers.rb +++ b/spec/support/helpers/repo_helpers.rb @@ -33,6 +33,7 @@ eos def sample_commit OpenStruct.new( id: "570e7b2abdd848b95f2f578043fc23bd6f6fd24d", + sha: "570e7b2abdd848b95f2f578043fc23bd6f6fd24d", parent_id: '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9', author_full_name: "Dmitriy Zaporozhets", author_email: "dmitriy.zaporozhets@gmail.com", @@ -50,6 +51,7 @@ eos def another_sample_commit OpenStruct.new( id: "e56497bb5f03a90a51293fc6d516788730953899", + sha: "e56497bb5f03a90a51293fc6d516788730953899", parent_id: '4cd80ccab63c82b4bad16faa5193fbd2aa06df40', author_full_name: "Sytse Sijbrandij", author_email: "sytse@gitlab.com", @@ -69,6 +71,7 @@ eos def sample_big_commit OpenStruct.new( id: "913c66a37b4a45b9769037c55c2d238bd0942d2e", + sha: "913c66a37b4a45b9769037c55c2d238bd0942d2e", author_full_name: "Dmitriy Zaporozhets", author_email: "dmitriy.zaporozhets@gmail.com", message: <<eos @@ -81,6 +84,7 @@ eos def sample_image_commit OpenStruct.new( id: "2f63565e7aac07bcdadb654e253078b727143ec4", + sha: "2f63565e7aac07bcdadb654e253078b727143ec4", author_full_name: "Dmitriy Zaporozhets", author_email: "dmitriy.zaporozhets@gmail.com", old_blob_id: '33f3729a45c02fc67d00adb1b8bca394b0e761d9', diff --git a/yarn.lock b/yarn.lock index 2c0afb67e8d..2a75187b06a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -781,10 +781,10 @@ eslint-plugin-vue "^6.2.1" vue-eslint-parser "^7.0.0" -"@gitlab/svgs@1.116.0": - version "1.116.0" - resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.116.0.tgz#a3c89f950bb256c2e109444c9a85fecdd261292c" - integrity sha512-sZLn3acu0IyrSnZRU1rE3UjxF6FlwvBNfjKQgn0qclxdbe8Ya6cGNVq4aGdCEkHwvb9rFpKbfHBujVgVKNkxSA== +"@gitlab/svgs@1.117.0": + version "1.117.0" + resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.117.0.tgz#05239ddcf529c62ca29e1ec1a25a7e24efb98207" + integrity sha512-dGy/VWuRAFCTZX3Yqu1+RnAHTSUWafteIk/RMfUCN9B/EMbYzjhYsNy0NLVoZ23Rj/KGv1bUGHvyQCoPP6VzpA== "@gitlab/ui@11.0.0": version "11.0.0" |