Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-04-07 12:08:53 +00:00
parent dc7cd84a3e
commit 6d5f18a3c1
36 changed files with 372 additions and 175 deletions

View File

@ -726,9 +726,6 @@ RSpec/EmptyLineAfterFinalLetItBe:
- ee/spec/services/requirements_management/update_requirement_service_spec.rb
- ee/spec/services/resource_access_tokens/create_service_spec.rb
- ee/spec/services/resource_access_tokens/revoke_service_spec.rb
- ee/spec/services/search/global_service_spec.rb
- ee/spec/services/search/group_service_spec.rb
- ee/spec/services/search/project_service_spec.rb
- ee/spec/services/security/auto_fix_label_service_spec.rb
- ee/spec/services/security/store_grouped_scans_service_spec.rb
- ee/spec/services/security/store_report_service_spec.rb

View File

@ -1,7 +1,9 @@
<script>
import { GlEmptyState } from '@gitlab/ui';
import Experiment from '~/experimentation/components/experiment.vue';
import { helpPagePath } from '~/helpers/help_page_helper';
import { s__ } from '~/locale';
import PipelinesCiTemplates from './pipelines_ci_templates.vue';
export default {
i18n: {
@ -15,6 +17,8 @@ export default {
name: 'PipelinesEmptyState',
components: {
GlEmptyState,
Experiment,
PipelinesCiTemplates,
},
props: {
emptyStateSvgPath: {
@ -35,19 +39,26 @@ export default {
</script>
<template>
<div>
<gl-empty-state
v-if="canSetCi"
:title="$options.i18n.title"
:svg-path="emptyStateSvgPath"
:description="$options.i18n.description"
:primary-button-text="$options.i18n.btnText"
:primary-button-link="ciHelpPagePath"
/>
<gl-empty-state
v-else
title=""
:svg-path="emptyStateSvgPath"
:description="$options.i18n.noCiDescription"
/>
<experiment name="pipeline_empty_state_templates">
<template #control>
<gl-empty-state
v-if="canSetCi"
:title="$options.i18n.title"
:svg-path="emptyStateSvgPath"
:description="$options.i18n.description"
:primary-button-text="$options.i18n.btnText"
:primary-button-link="ciHelpPagePath"
/>
<gl-empty-state
v-else
title=""
:svg-path="emptyStateSvgPath"
:description="$options.i18n.noCiDescription"
/>
</template>
<template #candidate>
<pipelines-ci-templates />
</template>
</experiment>
</div>
</template>

View File

@ -0,0 +1,73 @@
<script>
import { GlButton } from '@gitlab/ui';
import { mergeUrlParams } from '~/lib/utils/url_utility';
import { s__, sprintf } from '~/locale';
import { SUGGESTED_CI_TEMPLATES } from '../../constants';
export default {
components: {
GlButton,
},
i18n: {
title: s__('Pipelines|Try a sample CI/CD file'),
subtitle: s__(
'Pipelines|Use a sample file to implement GitLab CI/CD based on your projects language/framework.',
),
cta: s__('Pipelines|Use template'),
description: s__(
'Pipelines|Continuous deployment template to test and deploy your %{name} project.',
),
errorMessage: s__('Pipelines|An error occurred. Please try again.'),
},
inject: ['addCiYmlPath'],
data() {
const templates = Object.keys(SUGGESTED_CI_TEMPLATES).map((key) => {
return {
name: key,
logoPath: SUGGESTED_CI_TEMPLATES[key].logoPath,
link: mergeUrlParams({ template: key }, this.addCiYmlPath),
description: sprintf(this.$options.i18n.description, { name: key }),
};
});
return {
templates,
};
},
};
</script>
<template>
<div>
<h2>{{ $options.i18n.title }}</h2>
<p>{{ $options.i18n.subtitle }}</p>
<ul class="gl-list-style-none gl-pl-0">
<li v-for="template in templates" :key="template.key">
<div
class="gl-display-flex gl-align-items-center gl-justify-content-space-between gl-border-b-solid gl-border-b-1 gl-border-b-gray-100 gl-pb-5 gl-pt-5"
>
<div class="gl-display-flex gl-flex-direction-row gl-align-items-center">
<img
width="64"
height="64"
:src="template.logoPath"
class="gl-mr-6"
data-testid="template-logo"
/>
<div class="gl-flex-direction-row">
<strong class="gl-text-gray-800">{{ template.name }}</strong>
<p class="gl-mb-0" data-testid="template-description">{{ template.description }}</p>
</div>
</div>
<gl-button
category="primary"
variant="confirm"
:href="template.link"
data-testid="template-link"
>{{ $options.i18n.cta }}</gl-button
>
</div>
</li>
</ul>
</div>
</template>

View File

@ -35,3 +35,40 @@ export const POST_FAILURE = 'post_failure';
export const UNSUPPORTED_DATA = 'unsupported_data';
export const CHILD_VIEW = 'child';
// The keys of the Object are the same as the `key` value in the template list we get from the API.
export const SUGGESTED_CI_TEMPLATES = {
Android: { logoPath: '/assets/illustrations/logos/android.svg' },
Bash: { logoPath: '/assets/illustrations/logos/bash.svg' },
'C++': { logoPath: '/assets/illustrations/logos/c_plus_plus.svg' },
Clojure: { logoPath: '/assets/illustrations/logos/clojure.svg' },
Composer: { logoPath: '/assets/illustrations/logos/composer.svg' },
Crystal: { logoPath: '/assets/illustrations/logos/crystal.svg' },
Dart: { logoPath: '/assets/illustrations/logos/dart.svg' },
Django: { logoPath: '/assets/illustrations/logos/django.svg' },
Docker: { logoPath: '/assets/illustrations/logos/docker.svg' },
Elixir: { logoPath: '/assets/illustrations/logos/elixir.svg' },
'iOS-Fastlane': { logoPath: '/assets/illustrations/logos/fastlane.svg' },
Flutter: { logoPath: '/assets/illustrations/logos/flutter.svg' },
Go: { logoPath: '/assets/illustrations/logos/go_logo.svg' },
Gradle: { logoPath: '/assets/illustrations/logos/gradle.svg' },
Grails: { logoPath: '/assets/illustrations/logos/grails.svg' },
dotNET: { logoPath: '/assets/illustrations/logos/dotnet.svg' },
Rails: { logoPath: '/assets/illustrations/logos/rails.svg' },
Julia: { logoPath: '/assets/illustrations/logos/julia.svg' },
Laravel: { logoPath: '/assets/illustrations/logos/laravel.svg' },
Latex: { logoPath: '/assets/illustrations/logos/latex.svg' },
Maven: { logoPath: '/assets/illustrations/logos/maven.svg' },
Mono: { logoPath: '/assets/illustrations/logos/mono.svg' },
Nodejs: { logoPath: '/assets/illustrations/logos/node_js.svg' },
npm: { logoPath: '/assets/illustrations/logos/npm.svg' },
OpenShift: { logoPath: '/assets/illustrations/logos/openshift.svg' },
Packer: { logoPath: '/assets/illustrations/logos/packer.svg' },
PHP: { logoPath: '/assets/illustrations/logos/php.svg' },
Python: { logoPath: '/assets/illustrations/logos/python.svg' },
Ruby: { logoPath: '/assets/illustrations/logos/ruby.svg' },
Rust: { logoPath: '/assets/illustrations/logos/rust.svg' },
Scala: { logoPath: '/assets/illustrations/logos/scala.svg' },
Swift: { logoPath: '/assets/illustrations/logos/swift.svg' },
Terraform: { logoPath: '/assets/illustrations/logos/terraform.svg' },
};

View File

@ -27,6 +27,7 @@ export const initPipelinesIndex = (selector = '#pipelines-list-vue') => {
errorStateSvgPath,
noPipelinesSvgPath,
newPipelinePath,
addCiYmlPath,
canCreatePipeline,
hasGitlabCi,
ciLintPath,
@ -37,6 +38,9 @@ export const initPipelinesIndex = (selector = '#pipelines-list-vue') => {
return new Vue({
el,
provide: {
addCiYmlPath,
},
data() {
return {
store: new PipelinesStore(),

View File

@ -46,7 +46,17 @@ class Projects::PipelinesController < Projects::ApplicationController
@pipelines_count = limited_pipelines_count(project)
respond_to do |format|
format.html
format.html do
experiment(:pipeline_empty_state_templates, actor: current_user) do |e|
e.exclude! unless current_user
e.exclude! if @pipelines_count.to_i > 0
e.exclude! if helpers.has_gitlab_ci?(project)
e.use {}
e.try {}
e.track(:view, value: project.namespace_id)
end
end
format.json do
Gitlab::PollingInterval.set_header(response, interval: POLLING_INTERVAL)

View File

@ -135,6 +135,10 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
ide_edit_path(project, default_branch_or_master, 'README.md')
end
def add_ci_yml_path
add_special_file_path(file_name: ci_config_path_or_default)
end
def license_short_name
license = repository.license
license&.nickname || license&.name || 'LICENSE'

View File

@ -32,7 +32,7 @@
.col-md-6
%h4= _('Restrict projects for this runner')
- if @runner.projects.any?
%table.table.assigned-projects
%table.table{ data: { testid: 'assigned-projects' } }
%thead
%tr
%th= _('Assigned projects')
@ -49,7 +49,7 @@
.gl-alert-actions
= link_to s_('Disable'), admin_namespace_project_runner_project_path(project.namespace, project, runner_project), method: :delete, class: 'btn gl-alert-action btn-info btn-md gl-button'
%table.table.unassigned-projects
%table.table{ data: { testid: 'unassigned-projects' } }
%thead
%tr
%th= _('Project')

View File

@ -14,5 +14,6 @@
"can-create-pipeline" => can?(current_user, :create_pipeline, @project).to_s,
"new-pipeline-path" => can?(current_user, :create_pipeline, @project) && new_project_pipeline_path(@project),
"ci-lint-path" => can?(current_user, :create_pipeline, @project) && project_ci_lint_path(@project),
"reset-cache-path" => can?(current_user, :admin_pipeline, @project) && reset_cache_project_settings_ci_cd_path(@project) ,
"has-gitlab-ci" => has_gitlab_ci?(@project).to_s } }
"reset-cache-path" => can?(current_user, :admin_pipeline, @project) && reset_cache_project_settings_ci_cd_path(@project),
"has-gitlab-ci" => has_gitlab_ci?(@project).to_s,
"add-ci-yml-path" => can?(current_user, :create_pipeline, @project) && @project.present(current_user: current_user).add_ci_yml_path } }

View File

@ -0,0 +1,8 @@
---
name: pipeline_empty_state_templates
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57286
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/326299
milestone: '13.11'
type: experiment
group: group::activation
default_enabled: false

View File

@ -17,3 +17,4 @@ tier:
- premium
- ultimate
skip_validation: true
name: "count_distinct_user_id_from_<adjective describing: '(clusters_applications_cert_managers.status IN (3, 5))'>_clusters_<with>_<adjective describing: '(clusters_applications_cert_managers.status IN (3, 5))'>_clusters_applications_cert_managers"

View File

@ -17,3 +17,4 @@ tier:
- premium
- ultimate
skip_validation: true
name: "count_distinct_user_id_from_<adjective describing: '(clusters_applications_helm.status IN (3, 5))'>_clusters_<with>_<adjective describing: '(clusters_applications_helm.status IN (3, 5))'>_clusters_applications_helm"

View File

@ -17,3 +17,4 @@ tier:
- premium
- ultimate
skip_validation: true
name: "count_distinct_user_id_from_<adjective describing: '(clusters_applications_ingress.status IN (3, 5))'>_clusters_<with>_<adjective describing: '(clusters_applications_ingress.status IN (3, 5))'>_clusters_applications_ingress"

View File

@ -17,3 +17,4 @@ tier:
- premium
- ultimate
skip_validation: true
name: "count_distinct_user_id_from_<adjective describing: '(clusters_applications_knative.status IN (3, 5))'>_clusters_<with>_<adjective describing: '(clusters_applications_knative.status IN (3, 5))'>_clusters_applications_knative"

View File

@ -17,3 +17,4 @@ tier:
- premium
- ultimate
skip_validation: true
name: "count_distinct_user_id_from_<adjective describing: '(clusters.management_project_id IS NOT NULL)'>_clusters"

View File

@ -17,3 +17,4 @@ tier:
- premium
- ultimate
skip_validation: true
name: "count_distinct_user_id_from_<adjective describing: '(clusters.enabled = FALSE)'>_clusters"

View File

@ -17,3 +17,4 @@ tier:
- premium
- ultimate
skip_validation: true
name: "count_distinct_user_id_from_<adjective describing: '(clusters.enabled = TRUE)'>_clusters"

View File

@ -17,3 +17,4 @@ tier:
- premium
- ultimate
skip_validation: true
name: "count_distinct_user_id_from_<adjective describing: '(clusters.provider_type = 1 AND (cluster_providers_gcp.status IN (3)) AND clusters.enabled = TRUE)'>_clusters_<with>_<adjective describing: '(clusters.provider_type = 1 AND (cluster_providers_gcp.status IN (3)) AND clusters.enabled = TRUE)'>_cluster_providers_gcp"

View File

@ -17,3 +17,4 @@ tier:
- premium
- ultimate
skip_validation: true
name: "count_distinct_user_id_from_<adjective describing: '(clusters.provider_type = 2 AND (cluster_providers_aws.status IN (3)) AND clusters.enabled = TRUE)'>_clusters_<with>_<adjective describing: '(clusters.provider_type = 2 AND (cluster_providers_aws.status IN (3)) AND clusters.enabled = TRUE)'>_cluster_providers_aws"

View File

@ -17,3 +17,4 @@ tier:
- premium
- ultimate
skip_validation: true
name: "count_distinct_user_id_from_<adjective describing: '(clusters.provider_type = 0 AND clusters.enabled = TRUE)'>_clusters"

View File

@ -17,3 +17,4 @@ tier:
- premium
- ultimate
skip_validation: true
name: "count_distinct_user_id_from_<adjective describing: '(clusters.enabled = FALSE AND clusters.cluster_type = 1)'>_clusters"

View File

@ -17,3 +17,4 @@ tier:
- premium
- ultimate
skip_validation: true
name: "count_distinct_user_id_from_<adjective describing: '(clusters.enabled = TRUE AND clusters.cluster_type = 1)'>_clusters"

View File

@ -17,3 +17,4 @@ tier:
- premium
- ultimate
skip_validation: true
name: "count_distinct_user_id_from_<adjective describing: '(clusters.enabled = FALSE AND clusters.cluster_type = 2)'>_clusters"

View File

@ -17,3 +17,4 @@ tier:
- premium
- ultimate
skip_validation: true
name: "count_distinct_user_id_from_<adjective describing: '(clusters.enabled = TRUE AND clusters.cluster_type = 2)'>_clusters"

View File

@ -17,3 +17,4 @@ tier:
- premium
- ultimate
skip_validation: true
name: "count_distinct_user_id_from_<adjective describing: '(clusters.enabled = FALSE AND clusters.cluster_type = 3)'>_clusters"

View File

@ -17,3 +17,4 @@ tier:
- premium
- ultimate
skip_validation: true
name: "count_distinct_user_id_from_<adjective describing: '(clusters.enabled = TRUE AND clusters.cluster_type = 3)'>_clusters"

View File

@ -167,8 +167,9 @@ do this manually.
In GitLab 12.8 and earlier, see [Message: `sudo: gitlab-pg-ctl: command not found`](../replication/troubleshooting.md#message-sudo-gitlab-pg-ctl-command-not-found).
1. Edit `/etc/gitlab/gitlab.rb` and remove any of the following lines that
might be present:
1. Edit `/etc/gitlab/gitlab.rb` on every node in the **secondary** site to
reflect its new status as **primary** by removing any of the following
lines that might be present:
```ruby
geo_secondary_role['enable'] = true

View File

@ -18,9 +18,9 @@ full list of reference architectures, see
| Service | Nodes | Configuration | GCP | AWS | Azure |
|--------------------------------------------|-------------|-------------------------|------------------|--------------|-----------|
| External load balancing node | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` |
| Consul | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` |
| PostgreSQL | 3 | 8 vCPU, 30 GB memory | `n1-standard-8` | `m5.2xlarge` | `D8s v3` |
| PgBouncer | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` |
| Consul* | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` |
| PostgreSQL* | 3 | 8 vCPU, 30 GB memory | `n1-standard-8` | `m5.2xlarge` | `D8s v3` |
| PgBouncer* | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` |
| Internal load balancing node | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` |
| Redis - Cache* | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` |
| Redis - Queues / Shared State* | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` |
@ -2367,9 +2367,10 @@ Kubernetes, you can reap certain cloud native workload management benefits while
the others are deployed in compute VMs with Omnibus as described above in this
page.
It should be noted though that this is an advanced setup as running services in
Kubernetes is well known to be complex. **This setup is only recommended** if
you have strong working knowledge and experience in Kubernetes. The rest of this
NOTE:
This is an **advanced** setup. Running services in Kubernetes is well known
to be complex. **This setup is only recommended** if you have strong working
knowledge and experience in Kubernetes. The rest of this
section will assume this.
### Cluster topology
@ -2393,9 +2394,9 @@ services where applicable):
| Service | Nodes | Configuration | GCP |
|--------------------------------------------|-------|-------------------------|------------------|
| Consul | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` |
| Consul* | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` |
| PostgreSQL* | 3 | 8 vCPU, 30 GB memory | `n1-standard-8` |
| PgBouncer | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` |
| PgBouncer* | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` |
| Internal load balancing node | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` |
| Redis - Cache* | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` |
| Redis - Queues / Shared State* | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` |

View File

@ -30,11 +30,9 @@ below.
## How to enter data
Time Tracking uses two [quick actions](quick_actions.md)
that GitLab introduced with this new feature: `/spend` and `/estimate`.
Time Tracking uses two [quick actions](quick_actions.md): `/spend` and `/estimate`.
Quick actions can be used in the body of an issue or a merge request, but also
in a comment in both an issue or a merge request.
If you use either quick action more than once in a single comment, only the last occurrence is applied.
Below is an example of how you can use those new quick actions inside a comment.

View File

@ -22787,6 +22787,9 @@ msgstr ""
msgid "Pipelines|API"
msgstr ""
msgid "Pipelines|An error occurred. Please try again."
msgstr ""
msgid "Pipelines|Are you sure you want to run this pipeline?"
msgstr ""
@ -22805,6 +22808,9 @@ msgstr ""
msgid "Pipelines|Clear Runner Caches"
msgstr ""
msgid "Pipelines|Continuous deployment template to test and deploy your %{name} project."
msgstr ""
msgid "Pipelines|Copy trigger token"
msgstr ""
@ -22916,6 +22922,15 @@ msgstr ""
msgid "Pipelines|Trigger user has insufficient permissions to project"
msgstr ""
msgid "Pipelines|Try a sample CI/CD file"
msgstr ""
msgid "Pipelines|Use a sample file to implement GitLab CI/CD based on your projects language/framework."
msgstr ""
msgid "Pipelines|Use template"
msgstr ""
msgid "Pipelines|Validating GitLab CI configuration…"
msgstr ""

View File

@ -49,7 +49,7 @@
"@babel/preset-env": "^7.10.1",
"@gitlab/at.js": "1.5.7",
"@gitlab/favicon-overlay": "2.0.0",
"@gitlab/svgs": "1.185.0",
"@gitlab/svgs": "1.188.0",
"@gitlab/tributejs": "1.0.0",
"@gitlab/ui": "29.1.0",
"@gitlab/visual-review-tools": "1.6.1",

View File

@ -273,6 +273,23 @@ RSpec.describe Projects::PipelinesController do
end
end
describe 'GET #index' do
context 'pipeline_empty_state_templates experiment' do
before do
stub_application_setting(auto_devops_enabled: false)
end
it 'tracks the view', :experiment do
expect(experiment(:pipeline_empty_state_templates))
.to track(:view, value: project.namespace_id)
.with_context(actor: user)
.on_next_instance
get :index, params: { namespace_id: project.namespace, project_id: project }
end
end
end
describe 'GET show.json' do
let(:pipeline) { create(:ci_pipeline, project: project) }

View File

@ -321,11 +321,11 @@ RSpec.describe "Admin Runners" do
describe 'enable/create' do
shared_examples 'assignable runner' do
it 'enables a runner for a project' do
within '.unassigned-projects' do
within '[data-testid="unassigned-projects"]' do
click_on 'Enable'
end
assigned_project = page.find('.assigned-projects')
assigned_project = page.find('[data-testid="assigned-projects"]')
expect(assigned_project).to have_content(@project2.path)
end
@ -371,11 +371,11 @@ RSpec.describe "Admin Runners" do
end
it 'enables specific runner for project' do
within '.assigned-projects' do
within '[data-testid="assigned-projects"]' do
click_on 'Disable'
end
new_runner_project = page.find('.unassigned-projects')
new_runner_project = page.find('[data-testid="unassigned-projects"]')
expect(new_runner_project).to have_content(@project1.path)
end

View File

@ -3,8 +3,6 @@
require 'spec_helper'
RSpec.describe 'GFM autocomplete', :js do
let_it_be(:user_xss_title) { 'eve <img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;' }
let_it_be(:user_xss) { create(:user, name: user_xss_title, username: 'xss.user') }
let_it_be(:user) { create(:user, name: '💃speciąl someone💃', username: 'someone.special') }
let_it_be(:user2) { create(:user, name: 'Marge Simpson', username: 'msimpson') }
@ -14,8 +12,15 @@ RSpec.describe 'GFM autocomplete', :js do
let_it_be(:issue) { create(:issue, project: project, assignees: [user]) }
let_it_be(:label) { create(:label, project: project, title: 'special+') }
let_it_be(:label_scoped) { create(:label, project: project, title: 'scoped::label') }
let_it_be(:label_with_spaces) { create(:label, project: project, title: 'Accepting merge requests') }
let_it_be(:snippet) { create(:project_snippet, project: project, title: 'code snippet') }
let_it_be(:user_xss_title) { 'eve <img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;' }
let_it_be(:user_xss) { create(:user, name: user_xss_title, username: 'xss.user') }
let_it_be(:label_xss_title) { 'alert label &lt;img src=x onerror="alert(\'Hello xss\');" a' }
let_it_be(:label_xss) { create(:label, project: project, title: label_xss_title) }
before_all do
project.add_maintainer(user)
project.add_maintainer(user_xss)
@ -117,34 +122,44 @@ RSpec.describe 'GFM autocomplete', :js do
end
end
it 'opens autocomplete menu for Issues when field starts with text with item escaping HTML characters' do
issue_xss_title = 'This will execute alert<img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;'
create(:issue, project: project, title: issue_xss_title)
context 'xss checks' do
it 'opens autocomplete menu for Issues when field starts with text with item escaping HTML characters' do
issue_xss_title = 'This will execute alert<img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;'
create(:issue, project: project, title: issue_xss_title)
fill_in 'Comment', with: '#'
fill_in 'Comment', with: '#'
wait_for_requests
wait_for_requests
expect(find_autocomplete_menu).to have_text(issue_xss_title)
end
expect(find_autocomplete_menu).to have_text(issue_xss_title)
end
it 'opens autocomplete menu for Username when field starts with text with item escaping HTML characters' do
fill_in 'Comment', with: '@ev'
it 'opens autocomplete menu for Username when field starts with text with item escaping HTML characters' do
fill_in 'Comment', with: '@ev'
wait_for_requests
wait_for_requests
expect(find_highlighted_autocomplete_item).to have_text(user_xss.username)
end
expect(find_highlighted_autocomplete_item).to have_text(user_xss.username)
end
it 'opens autocomplete menu for Milestone when field starts with text with item escaping HTML characters' do
milestone_xss_title = 'alert milestone &lt;img src=x onerror="alert(\'Hello xss\');" a'
create(:milestone, project: project, title: milestone_xss_title)
it 'opens autocomplete menu for Milestone when field starts with text with item escaping HTML characters' do
milestone_xss_title = 'alert milestone &lt;img src=x onerror="alert(\'Hello xss\');" a'
create(:milestone, project: project, title: milestone_xss_title)
fill_in 'Comment', with: '%'
fill_in 'Comment', with: '%'
wait_for_requests
wait_for_requests
expect(find_autocomplete_menu).to have_text('alert milestone')
expect(find_autocomplete_menu).to have_text('alert milestone')
end
it 'opens autocomplete menu for Labels when field starts with text with item escaping HTML characters' do
fill_in 'Comment', with: '~'
wait_for_requests
expect(find_autocomplete_menu).to have_text('alert label')
end
end
describe 'autocomplete highlighting' do
@ -232,7 +247,7 @@ RSpec.describe 'GFM autocomplete', :js do
context 'if a selected value has special characters' do
it 'wraps the result in double quotes' do
fill_in 'Comment', with: "~#{label.title[0]}"
fill_in 'Comment', with: "~#{label.title[0..2]}"
find_highlighted_autocomplete_item.click
@ -246,15 +261,9 @@ RSpec.describe 'GFM autocomplete', :js do
expect(find_field('Comment').value).to have_text('cartwheel_tone1')
end
end
it 'triggers autocomplete after selecting a quick action' do
fill_in 'Comment', with: '/as'
find_highlighted_autocomplete_item.click
expect(find_autocomplete_menu).to have_text(user2.username)
end
context 'quick actions' do
it 'does not limit quick actions autocomplete list to 5' do
fill_in 'Comment', with: '/'
@ -263,40 +272,15 @@ RSpec.describe 'GFM autocomplete', :js do
end
context 'labels' do
it 'opens autocomplete menu for Labels when field starts with text with item escaping HTML characters' do
label_xss_title = 'alert label &lt;img src=x onerror="alert(\'Hello xss\');" a'
create(:label, project: project, title: label_xss_title)
fill_in 'Comment', with: '~'
wait_for_requests
expect(find_autocomplete_menu).to have_text('alert label')
end
it 'allows colons when autocompleting scoped labels' do
create(:label, project: project, title: 'scoped:label')
fill_in 'Comment', with: '~scoped:'
wait_for_requests
expect(find_autocomplete_menu).to have_text('scoped:label')
end
it 'allows colons when autocompleting scoped labels with double colons' do
create(:label, project: project, title: 'scoped::label')
fill_in 'Comment', with: '~scoped::'
wait_for_requests
expect(find_autocomplete_menu).to have_text('scoped::label')
end
it 'allows spaces when autocompleting multi-word labels' do
create(:label, project: project, title: 'Accepting merge requests')
fill_in 'Comment', with: '~Accepting merge'
wait_for_requests
@ -304,20 +288,15 @@ RSpec.describe 'GFM autocomplete', :js do
expect(find_autocomplete_menu).to have_text('Accepting merge requests')
end
it 'only autocompletes the latest label' do
create(:label, project: project, title: 'Accepting merge requests')
create(:label, project: project, title: 'Accepting job applicants')
fill_in 'Comment', with: '~Accepting merge requests foo bar ~Accepting job'
it 'only autocompletes the last label' do
fill_in 'Comment', with: '~scoped:: foo bar ~Accepting merge'
wait_for_requests
expect(find_autocomplete_menu).to have_text('Accepting job applicants')
expect(find_autocomplete_menu).to have_text('Accepting merge requests')
end
it 'does not autocomplete labels if no tilde is typed' do
create(:label, project: project, title: 'Accepting merge requests')
fill_in 'Comment', with: 'Accepting merge'
wait_for_requests
@ -376,13 +355,6 @@ RSpec.describe 'GFM autocomplete', :js do
it_behaves_like 'autocomplete suggestions'
end
context 'label' do
let!(:object) { label }
let(:expected_body) { object.title }
it_behaves_like 'autocomplete suggestions'
end
context 'milestone' do
let_it_be(:milestone_expired) { create(:milestone, project: project, due_date: 5.days.ago) }
let_it_be(:milestone_no_duedate) { create(:milestone, project: project, title: 'Foo - No due date') }
@ -486,34 +458,44 @@ RSpec.describe 'GFM autocomplete', :js do
end
end
it 'opens autocomplete menu for Issues when field starts with text with item escaping HTML characters' do
issue_xss_title = 'This will execute alert<img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;'
create(:issue, project: project, title: issue_xss_title)
context 'xss checks' do
it 'opens autocomplete menu for Issues when field starts with text with item escaping HTML characters' do
issue_xss_title = 'This will execute alert<img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;'
create(:issue, project: project, title: issue_xss_title)
fill_in 'Comment', with: '#'
fill_in 'Comment', with: '#'
wait_for_requests
wait_for_requests
expect(find_tribute_autocomplete_menu).to have_text(issue_xss_title)
end
expect(find_tribute_autocomplete_menu).to have_text(issue_xss_title)
end
it 'opens autocomplete menu for Username when field starts with text with item escaping HTML characters' do
fill_in 'Comment', with: '@ev'
it 'opens autocomplete menu for Username when field starts with text with item escaping HTML characters' do
fill_in 'Comment', with: '@ev'
wait_for_requests
wait_for_requests
expect(find_tribute_autocomplete_menu).to have_text(user_xss.username)
end
expect(find_tribute_autocomplete_menu).to have_text(user_xss.username)
end
it 'opens autocomplete menu for Milestone when field starts with text with item escaping HTML characters' do
milestone_xss_title = 'alert milestone &lt;img src=x onerror="alert(\'Hello xss\');" a'
create(:milestone, project: project, title: milestone_xss_title)
it 'opens autocomplete menu for Milestone when field starts with text with item escaping HTML characters' do
milestone_xss_title = 'alert milestone &lt;img src=x onerror="alert(\'Hello xss\');" a'
create(:milestone, project: project, title: milestone_xss_title)
fill_in 'Comment', with: '%'
fill_in 'Comment', with: '%'
wait_for_requests
wait_for_requests
expect(find_tribute_autocomplete_menu).to have_text('alert milestone')
expect(find_tribute_autocomplete_menu).to have_text('alert milestone')
end
it 'opens autocomplete menu for Labels when field starts with text with item escaping HTML characters' do
fill_in 'Comment', with: '~'
wait_for_requests
expect(find_tribute_autocomplete_menu).to have_text('alert label')
end
end
describe 'autocomplete highlighting' do
@ -592,7 +574,7 @@ RSpec.describe 'GFM autocomplete', :js do
context 'if a selected value has special characters' do
it 'wraps the result in double quotes' do
fill_in 'Comment', with: "~#{label.title[0]}"
fill_in 'Comment', with: "~#{label.title[0..2]}"
find_highlighted_tribute_autocomplete_menu.click
@ -606,7 +588,9 @@ RSpec.describe 'GFM autocomplete', :js do
expect(find_field('Comment').value).to have_text('cartwheel_tone1')
end
end
context 'quick actions' do
it 'autocompletes for quick actions' do
fill_in 'Comment', with: '/as'
@ -617,40 +601,15 @@ RSpec.describe 'GFM autocomplete', :js do
end
context 'labels' do
it 'opens autocomplete menu for Labels when field starts with text with item escaping HTML characters' do
label_xss_title = 'alert label &lt;img src=x onerror="alert(\'Hello xss\');" a'
create(:label, project: project, title: label_xss_title)
fill_in 'Comment', with: '~'
wait_for_requests
expect(find_tribute_autocomplete_menu).to have_text('alert label')
end
it 'allows colons when autocompleting scoped labels' do
create(:label, project: project, title: 'scoped:label')
fill_in 'Comment', with: '~scoped:'
wait_for_requests
expect(find_tribute_autocomplete_menu).to have_text('scoped:label')
end
it 'allows colons when autocompleting scoped labels with double colons' do
create(:label, project: project, title: 'scoped::label')
fill_in 'Comment', with: '~scoped::'
wait_for_requests
expect(find_tribute_autocomplete_menu).to have_text('scoped::label')
end
it 'autocompletes multi-word labels' do
create(:label, project: project, title: 'Accepting merge requests')
fill_in 'Comment', with: '~Acceptingmerge'
wait_for_requests
@ -658,24 +617,18 @@ RSpec.describe 'GFM autocomplete', :js do
expect(find_tribute_autocomplete_menu).to have_text('Accepting merge requests')
end
it 'only autocompletes the latest label' do
create(:label, project: project, title: 'documentation')
create(:label, project: project, title: 'feature')
fill_in 'Comment', with: '~documentation foo bar ~feat'
it 'only autocompletes the last label' do
fill_in 'Comment', with: '~scoped:: foo bar ~Acceptingmerge'
# Invoke autocompletion
find_field('Comment').native.send_keys(:right)
wait_for_requests
expect(find_tribute_autocomplete_menu).to have_text('feature')
expect(find_tribute_autocomplete_menu).not_to have_text('documentation')
expect(find_tribute_autocomplete_menu).to have_text('Accepting merge requests')
end
it 'does not autocomplete labels if no tilde is typed' do
create(:label, project: project, title: 'documentation')
fill_in 'Comment', with: 'document'
fill_in 'Comment', with: 'Accepting'
wait_for_requests
@ -733,13 +686,6 @@ RSpec.describe 'GFM autocomplete', :js do
it_behaves_like 'autocomplete suggestions'
end
context 'label' do
let!(:object) { label }
let(:expected_body) { object.title }
it_behaves_like 'autocomplete suggestions'
end
context 'milestone' do
let!(:object) { create(:milestone, project: project) }
let(:expected_body) { object.to_reference }

View File

@ -0,0 +1,58 @@
import { shallowMount } from '@vue/test-utils';
import PipelinesCiTemplate from '~/pipelines/components/pipelines_list/pipelines_ci_templates.vue';
import { SUGGESTED_CI_TEMPLATES } from '~/pipelines/constants';
const addCiYmlPath = "/-/new/master?commit_message='Add%20.gitlab-ci.yml'";
describe('Pipelines CI Templates', () => {
let wrapper;
const createWrapper = () => {
return shallowMount(PipelinesCiTemplate, {
provide: {
addCiYmlPath,
},
});
};
const findTemplateDescriptions = () => wrapper.findAll('[data-testid="template-description"]');
const findTemplateLinks = () => wrapper.findAll('[data-testid="template-link"]');
const findTemplateLogos = () => wrapper.findAll('[data-testid="template-logo"]');
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
describe('renders templates', () => {
beforeEach(() => {
wrapper = createWrapper();
});
it('renders all suggested templates', () => {
const content = wrapper.text();
const keys = Object.keys(SUGGESTED_CI_TEMPLATES);
expect(content).toContain(...keys);
});
it('links to the correct template', () => {
expect(findTemplateLinks().at(0).attributes('href')).toEqual(
addCiYmlPath.concat('&template=Android'),
);
});
it('has the description of the template', () => {
expect(findTemplateDescriptions().at(0).text()).toEqual(
'Continuous deployment template to test and deploy your Android project.',
);
});
it('has the right logo of the template', () => {
expect(findTemplateLogos().at(0).attributes('src')).toEqual(
'/assets/illustrations/logos/android.svg',
);
});
});
});

View File

@ -897,10 +897,10 @@
stylelint-declaration-strict-value "1.7.7"
stylelint-scss "3.18.0"
"@gitlab/svgs@1.185.0":
version "1.185.0"
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.185.0.tgz#15b5c6d680b5fcfc2deb2a5decef427939e34ed7"
integrity sha512-1XIyOm8MyTZi8H0v9WVnqVDziTLH8Q5H/fKfBj+nzprHNYvJj2fvz+EV9N5luF90KTzlQf1QYCbHWe2zKLZuUw==
"@gitlab/svgs@1.188.0":
version "1.188.0"
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.188.0.tgz#b98e279663776cf2c7bebaacc19eaab78362ccd8"
integrity sha512-7skRsKn3jzUpXwz0wOvQgVXZ2n1f7iZ5KURyUSWHe3gLMVWAPJmGBHHtdNSIq9hhsdVFPcwYBaKm26KvnkZr5A==
"@gitlab/tributejs@1.0.0":
version "1.0.0"