Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-03-24 06:08:31 +00:00
parent b132e99b27
commit 647e9a6eed
20 changed files with 341 additions and 25 deletions

View File

@ -94,7 +94,7 @@ variables:
# Run with decomposed databases by default
DECOMPOSED_DB: "true"
DOCS_REVIEW_APPS_DOMAIN: "178.62.207.141.nip.io"
DOCS_REVIEW_APPS_DOMAIN: "35.193.151.162.nip.io"
DOCS_GITLAB_REPO_SUFFIX: "ee"
REVIEW_APPS_DOMAIN: "gitlab-review.app"

View File

@ -121,7 +121,7 @@ export function formatIssueInput(issueInput, boardConfig) {
: issueInput?.milestoneId,
labelIds: [...labelIds, ...(labels?.map((l) => fullLabelId(l)) || [])],
assigneeIds: [...assigneeIds, ...(assigneeId ? [fullUserId(assigneeId)] : [])],
weight,
weight: weight > -1 ? weight : undefined,
};
}

View File

@ -1,3 +1,5 @@
import { mountApplications } from '~/pages/shared/wikis/show';
import { mountApplications as mountEditApplications } from '~/pages/shared/wikis/async_edit';
mountApplications();
mountEditApplications();

View File

@ -0,0 +1,92 @@
<script>
import { GlSkeletonLoader, GlSafeHtmlDirective, GlAlert } from '@gitlab/ui';
import createFlash from '~/flash';
import { __ } from '~/locale';
import axios from '~/lib/utils/axios_utils';
import { renderGFM } from '../render_gfm_facade';
export default {
components: {
GlSkeletonLoader,
GlAlert,
},
directives: {
SafeHtml: GlSafeHtmlDirective,
},
props: {
getWikiContentUrl: {
type: String,
required: true,
},
},
data() {
return {
isLoadingContent: false,
loadingContentFailed: false,
content: null,
};
},
mounted() {
this.loadWikiContent();
},
methods: {
async loadWikiContent() {
this.loadingContentFailed = false;
this.isLoadingContent = true;
try {
const {
data: { content },
} = await axios.get(this.getWikiContentUrl, { params: { render_html: true } });
this.content = content;
this.$nextTick()
.then(() => {
renderGFM(this.$refs.content);
})
.catch(() =>
createFlash({
message: this.$options.i18n.renderingContentFailed,
}),
);
} catch (e) {
this.loadingContentFailed = true;
} finally {
this.isLoadingContent = false;
}
},
},
i18n: {
loadingContentFailed: __(
'The content for this wiki page failed to load. To fix this error, reload the page.',
),
retryLoadingContent: __('Retry'),
renderingContentFailed: __('The content for this wiki page failed to render.'),
},
};
</script>
<template>
<gl-skeleton-loader v-if="isLoadingContent" :width="830" :height="113">
<rect width="540" height="16" rx="4" />
<rect y="49" width="701" height="16" rx="4" />
<rect y="24" width="830" height="16" rx="4" />
<rect y="73" width="540" height="16" rx="4" />
</gl-skeleton-loader>
<gl-alert
v-else-if="loadingContentFailed"
:dismissible="false"
variant="danger"
:primary-button-text="$options.i18n.retryLoadingContent"
@primaryAction="loadWikiContent"
>
{{ $options.i18n.loadingContentFailed }}
</gl-alert>
<div
v-else-if="!loadingContentFailed && !isLoadingContent"
ref="content"
data-qa-selector="wiki_page_content"
data-testid="wiki_page_content"
class="js-wiki-page-content md"
v-html="content /* eslint-disable-line vue/no-v-html */"
></div>
</template>

View File

@ -0,0 +1,5 @@
import $ from 'jquery';
export const renderGFM = (el) => {
return $(el).renderGFM();
};

View File

