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:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-10-25 09:10:36 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-10-25 09:10:36 +0300
commit866b1f8ed7db9b29b1188ffcba309b92572f354b (patch)
tree48f59dd9b5a292e58e8ce20fbff7e95b6178afe1
parent01fbd09ea9ea4eeae52ed9fb4f7cc4dd97b4eb69 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--app/assets/javascripts/access_tokens/components/new_access_token_app.vue7
-rw-r--r--app/assets/javascripts/pages/projects/hooks/index.js2
-rw-r--r--app/assets/javascripts/vue_shared/components/form/input_copy_toggle_visibility.vue2
-rw-r--r--app/assets/javascripts/webhooks/components/push_events.vue112
-rw-r--r--app/assets/javascripts/webhooks/constants.js17
-rw-r--r--app/assets/javascripts/webhooks/webhook.js23
-rw-r--r--app/helpers/events_helper.rb2
-rw-r--r--app/helpers/integrations_helper.rb25
-rw-r--r--app/helpers/todos_helper.rb37
-rw-r--r--app/views/dashboard/todos/_todo.html.haml3
-rw-r--r--db/post_migrate/20221006070927_finalize_invalid_member_cleanup.rb22
-rw-r--r--db/schema_migrations/202210060709271
-rw-r--r--lib/banzai/filter/math_filter.rb2
-rw-r--r--locale/gitlab.pot54
-rw-r--r--package.json2
-rw-r--r--qa/qa/page/component/access_tokens.rb10
-rw-r--r--spec/controllers/projects/jobs_controller_spec.rb5
-rw-r--r--spec/factories/ci/builds.rb2
-rw-r--r--spec/features/admin/admin_users_impersonation_tokens_spec.rb31
-rw-r--r--spec/features/profiles/personal_access_tokens_spec.rb39
-rw-r--r--spec/features/projects/settings/webhooks_settings_spec.rb2
-rw-r--r--spec/frontend/access_tokens/components/new_access_token_app_spec.js1
-rw-r--r--spec/frontend/webhooks/components/__snapshots__/push_events_spec.js.snap453
-rw-r--r--spec/frontend/webhooks/components/push_events_spec.js117
-rw-r--r--spec/helpers/events_helper_spec.rb24
-rw-r--r--spec/helpers/integrations_helper_spec.rb50
-rw-r--r--spec/helpers/todos_helper_spec.rb29
-rw-r--r--spec/lib/banzai/filter/math_filter_spec.rb3
-rw-r--r--spec/migrations/finalize_invalid_member_cleanup_spec.rb72
-rw-r--r--spec/models/ci/build_runner_session_spec.rb6
-rw-r--r--spec/support/helpers/features/access_token_helpers.rb19
-rw-r--r--spec/support/shared_examples/features/access_tokens_shared_examples.rb20
-rw-r--r--workhorse/go.mod2
-rw-r--r--workhorse/go.sum6
-rw-r--r--yarn.lock8
36 files changed, 1114 insertions, 98 deletions
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index 1a2cb3681bc..06bd7d509ce 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-e1dd9bfe694190e9350dad37b5cd8b5ea44eafa3
+bb32df05c777d0cd8a8d15249c99e2d8055e0769
diff --git a/app/assets/javascripts/access_tokens/components/new_access_token_app.vue b/app/assets/javascripts/access_tokens/components/new_access_token_app.vue
index ce5342ad1ea..d24285af5c3 100644
--- a/app/assets/javascripts/access_tokens/components/new_access_token_app.vue
+++ b/app/assets/javascripts/access_tokens/components/new_access_token_app.vue
@@ -104,18 +104,13 @@ export default {
@[$options.EVENT_ERROR]="onError"
@[$options.EVENT_SUCCESS]="onSuccess"
>
- <div ref="container">
+ <div ref="container" data-testid="access-token-section" data-qa-selector="access_token_section">
<template v-if="newToken">
- <!--
- After issue https://gitlab.com/gitlab-org/gitlab/-/issues/360921 is
- closed remove the `initial-visibility`.
- -->
<input-copy-toggle-visibility
:copy-button-title="copyButtonTitle"
:label="label"
:label-for="$options.tokenInputId"
:value="newToken"
- initial-visibility
:form-input-group-props="formInputGroupProps"
>
<template #description>
diff --git a/app/assets/javascripts/pages/projects/hooks/index.js b/app/assets/javascripts/pages/projects/hooks/index.js
index ed476d25f8b..9e559354205 100644
--- a/app/assets/javascripts/pages/projects/hooks/index.js
+++ b/app/assets/javascripts/pages/projects/hooks/index.js
@@ -1,5 +1,7 @@
import initSearchSettings from '~/search_settings';
import initWebhookForm from '~/webhooks';
+import { initPushEventsEditForm } from '~/webhooks/webhook';
initSearchSettings();
initWebhookForm();
+initPushEventsEditForm();
diff --git a/app/assets/javascripts/vue_shared/components/form/input_copy_toggle_visibility.vue b/app/assets/javascripts/vue_shared/components/form/input_copy_toggle_visibility.vue
index 482a2964b4c..2f10e068542 100644
--- a/app/assets/javascripts/vue_shared/components/form/input_copy_toggle_visibility.vue
+++ b/app/assets/javascripts/vue_shared/components/form/input_copy_toggle_visibility.vue
@@ -129,6 +129,8 @@ export default {
v-gl-tooltip.hover="toggleVisibilityLabel"
:aria-label="toggleVisibilityLabel"
:icon="toggleVisibilityIcon"
+ data-testid="toggle-visibility-button"
+ data-qa-selector="toggle_visibility_button"
@click.stop="handleToggleVisibilityButtonClick"
/>
<clipboard-button
diff --git a/app/assets/javascripts/webhooks/components/push_events.vue b/app/assets/javascripts/webhooks/components/push_events.vue
new file mode 100644
index 00000000000..677f06314e0
--- /dev/null
+++ b/app/assets/javascripts/webhooks/components/push_events.vue
@@ -0,0 +1,112 @@
+<script>
+import { GlFormCheckbox, GlFormRadio, GlFormRadioGroup, GlFormInput, GlSprintf } from '@gitlab/ui';
+import {
+ BRANCH_FILTER_ALL_BRANCHES,
+ WILDCARD_CODE_STABLE,
+ WILDCARD_CODE_PRODUCTION,
+ REGEX_CODE,
+ descriptionText,
+} from '~/webhooks/constants';
+
+export default {
+ components: {
+ GlFormCheckbox,
+ GlFormRadio,
+ GlFormRadioGroup,
+ GlFormInput,
+ GlSprintf,
+ },
+ inject: ['pushEvents', 'strategy', 'isNewHook', 'pushEventsBranchFilter'],
+ data() {
+ return {
+ pushEventsData: !this.isNewHook && this.pushEvents,
+ branchFilterStrategyData: this.isNewHook ? BRANCH_FILTER_ALL_BRANCHES : this.strategy,
+ pushEventsBranchFilterData: this.pushEventsBranchFilter,
+ };
+ },
+ WILDCARD_CODE_STABLE,
+ WILDCARD_CODE_PRODUCTION,
+ REGEX_CODE,
+ descriptionText,
+};
+</script>
+
+<template>
+ <div>
+ <gl-form-checkbox v-model="pushEventsData">{{ s__('Webhooks|Push events') }}</gl-form-checkbox>
+ <input type="hidden" :value="pushEventsData" name="hook[push_events]" />
+
+ <div v-if="pushEventsData" class="gl-pl-6">
+ <gl-form-radio-group v-model="branchFilterStrategyData" name="hook[branch_filter_strategy]">
+ <gl-form-radio
+ class="gl-mt-2 branch-filter-strategy-radio"
+ value="all_branches"
+ data-testid="rule_all_branches"
+ >
+ <div data-qa-selector="strategy_radio_all">{{ __('All branches') }}</div>
+ </gl-form-radio>
+
+ <!-- wildcard -->
+ <gl-form-radio
+ class="gl-mt-2 branch-filter-strategy-radio"
+ value="wildcard"
+ data-testid="rule_wildcard"
+ >
+ <div data-qa-selector="strategy_radio_wildcard">
+ {{ s__('Webhooks|Wildcard pattern') }}
+ </div>
+ </gl-form-radio>
+ <div class="gl-ml-6">
+ <gl-form-input
+ v-if="branchFilterStrategyData === 'wildcard'"
+ v-model="pushEventsBranchFilterData"
+ name="hook[push_events_branch_filter]"
+ data-qa-selector="webhook_branch_filter_field"
+ data-testid="webhook_branch_filter_field"
+ />
+ </div>
+ <p
+ v-if="branchFilterStrategyData === 'wildcard'"
+ class="form-text text-muted custom-control"
+ >
+ <gl-sprintf :message="$options.descriptionText.wildcard">
+ <template #WILDCARD_CODE_STABLE>
+ <code>{{ $options.WILDCARD_CODE_STABLE }}</code>
+ </template>
+ <template #WILDCARD_CODE_PRODUCTION>
+ <code>{{ $options.WILDCARD_CODE_PRODUCTION }}</code>
+ </template>
+ </gl-sprintf>
+ </p>
+
+ <!-- regex -->
+ <gl-form-radio
+ class="gl-mt-2 branch-filter-strategy-radio"
+ value="regex"
+ data-testid="rule_regex"
+ >
+ <div data-qa-selector="strategy_radio_regex">
+ {{ s__('Webhooks|Regular expression') }}
+ </div>
+ </gl-form-radio>
+ <div class="gl-ml-6">
+ <gl-form-input
+ v-if="branchFilterStrategyData === 'regex'"
+ v-model="pushEventsBranchFilterData"
+ name="hook[push_events_branch_filter]"
+ data-qa-selector="webhook_branch_filter_field"
+ data-testid="webhook_branch_filter_field"
+ />
+ </div>
+
+ <p v-if="branchFilterStrategyData === 'regex'" class="form-text text-muted custom-control">
+ <gl-sprintf :message="$options.descriptionText.regex">
+ <template #REGEX_CODE>
+ <code>{{ $options.REGEX_CODE }}</code>
+ </template>
+ </gl-sprintf>
+ </p>
+ </gl-form-radio-group>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/webhooks/constants.js b/app/assets/javascripts/webhooks/constants.js
new file mode 100644
index 00000000000..abef16545bc
--- /dev/null
+++ b/app/assets/javascripts/webhooks/constants.js
@@ -0,0 +1,17 @@
+import { s__ } from '~/locale';
+
+export const BRANCH_FILTER_ALL_BRANCHES = 'all_branches';
+export const BRANCH_FILTER_WILDCARD = 'wildcard';
+export const BRANCH_FILTER_REGEX = 'regex';
+
+export const WILDCARD_CODE_STABLE = '*-stable';
+export const WILDCARD_CODE_PRODUCTION = 'production/*';
+
+export const REGEX_CODE = '(feature|hotfix)/*';
+
+export const descriptionText = {
+ [BRANCH_FILTER_WILDCARD]: s__(
+ 'Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported.',
+ ),
+ [BRANCH_FILTER_REGEX]: s__('Webhooks|Regex such as %{REGEX_CODE} is supported.'),
+};
diff --git a/app/assets/javascripts/webhooks/webhook.js b/app/assets/javascripts/webhooks/webhook.js
new file mode 100644
index 00000000000..ca631502745
--- /dev/null
+++ b/app/assets/javascripts/webhooks/webhook.js
@@ -0,0 +1,23 @@
+import Vue from 'vue';
+import { parseBoolean } from '~/lib/utils/common_utils';
+import pushEvents from './components/push_events.vue';
+
+export function initPushEventsEditForm() {
+ const el = document.querySelector('.js-vue-push-events');
+
+ if (!el) return false;
+
+ const provide = {
+ isNewHook: parseBoolean(el.dataset.isNewHook),
+ pushEvents: parseBoolean(el.dataset.pushEvents),
+ strategy: el.dataset.strategy,
+ pushEventsBranchFilter: el.dataset.pushEventsBranchFilter,
+ };
+ return new Vue({
+ el,
+ provide,
+ render(createElement) {
+ return createElement(pushEvents);
+ },
+ });
+}
diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb
index b717cbcc312..087e4838ed9 100644
--- a/app/helpers/events_helper.rb
+++ b/app/helpers/events_helper.rb
@@ -68,7 +68,7 @@ module EventsHelper
author = event.author
if author
- name = self_added ? 'You' : author.name
+ name = self_added ? _('You') : author.name
link_to name, user_path(author.username), title: name
else
escape_once(event.author_name)
diff --git a/app/helpers/integrations_helper.rb b/app/helpers/integrations_helper.rb
index a1512d40235..abfa55cff24 100644
--- a/app/helpers/integrations_helper.rb
+++ b/app/helpers/integrations_helper.rb
@@ -160,6 +160,31 @@ module IntegrationsHelper
!Gitlab.com?
end
+ def integration_issue_type(issue_type)
+ issue_type_i18n_map = {
+ 'issue' => _('Issue'),
+ 'incident' => _('Incident'),
+ 'test_case' => _('Test case'),
+ 'requirement' => _('Requirement'),
+ 'task' => _('Task')
+ }
+
+ issue_type_i18n_map[issue_type] || issue_type
+ end
+
+ def integration_todo_target_type(target_type)
+ target_type_i18n_map = {
+ 'Commit' => _('Commit'),
+ 'Issue' => _('Issue'),
+ 'MergeRequest' => _('Merge Request'),
+ 'Epic' => _('Epic'),
+ DesignManagement::Design.name => _('design'),
+ AlertManagement::Alert.name => _('alert')
+ }
+
+ target_type_i18n_map[target_type] || target_type
+ end
+
extend self
private
diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb
index 520cde9ecee..2663246ef81 100644
--- a/app/helpers/todos_helper.rb
+++ b/app/helpers/todos_helper.rb
@@ -15,21 +15,25 @@ module TodosHelper
def todo_action_name(todo)
case todo.action
- when Todo::ASSIGNED then todo.self_added? ? 'assigned' : 'assigned you'
- when Todo::REVIEW_REQUESTED then 'requested a review of'
- when Todo::MENTIONED, Todo::DIRECTLY_ADDRESSED then "mentioned #{todo_action_subject(todo)} on"
- when Todo::BUILD_FAILED then 'The pipeline failed in'
- when Todo::MARKED then 'added a todo for'
- when Todo::APPROVAL_REQUIRED then "set #{todo_action_subject(todo)} as an approver for"
- when Todo::UNMERGEABLE then 'Could not merge'
- when Todo::MERGE_TRAIN_REMOVED then "Removed from Merge Train:"
+ when Todo::ASSIGNED then todo.self_added? ? _('assigned') : _('assigned you')
+ when Todo::REVIEW_REQUESTED then s_('Todos|requested a review of')
+ when Todo::MENTIONED, Todo::DIRECTLY_ADDRESSED then format(
+ s_("Todos|mentioned %{who} on"), who: todo_action_subject(todo)
+ )
+ when Todo::BUILD_FAILED then s_('Todos|The pipeline failed in')
+ when Todo::MARKED then s_('Todos|added a todo for')
+ when Todo::APPROVAL_REQUIRED then format(
+ s_("Todos|set %{who} as an approver for"), who: todo_action_subject(todo)
+ )
+ when Todo::UNMERGEABLE then s_('Todos|Could not merge')
+ when Todo::MERGE_TRAIN_REMOVED then s_("Todos|Removed from Merge Train:")
end
end
def todo_self_addressing(todo)
case todo.action
- when Todo::ASSIGNED then 'to yourself'
- when Todo::REVIEW_REQUESTED then 'from yourself'
+ when Todo::ASSIGNED then _('to yourself')
+ when Todo::REVIEW_REQUESTED then _('from yourself')
end
end
@@ -66,9 +70,9 @@ module TodosHelper
return _('alert') if todo.for_alert?
target_type = if todo.for_issue_or_work_item?
- todo.target.issue_type
+ IntegrationsHelper.integration_issue_type(todo.target.issue_type)
else
- todo.target_type
+ IntegrationsHelper.integration_todo_target_type(todo.target_type)
end
target_type.titleize.downcase
@@ -109,6 +113,11 @@ module TodosHelper
return unless show_todo_state?(todo)
state = todo.target.state.to_s
+ raw_state_to_i18n = {
+ "closed" => _('Closed'),
+ "merged" => _('Merged'),
+ "resolved" => _('Resolved')
+ }
case todo.target
when MergeRequest
@@ -124,7 +133,7 @@ module TodosHelper
end
tag.span class: "gl-my-0 gl-px-2 status-box #{background_class}" do
- todo.target.state.to_s.capitalize
+ raw_state_to_i18n[state] || state.capitalize
end
end
@@ -237,7 +246,7 @@ module TodosHelper
end
def todo_action_subject(todo)
- todo.self_added? ? 'yourself' : 'you'
+ todo.self_added? ? s_('Todos|yourself') : _('you')
end
def show_todo_state?(todo)
diff --git a/app/views/dashboard/todos/_todo.html.haml b/app/views/dashboard/todos/_todo.html.haml
index b4668b1e52a..47bc8f5c95b 100644
--- a/app/views/dashboard/todos/_todo.html.haml
+++ b/app/views/dashboard/todos/_todo.html.haml
@@ -27,8 +27,7 @@
= todo_target_title(todo)
%span.title-item.todo-project.todo-label
- at
- = todo_parent_path(todo)
+ = s_('Todo|at %{todo_parent_path}').html_safe % { todo_parent_path: todo_parent_path(todo) }
- if todo.self_assigned?
%span.title-item.action-name
diff --git a/db/post_migrate/20221006070927_finalize_invalid_member_cleanup.rb b/db/post_migrate/20221006070927_finalize_invalid_member_cleanup.rb
new file mode 100644
index 00000000000..78786e46f5c
--- /dev/null
+++ b/db/post_migrate/20221006070927_finalize_invalid_member_cleanup.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+class FinalizeInvalidMemberCleanup < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ MIGRATION = 'DestroyInvalidMembers'
+
+ def up
+ ensure_batched_background_migration_is_finished(
+ job_class_name: MIGRATION,
+ table_name: :members,
+ column_name: :id,
+ job_arguments: []
+ )
+ end
+
+ def down
+ # noop
+ end
+end
diff --git a/db/schema_migrations/20221006070927 b/db/schema_migrations/20221006070927
new file mode 100644
index 00000000000..804f77384e0
--- /dev/null
+++ b/db/schema_migrations/20221006070927
@@ -0,0 +1 @@
+933cb5a869696f2343b0b8dfc32f94a64ed7a5119c3f6b2b64ce30e3ae4e555c \ No newline at end of file
diff --git a/lib/banzai/filter/math_filter.rb b/lib/banzai/filter/math_filter.rb
index 1ca4b2c89db..ca13a8d6474 100644
--- a/lib/banzai/filter/math_filter.rb
+++ b/lib/banzai/filter/math_filter.rb
@@ -32,7 +32,7 @@ module Banzai
# Corresponds to the $$\n...\n$$ syntax
DOLLAR_DISPLAY_BLOCK_PATTERN = %r{
^(?<matched>\$\$\ *\n(?<math>.*)\n\$\$\ *)$
- }x.freeze
+ }mx.freeze
# Order dependent. Handle the `$$` syntax before the `$` syntax
DOLLAR_MATH_PIPELINE = [
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index c765793c1c6..3575e9b637c 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -42348,6 +42348,9 @@ msgstr ""
msgid "Todos|Assigned"
msgstr ""
+msgid "Todos|Could not merge"
+msgstr ""
+
msgid "Todos|Design"
msgstr ""
@@ -42399,9 +42402,15 @@ msgstr ""
msgid "Todos|Pipelines"
msgstr ""
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
msgid "Todos|Review requested"
msgstr ""
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42414,6 +42423,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -45418,6 +45445,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45478,6 +45511,12 @@ msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -47276,6 +47315,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -48018,6 +48063,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -49076,6 +49124,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -49212,6 +49263,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/package.json b/package.json
index 1101cb65fd6..bf0dbf59f9d 100644
--- a/package.json
+++ b/package.json
@@ -106,7 +106,7 @@
"codesandbox-api": "0.0.23",
"compression-webpack-plugin": "^5.0.2",
"copy-webpack-plugin": "^6.4.1",
- "core-js": "^3.25.5",
+ "core-js": "^3.26.0",
"cron-validator": "^1.1.1",
"cronstrue": "^1.122.0",
"cropper": "^2.3.0",
diff --git a/qa/qa/page/component/access_tokens.rb b/qa/qa/page/component/access_tokens.rb
index 8723f6619d9..586f69b8a64 100644
--- a/qa/qa/page/component/access_tokens.rb
+++ b/qa/qa/page/component/access_tokens.rb
@@ -28,9 +28,14 @@ module QA
end
base.view 'app/assets/javascripts/access_tokens/components/new_access_token_app.vue' do
+ element :access_token_section
element :created_access_token_field
end
+ base.view 'app/assets/javascripts/vue_shared/components/form/input_copy_toggle_visibility.vue' do
+ element :toggle_visibility_button
+ end
+
base.view 'app/assets/javascripts/access_tokens/components/access_token_table_app.vue' do
element :revoke_button
end
@@ -49,7 +54,10 @@ module QA
end
def created_access_token
- find_element(:created_access_token_field, wait: 30).value
+ within_element(:access_token_section) do
+ click_element(:toggle_visibility_button, wait: 30)
+ find_element(:created_access_token_field).value
+ end
end
def fill_expiry_date(date)
diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb
index 556dd23c135..58627c4dc74 100644
--- a/spec/controllers/projects/jobs_controller_spec.rb
+++ b/spec/controllers/projects/jobs_controller_spec.rb
@@ -1380,7 +1380,7 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
{
'Channel' => {
'Subprotocols' => ["terminal.gitlab.com"],
- 'Url' => 'wss://localhost/proxy/build/default_port/',
+ 'Url' => 'wss://gitlab.example.com/proxy/build/default_port/',
'Header' => {
'Authorization' => [nil]
},
@@ -1536,7 +1536,8 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
allow(Gitlab::Workhorse).to receive(:verify_api_request!).and_return(nil)
expect(job.runner_session_url).to start_with('https://')
- expect(Gitlab::Workhorse).to receive(:channel_websocket).with(a_hash_including(url: "wss://localhost/proxy/build/default_port/"))
+ expect(Gitlab::Workhorse).to receive(:channel_websocket)
+ .with(a_hash_including(url: "wss://gitlab.example.com/proxy/build/default_port/"))
make_request
end
diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb
index 9a3b2837ab8..8396ef480c7 100644
--- a/spec/factories/ci/builds.rb
+++ b/spec/factories/ci/builds.rb
@@ -716,7 +716,7 @@ FactoryBot.define do
trait :with_runner_session do
after(:build) do |build|
- build.build_runner_session(url: 'https://localhost')
+ build.build_runner_session(url: 'https://gitlab.example.com')
end
end
diff --git a/spec/features/admin/admin_users_impersonation_tokens_spec.rb b/spec/features/admin/admin_users_impersonation_tokens_spec.rb
index 45dccf9921f..d93dac4834e 100644
--- a/spec/features/admin/admin_users_impersonation_tokens_spec.rb
+++ b/spec/features/admin/admin_users_impersonation_tokens_spec.rb
@@ -4,18 +4,11 @@ require 'spec_helper'
RSpec.describe 'Admin > Users > Impersonation Tokens', :js do
include Spec::Support::Helpers::ModalHelpers
+ include Spec::Support::Helpers::AccessTokenHelpers
let(:admin) { create(:admin) }
let!(:user) { create(:user) }
- def active_impersonation_tokens
- find("[data-testid='active-tokens']")
- end
-
- def created_impersonation_token
- find_field('new-access-token').value
- end
-
before do
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
@@ -39,12 +32,12 @@ RSpec.describe 'Admin > Users > Impersonation Tokens', :js do
click_on "Create impersonation token"
- expect(active_impersonation_tokens).to have_text(name)
- expect(active_impersonation_tokens).to have_text('in')
- expect(active_impersonation_tokens).to have_text('read_api')
- expect(active_impersonation_tokens).to have_text('read_user')
+ expect(active_access_tokens).to have_text(name)
+ expect(active_access_tokens).to have_text('in')
+ expect(active_access_tokens).to have_text('read_api')
+ expect(active_access_tokens).to have_text('read_user')
expect(PersonalAccessTokensFinder.new(impersonation: true).execute.count).to equal(1)
- expect(created_impersonation_token).not_to be_empty
+ expect(created_access_token).to match(/[\w-]{20}/)
end
end
@@ -55,16 +48,16 @@ RSpec.describe 'Admin > Users > Impersonation Tokens', :js do
it 'only shows impersonation tokens' do
visit admin_user_impersonation_tokens_path(user_id: user.username)
- expect(active_impersonation_tokens).to have_text(impersonation_token.name)
- expect(active_impersonation_tokens).not_to have_text(personal_access_token.name)
- expect(active_impersonation_tokens).to have_text('in')
+ expect(active_access_tokens).to have_text(impersonation_token.name)
+ expect(active_access_tokens).not_to have_text(personal_access_token.name)
+ expect(active_access_tokens).to have_text('in')
end
it 'shows absolute times' do
admin.update!(time_display_relative: false)
visit admin_user_impersonation_tokens_path(user_id: user.username)
- expect(active_impersonation_tokens).to have_text(personal_access_token.expires_at.strftime('%b %-d'))
+ expect(active_access_tokens).to have_text(personal_access_token.expires_at.strftime('%b %-d'))
end
end
@@ -76,7 +69,7 @@ RSpec.describe 'Admin > Users > Impersonation Tokens', :js do
accept_gl_confirm(button_text: 'Revoke') { click_on "Revoke" }
- expect(active_impersonation_tokens).to have_text("This user has no active impersonation tokens.")
+ expect(active_access_tokens).to have_text("This user has no active impersonation tokens.")
end
it "removes expired tokens from 'active' section" do
@@ -84,7 +77,7 @@ RSpec.describe 'Admin > Users > Impersonation Tokens', :js do
visit admin_user_impersonation_tokens_path(user_id: user.username)
- expect(active_impersonation_tokens).to have_text("This user has no active impersonation tokens.")
+ expect(active_access_tokens).to have_text("This user has no active impersonation tokens.")
end
end
diff --git a/spec/features/profiles/personal_access_tokens_spec.rb b/spec/features/profiles/personal_access_tokens_spec.rb
index 088c8a7a15a..3ae88da06f6 100644
--- a/spec/features/profiles/personal_access_tokens_spec.rb
+++ b/spec/features/profiles/personal_access_tokens_spec.rb
@@ -4,22 +4,11 @@ require 'spec_helper'
RSpec.describe 'Profile > Personal Access Tokens', :js do
include Spec::Support::Helpers::ModalHelpers
+ include Spec::Support::Helpers::AccessTokenHelpers
let(:user) { create(:user) }
let(:pat_create_service) { double('PersonalAccessTokens::CreateService', execute: ServiceResponse.error(message: 'error', payload: { personal_access_token: PersonalAccessToken.new })) }
- def active_personal_access_tokens
- find("[data-testid='active-tokens']")
- end
-
- def created_personal_access_token
- find_field('new-access-token').value
- end
-
- def feed_token_description
- "Your feed token authenticates you when your RSS reader loads a personalized RSS feed or when your calendar application loads a personalized calendar. It is visible in those feed URLs."
- end
-
before do
sign_in(user)
end
@@ -43,11 +32,11 @@ RSpec.describe 'Profile > Personal Access Tokens', :js do
click_on "Create personal access token"
wait_for_all_requests
- expect(active_personal_access_tokens).to have_text(name)
- expect(active_personal_access_tokens).to have_text('in')
- expect(active_personal_access_tokens).to have_text('read_api')
- expect(active_personal_access_tokens).to have_text('read_user')
- expect(created_personal_access_token).not_to be_empty
+ expect(active_access_tokens).to have_text(name)
+ expect(active_access_tokens).to have_text('in')
+ expect(active_access_tokens).to have_text('read_api')
+ expect(active_access_tokens).to have_text('read_user')
+ expect(created_access_token).to match(/[\w-]{20}/)
end
context "when creation fails" do
@@ -73,8 +62,8 @@ RSpec.describe 'Profile > Personal Access Tokens', :js do
it 'only shows personal access tokens' do
visit profile_personal_access_tokens_path
- expect(active_personal_access_tokens).to have_text(personal_access_token.name)
- expect(active_personal_access_tokens).not_to have_text(impersonation_token.name)
+ expect(active_access_tokens).to have_text(personal_access_token.name)
+ expect(active_access_tokens).not_to have_text(impersonation_token.name)
end
context 'when User#time_display_relative is false' do
@@ -85,7 +74,7 @@ RSpec.describe 'Profile > Personal Access Tokens', :js do
it 'shows absolute times for expires_at' do
visit profile_personal_access_tokens_path
- expect(active_personal_access_tokens).to have_text(PersonalAccessToken.last.expires_at.strftime('%b %-d'))
+ expect(active_access_tokens).to have_text(PersonalAccessToken.last.expires_at.strftime('%b %-d'))
end
end
end
@@ -97,14 +86,14 @@ RSpec.describe 'Profile > Personal Access Tokens', :js do
visit profile_personal_access_tokens_path
accept_gl_confirm(button_text: 'Revoke') { click_on "Revoke" }
- expect(active_personal_access_tokens).to have_text("This user has no active personal access tokens.")
+ expect(active_access_tokens).to have_text("This user has no active personal access tokens.")
end
it "removes expired tokens from 'active' section" do
personal_access_token.update!(expires_at: 5.days.ago)
visit profile_personal_access_tokens_path
- expect(active_personal_access_tokens).to have_text("This user has no active personal access tokens.")
+ expect(active_access_tokens).to have_text("This user has no active personal access tokens.")
end
context "when revocation fails" do
@@ -115,12 +104,16 @@ RSpec.describe 'Profile > Personal Access Tokens', :js do
visit profile_personal_access_tokens_path
accept_gl_confirm(button_text: "Revoke") { click_on "Revoke" }
- expect(active_personal_access_tokens).to have_text(personal_access_token.name)
+ expect(active_access_tokens).to have_text(personal_access_token.name)
end
end
end
describe "feed token" do
+ def feed_token_description
+ "Your feed token authenticates you when your RSS reader loads a personalized RSS feed or when your calendar application loads a personalized calendar. It is visible in those feed URLs."
+ end
+
context "when enabled" do
it "displays feed token" do
allow(Gitlab::CurrentSettings).to receive(:disable_feed_token).and_return(false)
diff --git a/spec/features/projects/settings/webhooks_settings_spec.rb b/spec/features/projects/settings/webhooks_settings_spec.rb
index ad434749198..adbf2f6ee5c 100644
--- a/spec/features/projects/settings/webhooks_settings_spec.rb
+++ b/spec/features/projects/settings/webhooks_settings_spec.rb
@@ -87,7 +87,7 @@ RSpec.describe 'Projects > Settings > Webhook Settings' do
expect(page).to have_content('SSL Verification: enabled')
expect(page).to have_content('Tag push events')
expect(page).to have_content('Job events')
- expect(page).to have_selector('.js-vue-push-events', visible: :all)
+ expect(page).to have_content('Push events')
end
end
diff --git a/spec/frontend/access_tokens/components/new_access_token_app_spec.js b/spec/frontend/access_tokens/components/new_access_token_app_spec.js
index b4af11169ad..e4313bdfa26 100644
--- a/spec/frontend/access_tokens/components/new_access_token_app_spec.js
+++ b/spec/frontend/access_tokens/components/new_access_token_app_spec.js
@@ -73,7 +73,6 @@ describe('~/access_tokens/components/new_access_token_app', () => {
expect(InputCopyToggleVisibilityComponent.props('copyButtonTitle')).toBe(
sprintf(__('Copy %{accessTokenType}'), { accessTokenType }),
);
- expect(InputCopyToggleVisibilityComponent.props('initialVisibility')).toBe(true);
expect(InputCopyToggleVisibilityComponent.attributes('label')).toBe(
sprintf(__('Your new %{accessTokenType}'), { accessTokenType }),
);
diff --git a/spec/frontend/webhooks/components/__snapshots__/push_events_spec.js.snap b/spec/frontend/webhooks/components/__snapshots__/push_events_spec.js.snap
new file mode 100644
index 00000000000..3dbff024a6b
--- /dev/null
+++ b/spec/frontend/webhooks/components/__snapshots__/push_events_spec.js.snap
@@ -0,0 +1,453 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Webhook push events form editor component Different push events rules when editing existing hook with "all_branches" strategy selected 1`] = `
+<gl-form-radio-group-stub
+ checked="all_branches"
+ disabledfield="disabled"
+ htmlfield="html"
+ name="hook[branch_filter_strategy]"
+ options=""
+ textfield="text"
+ valuefield="value"
+>
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_all_branches"
+ value="all_branches"
+ >
+ <div
+ data-qa-selector="strategy_radio_all"
+ >
+ All branches
+ </div>
+ </gl-form-radio-stub>
+
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_wildcard"
+ value="wildcard"
+ >
+ <div
+ data-qa-selector="strategy_radio_wildcard"
+ >
+
+ Wildcard pattern
+
+ </div>
+ </gl-form-radio-stub>
+
+ <div
+ class="gl-ml-6"
+ >
+ <!---->
+ </div>
+
+ <!---->
+
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_regex"
+ value="regex"
+ >
+ <div
+ data-qa-selector="strategy_radio_regex"
+ >
+
+ Regular expression
+
+ </div>
+ </gl-form-radio-stub>
+
+ <div
+ class="gl-ml-6"
+ >
+ <!---->
+ </div>
+
+ <!---->
+</gl-form-radio-group-stub>
+`;
+
+exports[`Webhook push events form editor component Different push events rules when editing existing hook with "regex" strategy selected 1`] = `
+<gl-form-radio-group-stub
+ checked="regex"
+ disabledfield="disabled"
+ htmlfield="html"
+ name="hook[branch_filter_strategy]"
+ options=""
+ textfield="text"
+ valuefield="value"
+>
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_all_branches"
+ value="all_branches"
+ >
+ <div
+ data-qa-selector="strategy_radio_all"
+ >
+ All branches
+ </div>
+ </gl-form-radio-stub>
+
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_wildcard"
+ value="wildcard"
+ >
+ <div
+ data-qa-selector="strategy_radio_wildcard"
+ >
+
+ Wildcard pattern
+
+ </div>
+ </gl-form-radio-stub>
+
+ <div
+ class="gl-ml-6"
+ >
+ <!---->
+ </div>
+
+ <!---->
+
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_regex"
+ value="regex"
+ >
+ <div
+ data-qa-selector="strategy_radio_regex"
+ >
+
+ Regular expression
+
+ </div>
+ </gl-form-radio-stub>
+
+ <div
+ class="gl-ml-6"
+ >
+ <gl-form-input-stub
+ data-qa-selector="webhook_branch_filter_field"
+ data-testid="webhook_branch_filter_field"
+ name="hook[push_events_branch_filter]"
+ value="foo"
+ />
+ </div>
+
+ <p
+ class="form-text text-muted custom-control"
+ >
+ <gl-sprintf-stub
+ message="Regex such as %{REGEX_CODE} is supported."
+ />
+ </p>
+</gl-form-radio-group-stub>
+`;
+
+exports[`Webhook push events form editor component Different push events rules when editing existing hook with "wildcard" strategy selected 1`] = `
+<gl-form-radio-group-stub
+ checked="wildcard"
+ disabledfield="disabled"
+ htmlfield="html"
+ name="hook[branch_filter_strategy]"
+ options=""
+ textfield="text"
+ valuefield="value"
+>
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_all_branches"
+ value="all_branches"
+ >
+ <div
+ data-qa-selector="strategy_radio_all"
+ >
+ All branches
+ </div>
+ </gl-form-radio-stub>
+
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_wildcard"
+ value="wildcard"
+ >
+ <div
+ data-qa-selector="strategy_radio_wildcard"
+ >
+
+ Wildcard pattern
+
+ </div>
+ </gl-form-radio-stub>
+
+ <div
+ class="gl-ml-6"
+ >
+ <gl-form-input-stub
+ data-qa-selector="webhook_branch_filter_field"
+ data-testid="webhook_branch_filter_field"
+ name="hook[push_events_branch_filter]"
+ value="foo"
+ />
+ </div>
+
+ <p
+ class="form-text text-muted custom-control"
+ >
+ <gl-sprintf-stub
+ message="Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+ />
+ </p>
+
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_regex"
+ value="regex"
+ >
+ <div
+ data-qa-selector="strategy_radio_regex"
+ >
+
+ Regular expression
+
+ </div>
+ </gl-form-radio-stub>
+
+ <div
+ class="gl-ml-6"
+ >
+ <!---->
+ </div>
+
+ <!---->
+</gl-form-radio-group-stub>
+`;
+
+exports[`Webhook push events form editor component Different push events rules when editing new hook all_branches should be selected by default 1`] = `
+<gl-form-radio-group-stub
+ checked="all_branches"
+ disabledfield="disabled"
+ htmlfield="html"
+ name="hook[branch_filter_strategy]"
+ options=""
+ textfield="text"
+ valuefield="value"
+>
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_all_branches"
+ value="all_branches"
+ >
+ <div
+ data-qa-selector="strategy_radio_all"
+ >
+ All branches
+ </div>
+ </gl-form-radio-stub>
+
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_wildcard"
+ value="wildcard"
+ >
+ <div
+ data-qa-selector="strategy_radio_wildcard"
+ >
+
+ Wildcard pattern
+
+ </div>
+ </gl-form-radio-stub>
+
+ <div
+ class="gl-ml-6"
+ >
+ <!---->
+ </div>
+
+ <!---->
+
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_regex"
+ value="regex"
+ >
+ <div
+ data-qa-selector="strategy_radio_regex"
+ >
+
+ Regular expression
+
+ </div>
+ </gl-form-radio-stub>
+
+ <div
+ class="gl-ml-6"
+ >
+ <!---->
+ </div>
+
+ <!---->
+</gl-form-radio-group-stub>
+`;
+
+exports[`Webhook push events form editor component Different push events rules when editing new hook should be able to set regex rule 1`] = `
+<gl-form-radio-group-stub
+ checked="regex"
+ disabledfield="disabled"
+ htmlfield="html"
+ name="hook[branch_filter_strategy]"
+ options=""
+ textfield="text"
+ valuefield="value"
+>
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_all_branches"
+ value="all_branches"
+ >
+ <div
+ data-qa-selector="strategy_radio_all"
+ >
+ All branches
+ </div>
+ </gl-form-radio-stub>
+
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_wildcard"
+ value="wildcard"
+ >
+ <div
+ data-qa-selector="strategy_radio_wildcard"
+ >
+
+ Wildcard pattern
+
+ </div>
+ </gl-form-radio-stub>
+
+ <div
+ class="gl-ml-6"
+ >
+ <!---->
+ </div>
+
+ <!---->
+
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_regex"
+ value="regex"
+ >
+ <div
+ data-qa-selector="strategy_radio_regex"
+ >
+
+ Regular expression
+
+ </div>
+ </gl-form-radio-stub>
+
+ <div
+ class="gl-ml-6"
+ >
+ <gl-form-input-stub
+ data-qa-selector="webhook_branch_filter_field"
+ data-testid="webhook_branch_filter_field"
+ name="hook[push_events_branch_filter]"
+ value=""
+ />
+ </div>
+
+ <p
+ class="form-text text-muted custom-control"
+ >
+ <gl-sprintf-stub
+ message="Regex such as %{REGEX_CODE} is supported."
+ />
+ </p>
+</gl-form-radio-group-stub>
+`;
+
+exports[`Webhook push events form editor component Different push events rules when editing new hook should be able to set wildcard rule 1`] = `
+<gl-form-radio-group-stub
+ checked="wildcard"
+ disabledfield="disabled"
+ htmlfield="html"
+ name="hook[branch_filter_strategy]"
+ options=""
+ textfield="text"
+ valuefield="value"
+>
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_all_branches"
+ value="all_branches"
+ >
+ <div
+ data-qa-selector="strategy_radio_all"
+ >
+ All branches
+ </div>
+ </gl-form-radio-stub>
+
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_wildcard"
+ value="wildcard"
+ >
+ <div
+ data-qa-selector="strategy_radio_wildcard"
+ >
+
+ Wildcard pattern
+
+ </div>
+ </gl-form-radio-stub>
+
+ <div
+ class="gl-ml-6"
+ >
+ <gl-form-input-stub
+ data-qa-selector="webhook_branch_filter_field"
+ data-testid="webhook_branch_filter_field"
+ name="hook[push_events_branch_filter]"
+ value=""
+ />
+ </div>
+
+ <p
+ class="form-text text-muted custom-control"
+ >
+ <gl-sprintf-stub
+ message="Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+ />
+ </p>
+
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_regex"
+ value="regex"
+ >
+ <div
+ data-qa-selector="strategy_radio_regex"
+ >
+
+ Regular expression
+
+ </div>
+ </gl-form-radio-stub>
+
+ <div
+ class="gl-ml-6"
+ >
+ <!---->
+ </div>
+
+ <!---->
+</gl-form-radio-group-stub>
+`;
diff --git a/spec/frontend/webhooks/components/push_events_spec.js b/spec/frontend/webhooks/components/push_events_spec.js
new file mode 100644
index 00000000000..ccb61c4049a
--- /dev/null
+++ b/spec/frontend/webhooks/components/push_events_spec.js
@@ -0,0 +1,117 @@
+import { nextTick } from 'vue';
+import { GlFormCheckbox, GlFormRadioGroup } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import PushEvents from '~/webhooks/components/push_events.vue';
+
+describe('Webhook push events form editor component', () => {
+ let wrapper;
+
+ const findPushEventsCheckBox = (w = wrapper) => w.findComponent(GlFormCheckbox);
+ const findPushEventsIndicator = (w = wrapper) => w.find('input[name="hook[push_events]"]');
+ const findPushEventRulesGroup = (w = wrapper) => w.findComponent(GlFormRadioGroup);
+ const getPushEventsRuleValue = (w = wrapper) => findPushEventRulesGroup(w).vm.$attrs.checked;
+ const findWildcardRuleInput = (w = wrapper) => w.findByTestId('webhook_branch_filter_field');
+ const findRegexRuleInput = (w = wrapper) => w.findByTestId('webhook_branch_filter_field');
+
+ const createComponent = (provides) =>
+ shallowMountExtended(PushEvents, {
+ provide: {
+ isNewHook: true,
+ pushEvents: false,
+ strategy: 'wildcard',
+ pushEventsBranchFilter: '',
+ ...provides,
+ },
+ });
+
+ describe('Renders push events checkbox', () => {
+ it('when it is a new hook', async () => {
+ wrapper = createComponent({
+ isNewHook: true,
+ });
+ await nextTick();
+
+ const checkbox = findPushEventsCheckBox();
+ expect(checkbox.exists()).toBe(true);
+ expect(findPushEventRulesGroup().exists()).toBe(false);
+ expect(findPushEventsIndicator().attributes('value')).toBe('false');
+ });
+
+ it('when it is not a new hook and push events is enabled', async () => {
+ wrapper = createComponent({
+ isNewHook: false,
+ pushEvents: true,
+ });
+ await nextTick();
+
+ expect(findPushEventsCheckBox().exists()).toBe(true);
+ expect(findPushEventRulesGroup().exists()).toBe(true);
+ expect(findPushEventsIndicator().attributes('value')).toBe('true');
+ });
+ });
+
+ describe('Different push events rules', () => {
+ describe('when editing new hook', () => {
+ beforeEach(async () => {
+ wrapper = createComponent({
+ isNewHook: true,
+ });
+ await nextTick();
+ await findPushEventsCheckBox().vm.$emit('input', true);
+ await nextTick();
+ });
+
+ it('all_branches should be selected by default', async () => {
+ expect(findPushEventRulesGroup().element).toMatchSnapshot();
+ });
+
+ it('should be able to set wildcard rule', async () => {
+ expect(getPushEventsRuleValue()).toBe('all_branches');
+ expect(findWildcardRuleInput().exists()).toBe(false);
+ expect(findRegexRuleInput().exists()).toBe(false);
+
+ await findPushEventRulesGroup(wrapper).vm.$emit('input', 'wildcard');
+ expect(findWildcardRuleInput().exists()).toBe(true);
+ expect(findPushEventRulesGroup().element).toMatchSnapshot();
+
+ const testVal = 'test-val';
+ findWildcardRuleInput().vm.$emit('input', testVal);
+ await nextTick();
+ expect(findWildcardRuleInput().attributes('value')).toBe(testVal);
+ });
+
+ it('should be able to set regex rule', async () => {
+ expect(getPushEventsRuleValue()).toBe('all_branches');
+ expect(findRegexRuleInput().exists()).toBe(false);
+ expect(findWildcardRuleInput().exists()).toBe(false);
+
+ await findPushEventRulesGroup(wrapper).vm.$emit('input', 'regex');
+ expect(findRegexRuleInput().exists()).toBe(true);
+ expect(findPushEventRulesGroup().element).toMatchSnapshot();
+
+ const testVal = 'test-val';
+ findRegexRuleInput().vm.$emit('input', testVal);
+ await nextTick();
+ expect(findRegexRuleInput().attributes('value')).toBe(testVal);
+ });
+ });
+
+ describe('when editing existing hook', () => {
+ it.each(['all_branches', 'wildcard', 'regex'])(
+ 'with "%s" strategy selected',
+ async (strategy) => {
+ wrapper = createComponent({
+ isNewHook: false,
+ pushEvents: true,
+ pushEventsBranchFilter: 'foo',
+ strategy,
+ });
+ await nextTick();
+
+ expect(findPushEventsIndicator().attributes('value')).toBe('true');
+ expect(findPushEventRulesGroup().element).toMatchSnapshot();
+ },
+ );
+ });
+ });
+});
diff --git a/spec/helpers/events_helper_spec.rb b/spec/helpers/events_helper_spec.rb
index 7005b3dc53e..39901047b0f 100644
--- a/spec/helpers/events_helper_spec.rb
+++ b/spec/helpers/events_helper_spec.rb
@@ -4,6 +4,30 @@ require 'spec_helper'
RSpec.describe EventsHelper do
include Gitlab::Routing
+ include Banzai::Filter::OutputSafety
+
+ describe '#link_to_author' do
+ let(:user) { create(:user) }
+ let(:event) { create(:event, author: user) }
+
+ it 'returns a link to the author' do
+ name = user.name
+ expect(helper.link_to_author(event)).to eq(link_to(name, user_path(user.username), title: name))
+ end
+
+ it 'returns the author name if the author is not present' do
+ event.author = nil
+
+ expect(helper.link_to_author(event)).to eq(escape_once(event.author_name))
+ end
+
+ it 'returns "You" if the author is the current user' do
+ allow(helper).to receive(:current_user).and_return(user)
+
+ name = _('You')
+ expect(helper.link_to_author(event, self_added: true)).to eq(link_to(name, user_path(user.username), title: name))
+ end
+ end
describe '#event_target_path' do
subject { helper.event_target_path(event.present) }
diff --git a/spec/helpers/integrations_helper_spec.rb b/spec/helpers/integrations_helper_spec.rb
index 95dfc51e8fd..3e5ec9b5348 100644
--- a/spec/helpers/integrations_helper_spec.rb
+++ b/spec/helpers/integrations_helper_spec.rb
@@ -150,4 +150,54 @@ RSpec.describe IntegrationsHelper do
end
end
end
+
+ describe '#integration_issue_type' do
+ using RSpec::Parameterized::TableSyntax
+ let_it_be(:issue) { create(:issue) }
+
+ where(:issue_type, :expected_i18n_issue_type) do
+ "issue" | _('Issue')
+ "incident" | _('Incident')
+ "test_case" | _('Test case')
+ "requirement" | _('Requirement')
+ "task" | _('Task')
+ end
+
+ with_them do
+ before do
+ issue.update!(issue_type: issue_type)
+ end
+
+ it "return the correct i18n issue type" do
+ expect(described_class.integration_issue_type(issue.issue_type)).to eq(expected_i18n_issue_type)
+ end
+ end
+
+ it "only consider these enumeration values are valid" do
+ expected_valid_types = %w[issue incident test_case requirement task]
+ expect(Issue.issue_types.keys).to contain_exactly(*expected_valid_types)
+ end
+ end
+
+ describe '#integration_todo_target_type' do
+ using RSpec::Parameterized::TableSyntax
+ let!(:todo) { create(:todo, commit_id: '123') }
+
+ where(:target_type, :expected_i18n_target_type) do
+ "Commit" | _("Commit")
+ "Issue" | _("Issue")
+ "MergeRequest" | _("Merge Request")
+ 'Epic' | _('Epic')
+ DesignManagement::Design.name | _('design')
+ AlertManagement::Alert.name | _('alert')
+ end
+
+ with_them do
+ before do
+ todo.update!(target_type: target_type)
+ end
+
+ it { expect(described_class.integration_todo_target_type(todo.target_type)).to eq(expected_i18n_target_type) }
+ end
+ end
end
diff --git a/spec/helpers/todos_helper_spec.rb b/spec/helpers/todos_helper_spec.rb
index c64d5990cd9..49e3c6dd740 100644
--- a/spec/helpers/todos_helper_spec.rb
+++ b/spec/helpers/todos_helper_spec.rb
@@ -310,4 +310,33 @@ RSpec.describe TodosHelper do
it { expect(helper.todos_filter_params[:state]).to eq(result) }
end
end
+
+ describe '#todo_action_name' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:action, :self_added?, :expected_action_name) do
+ Todo::ASSIGNED | false | s_('Todos|assigned you')
+ Todo::ASSIGNED | true | s_('Todos|assigned')
+ Todo::REVIEW_REQUESTED | true | s_('Todos|requested a review of')
+ Todo::MENTIONED | true | format(s_("Todos|mentioned %{who} on"), who: s_('Todos|yourself'))
+ Todo::MENTIONED | false | format(s_("Todos|mentioned %{who} on"), who: _('you'))
+ Todo::DIRECTLY_ADDRESSED | true | format(s_("Todos|mentioned %{who} on"), who: s_('Todos|yourself'))
+ Todo::DIRECTLY_ADDRESSED | false | format(s_("Todos|mentioned %{who} on"), who: _('you'))
+ Todo::BUILD_FAILED | true | s_('Todos|The pipeline failed in')
+ Todo::MARKED | true | s_('Todos|added a todo for')
+ Todo::APPROVAL_REQUIRED | true | format(s_("Todos|set %{who} as an approver for"), who: s_('Todos|yourself'))
+ Todo::APPROVAL_REQUIRED | false | format(s_("Todos|set %{who} as an approver for"), who: _('you'))
+ Todo::UNMERGEABLE | true | s_('Todos|Could not merge')
+ Todo::MERGE_TRAIN_REMOVED | true | s_("Todos|Removed from Merge Train:")
+ end
+
+ with_them do
+ before do
+ alert_todo.action = action
+ alert_todo.user = self_added? ? alert_todo.author : user
+ end
+
+ it { expect(helper.todo_action_name(alert_todo)).to eq(expected_action_name) }
+ end
+ end
end
diff --git a/spec/lib/banzai/filter/math_filter_spec.rb b/spec/lib/banzai/filter/math_filter_spec.rb
index dd116eb1109..350ac1edbe1 100644
--- a/spec/lib/banzai/filter/math_filter_spec.rb
+++ b/spec/lib/banzai/filter/math_filter_spec.rb
@@ -97,7 +97,8 @@ RSpec.describe Banzai::Filter::MathFilter do
describe 'block display math using $$\n...\n$$ syntax' do
context 'with valid syntax' do
where(:text, :result_template) do
- "$$\n2+2\n$$" | "<math>2+2</math>"
+ "$$\n2+2\n$$" | "<math>2+2</math>"
+ "$$\n2+2\n3+4\n$$" | "<math>2+2\n3+4</math>"
end
with_them do
diff --git a/spec/migrations/finalize_invalid_member_cleanup_spec.rb b/spec/migrations/finalize_invalid_member_cleanup_spec.rb
new file mode 100644
index 00000000000..a29a89c2396
--- /dev/null
+++ b/spec/migrations/finalize_invalid_member_cleanup_spec.rb
@@ -0,0 +1,72 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe FinalizeInvalidMemberCleanup, :migration do
+ let(:batched_migrations) { table(:batched_background_migrations) }
+
+ let_it_be(:migration) { described_class::MIGRATION }
+
+ describe '#up' do
+ shared_examples 'finalizes the migration' do
+ it 'finalizes the migration' do
+ allow_next_instance_of(Gitlab::Database::BackgroundMigration::BatchedMigrationRunner) do |runner|
+ expect(runner).to receive(:finalize).with('DestroyInvalidMembers', :members, :id, [])
+ end
+ end
+ end
+
+ context 'when migration is missing' do
+ it 'warns migration not found' do
+ expect(Gitlab::AppLogger)
+ .to receive(:warn).with(/Could not find batched background migration for the given configuration:/)
+
+ migrate!
+ end
+ end
+
+ context 'with migration present' do
+ let!(:destroy_invalid_member_migration) do
+ batched_migrations.create!(
+ job_class_name: 'DestroyInvalidMembers',
+ table_name: :members,
+ column_name: :id,
+ job_arguments: [],
+ interval: 2.minutes,
+ min_value: 1,
+ max_value: 2,
+ batch_size: 1000,
+ sub_batch_size: 200,
+ gitlab_schema: :gitlab_main,
+ status: 3 # finished
+ )
+ end
+
+ context 'when migration finished successfully' do
+ it 'does not raise exception' do
+ expect { migrate! }.not_to raise_error
+ end
+ end
+
+ context 'with different migration statuses' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:status, :description) do
+ 0 | 'paused'
+ 1 | 'active'
+ 4 | 'failed'
+ 5 | 'finalizing'
+ end
+
+ with_them do
+ before do
+ destroy_invalid_member_migration.update!(status: status)
+ end
+
+ it_behaves_like 'finalizes the migration'
+ end
+ end
+ end
+ end
+end
diff --git a/spec/models/ci/build_runner_session_spec.rb b/spec/models/ci/build_runner_session_spec.rb
index ed5ed456d7b..9bb8a1bd626 100644
--- a/spec/models/ci/build_runner_session_spec.rb
+++ b/spec/models/ci/build_runner_session_spec.rb
@@ -72,7 +72,7 @@ RSpec.describe Ci::BuildRunnerSession, model: true do
let(:specification) { subject.service_specification(service: service, port: port, path: path, subprotocols: subprotocols) }
it 'returns service proxy url' do
- expect(specification[:url]).to eq "https://localhost/proxy/#{service}/#{port}/#{path}"
+ expect(specification[:url]).to eq "https://gitlab.example.com/proxy/#{service}/#{port}/#{path}"
end
it 'returns default service proxy websocket subprotocol' do
@@ -89,7 +89,7 @@ RSpec.describe Ci::BuildRunnerSession, model: true do
let(:port) { nil }
it 'uses the default port name' do
- expect(specification[:url]).to eq "https://localhost/proxy/#{service}/default_port/#{path}"
+ expect(specification[:url]).to eq "https://gitlab.example.com/proxy/#{service}/default_port/#{path}"
end
end
@@ -97,7 +97,7 @@ RSpec.describe Ci::BuildRunnerSession, model: true do
let(:service) { '' }
it 'uses the service name "build" as default' do
- expect(specification[:url]).to eq "https://localhost/proxy/build/#{port}/#{path}"
+ expect(specification[:url]).to eq "https://gitlab.example.com/proxy/build/#{port}/#{path}"
end
end
diff --git a/spec/support/helpers/features/access_token_helpers.rb b/spec/support/helpers/features/access_token_helpers.rb
new file mode 100644
index 00000000000..f4bdb70c160
--- /dev/null
+++ b/spec/support/helpers/features/access_token_helpers.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+module Spec
+ module Support
+ module Helpers
+ module AccessTokenHelpers
+ def active_access_tokens
+ find("[data-testid='active-tokens']")
+ end
+
+ def created_access_token
+ within('[data-testid=access-token-section]') do
+ find('[data-testid=toggle-visibility-button]').click
+ find_field('new-access-token').value
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/features/access_tokens_shared_examples.rb b/spec/support/shared_examples/features/access_tokens_shared_examples.rb
index cd255abd7a8..4940c0d04cc 100644
--- a/spec/support/shared_examples/features/access_tokens_shared_examples.rb
+++ b/spec/support/shared_examples/features/access_tokens_shared_examples.rb
@@ -9,13 +9,7 @@ RSpec.shared_examples 'resource access tokens missing access rights' do
end
RSpec.shared_examples 'resource access tokens creation' do |resource_type|
- def active_resource_access_tokens
- find("[data-testid='active-tokens']")
- end
-
- def created_resource_access_token
- find_field('new-access-token').value
- end
+ include Spec::Support::Helpers::AccessTokenHelpers
it 'allows creation of an access token', :aggregate_failures do
name = 'My access token'
@@ -34,12 +28,12 @@ RSpec.shared_examples 'resource access tokens creation' do |resource_type|
click_on "Create #{resource_type} access token"
- expect(active_resource_access_tokens).to have_text(name)
- expect(active_resource_access_tokens).to have_text('in')
- expect(active_resource_access_tokens).to have_text('read_api')
- expect(active_resource_access_tokens).to have_text('read_repository')
- expect(active_resource_access_tokens).to have_text('Guest')
- expect(created_resource_access_token).not_to be_empty
+ expect(active_access_tokens).to have_text(name)
+ expect(active_access_tokens).to have_text('in')
+ expect(active_access_tokens).to have_text('read_api')
+ expect(active_access_tokens).to have_text('read_repository')
+ expect(active_access_tokens).to have_text('Guest')
+ expect(created_access_token).to match(/[\w-]{20}/)
end
end
diff --git a/workhorse/go.mod b/workhorse/go.mod
index 28d1eb5f975..3b2a4b1fc70 100644
--- a/workhorse/go.mod
+++ b/workhorse/go.mod
@@ -25,7 +25,7 @@ require (
github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a
github.com/sirupsen/logrus v1.9.0
github.com/smartystreets/goconvey v1.7.2
- github.com/stretchr/testify v1.8.0
+ github.com/stretchr/testify v1.8.1
gitlab.com/gitlab-org/gitaly/v15 v15.4.2
gitlab.com/gitlab-org/golang-archive-zip v0.1.1
gitlab.com/gitlab-org/labkit v1.16.0
diff --git a/workhorse/go.sum b/workhorse/go.sum
index c4f8f62c551..91b92d55bc6 100644
--- a/workhorse/go.sum
+++ b/workhorse/go.sum
@@ -896,8 +896,9 @@ github.com/ssgelm/cookiejarparser v1.0.1/go.mod h1:DUfC0mpjIzlDN7DzKjXpHj0qMI5m9
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
-github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -906,8 +907,9 @@ github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tinylib/msgp v1.1.2 h1:gWmO7n0Ys2RBEb7GPYB9Ujq8Mk5p2U08lRnmMcGy6BQ=
github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
diff --git a/yarn.lock b/yarn.lock
index f9063cf1e62..ed6bdf1fa74 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3903,10 +3903,10 @@ core-js-pure@^3.0.0:
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.5.tgz#c79e75f5e38dbc85a662d91eea52b8256d53b813"
integrity sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA==
-core-js@^3.25.5:
- version "3.25.5"
- resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.25.5.tgz#e86f651a2ca8a0237a5f064c2fe56cef89646e27"
- integrity sha512-nbm6eZSjm+ZuBQxCUPQKQCoUEfFOXjUZ8dTTyikyKaWrTYmAVbykQfwsKE5dBK88u3QCkCrzsx/PPlKfhsvgpw==
+core-js@^3.26.0:
+ version "3.26.0"
+ resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.26.0.tgz#a516db0ed0811be10eac5d94f3b8463d03faccfe"
+ integrity sha512-+DkDrhoR4Y0PxDz6rurahuB+I45OsEUv8E1maPTB6OuHRohMMcznBq9TMpdpDMm/hUPob/mJJS3PqgbHpMTQgw==
core-util-is@~1.0.0:
version "1.0.3"