Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
dc7cd84a3e
commit
6d5f18a3c1
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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 project’s 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>
|
||||
|
|
@ -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' },
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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 } }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -17,3 +17,4 @@ tier:
|
|||
- premium
|
||||
- ultimate
|
||||
skip_validation: true
|
||||
name: "count_distinct_user_id_from_<adjective describing: '(clusters.enabled = FALSE)'>_clusters"
|
||||
|
|
|
|||
|
|
@ -17,3 +17,4 @@ tier:
|
|||
- premium
|
||||
- ultimate
|
||||
skip_validation: true
|
||||
name: "count_distinct_user_id_from_<adjective describing: '(clusters.enabled = TRUE)'>_clusters"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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` |
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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 project’s language/framework."
|
||||
msgstr ""
|
||||
|
||||
msgid "Pipelines|Use template"
|
||||
msgstr ""
|
||||
|
||||
msgid "Pipelines|Validating GitLab CI configuration…"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)<img src=x onerror=alert(1)>' }
|
||||
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)<img src=x onerror=alert(1)>' }
|
||||
let_it_be(:user_xss) { create(:user, name: user_xss_title, username: 'xss.user') }
|
||||
let_it_be(:label_xss_title) { 'alert label <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)<img src=x onerror=alert(1)>'
|
||||
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)<img src=x onerror=alert(1)>'
|
||||
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 <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 <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 <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)<img src=x onerror=alert(1)>'
|
||||
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)<img src=x onerror=alert(1)>'
|
||||
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 <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 <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 <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 }
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Reference in New Issue