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
<!-- 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?
......
......@@ -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'
......
......@@ -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>
......
......@@ -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; }
......
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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
......
---
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:
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
......
......@@ -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
......
......@@ -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 &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
......
......@@ -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 | | | ✓ | ✓ | ✓ |
......
......@@ -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.
......
# Design Management **(PREMIUM)**
# Design Management
> [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
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
......
......@@ -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
......
......@@ -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
......
......@@ -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
# 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 ""
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 ""
......
......@@ -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)
......
......@@ -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
......
......@@ -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)
......
......@@ -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
......
......@@ -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|
##
......
......@@ -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
# frozen_string_literal: true
FactoryBot.define do
factory :issue do
factory :issue, traits: [:has_internal_id] do
title { generate(:title) }
project
author { project.creator }
......
# 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 }
......
# frozen_string_literal: true
FactoryBot.define do
factory :milestone do
factory :milestone, traits: [:has_internal_id] do
title
transient do
......
......@@ -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
......
......@@ -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
......@@ -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 })
......
......@@ -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>
......
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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' }
......
......@@ -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
......@@ -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
......@@ -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 }
......
......@@ -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',
......
......@@ -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"
......
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