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--.rubocop_manual_todo.yml2
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--app/assets/javascripts/vue_shared/components/dropdown/dropdown_button.vue11
-rw-r--r--app/controllers/application_controller.rb6
-rw-r--r--app/controllers/registrations_controller.rb4
-rw-r--r--app/helpers/recaptcha_experiment_helper.rb9
-rw-r--r--app/helpers/recaptcha_helper.rb7
-rw-r--r--app/services/issues/reopen_service.rb8
-rw-r--r--app/services/jira_connect_subscriptions/create_service.rb4
-rw-r--r--app/views/admin/application_settings/_eks.html.haml2
-rw-r--r--app/views/admin/application_settings/_gitpod.html.haml2
-rw-r--r--app/views/admin/application_settings/_plantuml.html.haml2
-rw-r--r--app/views/admin/application_settings/_snowplow.html.haml2
-rw-r--r--app/views/admin/application_settings/_third_party_offers.html.haml2
-rw-r--r--app/views/admin/application_settings/general.html.haml18
-rw-r--r--app/views/jira_connect/subscriptions/index.html.haml4
-rw-r--r--changelogs/unreleased/273813-rename-cycle-analytics-with-value-stream-analytics-in-strings-unde.yml5
-rw-r--r--changelogs/unreleased/280795-stop-finding-commit-empty-ref.yml5
-rw-r--r--changelogs/unreleased/47531-fix-secure-bin-tmpl.yml5
-rw-r--r--changelogs/unreleased/mw-replace-fa-chevron-down-dropdown-button.yml5
-rw-r--r--config/feature_flags/development/pat_creation_api_for_admin.yml7
-rw-r--r--doc/administration/audit_events.md2
-rw-r--r--doc/api/personal_access_tokens.md4
-rw-r--r--doc/api/users.md68
-rw-r--r--doc/ci/unit_test_reports.md21
-rw-r--r--doc/development/api_graphql_styleguide.md2
-rw-r--r--doc/development/graphql_guide/batchloader.md121
-rw-r--r--doc/development/testing_guide/frontend_testing.md31
-rw-r--r--lib/api/users.rb38
-rw-r--r--lib/bulk_imports/pipeline/runner.rb61
-rw-r--r--lib/csv_builders/stream.rb17
-rw-r--r--lib/extracts_ref.rb2
-rw-r--r--lib/gitlab/ci/templates/Security/Secure-Binaries.gitlab-ci.yml4
-rw-r--r--locale/gitlab.pot6
-rwxr-xr-xscripts/verify-tff-mapping6
-rw-r--r--spec/controllers/projects/cycle_analytics/events_controller_spec.rb2
-rw-r--r--spec/controllers/projects/cycle_analytics_controller_spec.rb2
-rw-r--r--spec/factories/packages.rb18
-rw-r--r--spec/factories/packages/package_file.rb2
-rw-r--r--spec/frontend/ide/components/ide_spec.js28
-rw-r--r--spec/frontend/vue_shared/components/dropdown/dropdown_button_spec.js3
-rw-r--r--spec/helpers/recaptcha_helper_spec.rb (renamed from spec/helpers/recaptcha_experiment_helper_spec.rb)2
-rw-r--r--spec/lib/bulk_imports/pipeline/runner_spec.rb16
-rw-r--r--spec/lib/csv_builders/stream_spec.rb42
-rw-r--r--spec/lib/extracts_path_spec.rb13
-rw-r--r--spec/lib/extracts_ref_spec.rb17
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/stage_events/code_stage_start_spec.rb2
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_created_spec.rb2
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_first_mentioned_in_commit_spec.rb2
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_stage_end_spec.rb2
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_created_spec.rb2
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_first_deployed_to_production_spec.rb2
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_finished_spec.rb2
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_started_spec.rb2
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_merged_spec.rb2
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/stage_events/plan_stage_start_spec.rb2
-rw-r--r--spec/lib/gitlab/cycle_analytics/events_spec.rb2
-rw-r--r--spec/models/analytics/cycle_analytics/project_stage_spec.rb2
-rw-r--r--spec/requests/api/users_spec.rb222
-rw-r--r--spec/support/cycle_analytics_helpers/test_generation.rb6
-rw-r--r--spec/support/shared_examples/lib/gitlab/cycle_analytics/event_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/cycle_analytics_stage_shared_examples.rb4
-rw-r--r--spec/tooling/lib/tooling/test_file_finder_spec.rb8
63 files changed, 726 insertions, 180 deletions
diff --git a/.rubocop_manual_todo.yml b/.rubocop_manual_todo.yml
index 56a7b19eb3b..b99a665913c 100644
--- a/.rubocop_manual_todo.yml
+++ b/.rubocop_manual_todo.yml
@@ -16,8 +16,6 @@ FactoryBot/InlineAssociation:
- 'spec/factories/import_export_uploads.rb'
- 'spec/factories/merge_requests.rb'
- 'spec/factories/notes.rb'
- - 'spec/factories/packages.rb'
- - 'spec/factories/packages/package_file.rb'
- 'spec/factories/sent_notifications.rb'
- 'spec/factories/uploads.rb'
- 'spec/factories/wiki_pages.rb'
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index 9524711e948..c0359917f4f 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-194a9f58926793ade53152de90b474d66804e21e
+506c44cc07dcb804ce970ec1c02bb6e0d52320d8
diff --git a/app/assets/javascripts/vue_shared/components/dropdown/dropdown_button.vue b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_button.vue
index 494df2d7a37..7e82d8f3f9c 100644
--- a/app/assets/javascripts/vue_shared/components/dropdown/dropdown_button.vue
+++ b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_button.vue
@@ -1,10 +1,11 @@
<script>
-import { GlLoadingIcon } from '@gitlab/ui';
+import { GlLoadingIcon, GlIcon } from '@gitlab/ui';
import { __ } from '~/locale';
export default {
components: {
GlLoadingIcon,
+ GlIcon,
},
props: {
isDisabled: {
@@ -39,8 +40,10 @@ export default {
<slot v-if="$slots.default"></slot>
<span v-else class="dropdown-toggle-text"> {{ toggleText }} </span>
</template>
- <span v-show="!isLoading" class="dropdown-toggle-icon">
- <i class="fa fa-chevron-down" aria-hidden="true" data-hidden="true"></i>
- </span>
+ <gl-icon
+ v-show="!isLoading"
+ class="gl-absolute gl-top-3 gl-right-3 gl-text-gray-500"
+ name="chevron-down"
+ />
</button>
</template>
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index f7f5ef3fbad..c38c6abddc1 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -266,6 +266,12 @@ class ApplicationController < ActionController::Base
end
end
+ def stream_headers
+ headers['Content-Length'] = nil
+ headers['X-Accel-Buffering'] = 'no' # Disable buffering on Nginx
+ headers['Last-Modified'] = '0' # Prevent buffering via Rack::ETag middleware
+ end
+
def default_headers
headers['X-Frame-Options'] = 'DENY'
headers['X-XSS-Protection'] = '1; mode=block'
diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb
index a793a8ddbdb..04cb9616cf6 100644
--- a/app/controllers/registrations_controller.rb
+++ b/app/controllers/registrations_controller.rb
@@ -3,7 +3,7 @@
class RegistrationsController < Devise::RegistrationsController
include Recaptcha::Verify
include AcceptsPendingInvitations
- include RecaptchaExperimentHelper
+ include RecaptchaHelper
include InvisibleCaptchaOnSignup
BLOCKED_PENDING_APPROVAL_STATE = 'blocked_pending_approval'.freeze
@@ -176,5 +176,3 @@ class RegistrationsController < Devise::RegistrationsController
@invite_email = ActionController::Base.helpers.sanitize(params[:invite_email])
end
end
-
-RegistrationsController.prepend_if_ee('EE::RegistrationsController')
diff --git a/app/helpers/recaptcha_experiment_helper.rb b/app/helpers/recaptcha_experiment_helper.rb
deleted file mode 100644
index f15e92c0e99..00000000000
--- a/app/helpers/recaptcha_experiment_helper.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-# frozen_string_literal: true
-
-module RecaptchaExperimentHelper
- def show_recaptcha_sign_up?
- !!Gitlab::Recaptcha.enabled?
- end
-end
-
-RecaptchaExperimentHelper.prepend_if_ee('EE::RecaptchaExperimentHelper')
diff --git a/app/helpers/recaptcha_helper.rb b/app/helpers/recaptcha_helper.rb
new file mode 100644
index 00000000000..4ebac1d5b7f
--- /dev/null
+++ b/app/helpers/recaptcha_helper.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+module RecaptchaHelper
+ def show_recaptcha_sign_up?
+ !!Gitlab::Recaptcha.enabled?
+ end
+end
diff --git a/app/services/issues/reopen_service.rb b/app/services/issues/reopen_service.rb
index 12dbff57ec5..e2b1b5400c7 100644
--- a/app/services/issues/reopen_service.rb
+++ b/app/services/issues/reopen_service.rb
@@ -5,8 +5,6 @@ module Issues
def execute(issue)
return issue unless can?(current_user, :reopen_issue, issue)
- before_reopen(issue)
-
if issue.reopen
event_service.reopen_issue(issue, current_user)
create_note(issue, 'reopened')
@@ -23,14 +21,8 @@ module Issues
private
- def before_reopen(issue)
- # Overriden in EE
- end
-
def create_note(issue, state = issue.state)
SystemNoteService.change_status(issue, issue.project, current_user, state, nil)
end
end
end
-
-Issues::ReopenService.prepend_if_ee('EE::Issues::ReopenService')
diff --git a/app/services/jira_connect_subscriptions/create_service.rb b/app/services/jira_connect_subscriptions/create_service.rb
index 781eaaf0efb..b169d97615d 100644
--- a/app/services/jira_connect_subscriptions/create_service.rb
+++ b/app/services/jira_connect_subscriptions/create_service.rb
@@ -4,7 +4,7 @@ module JiraConnectSubscriptions
class CreateService < ::JiraConnectSubscriptions::BaseService
include Gitlab::Utils::StrongMemoize
MERGE_REQUEST_SYNC_BATCH_SIZE = 20
- MERGE_REQUEST_SYNC_BATCH_delay = 1.minute.freeze
+ MERGE_REQUEST_SYNC_BATCH_DELAY = 1.minute.freeze
def execute
unless namespace && can?(current_user, :create_jira_connect_subscription, namespace)
@@ -39,7 +39,7 @@ module JiraConnectSubscriptions
namespace.all_projects.each_batch(of: MERGE_REQUEST_SYNC_BATCH_SIZE) do |projects, index|
JiraConnect::SyncProjectWorker.bulk_perform_in_with_contexts(
- index * MERGE_REQUEST_SYNC_BATCH_delay,
+ index * MERGE_REQUEST_SYNC_BATCH_DELAY,
projects,
arguments_proc: -> (project) { [project.id, Atlassian::JiraConnect::Client.generate_update_sequence_id] },
context_proc: -> (project) { { project: project } }
diff --git a/app/views/admin/application_settings/_eks.html.haml b/app/views/admin/application_settings/_eks.html.haml
index 68324425ef9..5c0e544eaad 100644
--- a/app/views/admin/application_settings/_eks.html.haml
+++ b/app/views/admin/application_settings/_eks.html.haml
@@ -3,7 +3,7 @@
.settings-header
%h4
= _('Amazon EKS')
- %button.btn.js-settings-toggle{ type: 'button' }
+ %button.btn.gl-button.js-settings-toggle{ type: 'button' }
= expanded ? 'Collapse' : 'Expand'
%p
= _('Amazon EKS integration allows you to provision EKS clusters from GitLab.')
diff --git a/app/views/admin/application_settings/_gitpod.html.haml b/app/views/admin/application_settings/_gitpod.html.haml
index 3a6451f4283..1baec07fa25 100644
--- a/app/views/admin/application_settings/_gitpod.html.haml
+++ b/app/views/admin/application_settings/_gitpod.html.haml
@@ -5,7 +5,7 @@
.settings-header
%h4
= _('Gitpod')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ %button.btn.gl-button.btn-default.js-settings-toggle{ type: 'button' }
= expanded ? _('Collapse') : _('Expand')
%p
%integration-help-text{ "id" => "js-gitpod-settings-help-text", "message" => gitpod_enable_description, "message-url" => "https://gitpod.io/" }
diff --git a/app/views/admin/application_settings/_plantuml.html.haml b/app/views/admin/application_settings/_plantuml.html.haml
index 324f544a108..30acb773424 100644
--- a/app/views/admin/application_settings/_plantuml.html.haml
+++ b/app/views/admin/application_settings/_plantuml.html.haml
@@ -3,7 +3,7 @@
.settings-header
%h4
= _('PlantUML')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ %button.btn.gl-button.btn-default.js-settings-toggle{ type: 'button' }
= expanded ? _('Collapse') : _('Expand')
%p
= _('Allow rendering of PlantUML diagrams in Asciidoc documents.')
diff --git a/app/views/admin/application_settings/_snowplow.html.haml b/app/views/admin/application_settings/_snowplow.html.haml
index 7c2c5e0b3dc..c1edaf9ff29 100644
--- a/app/views/admin/application_settings/_snowplow.html.haml
+++ b/app/views/admin/application_settings/_snowplow.html.haml
@@ -3,7 +3,7 @@
.settings-header
%h4
= _('Snowplow')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ %button.btn.gl-button.btn-default.js-settings-toggle{ type: 'button' }
= expanded ? _('Collapse') : _('Expand')
%p
= _('Configure the %{link} integration.').html_safe % { link: link_to('Snowplow', 'https://snowplowanalytics.com/', target: '_blank') }
diff --git a/app/views/admin/application_settings/_third_party_offers.html.haml b/app/views/admin/application_settings/_third_party_offers.html.haml
index 7e3e063118e..32023b11993 100644
--- a/app/views/admin/application_settings/_third_party_offers.html.haml
+++ b/app/views/admin/application_settings/_third_party_offers.html.haml
@@ -3,7 +3,7 @@
.settings-header
%h4
= _('Third party offers')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ %button.btn.gl-button.btn-default.js-settings-toggle{ type: 'button' }
= expanded ? _('Collapse') : _('Expand')
%p
= _('Control the display of third party offers.')
diff --git a/app/views/admin/application_settings/general.html.haml b/app/views/admin/application_settings/general.html.haml
index 2d336bebc8d..5c3f68843a2 100644
--- a/app/views/admin/application_settings/general.html.haml
+++ b/app/views/admin/application_settings/general.html.haml
@@ -6,7 +6,7 @@
.settings-header
%h4
= _('Visibility and access controls')
- %button.btn.js-settings-toggle{ type: 'button' }
+ %button.btn.gl-button.js-settings-toggle{ type: 'button' }
= expanded_by_default? ? _('Collapse') : _('Expand')
%p
= _('Set default and restrict visibility levels. Configure import sources and git access protocol.')
@@ -17,7 +17,7 @@
.settings-header
%h4
= _('Account and limit')
- %button.btn.js-settings-toggle{ type: 'button' }
+ %button.btn.gl-button.js-settings-toggle{ type: 'button' }
= expanded_by_default? ? _('Collapse') : _('Expand')
%p
= _('Set projects and maximum size limits, session duration, user options, and check feature availability for namespace plan.')
@@ -28,7 +28,7 @@
.settings-header
%h4
= _('Diff limits')
- %button.btn.js-settings-toggle{ type: 'button' }
+ %button.btn.gl-button.js-settings-toggle{ type: 'button' }
= expanded_by_default? ? _('Collapse') : _('Expand')
%p
= _('Diff content limits')
@@ -39,7 +39,7 @@
.settings-header
%h4
= _('Sign-up restrictions')
- %button.btn.js-settings-toggle{ type: 'button' }
+ %button.btn.gl-button.js-settings-toggle{ type: 'button' }
= expanded_by_default? ? _('Collapse') : _('Expand')
%p
= _('Configure the way a user creates a new account.')
@@ -50,7 +50,7 @@
.settings-header
%h4
= _('Sign-in restrictions')
- %button.btn.js-settings-toggle{ type: 'button' }
+ %button.btn.gl-button.js-settings-toggle{ type: 'button' }
= expanded_by_default? ? _('Collapse') : _('Expand')
%p
= _('Set requirements for a user to sign-in. Enable mandatory two-factor authentication.')
@@ -61,7 +61,7 @@
.settings-header
%h4
= _('Terms of Service and Privacy Policy')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ %button.btn.gl-button.btn-default.js-settings-toggle{ type: 'button' }
= expanded_by_default? ? _('Collapse') : _('Expand')
%p
= _('Include a Terms of Service agreement and Privacy Policy that all users must accept.')
@@ -74,7 +74,7 @@
.settings-header
%h4
= _('Web terminal')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ %button.btn.gl-button.btn-default.js-settings-toggle{ type: 'button' }
= expanded_by_default? ? _('Collapse') : _('Expand')
%p
= _('Set max session time for web terminal.')
@@ -85,7 +85,7 @@
.settings-header
%h4
= _('Web IDE')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ %button.btn.gl-button.btn-default.js-settings-toggle{ type: 'button' }
= expanded_by_default? ? _('Collapse') : _('Expand')
%p
= _('Manage Web IDE features')
@@ -108,7 +108,7 @@
.settings-header
%h4
= _('Maintenance mode')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ %button.btn.gl-button.btn-default.js-settings-toggle{ type: 'button' }
= expanded_by_default? ? _('Collapse') : _('Expand')
%p
= _('Prevent users from performing write operations on GitLab while performing maintenance.')
diff --git a/app/views/jira_connect/subscriptions/index.html.haml b/app/views/jira_connect/subscriptions/index.html.haml
index 5156472d203..355ffabd7ec 100644
--- a/app/views/jira_connect/subscriptions/index.html.haml
+++ b/app/views/jira_connect/subscriptions/index.html.haml
@@ -52,11 +52,11 @@
%p.browser-limitations-notice
%strong Browser limitations:
- Adding a namespace currently works only in browsers that allow cross site cookies. Please make sure to use
+ Adding a namespace currently works only in browsers that allow cross‑site cookies. Please make sure to use
%a{ href: 'https://www.mozilla.org/en-US/firefox/', target: '_blank', rel: 'noopener noreferrer' } Firefox
or
%a{ href: 'https://www.google.com/chrome/index.html', target: '_blank', rel: 'noopener noreferrer' } Google Chrome
- or enable cross-site cookies in your browser when adding a namespace.
+ or enable cross‑site cookies in your browser when adding a namespace.
%a{ href: 'https://gitlab.com/gitlab-org/gitlab/-/issues/263509', target: '_blank', rel: 'noopener noreferrer' } Learn more
= webpack_bundle_tag 'performance_bar' if performance_bar_enabled?
diff --git a/changelogs/unreleased/273813-rename-cycle-analytics-with-value-stream-analytics-in-strings-unde.yml b/changelogs/unreleased/273813-rename-cycle-analytics-with-value-stream-analytics-in-strings-unde.yml
new file mode 100644
index 00000000000..b35d7b7618b
--- /dev/null
+++ b/changelogs/unreleased/273813-rename-cycle-analytics-with-value-stream-analytics-in-strings-unde.yml
@@ -0,0 +1,5 @@
+---
+title: Rename "cycle analytics" with "value stream analytics" under /spec
+merge_request: 46613
+author: Takuya Noguchi
+type: other
diff --git a/changelogs/unreleased/280795-stop-finding-commit-empty-ref.yml b/changelogs/unreleased/280795-stop-finding-commit-empty-ref.yml
new file mode 100644
index 00000000000..a4f7e20daa8
--- /dev/null
+++ b/changelogs/unreleased/280795-stop-finding-commit-empty-ref.yml
@@ -0,0 +1,5 @@
+---
+title: Stop finding commit with empty ref
+merge_request: 47497
+author:
+type: fixed
diff --git a/changelogs/unreleased/47531-fix-secure-bin-tmpl.yml b/changelogs/unreleased/47531-fix-secure-bin-tmpl.yml
new file mode 100644
index 00000000000..86558a81028
--- /dev/null
+++ b/changelogs/unreleased/47531-fix-secure-bin-tmpl.yml
@@ -0,0 +1,5 @@
+---
+title: Bump versions of secrets and klar in the Secure-Binaries template
+merge_request: 47531
+author:
+type: fixed
diff --git a/changelogs/unreleased/mw-replace-fa-chevron-down-dropdown-button.yml b/changelogs/unreleased/mw-replace-fa-chevron-down-dropdown-button.yml
new file mode 100644
index 00000000000..f46d24e66d9
--- /dev/null
+++ b/changelogs/unreleased/mw-replace-fa-chevron-down-dropdown-button.yml
@@ -0,0 +1,5 @@
+---
+title: Replace fa-chevron-down in dropdown button
+merge_request: 47758
+author:
+type: changed
diff --git a/config/feature_flags/development/pat_creation_api_for_admin.yml b/config/feature_flags/development/pat_creation_api_for_admin.yml
new file mode 100644
index 00000000000..246f7623cc9
--- /dev/null
+++ b/config/feature_flags/development/pat_creation_api_for_admin.yml
@@ -0,0 +1,7 @@
+---
+name: pat_creation_api_for_admin
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/45152
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/267553
+type: development
+group: group::access
+default_enabled: false
diff --git a/doc/administration/audit_events.md b/doc/administration/audit_events.md
index 676f402f7cf..67a3a3c1539 100644
--- a/doc/administration/audit_events.md
+++ b/doc/administration/audit_events.md
@@ -239,7 +239,7 @@ The first row contains the headers, which are listed in the following table alon
### Limitation
-The Audit Log CSV file size is limited to a maximum of `15 MB`.
+The Audit Log CSV file size is limited to a maximum of `100,000` events.
The remaining records are truncated when this limit is reached.
### Enable or disable Audit Log Export to CSV
diff --git a/doc/api/personal_access_tokens.md b/doc/api/personal_access_tokens.md
index 5bd804b8042..8a838a0f179 100644
--- a/doc/api/personal_access_tokens.md
+++ b/doc/api/personal_access_tokens.md
@@ -93,3 +93,7 @@ curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://git
- `204: No Content` if successfully revoked.
- `400 Bad Request` if not revoked successfully.
+
+## Create a personal access token (admin only)
+
+See the [Users API documentation](users.md#create-a-personal-access-token-admin-only) for information on creating a personal access token.
diff --git a/doc/api/users.md b/doc/api/users.md
index 31e8bb67bd3..e1fa97765df 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -1441,7 +1441,54 @@ Parameters:
| `user_id` | integer | yes | The ID of the user |
| `impersonation_token_id` | integer | yes | The ID of the impersonation token |
-### Get user activities (admin only)
+## Create a personal access token (admin only)
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/17176) in GitLab 13.6.
+> - It's [deployed behind a feature flag](../user/feature_flags.md), disabled by default.
+> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-an-administrators-ability-to-use-the-api-to-create-personal-access-tokens). **(CORE)**
+
+CAUTION: **Warning:**
+This feature might not be available to you. Check the **version history** note above for details.
+
+> Requires admin permissions.
+> Token values are returned once. Make sure you save it - you won't be able to access it again.
+
+It creates a new personal access token.
+
+```plaintext
+POST /users/:user_id/personal_access_tokens
+```
+
+| Attribute | Type | Required | Description |
+| ------------ | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------ |
+| `user_id` | integer | yes | The ID of the user |
+| `name` | string | yes | The name of the personal access token |
+| `expires_at` | date | no | The expiration date of the personal access token in ISO format (`YYYY-MM-DD`) |
+| `scopes` | array | yes | The array of scopes of the personal access token (`api`, `read_user`, `read_api`, `read_repository`, `write_repository`) |
+
+```shell
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --data "name=mytoken" --data "expires_at=2017-04-04" --data "scopes[]=api" "https://gitlab.example.com/api/v4/users/42/personal_access_tokens"
+```
+
+Example response:
+
+```json
+{
+ "id": 3,
+ "name": "mytoken",
+ "revoked": false,
+ "created_at": "2020-10-14T11:58:53.526Z",
+ "scopes": [
+ "api"
+ ],
+ "user_id": 42,
+ "active": true,
+ "expires_at": "2020-12-31",
+ "token": "ggbfKkC4n-Lujy8jwCR2"
+}
+```
+
+## Get user activities (admin only)
NOTE: **Note:**
This API endpoint is only available on 8.15 (EE) and 9.1 (CE) and above.
@@ -1546,3 +1593,22 @@ Example response:
},
]
```
+
+## Enable or disable an administrator's ability to use the API to create personal access tokens **(CORE)**
+
+An administrator's ability to create personal access tokens through the API is
+deployed behind a feature flag that is **disabled by default**.
+[GitLab administrators with access to the GitLab Rails console](../administration/feature_flags.md)
+can enable it.
+
+To enable it:
+
+```ruby
+Feature.enable(:pat_creation_api_for_admin)
+```
+
+To disable it:
+
+```ruby
+Feature.disable(:pat_creation_api_for_admin)
+```
diff --git a/doc/ci/unit_test_reports.md b/doc/ci/unit_test_reports.md
index b9c1809bf0d..a6f2499d0fc 100644
--- a/doc/ci/unit_test_reports.md
+++ b/doc/ci/unit_test_reports.md
@@ -244,6 +244,27 @@ Test:
- ./**/*test-result.xml
```
+### JavaScript example
+
+There are a few tools that can produce JUnit report format XML files in JavaScript.
+
+#### Jest
+
+The [jest-junit](https://github.com/jest-community/jest-junit) npm package can generate test reports for JavaScript applications.
+In the following `.gitlab-ci.yml` example, the `javascript` job uses Jest to generate the test reports:
+
+```yaml
+javascript:
+ stage: test
+ script:
+ - 'jest --ci --reporters=default --reporters=jest-junit'
+ artifacts:
+ when: always
+ reports:
+ junit:
+ - junit.xml
+```
+
## Viewing Unit test reports on GitLab
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/24792) in GitLab 12.5 behind a feature flag (`junit_pipeline_view`), disabled by default.
diff --git a/doc/development/api_graphql_styleguide.md b/doc/development/api_graphql_styleguide.md
index 6760a2efb7f..231b3bcfd88 100644
--- a/doc/development/api_graphql_styleguide.md
+++ b/doc/development/api_graphql_styleguide.md
@@ -756,7 +756,7 @@ To find objects to display in a field, we can add resolvers to
Arguments can be defined within the resolver in the same way as in a mutation.
See the [Mutation arguments](#object-identifier-arguments) section.
-To limit the amount of queries performed, we can use `BatchLoader`.
+To limit the amount of queries performed, we can use [BatchLoader](graphql_guide/batchloader.md).
### Writing resolvers
diff --git a/doc/development/graphql_guide/batchloader.md b/doc/development/graphql_guide/batchloader.md
new file mode 100644
index 00000000000..c9a22e04857
--- /dev/null
+++ b/doc/development/graphql_guide/batchloader.md
@@ -0,0 +1,121 @@
+---
+stage: none
+group: unassigned
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
+---
+
+# GraphQL BatchLoader
+
+GitLab uses the [batch-loader](https://github.com/exAspArk/batch-loader) Ruby gem to optimize and avoid N+1 SQL queries.
+
+It is the properties of the GraphQL query tree that create opportunities for batching like this - disconnected nodes might need the same data, but cannot know about themselves.
+
+## When should you use it?
+
+We should try to batch DB requests as much as possible during GraphQL **query** execution. There is no need to batch loading during **mutations** because they are executed serially. If you need to make a database query, and it is possible to combine two similar (but not identical) queries, then consider using the batch-loader.
+
+When implementing a new endpoint we should aim to minimise the number of SQL queries. For stability and scalability we must also ensure that our queries do not suffer from N+1 performance issues.
+
+## Implementation
+
+Batch loading is useful when a series of queries for inputs `Qα, Qβ, ... Qω` can be combined to a single query for `Q[α, β, ... ω]`. An example of this is lookups by ID, where we can find two users by usernames as cheaply as one, but real-world examples can be more complex.
+
+Batchloading is not suitable when the result sets have different sort-orders, grouping, aggregation or other non-composable features.
+
+There are two ways to use the batch-loader in your code. For simple ID lookups, use `::Gitlab::Graphql::Loaders::BatchModelLoader.new(model, id).find`. For more complex cases, you can use the batch API directly.
+
+For example, to load a `User` by `username`, we can add batching as follows:
+
+```ruby
+class UserResolver < BaseResolver
+ type UserType, null: true
+ argument :username, ::GraphQL::STRING_TYPE, required: true
+
+ def resolve(**args)
+ BatchLoader::GraphQL.for(username).batch do |usernames, loader|
+ User.by_username(usernames).each do |user|
+ loader.call(user.username, user)
+ end
+ end
+ end
+end
+```
+
+- `project_id` is the `ID` of the current project being queried
+- `loader.call` is used to map the result back to the input key (here a project ID)
+- `BatchLoader::GraphQL` returns a lazy object (suspended promise to fetch the data)
+
+Here an [example MR](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46549) illustrating how to use our `BatchLoading` mechanism.
+
+## How does it work exactly?
+
+Each lazy object knows which data it needs to load and how to batch the query. When we need to use the lazy objects (which we announce by calling `#sync`), they will be loaded along with all other similar objects in the current batch.
+
+Inside the block we execute a batch query for our items (`User`). After that, all we have to do is to call loader by passing an item which was used in `BatchLoader::GraphQL.for` method (`usernames`) and the loaded object itself (`user`):
+
+```ruby
+BatchLoader::GraphQL.for(username).batch do |usernames, loader|
+ User.by_username(usernames).each do |user|
+ loader.call(user.username, user)
+ end
+end
+```
+
+### What does lazy mean?
+
+It is important to avoid syncing batches too early. In the example below we can see how calling sync too early can eliminate opportunities for batching:
+
+```ruby
+x = find_lazy(1)
+y = find_lazy(2)
+
+# calling .sync will flush the current batch and will inhibit maximum laziness
+x.sync
+
+z = find_lazy(3)
+
+y.sync
+z.sync
+
+# => will run 2 queries
+```
+
+```ruby
+x = find_lazy(1)
+y = find_lazy(2)
+z = find_lazy(3)
+
+x.sync
+y.sync
+z.sync
+
+# => will run 1 query
+```
+
+## Testing
+
+Any GraphQL field that supports `BatchLoading` should be tested using the `batch_sync` method available in [GraphQLHelpers](https://gitlab.com/gitlab-org/gitlab/-/blob/master/spec/support/helpers/graphql_helpers.rb).
+
+```ruby
+it 'returns data as a batch' do
+ results = batch_sync(max_queries: 1) do
+ [{ id: 1 }, { id: 2 }].map { |args| resolve(args) }
+ end
+
+ expect(results).to eq(expected_results)
+end
+
+def resolve(args = {}, context = { current_user: current_user })
+ resolve(described_class, obj: obj, args: args, ctx: context)
+end
+```
+
+We can also use [QueryRecorder](../query_recorder.md) to make sure we are performing only **one SQL query** per call.
+
+```ruby
+it 'executes only 1 SQL query' do
+ query_count = ActiveRecord::QueryRecorder.new { subject }.count
+
+ expect(query_count).to eq(1)
+end
+```
diff --git a/doc/development/testing_guide/frontend_testing.md b/doc/development/testing_guide/frontend_testing.md
index fee59c60f79..28fe63f1fb4 100644
--- a/doc/development/testing_guide/frontend_testing.md
+++ b/doc/development/testing_guide/frontend_testing.md
@@ -115,6 +115,37 @@ describe('Component', () => {
Remember that the performance of each test depends on the environment.
+### Timout error due to async components
+
+If your component is fetching some other components asynchroneously based on some conditions, it might happen so that your Jest suite for this component will become flaky timing out from time to time.
+
+```javascript
+// ide.vue
+export default {
+ components: {
+ 'error-message': () => import('./error_message.vue'),
+ 'gl-button': () => import('@gitlab/ui/src/components/base/button/button.vue'),
+ ...
+};
+```
+
+To address this issue, you can "help" Jest by stubbing the async components so that Jest would not need to fetch those asynchroneously at the run-time.
+
+```javascript
+// ide_spec.js
+import { GlButton } from '@gitlab/ui';
+import ErrorMessage from '~/ide/components/error_message.vue';
+...
+return shallowMount(ide, {
+ ...
+ stubs: {
+ ErrorMessage,
+ GlButton,
+ ...
+ },
+})
+```
+
## What and how to test
Before jumping into more gritty details about Jest-specific workflows like mocks and spies, we should briefly cover what to test with Jest.
diff --git a/lib/api/users.rb b/lib/api/users.rb
index 54228373512..501ed629c7e 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -65,9 +65,9 @@ module API
params :sort_params do
optional :order_by, type: String, values: %w[id name username created_at updated_at],
- default: 'id', desc: 'Return users ordered by a field'
+ default: 'id', desc: 'Return users ordered by a field'
optional :sort, type: String, values: %w[asc desc], default: 'desc',
- desc: 'Return users sorted in ascending and descending order'
+ desc: 'Return users sorted in ascending and descending order'
end
end
@@ -706,6 +706,40 @@ module API
end
end
end
+
+ resource :personal_access_tokens do
+ helpers do
+ def target_user
+ find_user_by_id(params)
+ end
+ end
+
+ before { authenticated_as_admin! }
+
+ desc 'Create a personal access token. Available only for admins.' do
+ detail 'This feature was introduced in GitLab 13.6'
+ success Entities::PersonalAccessTokenWithToken
+ end
+ params do
+ requires :name, type: String, desc: 'The name of the personal access token'
+ requires :scopes, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, values: ::Gitlab::Auth.all_available_scopes.map(&:to_s),
+ desc: 'The array of scopes of the personal access token'
+ optional :expires_at, type: Date, desc: 'The expiration date in the format YEAR-MONTH-DAY of the personal access token'
+ end
+ post feature_category: :authentication_and_authorization do
+ not_found! unless Feature.enabled?(:pat_creation_api_for_admin)
+
+ response = ::PersonalAccessTokens::CreateService.new(
+ current_user: current_user, target_user: target_user, params: declared_params(include_missing: false)
+ ).execute
+
+ if response.success?
+ present response.payload[:personal_access_token], with: Entities::PersonalAccessTokenWithToken
+ else
+ render_api_error!(response.message, response.http_status || :unprocessable_entity)
+ end
+ end
+ end
end
end
diff --git a/lib/bulk_imports/pipeline/runner.rb b/lib/bulk_imports/pipeline/runner.rb
index cf94b500612..04038e50399 100644
--- a/lib/bulk_imports/pipeline/runner.rb
+++ b/lib/bulk_imports/pipeline/runner.rb
@@ -6,34 +6,61 @@ module BulkImports
extend ActiveSupport::Concern
included do
- attr_reader :extractors, :transformers, :loaders
+ private
- def initialize
- @extractors = self.class.extractors.map(&method(:instantiate))
- @transformers = self.class.transformers.map(&method(:instantiate))
- @loaders = self.class.loaders.map(&method(:instantiate))
+ def extractors
+ @extractors ||= self.class.extractors.map(&method(:instantiate))
+ end
- super
+ def transformers
+ @transformers ||= self.class.transformers.map(&method(:instantiate))
end
- def run(context)
- extractors.each do |extractor|
- extractor.extract(context).each do |entry|
- transformers.each do |transformer|
- entry = transformer.transform(context, entry)
- end
+ def loaders
+ @loaders ||= self.class.loaders.map(&method(:instantiate))
+ end
- loaders.each do |loader|
- loader.load(context, entry)
- end
- end
- end
+ def pipeline_name
+ @pipeline ||= self.class.name
end
def instantiate(class_config)
class_config[:klass].new(class_config[:options])
end
end
+
+ def run(context)
+ info(context, message: "Pipeline started", pipeline: pipeline_name)
+
+ extractors.each do |extractor|
+ extractor.extract(context).each do |entry|
+ info(context, extractor: extractor.class.name)
+
+ transformers.each do |transformer|
+ info(context, transformer: transformer.class.name)
+ entry = transformer.transform(context, entry)
+ end
+
+ loaders.each do |loader|
+ info(context, loader: loader.class.name)
+ loader.load(context, entry)
+ end
+ end
+ end
+ end
+
+ private # rubocop:disable Lint/UselessAccessModifier
+
+ def info(context, extra = {})
+ logger.info({
+ entity: context.entity.id,
+ entity_type: context.entity.source_type
+ }.merge(extra))
+ end
+
+ def logger
+ @logger ||= Gitlab::Import::Logger.build
+ end
end
end
end
diff --git a/lib/csv_builders/stream.rb b/lib/csv_builders/stream.rb
new file mode 100644
index 00000000000..a2b9fca84cb
--- /dev/null
+++ b/lib/csv_builders/stream.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module CsvBuilders
+ class Stream < CsvBuilder
+ def render(max_rows = 100_000)
+ max_rows_including_header = max_rows + 1
+
+ Enumerator.new do |csv|
+ csv << CSV.generate_line(headers)
+
+ each do |object|
+ csv << CSV.generate_line(row(object))
+ end
+ end.lazy.take(max_rows_including_header) # rubocop: disable CodeReuse/ActiveRecord
+ end
+ end
+end
diff --git a/lib/extracts_ref.rb b/lib/extracts_ref.rb
index adbe93cfa3a..34511423d4a 100644
--- a/lib/extracts_ref.rb
+++ b/lib/extracts_ref.rb
@@ -68,7 +68,7 @@ module ExtractsRef
raise InvalidPathError if @ref.match?(/\s/)
- @commit = @repo.commit(@ref)
+ @commit = @repo.commit(@ref) if @ref.present?
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
diff --git a/lib/gitlab/ci/templates/Security/Secure-Binaries.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/Secure-Binaries.gitlab-ci.yml
index 2d2e0859373..232c320562b 100644
--- a/lib/gitlab/ci/templates/Security/Secure-Binaries.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Security/Secure-Binaries.gitlab-ci.yml
@@ -131,6 +131,8 @@ secrets:
variables:
- $SECURE_BINARIES_DOWNLOAD_IMAGES == "true" &&
$SECURE_BINARIES_ANALYZERS =~ /\bsecrets\b/
+ variables:
+ SECURE_BINARIES_ANALYZER_VERSION: "3"
sobelow:
extends: .download_images
@@ -162,6 +164,8 @@ klar:
variables:
- $SECURE_BINARIES_DOWNLOAD_IMAGES == "true" &&
$SECURE_BINARIES_ANALYZERS =~ /\bklar\b/
+ variables:
+ SECURE_BINARIES_ANALYZER_VERSION: "3"
clair-vulnerabilities-db:
extends: .download_images
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index e1c37c9057b..cf92cee430c 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -16536,6 +16536,9 @@ msgstr ""
msgid "MattermostService|This service allows users to perform common operations on this project by entering slash commands in Mattermost."
msgstr ""
+msgid "Max 100,000 events"
+msgstr ""
+
msgid "Max Group Export Download requests per minute per user"
msgstr ""
@@ -16560,9 +16563,6 @@ msgstr ""
msgid "Max role"
msgstr ""
-msgid "Max size 15 MB"
-msgstr ""
-
msgid "MaxBuilds"
msgstr ""
diff --git a/scripts/verify-tff-mapping b/scripts/verify-tff-mapping
index 9541d2468b1..1f73753be82 100755
--- a/scripts/verify-tff-mapping
+++ b/scripts/verify-tff-mapping
@@ -40,12 +40,6 @@ tests = [
},
{
- explanation: 'EE lib should map to respective spec',
- source: 'ee/lib/flipper_session.rb',
- expected: ['ee/spec/lib/flipper_session_spec.rb']
- },
-
- {
explanation: 'Tooling should map to respective spec',
source: 'tooling/lib/tooling/test_file_finder.rb',
expected: ['spec/tooling/lib/tooling/test_file_finder_spec.rb']
diff --git a/spec/controllers/projects/cycle_analytics/events_controller_spec.rb b/spec/controllers/projects/cycle_analytics/events_controller_spec.rb
index c5b72ff2b3b..f940da7ea35 100644
--- a/spec/controllers/projects/cycle_analytics/events_controller_spec.rb
+++ b/spec/controllers/projects/cycle_analytics/events_controller_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe Projects::CycleAnalytics::EventsController do
project.add_maintainer(user)
end
- describe 'cycle analytics not set up flag' do
+ describe 'value stream analytics not set up flag' do
context 'with no data' do
it 'is empty' do
get_issue
diff --git a/spec/controllers/projects/cycle_analytics_controller_spec.rb b/spec/controllers/projects/cycle_analytics_controller_spec.rb
index e956065972f..24c2d568d9a 100644
--- a/spec/controllers/projects/cycle_analytics_controller_spec.rb
+++ b/spec/controllers/projects/cycle_analytics_controller_spec.rb
@@ -32,7 +32,7 @@ RSpec.describe Projects::CycleAnalyticsController do
end
end
- describe 'cycle analytics not set up flag' do
+ describe 'value stream analytics not set up flag' do
context 'with no data' do
it 'is true' do
get(:show,
diff --git a/spec/factories/packages.rb b/spec/factories/packages.rb
index e2c5b000988..e4fadb51d41 100644
--- a/spec/factories/packages.rb
+++ b/spec/factories/packages.rb
@@ -129,7 +129,7 @@ FactoryBot.define do
end
trait(:without_loaded_metadatum) do
- conan_metadatum { build(:conan_metadatum, package: nil) }
+ conan_metadatum { build(:conan_metadatum, package: nil) } # rubocop:disable FactoryBot/InlineAssociation
end
end
@@ -141,7 +141,7 @@ FactoryBot.define do
end
factory :composer_metadatum, class: 'Packages::Composer::Metadatum' do
- package { create(:composer_package) }
+ package { association(:composer_package) }
target_sha { '123' }
composer_json { { name: 'foo' } }
@@ -166,12 +166,12 @@ FactoryBot.define do
end
factory :pypi_metadatum, class: 'Packages::Pypi::Metadatum' do
- package { create(:pypi_package, without_loaded_metadatum: true) }
+ package { association(:pypi_package, without_loaded_metadatum: true) }
required_python { '>=2.7' }
end
factory :nuget_metadatum, class: 'Packages::Nuget::Metadatum' do
- package { create(:nuget_package) }
+ package { association(:nuget_package) }
license_url { 'http://www.gitlab.com' }
project_url { 'http://www.gitlab.com' }
@@ -179,7 +179,7 @@ FactoryBot.define do
end
factory :conan_file_metadatum, class: 'Packages::Conan::FileMetadatum' do
- package_file { create(:conan_package_file, :conan_recipe_file, without_loaded_metadatum: true) }
+ package_file { association(:conan_package_file, :conan_recipe_file, without_loaded_metadatum: true) }
recipe_revision { '0' }
conan_file_type { 'recipe_file' }
@@ -188,7 +188,7 @@ FactoryBot.define do
end
trait(:package_file) do
- package_file { create(:conan_package_file, :conan_package, without_loaded_metadatum: true) }
+ package_file { association(:conan_package_file, :conan_package, without_loaded_metadatum: true) }
conan_file_type { 'package_file' }
package_revision { '0' }
conan_package_reference { '123456789' }
@@ -201,8 +201,8 @@ FactoryBot.define do
end
factory :packages_dependency_link, class: 'Packages::DependencyLink' do
- package { create(:nuget_package) }
- dependency { create(:packages_dependency) }
+ package { association(:nuget_package) }
+ dependency { association(:packages_dependency) }
dependency_type { :dependencies }
trait(:with_nuget_metadatum) do
@@ -213,7 +213,7 @@ FactoryBot.define do
end
factory :nuget_dependency_link_metadatum, class: 'Packages::Nuget::DependencyLinkMetadatum' do
- dependency_link { create(:packages_dependency_link) }
+ dependency_link { association(:packages_dependency_link) }
target_framework { '.NETStandard2.0' }
end
diff --git a/spec/factories/packages/package_file.rb b/spec/factories/packages/package_file.rb
index bcca48fb086..643ab8e4f95 100644
--- a/spec/factories/packages/package_file.rb
+++ b/spec/factories/packages/package_file.rb
@@ -15,7 +15,7 @@ FactoryBot.define do
end
factory :conan_package_file do
- package { create(:conan_package, without_package_files: true) }
+ package { association(:conan_package, without_package_files: true) }
transient do
without_loaded_metadatum { false }
diff --git a/spec/frontend/ide/components/ide_spec.js b/spec/frontend/ide/components/ide_spec.js
index 1f9d62f5558..ff3852b6775 100644
--- a/spec/frontend/ide/components/ide_spec.js
+++ b/spec/frontend/ide/components/ide_spec.js
@@ -1,7 +1,15 @@
import Vuex from 'vuex';
import { createLocalVue, shallowMount } from '@vue/test-utils';
+import { GlButton, GlLoadingIcon } from '@gitlab/ui';
import { createStore } from '~/ide/stores';
import ErrorMessage from '~/ide/components/error_message.vue';
+import FindFile from '~/vue_shared/components/file_finder/index.vue';
+import CommitEditorHeader from '~/ide/components/commit_sidebar/editor_header.vue';
+import RepoTabs from '~/ide/components/repo_tabs.vue';
+import IdeStatusBar from '~/ide/components/ide_status_bar.vue';
+import RightPane from '~/ide/components/panes/right.vue';
+import NewModal from '~/ide/components/new_dropdown/modal.vue';
+
import ide from '~/ide/components/ide.vue';
import { file } from '../helpers';
import { projectData } from '../mock_data';
@@ -14,7 +22,7 @@ describe('WebIDE', () => {
let wrapper;
- function createComponent({ projData = emptyProjData, state = {}, mockStubs = {} } = {}) {
+ function createComponent({ projData = emptyProjData, state = {} } = {}) {
const store = createStore();
store.state.currentProjectId = 'abcproject';
@@ -31,7 +39,17 @@ describe('WebIDE', () => {
return shallowMount(ide, {
store,
localVue,
- stubs: mockStubs,
+ stubs: {
+ ErrorMessage,
+ GlButton,
+ GlLoadingIcon,
+ CommitEditorHeader,
+ RepoTabs,
+ IdeStatusBar,
+ FindFile,
+ RightPane,
+ NewModal,
+ },
});
}
@@ -61,9 +79,6 @@ describe('WebIDE', () => {
state: {
errorMessage: null,
},
- mockStubs: {
- ErrorMessage,
- },
});
expect(wrapper.find(ErrorMessage).exists()).toBe(false);
@@ -76,9 +91,6 @@ describe('WebIDE', () => {
text: 'error',
},
},
- mockStubs: {
- ErrorMessage,
- },
});
expect(wrapper.find(ErrorMessage).exists()).toBe(true);
diff --git a/spec/frontend/vue_shared/components/dropdown/dropdown_button_spec.js b/spec/frontend/vue_shared/components/dropdown/dropdown_button_spec.js
index 892a96b76fd..08e5d828b8f 100644
--- a/spec/frontend/vue_shared/components/dropdown/dropdown_button_spec.js
+++ b/spec/frontend/vue_shared/components/dropdown/dropdown_button_spec.js
@@ -60,10 +60,9 @@ describe('DropdownButtonComponent', () => {
});
it('renders dropdown button icon', () => {
- const dropdownIconEl = vm.$el.querySelector('.dropdown-toggle-icon i.fa');
+ const dropdownIconEl = vm.$el.querySelector('[data-testid="chevron-down-icon"]');
expect(dropdownIconEl).not.toBeNull();
- expect(dropdownIconEl.classList.contains('fa-chevron-down')).toBe(true);
});
it('renders slot, if default slot exists', () => {
diff --git a/spec/helpers/recaptcha_experiment_helper_spec.rb b/spec/helpers/recaptcha_helper_spec.rb
index e677164c950..e7f9ba5b73a 100644
--- a/spec/helpers/recaptcha_experiment_helper_spec.rb
+++ b/spec/helpers/recaptcha_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe RecaptchaExperimentHelper, type: :helper do
+RSpec.describe RecaptchaHelper, type: :helper do
let(:session) { {} }
before do
diff --git a/spec/lib/bulk_imports/pipeline/runner_spec.rb b/spec/lib/bulk_imports/pipeline/runner_spec.rb
index 58ec1d1afca..8c882c799ec 100644
--- a/spec/lib/bulk_imports/pipeline/runner_spec.rb
+++ b/spec/lib/bulk_imports/pipeline/runner_spec.rb
@@ -39,7 +39,10 @@ RSpec.describe BulkImports::Pipeline::Runner do
end
it 'runs pipeline extractor, transformer, loader' do
- context = instance_double(BulkImports::Pipeline::Context)
+ context = instance_double(
+ BulkImports::Pipeline::Context,
+ entity: instance_double(BulkImports::Entity, id: 1, source_type: 'group')
+ )
entries = [{ foo: :bar }]
expect_next_instance_of(BulkImports::Extractor) do |extractor|
@@ -54,6 +57,17 @@ RSpec.describe BulkImports::Pipeline::Runner do
expect(loader).to receive(:load).with(context, entries.first)
end
+ expect_next_instance_of(Gitlab::Import::Logger) do |logger|
+ expect(logger).to receive(:info)
+ .with(message: "Pipeline started", pipeline: 'BulkImports::MyPipeline', entity: 1, entity_type: 'group')
+ expect(logger).to receive(:info)
+ .with(entity: 1, entity_type: 'group', extractor: 'BulkImports::Extractor')
+ expect(logger).to receive(:info)
+ .with(entity: 1, entity_type: 'group', transformer: 'BulkImports::Transformer')
+ expect(logger).to receive(:info)
+ .with(entity: 1, entity_type: 'group', loader: 'BulkImports::Loader')
+ end
+
BulkImports::MyPipeline.new.run(context)
end
end
diff --git a/spec/lib/csv_builders/stream_spec.rb b/spec/lib/csv_builders/stream_spec.rb
new file mode 100644
index 00000000000..204baf965d0
--- /dev/null
+++ b/spec/lib/csv_builders/stream_spec.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe CsvBuilders::Stream do
+ let(:event_1) { double(title: 'Added salt', description: 'A teaspoon') }
+ let(:event_2) { double(title: 'Added sugar', description: 'Just a pinch') }
+ let(:fake_relation) { FakeRelation.new([event_1, event_2]) }
+
+ subject(:builder) { described_class.new(fake_relation, 'Title' => 'title', 'Description' => 'description') }
+
+ describe '#render' do
+ before do
+ stub_const('FakeRelation', Array)
+
+ FakeRelation.class_eval do
+ def find_each(&block)
+ each(&block)
+ end
+ end
+ end
+
+ it 'returns a lazy enumerator' do
+ expect(builder.render).to be_an(Enumerator::Lazy)
+ end
+
+ it 'returns all rows up to default max value' do
+ expect(builder.render.to_a).to eq([
+ "Title,Description\n",
+ "Added salt,A teaspoon\n",
+ "Added sugar,Just a pinch\n"
+ ])
+ end
+
+ it 'truncates to max rows' do
+ expect(builder.render(1).to_a).to eq([
+ "Title,Description\n",
+ "Added salt,A teaspoon\n"
+ ])
+ end
+ end
+end
diff --git a/spec/lib/extracts_path_spec.rb b/spec/lib/extracts_path_spec.rb
index dbb3aa8797e..b69cbbf0ec0 100644
--- a/spec/lib/extracts_path_spec.rb
+++ b/spec/lib/extracts_path_spec.rb
@@ -112,6 +112,19 @@ RSpec.describe ExtractsPath do
end
end
end
+
+ context 'ref and path are nil' do
+ let(:params) { { path: nil, ref: nil } }
+
+ it 'does not set commit' do
+ expect(container.repository).not_to receive(:commit).with('')
+ expect(self).to receive(:render_404)
+
+ assign_ref_vars
+
+ expect(@commit).to be_nil
+ end
+ end
end
it_behaves_like 'extracts refs'
diff --git a/spec/lib/extracts_ref_spec.rb b/spec/lib/extracts_ref_spec.rb
index ca2f1fd7dc1..5433a512981 100644
--- a/spec/lib/extracts_ref_spec.rb
+++ b/spec/lib/extracts_ref_spec.rb
@@ -18,6 +18,21 @@ RSpec.describe ExtractsRef do
allow_any_instance_of(described_class).to receive(:repository_container).and_return(container)
end
- it_behaves_like 'assigns ref vars'
+ describe '#assign_ref_vars' do
+ it_behaves_like 'assigns ref vars'
+
+ context 'ref and path are nil' do
+ let(:params) { { path: nil, ref: nil } }
+
+ it 'does not set commit' do
+ expect(container.repository).not_to receive(:commit).with('')
+
+ assign_ref_vars
+
+ expect(@commit).to be_nil
+ end
+ end
+ end
+
it_behaves_like 'extracts refs'
end
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/code_stage_start_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/code_stage_start_spec.rb
index 2809ca2105f..52e9f2d9846 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/code_stage_start_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/code_stage_start_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::CodeStageStart do
let(:subject) { described_class.new({}) }
let(:project) { create(:project) }
- it_behaves_like 'cycle analytics event'
+ it_behaves_like 'value stream analytics event'
it 'needs connection with an issue via merge_requests_closing_issues table' do
issue = create(:issue, project: project)
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_created_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_created_spec.rb
index 5cc6b05407f..224a18653ed 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_created_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_created_spec.rb
@@ -3,5 +3,5 @@
require 'spec_helper'
RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::IssueCreated do
- it_behaves_like 'cycle analytics event'
+ it_behaves_like 'value stream analytics event'
end
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_first_mentioned_in_commit_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_first_mentioned_in_commit_spec.rb
index 715ad5a8e7d..bc0e388cf53 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_first_mentioned_in_commit_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_first_mentioned_in_commit_spec.rb
@@ -3,5 +3,5 @@
require 'spec_helper'
RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::IssueFirstMentionedInCommit do
- it_behaves_like 'cycle analytics event'
+ it_behaves_like 'value stream analytics event'
end
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_stage_end_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_stage_end_spec.rb
index 56241194f36..ddc5f015a8c 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_stage_end_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/issue_stage_end_spec.rb
@@ -3,5 +3,5 @@
require 'spec_helper'
RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::IssueStageEnd do
- it_behaves_like 'cycle analytics event'
+ it_behaves_like 'value stream analytics event'
end
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_created_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_created_spec.rb
index f3202eab5bb..281cc31c9e0 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_created_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_created_spec.rb
@@ -3,5 +3,5 @@
require 'spec_helper'
RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestCreated do
- it_behaves_like 'cycle analytics event'
+ it_behaves_like 'value stream analytics event'
end
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_first_deployed_to_production_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_first_deployed_to_production_spec.rb
index 03b0ccfae43..e1dd2e56e2b 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_first_deployed_to_production_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_first_deployed_to_production_spec.rb
@@ -3,5 +3,5 @@
require 'spec_helper'
RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestFirstDeployedToProduction do
- it_behaves_like 'cycle analytics event'
+ it_behaves_like 'value stream analytics event'
end
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_finished_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_finished_spec.rb
index b0c003e6f2a..51324966f26 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_finished_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_finished_spec.rb
@@ -3,5 +3,5 @@
require 'spec_helper'
RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastBuildFinished do
- it_behaves_like 'cycle analytics event'
+ it_behaves_like 'value stream analytics event'
end
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_started_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_started_spec.rb
index 8f9aaf6f463..10dcaf23b81 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_started_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_last_build_started_spec.rb
@@ -3,5 +3,5 @@
require 'spec_helper'
RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestLastBuildStarted do
- it_behaves_like 'cycle analytics event'
+ it_behaves_like 'value stream analytics event'
end
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_merged_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_merged_spec.rb
index f1d2ca9f36e..6e20eb73ed9 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_merged_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/merge_request_merged_spec.rb
@@ -3,5 +3,5 @@
require 'spec_helper'
RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::MergeRequestMerged do
- it_behaves_like 'cycle analytics event'
+ it_behaves_like 'value stream analytics event'
end
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/plan_stage_start_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/plan_stage_start_spec.rb
index 3248af524bd..b8c68003127 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/plan_stage_start_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/plan_stage_start_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::PlanStageStart do
let(:subject) { described_class.new({}) }
let(:project) { create(:project) }
- it_behaves_like 'cycle analytics event'
+ it_behaves_like 'value stream analytics event'
it 'filters issues where first_associated_with_milestone_at or first_added_to_board_at is filled' do
issue1 = create(:issue, project: project)
diff --git a/spec/lib/gitlab/cycle_analytics/events_spec.rb b/spec/lib/gitlab/cycle_analytics/events_spec.rb
index a31f34d82d7..2c5988f06b2 100644
--- a/spec/lib/gitlab/cycle_analytics/events_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/events_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'cycle analytics events', :aggregate_failures do
+RSpec.describe 'value stream analytics events', :aggregate_failures do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user, :admin) }
let(:from_date) { 10.days.ago }
diff --git a/spec/models/analytics/cycle_analytics/project_stage_spec.rb b/spec/models/analytics/cycle_analytics/project_stage_spec.rb
index 4675f037957..fce31af619c 100644
--- a/spec/models/analytics/cycle_analytics/project_stage_spec.rb
+++ b/spec/models/analytics/cycle_analytics/project_stage_spec.rb
@@ -16,7 +16,7 @@ RSpec.describe Analytics::CycleAnalytics::ProjectStage do
end
end
- it_behaves_like 'cycle analytics stage' do
+ it_behaves_like 'value stream analytics stage' do
let(:parent) { build(:project) }
let(:parent_name) { :project }
end
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index 7330c89fe77..98840d6238a 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -161,7 +161,7 @@ RSpec.describe API::Users, :do_not_mock_admin_mode do
end
context 'accesses the profile of another admin' do
- let(:admin_2) {create(:admin, note: '2010-10-10 | 2FA added | admin requested | www.gitlab.com')}
+ let(:admin_2) { create(:admin, note: '2010-10-10 | 2FA added | admin requested | www.gitlab.com') }
it 'contains the note of the user' do
get api("/user?private_token=#{admin_personal_access_token}&sudo=#{admin_2.id}")
@@ -772,11 +772,11 @@ RSpec.describe API::Users, :do_not_mock_admin_mode do
it "does not create user with invalid email" do
post api('/users', admin),
- params: {
- email: 'invalid email',
- password: 'password',
- name: 'test'
- }
+ params: {
+ email: 'invalid email',
+ password: 'password',
+ name: 'test'
+ }
expect(response).to have_gitlab_http_status(:bad_request)
end
@@ -811,14 +811,14 @@ RSpec.describe API::Users, :do_not_mock_admin_mode do
it 'returns 400 error if user does not validate' do
post api('/users', admin),
- params: {
- password: 'pass',
- email: 'test@example.com',
- username: 'test!',
- name: 'test',
- bio: 'g' * 256,
- projects_limit: -1
- }
+ params: {
+ password: 'pass',
+ email: 'test@example.com',
+ username: 'test!',
+ name: 'test',
+ bio: 'g' * 256,
+ projects_limit: -1
+ }
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['message']['password'])
.to eq(['is too short (minimum is 8 characters)'])
@@ -838,23 +838,23 @@ RSpec.describe API::Users, :do_not_mock_admin_mode do
context 'with existing user' do
before do
post api('/users', admin),
- params: {
- email: 'test@example.com',
- password: 'password',
- username: 'test',
- name: 'foo'
- }
+ params: {
+ email: 'test@example.com',
+ password: 'password',
+ username: 'test',
+ name: 'foo'
+ }
end
it 'returns 409 conflict error if user with same email exists' do
expect do
post api('/users', admin),
- params: {
- name: 'foo',
- email: 'test@example.com',
- password: 'password',
- username: 'foo'
- }
+ params: {
+ name: 'foo',
+ email: 'test@example.com',
+ password: 'password',
+ username: 'foo'
+ }
end.to change { User.count }.by(0)
expect(response).to have_gitlab_http_status(:conflict)
expect(json_response['message']).to eq('Email has already been taken')
@@ -863,12 +863,12 @@ RSpec.describe API::Users, :do_not_mock_admin_mode do
it 'returns 409 conflict error if same username exists' do
expect do
post api('/users', admin),
- params: {
- name: 'foo',
- email: 'foo@example.com',
- password: 'password',
- username: 'test'
- }
+ params: {
+ name: 'foo',
+ email: 'foo@example.com',
+ password: 'password',
+ username: 'test'
+ }
end.to change { User.count }.by(0)
expect(response).to have_gitlab_http_status(:conflict)
expect(json_response['message']).to eq('Username has already been taken')
@@ -877,12 +877,12 @@ RSpec.describe API::Users, :do_not_mock_admin_mode do
it 'returns 409 conflict error if same username exists (case insensitive)' do
expect do
post api('/users', admin),
- params: {
- name: 'foo',
- email: 'foo@example.com',
- password: 'password',
- username: 'TEST'
- }
+ params: {
+ name: 'foo',
+ email: 'foo@example.com',
+ password: 'password',
+ username: 'TEST'
+ }
end.to change { User.count }.by(0)
expect(response).to have_gitlab_http_status(:conflict)
expect(json_response['message']).to eq('Username has already been taken')
@@ -1185,14 +1185,14 @@ RSpec.describe API::Users, :do_not_mock_admin_mode do
it 'returns 400 error if user does not validate' do
put api("/users/#{user.id}", admin),
- params: {
- password: 'pass',
- email: 'test@example.com',
- username: 'test!',
- name: 'test',
- bio: 'g' * 256,
- projects_limit: -1
- }
+ params: {
+ password: 'pass',
+ email: 'test@example.com',
+ username: 'test!',
+ name: 'test',
+ bio: 'g' * 256,
+ projects_limit: -1
+ }
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['message']['password'])
.to eq(['is too short (minimum is 8 characters)'])
@@ -1714,14 +1714,14 @@ RSpec.describe API::Users, :do_not_mock_admin_mode do
context "hard delete disabled" do
it "does not delete user" do
- perform_enqueued_jobs { delete api("/users/#{user.id}", admin)}
+ perform_enqueued_jobs { delete api("/users/#{user.id}", admin) }
expect(response).to have_gitlab_http_status(:conflict)
end
end
context "hard delete enabled" do
it "delete user and group", :sidekiq_might_not_need_inline do
- perform_enqueued_jobs { delete api("/users/#{user.id}?hard_delete=true", admin)}
+ perform_enqueued_jobs { delete api("/users/#{user.id}?hard_delete=true", admin) }
expect(response).to have_gitlab_http_status(:no_content)
expect(Group.exists?(group.id)).to be_falsy
end
@@ -1993,7 +1993,7 @@ RSpec.describe API::Users, :do_not_mock_admin_mode do
delete api("/user/keys/#{key.id}", user)
expect(response).to have_gitlab_http_status(:no_content)
- end.to change { user.keys.count}.by(-1)
+ end.to change { user.keys.count }.by(-1)
end
it_behaves_like '412 response' do
@@ -2124,7 +2124,7 @@ RSpec.describe API::Users, :do_not_mock_admin_mode do
post api("/user/gpg_keys/#{gpg_key.id}/revoke", user)
expect(response).to have_gitlab_http_status(:accepted)
- end.to change { user.gpg_keys.count}.by(-1)
+ end.to change { user.gpg_keys.count }.by(-1)
end
it 'returns 404 if key ID not found' do
@@ -2157,7 +2157,7 @@ RSpec.describe API::Users, :do_not_mock_admin_mode do
delete api("/user/gpg_keys/#{gpg_key.id}", user)
expect(response).to have_gitlab_http_status(:no_content)
- end.to change { user.gpg_keys.count}.by(-1)
+ end.to change { user.gpg_keys.count }.by(-1)
end
it 'returns 404 if key ID not found' do
@@ -2279,7 +2279,7 @@ RSpec.describe API::Users, :do_not_mock_admin_mode do
delete api("/user/emails/#{email.id}", user)
expect(response).to have_gitlab_http_status(:no_content)
- end.to change { user.emails.count}.by(-1)
+ end.to change { user.emails.count }.by(-1)
end
it_behaves_like '412 response' do
@@ -2756,6 +2756,124 @@ RSpec.describe API::Users, :do_not_mock_admin_mode do
end
end
+ describe 'POST /users/:user_id/personal_access_tokens' do
+ let(:name) { 'new pat' }
+ let(:expires_at) { 3.days.from_now.to_date.to_s }
+ let(:scopes) { %w(api read_user) }
+
+ context 'when feature flag is enabled' do
+ before do
+ stub_feature_flags(pat_creation_api_for_admin: true)
+ end
+
+ it 'returns error if required attributes are missing' do
+ post api("/users/#{user.id}/personal_access_tokens", admin)
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['error']).to eq('name is missing, scopes is missing, scopes does not have a valid value')
+ end
+
+ it 'returns a 404 error if user not found' do
+ post api("/users/#{non_existing_record_id}/personal_access_tokens", admin),
+ params: {
+ name: name,
+ scopes: scopes,
+ expires_at: expires_at
+ }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(json_response['message']).to eq('404 User Not Found')
+ end
+
+ it 'returns a 401 error when not authenticated' do
+ post api("/users/#{user.id}/personal_access_tokens"),
+ params: {
+ name: name,
+ scopes: scopes,
+ expires_at: expires_at
+ }
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ expect(json_response['message']).to eq('401 Unauthorized')
+ end
+
+ it 'returns a 403 error when authenticated as normal user' do
+ post api("/users/#{user.id}/personal_access_tokens", user),
+ params: {
+ name: name,
+ scopes: scopes,
+ expires_at: expires_at
+ }
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ expect(json_response['message']).to eq('403 Forbidden')
+ end
+
+ it 'creates a personal access token when authenticated as admin' do
+ post api("/users/#{user.id}/personal_access_tokens", admin),
+ params: {
+ name: name,
+ expires_at: expires_at,
+ scopes: scopes
+ }
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(json_response['name']).to eq(name)
+ expect(json_response['scopes']).to eq(scopes)
+ expect(json_response['expires_at']).to eq(expires_at)
+ expect(json_response['id']).to be_present
+ expect(json_response['created_at']).to be_present
+ expect(json_response['active']).to be_truthy
+ expect(json_response['revoked']).to be_falsey
+ expect(json_response['token']).to be_present
+ end
+
+ context 'when an error is thrown by the model' do
+ let!(:admin_personal_access_token) { create(:personal_access_token, user: admin) }
+ let(:error_message) { 'error message' }
+
+ before do
+ allow_next_instance_of(PersonalAccessToken) do |personal_access_token|
+ allow(personal_access_token).to receive_message_chain(:errors, :full_messages)
+ .and_return([error_message])
+
+ allow(personal_access_token).to receive(:save).and_return(false)
+ end
+ end
+
+ it 'returns the error' do
+ post api("/users/#{user.id}/personal_access_tokens", personal_access_token: admin_personal_access_token),
+ params: {
+ name: name,
+ expires_at: expires_at,
+ scopes: scopes
+ }
+
+ expect(response).to have_gitlab_http_status(:unprocessable_entity)
+ expect(json_response['message']).to eq(error_message)
+ end
+ end
+ end
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(pat_creation_api_for_admin: false)
+ end
+
+ it 'returns a 404' do
+ post api("/users/#{user.id}/personal_access_tokens", admin),
+ params: {
+ name: name,
+ expires_at: expires_at,
+ scopes: scopes
+ }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(json_response['message']).to eq('404 Not Found')
+ end
+ end
+ end
+
describe 'GET /users/:user_id/impersonation_tokens' do
let_it_be(:active_personal_access_token) { create(:personal_access_token, user: user) }
let_it_be(:revoked_personal_access_token) { create(:personal_access_token, :revoked, user: user) }
diff --git a/spec/support/cycle_analytics_helpers/test_generation.rb b/spec/support/cycle_analytics_helpers/test_generation.rb
index c577e5cc665..f866220b919 100644
--- a/spec/support/cycle_analytics_helpers/test_generation.rb
+++ b/spec/support/cycle_analytics_helpers/test_generation.rb
@@ -6,7 +6,7 @@
# multiple nested contexts. This shouldn't count as a violation.
module CycleAnalyticsHelpers
module TestGeneration
- # Generate the most common set of specs that all cycle analytics phases need to have.
+ # Generate the most common set of specs that all value stream analytics phases need to have.
#
# Arguments:
#
@@ -14,10 +14,10 @@ module CycleAnalyticsHelpers
# data_fn: A function that returns a hash, constituting initial data for the test case
# start_time_conditions: An array of `conditions`. Each condition is an tuple of `condition_name` and `condition_fn`. `condition_fn` is called with
# `context` (no lexical scope, so need to do `context.create` for factories, for example) and `data` (from the `data_fn`).
- # Each `condition_fn` is expected to implement a case which consitutes the start of the given cycle analytics phase.
+ # Each `condition_fn` is expected to implement a case which consitutes the start of the given value stream analytics phase.
# end_time_conditions: An array of `conditions`. Each condition is an tuple of `condition_name` and `condition_fn`. `condition_fn` is called with
# `context` (no lexical scope, so need to do `context.create` for factories, for example) and `data` (from the `data_fn`).
- # Each `condition_fn` is expected to implement a case which consitutes the end of the given cycle analytics phase.
+ # Each `condition_fn` is expected to implement a case which consitutes the end of the given value stream analytics phase.
# before_end_fn: This function is run before calling the end time conditions. Used for setup that needs to be run between the start and end conditions.
# post_fn: Code that needs to be run after running the end time conditions.
diff --git a/spec/support/shared_examples/lib/gitlab/cycle_analytics/event_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/cycle_analytics/event_shared_examples.rb
index d0e41605e00..145a7290ac8 100644
--- a/spec/support/shared_examples/lib/gitlab/cycle_analytics/event_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/cycle_analytics/event_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.shared_examples_for 'cycle analytics event' do
+RSpec.shared_examples_for 'value stream analytics event' do
let(:params) { {} }
let(:instance) { described_class.new(params) }
diff --git a/spec/support/shared_examples/models/cycle_analytics_stage_shared_examples.rb b/spec/support/shared_examples/models/cycle_analytics_stage_shared_examples.rb
index 8092f87383d..17948d648cb 100644
--- a/spec/support/shared_examples/models/cycle_analytics_stage_shared_examples.rb
+++ b/spec/support/shared_examples/models/cycle_analytics_stage_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.shared_examples 'cycle analytics stage' do
+RSpec.shared_examples 'value stream analytics stage' do
let(:valid_params) do
{
name: 'My Stage',
@@ -111,7 +111,7 @@ RSpec.shared_examples 'cycle analytics stage' do
end
end
-RSpec.shared_examples 'cycle analytics label based stage' do
+RSpec.shared_examples 'value stream analytics label based stage' do
context 'when creating label based event' do
context 'when the label id is not passed' do
it 'returns validation error when `start_event_label_id` is missing' do
diff --git a/spec/tooling/lib/tooling/test_file_finder_spec.rb b/spec/tooling/lib/tooling/test_file_finder_spec.rb
index 64b55b9b1d6..683bc647b8a 100644
--- a/spec/tooling/lib/tooling/test_file_finder_spec.rb
+++ b/spec/tooling/lib/tooling/test_file_finder_spec.rb
@@ -63,14 +63,6 @@ RSpec.describe Tooling::TestFileFinder do
end
end
- context 'when given a lib file in ee/' do
- let(:file) { 'ee/lib/flipper_session.rb' }
-
- it 'returns the matching ee/ lib test file' do
- expect(subject.test_files).to contain_exactly('ee/spec/lib/flipper_session_spec.rb')
- end
- end
-
context 'when given a test file in ee/' do
let(:file) { 'ee/spec/models/container_registry/event_spec.rb' }