Commit b6847c62 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent c08d9c22
<!-- 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 ### 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 ### 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. <!-- 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) * [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) * [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) * [Delaney (Development Team Lead)](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#delaney-development-team-lead)
...@@ -16,13 +20,11 @@ ...@@ -16,13 +20,11 @@
* [Sam (Security Analyst)](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#sam-security-analyst) * [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) * [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) * [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) * [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/ -->
### Further details ### 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 ### Proposal
...@@ -35,14 +37,15 @@ Personas are described at https://about.gitlab.com/handbook/marketing/product-ma ...@@ -35,14 +37,15 @@ Personas are described at https://about.gitlab.com/handbook/marketing/product-ma
### Documentation ### Documentation
<!-- See the Feature Change Documentation Workflow https://docs.gitlab.com/ee/development/documentation/feature-change-workflow.html <!-- 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 ### Availability & Testing
<!-- This section needs to be retained and filled in during the workflow planning breakdown phase of this feature proposal, if not earlier. <!-- 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. 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 * Unit test changes
...@@ -57,7 +60,8 @@ See the test engineering planning process and reach out to your counterpart Soft ...@@ -57,7 +60,8 @@ See the test engineering planning process and reach out to your counterpart Soft
### What is the type of buyer? ### 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? ### Is this a cross-stage feature?
......
...@@ -217,12 +217,10 @@ Gitlab/DuplicateSpecLocation: ...@@ -217,12 +217,10 @@ Gitlab/DuplicateSpecLocation:
- ee/spec/helpers/auth_helper_spec.rb - ee/spec/helpers/auth_helper_spec.rb
- ee/spec/lib/gitlab/gl_repository_spec.rb - ee/spec/lib/gitlab/gl_repository_spec.rb
- ee/spec/models/namespace_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/refresh_service_spec.rb
- ee/spec/services/merge_requests/update_service_spec.rb - ee/spec/services/merge_requests/update_service_spec.rb
- ee/spec/helpers/ee/auth_helper_spec.rb - ee/spec/helpers/ee/auth_helper_spec.rb
- ee/spec/models/ee/namespace_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/refresh_service_spec.rb
- ee/spec/services/ee/merge_requests/update_service_spec.rb - ee/spec/services/ee/merge_requests/update_service_spec.rb
...@@ -398,7 +396,6 @@ RSpec/RepeatedExample: ...@@ -398,7 +396,6 @@ RSpec/RepeatedExample:
- 'spec/graphql/gitlab_schema_spec.rb' - 'spec/graphql/gitlab_schema_spec.rb'
- 'spec/helpers/users_helper_spec.rb' - 'spec/helpers/users_helper_spec.rb'
- 'spec/lib/gitlab/closing_issue_extractor_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/lib/gitlab/import_export/project/relation_factory_spec.rb'
- 'spec/rubocop/cop/migration/update_large_table_spec.rb' - 'spec/rubocop/cop/migration/update_large_table_spec.rb'
- 'spec/services/notification_service_spec.rb' - 'spec/services/notification_service_spec.rb'
......
...@@ -478,7 +478,7 @@ export default { ...@@ -478,7 +478,7 @@ export default {
:title="s__('Metrics|Reload this page')" :title="s__('Metrics|Reload this page')"
@click="refreshDashboard" @click="refreshDashboard"
> >
<icon name="repeat" /> <icon name="retry" />
</gl-deprecated-button> </gl-deprecated-button>
</gl-form-group> </gl-form-group>
......
...@@ -76,10 +76,16 @@ ...@@ -76,10 +76,16 @@
.gl-bg-green-100 { @include gl-bg-green-100;} .gl-bg-green-100 { @include gl-bg-green-100;}
.gl-text-blue-500 { @include gl-text-blue-500; } .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-700 { @include gl-text-gray-700; }
.gl-text-gray-900 { @include gl-text-gray-900; } .gl-text-gray-900 { @include gl-text-gray-900; }
.gl-text-red-700 { @include gl-text-red-700; } .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-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-text-green-700 { @include gl-text-green-700; }
.gl-align-items-center { @include gl-align-items-center; } .gl-align-items-center { @include gl-align-items-center; }
......
...@@ -67,10 +67,12 @@ module Types ...@@ -67,10 +67,12 @@ module Types
field :ssh_url_to_repo, type: GraphQL::STRING_TYPE, field :ssh_url_to_repo, type: GraphQL::STRING_TYPE,
description: 'SSH URL to the snippet repository', description: 'SSH URL to the snippet repository',
calls_gitaly: true,
null: true null: true
field :http_url_to_repo, type: GraphQL::STRING_TYPE, field :http_url_to_repo, type: GraphQL::STRING_TYPE,
description: 'HTTP URL to the snippet repository', description: 'HTTP URL to the snippet repository',
calls_gitaly: true,
null: true null: true
markdown_field :description_html, null: true, method: :description markdown_field :description_html, null: true, method: :description
......
...@@ -39,6 +39,7 @@ class ProjectWiki ...@@ -39,6 +39,7 @@ class ProjectWiki
def full_path def full_path
@project.full_path + '.wiki' @project.full_path + '.wiki'
end 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 # @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 alias_method :path_with_namespace, :full_path
......
...@@ -310,7 +310,7 @@ class Snippet < ApplicationRecord ...@@ -310,7 +310,7 @@ class Snippet < ApplicationRecord
end end
def versioned_enabled_for?(user) def versioned_enabled_for?(user)
repository_exists? && ::Feature.enabled?(:version_snippets, user) ::Feature.enabled?(:version_snippets, user) && repository_exists?
end end
class << self class << self
......
...@@ -58,6 +58,8 @@ class User < ApplicationRecord ...@@ -58,6 +58,8 @@ class User < ApplicationRecord
BLOCKED_MESSAGE = "Your account has been blocked. Please contact your GitLab " \ BLOCKED_MESSAGE = "Your account has been blocked. Please contact your GitLab " \
"administrator if you think this is an error." "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 MINIMUM_INACTIVE_DAYS = 180
...@@ -299,14 +301,6 @@ class User < ApplicationRecord ...@@ -299,14 +301,6 @@ class User < ApplicationRecord
def blocked? def blocked?
true true
end end
def active_for_authentication?
false
end
def inactive_message
BLOCKED_MESSAGE
end
end end
before_transition do before_transition do
...@@ -354,6 +348,20 @@ class User < ApplicationRecord ...@@ -354,6 +348,20 @@ class User < ApplicationRecord
.expiring_and_not_notified(at).select(1)) .expiring_and_not_notified(at).select(1))
end 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) def self.with_visible_profile(user)
return with_public_profile if user.nil? return with_public_profile if user.nil?
...@@ -1701,6 +1709,10 @@ class User < ApplicationRecord ...@@ -1701,6 +1709,10 @@ class User < ApplicationRecord
members.non_request.maximum(:access_level) members.non_request.maximum(:access_level)
end end
def confirmation_required_on_sign_in?
!confirmed? && !confirmation_period_valid?
end
protected protected
# override, from Devise::Validatable # override, from Devise::Validatable
......
...@@ -25,8 +25,7 @@ class BasePolicy < DeclarativePolicy::Base ...@@ -25,8 +25,7 @@ class BasePolicy < DeclarativePolicy::Base
with_options scope: :user, score: 0 with_options scope: :user, score: 0
condition(:inactive) do condition(:inactive) do
Feature.enabled?(:inactive_policy_condition, default_enabled: true) && Feature.enabled?(:inactive_policy_condition, default_enabled: true) &&
@user && @user&.confirmation_required_on_sign_in? || @user&.access_locked?
!@user&.active_for_authentication?
end end
with_options scope: :user, score: 0 with_options scope: :user, score: 0
......
---
title: Remove design management as a license feature
merge_request: 28589
author:
type: added
---
title: Remove duplicate spec from changelog spec
merge_request: 28801
author: Rajendra Kadam
type: added
---
title: Add api endpoint to get x509 signature
merge_request: 28590
author: Roger Meier
type: added
---
title: Change redo for retry icon in metrics dashboard
merge_request: 28670
author:
type: other
---
title: Fix GraphQL SnippetType repo urls
merge_request: 28673
author:
type: fixed
...@@ -741,19 +741,43 @@ Parameters: ...@@ -741,19 +741,43 @@ Parameters:
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/repository/commits/da738facbc19eb2fc2cef57c49be0e6038570352/signature" 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 ```json
{ {
"signature_type": "PGP",
"verification_status": "verified",
"gpg_key_id": 1, "gpg_key_id": 1,
"gpg_key_primary_keyid": "8254AAB3FBD54AC9", "gpg_key_primary_keyid": "8254AAB3FBD54AC9",
"gpg_key_user_name": "John Doe", "gpg_key_user_name": "John Doe",
"gpg_key_user_email": "johndoe@example.com", "gpg_key_user_email": "johndoe@example.com",
"verification_status": "verified",
"gpg_key_subkey_id": null "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: Example response if commit is unsigned:
```json ```json
......
...@@ -4,7 +4,7 @@ type: reference ...@@ -4,7 +4,7 @@ type: reference
# GitLab CI/CD environment variables # 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, this document teaches you how to use GitLab CI/CD's
variables, presents the full reference for predefined variables, variables, presents the full reference for predefined variables,
and dives into more advanced applications. and dives into more advanced applications.
...@@ -715,8 +715,8 @@ if [[ -d "/builds/gitlab-examples/ci-debug-trace/.git" ]]; then ...@@ -715,8 +715,8 @@ if [[ -d "/builds/gitlab-examples/ci-debug-trace/.git" ]]; then
++ CI_SERVER_VERSION_PATCH=0 ++ CI_SERVER_VERSION_PATCH=0
++ export CI_SERVER_REVISION=f4cc00ae823 ++ export CI_SERVER_REVISION=f4cc00ae823
++ 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 ++ 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_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_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 ++ export CI_PROJECT_ID=17893
++ CI_PROJECT_ID=17893 ++ CI_PROJECT_ID=17893
++ export CI_PROJECT_NAME=ci-debug-trace ++ export CI_PROJECT_NAME=ci-debug-trace
......
...@@ -550,8 +550,9 @@ The more challenging part are mocks, which can be used for functions or even dep ...@@ -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 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. 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). > **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` in the relevant spec file. > 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? #### 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 ...@@ -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. - 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. - 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`. ### Keep mocks light
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
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 &gt;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 ## Running Frontend Tests
......
...@@ -57,7 +57,7 @@ The following table depicts the various user permission levels in a project. ...@@ -57,7 +57,7 @@ The following table depicts the various user permission levels in a project.
| View Dependency list **(ULTIMATE)** | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | | View Dependency list **(ULTIMATE)** | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
| View License list **(ULTIMATE)** | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | | View License list **(ULTIMATE)** | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
| View licenses in Dependency 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*) | ✓ | ✓ | ✓ | ✓ | | View project code | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
| Pull project code | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | | Pull project code | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
| View GitLab Pages protected by [access control](project/pages/introduction.md#gitlab-pages-access-control-core) | ✓ | ✓ | ✓ | ✓ | ✓ | | 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. ...@@ -87,7 +87,7 @@ The following table depicts the various user permission levels in a project.
| Create/edit/delete [Releases](project/releases/index.md)| | | ✓ | ✓ | ✓ | | 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)** | | ✓ | ✓ | ✓ | ✓ | | 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)** | | | ✓ | ✓ | ✓ | | 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 | | | ✓ | ✓ | ✓ | | Create new branches | | | ✓ | ✓ | ✓ |
| Push to non-protected branches | | | ✓ | ✓ | ✓ | | Push to non-protected branches | | | ✓ | ✓ | ✓ |
| Force push to non-protected branches | | | ✓ | ✓ | ✓ | | Force push to non-protected branches | | | ✓ | ✓ | ✓ |
......
...@@ -203,9 +203,10 @@ If you don't have editing permission in a board, you're still able to see the co ...@@ -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) ![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. 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.
......
# Design Management **(PREMIUM)** # Design Management
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/660) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.2. > [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/660) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.2.
......
...@@ -126,7 +126,7 @@ associated label or assignee will change to match that of the new column. The en ...@@ -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 board can also be filtered to only include issues from a certain milestone or an overarching
label. label.
### Design Management **(PREMIUM)** ### Design Management
With [Design Management](design_management.md), you can upload design With [Design Management](design_management.md), you can upload design
assets to issues and view them all together to easily share and assets to issues and view them all together to easily share and
......
...@@ -75,7 +75,7 @@ The following items will be exported: ...@@ -75,7 +75,7 @@ The following items will be exported:
- Project configuration, including services - Project configuration, including services
- Issues with comments, merge requests with diffs and comments, labels, milestones, snippets, - Issues with comments, merge requests with diffs and comments, labels, milestones, snippets,
and other project entities and other project entities
- Design Management files and data **(PREMIUM)** - Design Management files and data
- LFS objects - LFS objects
- Issue boards - Issue boards
- Pipelines history - Pipelines history
......
...@@ -356,7 +356,7 @@ module API ...@@ -356,7 +356,7 @@ module API
present paginate(commit_merge_requests), with: Entities::MergeRequestBasic present paginate(commit_merge_requests), with: Entities::MergeRequestBasic
end end
desc "Get a commit's GPG signature" do desc "Get a commit's signature" do
success Entities::CommitSignature success Entities::CommitSignature
end end
params do params do
...@@ -365,11 +365,9 @@ module API ...@@ -365,11 +365,9 @@ module API
get ':id/repository/commits/:sha/signature', requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do get ':id/repository/commits/:sha/signature', requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do
commit = user_project.commit(params[:sha]) commit = user_project.commit(params[:sha])
not_found! 'Commit' unless commit not_found! 'Commit' unless commit
not_found! 'Signature' unless commit.has_signature?
signature = commit.signature present commit, with: Entities::CommitSignature
not_found! 'GPG Signature' unless signature
present signature, with: Entities::CommitSignature
end end
end end
end end
......
...@@ -3,10 +3,14 @@ ...@@ -3,10 +3,14 @@
module API module API
module Entities module Entities
class CommitSignature < Grape::Entity class CommitSignature < Grape::Entity
expose :gpg_key_id expose :signature_type
expose :gpg_key_primary_keyid, :gpg_key_user_name, :gpg_key_user_email expose :signature, merge: true do |commit, options|
expose :verification_status if commit.signature.is_a?(GpgSignature)
expose :gpg_key_subkey_id ::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 end
end end
# 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
# 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
# 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
# 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
...@@ -11228,9 +11228,6 @@ msgstr "" ...@@ -11228,9 +11228,6 @@ msgstr ""
msgid "Issue already promoted to epic." msgid "Issue already promoted to epic."
msgstr "" msgstr ""
msgid "Issue board focus mode"
msgstr ""
msgid "Issue cannot be found." msgid "Issue cannot be found."
msgstr "" msgstr ""
...@@ -22708,6 +22705,9 @@ msgstr "" ...@@ -22708,6 +22705,9 @@ msgstr ""
msgid "Vulnerability|Description" msgid "Vulnerability|Description"
msgstr "" msgstr ""
msgid "Vulnerability|Evidence"
msgstr ""
msgid "Vulnerability|File" msgid "Vulnerability|File"
msgstr "" msgstr ""
......
...@@ -14,6 +14,7 @@ describe ControllerWithCrossProjectAccessCheck do ...@@ -14,6 +14,7 @@ describe ControllerWithCrossProjectAccessCheck do
context 'When reading cross project is not allowed' do context 'When reading cross project is not allowed' do
before do before do
allow(Ability).to receive(:allowed).and_call_original 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?) allow(Ability).to receive(:allowed?)
.with(user, :read_cross_project, :global) .with(user, :read_cross_project, :global)
.and_return(false) .and_return(false)
......
...@@ -46,6 +46,7 @@ describe GraphqlController do ...@@ -46,6 +46,7 @@ describe GraphqlController do
# User cannot access API in a couple of cases # User cannot access API in a couple of cases
# * When user is internal(like ghost users) # * When user is internal(like ghost users)
# * When user is blocked # * 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) expect(Ability).to receive(:allowed?).with(user, :access_api, :global).and_return(false)
post :execute post :execute
......
...@@ -26,6 +26,7 @@ describe Groups::BoardsController do ...@@ -26,6 +26,7 @@ describe Groups::BoardsController do
context 'with unauthorized user' do context 'with unauthorized user' do
before 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_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(true)
allow(Ability).to receive(:allowed?).with(user, :read_board, group).and_return(false) allow(Ability).to receive(:allowed?).with(user, :read_board, group).and_return(false)
...@@ -70,6 +71,7 @@ describe Groups::BoardsController do ...@@ -70,6 +71,7 @@ describe Groups::BoardsController do
context 'with unauthorized user' do context 'with unauthorized user' do
before 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_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(true)
allow(Ability).to receive(:allowed?).with(user, :read_board, group).and_return(false) allow(Ability).to receive(:allowed?).with(user, :read_board, group).and_return(false)
...@@ -106,6 +108,7 @@ describe Groups::BoardsController do ...@@ -106,6 +108,7 @@ describe Groups::BoardsController do
context 'with unauthorized user' do context 'with unauthorized user' do
before 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_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(true)
allow(Ability).to receive(:allowed?).with(user, :read_board, group).and_return(false) allow(Ability).to receive(:allowed?).with(user, :read_board, group).and_return(false)
...@@ -144,6 +147,7 @@ describe Groups::BoardsController do ...@@ -144,6 +147,7 @@ describe Groups::BoardsController do
context 'with unauthorized user' do context 'with unauthorized user' do
before 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_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(true)
allow(Ability).to receive(:allowed?).with(user, :read_group, group).and_return(false) allow(Ability).to receive(:allowed?).with(user, :read_group, group).and_return(false)
......
...@@ -32,6 +32,7 @@ describe Projects::BoardsController do ...@@ -32,6 +32,7 @@ describe Projects::BoardsController do
context 'with unauthorized user' do context 'with unauthorized user' do
before 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_project, project).and_return(true)
allow(Ability).to receive(:allowed?).with(user, :read_board, project).and_return(false) allow(Ability).to receive(:allowed?).with(user, :read_board, project).and_return(false)
end end
...@@ -75,6 +76,7 @@ describe Projects::BoardsController do ...@@ -75,6 +76,7 @@ describe Projects::BoardsController do
context 'with unauthorized user' do context 'with unauthorized user' do
before 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_project, project).and_return(true)
allow(Ability).to receive(:allowed?).with(user, :read_board, project).and_return(false) allow(Ability).to receive(:allowed?).with(user, :read_board, project).and_return(false)
end end
...@@ -130,6 +132,7 @@ describe Projects::BoardsController do ...@@ -130,6 +132,7 @@ describe Projects::BoardsController do
context 'with unauthorized user' do context 'with unauthorized user' do
before 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_project, project).and_return(true)
allow(Ability).to receive(:allowed?).with(user, :read_board, project).and_return(false) allow(Ability).to receive(:allowed?).with(user, :read_board, project).and_return(false)
end end
...@@ -167,6 +170,7 @@ describe Projects::BoardsController do ...@@ -167,6 +170,7 @@ describe Projects::BoardsController do
context 'with unauthorized user' do context 'with unauthorized user' do
before 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_project, project).and_return(true)
allow(Ability).to receive(:allowed?).with(user, :read_board, project).and_return(false) allow(Ability).to receive(:allowed?).with(user, :read_board, project).and_return(false)
end end
......
...@@ -29,6 +29,7 @@ FactoryBot.define do ...@@ -29,6 +29,7 @@ FactoryBot.define do
end end
pipeline factory: :ci_pipeline pipeline factory: :ci_pipeline
project { pipeline.project }
trait :degenerated do trait :degenerated do
options { nil } options { nil }
...@@ -220,10 +221,6 @@ FactoryBot.define do ...@@ -220,10 +221,6 @@ FactoryBot.define do
end end
end end
after(:build) do |build, evaluator|
build.project ||= build.pipeline.project
end
trait :with_deployment do trait :with_deployment do
after(:build) do |build, evaluator| after(:build) do |build, evaluator|
## ##
......
...@@ -6,4 +6,10 @@ FactoryBot.define do ...@@ -6,4 +6,10 @@ FactoryBot.define do
usage { :issues } usage { :issues }
last_value { project.issues.maximum(:iid) || 0 } last_value { project.issues.maximum(:iid) || 0 }
end end
trait :has_internal_id do
after(:stub) do |record|
record.iid ||= generate(:iid)
end
end
end end
# frozen_string_literal: true # frozen_string_literal: true
FactoryBot.define do FactoryBot.define do
factory :issue do factory :issue, traits: [:has_internal_id] do
title { generate(:title) } title { generate(:title) }
project project
author { project.creator } author { project.creator }
......
# frozen_string_literal: true # frozen_string_literal: true
FactoryBot.define do FactoryBot.define do
factory :merge_request do factory :merge_request, traits: [:has_internal_id] do
title { generate(:title) } title { generate(:title) }
association :source_project, :repository, factory: :project association :source_project, :repository, factory: :project
target_project { source_project } target_project { source_project }
......
# frozen_string_literal: true # frozen_string_literal: true
FactoryBot.define do FactoryBot.define do
factory :milestone do factory :milestone, traits: [:has_internal_id] do
title title
transient do transient do
......
...@@ -40,7 +40,7 @@ FactoryBot.define do ...@@ -40,7 +40,7 @@ FactoryBot.define do
factory :discussion_note_on_personal_snippet, traits: [:on_personal_snippet], class: 'DiscussionNote' 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' factory :legacy_diff_note_on_commit, traits: [:on_commit, :legacy_diff_note], class: 'LegacyDiffNote'
...@@ -120,23 +120,19 @@ FactoryBot.define do ...@@ -120,23 +120,19 @@ FactoryBot.define do
end end
trait :on_issue do trait :on_issue do
noteable { create(:issue, project: project) } noteable { association(:issue, project: project) }
end
trait :on_snippet do
noteable { create(:snippet, project: project) }
end end
trait :on_merge_request do trait :on_merge_request do
noteable { create(:merge_request, source_project: project) } noteable { association(:merge_request, source_project: project) }
end end
trait :on_project_snippet do trait :on_project_snippet do
noteable { create(:project_snippet, project: project) } noteable { association(:project_snippet, project: project) }
end end
trait :on_personal_snippet do trait :on_personal_snippet do
noteable { create(:personal_snippet) } noteable { association(:personal_snippet) }
project { nil } project { nil }
end end
......
...@@ -11,4 +11,5 @@ FactoryBot.define do ...@@ -11,4 +11,5 @@ FactoryBot.define do
sequence(:label_title) { |n| "label#{n}" } sequence(:label_title) { |n| "label#{n}" }
sequence(:branch) { |n| "my-branch-#{n}" } sequence(:branch) { |n| "my-branch-#{n}" }
sequence(:past_time) { |n| 4.hours.ago + (2 * n).seconds } sequence(:past_time) { |n| 4.hours.ago + (2 * n).seconds }
sequence(:iid)
end end
...@@ -27,7 +27,7 @@ describe SnippetsController, '(JavaScript fixtures)', type: :controller do ...@@ -27,7 +27,7 @@ describe SnippetsController, '(JavaScript fixtures)', type: :controller do
end end
it 'snippets/show.html' do 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 }) get(:show, params: { id: snippet.to_param })
......
...@@ -96,7 +96,7 @@ exports[`Dashboard template matches the default snapshot 1`] = ` ...@@ -96,7 +96,7 @@ exports[`Dashboard template matches the default snapshot 1`] = `
variant="default" variant="default"
> >
<icon-stub <icon-stub
name="repeat" name="retry"
size="16" size="16"
/> />
</gl-deprecated-button-stub> </gl-deprecated-button-stub>
......
...@@ -27,25 +27,9 @@ describe GitlabSchema.types['Snippet'] do ...@@ -27,25 +27,9 @@ describe GitlabSchema.types['Snippet'] do
end end
end end
describe 'Repository URLs' do shared_examples 'snippets with repositories' 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 snippet has repository' 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 it 'responds with repository URLs' do
expect(response['sshUrlToRepo']).to eq(snippet.ssh_url_to_repo) expect(response['sshUrlToRepo']).to eq(snippet.ssh_url_to_repo)
...@@ -60,14 +44,44 @@ describe GitlabSchema.types['Snippet'] do ...@@ -60,14 +44,44 @@ describe GitlabSchema.types['Snippet'] do
it_behaves_like 'response without repository URLs' it_behaves_like 'response without repository URLs'
end end
end end
end
shared_examples 'snippets without repositories' do
context 'when snippet does not have a repository' 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' it_behaves_like 'response without repository URLs'
end end
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 describe '#blob' do
let(:query_blob) { subject.dig('data', 'snippets', 'edges')[0]['node']['blob'] } let(:query_blob) { subject.dig('data', 'snippets', 'edges')[0]['node']['blob'] }
let(:query) do let(:query) do
......
...@@ -181,7 +181,7 @@ describe EventsHelper do ...@@ -181,7 +181,7 @@ describe EventsHelper do
end end
it 'returns a project snippet note url' do 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}") expect(subject).to eq("#{project_base_url}/snippets/#{event.note_target.id}#note_#{event.target.id}")
end end
......
...@@ -28,18 +28,6 @@ describe Gitlab::Danger::Changelog do ...@@ -28,18 +28,6 @@ describe Gitlab::Danger::Changelog do
describe '#needed?' do describe '#needed?' do
subject { changelog.needed? } 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 where(:categories, :labels) do
{ backend: nil } | %w[backend backstage] { backend: nil } | %w[backend backstage]
{ frontend: nil, docs: nil } | ['ci-build'] { frontend: nil, docs: nil } | ['ci-build']
...@@ -50,7 +38,7 @@ describe Gitlab::Danger::Changelog do ...@@ -50,7 +38,7 @@ describe Gitlab::Danger::Changelog do
let(:changes_by_category) { categories } let(:changes_by_category) { categories }
let(:mr_labels) { labels } 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 is_expected.to be_falsy
end end
end end
......
...@@ -3,11 +3,11 @@ ...@@ -3,11 +3,11 @@
require 'spec_helper' require 'spec_helper'
describe Gitlab::Gfm::ReferenceRewriter do describe Gitlab::Gfm::ReferenceRewriter do
let(:group) { create(:group) } let_it_be(:group) { create(:group) }
let(:old_project) { create(:project, name: 'old-project', group: group) } let_it_be(:user) { create(:user) }
let(:new_project) { create(:project, name: 'new-project', group: group) }
let(: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(:old_project_ref) { old_project.to_reference_base(new_project) }
let(:text) { 'some text' } let(:text) { 'some text' }
......
...@@ -4475,4 +4475,73 @@ describe User, :do_not_mock_admin_mode do ...@@ -4475,4 +4475,73 @@ describe User, :do_not_mock_admin_mode do
end end
end 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 end
...@@ -1889,11 +1889,11 @@ describe API::Commits do ...@@ -1889,11 +1889,11 @@ describe API::Commits do
context 'unsigned commit' do context 'unsigned commit' do
it_behaves_like '404 response' do it_behaves_like '404 response' do
let(:request) { get api(route, current_user) } let(:request) { get api(route, current_user) }
let(:message) { '404 GPG Signature Not Found'} let(:message) { '404 Signature Not Found'}
end end
end end
context 'signed commit' do context 'gpg signed commit' do
let(:commit) { project.repository.commit(GpgHelpers::SIGNED_COMMIT_SHA) } let(:commit) { project.repository.commit(GpgHelpers::SIGNED_COMMIT_SHA) }
let(:commit_id) { commit.id } let(:commit_id) { commit.id }
...@@ -1901,11 +1901,35 @@ describe API::Commits do ...@@ -1901,11 +1901,35 @@ describe API::Commits do
get api(route, current_user) get api(route, current_user)
expect(response).to have_gitlab_http_status(:ok) 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_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_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['gpg_key_primary_keyid']).to eq(commit.signature.gpg_key_primary_keyid)
expect(json_response['verification_status']).to eq(commit.signature.verification_status) expect(json_response['verification_status']).to eq(commit.signature.verification_status)
end end
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
end end
...@@ -31,7 +31,7 @@ describe API::Discussions do ...@@ -31,7 +31,7 @@ describe API::Discussions do
context 'when noteable is a Snippet' do context 'when noteable is a Snippet' do
let!(:snippet) { create(:project_snippet, project: project, author: user) } 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 it_behaves_like 'discussions API', 'projects', 'snippets', 'id' do
let(:parent) { project } let(:parent) { project }
......
...@@ -33,6 +33,7 @@ eos ...@@ -33,6 +33,7 @@ eos
def sample_commit def sample_commit
OpenStruct.new( OpenStruct.new(
id: "570e7b2abdd848b95f2f578043fc23bd6f6fd24d", id: "570e7b2abdd848b95f2f578043fc23bd6f6fd24d",
sha: "570e7b2abdd848b95f2f578043fc23bd6f6fd24d",
parent_id: '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9', parent_id: '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9',
author_full_name: "Dmitriy Zaporozhets", author_full_name: "Dmitriy Zaporozhets",
author_email: "dmitriy.zaporozhets@gmail.com", author_email: "dmitriy.zaporozhets@gmail.com",
...@@ -50,6 +51,7 @@ eos ...@@ -50,6 +51,7 @@ eos
def another_sample_commit def another_sample_commit
OpenStruct.new( OpenStruct.new(
id: "e56497bb5f03a90a51293fc6d516788730953899", id: "e56497bb5f03a90a51293fc6d516788730953899",
sha: "e56497bb5f03a90a51293fc6d516788730953899",
parent_id: '4cd80ccab63c82b4bad16faa5193fbd2aa06df40', parent_id: '4cd80ccab63c82b4bad16faa5193fbd2aa06df40',
author_full_name: "Sytse Sijbrandij", author_full_name: "Sytse Sijbrandij",
author_email: "sytse@gitlab.com", author_email: "sytse@gitlab.com",
...@@ -69,6 +71,7 @@ eos ...@@ -69,6 +71,7 @@ eos
def sample_big_commit def sample_big_commit
OpenStruct.new( OpenStruct.new(
id: "913c66a37b4a45b9769037c55c2d238bd0942d2e", id: "913c66a37b4a45b9769037c55c2d238bd0942d2e",
sha: "913c66a37b4a45b9769037c55c2d238bd0942d2e",
author_full_name: "Dmitriy Zaporozhets", author_full_name: "Dmitriy Zaporozhets",
author_email: "dmitriy.zaporozhets@gmail.com", author_email: "dmitriy.zaporozhets@gmail.com",
message: <<eos message: <<eos
...@@ -81,6 +84,7 @@ eos ...@@ -81,6 +84,7 @@ eos
def sample_image_commit def sample_image_commit
OpenStruct.new( OpenStruct.new(
id: "2f63565e7aac07bcdadb654e253078b727143ec4", id: "2f63565e7aac07bcdadb654e253078b727143ec4",
sha: "2f63565e7aac07bcdadb654e253078b727143ec4",
author_full_name: "Dmitriy Zaporozhets", author_full_name: "Dmitriy Zaporozhets",
author_email: "dmitriy.zaporozhets@gmail.com", author_email: "dmitriy.zaporozhets@gmail.com",
old_blob_id: '33f3729a45c02fc67d00adb1b8bca394b0e761d9', old_blob_id: '33f3729a45c02fc67d00adb1b8bca394b0e761d9',
......
...@@ -781,10 +781,10 @@ ...@@ -781,10 +781,10 @@
eslint-plugin-vue "^6.2.1" eslint-plugin-vue "^6.2.1"
vue-eslint-parser "^7.0.0" vue-eslint-parser "^7.0.0"
"@gitlab/svgs@1.116.0": "@gitlab/svgs@1.117.0":
version "1.116.0" version "1.117.0"
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.116.0.tgz#a3c89f950bb256c2e109444c9a85fecdd261292c" resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.117.0.tgz#05239ddcf529c62ca29e1ec1a25a7e24efb98207"
integrity sha512-sZLn3acu0IyrSnZRU1rE3UjxF6FlwvBNfjKQgn0qclxdbe8Ya6cGNVq4aGdCEkHwvb9rFpKbfHBujVgVKNkxSA== integrity sha512-dGy/VWuRAFCTZX3Yqu1+RnAHTSUWafteIk/RMfUCN9B/EMbYzjhYsNy0NLVoZ23Rj/KGv1bUGHvyQCoPP6VzpA==
"@gitlab/ui@11.0.0": "@gitlab/ui@11.0.0":
version "11.0.0" version "11.0.0"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment