Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab/issue_templates/Feature proposal.md2
-rw-r--r--.gitlab/issue_templates/Lean Feature Proposal.md2
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--app/assets/javascripts/error_tracking/components/error_tracking_list.vue6
-rw-r--r--app/models/project_services/jira_service.rb5
-rw-r--r--app/views/profiles/accounts/show.html.haml2
-rw-r--r--app/views/profiles/two_factor_auths/show.html.haml3
-rw-r--r--changelogs/unreleased/277436-2fa-ux-text-changes.yml5
-rw-r--r--changelogs/unreleased/docs-redirects-removal-6.yml5
-rw-r--r--changelogs/unreleased/map-prometheus-payload-severity.yml5
-rw-r--r--config/feature_flags/development/rubygem_packages.yml8
-rw-r--r--config/feature_flags/development/user_mode_in_session.yml8
-rw-r--r--config/gitlab.yml.example4
-rw-r--r--danger/product_intelligence/Dangerfile2
-rw-r--r--data/whats_new/202008180003_13_01.yml2
-rw-r--r--doc/development/testing_guide/frontend_testing.md32
-rw-r--r--doc/operations/metrics/alerts.md8
-rw-r--r--doc/raketasks/backup_restore.md1
-rw-r--r--lib/api/api.rb1
-rw-r--r--lib/api/nuget_group_packages.rb2
-rw-r--r--lib/api/nuget_project_packages.rb2
-rw-r--r--lib/api/rubygem_packages.rb102
-rw-r--r--lib/feature.rb2
-rw-r--r--lib/gitlab/alert_management/payload/prometheus.rb46
-rw-r--r--lib/gitlab/api_authentication/token_locator.rb11
-rw-r--r--lib/gitlab/api_authentication/token_resolver.rb100
-rw-r--r--lib/gitlab/ci/templates/Maven.gitlab-ci.yml4
-rw-r--r--lib/gitlab/ci/templates/Security/License-Scanning.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/variables/collection/sorted.rb7
-rw-r--r--lib/gitlab/gon_helper.rb1
-rw-r--r--lib/gitlab/usage_data_counters/aggregated_metrics/common.yml10
-rw-r--r--locale/gitlab.pot12
-rw-r--r--qa/README.md2
-rw-r--r--spec/features/users/login_spec.rb2
-rw-r--r--spec/frontend/__helpers__/fake_date/fake_date.js (renamed from spec/frontend/__helpers__/fake_date.js)21
-rw-r--r--spec/frontend/__helpers__/fake_date/fake_date_spec.js (renamed from spec/frontend/__helpers__/fake_date_spec.js)8
-rw-r--r--spec/frontend/__helpers__/fake_date/index.js2
-rw-r--r--spec/frontend/__helpers__/fake_date/jest.js41
-rw-r--r--spec/frontend/__helpers__/jest_execution_watcher.js12
-rw-r--r--spec/frontend/access_tokens/components/expires_at_field_spec.js3
-rw-r--r--spec/frontend/analytics/instance_statistics/components/projects_and_groups_chart_spec.js5
-rw-r--r--spec/frontend/analytics/instance_statistics/components/users_chart_spec.js5
-rw-r--r--spec/frontend/diffs/components/compare_dropdown_layout_spec.js2
-rw-r--r--spec/frontend/environment.js5
-rw-r--r--spec/frontend/error_tracking/components/error_tracking_list_spec.js4
-rw-r--r--spec/frontend/frequent_items/components/app_spec.js31
-rw-r--r--spec/frontend/issuable_list/components/issuable_item_spec.js5
-rw-r--r--spec/frontend/issuable_show/components/issuable_body_spec.js9
-rw-r--r--spec/frontend/issues_list/components/issuable_spec.js29
-rw-r--r--spec/frontend/releases/components/release_block_footer_spec.js24
-rw-r--r--spec/frontend/test_setup.js5
-rw-r--r--spec/lib/gitlab/alert_management/payload/prometheus_spec.rb65
-rw-r--r--spec/lib/gitlab/api_authentication/token_locator_spec.rb21
-rw-r--r--spec/lib/gitlab/api_authentication/token_resolver_spec.rb63
-rw-r--r--spec/lib/gitlab/ci/variables/collection/sorted_spec.rb20
-rw-r--r--spec/models/project_services/jira_service_spec.rb2
-rw-r--r--spec/presenters/ci/build_runner_presenter_spec.rb4
-rw-r--r--spec/requests/api/rubygem_packages_spec.rb139
-rw-r--r--[-rwxr-xr-x]vendor/gitignore/C++.gitignore0
-rw-r--r--[-rwxr-xr-x]vendor/gitignore/Java.gitignore0
60 files changed, 773 insertions, 160 deletions
diff --git a/.gitlab/issue_templates/Feature proposal.md b/.gitlab/issue_templates/Feature proposal.md
index 98cf778f196..1090a04ad36 100644
--- a/.gitlab/issue_templates/Feature proposal.md
+++ b/.gitlab/issue_templates/Feature proposal.md
@@ -61,7 +61,7 @@ Consider adding checkboxes and expectations of users with certain levels of memb
<!-- See the Feature Change Documentation Workflow https://docs.gitlab.com/ee/development/documentation/workflow.html#for-a-product-change
-* Add all known Documentation Requirements in this section. See https://docs.gitlab.com/ee/development/documentation/feature-change-workflow.html#documentation-requirements
+* Add all known Documentation Requirements in this section. See https://docs.gitlab.com/ee/development/documentation/workflow.html
* If this feature requires changing permissions, update the permissions document. See https://docs.gitlab.com/ee/user/permissions.html -->
### Availability & Testing
diff --git a/.gitlab/issue_templates/Lean Feature Proposal.md b/.gitlab/issue_templates/Lean Feature Proposal.md
index c1db9356fa4..a1f217fc624 100644
--- a/.gitlab/issue_templates/Lean Feature Proposal.md
+++ b/.gitlab/issue_templates/Lean Feature Proposal.md
@@ -73,7 +73,7 @@ Consider adding checkboxes and expectations of users with certain levels of memb
See the Feature Change Documentation Workflow https://docs.gitlab.com/ee/development/documentation/workflow.html#for-a-product-change
-* Add all known Documentation Requirements in this section. See https://docs.gitlab.com/ee/development/documentation/feature-change-workflow.html#documentation-requirements
+* Add all known Documentation Requirements in this section. See https://docs.gitlab.com/ee/development/documentation/workflow.html
* If this feature requires changing permissions, update the permissions document. See https://docs.gitlab.com/ee/user/permissions.html
### Availability & Testing
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index d7c181541bf..76e955d251d 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-320f41869d84d64ebbec8d3e0febfb37eca05ffb
+88ef3e7f64498ae3574f29b0705c29cf3b4e9311
diff --git a/app/assets/javascripts/error_tracking/components/error_tracking_list.vue b/app/assets/javascripts/error_tracking/components/error_tracking_list.vue
index b712c8d6e85..04efd9fff40 100644
--- a/app/assets/javascripts/error_tracking/components/error_tracking_list.vue
+++ b/app/assets/javascripts/error_tracking/components/error_tracking_list.vue
@@ -15,6 +15,7 @@ import {
GlPagination,
} from '@gitlab/ui';
import { isEmpty } from 'lodash';
+import { helpPagePath } from '~/helpers/help_page_helper';
import AccessorUtils from '~/lib/utils/accessor';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
import { __ } from '~/locale';
@@ -138,6 +139,9 @@ export default {
paginationRequired() {
return !isEmpty(this.pagination);
},
+ errorTrackingHelpUrl() {
+ return helpPagePath('operations/error_tracking');
+ },
},
watch: {
pagination() {
@@ -404,7 +408,7 @@ export default {
<template #description>
<div>
<span>{{ __('Monitor your errors by integrating with Sentry.') }}</span>
- <gl-link target="_blank" href="/help/user/project/operations/error_tracking.html">{{
+ <gl-link target="_blank" :href="errorTrackingHelpUrl">{{
__('More information')
}}</gl-link>
</div>
diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb
index c637813ae58..5857d86f921 100644
--- a/app/models/project_services/jira_service.rb
+++ b/app/models/project_services/jira_service.rb
@@ -159,7 +159,10 @@ class JiraService < IssueTrackerService
# support any events.
end
- def find_issue(issue_key, options = {})
+ def find_issue(issue_key, rendered_fields: false)
+ options = {}
+ options = options.merge(expand: 'renderedFields') if rendered_fields
+
jira_request { client.Issue.find(issue_key, options) }
end
diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml
index e8b2c5db4e6..e16bb789a4c 100644
--- a/app/views/profiles/accounts/show.html.haml
+++ b/app/views/profiles/accounts/show.html.haml
@@ -13,7 +13,7 @@
%button.gl-alert-dismiss.js-close-2fa-enabled-success-alert{ type: 'button', aria: { label: _('Close') } }
= sprite_icon('close', size: 16)
.gl-alert-body
- = _('Congratulations! You have enabled Two-factor Authentication!')
+ = html_escape(_('You have set up 2FA for your account! If you lose access to your 2FA device, you can use your recovery codes to access your account. Alternatively, if you upload an SSH key, you can %{anchorOpen}use that key to generate additional recovery codes%{anchorClose}.')) % { anchorOpen: '<a href="%{href}">'.html_safe % { href: help_page_path('user/profile/account/two_factor_authentication', anchor: 'generate-new-recovery-codes-using-ssh') }, anchorClose: '</a>'.html_safe }
.row.gl-mt-3.js-search-settings-section
.col-lg-4.profile-settings-sidebar
diff --git a/app/views/profiles/two_factor_auths/show.html.haml b/app/views/profiles/two_factor_auths/show.html.haml
index ff4ddd4ad69..7c9b00f9b06 100644
--- a/app/views/profiles/two_factor_auths/show.html.haml
+++ b/app/views/profiles/two_factor_auths/show.html.haml
@@ -26,8 +26,7 @@
- else
%p
- - help_link_start = '<a href="%{url}" target="_blank">' % { url: help_page_path('user/profile/account/two_factor_authentication') }
- - register_2fa_token = _('Install a soft token authenticator like %{free_otp_link} or Google Authenticator from your application repository and use that app to scan this QR code. More information is available in the %{help_link_start}documentation%{help_link_end}.') % { free_otp_link:'<a href="https://freeotp.github.io/">FreeOTP</a>', help_link_start:help_link_start, help_link_end:'</a>' }
+ - register_2fa_token = _('We recommend cloud-based mobile authenticator apps such as Authy, Duo Mobile, and LastPass. They can restore access if you lose your hardware device.')
= register_2fa_token.html_safe
.row.gl-mb-3
.col-md-4
diff --git a/changelogs/unreleased/277436-2fa-ux-text-changes.yml b/changelogs/unreleased/277436-2fa-ux-text-changes.yml
new file mode 100644
index 00000000000..59fc9215b91
--- /dev/null
+++ b/changelogs/unreleased/277436-2fa-ux-text-changes.yml
@@ -0,0 +1,5 @@
+---
+title: Change UI text for 2FA setup
+merge_request: 53677
+author:
+type: changed
diff --git a/changelogs/unreleased/docs-redirects-removal-6.yml b/changelogs/unreleased/docs-redirects-removal-6.yml
new file mode 100644
index 00000000000..f03d5df1442
--- /dev/null
+++ b/changelogs/unreleased/docs-redirects-removal-6.yml
@@ -0,0 +1,5 @@
+---
+title: Update links to redirected docs
+merge_request: 53004
+author:
+type: other
diff --git a/changelogs/unreleased/map-prometheus-payload-severity.yml b/changelogs/unreleased/map-prometheus-payload-severity.yml
new file mode 100644
index 00000000000..4fe69286c09
--- /dev/null
+++ b/changelogs/unreleased/map-prometheus-payload-severity.yml
@@ -0,0 +1,5 @@
+---
+title: Map common severity values from a Prometheus alert payload
+merge_request: 50871
+author:
+type: added
diff --git a/config/feature_flags/development/rubygem_packages.yml b/config/feature_flags/development/rubygem_packages.yml
new file mode 100644
index 00000000000..9f394f091bb
--- /dev/null
+++ b/config/feature_flags/development/rubygem_packages.yml
@@ -0,0 +1,8 @@
+---
+name: rubygem_packages
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/52147
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/299383
+milestone: '13.9'
+type: development
+group: group::package
+default_enabled: false
diff --git a/config/feature_flags/development/user_mode_in_session.yml b/config/feature_flags/development/user_mode_in_session.yml
index a3c4d44e4ce..1b0a0053cf4 100644
--- a/config/feature_flags/development/user_mode_in_session.yml
+++ b/config/feature_flags/development/user_mode_in_session.yml
@@ -1,8 +1,8 @@
---
name: user_mode_in_session
-introduced_by_url:
-rollout_issue_url:
-milestone:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/16981
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/321025
+milestone: 12.4
type: development
-group:
+group: group::access
default_enabled: false
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index 29b60aa91c5..65627b0e166 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -416,7 +416,7 @@ production: &base
## Gravatar
## If using gravatar.com, there's nothing to change here. For Libravatar
## you'll need to provide the custom URLs. For more information,
- ## see: https://docs.gitlab.com/ee/customization/libravatar.html
+ ## see: https://docs.gitlab.com/ee/administration/libravatar.html
gravatar:
# Gravatar/Libravatar URLs: possible placeholders: %{hash} %{size} %{email} %{username}
# plain_url: "http://..." # default: https://www.gravatar.com/avatar/%{hash}?s=%{size}&d=identicon
@@ -590,7 +590,7 @@ production: &base
# enabled: true
# primary_api_url: http://localhost:5000/ # internal address to the primary registry, will be used by GitLab to directly communicate with primary registry API
- ## Feature Flag https://docs.gitlab.com/ee/user/project/operations/feature_flags.html
+ ## Feature Flag https://docs.gitlab.com/ee/operations/feature_flags.html
feature_flags:
unleash:
# enabled: false
diff --git a/danger/product_intelligence/Dangerfile b/danger/product_intelligence/Dangerfile
index 89c3e969bdf..1a53b485093 100644
--- a/danger/product_intelligence/Dangerfile
+++ b/danger/product_intelligence/Dangerfile
@@ -3,7 +3,7 @@
CHANGED_FILES_MESSAGE = <<~MSG
For the following files, a review from the [Data team and Product Intelligence team](https://gitlab.com/groups/gitlab-org/growth/product-intelligence/engineers/-/group_members?with_inherited_permissions=exclude) is recommended
-Please check the ~"product intelligence" [guide](https://docs.gitlab.com/ee/development/product_analytics/usage_ping.html) and reach out to %<engineers_group>s group for a review.
+Please check the ~"product intelligence" [guide](https://docs.gitlab.com/ee/development/usage_ping.html) and reach out to %<engineers_group>s group for a review.
%<changed_files>s
diff --git a/data/whats_new/202008180003_13_01.yml b/data/whats_new/202008180003_13_01.yml
index dd132c50806..9f8a87ebe27 100644
--- a/data/whats_new/202008180003_13_01.yml
+++ b/data/whats_new/202008180003_13_01.yml
@@ -8,7 +8,7 @@
self-managed: true
gitlab-com: true
packages: [Free, Premium, Ultimate]
- url: https://docs.gitlab.com/ee/user/project/operations/alert_management.html
+ url: https://docs.gitlab.com/ee/operations/incident_management/index.html
image_url: https://about.gitlab.com/images/13_1/alert_management.png
published_at: 2020-06-22
release: 13.1
diff --git a/doc/development/testing_guide/frontend_testing.md b/doc/development/testing_guide/frontend_testing.md
index a738ee9839e..73fce3a38d7 100644
--- a/doc/development/testing_guide/frontend_testing.md
+++ b/doc/development/testing_guide/frontend_testing.md
@@ -655,15 +655,41 @@ Non-determinism is the breeding ground for flaky and brittle specs. Such specs e
### Faking `Date` for determinism
-Consider using `useFakeDate` to ensure a consistent value is returned with every `new Date()` or `Date.now()`.
+`Date` is faked by default in our Jest environment. This means every call to `Date()` or `Date.now()` returns a fixed deterministic value.
+
+If you really need to change the default fake date, you can call `useFakeDate` within any `describe` block, and
+the date will be replaced for that specs within that `describe` context only:
```javascript
import { useFakeDate } from 'helpers/fake_date';
describe('cool/component', () => {
- useFakeDate();
+ // Default fake `Date`
+ const TODAY = new Date();
- // ...
+ // NOTE: `useFakeDate` cannot be called during test execution (i.e. inside `it`, `beforeEach`, `beforeAll`, etc.).
+ describe("on Ada Lovelace's Birthday", () => {
+ useFakeDate(1815, 11, 10)
+
+ it('Date is no longer default', () => {
+ expect(new Date()).not.toEqual(TODAY);
+ });
+ });
+
+ it('Date is still default in this scope', () => {
+ expect(new Date()).toEqual(TODAY)
+ });
+})
+```
+
+Similarly, if you really need to use the real `Date` class, then you can import and call `useRealDate` within any `describe` block:
+
+```javascript
+import { useRealDate } from 'helpers/fake_date';
+
+// NOTE: `useRealDate` cannot be called during test execution (i.e. inside `it`, `beforeEach`, `beforeAll`, etc.).
+describe('with real date', () => {
+ useRealDate();
});
```
diff --git a/doc/operations/metrics/alerts.md b/doc/operations/metrics/alerts.md
index 9c33ea98411..98beb8d6773 100644
--- a/doc/operations/metrics/alerts.md
+++ b/doc/operations/metrics/alerts.md
@@ -110,6 +110,14 @@ values extracted from the [`alerts` field in webhook payload](https://prometheus
- `full_query`: Alert query extracted from the payload's `generatorURL` field
- Optional list of attached annotations extracted from `annotations/*`
- Alert [GFM](../../user/markdown.md): GitLab Flavored Markdown from the payload's `annotations/gitlab_incident_markdown` field.
+- Alert Severity (introduced in GitLab version [13.9](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/50871):
+ Extracted from the alert payload field `labels/severity`. Maps case-insensitive
+ value to [Alert's severity](../incident_management/alerts.md#alert-severity):
+ - **Critical**: `critical`, `s1`, `p1`, `emergency`, `fatal`, or any value not in this list
+ - **High**: `high`, `s2`, `p2`, `major`, `page`
+ - **Medium**: `medium`, `s3`, `p3`, `error`, `alert`
+ - **Low**: `low`, `s4`, `p4`, `warn`, `warning`
+ - **Info**: `info`, `s5`, `p5`, `debug`, `information`, `notice`
When GitLab receives a **Recovery Alert**, it closes the associated issue.
This action is recorded as a system message on the issue indicating that it
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index 24b1c7a6978..690820cf6a6 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -1285,6 +1285,7 @@ You may need to reconfigure or restart GitLab for the changes to take effect.
UPDATE namespaces SET runners_token = null, runners_token_encrypted = null;
-- Clear instance tokens
UPDATE application_settings SET runners_registration_token_encrypted = null;
+ UPDATE application_settings SET encrypted_ci_jwt_signing_key = null;
-- Clear runner tokens
UPDATE ci_runners SET token = null, token_encrypted = null;
```
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 725dddead70..7ba37ed7f51 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -269,6 +269,7 @@ module API
mount ::API::RemoteMirrors
mount ::API::Repositories
mount ::API::ResourceAccessTokens
+ mount ::API::RubygemPackages
mount ::API::Search
mount ::API::Services
mount ::API::Settings
diff --git a/lib/api/nuget_group_packages.rb b/lib/api/nuget_group_packages.rb
index e373f051b24..a80de06d6b0 100644
--- a/lib/api/nuget_group_packages.rb
+++ b/lib/api/nuget_group_packages.rb
@@ -18,7 +18,7 @@ module API
default_format :json
authenticate_with do |accept|
- accept.token_types(:personal_access_token, :deploy_token, :job_token)
+ accept.token_types(:personal_access_token_with_username, :deploy_token_with_username, :job_token_with_username)
.sent_through(:http_basic_auth)
end
diff --git a/lib/api/nuget_project_packages.rb b/lib/api/nuget_project_packages.rb
index 2146f4d4b78..e071b6bd68f 100644
--- a/lib/api/nuget_project_packages.rb
+++ b/lib/api/nuget_project_packages.rb
@@ -20,7 +20,7 @@ module API
default_format :json
authenticate_with do |accept|
- accept.token_types(:personal_access_token, :deploy_token, :job_token)
+ accept.token_types(:personal_access_token_with_username, :deploy_token_with_username, :job_token_with_username)
.sent_through(:http_basic_auth)
end
diff --git a/lib/api/rubygem_packages.rb b/lib/api/rubygem_packages.rb
new file mode 100644
index 00000000000..7819aab879c
--- /dev/null
+++ b/lib/api/rubygem_packages.rb
@@ -0,0 +1,102 @@
+# frozen_string_literal: true
+
+###
+# API endpoints for the RubyGem package registry
+module API
+ class RubygemPackages < ::API::Base
+ include ::API::Helpers::Authentication
+ helpers ::API::Helpers::PackagesHelpers
+
+ feature_category :package_registry
+
+ # The Marshal version can be found by "#{Marshal::MAJOR_VERSION}.#{Marshal::MINOR_VERSION}"
+ # Updating the version should require a GitLab API version change.
+ MARSHAL_VERSION = '4.8'
+
+ FILE_NAME_REQUIREMENTS = {
+ file_name: API::NO_SLASH_URL_PART_REGEX
+ }.freeze
+
+ content_type :binary, 'application/octet-stream'
+
+ authenticate_with do |accept|
+ accept.token_types(:personal_access_token, :deploy_token, :job_token)
+ .sent_through(:http_token)
+ end
+
+ before do
+ require_packages_enabled!
+ authenticate!
+ not_found! unless Feature.enabled?(:rubygem_packages, user_project)
+ end
+
+ params do
+ requires :id, type: String, desc: 'The ID or full path of a project'
+ end
+ resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
+ namespace ':id/packages/rubygems' do
+ desc 'Download the spec index file' do
+ detail 'This feature was introduced in GitLab 13.9'
+ end
+ params do
+ requires :file_name, type: String, desc: 'Spec file name'
+ end
+ get ":file_name", requirements: FILE_NAME_REQUIREMENTS do
+ # To be implemented in https://gitlab.com/gitlab-org/gitlab/-/issues/299267
+ not_found!
+ end
+
+ desc 'Download the gemspec file' do
+ detail 'This feature was introduced in GitLab 13.9'
+ end
+ params do
+ requires :file_name, type: String, desc: 'Gemspec file name'
+ end
+ get "quick/Marshal.#{MARSHAL_VERSION}/:file_name", requirements: FILE_NAME_REQUIREMENTS do
+ # To be implemented in https://gitlab.com/gitlab-org/gitlab/-/issues/299284
+ not_found!
+ end
+
+ desc 'Download the .gem package' do
+ detail 'This feature was introduced in GitLab 13.9'
+ end
+ params do
+ requires :file_name, type: String, desc: 'Package file name'
+ end
+ get "gems/:file_name", requirements: FILE_NAME_REQUIREMENTS do
+ # To be implemented in https://gitlab.com/gitlab-org/gitlab/-/issues/299283
+ not_found!
+ end
+
+ namespace 'api/v1' do
+ desc 'Authorize a gem upload from workhorse' do
+ detail 'This feature was introduced in GitLab 13.9'
+ end
+ post 'gems/authorize' do
+ # To be implemented in https://gitlab.com/gitlab-org/gitlab/-/issues/299263
+ not_found!
+ end
+
+ desc 'Upload a gem' do
+ detail 'This feature was introduced in GitLab 13.9'
+ end
+ post 'gems' do
+ # To be implemented in https://gitlab.com/gitlab-org/gitlab/-/issues/299263
+ not_found!
+ end
+
+ desc 'Fetch a list of dependencies' do
+ detail 'This feature was introduced in GitLab 13.9'
+ end
+ params do
+ optional :gems, type: String, desc: 'Comma delimited gem names'
+ end
+ get 'dependencies' do
+ # To be implemented in https://gitlab.com/gitlab-org/gitlab/-/issues/299282
+ not_found!
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/feature.rb b/lib/feature.rb
index 3d4a919b043..7c926b25587 100644
--- a/lib/feature.rb
+++ b/lib/feature.rb
@@ -133,7 +133,7 @@ class Feature
# This method is called from config/initializers/flipper.rb and can be used
# to register Flipper groups.
- # See https://docs.gitlab.com/ee/development/feature_flags.html#feature-groups
+ # See https://docs.gitlab.com/ee/development/feature_flags/index.html
def register_feature_groups
end
diff --git a/lib/gitlab/alert_management/payload/prometheus.rb b/lib/gitlab/alert_management/payload/prometheus.rb
index 336e9b319e8..f278da7937b 100644
--- a/lib/gitlab/alert_management/payload/prometheus.rb
+++ b/lib/gitlab/alert_management/payload/prometheus.rb
@@ -1,9 +1,9 @@
# frozen_string_literal: true
-# Attribute mapping for alerts via prometheus alerting integration.
module Gitlab
module AlertManagement
module Payload
+ # Attribute mapping for alerts via prometheus alerting integration.
class Prometheus < Base
attribute :alert_markdown, paths: %w(annotations gitlab_incident_markdown)
attribute :annotations, paths: 'annotations'
@@ -26,13 +26,49 @@ module Gitlab
paths: [%w(annotations title),
%w(annotations summary),
%w(labels alertname)]
-
attribute :starts_at_raw,
paths: [%w(startsAt)]
private :starts_at_raw
+ attribute :severity_raw, paths: %w(labels severity)
+ private :severity_raw
+
METRIC_TIME_WINDOW = 30.minutes
+ SEVERITY_MAP = {
+ 'critical' => :critical,
+ 'high' => :high,
+ 'medium' => :medium,
+ 'low' => :low,
+ 'info' => :info,
+ 's1' => :critical,
+ 's2' => :high,
+ 's3' => :medium,
+ 's4' => :low,
+ 's5' => :info,
+ 'p1' => :critical,
+ 'p2' => :high,
+ 'p3' => :medium,
+ 'p4' => :low,
+ 'p5' => :info,
+ 'debug' => :info,
+ 'information' => :info,
+ 'notice' => :info,
+ 'warn' => :low,
+ 'warning' => :low,
+ 'minor' => :low,
+ 'error' => :medium,
+ 'major' => :high,
+ 'emergency' => :critical,
+ 'fatal' => :critical,
+ 'alert' => :medium,
+ 'page' => :high
+ }.freeze
+
+ # Handle an unmapped severity value the same way we treat missing values
+ # so we can fallback to alert's default severity `critical`.
+ UNMAPPED_SEVERITY = nil
+
def monitoring_tool
Gitlab::AlertManagement::Payload::MONITORING_TOOLS[:prometheus]
end
@@ -65,6 +101,12 @@ module Gitlab
project && title && starts_at_raw
end
+ def severity
+ return unless severity_raw
+
+ SEVERITY_MAP.fetch(severity_raw.to_s.downcase, UNMAPPED_SEVERITY)
+ end
+
private
def plain_gitlab_fingerprint
diff --git a/lib/gitlab/api_authentication/token_locator.rb b/lib/gitlab/api_authentication/token_locator.rb
index 32a98908e5b..09039f3fc43 100644
--- a/lib/gitlab/api_authentication/token_locator.rb
+++ b/lib/gitlab/api_authentication/token_locator.rb
@@ -10,7 +10,7 @@ module Gitlab
attr_reader :location
- validates :location, inclusion: { in: %i[http_basic_auth] }
+ validates :location, inclusion: { in: %i[http_basic_auth http_token] }
def initialize(location)
@location = location
@@ -21,6 +21,8 @@ module Gitlab
case @location
when :http_basic_auth
extract_from_http_basic_auth request
+ when :http_token
+ extract_from_http_token request
end
end
@@ -32,6 +34,13 @@ module Gitlab
UsernameAndPassword.new(username, password)
end
+
+ def extract_from_http_token(request)
+ password = request.headers['Authorization']
+ return unless password.present?
+
+ UsernameAndPassword.new(nil, password)
+ end
end
end
end
diff --git a/lib/gitlab/api_authentication/token_resolver.rb b/lib/gitlab/api_authentication/token_resolver.rb
index 5b30777b6ec..9234837cdf7 100644
--- a/lib/gitlab/api_authentication/token_resolver.rb
+++ b/lib/gitlab/api_authentication/token_resolver.rb
@@ -7,7 +7,16 @@ module Gitlab
attr_reader :token_type
- validates :token_type, inclusion: { in: %i[personal_access_token job_token deploy_token] }
+ validates :token_type, inclusion: {
+ in: %i[
+ personal_access_token_with_username
+ job_token_with_username
+ deploy_token_with_username
+ personal_access_token
+ job_token
+ deploy_token
+ ]
+ }
def initialize(token_type)
@token_type = token_type
@@ -38,49 +47,94 @@ module Gitlab
when :deploy_token
resolve_deploy_token raw
+
+ when :personal_access_token_with_username
+ resolve_personal_access_token_with_username raw
+
+ when :job_token_with_username
+ resolve_job_token_with_username raw
+
+ when :deploy_token_with_username
+ resolve_deploy_token_with_username raw
end
end
private
- def resolve_personal_access_token(raw)
- # Check if the password is a personal access token
- pat = ::PersonalAccessToken.find_by_token(raw.password)
- return unless pat
+ def resolve_personal_access_token_with_username(raw)
+ raise ::Gitlab::Auth::UnauthorizedError unless raw.username
+
+ with_personal_access_token(raw) do |pat|
+ break unless pat
- # Ensure that the username matches the token. This check is a subtle
- # departure from the existing behavior of #find_personal_access_token_from_http_basic_auth.
- # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38627#note_435907856
- raise ::Gitlab::Auth::UnauthorizedError unless pat.user.username == raw.username
+ # Ensure that the username matches the token. This check is a subtle
+ # departure from the existing behavior of #find_personal_access_token_from_http_basic_auth.
+ # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38627#note_435907856
+ raise ::Gitlab::Auth::UnauthorizedError unless pat.user.username == raw.username
- pat
+ pat
+ end
end
- def resolve_job_token(raw)
+ def resolve_job_token_with_username(raw)
# Only look for a job if the username is correct
return if ::Gitlab::Auth::CI_JOB_USER != raw.username
- job = ::Ci::AuthJobFinder.new(token: raw.password).execute
+ with_job_token(raw) do |job|
+ job
+ end
+ end
- # Actively reject credentials with the username `gitlab-ci-token` if
- # the password is not a valid job token. This replicates existing
- # behavior of #find_user_from_job_token.
- raise ::Gitlab::Auth::UnauthorizedError unless job
+ def resolve_deploy_token_with_username(raw)
+ with_deploy_token(raw) do |token|
+ break unless token
+
+ # Ensure that the username matches the token. This check is a subtle
+ # departure from the existing behavior of #deploy_token_from_request.
+ # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38627#note_474826205
+ raise ::Gitlab::Auth::UnauthorizedError unless token.username == raw.username
- job
+ token
+ end
+ end
+
+ def resolve_personal_access_token(raw)
+ with_personal_access_token(raw) do |pat|
+ pat
+ end
+ end
+
+ def resolve_job_token(raw)
+ with_job_token(raw) do |job|
+ job
+ end
end
def resolve_deploy_token(raw)
- # Check if the password is a deploy token
+ with_deploy_token(raw) do |token|
+ token
+ end
+ end
+
+ def with_personal_access_token(raw, &block)
+ pat = ::PersonalAccessToken.find_by_token(raw.password)
+ return unless pat
+
+ yield(pat)
+ end
+
+ def with_deploy_token(raw, &block)
token = ::DeployToken.active.find_by_token(raw.password)
return unless token
- # Ensure that the username matches the token. This check is a subtle
- # departure from the existing behavior of #deploy_token_from_request.
- # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38627#note_474826205
- raise ::Gitlab::Auth::UnauthorizedError unless token.username == raw.username
+ yield(token)
+ end
+
+ def with_job_token(raw, &block)
+ job = ::Ci::AuthJobFinder.new(token: raw.password).execute
+ raise ::Gitlab::Auth::UnauthorizedError unless job
- token
+ yield(job)
end
end
end
diff --git a/lib/gitlab/ci/templates/Maven.gitlab-ci.yml b/lib/gitlab/ci/templates/Maven.gitlab-ci.yml
index 84bb0ff3b33..8f64da24410 100644
--- a/lib/gitlab/ci/templates/Maven.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Maven.gitlab-ci.yml
@@ -40,14 +40,14 @@ verify:jdk8:
<<: *verify
# To deploy packages from CI, create a ci_settings.xml file
-# For deploying packages to GitLab's Maven Repository: See https://docs.gitlab.com/ee/user/project/packages/maven_repository.html#creating-maven-packages-with-gitlab-cicd for more details.
+# For deploying packages to GitLab's Maven Repository: See https://docs.gitlab.com/ee/user/packages/maven_repository/index.html#create-maven-packages-with-gitlab-cicd for more details.
# Please note: The GitLab Maven Repository is currently only available in GitLab Premium / Ultimate.
# For `master` branch run `mvn deploy` automatically.
deploy:jdk8:
stage: deploy
script:
- if [ ! -f ci_settings.xml ];
- then echo "CI settings missing\! If deploying to GitLab Maven Repository, please see https://docs.gitlab.com/ee/user/project/packages/maven_repository.html#creating-maven-packages-with-gitlab-cicd for instructions.";
+ then echo "CI settings missing\! If deploying to GitLab Maven Repository, please see https://docs.gitlab.com/ee/user/packages/maven_repository/index.html#create-maven-packages-with-gitlab-cicd for instructions.";
fi
- 'mvn $MAVEN_CLI_OPTS deploy -s ci_settings.xml'
only:
diff --git a/lib/gitlab/ci/templates/Security/License-Scanning.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/License-Scanning.gitlab-ci.yml
index 63237e41376..face4d3af01 100644
--- a/lib/gitlab/ci/templates/Security/License-Scanning.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Security/License-Scanning.gitlab-ci.yml
@@ -1,4 +1,4 @@
-# Read more about this feature here: https://docs.gitlab.com/ee/user/application_security/license_compliance/
+# Read more about this feature here: https://docs.gitlab.com/ee/user/compliance/license_compliance/index.html
#
# Configure the scanning tool through the environment variables.
# List of the variables: https://gitlab.com/gitlab-org/security-products/analyzers/license-finder#settings
diff --git a/lib/gitlab/ci/variables/collection/sorted.rb b/lib/gitlab/ci/variables/collection/sorted.rb
index 6abc6a5644f..e641df10462 100644
--- a/lib/gitlab/ci/variables/collection/sorted.rb
+++ b/lib/gitlab/ci/variables/collection/sorted.rb
@@ -8,8 +8,9 @@ module Gitlab
include TSort
include Gitlab::Utils::StrongMemoize
- def initialize(variables)
+ def initialize(variables, project)
@variables = variables
+ @project = project
end
def valid?
@@ -19,7 +20,7 @@ module Gitlab
# errors sorts an array of variables, ignoring unknown variable references,
# and returning an error string if a circular variable reference is found
def errors
- return if Feature.disabled?(:variable_inside_variable)
+ return if Feature.disabled?(:variable_inside_variable, @project)
strong_memoize(:errors) do
# Check for cyclic dependencies and build error message in that case
@@ -34,7 +35,7 @@ module Gitlab
# sort sorts an array of variables, ignoring unknown variable references.
# If a circular variable reference is found, the original array is returned
def sort
- return @variables if Feature.disabled?(:variable_inside_variable)
+ return @variables if Feature.disabled?(:variable_inside_variable, @project)
return @variables if errors
tsort
diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb
index 46c7935cb1d..fdf736f122d 100644
--- a/lib/gitlab/gon_helper.rb
+++ b/lib/gitlab/gon_helper.rb
@@ -33,6 +33,7 @@ module Gitlab
gon.suggested_label_colors = LabelsHelper.suggested_colors
gon.first_day_of_week = current_user&.first_day_of_week || Gitlab::CurrentSettings.first_day_of_week
gon.ee = Gitlab.ee?
+ gon.dot_com = Gitlab.com?
if current_user
gon.current_user_id = current_user.id
diff --git a/lib/gitlab/usage_data_counters/aggregated_metrics/common.yml b/lib/gitlab/usage_data_counters/aggregated_metrics/common.yml
index 4161759cdeb..4d92202e7fd 100644
--- a/lib/gitlab/usage_data_counters/aggregated_metrics/common.yml
+++ b/lib/gitlab/usage_data_counters/aggregated_metrics/common.yml
@@ -48,3 +48,13 @@
'incident_management_incident_unrelate',
'incident_management_incident_change_confidential'
]
+- name: i_testing_paid_monthly_active_user_total
+ operator: OR
+ source: redis
+ events: [
+ 'i_testing_web_performance_widget_total',
+ 'i_testing_full_code_quality_report_total',
+ 'i_testing_group_code_coverage_visit_total',
+ 'i_testing_load_performance_widget_total',
+ 'i_testing_metrics_report_widget_total'
+]
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 36be2b217c1..b43396635a3 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -7567,9 +7567,6 @@ msgstr ""
msgid "ConfluenceService|Your GitLab Wiki can be accessed here: %{wiki_link}. To re-enable your GitLab Wiki, disable this integration"
msgstr ""
-msgid "Congratulations! You have enabled Two-factor Authentication!"
-msgstr ""
-
msgid "Congratulations, your free trial is activated."
msgstr ""
@@ -15747,9 +15744,6 @@ msgstr ""
msgid "Install GitLab Runner on Kubernetes"
msgstr ""
-msgid "Install a soft token authenticator like %{free_otp_link} or Google Authenticator from your application repository and use that app to scan this QR code. More information is available in the %{help_link_start}documentation%{help_link_end}."
-msgstr ""
-
msgid "Install on clusters"
msgstr ""
@@ -32543,6 +32537,9 @@ msgstr ""
msgid "We heard back from your device. You have been authenticated."
msgstr ""
+msgid "We recommend cloud-based mobile authenticator apps such as Authy, Duo Mobile, and LastPass. They can restore access if you lose your hardware device."
+msgstr ""
+
msgid "We recommend that you buy more Pipeline minutes to avoid any interruption of service."
msgstr ""
@@ -33457,6 +33454,9 @@ msgstr ""
msgid "You have reached your project limit"
msgstr ""
+msgid "You have set up 2FA for your account! If you lose access to your 2FA device, you can use your recovery codes to access your account. Alternatively, if you upload an SSH key, you can %{anchorOpen}use that key to generate additional recovery codes%{anchorClose}."
+msgstr ""
+
msgid "You have successfully purchased a %{plan} plan subscription for %{seats}. You’ll receive a receipt via email."
msgstr ""
diff --git a/qa/README.md b/qa/README.md
index f959acbc366..02fa84f4488 100644
--- a/qa/README.md
+++ b/qa/README.md
@@ -216,7 +216,7 @@ run all the tests in the `Test::Instance::All` scenario, and then enable the
feature flag again if it was enabled earlier.
Note: the QA framework doesn't currently allow you to easily toggle a feature
-flag during a single test, [as you can in unit tests](https://docs.gitlab.com/ee/development/feature_flags.html#specs),
+flag during a single test, [as you can in unit tests](https://docs.gitlab.com/ee/development/feature_flags/index.html),
but [that capability is planned](https://gitlab.com/gitlab-org/quality/team-tasks/issues/77).
Note also that the `--` separator isn't used because `--enable-feature` and `--disable-feature`
diff --git a/spec/features/users/login_spec.rb b/spec/features/users/login_spec.rb
index 5a537c1d4df..1d1120709b5 100644
--- a/spec/features/users/login_spec.rb
+++ b/spec/features/users/login_spec.rb
@@ -765,7 +765,7 @@ RSpec.describe 'Login' do
click_link 'Proceed'
expect(current_path).to eq(profile_account_path)
- expect(page).to have_content('Congratulations! You have enabled Two-factor Authentication!')
+ expect(page).to have_content('You have set up 2FA for your account! If you lose access to your 2FA device, you can use your recovery codes to access your account. Alternatively, if you upload an SSH key, you can use that key to generate additional recovery codes.')
end
end
diff --git a/spec/frontend/__helpers__/fake_date.js b/spec/frontend/__helpers__/fake_date/fake_date.js
index 5391ae04797..bc088ad96b6 100644
--- a/spec/frontend/__helpers__/fake_date.js
+++ b/spec/frontend/__helpers__/fake_date/fake_date.js
@@ -1,11 +1,13 @@
// Frida Kahlo's birthday (6 = July)
-export const DEFAULT_ARGS = [2020, 6, 6];
+const DEFAULT_ARGS = [2020, 6, 6];
const RealDate = Date;
const isMocked = (val) => Boolean(val.mock);
-export const createFakeDateClass = (ctorDefault) => {
+const createFakeDateClass = (ctorDefaultParam = []) => {
+ const ctorDefault = ctorDefaultParam.length ? ctorDefaultParam : DEFAULT_ARGS;
+
const FakeDate = new Proxy(RealDate, {
construct: (target, argArray) => {
const ctorArgs = argArray.length ? argArray : ctorDefault;
@@ -39,11 +41,20 @@ export const createFakeDateClass = (ctorDefault) => {
return FakeDate;
};
-export const useFakeDate = (...args) => {
- const FakeDate = createFakeDateClass(args.length ? args : DEFAULT_ARGS);
+const setGlobalDateToFakeDate = (...args) => {
+ const FakeDate = createFakeDateClass(args);
global.Date = FakeDate;
};
-export const useRealDate = () => {
+const setGlobalDateToRealDate = () => {
global.Date = RealDate;
};
+
+// We use commonjs so that the test environment module can pick this up
+// eslint-disable-next-line import/no-commonjs
+module.exports = {
+ setGlobalDateToFakeDate,
+ setGlobalDateToRealDate,
+ createFakeDateClass,
+ RealDate,
+};
diff --git a/spec/frontend/__helpers__/fake_date_spec.js b/spec/frontend/__helpers__/fake_date/fake_date_spec.js
index b3ed13e238a..730765e52d2 100644
--- a/spec/frontend/__helpers__/fake_date_spec.js
+++ b/spec/frontend/__helpers__/fake_date/fake_date_spec.js
@@ -1,15 +1,11 @@
-import { createFakeDateClass, DEFAULT_ARGS, useRealDate } from './fake_date';
+import { createFakeDateClass } from './fake_date';
describe('spec/helpers/fake_date', () => {
describe('createFakeDateClass', () => {
let FakeDate;
- beforeAll(() => {
- useRealDate();
- });
-
beforeEach(() => {
- FakeDate = createFakeDateClass(DEFAULT_ARGS);
+ FakeDate = createFakeDateClass();
});
it('should use default args', () => {
diff --git a/spec/frontend/__helpers__/fake_date/index.js b/spec/frontend/__helpers__/fake_date/index.js
new file mode 100644
index 00000000000..3d1b124ce79
--- /dev/null
+++ b/spec/frontend/__helpers__/fake_date/index.js
@@ -0,0 +1,2 @@
+export * from './fake_date';
+export * from './jest';
diff --git a/spec/frontend/__helpers__/fake_date/jest.js b/spec/frontend/__helpers__/fake_date/jest.js
new file mode 100644
index 00000000000..65e45619049
--- /dev/null
+++ b/spec/frontend/__helpers__/fake_date/jest.js
@@ -0,0 +1,41 @@
+import { createJestExecutionWatcher } from '../jest_execution_watcher';
+import { RealDate, createFakeDateClass } from './fake_date';
+
+const throwInsideExecutionError = (fnName) => {
+ throw new Error(`Cannot call "${fnName}" during test execution (i.e. within "it", "beforeEach", "beforeAll", etc.).
+
+Instead, please move the call to "${fnName}" inside the "describe" block itself.
+
+ describe('', () => {
+ + ${fnName}();
+
+ it('', () => {
+ - ${fnName}();
+ })
+ })
+`);
+};
+
+const isExecutingTest = createJestExecutionWatcher();
+
+export const useDateInScope = (fnName, factory) => {
+ if (isExecutingTest()) {
+ throwInsideExecutionError(fnName);
+ }
+
+ let origDate;
+
+ beforeAll(() => {
+ origDate = global.Date;
+ global.Date = factory();
+ });
+
+ afterAll(() => {
+ global.Date = origDate;
+ });
+};
+
+export const useFakeDate = (...args) =>
+ useDateInScope('useFakeDate', () => createFakeDateClass(args));
+
+export const useRealDate = () => useDateInScope('useRealDate', () => RealDate);
diff --git a/spec/frontend/__helpers__/jest_execution_watcher.js b/spec/frontend/__helpers__/jest_execution_watcher.js
new file mode 100644
index 00000000000..0fc3d330ec3
--- /dev/null
+++ b/spec/frontend/__helpers__/jest_execution_watcher.js
@@ -0,0 +1,12 @@
+export const createJestExecutionWatcher = () => {
+ let isExecuting = false;
+
+ beforeAll(() => {
+ isExecuting = true;
+ });
+ afterAll(() => {
+ isExecuting = false;
+ });
+
+ return () => isExecuting;
+};
diff --git a/spec/frontend/access_tokens/components/expires_at_field_spec.js b/spec/frontend/access_tokens/components/expires_at_field_spec.js
index cd235d0afa5..4a2815e6931 100644
--- a/spec/frontend/access_tokens/components/expires_at_field_spec.js
+++ b/spec/frontend/access_tokens/components/expires_at_field_spec.js
@@ -1,10 +1,7 @@
import { shallowMount } from '@vue/test-utils';
-import { useFakeDate } from 'helpers/fake_date';
import ExpiresAtField from '~/access_tokens/components/expires_at_field.vue';
describe('~/access_tokens/components/expires_at_field', () => {
- useFakeDate();
-
let wrapper;
const createComponent = () => {
diff --git a/spec/frontend/analytics/instance_statistics/components/projects_and_groups_chart_spec.js b/spec/frontend/analytics/instance_statistics/components/projects_and_groups_chart_spec.js
index bf94e476ea3..93c1e330fa7 100644
--- a/spec/frontend/analytics/instance_statistics/components/projects_and_groups_chart_spec.js
+++ b/spec/frontend/analytics/instance_statistics/components/projects_and_groups_chart_spec.js
@@ -3,7 +3,6 @@ import { GlLineChart } from '@gitlab/ui/dist/charts';
import { GlAlert } from '@gitlab/ui';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
-import { useFakeDate } from 'helpers/fake_date';
import ProjectsAndGroupChart from '~/analytics/instance_statistics/components/projects_and_groups_chart.vue';
import ChartSkeletonLoader from '~/vue_shared/components/resizable_chart/skeleton_loader.vue';
import projectsQuery from '~/analytics/instance_statistics/graphql/queries/projects.query.graphql';
@@ -45,8 +44,8 @@ describe('ProjectsAndGroupChart', () => {
return shallowMount(ProjectsAndGroupChart, {
props: {
- startDate: useFakeDate(2020, 9, 26),
- endDate: useFakeDate(2020, 10, 1),
+ startDate: new Date(2020, 9, 26),
+ endDate: new Date(2020, 10, 1),
totalDataPoints: mockCountsData2.length,
},
localVue,
diff --git a/spec/frontend/analytics/instance_statistics/components/users_chart_spec.js b/spec/frontend/analytics/instance_statistics/components/users_chart_spec.js
index b9fa30643df..b35ab8ec646 100644
--- a/spec/frontend/analytics/instance_statistics/components/users_chart_spec.js
+++ b/spec/frontend/analytics/instance_statistics/components/users_chart_spec.js
@@ -3,7 +3,6 @@ import { GlAreaChart } from '@gitlab/ui/dist/charts';
import { GlAlert } from '@gitlab/ui';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
-import { useFakeDate } from 'helpers/fake_date';
import UsersChart from '~/analytics/instance_statistics/components/users_chart.vue';
import ChartSkeletonLoader from '~/vue_shared/components/resizable_chart/skeleton_loader.vue';
import usersQuery from '~/analytics/instance_statistics/graphql/queries/users.query.graphql';
@@ -31,8 +30,8 @@ describe('UsersChart', () => {
return shallowMount(UsersChart, {
props: {
- startDate: useFakeDate(2020, 9, 26),
- endDate: useFakeDate(2020, 10, 1),
+ startDate: new Date(2020, 9, 26),
+ endDate: new Date(2020, 10, 1),
totalDataPoints: mockCountsData2.length,
},
localVue,
diff --git a/spec/frontend/diffs/components/compare_dropdown_layout_spec.js b/spec/frontend/diffs/components/compare_dropdown_layout_spec.js
index d99933a1ee9..f050d924000 100644
--- a/spec/frontend/diffs/components/compare_dropdown_layout_spec.js
+++ b/spec/frontend/diffs/components/compare_dropdown_layout_spec.js
@@ -69,7 +69,7 @@ describe('CompareDropdownLayout', () => {
expect(findListItemsData()).toEqual([
{
href: 'version/1',
- text: 'version 1 (base) abcdef1 1 commit 2 years ago',
+ text: 'version 1 (base) abcdef1 1 commit 1 year ago',
createdAt: TEST_CREATED_AT,
isActive: true,
},
diff --git a/spec/frontend/environment.js b/spec/frontend/environment.js
index c055702d832..83702b22198 100644
--- a/spec/frontend/environment.js
+++ b/spec/frontend/environment.js
@@ -4,6 +4,7 @@ const path = require('path');
const { ErrorWithStack } = require('jest-util');
const JSDOMEnvironment = require('jest-environment-jsdom');
const { TEST_HOST } = require('./__helpers__/test_constants');
+const { setGlobalDateToFakeDate } = require('./__helpers__/fake_date/fake_date');
const ROOT_PATH = path.resolve(__dirname, '../..');
@@ -12,6 +13,10 @@ class CustomEnvironment extends JSDOMEnvironment {
// Setup testURL so that window.location is setup properly
super({ ...config, testURL: TEST_HOST }, context);
+ // Fake the `Date` for `jsdom` which fixes things like document.cookie
+ // https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39496#note_503084332
+ setGlobalDateToFakeDate();
+
Object.assign(context.console, {
error(...args) {
throw new ErrorWithStack(
diff --git a/spec/frontend/error_tracking/components/error_tracking_list_spec.js b/spec/frontend/error_tracking/components/error_tracking_list_spec.js
index d41233a6b72..034e87c0cf3 100644
--- a/spec/frontend/error_tracking/components/error_tracking_list_spec.js
+++ b/spec/frontend/error_tracking/components/error_tracking_list_spec.js
@@ -298,9 +298,7 @@ describe('ErrorTrackingList', () => {
});
it('shows empty state', () => {
- expect(wrapper.find('a').attributes('href')).toBe(
- '/help/user/project/operations/error_tracking.html',
- );
+ expect(wrapper.find(GlEmptyState).isVisible()).toBe(true);
});
});
diff --git a/spec/frontend/frequent_items/components/app_spec.js b/spec/frontend/frequent_items/components/app_spec.js
index 5b1d397ec0b..ac642bb19b5 100644
--- a/spec/frontend/frequent_items/components/app_spec.js
+++ b/spec/frontend/frequent_items/components/app_spec.js
@@ -3,6 +3,7 @@ import Vue from 'vue';
import { mountComponentWithStore } from 'helpers/vue_mount_component_helper';
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
import waitForPromises from 'helpers/wait_for_promises';
+import { useRealDate } from 'helpers/fake_date';
import axios from '~/lib/utils/axios_utils';
import appComponent from '~/frequent_items/components/app.vue';
import eventHub from '~/frequent_items/event_hub';
@@ -93,23 +94,27 @@ describe('Frequent Items App Component', () => {
expect(projects.length).toBe(1);
});
- it('should increase frequency of report if it was logged multiple times over the course of an hour', () => {
- let projects;
- const newTimestamp = Date.now() + HOUR_IN_MS + 1;
+ describe('with real date', () => {
+ useRealDate();
- vm.logItemAccess(session.storageKey, session.project);
- projects = JSON.parse(storage[session.storageKey]);
+ it('should increase frequency of report if it was logged multiple times over the course of an hour', () => {
+ let projects;
+ const newTimestamp = Date.now() + HOUR_IN_MS + 1;
- expect(projects[0].frequency).toBe(1);
+ vm.logItemAccess(session.storageKey, session.project);
+ projects = JSON.parse(storage[session.storageKey]);
- vm.logItemAccess(session.storageKey, {
- ...session.project,
- lastAccessedOn: newTimestamp,
- });
- projects = JSON.parse(storage[session.storageKey]);
+ expect(projects[0].frequency).toBe(1);
- expect(projects[0].frequency).toBe(2);
- expect(projects[0].lastAccessedOn).not.toBe(session.project.lastAccessedOn);
+ vm.logItemAccess(session.storageKey, {
+ ...session.project,
+ lastAccessedOn: newTimestamp,
+ });
+ projects = JSON.parse(storage[session.storageKey]);
+
+ expect(projects[0].frequency).toBe(2);
+ expect(projects[0].lastAccessedOn).not.toBe(session.project.lastAccessedOn);
+ });
});
it('should always update project metadata', () => {
diff --git a/spec/frontend/issuable_list/components/issuable_item_spec.js b/spec/frontend/issuable_list/components/issuable_item_spec.js
index 65e52d05084..e84bb5074bc 100644
--- a/spec/frontend/issuable_list/components/issuable_item_spec.js
+++ b/spec/frontend/issuable_list/components/issuable_item_spec.js
@@ -1,6 +1,6 @@
import { shallowMount } from '@vue/test-utils';
import { GlLink, GlLabel, GlIcon, GlFormCheckbox } from '@gitlab/ui';
-
+import { useFakeDate } from 'helpers/fake_date';
import IssuableItem from '~/issuable_list/components/issuable_item.vue';
import IssuableAssignees from '~/vue_shared/components/issue/issue_assignees.vue';
@@ -19,6 +19,9 @@ const createComponent = ({ issuableSymbol = '#', issuable = mockIssuable, slots
});
describe('IssuableItem', () => {
+ // The mock data is dependent that this is after our default date
+ useFakeDate(2020, 11, 11);
+
const mockLabels = mockIssuable.labels.nodes;
const mockAuthor = mockIssuable.author;
const originalUrl = gon.gitlab_url;
diff --git a/spec/frontend/issuable_show/components/issuable_body_spec.js b/spec/frontend/issuable_show/components/issuable_body_spec.js
index 4ffbbad4f37..d7455e2774a 100644
--- a/spec/frontend/issuable_show/components/issuable_body_spec.js
+++ b/spec/frontend/issuable_show/components/issuable_body_spec.js
@@ -1,4 +1,5 @@
import { shallowMount } from '@vue/test-utils';
+import { useFakeDate } from 'helpers/fake_date';
import IssuableBody from '~/issuable_show/components/issuable_body.vue';
@@ -35,6 +36,9 @@ const createComponent = (propsData = issuableBodyProps) =>
});
describe('IssuableBody', () => {
+ // Some assertions expect a date later than our default
+ useFakeDate(2020, 11, 11);
+
let wrapper;
beforeEach(() => {
@@ -98,11 +102,8 @@ describe('IssuableBody', () => {
it('renders issuable edit info', () => {
const editedEl = wrapper.find('small');
- const sanitizedText = editedEl.text().replace(/\n/g, ' ').replace(/\s+/g, ' ');
- expect(sanitizedText).toContain('Edited');
- expect(sanitizedText).toContain('ago');
- expect(sanitizedText).toContain(`by ${mockIssuable.updatedBy.name}`);
+ expect(editedEl.text()).toMatchInterpolatedText('Edited 3 months ago by Administrator');
});
it('renders issuable-edit-form when `editFormVisible` prop is true', async () => {
diff --git a/spec/frontend/issues_list/components/issuable_spec.js b/spec/frontend/issues_list/components/issuable_spec.js
index dcc3542e905..776d0f2c2de 100644
--- a/spec/frontend/issues_list/components/issuable_spec.js
+++ b/spec/frontend/issues_list/components/issuable_spec.js
@@ -12,9 +12,15 @@ import { simpleIssue, testAssignees, testLabels } from '../issuable_list_test_da
jest.mock('~/user_popovers');
-const TEST_NOW = '2019-08-28T20:03:04.713Z';
-const TEST_MONTH_AGO = '2019-07-28';
-const TEST_MONTH_LATER = '2019-09-30';
+const TODAY = new Date();
+
+const createTestDateFromDelta = (timeDelta) =>
+ formatDate(new Date(TODAY.getTime() + timeDelta), 'yyyy-mm-dd');
+
+// TODO: Encapsulate date helpers https://gitlab.com/gitlab-org/gitlab/-/issues/320883
+const MONTHS_IN_MS = 1000 * 60 * 60 * 24 * 31;
+const TEST_MONTH_AGO = createTestDateFromDelta(-MONTHS_IN_MS);
+const TEST_MONTH_LATER = createTestDateFromDelta(MONTHS_IN_MS);
const DATE_FORMAT = 'mmm d, yyyy';
const TEST_USER_NAME = 'Tyler Durden';
const TEST_BASE_URL = `${TEST_HOST}/issues`;
@@ -26,16 +32,8 @@ const TEST_MILESTONE = {
const TEXT_CLOSED = 'CLOSED';
const TEST_META_COUNT = 100;
-// Use FixedDate so that time sensitive info in snapshots don't fail
-class FixedDate extends Date {
- constructor(date = TEST_NOW) {
- super(date);
- }
-}
-
describe('Issuable component', () => {
let issuable;
- let DateOrig;
let wrapper;
const factory = (props = {}, scopedLabelsAvailable = false) => {
@@ -63,15 +61,6 @@ describe('Issuable component', () => {
wrapper = null;
});
- beforeAll(() => {
- DateOrig = window.Date;
- window.Date = FixedDate;
- });
-
- afterAll(() => {
- window.Date = DateOrig;
- });
-
const checkExists = (findFn) => () => findFn().exists();
const hasIcon = (iconName, iconWrapper = wrapper) =>
iconWrapper.findAll(GlIcon).wrappers.some((icon) => icon.props('name') === iconName);
diff --git a/spec/frontend/releases/components/release_block_footer_spec.js b/spec/frontend/releases/components/release_block_footer_spec.js
index b3161f9fc0d..cf2f71a78f9 100644
--- a/spec/frontend/releases/components/release_block_footer_spec.js
+++ b/spec/frontend/releases/components/release_block_footer_spec.js
@@ -8,19 +8,9 @@ import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
const originalRelease = getJSONFixture('api/releases/release.json');
-const mockFutureDate = new Date(9999, 0, 0).toISOString();
-let mockIsFutureRelease = false;
-
-jest.mock('~/vue_shared/mixins/timeago', () => ({
- methods: {
- timeFormatted() {
- return mockIsFutureRelease ? 'in 1 month' : '7 fortnights ago';
- },
- tooltipTitle() {
- return 'February 30, 2401';
- },
- },
-}));
+// TODO: Encapsulate date helpers https://gitlab.com/gitlab-org/gitlab/-/issues/320883
+const MONTHS_IN_MS = 1000 * 60 * 60 * 24 * 31;
+const mockFutureDate = new Date(new Date().getTime() + MONTHS_IN_MS).toISOString();
describe('Release block footer', () => {
let wrapper;
@@ -44,7 +34,6 @@ describe('Release block footer', () => {
afterEach(() => {
wrapper.destroy();
wrapper = null;
- mockIsFutureRelease = false;
});
const commitInfoSection = () => wrapper.find('.js-commit-info');
@@ -88,7 +77,7 @@ describe('Release block footer', () => {
it('renders the author and creation time info', () => {
expect(trimText(authorDateInfoSection().text())).toBe(
- `Created 7 fortnights ago by ${release.author.username}`,
+ `Created 1 year ago by ${release.author.username}`,
);
});
@@ -100,7 +89,6 @@ describe('Release block footer', () => {
describe('renders the author and creation time info with future release date', () => {
beforeEach(() => {
- mockIsFutureRelease = true;
factory({ releasedAt: mockFutureDate });
});
@@ -113,7 +101,6 @@ describe('Release block footer', () => {
describe('when the release date is in the future', () => {
beforeEach(() => {
- mockIsFutureRelease = true;
factory({ releasedAt: mockFutureDate });
});
@@ -177,13 +164,12 @@ describe('Release block footer', () => {
beforeEach(() => factory({ author: undefined }));
it('renders the release date without the author name', () => {
- expect(trimText(authorDateInfoSection().text())).toBe(`Created 7 fortnights ago`);
+ expect(trimText(authorDateInfoSection().text())).toBe(`Created 1 year ago`);
});
});
describe('future release without any author info', () => {
beforeEach(() => {
- mockIsFutureRelease = true;
factory({ author: undefined, releasedAt: mockFutureDate });
});
diff --git a/spec/frontend/test_setup.js b/spec/frontend/test_setup.js
index a122b06fdda..61746b3c453 100644
--- a/spec/frontend/test_setup.js
+++ b/spec/frontend/test_setup.js
@@ -3,6 +3,7 @@ import 'jquery';
import * as jqueryMatchers from 'custom-jquery-matchers';
import { config as testUtilsConfig } from '@vue/test-utils';
+import { setGlobalDateToFakeDate } from 'helpers/fake_date';
import Translate from '~/vue_shared/translate';
import { initializeTestTimeout } from './__helpers__/timeout';
import { getJSONFixture, loadHTMLFixture, setHTMLFixture } from './__helpers__/fixtures';
@@ -20,6 +21,10 @@ process.on('unhandledRejection', global.promiseRejectionHandler);
setupManualMocks();
+// Fake the `Date` for the rest of the jest spec runtime environment.
+// https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39496#note_503084332
+setGlobalDateToFakeDate();
+
afterEach(() =>
// give Promises a bit more time so they fail the right test
new Promise(setImmediate).then(() => {
diff --git a/spec/lib/gitlab/alert_management/payload/prometheus_spec.rb b/spec/lib/gitlab/alert_management/payload/prometheus_spec.rb
index 457db58a28b..6db0a714a4c 100644
--- a/spec/lib/gitlab/alert_management/payload/prometheus_spec.rb
+++ b/spec/lib/gitlab/alert_management/payload/prometheus_spec.rb
@@ -156,8 +156,6 @@ RSpec.describe Gitlab::AlertManagement::Payload::Prometheus do
end
describe '#gitlab_fingerprint' do
- subject { parsed_payload.gitlab_fingerprint }
-
let(:raw_payload) do
{
'startsAt' => Time.current.to_s,
@@ -166,6 +164,8 @@ RSpec.describe Gitlab::AlertManagement::Payload::Prometheus do
}
end
+ subject { parsed_payload.gitlab_fingerprint }
+
it 'returns a fingerprint' do
plain_fingerprint = [
parsed_payload.send(:starts_at_raw),
@@ -237,4 +237,65 @@ RSpec.describe Gitlab::AlertManagement::Payload::Prometheus do
it { is_expected.to be_falsey }
end
end
+
+ describe '#severity' do
+ using RSpec::Parameterized::TableSyntax
+
+ let(:raw_payload) { { 'labels' => { 'severity' => payload_severity } } }
+
+ subject { parsed_payload.severity }
+
+ context 'when set' do
+ where(:payload_severity, :expected_severity) do
+ 'critical' | :critical
+ 'high' | :high
+ 'medium' | :medium
+ 'low' | :low
+ 'info' | :info
+
+ 's1' | :critical
+ 's2' | :high
+ 's3' | :medium
+ 's4' | :low
+ 's5' | :info
+ 'p1' | :critical
+ 'p2' | :high
+ 'p3' | :medium
+ 'p4' | :low
+ 'p5' | :info
+
+ 'CRITICAL' | :critical
+ 'cRiTiCaL' | :critical
+ 'S1' | :critical
+
+ 'unmapped' | nil
+ 1 | nil
+ nil | nil
+
+ 'debug' | :info
+ 'information' | :info
+ 'notice' | :info
+ 'warn' | :low
+ 'warning' | :low
+ 'minor' | :low
+ 'error' | :medium
+ 'major' | :high
+ 'emergency' | :critical
+ 'fatal' | :critical
+
+ 'alert' | :medium
+ 'page' | :high
+ end
+
+ with_them do
+ it { is_expected.to eq(expected_severity) }
+ end
+ end
+
+ context 'without key' do
+ let(:raw_payload) { {} }
+
+ it { is_expected.to be_nil }
+ end
+ end
end
diff --git a/spec/lib/gitlab/api_authentication/token_locator_spec.rb b/spec/lib/gitlab/api_authentication/token_locator_spec.rb
index 68ce48a70ea..e933fd8352e 100644
--- a/spec/lib/gitlab/api_authentication/token_locator_spec.rb
+++ b/spec/lib/gitlab/api_authentication/token_locator_spec.rb
@@ -51,5 +51,26 @@ RSpec.describe Gitlab::APIAuthentication::TokenLocator do
end
end
end
+
+ context 'with :http_token' do
+ let(:type) { :http_token }
+
+ context 'without credentials' do
+ let(:request) { double(headers: {}) }
+
+ it 'returns nil' do
+ expect(subject).to be(nil)
+ end
+ end
+
+ context 'with credentials' do
+ let(:password) { 'bar' }
+ let(:request) { double(headers: { "Authorization" => password }) }
+
+ it 'returns the credentials' do
+ expect(subject.password).to eq(password)
+ end
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/api_authentication/token_resolver_spec.rb b/spec/lib/gitlab/api_authentication/token_resolver_spec.rb
index 0028fb080ac..97a7c8ba7cf 100644
--- a/spec/lib/gitlab/api_authentication/token_resolver_spec.rb
+++ b/spec/lib/gitlab/api_authentication/token_resolver_spec.rb
@@ -47,8 +47,8 @@ RSpec.describe Gitlab::APIAuthentication::TokenResolver do
subject { resolver.resolve(raw) }
- context 'with :personal_access_token' do
- let(:type) { :personal_access_token }
+ context 'with :personal_access_token_with_username' do
+ let(:type) { :personal_access_token_with_username }
let(:token) { personal_access_token }
context 'with valid credentials' do
@@ -62,10 +62,16 @@ RSpec.describe Gitlab::APIAuthentication::TokenResolver do
it_behaves_like 'an unauthorized request'
end
+
+ context 'with no username' do
+ let(:raw) { username_and_password(nil, token.token) }
+
+ it_behaves_like 'an unauthorized request'
+ end
end
- context 'with :job_token' do
- let(:type) { :job_token }
+ context 'with :job_token_with_username' do
+ let(:type) { :job_token_with_username }
let(:token) { ci_job }
context 'with valid credentials' do
@@ -93,8 +99,8 @@ RSpec.describe Gitlab::APIAuthentication::TokenResolver do
end
end
- context 'with :deploy_token' do
- let(:type) { :deploy_token }
+ context 'with :deploy_token_with_username' do
+ let(:type) { :deploy_token_with_username }
let(:token) { deploy_token }
context 'with a valid deploy token' do
@@ -109,6 +115,51 @@ RSpec.describe Gitlab::APIAuthentication::TokenResolver do
it_behaves_like 'an unauthorized request'
end
end
+
+ context 'with :personal_access_token' do
+ let(:type) { :personal_access_token }
+ let(:token) { personal_access_token }
+
+ context 'with valid credentials' do
+ let(:raw) { username_and_password(nil, token.token) }
+
+ it_behaves_like 'an authorized request'
+ end
+ end
+
+ context 'with :job_token' do
+ let(:type) { :job_token }
+ let(:token) { ci_job }
+
+ context 'with valid credentials' do
+ let(:raw) { username_and_password(nil, token.token) }
+
+ it_behaves_like 'an authorized request'
+ end
+
+ context 'when the job is not running' do
+ let(:raw) { username_and_password(nil, ci_job_done.token) }
+
+ it_behaves_like 'an unauthorized request'
+ end
+
+ context 'with an invalid job token' do
+ let(:raw) { username_and_password(nil, "not a valid CI job token") }
+
+ it_behaves_like 'an unauthorized request'
+ end
+ end
+
+ context 'with :deploy_token' do
+ let(:type) { :deploy_token }
+ let(:token) { deploy_token }
+
+ context 'with a valid deploy token' do
+ let(:raw) { username_and_password(nil, token.token) }
+
+ it_behaves_like 'an authorized request'
+ end
+ end
end
def username_and_password(username, password)
diff --git a/spec/lib/gitlab/ci/variables/collection/sorted_spec.rb b/spec/lib/gitlab/ci/variables/collection/sorted_spec.rb
index d85bf29f77f..954273fd41e 100644
--- a/spec/lib/gitlab/ci/variables/collection/sorted_spec.rb
+++ b/spec/lib/gitlab/ci/variables/collection/sorted_spec.rb
@@ -5,8 +5,11 @@ require 'spec_helper'
RSpec.describe Gitlab::Ci::Variables::Collection::Sorted do
describe '#errors' do
context 'when FF :variable_inside_variable is disabled' do
+ let_it_be(:project_with_flag_disabled) { create(:project) }
+ let_it_be(:project_with_flag_enabled) { create(:project) }
+
before do
- stub_feature_flags(variable_inside_variable: false)
+ stub_feature_flags(variable_inside_variable: [project_with_flag_enabled])
end
context 'table tests' do
@@ -53,7 +56,7 @@ RSpec.describe Gitlab::Ci::Variables::Collection::Sorted do
end
with_them do
- subject { Gitlab::Ci::Variables::Collection::Sorted.new(variables) }
+ subject { Gitlab::Ci::Variables::Collection::Sorted.new(variables, project_with_flag_disabled) }
it 'does not report error' do
expect(subject.errors).to eq(nil)
@@ -67,8 +70,11 @@ RSpec.describe Gitlab::Ci::Variables::Collection::Sorted do
end
context 'when FF :variable_inside_variable is enabled' do
+ let_it_be(:project_with_flag_disabled) { create(:project) }
+ let_it_be(:project_with_flag_enabled) { create(:project) }
+
before do
- stub_feature_flags(variable_inside_variable: true)
+ stub_feature_flags(variable_inside_variable: [project_with_flag_enabled])
end
context 'table tests' do
@@ -100,7 +106,7 @@ RSpec.describe Gitlab::Ci::Variables::Collection::Sorted do
end
with_them do
- subject { Gitlab::Ci::Variables::Collection::Sorted.new(variables) }
+ subject { Gitlab::Ci::Variables::Collection::Sorted.new(variables, project_with_flag_enabled) }
it 'errors matches expected validation result' do
expect(subject.errors).to eq(validation_result)
@@ -164,7 +170,8 @@ RSpec.describe Gitlab::Ci::Variables::Collection::Sorted do
end
with_them do
- subject { Gitlab::Ci::Variables::Collection::Sorted.new(variables) }
+ let_it_be(:project) { create(:project) }
+ subject { Gitlab::Ci::Variables::Collection::Sorted.new(variables, project) }
it 'does not expand variables' do
expect(subject.sort).to eq(variables)
@@ -239,7 +246,8 @@ RSpec.describe Gitlab::Ci::Variables::Collection::Sorted do
end
with_them do
- subject { Gitlab::Ci::Variables::Collection::Sorted.new(variables) }
+ let_it_be(:project) { create(:project) }
+ subject { Gitlab::Ci::Variables::Collection::Sorted.new(variables, project) }
it 'sort returns correctly sorted variables' do
expect(subject.sort.map { |var| var[:key] }).to eq(result)
diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb
index 445f4f249ee..78bd0e91208 100644
--- a/spec/models/project_services/jira_service_spec.rb
+++ b/spec/models/project_services/jira_service_spec.rb
@@ -463,7 +463,7 @@ RSpec.describe JiraService do
let(:issue_url) { "#{url}/rest/api/2/issue/#{issue_key}?expand=renderedFields" }
it 'calls the Jira API with the options to get the issue' do
- jira_service.find_issue(issue_key, { expand: 'renderedFields' })
+ jira_service.find_issue(issue_key, rendered_fields: true)
expect(WebMock).to have_requested(:get, issue_url)
end
diff --git a/spec/presenters/ci/build_runner_presenter_spec.rb b/spec/presenters/ci/build_runner_presenter_spec.rb
index 1e6c33484ec..43b677483ce 100644
--- a/spec/presenters/ci/build_runner_presenter_spec.rb
+++ b/spec/presenters/ci/build_runner_presenter_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe Ci::BuildRunnerPresenter do
describe '#artifacts' do
context "when option contains archive-type artifacts" do
- let(:build) { create(:ci_build, options: { artifacts: archive } ) }
+ let(:build) { create(:ci_build, options: { artifacts: archive }) }
it 'presents correct hash' do
expect(presenter.artifacts.first).to include(archive_expectation)
@@ -249,7 +249,7 @@ RSpec.describe Ci::BuildRunnerPresenter do
it 'returns the correct refspecs' do
is_expected.to contain_exactly("+#{pipeline.sha}:refs/pipelines/#{pipeline.id}",
- "+refs/heads/#{build.ref}:refs/remotes/origin/#{build.ref}")
+ "+refs/heads/#{build.ref}:refs/remotes/origin/#{build.ref}")
end
end
end
diff --git a/spec/requests/api/rubygem_packages_spec.rb b/spec/requests/api/rubygem_packages_spec.rb
new file mode 100644
index 00000000000..5dd68bf9b10
--- /dev/null
+++ b/spec/requests/api/rubygem_packages_spec.rb
@@ -0,0 +1,139 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe API::RubygemPackages do
+ using RSpec::Parameterized::TableSyntax
+
+ let_it_be(:project) { create(:project) }
+ let_it_be(:personal_access_token) { create(:personal_access_token) }
+ let_it_be(:user) { personal_access_token.user }
+ let_it_be(:job) { create(:ci_build, :running, user: user) }
+ let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) }
+ let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) }
+ let_it_be(:headers) { {} }
+
+ shared_examples 'when feature flag is disabled' do
+ let(:headers) do
+ { 'HTTP_AUTHORIZATION' => personal_access_token.token }
+ end
+
+ before do
+ stub_feature_flags(rubygem_packages: false)
+ end
+
+ it_behaves_like 'returning response status', :not_found
+ end
+
+ shared_examples 'when package feature is disabled' do
+ before do
+ stub_config(packages: { enabled: false })
+ end
+
+ it_behaves_like 'returning response status', :not_found
+ end
+
+ shared_examples 'without authentication' do
+ it_behaves_like 'returning response status', :unauthorized
+ end
+
+ shared_examples 'with authentication' do
+ let(:headers) do
+ { 'HTTP_AUTHORIZATION' => token }
+ end
+
+ let(:tokens) do
+ {
+ personal_access_token: personal_access_token.token,
+ deploy_token: deploy_token.token,
+ job_token: job.token
+ }
+ end
+
+ where(:user_role, :token_type, :valid_token, :status) do
+ :guest | :personal_access_token | true | :not_found
+ :guest | :personal_access_token | false | :unauthorized
+ :guest | :deploy_token | true | :not_found
+ :guest | :deploy_token | false | :unauthorized
+ :guest | :job_token | true | :not_found
+ :guest | :job_token | false | :unauthorized
+ :reporter | :personal_access_token | true | :not_found
+ :reporter | :personal_access_token | false | :unauthorized
+ :reporter | :deploy_token | true | :not_found
+ :reporter | :deploy_token | false | :unauthorized
+ :reporter | :job_token | true | :not_found
+ :reporter | :job_token | false | :unauthorized
+ :developer | :personal_access_token | true | :not_found
+ :developer | :personal_access_token | false | :unauthorized
+ :developer | :deploy_token | true | :not_found
+ :developer | :deploy_token | false | :unauthorized
+ :developer | :job_token | true | :not_found
+ :developer | :job_token | false | :unauthorized
+ end
+
+ with_them do
+ before do
+ project.send("add_#{user_role}", user) unless user_role == :anonymous
+ end
+
+ let(:token) { valid_token ? tokens[token_type] : 'invalid-token123' }
+
+ it_behaves_like 'returning response status', params[:status]
+ end
+ end
+
+ shared_examples 'an unimplemented route' do
+ it_behaves_like 'without authentication'
+ it_behaves_like 'with authentication'
+ it_behaves_like 'when feature flag is disabled'
+ it_behaves_like 'when package feature is disabled'
+ end
+
+ describe 'GET /api/v4/projects/:project_id/packages/rubygems/:filename' do
+ let(:url) { api("/projects/#{project.id}/packages/rubygems/specs.4.8.gz") }
+
+ subject { get(url, headers: headers) }
+
+ it_behaves_like 'an unimplemented route'
+ end
+
+ describe 'GET /api/v4/projects/:project_id/packages/rubygems/quick/Marshal.4.8/:file_name' do
+ let(:url) { api("/projects/#{project.id}/packages/rubygems/quick/Marshal.4.8/my_gem-1.0.0.gemspec.rz") }
+
+ subject { get(url, headers: headers) }
+
+ it_behaves_like 'an unimplemented route'
+ end
+
+ describe 'GET /api/v4/projects/:project_id/packages/rubygems/gems/:file_name' do
+ let(:url) { api("/projects/#{project.id}/packages/rubygems/gems/my_gem-1.0.0.gem") }
+
+ subject { get(url, headers: headers) }
+
+ it_behaves_like 'an unimplemented route'
+ end
+
+ describe 'POST /api/v4/projects/:project_id/packages/rubygems/api/v1/gems/authorize' do
+ let(:url) { api("/projects/#{project.id}/packages/rubygems/api/v1/gems/authorize") }
+
+ subject { post(url, headers: headers) }
+
+ it_behaves_like 'an unimplemented route'
+ end
+
+ describe 'POST /api/v4/projects/:project_id/packages/rubygems/api/v1/gems' do
+ let(:url) { api("/projects/#{project.id}/packages/rubygems/api/v1/gems") }
+
+ subject { post(url, headers: headers) }
+
+ it_behaves_like 'an unimplemented route'
+ end
+
+ describe 'GET /api/v4/projects/:project_id/packages/rubygems/api/v1/dependencies' do
+ let(:url) { api("/projects/#{project.id}/packages/rubygems/api/v1/dependencies") }
+
+ subject { get(url, headers: headers) }
+
+ it_behaves_like 'an unimplemented route'
+ end
+end
diff --git a/vendor/gitignore/C++.gitignore b/vendor/gitignore/C++.gitignore
index 259148fa18f..259148fa18f 100755..100644
--- a/vendor/gitignore/C++.gitignore
+++ b/vendor/gitignore/C++.gitignore
diff --git a/vendor/gitignore/Java.gitignore b/vendor/gitignore/Java.gitignore
index a1c2a238a96..a1c2a238a96 100755..100644
--- a/vendor/gitignore/Java.gitignore
+++ b/vendor/gitignore/Java.gitignore