@ -0,0 +1,27 @@
import Vue from 'vue';
import Wikis from './wikis';
import WikiContent from './components/wiki_content.vue';
const mountWikiContentApp = () => {
const el = document.querySelector('.js-async-wiki-page-content');
if (el) {
const { getWikiContentUrl } = el.dataset;
// eslint-disable-next-line no-new
new Vue({
el,
render(createElement) {
return createElement(WikiContent, {
props: { getWikiContentUrl },
});
},
});
}
};
export const mountApplications = () => {
// eslint-disable-next-line no-new
new Wikis();
mountWikiContentApp();
};

View File

@ -223,7 +223,7 @@ module WikiActions
def page
strong_memoize(:page) do
wiki.find_page(*page_params)
wiki.find_page(*page_params, load_content: load_content?)
end
end
@ -310,6 +310,13 @@ module WikiActions
def send_wiki_file_blob(wiki, file_blob)
send_blob(wiki.repository, file_blob)
end
def load_content?
return false if params[:action] == 'history'
return false if params[:action] == 'show' && Feature.enabled?(:wiki_async_load, container, default_enabled: :yaml)
true
end
end
WikiActions.prepend_mod

View File

@ -5,6 +5,7 @@ module Ci
def schema
{
'type' => 'object',
'required' => ['pipeline_id'],
'properties' => {
'pipeline_id' => { 'type' => 'integer' }
}

View File

@ -134,6 +134,16 @@ module WikiHelper
current_user&.can?(:admin_project, container) &&
!container.has_confluence?
end
def wiki_page_render_api_endpoint(page)
api_v4_projects_wikis_path(wiki_page_render_api_endpoint_params(page))
end
private
def wiki_page_render_api_endpoint_params(page)
{ id: page.container.id, slug: ERB::Util.url_encode(page.slug), params: { version: page.version.id } }
end
end
WikiHelper.prepend_mod_with('WikiHelper')

View File

@ -13,8 +13,7 @@
%li= s_('GroupSettings|You will need to update your local repositories to point to the new location.')
%li= s_("GroupSettings|If the parent group's visibility is lower than the group's current visibility, visibility levels for subgroups and projects will be changed to match the new parent group's visibility.")
- if group.paid?
.gl-alert.gl-alert-info.gl-mb-5
= sprite_icon('information-o', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
= render 'shared/global_alert', dismissible: false, alert_class: 'gl-mb-5' do
.gl-alert-body
= html_escape(_("This group can't be transferred because it is linked to a subscription. To transfer this group, %{linkStart}link the subscription%{linkEnd} with a different group.")) % { linkStart: "<a href=\"#{help_page_path('subscriptions/index', anchor: 'change-the-linked-namespace')}\">".html_safe, linkEnd: '</a>'.html_safe }
.js-transfer-group-form{ data: initial_data }

View File

@ -26,6 +26,10 @@
%div
- if can?(current_user, :create_wiki, @wiki.container) && @page.latest? && @valid_encoding
= link_to sprite_icon('pencil', css_class: 'gl-icon'), wiki_page_path(@wiki, @page, action: :edit), title: 'Edit', role: "button", class: 'btn gl-button btn-icon btn-default js-wiki-edit', data: { qa_selector: 'edit_page_button', testid: 'wiki_edit_button' }
= render 'shared/wikis/wiki_content'
- if Feature.enabled?(:wiki_async_load, @wiki.container, default_enabled: :yaml)
.js-async-wiki-page-content.md.gl-pt-2{ data: { qa_selector: 'wiki_page_content', testid: 'wiki_page_content', tracking_context: wiki_page_tracking_context(@page).to_json, get_wiki_content_url: wiki_page_render_api_endpoint(@page) } }
- else
= render 'shared/wikis/wiki_content'
= render 'shared/wikis/sidebar'

View File

@ -0,0 +1,8 @@
---
name: wiki_async_load
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/82394
rollout_issue_url:
milestone: '14.9'
type: development
group: group::editor
default_enabled: false

View File

@ -293,8 +293,7 @@ in the `handle_event` method of the subscriber worker.
## Testing
A publisher doesn't must care what subscribed to the event being published. The publisher's
responsibility is to ensure that the event is published correctly.
The publisher's responsibility is to ensure that the event is published correctly.
To test that an event has been published correctly, we can use the RSpec matcher `:publish_event`:

View File

@ -37131,6 +37131,12 @@ msgstr ""
msgid "The content editor may change the markdown formatting style of the document, which may not match your original markdown style."
msgstr ""
msgid "The content for this wiki page failed to load. To fix this error, reload the page."
msgstr ""
msgid "The content for this wiki page failed to render."
msgstr ""
msgid "The content of this page is not encoded in UTF-8. Edits can only be made via the Git repository."
msgstr ""

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Create', :requires_admin, :skip_live_env do
RSpec.describe 'Create', :requires_admin, :skip_live_env, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/195179', type: :flaky } do
describe 'Jenkins integration' do
let(:project_name) { "project_with_jenkins_#{SecureRandom.hex(4)}" }

View File

@ -56,8 +56,11 @@ module DeprecationToolkitEnv
# In this case, we recommend to add a silence together with an issue to patch or update
# the dependency causing the problem.
# See https://gitlab.com/gitlab-org/gitlab/-/commit/aea37f506bbe036378998916d374966c031bf347#note_647515736
#
# - lib/gitlab/lazy.rb: https://gitlab.com/gitlab-org/gitlab/-/issues/356367
def self.allowed_kwarg_warning_paths
%w[
lib/gitlab/lazy.rb
]
end

View File

@ -0,0 +1,27 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Ci::PipelineCreatedEvent do
using RSpec::Parameterized::TableSyntax
where(:data, :valid) do
{ pipeline_id: 1 } | true
{ pipeline_id: nil } | false
{ pipeline_id: "test" } | false
{} | false
{ job_id: 1 } | false
end
with_them do
let(:event) { described_class.new(data: data) }
it 'validates the data according to the schema' do
if valid
expect { event }.not_to raise_error
else
expect { event }.to raise_error(Gitlab::EventStore::InvalidEvent)
end
end
end
end

View File

@ -8,14 +8,26 @@ RSpec.describe 'Project wikis', :js do
let(:wiki) { create(:project_wiki, user: user, project: project) }
let(:project) { create(:project, namespace: user.namespace, creator: user) }
it_behaves_like 'User creates wiki page'
it_behaves_like 'User deletes wiki page'
it_behaves_like 'User previews wiki changes'
it_behaves_like 'User updates wiki page'
it_behaves_like 'User uses wiki shortcuts'
it_behaves_like 'User views AsciiDoc page with includes'
it_behaves_like 'User views a wiki page'
it_behaves_like 'User views wiki pages'
it_behaves_like 'User views wiki sidebar'
it_behaves_like 'User views Git access wiki page'
shared_examples 'wiki feature tests' do
it_behaves_like 'User creates wiki page'
it_behaves_like 'User deletes wiki page'
it_behaves_like 'User previews wiki changes'
it_behaves_like 'User updates wiki page'
it_behaves_like 'User uses wiki shortcuts'
it_behaves_like 'User views AsciiDoc page with includes'
it_behaves_like 'User views a wiki page'
it_behaves_like 'User views wiki pages'
it_behaves_like 'User views wiki sidebar'
it_behaves_like 'User views Git access wiki page'
end
it_behaves_like 'wiki feature tests'
context 'when feature flag :wiki_async_load is disabled' do
before do
stub_feature_flags(wiki_async_load: false)
end
it_behaves_like 'wiki feature tests'
end
end

View File

@ -1,6 +1,12 @@
import { formatIssueInput, filterVariables } from '~/boards/boards_util';
describe('formatIssueInput', () => {
const issueInput = {
labelIds: ['gid://gitlab/GroupLabel/5'],
projectPath: 'gitlab-org/gitlab-test',
id: 'gid://gitlab/Issue/11',
};
it('correctly merges boardConfig into the issue', () => {
const boardConfig = {
labels: [
@ -14,12 +20,6 @@ describe('formatIssueInput', () => {
weight: 1,
};
const issueInput = {
labelIds: ['gid://gitlab/GroupLabel/5'],
projectPath: 'gitlab-org/gitlab-test',
id: 'gid://gitlab/Issue/11',
};
const result = formatIssueInput(issueInput, boardConfig);
expect(result).toEqual({
projectPath: 'gitlab-org/gitlab-test',
@ -30,6 +30,23 @@ describe('formatIssueInput', () => {
weight: 1,
});
});
it('does not add weight to input if weight is NONE', () => {
const boardConfig = {
weight: -2, // NO_WEIGHT
};
const result = formatIssueInput(issueInput, boardConfig);
const expected = {
projectPath: 'gitlab-org/gitlab-test',
id: 'gid://gitlab/Issue/11',
labelIds: ['gid://gitlab/GroupLabel/5'],
assigneeIds: [],
milestoneId: undefined,
};
expect(result).toEqual(expected);
});
});
describe('filterVariables', () => {

View File

@ -0,0 +1,97 @@
import { GlSkeletonLoader, GlAlert } from '@gitlab/ui';
import { nextTick } from 'vue';
import { shallowMount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import WikiContent from '~/pages/shared/wikis/components/wiki_content.vue';
import { renderGFM } from '~/pages/shared/wikis/render_gfm_facade';
import axios from '~/lib/utils/axios_utils';
import httpStatus from '~/lib/utils/http_status';
import waitForPromises from 'helpers/wait_for_promises';
jest.mock('~/pages/shared/wikis/render_gfm_facade');
describe('pages/shared/wikis/components/wiki_content', () => {
const PATH = '/test';
let wrapper;
let mock;
function buildWrapper(propsData = {}) {
wrapper = shallowMount(WikiContent, {
propsData: { getWikiContentUrl: PATH, ...propsData },
stubs: {
GlSkeletonLoader,
GlAlert,
},
});
}
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
const findGlAlert = () => wrapper.findComponent(GlAlert);
const findGlSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
const findContent = () => wrapper.find('[data-testid="wiki_page_content"]');
describe('when loading content', () => {
beforeEach(() => {
buildWrapper();
});
it('renders skeleton loader', () => {
expect(findGlSkeletonLoader().exists()).toBe(true);
});
it('does not render content container or error alert', () => {
expect(findGlAlert().exists()).toBe(false);
expect(findContent().exists()).toBe(false);
});
});
describe('when content loads successfully', () => {
const content = 'content';
beforeEach(() => {
mock.onGet(PATH, { params: { render_html: true } }).replyOnce(httpStatus.OK, { content });
buildWrapper();
return waitForPromises();
});
it('renders content container', () => {
expect(findContent().text()).toBe(content);
});
it('does not render skeleton loader or error alert', () => {
expect(findGlAlert().exists()).toBe(false);
expect(findGlSkeletonLoader().exists()).toBe(false);
});
it('calls renderGFM after nextTick', async () => {
await nextTick();
expect(renderGFM).toHaveBeenCalledWith(wrapper.element);
});
});
describe('when loading content fails', () => {
beforeEach(() => {
mock.onGet(PATH).replyOnce(httpStatus.INTERNAL_SERVER_ERROR, '');
buildWrapper();
return waitForPromises();
});
it('renders error alert', () => {
expect(findGlAlert().exists()).toBe(true);
});
it('does not render skeleton loader or content container', () => {
expect(findContent().exists()).toBe(false);
expect(findGlSkeletonLoader().exists()).toBe(false);
});
});
});