Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-09-02 18:09:42 +00:00
parent 0a70b104d0
commit a37d7647a5
30 changed files with 304 additions and 283 deletions

View File

@ -71,29 +71,31 @@ export default {
};
</script>
<template>
<gl-dropdown
v-gl-tooltip
:title="__('Insert image')"
:text="__('Insert image')"
size="small"
category="tertiary"
icon="media"
text-sr-only
data-testid="insert-image-toolbar-button"
@hidden="resetFields()"
>
<gl-dropdown-form class="gl-px-3!">
<gl-form-input-group v-model="imgSrc" :placeholder="__('Image URL')">
<template #append>
<gl-button variant="confirm" @click="insertImage">{{ __('Insert') }}</gl-button>
</template>
</gl-form-input-group>
</gl-dropdown-form>
<gl-dropdown-divider />
<gl-dropdown-item @click="openFileUpload">
{{ __('Upload image') }}
</gl-dropdown-item>
<span class="gl-display-inline-flex">
<gl-dropdown
v-gl-tooltip
:text="__('Insert image')"
:title="__('Insert image')"
size="small"
category="tertiary"
icon="media"
lazy
text-sr-only
data-testid="insert-image-toolbar-button"
@hidden="resetFields()"
>
<gl-dropdown-form class="gl-px-3!">
<gl-form-input-group v-model="imgSrc" :placeholder="__('Image URL')">
<template #append>
<gl-button variant="confirm" @click="insertImage">{{ __('Insert') }}</gl-button>
</template>
</gl-form-input-group>
</gl-dropdown-form>
<gl-dropdown-divider />
<gl-dropdown-item @click="openFileUpload">
{{ __('Upload image') }}
</gl-dropdown-item>
</gl-dropdown>
<input
ref="fileSelector"
type="file"
@ -103,5 +105,5 @@ export default {
data-qa-selector="file_upload_field"
@change="onFileSelect"
/>
</gl-dropdown>
</span>
</template>

View File

@ -89,32 +89,34 @@ export default {
</script>
<template>
<editor-state-observer @transaction="updateLinkState">
<gl-dropdown
v-gl-tooltip
:title="__('Insert link')"
:text="__('Insert link')"
:toggle-class="{ active: isActive }"
text-sr-only
size="small"
category="tertiary"
icon="link"
@show="selectLink()"
>
<gl-dropdown-form class="gl-px-3!">
<gl-form-input-group v-model="linkHref" :placeholder="__('Link URL')">
<template #append>
<gl-button variant="confirm" @click="updateLink">{{ __('Apply') }}</gl-button>
</template>
</gl-form-input-group>
</gl-dropdown-form>
<gl-dropdown-divider />
<gl-dropdown-item v-if="isActive" @click="removeLink">
{{ __('Remove link') }}
</gl-dropdown-item>
<gl-dropdown-item v-else @click="openFileUpload">
{{ __('Upload file') }}
</gl-dropdown-item>
<span class="gl-display-inline-flex">
<gl-dropdown
v-gl-tooltip
:title="__('Insert link')"
:text="__('Insert link')"
:toggle-class="{ active: isActive }"
size="small"
category="tertiary"
icon="link"
text-sr-only
lazy
@show="selectLink()"
>
<gl-dropdown-form class="gl-px-3!">
<gl-form-input-group v-model="linkHref" :placeholder="__('Link URL')">
<template #append>
<gl-button variant="confirm" @click="updateLink">{{ __('Apply') }}</gl-button>
</template>
</gl-form-input-group>
</gl-dropdown-form>
<gl-dropdown-divider />
<gl-dropdown-item v-if="isActive" @click="removeLink">
{{ __('Remove link') }}
</gl-dropdown-item>
<gl-dropdown-item v-else @click="openFileUpload">
{{ __('Upload file') }}
</gl-dropdown-item>
</gl-dropdown>
<input
ref="fileSelector"
type="file"
@ -122,6 +124,6 @@ export default {
class="gl-display-none"
@change="onFileSelect"
/>
</gl-dropdown>
</span>
</editor-state-observer>
</template>

View File

@ -56,6 +56,7 @@ export default {
text-sr-only
class="content-editor-dropdown"
right
lazy
>
<gl-dropdown-item @click="insert('codeBlock')">
{{ __('Code block') }}

View File

@ -81,6 +81,7 @@ export default {
class="content-editor-dropdown"
right
text-sr-only
lazy
>
<gl-dropdown-form class="gl-px-3!">
<div v-for="r of list(maxRows)" :key="r" class="gl-display-flex">

View File

@ -64,6 +64,7 @@ export default {
data-qa-selector="text_style_dropdown"
:disabled="!activeItem"
:text="activeItemLabel"
lazy
>
<gl-dropdown-item
v-for="(item, index) in $options.items"

View File

@ -25,7 +25,7 @@ export default {
</script>
<template>
<div
class="gl-display-flex gl-flex-wrap gl-pb-3 gl-pt-0 gl-border-b-solid gl-border-b-1 gl-border-b-gray-200"
class="gl-display-flex gl-flex-wrap gl-pb-3 gl-pt-3 gl-border-b-solid gl-border-b-1 gl-border-b-gray-200"
>
<toolbar-text-style-dropdown
data-testid="text-styles"

View File

@ -1,3 +1,3 @@
import { initAdminRunnerEdit } from '~/runner/admin_runner_edit';
import { initRunnerEdit } from '~/runner/runner_edit';
initAdminRunnerEdit();
initRunnerEdit('#js-admin-runner-edit');

View File

@ -0,0 +1,3 @@
import { initRunnerEdit } from '~/runner/runner_edit';
initRunnerEdit('#js-group-runner-edit');

View File

@ -1,11 +1,14 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
import { showAlertFromLocalStorage } from '../local_storage_alert/show_alert_from_local_storage';
import GroupRunnerShowApp from './group_runner_show_app.vue';
Vue.use(VueApollo);
export const initGroupRunnerShow = (selector = '#js-group-runner-show') => {
showAlertFromLocalStorage();
const el = document.querySelector(selector);
if (!el) {

View File

@ -1,11 +1,11 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
import AdminRunnerEditApp from './admin_runner_edit_app.vue';
import RunnerEditApp from './runner_edit_app.vue';
Vue.use(VueApollo);
export const initAdminRunnerEdit = (selector = '#js-admin-runner-edit') => {
export const initRunnerEdit = (selector) => {
const el = document.querySelector(selector);
if (!el) {
@ -22,7 +22,7 @@ export const initAdminRunnerEdit = (selector = '#js-admin-runner-edit') => {
el,
apolloProvider,
render(h) {
return h(AdminRunnerEditApp, {
return h(RunnerEditApp, {
props: {
runnerId,
runnerPath,

View File

@ -9,7 +9,7 @@ import runnerFormQuery from '../graphql/edit/runner_form.query.graphql';
import { captureException } from '../sentry_utils';
export default {
name: 'AdminRunnerEditApp',
name: 'RunnerEditApp',
components: {
RunnerHeader,
RunnerUpdateForm,

View File

@ -1,14 +1,16 @@
- runner_name = "##{@runner.id} (#{@runner.short_sha})"
- breadcrumb_title _('Edit')
- page_title _('Edit'), "##{@runner.id} (#{@runner.short_sha})"
- page_title _('Edit'), runner_name
- add_to_breadcrumbs _('Runners'), group_runners_path(@group)
- add_to_breadcrumbs "#{@runner.short_sha}", group_runner_path(@group, @runner)
- add_to_breadcrumbs runner_name, group_runner_path(@group, @runner)
- if Feature.enabled?(:group_runner_edit_vue_ui, @group)
#js-group-runner-edit{ data: {runner_id: @runner.id, runner_path: group_runner_path(@group, @runner) } }
- else
%h1.page-title.gl-font-size-h-display
= s_('Runners|Runner #%{runner_id}' % { runner_id: @runner.id })
= render 'shared/runners/runner_type_badge', runner: @runner
%h1.page-title.gl-font-size-h-display
= s_('Runners|Runner #%{runner_id}' % { runner_id: @runner.id })
= render 'shared/runners/runner_type_badge', runner: @runner
= render 'shared/runners/runner_type_alert', runner: @runner
= render 'shared/runners/runner_type_alert', runner: @runner
= render 'shared/runners/form', runner: @runner, runner_form_url: group_runner_path(@group, @runner)
= render 'shared/runners/form', runner: @runner, runner_form_url: group_runner_path(@group, @runner)

View File

@ -0,0 +1,8 @@
---
name: group_runner_edit_vue_ui
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/issues/372055
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96451
milestone: '15.4'
type: development
group: group::runner
default_enabled: false

View File

@ -18,7 +18,9 @@ extra load for Redis and PostgreSQL.
To change the expiry value:
**For Omnibus installations**
::Tabs
:::TabTitle Omnibus package
1. Edit `/etc/gitlab/gitlab.rb`:
@ -34,7 +36,7 @@ To change the expiry value:
gitlab-ctl restart
```
**For installations from source**
:::TabTitle Source
1. Edit `config/gitlab.yml`:
@ -45,3 +47,5 @@ To change the expiry value:
1. Save the file, and then [restart](restart_gitlab.md#installations-from-source)
GitLab for the changes to take effect.
::EndTabs

View File

@ -341,13 +341,20 @@ We also run our test suite against PG11 upon specific database library changes i
### Current versions testing
| Where? | PostgreSQL version | Ruby version |
| ------ | ------------------ | ------------ |
| Merge requests | 12 (default version), 11 for DB library changes | 2.7 (default version) |
| `master` branch commits | 12 (default version), 11 for DB library changes | 2.7 (default version) |
| `maintenance` scheduled pipelines (every 2 hours at even hour) | 12 (default version), 11 for DB library changes | 2.7 (default version) |
| `maintenance` scheduled pipelines (every 2 hours at odd hour) | 12 (default version), 11 for DB library changes | 3.0 (set in the schedule variables) |
| `nightly` scheduled pipelines | 12 (default version), 11, 13 | 2.7 (default version) |
| Where? | PostgreSQL version | Ruby version |
|------------------------------------------------------------------------------------------------|-------------------------------------------------|--------------|
| Merge requests | 12 (default version), 11 for DB library changes | 2.7 (default version) |
| `master` branch commits | 12 (default version), 11 for DB library changes | 2.7 (default version) |
| `maintenance` scheduled pipelines for the `master` branch (every even-numbered hour) | 12 (default version), 11 for DB library changes | 2.7 (default version) |
| `maintenance` scheduled pipelines for the `ruby3` branch (every odd-numbered hour), see below. | 12 (default version), 11 for DB library changes | 3.0 (coded in the branch) |
| `nightly` scheduled pipelines for the `master` branch | 12 (default version), 11, 13 | 2.7 (default version) |
The pipeline configuration for the scheduled pipeline testing Ruby 3 is
stored in the `ruby3-sync` branch. The pipeline updates the `ruby3` branch
with latest `master`, and then it triggers a regular branch pipeline for
`ruby3`. Any changes in `ruby3` are only for running the pipeline. It should
never be merged back to `master`. Any other Ruby 3 changes should go into
`master` directly, which should be compatible with Ruby 2.7.
### Long-term plan

View File

@ -75,20 +75,6 @@ In GitLab, the agent for Kubernetes regularly compares the desired state from th
the actual state from the Kubernetes cluster. Deviations from the desired state are fixed at every check. These checks
happen automatically every 5 minutes. They are not configurable.
## Known issues
The following are known issues:
- Your chart must be in a GitLab project. The project must be an agent configuration project or a public
project. This known issue also exists for manifest-based GitOps and is tracked in
[this epic](https://gitlab.com/groups/gitlab-org/-/epics/7704).
- Values for the chart must be in a `values.yaml` file. This file must be with the chart,
in the same project and path.
- Because of drift detection and remediation, release history, stored in the cluster, is not useful.
A new release is created every five minutes and the oldest release is discarded.
Eventually history consists only of the same information.
View [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/372023) for details.
## Example repository layout
```plaintext
@ -104,6 +90,20 @@ The following are known issues:
└── some-file-used-in-chart.txt
```
## Known issues
The following are known issues:
- Your chart must be in a GitLab project. The project must be an agent configuration project or a public
project. This known issue also exists for manifest-based GitOps and is tracked in
[this epic](https://gitlab.com/groups/gitlab-org/-/epics/7704).
- Values for the chart must be in a `values.yaml` file. This file must be with the chart,
in the same project and path.
- Because of drift detection and remediation, release history, stored in the cluster, is not useful.
A new release is created every five minutes and the oldest release is discarded.
Eventually history consists only of the same information.
View [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/372023) for details.
## Troubleshooting
### Agent cannot find values for the chart

View File

@ -6240,12 +6240,6 @@ msgstr ""
msgid "Billings|Shared runners cannot be enabled until a valid credit card is on file."
msgstr ""
msgid "Billings|The last owner cannot be removed from a seat."
msgstr ""
msgid "Billings|To make this member active, you must first remove an existing active member, or toggle them to over limit."
msgstr ""
msgid "Billings|To use free CI/CD minutes on shared runners, youll need to validate your account with a credit card. If you prefer not to provide one, you can run pipelines by bringing your own runners and disabling shared runners for your project. This is required to discourage and reduce abuse on GitLab infrastructure. %{strongStart}GitLab will not charge your card, it will only be used for validation.%{strongEnd} %{linkStart}Learn more%{linkEnd}."
msgstr ""
@ -6261,12 +6255,6 @@ msgstr ""
msgid "Billings|Validate user account"
msgstr ""
msgid "Billings|You can't change the seat status of a user who was invited via a group or project."
msgstr ""
msgid "Billings|You can't remove yourself from a seat, but you can leave the group."
msgstr ""
msgid "Billings|You'll now be able to take advantage of free CI/CD minutes on shared runners."
msgstr ""
@ -20067,9 +20055,6 @@ msgstr ""
msgid "Improve customer support with Service Desk"
msgstr ""
msgid "In a seat"
msgstr ""
msgid "In case of pull mirroring, your user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""

View File

@ -520,44 +520,19 @@ RSpec.describe "Admin Runners" do
end
describe "Runner edit page" do
let(:runner) { create(:ci_runner, :project) }
let(:project_runner) { create(:ci_runner, :project) }
let!(:project1) { create(:project) }
let!(:project2) { create(:project) }
before do
visit edit_admin_runner_path(runner)
visit edit_admin_runner_path(project_runner)
wait_for_requests
end
describe 'breadcrumbs' do
it 'contains the current runner id and token' do
page.within '[data-testid="breadcrumb-links"]' do
expect(page).to have_link("##{runner.id} (#{runner.short_sha})")
expect(page.find('[data-testid="breadcrumb-current-link"]')).to have_content("Edit")
end
end
end
describe 'runner header', :js do
it 'contains the runner status, type and id' do
expect(page).to have_content("never contacted specific Runner ##{runner.id} created")
end
end
context 'when a runner is updated', :js do
before do
click_on _('Save changes')
wait_for_requests
end
it 'show success alert' do
expect(page.find('[data-testid="alert-success"]')).to have_content('saved')
end
it 'redirects to runner page' do
expect(current_url).to match(admin_runner_path(runner))
end
it_behaves_like 'submits edit runner form' do
let(:runner) { project_runner }
let(:runner_page_path) { admin_runner_path(project_runner) }
end
describe 'projects' do
@ -583,7 +558,7 @@ RSpec.describe "Admin Runners" do
describe 'enable/create' do
shared_examples 'assignable runner' do
it 'enables a runner for a project' do
within '[data-testid="unassigned-projects"]' do
within find('[data-testid="unassigned-projects"] tr', text: project2.full_name) do
click_on 'Enable'
end
@ -594,21 +569,21 @@ RSpec.describe "Admin Runners" do
end
end
context 'with specific runner' do
let(:runner) { create(:ci_runner, :project, projects: [project1]) }
context 'with project runner' do
let(:project_runner) { create(:ci_runner, :project, projects: [project1]) }
before do
visit edit_admin_runner_path(runner)
visit edit_admin_runner_path(project_runner)
end
it_behaves_like 'assignable runner'
end
context 'with locked runner' do
let(:runner) { create(:ci_runner, :project, projects: [project1], locked: true) }
let(:locked_runner) { create(:ci_runner, :project, projects: [project1], locked: true) }
before do
visit edit_admin_runner_path(runner)
visit edit_admin_runner_path(locked_runner)
end
it_behaves_like 'assignable runner'

View File

@ -144,44 +144,70 @@ RSpec.describe "Group Runners" do
end
end
describe "Group runner edit page", :js do
let!(:runner) do
create(:ci_runner, :group, groups: [group], description: 'runner-foo', contacted_at: Time.zone.now)
describe "Group runner show page", :js do
let!(:group_runner) do
create(:ci_runner, :group, groups: [group], description: 'runner-foo')
end
it 'user views runner details' do
visit group_runner_path(group, runner)
visit group_runner_path(group, group_runner)
expect(page).to have_content "#{s_('Runners|Description')} runner-foo"
end
end
it 'user edits the runner to be protected' do
visit edit_group_runner_path(group, runner)
expect(page.find_field('runner[access_level]')).not_to be_checked
check 'runner_access_level'
click_button _('Save changes')
expect(page).to have_content "#{s_('Runners|Configuration')} #{s_('Runners|Protected')}"
describe "Group runner edit page", :js do
let!(:group_runner) do
create(:ci_runner, :group, groups: [group])
end
context 'when a runner has a tag' do
context 'when group_runner_edit_vue_ui is disabled' do
before do
runner.update!(tag_list: ['tag1'])
stub_feature_flags(group_runner_edit_vue_ui: false)
end
it 'user edits runner not to run untagged jobs' do
visit edit_group_runner_path(group, runner)
it 'user edits the runner to be protected' do
visit edit_group_runner_path(group, group_runner)
page.find_field('runner[tag_list]').set('tag1, tag2')
expect(page.find_field('runner[access_level]')).not_to be_checked
uncheck 'runner_run_untagged'
check 'runner_access_level'
click_button _('Save changes')
# Tags can be in any order
expect(page).to have_content /#{s_('Runners|Tags')}.*tag1/
expect(page).to have_content /#{s_('Runners|Tags')}.*tag2/
expect(page).to have_content "#{s_('Runners|Configuration')} #{s_('Runners|Protected')}"
end
context 'when a runner has a tag' do
before do
group_runner.update!(tag_list: ['tag1'])
end
it 'user edits runner not to run untagged jobs' do
visit edit_group_runner_path(group, group_runner)
page.find_field('runner[tag_list]').set('tag1, tag2')
uncheck 'runner_run_untagged'
click_button _('Save changes')
# Tags can be in any order
expect(page).to have_content /#{s_('Runners|Tags')}.*tag1/
expect(page).to have_content /#{s_('Runners|Tags')}.*tag2/
end
end
end
context 'when group_runner_edit_vue_ui is enabled' do
before do
stub_feature_flags(group_runner_edit_vue_ui: true)
visit edit_group_runner_path(group, group_runner)
wait_for_requests
end
it_behaves_like 'submits edit runner form' do
let(:runner) { group_runner }
let(:runner_page_path) { group_runner_path(group, group_runner) }
end
end
end

View File

@ -1,49 +1,33 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`content_editor/components/toolbar_link_button renders dropdown component 1`] = `
"<div class=\\"dropdown b-dropdown gl-new-dropdown btn-group\\" title=\\"Insert link\\">
<!----><button aria-haspopup=\\"true\\" aria-expanded=\\"false\\" type=\\"button\\" class=\\"btn dropdown-toggle btn-default btn-sm gl-button gl-dropdown-toggle btn-default-tertiary dropdown-icon-only\\">
<!----> <svg data-testid=\\"link-icon\\" role=\\"img\\" aria-hidden=\\"true\\" class=\\"dropdown-icon gl-icon s16\\">
<use href=\\"#link\\"></use>
</svg> <span class=\\"gl-new-dropdown-button-text gl-sr-only\\">Insert link</span> <svg data-testid=\\"chevron-down-icon\\" role=\\"img\\" aria-hidden=\\"true\\" class=\\"gl-button-icon dropdown-chevron gl-icon s16\\">
<use href=\\"#chevron-down\\"></use>
</svg></button>
<ul role=\\"menu\\" tabindex=\\"-1\\" class=\\"dropdown-menu\\">
<div class=\\"gl-new-dropdown-inner\\">
<!---->
<!---->
<div class=\\"gl-new-dropdown-contents\\">
"<div title=\\"Insert link\\" lazy=\\"\\">
<li role=\\"presentation\\" class=\\"gl-px-3!\\">
<form tabindex=\\"-1\\" class=\\"b-dropdown-form gl-p-0\\">
<div role=\\"group\\" class=\\"input-group\\" placeholder=\\"Link URL\\">
<!---->
<li role=\\"presentation\\" class=\\"gl-px-3!\\">
<form tabindex=\\"-1\\" class=\\"b-dropdown-form gl-p-0\\">
<div role=\\"group\\" class=\\"input-group\\" placeholder=\\"Link URL\\">
<!---->
<!----> <input type=\\"text\\" placeholder=\\"Link URL\\" class=\\"form-control gl-form-input\\">
<div class=\\"input-group-append\\"><button type=\\"button\\" class=\\"btn btn-confirm btn-md gl-button\\">
<!---->
<!----> <span class=\\"gl-button-text\\">Apply</span></button></div>
<!---->
</div>
</form>
</li>
<li role=\\"presentation\\" class=\\"gl-new-dropdown-divider\\">
<hr role=\\"separator\\" aria-orientation=\\"horizontal\\" class=\\"dropdown-divider\\">
</li>
<li role=\\"presentation\\" class=\\"gl-new-dropdown-item\\"><button role=\\"menuitem\\" type=\\"button\\" class=\\"dropdown-item\\">
<!----> <input type=\\"text\\" placeholder=\\"Link URL\\" class=\\"form-control gl-form-input\\">
<div class=\\"input-group-append\\"><button type=\\"button\\" class=\\"btn btn-confirm btn-md gl-button\\">
<!---->
<!---->
<!---->
<div class=\\"gl-new-dropdown-item-text-wrapper\\">
<p class=\\"gl-new-dropdown-item-text-primary\\">
Upload file
</p>
<!---->
</div>
<!---->
</button></li> <input type=\\"file\\" name=\\"content_editor_attachment\\" class=\\"gl-display-none\\">
<!----> <span class=\\"gl-button-text\\">Apply</span></button></div>
<!---->
</div>
</form>
</li>
<li role=\\"presentation\\" class=\\"gl-new-dropdown-divider\\">
<hr role=\\"separator\\" aria-orientation=\\"horizontal\\" class=\\"dropdown-divider\\">
</li>
<li role=\\"presentation\\" class=\\"gl-new-dropdown-item\\"><button role=\\"menuitem\\" type=\\"button\\" class=\\"dropdown-item\\">
<!---->
<!---->
<!---->
<div class=\\"gl-new-dropdown-item-text-wrapper\\">
<p class=\\"gl-new-dropdown-item-text-primary\\">
Upload file
</p>
<!---->
</div>
<!---->
</div>
</ul>
</button></li>
</div>"
`;

View File

@ -3,6 +3,7 @@ import { mountExtended } from 'helpers/vue_test_utils_helper';
import ToolbarImageButton from '~/content_editor/components/toolbar_image_button.vue';
import Attachment from '~/content_editor/extensions/attachment';
import Image from '~/content_editor/extensions/image';
import { stubComponent } from 'helpers/stub_component';
import { createTestEditor, mockChainedCommands } from '../test_utils';
describe('content_editor/components/toolbar_image_button', () => {
@ -14,6 +15,9 @@ describe('content_editor/components/toolbar_image_button', () => {
provide: {
tiptapEditor: editor,
},
stubs: {
GlDropdown: stubComponent(GlDropdown),
},
});
};

View File

@ -4,6 +4,7 @@ import ToolbarLinkButton from '~/content_editor/components/toolbar_link_button.v
import eventHubFactory from '~/helpers/event_hub_factory';
import Link from '~/content_editor/extensions/link';
import { hasSelection } from '~/content_editor/services/utils';
import { stubComponent } from 'helpers/stub_component';
import { createTestEditor, mockChainedCommands, emitEditorEvent } from '../test_utils';
jest.mock('~/content_editor/services/utils');
@ -18,6 +19,9 @@ describe('content_editor/components/toolbar_link_button', () => {
tiptapEditor: editor,
eventHub: eventHubFactory(),
},
stubs: {
GlDropdown: stubComponent(GlDropdown),
},
});
};
const findDropdown = () => wrapper.findComponent(GlDropdown);

View File

@ -4,6 +4,7 @@ import ToolbarMoreDropdown from '~/content_editor/components/toolbar_more_dropdo
import Diagram from '~/content_editor/extensions/diagram';
import HorizontalRule from '~/content_editor/extensions/horizontal_rule';
import eventHubFactory from '~/helpers/event_hub_factory';
import { stubComponent } from 'helpers/stub_component';
import { createTestEditor, mockChainedCommands, emitEditorEvent } from '../test_utils';
describe('content_editor/components/toolbar_more_dropdown', () => {
@ -24,6 +25,9 @@ describe('content_editor/components/toolbar_more_dropdown', () => {
tiptapEditor,
eventHub,
},
stubs: {
GlDropdown: stubComponent(GlDropdown),
},
propsData,
});
};

View File

@ -1,6 +1,7 @@
import { GlDropdown, GlButton } from '@gitlab/ui';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import ToolbarTableButton from '~/content_editor/components/toolbar_table_button.vue';
import { stubComponent } from 'helpers/stub_component';
import { createTestEditor, mockChainedCommands } from '../test_utils';
describe('content_editor/components/toolbar_table_button', () => {
@ -12,6 +13,9 @@ describe('content_editor/components/toolbar_table_button', () => {
provide: {
tiptapEditor: editor,
},
stubs: {
GlDropdown: stubComponent(GlDropdown),
},
});
};

View File

@ -1,6 +1,7 @@
import Vue, { nextTick } from 'vue';
import { GlForm, GlSkeletonLoader } from '@gitlab/ui';
import VueApollo from 'vue-apollo';
import { __ } from '~/locale';
import createMockApollo from 'helpers/mock_apollo_helper';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
@ -47,6 +48,7 @@ describe('RunnerUpdateForm', () => {
const findSubmit = () => wrapper.find('[type="submit"]');
const findSubmitDisabledAttr = () => findSubmit().attributes('disabled');
const findCancelBtn = () => wrapper.findByRole('link', { name: __('Cancel') });
const submitForm = () => findForm().trigger('submit');
const submitFormAndWait = () => submitForm().then(waitForPromises);
@ -117,6 +119,11 @@ describe('RunnerUpdateForm', () => {
expect(mockRunner).toMatchObject(getFieldsModel());
});
it('Form shows a cancel button', () => {
expect(runnerUpdateHandler).not.toHaveBeenCalled();
expect(findCancelBtn().attributes('href')).toBe(mockRunnerPath);
});
it('Form prevent multiple submissions', async () => {
await submitForm();

View File

@ -9,7 +9,7 @@ import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import RunnerHeader from '~/runner/components/runner_header.vue';
import RunnerUpdateForm from '~/runner/components/runner_update_form.vue';
import runnerFormQuery from '~/runner/graphql/edit/runner_form.query.graphql';
import AdminRunnerEditApp from '~//runner/admin_runner_edit/admin_runner_edit_app.vue';
import RunnerEditApp from '~//runner/runner_edit/runner_edit_app.vue';
import { captureException } from '~/runner/sentry_utils';
import { runnerFormData } from '../mock_data';
@ -24,7 +24,7 @@ const mockRunnerPath = `/admin/runners/${mockRunnerId}`;
Vue.use(VueApollo);
describe('AdminRunnerEditApp', () => {
describe('RunnerEditApp', () => {
let wrapper;
let mockRunnerQuery;
@ -32,7 +32,7 @@ describe('AdminRunnerEditApp', () => {
const findRunnerUpdateForm = () => wrapper.findComponent(RunnerUpdateForm);
const createComponentWithApollo = ({ props = {}, mountFn = shallowMount } = {}) => {
wrapper = mountFn(AdminRunnerEditApp, {
wrapper = mountFn(RunnerEditApp, {
apolloProvider: createMockApollo([[runnerFormQuery, mockRunnerQuery]]),
propsData: {
runnerId: mockRunnerId,
@ -102,7 +102,7 @@ describe('AdminRunnerEditApp', () => {
it('error is reported to sentry', () => {
expect(captureException).toHaveBeenCalledWith({
error: new Error('Error!'),
component: 'AdminRunnerEditApp',
component: 'RunnerEditApp',
});
});

View File

@ -75,10 +75,12 @@ RSpec.describe ProtectedBranches::CacheService, :clean_gitlab_redis_cache do
expect(service.fetch('main', dry_run: true) { true }).to eq(true)
expect(Gitlab::AppLogger).to receive(:error).with(
'class' => described_class.name,
'message' => /Cache mismatch/,
'project_id' => project.id,
'project_path' => project.full_path
{
'class' => described_class.name,
'message' => /Cache mismatch/,
'project_id' => project.id,
'project_path' => project.full_path
}
)
expect(service.fetch('main', dry_run: true) { false }).to eq(false)

View File

@ -145,3 +145,39 @@ RSpec.shared_examples 'pauses, resumes and deletes a runner' do
end
end
end
RSpec.shared_examples 'submits edit runner form' do
it 'breadcrumb contains runner id and token' do
page.within '[data-testid="breadcrumb-links"]' do
expect(page).to have_link("##{runner.id} (#{runner.short_sha})")
expect(page.find('[data-testid="breadcrumb-current-link"]')).to have_content("Edit")
end
end
describe 'runner header', :js do
it 'contains the runner id' do
expect(page).to have_content("Runner ##{runner.id} created")
end
end
context 'when a runner is updated', :js do
before do
find('[data-testid="runner-field-description"] input').set('new-runner-description')
click_on _('Save changes')
wait_for_requests
end
it 'redirects to runner page' do
expect(current_url).to match(runner_page_path)
end
it 'show success alert' do
expect(page.find('[data-testid="alert-success"]')).to have_content('saved')
end
it 'shows updated information' do
expect(page).to have_content("#{s_('Runners|Description')} new-runner-description")
end
end
end

View File

@ -17,15 +17,7 @@ module OmniAuth
protected
def request_phase
if env['REQUEST_METHOD'] == 'GET'
if @configuration.use_sessions? && request.cookies[@configuration.session_cookie]
redirect callback_url
else
get_credentials
end
elsif (env['REQUEST_METHOD'] == 'POST') && (not request.params['username'])
if (env['REQUEST_METHOD'] == 'POST') && (not request.params['username'])
get_credentials
else
session['omniauth.crowd'] = {'username' => request['username'], 'password' => request['password']}

View File

@ -20,9 +20,21 @@ describe OmniAuth::Strategies::Crowd, :type=>:strategy do
@sso_url_image = nil
let(:config) { OmniAuth::Strategies::Crowd::Configuration.new(strategy[1]) }
let(:validator) { OmniAuth::Strategies::Crowd::CrowdValidator.new(config, 'foo', 'bar', nil, nil) }
let(:csrf_token) { SecureRandom.base64(32) }
let(:base_env) { { 'rack.session' => { csrf: csrf_token }, 'rack.input' => StringIO.new("authenticity_token=#{escaped_token}") } }
let(:post_env) { make_env('/auth/crowd', base_env) }
let(:escaped_token) { URI.encode_www_form_component(csrf_token, Encoding::UTF_8) }
def make_env(path = '/auth/crowd', props = {})
{
'REQUEST_METHOD' => 'POST',
'PATH_INFO' => path,
'rack.session' => {},
'rack.input' => StringIO.new('test=true')
}.merge(props)
end
describe 'Authentication Request Body' do
it 'should send password in session request' do
body = <<-BODY.strip
<password>
@ -42,18 +54,10 @@ BODY
end
end
describe 'GET /auth/crowd' do
it 'should show the login form' do
get '/auth/crowd'
expect(last_response).to be_ok
end
end
describe 'POST /auth/crowd' do
it 'should redirect to callback' do
post '/auth/crowd', :username=>'foo', :password=>'bar'
expect(last_response).to be_redirect
expect(last_response.headers['Location']).to eq('http://example.org/auth/crowd/callback')
it 'should show the login form' do
post '/auth/crowd', nil, post_env
expect(last_response).to be_ok
end
end
@ -79,13 +83,16 @@ BODY
to_return(:status => [415, "Unsupported Media Type"])
get '/auth/crowd/callback', nil, 'rack.session'=>{'omniauth.crowd'=> {"username"=>"foo", "password"=>"ba"}}
end
it 'should call through to the master app' do
expect(last_response.body).to eq('true')
end
it 'should have an auth hash' do
auth = last_request.env['omniauth.auth']
expect(auth).to be_kind_of(Hash)
end
it 'should have good data' do
auth = last_request.env['omniauth.auth']
expect(auth['provider']).to eq(:crowd)
@ -142,8 +149,7 @@ BODY
end
end
describe 'GET /auth/crowd without credentials will redirect to login form' do
describe 'POST /auth/crowd without credentials will redirect to login form' do
sso_url = 'https://foo.bar'
before do
@ -152,10 +158,9 @@ BODY
end
it 'should have the SSO button in the response body' do
found_legend = found_anchor = nil
get '/auth/crowd'
post '/auth/crowd', nil, post_env
Nokogiri::HTML(last_response.body).xpath('//html/body/form/fieldset/*').each do |element|
@ -163,26 +168,23 @@ BODY
found_legend = true
elsif element.name === 'a' && element.attr('href') === "#{sso_url}/users/auth/crowd/callback"
found_anchor = true
end
end
end
expect(found_legend).to(be(true))
expect(found_anchor).to(be(true))
end
after do
@using_sessions = false
@sso_url = nil
end
end
describe 'GET /auth/crowd without credentials will redirect to login form which has custom image in the SSO link' do
describe 'POST /auth/crowd without credentials will redirect to login form which has custom image in the SSO link' do
sso_url = 'https://foo.bar'
sso_url_image = 'https://foo.bar/image.png'
before do
@using_sessions = true
@sso_url = sso_url
@ -190,10 +192,9 @@ BODY
end
it 'should have the SSO button with a custom image in the response body' do
found_legend = found_anchor = found_image = false
get '/auth/crowd'
post '/auth/crowd', nil, post_env
Nokogiri::HTML(last_response.body).xpath('//html/body/form/fieldset/*').each do |element|
@ -206,14 +207,12 @@ BODY
if element.children.length === 1 && element.children.first.name === 'img' && element.children.first.attr('src') === sso_url_image
found_image = true
end
end
end
expect(found_legend).to(be(true))
expect(found_anchor).to(be(true))
expect(found_image).to(be(true))
end
after do
@ -221,46 +220,13 @@ BODY
@sso_url = nil
@sso_url_image = nil
end
end
describe 'GET /auth/crowd without credentials but with SSO cookie will redirect to callback' do
sso_url = 'https://foo.bar'
before do
@using_sessions = true
@sso_url = sso_url
set_cookie('crowd.token_key=foobar')
end
it 'should redirect to callback' do
get '/auth/crowd'
expect(last_response).to be_redirect
expect(last_response.headers['Location']).to eq('http://example.org/auth/crowd/callback')
end
after do
@using_sessions = false
@sso_url = nil
clear_cookies()
end
end
describe 'POST /auth/crowd/callback without credentials but with SSO cookie will redirect to login form because session is invalid' do
sso_url = 'https://foo.bar'
token = 'foobar'
before do
@using_sessions = true
@sso_url = sso_url
@ -268,7 +234,6 @@ BODY
to_return(:status => [404])
set_cookie("crowd.token_key=#{token}")
end
it 'should redirect to login form' do
@ -360,7 +325,6 @@ BODY
end
it 'should return user data' do
auth = nil
get '/auth/crowd/callback'