...@@ -9,6 +9,7 @@ import GitignoreSelector from './template_selectors/gitignore_selector'; ...@@ -9,6 +9,7 @@ import GitignoreSelector from './template_selectors/gitignore_selector';
import LicenseSelector from './template_selectors/license_selector'; import LicenseSelector from './template_selectors/license_selector';
import toast from '~/vue_shared/plugins/global_toast'; import toast from '~/vue_shared/plugins/global_toast';
import { __ } from '~/locale'; import { __ } from '~/locale';
import initPopover from '~/blob/suggest_gitlab_ci_yml';
export default class FileTemplateMediator { export default class FileTemplateMediator {
constructor({ editor, currentAction, projectId }) { constructor({ editor, currentAction, projectId }) {
...@@ -128,6 +129,7 @@ export default class FileTemplateMediator { ...@@ -128,6 +129,7 @@ export default class FileTemplateMediator {
selectTemplateFile(selector, query, data) { selectTemplateFile(selector, query, data) {
const self = this; const self = this;
const { name } = selector.config; const { name } = selector.config;
const suggestCommitChanges = document.querySelector('.js-suggest-gitlab-ci-yml-commit-changes');
selector.renderLoading(); selector.renderLoading();
...@@ -146,6 +148,10 @@ export default class FileTemplateMediator { ...@@ -146,6 +148,10 @@ export default class FileTemplateMediator {
}, },
}, },
}); });
if (suggestCommitChanges) {
initPopover(suggestCommitChanges);
}
}) })
.catch(err => new Flash(`An error occurred while fetching the template: ${err}`)); .catch(err => new Flash(`An error occurred while fetching the template: ${err}`));
} }
... ...
......
<script> <script>
import { GlPopover, GlSprintf, GlButton, GlIcon } from '@gitlab/ui'; import { GlPopover, GlSprintf, GlButton, GlIcon } from '@gitlab/ui';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import { parseBoolean } from '~/lib/utils/common_utils'; import { parseBoolean, scrollToElement } from '~/lib/utils/common_utils';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import { glEmojiTag } from '~/emoji'; import { glEmojiTag } from '~/emoji';
const popoverStates = {
suggest_gitlab_ci_yml: {
title: s__(`suggestPipeline|1/2: Choose a template`),
content: s__(
`suggestPipeline|We recommend the %{boldStart}Code Quality%{boldEnd} template, which will add a report widget to your Merge Requests. This way you’ll learn about code quality degradations much sooner. %{footerStart} Goodbye technical debt! %{footerEnd}`,
),
emoji: glEmojiTag('wave'),
},
suggest_commit_first_project_gitlab_ci_yml: {
title: s__(`suggestPipeline|2/2: Commit your changes`),
content: s__(
`suggestPipeline|Commit the changes and your pipeline will automatically run for the first time.`,
),
},
};
export default { export default {
components: { components: {
GlPopover, GlPopover,
...@@ -17,7 +32,7 @@ export default { ...@@ -17,7 +32,7 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
cssClass: { trackLabel: {
type: String, type: String,
required: true, required: true,
}, },
...@@ -33,16 +48,18 @@ export default { ...@@ -33,16 +48,18 @@ export default {
}, },
computed: { computed: {
suggestTitle() { suggestTitle() {
return s__(`suggestPipeline|1/2: Choose a template`); return popoverStates[this.trackLabel].title || '';
}, },
suggestContent() { suggestContent() {
return s__( return popoverStates[this.trackLabel].content || '';
`suggestPipeline|We recommend the %{boldStart}Code Quality%{boldEnd} template, which will add a report widget to your Merge Requests. This way you’ll learn about code quality degradations much sooner. %{footerStart} Goodbye technical debt! %{footerEnd}`,
);
}, },
emoji() { emoji() {
return glEmojiTag('wave'); return popoverStates[this.trackLabel].emoji || '';
},
}, },
mounted() {
if (this.trackLabel === 'suggest_commit_first_project_gitlab_ci_yml' && !this.popoverDismissed)
scrollToElement(document.querySelector(this.target));
}, },
methods: { methods: {
onDismiss() { onDismiss() {
...@@ -61,13 +78,15 @@ export default { ...@@ -61,13 +78,15 @@ export default {
placement="rightbottom" placement="rightbottom"
trigger="manual" trigger="manual"
container="viewport" container="viewport"
:css-classes="[cssClass]" :css-classes="['suggest-gitlab-ci-yml', 'ml-4']"
> >
<template #title> <template #title>
<gl-button :aria-label="__('Close')" class="btn-blank float-right" @click="onDismiss"> <span v-html="suggestTitle"></span>
<span class="ml-auto">
<gl-button :aria-label="__('Close')" class="btn-blank" @click="onDismiss">
<gl-icon name="close" aria-hidden="true" /> <gl-icon name="close" aria-hidden="true" />
</gl-button> </gl-button>
{{ suggestTitle }} </span>
</template> </template>
<gl-sprintf :message="suggestContent"> <gl-sprintf :message="suggestContent">
... ...
......
...@@ -8,7 +8,7 @@ export default el => ...@@ -8,7 +8,7 @@ export default el =>
return createElement(Popover, { return createElement(Popover, {
props: { props: {
target: el.dataset.target, target: el.dataset.target,
cssClass: el.dataset.cssClass, trackLabel: el.dataset.trackLabel,
dismissKey: el.dataset.dismissKey, dismissKey: el.dataset.dismissKey,
}, },
}); });
... ...
......
...@@ -4,11 +4,13 @@ import $ from 'jquery'; ...@@ -4,11 +4,13 @@ import $ from 'jquery';
import NewCommitForm from '../new_commit_form'; import NewCommitForm from '../new_commit_form';
import EditBlob from './edit_blob'; import EditBlob from './edit_blob';
import BlobFileDropzone from '../blob/blob_file_dropzone'; import BlobFileDropzone from '../blob/blob_file_dropzone';
import initPopover from '~/blob/suggest_gitlab_ci_yml';
export default () => { export default () => {
const editBlobForm = $('.js-edit-blob-form'); const editBlobForm = $('.js-edit-blob-form');
const uploadBlobForm = $('.js-upload-blob-form'); const uploadBlobForm = $('.js-upload-blob-form');
const deleteBlobForm = $('.js-delete-blob-form'); const deleteBlobForm = $('.js-delete-blob-form');
const suggestEl = document.querySelector('.js-suggest-gitlab-ci-yml');
if (editBlobForm.length) { if (editBlobForm.length) {
const urlRoot = editBlobForm.data('relativeUrlRoot'); const urlRoot = editBlobForm.data('relativeUrlRoot');
...@@ -56,4 +58,8 @@ export default () => { ...@@ -56,4 +58,8 @@ export default () => {
if (deleteBlobForm.length) { if (deleteBlobForm.length) {
new NewCommitForm(deleteBlobForm); new NewCommitForm(deleteBlobForm);
} }
if (suggestEl) {
initPopover(suggestEl);
}
}; };
...@@ -95,7 +95,7 @@ export default { ...@@ -95,7 +95,7 @@ export default {
<li :id="groupDomId" :class="rowClass" class="group-row" @click.stop="onClickRowGroup"> <li :id="groupDomId" :class="rowClass" class="group-row" @click.stop="onClickRowGroup">
<div <div
:class="{ 'project-row-contents': !isGroup }" :class="{ 'project-row-contents': !isGroup }"
class="group-row-contents d-flex align-items-center py-2" class="group-row-contents d-flex align-items-center py-2 pr-3"
> >
<div class="folder-toggle-wrap append-right-4 d-flex align-items-center"> <div class="folder-toggle-wrap append-right-4 d-flex align-items-center">
<item-caret :is-group-open="group.isOpen" /> <item-caret :is-group-open="group.isOpen" />
...@@ -103,8 +103,8 @@ export default { ...@@ -103,8 +103,8 @@ export default {
</div> </div>
<gl-loading-icon <gl-loading-icon
v-if="group.isChildrenLoading" v-if="group.isChildrenLoading"
size="md" size="lg"
class="d-none d-sm-inline-flex flex-shrink-0 append-right-10" class="d-none d-sm-inline-flex flex-shrink-0 append-right-8"
/> />
<div <div
:class="{ 'd-sm-flex': !group.isChildrenLoading }" :class="{ 'd-sm-flex': !group.isChildrenLoading }"
... ...
......
...@@ -68,7 +68,7 @@ export default { ...@@ -68,7 +68,7 @@ export default {
data-placement="bottom" data-placement="bottom"
class="edit-group btn btn-xs no-expand" class="edit-group btn btn-xs no-expand"
> >
<icon name="settings" class="position-top-0" /> <icon name="settings" class="position-top-0 align-middle" />
</a> </a>
</div> </div>
</template> </template>
...@@ -144,9 +144,7 @@ ...@@ -144,9 +144,7 @@
.popover-header { .popover-header {
padding: $gl-padding; padding: $gl-padding;
display: flex;
.ic-close { align-items: center;
margin-top: -1em;
}
} }
} }
...@@ -50,7 +50,7 @@ module Clusters ...@@ -50,7 +50,7 @@ module Clusters
end end
def helm_api def helm_api
@helm_api ||= Gitlab::Kubernetes::Helm::Api.new(kubeclient) @helm_api ||= Gitlab::Kubernetes::Helm::API.new(kubeclient)
end end
def install_command def install_command
... ...
......
.form-actions .form-actions
= button_tag 'Commit changes', class: 'btn commit-btn js-commit-button btn-success qa-commit-button' = button_tag 'Commit changes', id: 'commit-changes', class: 'btn commit-btn js-commit-button btn-success qa-commit-button'
= link_to 'Cancel', cancel_path, = link_to 'Cancel', cancel_path,
class: 'btn btn-cancel', data: {confirm: leave_edit_message} class: 'btn btn-cancel', data: {confirm: leave_edit_message}
... ...
......
...@@ -20,7 +20,10 @@ ...@@ -20,7 +20,10 @@
required: true, class: 'form-control new-file-name js-file-path-name-input', value: params[:file_name] || (should_suggest_gitlab_ci_yml? ? '.gitlab-ci.yml' : '') required: true, class: 'form-control new-file-name js-file-path-name-input', value: params[:file_name] || (should_suggest_gitlab_ci_yml? ? '.gitlab-ci.yml' : '')
= render 'template_selectors' = render 'template_selectors'
- if should_suggest_gitlab_ci_yml? - if should_suggest_gitlab_ci_yml?
= render partial: 'suggest_gitlab_ci_yml', locals: { target: '#gitlab-ci-yml-selector', dismiss_key: "suggest_gitlab_ci_yml_#{@project.id}" } .js-suggest-gitlab-ci-yml{ data: { toggle: 'popover',
target: '#gitlab-ci-yml-selector',
track_label: 'suggest_gitlab_ci_yml',
dismiss_key: "suggest_gitlab_ci_yml_#{@project.id}" } }
.file-buttons .file-buttons
- if is_markdown - if is_markdown
... ...
......
.js-suggest-gitlab-ci-yml{ data: { toggle: 'popover',
target: target,
css_class: 'suggest-gitlab-ci-yml ml-4',
dismiss_key: dismiss_key } }
...@@ -13,3 +13,8 @@ ...@@ -13,3 +13,8 @@
= hidden_field_tag 'content', '', id: 'file-content' = hidden_field_tag 'content', '', id: 'file-content'
= render 'projects/commit_button', ref: @ref, = render 'projects/commit_button', ref: @ref,
cancel_path: project_tree_path(@project, @id) cancel_path: project_tree_path(@project, @id)
- if should_suggest_gitlab_ci_yml?
.js-suggest-gitlab-ci-yml-commit-changes{ data: { toggle: 'popover',
target: '#commit-changes',
track_label: 'suggest_commit_first_project_gitlab_ci_yml',
dismiss_key: "suggest_commit_first_project_gitlab_ci_yml_#{@project.id}" } }
---
title: Added a padding-right to items in subgroup list
merge_request: 26791
author:
type: fixed
# frozen_string_literal: true
class AddIndexServicesOnTemplate < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
# This migration is a corrective action to add the missing
# index_services_on_template index on staging.
def up
add_concurrent_index(:services, :template) unless index_exists?(:services, :template)
end
def down
# No reverse action as this is a corrective migration.
end
end
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2020_03_06_170531) do ActiveRecord::Schema.define(version: 2020_03_09_105539) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "pg_trgm" enable_extension "pg_trgm"
... ...
......
...@@ -92,6 +92,7 @@ and are as follows: ...@@ -92,6 +92,7 @@ and are as follows:
1. For tags, create a pipeline. 1. For tags, create a pipeline.
1. If `$GITLAB_INTERNAL` isn't set, don't create a pipeline. 1. If `$GITLAB_INTERNAL` isn't set, don't create a pipeline.
1. For stable, auto-deploy, and security branches, create a pipeline. 1. For stable, auto-deploy, and security branches, create a pipeline.
1. For any other cases (e.g. when pushing a branch with no MR for it), no pipeline is created.
## `rules`, `if:` conditions and `changes:` patterns ## `rules`, `if:` conditions and `changes:` patterns
... ...
......
...@@ -183,6 +183,7 @@ Continued reading: ...@@ -183,6 +183,7 @@ Continued reading:
- [Best Practices](best_practices.md) - [Best Practices](best_practices.md)
- [Testing with feature flags](feature_flags.md) - [Testing with feature flags](feature_flags.md)
- [Flows](flows.md) - [Flows](flows.md)
- [RSpec metadata/tags](rspec_metadata_tests.md)
## Where can I ask for help? ## Where can I ask for help?
... ...
......
# RSpec metadata for end-to-end tests
This is a partial list of the [RSpec metadata](https://relishapp.com/rspec/rspec-core/docs/metadata/user-defined-metadata)
(a.k.a. tags) that are used in our end-to-end tests.
<!-- Please keep the tags in alphabetical order -->
| Tag | Description |
|-|-|
| `:elasticsearch` | The test requires an Elasticsearch service. It is used by the [instance-level scenario](https://gitlab.com/gitlab-org/gitlab-qa#definitions) [`Test::Integration::Elasticsearch`](https://gitlab.com/gitlab-org/gitlab/-/blob/72b62b51bdf513e2936301cb6c7c91ec27c35b4d/qa/qa/ee/scenario/test/integration/elasticsearch.rb) to include only tests that require Elasticsearch. |
| `:orchestrated` | The GitLab instance under test may be [configured by `gitlab-qa`](https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/docs/what_tests_can_be_run.md#orchestrated-tests) to be different to the default GitLab configuration, or `gitlab-qa` may launch additional services in separate docker containers, or both. Tests tagged with `:orchestrated` are excluded when testing environments where we can't dynamically modify GitLab's configuration (for example, Staging). |
| `:quarantine` | The test has been [quarantined](https://about.gitlab.com/handbook/engineering/quality/guidelines/debugging-qa-test-failures/#quarantining-tests), will run in a separate job that only includes quarantined tests, and is allowed to fail. The test will be skipped in its regular job so that if it fails it will not hold up the pipeline. |
| `:requires_admin` | The test requires an admin account. Tests with the tag are excluded when run against Canary and Production environments. |
...@@ -4,7 +4,7 @@ type: howto ...@@ -4,7 +4,7 @@ type: howto
# How to unlock a locked user from the command line # How to unlock a locked user from the command line
After six failed login attempts a user gets in a locked state. After ten failed login attempts a user gets in a locked state.
To unlock a locked user: To unlock a locked user:
... ...
......
...@@ -744,9 +744,9 @@ workers: ...@@ -744,9 +744,9 @@ workers:
By default, all Kubernetes pods are By default, all Kubernetes pods are
[non-isolated](https://kubernetes.io/docs/concepts/services-networking/network-policies/#isolated-and-non-isolated-pods), [non-isolated](https://kubernetes.io/docs/concepts/services-networking/network-policies/#isolated-and-non-isolated-pods),
and accept traffic from any source. You can use meaning that they will accept traffic to and from any source. You can use
[NetworkPolicy](https://kubernetes.io/docs/concepts/services-networking/network-policies/) [NetworkPolicy](https://kubernetes.io/docs/concepts/services-networking/network-policies/)
to restrict connections to selected pods or namespaces. to restrict connections to and from selected pods, namespaces, and the Internet.
NOTE: **Note:** NOTE: **Note:**
You must use a Kubernetes network plugin that implements support for You must use a Kubernetes network plugin that implements support for
...@@ -767,7 +767,7 @@ networkPolicy: ...@@ -767,7 +767,7 @@ networkPolicy:
The default policy deployed by the auto deploy pipeline will allow The default policy deployed by the auto deploy pipeline will allow
traffic within a local namespace and from the `gitlab-managed-apps` traffic within a local namespace and from the `gitlab-managed-apps`
namespace. All other inbound connection will be blocked. Outbound namespace. All other inbound connection will be blocked. Outbound
traffic is not affected by the default policy. traffic (for example, to the Internet) is not affected by the default policy.
You can also provide a custom [policy specification](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.16/#networkpolicyspec-v1-networking-k8s-io) You can also provide a custom [policy specification](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.16/#networkpolicyspec-v1-networking-k8s-io)
via the `.gitlab/auto-deploy-values.yaml` file, for example: via the `.gitlab/auto-deploy-values.yaml` file, for example:
...@@ -788,6 +788,9 @@ networkPolicy: ...@@ -788,6 +788,9 @@ networkPolicy:
app.gitlab.com/managed_by: gitlab app.gitlab.com/managed_by: gitlab
``` ```
For more information on how to install Network Policies, see
[Install Cilium using GitLab CI](../../user/clusters/applications.md#install-cilium-using-gitlab-ci).
#### Web Application Firewall (ModSecurity) customization #### Web Application Firewall (ModSecurity) customization
> [Introduced](https://gitlab.com/gitlab-org/charts/auto-deploy-app/-/merge_requests/44) in GitLab 12.8. > [Introduced](https://gitlab.com/gitlab-org/charts/auto-deploy-app/-/merge_requests/44) in GitLab 12.8.
... ...
......