summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-05-04 21:09:41 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-05-04 21:09:41 +0000
commitb3cd77e90438a6c6e837dc27627d4c76f85ecd29 (patch)
tree52bbe45c9fd2aaceaca613bce04e7aab4a8aa07b
parent9bbcab8301ed38576debcb6a7f07f99005ff805a (diff)
downloadgitlab-ce-b3cd77e90438a6c6e837dc27627d4c76f85ecd29.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/static_site_editor/components/app.vue3
-rw-r--r--app/assets/javascripts/static_site_editor/index.js11
-rw-r--r--app/assets/javascripts/static_site_editor/pages/home.vue (renamed from app/assets/javascripts/static_site_editor/components/static_site_editor.vue)12
-rw-r--r--app/assets/javascripts/static_site_editor/router/constants.js2
-rw-r--r--app/assets/javascripts/static_site_editor/router/index.js15
-rw-r--r--app/assets/javascripts/static_site_editor/router/routes.js10
-rw-r--r--app/assets/javascripts/vue_shared/components/clone_dropdown.vue14
-rw-r--r--app/models/concerns/has_user_type.rb5
-rw-r--r--app/models/user.rb10
-rw-r--r--app/policies/global_policy.rb6
-rw-r--r--app/views/profiles/keys/_form.html.haml2
-rw-r--r--app/views/projects/static_site_editor/show.html.haml5
-rw-r--r--changelogs/unreleased/213678-API-documentation.yml5
-rw-r--r--changelogs/unreleased/216035-clone-dropdown-icons-alignment.yml5
-rw-r--r--changelogs/unreleased/fj-add-migration-user.yml5
-rw-r--r--doc/.vale/gitlab/spelling-exceptions.txt2
-rw-r--r--doc/api/releases/index.md11
-rw-r--r--doc/user/clusters/applications.md2
-rw-r--r--doc/user/project/clusters/runbooks/index.md166
-rw-r--r--doc/user/project/integrations/prometheus.md8
-rw-r--r--doc/user/project/operations/feature_flags.md55
-rw-r--r--qa/Gemfile3
-rw-r--r--qa/Gemfile.lock51
-rw-r--r--qa/qa/page/profile/ssh_keys.rb18
-rw-r--r--qa/qa/resource/ssh_key.rb10
-rw-r--r--qa/qa/runtime/api/client.rb2
-rw-r--r--qa/qa/specs/features/api/1_manage/rate_limits_spec.rb2
-rw-r--r--qa/qa/specs/features/api/1_manage/users_spec.rb2
-rw-r--r--qa/qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb2
-rw-r--r--qa/qa/specs/features/api/3_create/repository/files_spec.rb1
-rw-r--r--qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb1
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/add_ssh_key_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb10
-rw-r--r--qa/qa/support/api.rb2
-rw-r--r--qa/spec/resource/ssh_key_spec.rb21
-rw-r--r--qa/spec/specs/helpers/quarantine_spec.rb8
-rw-r--r--spec/factories/users.rb4
-rw-r--r--spec/frontend/pipelines/pipeline_details_mediator_spec.js (renamed from spec/javascripts/pipelines/pipeline_details_mediator_spec.js)8
-rw-r--r--spec/frontend/static_site_editor/pages/home_spec.js (renamed from spec/frontend/static_site_editor/components/static_site_editor_spec.js)6
-rw-r--r--spec/frontend/vue_shared/components/__snapshots__/clone_dropdown_spec.js.snap22
-rw-r--r--spec/models/concerns/has_user_type_spec.rb4
-rw-r--r--spec/models/user_spec.rb16
-rw-r--r--spec/policies/global_policy_spec.rb31
-rw-r--r--spec/views/admin/users/_user.html.haml_spec.rb10
45 files changed, 404 insertions, 188 deletions
diff --git a/app/assets/javascripts/static_site_editor/components/app.vue b/app/assets/javascripts/static_site_editor/components/app.vue
new file mode 100644
index 00000000000..98240aef810
--- /dev/null
+++ b/app/assets/javascripts/static_site_editor/components/app.vue
@@ -0,0 +1,3 @@
+<template>
+ <router-view />
+</template>
diff --git a/app/assets/javascripts/static_site_editor/index.js b/app/assets/javascripts/static_site_editor/index.js
index fe5d11f1bd9..b53d461f5a9 100644
--- a/app/assets/javascripts/static_site_editor/index.js
+++ b/app/assets/javascripts/static_site_editor/index.js
@@ -1,10 +1,11 @@
import Vue from 'vue';
import { parseBoolean } from '~/lib/utils/common_utils';
-import StaticSiteEditor from './components/static_site_editor.vue';
+import App from './components/app.vue';
import createStore from './store';
+import createRouter from './router';
const initStaticSiteEditor = el => {
- const { isSupportedContent, projectId, path: sourcePath, returnUrl } = el.dataset;
+ const { isSupportedContent, projectId, path: sourcePath, returnUrl, baseUrl } = el.dataset;
const store = createStore({
initialState: {
@@ -15,15 +16,17 @@ const initStaticSiteEditor = el => {
username: window.gon.current_username,
},
});
+ const router = createRouter(baseUrl);
return new Vue({
el,
store,
+ router,
components: {
- StaticSiteEditor,
+ App,
},
render(createElement) {
- return createElement('static-site-editor', StaticSiteEditor);
+ return createElement('app');
},
});
};
diff --git a/app/assets/javascripts/static_site_editor/components/static_site_editor.vue b/app/assets/javascripts/static_site_editor/pages/home.vue
index 79e4b4a4581..3de4a4a27cf 100644
--- a/app/assets/javascripts/static_site_editor/components/static_site_editor.vue
+++ b/app/assets/javascripts/static_site_editor/pages/home.vue
@@ -2,12 +2,12 @@
import { mapState, mapGetters, mapActions } from 'vuex';
import { GlSkeletonLoader } from '@gitlab/ui';
-import EditArea from './edit_area.vue';
-import EditHeader from './edit_header.vue';
-import SavedChangesMessage from './saved_changes_message.vue';
-import PublishToolbar from './publish_toolbar.vue';
-import InvalidContentMessage from './invalid_content_message.vue';
-import SubmitChangesError from './submit_changes_error.vue';
+import EditArea from '../components/edit_area.vue';
+import EditHeader from '../components/edit_header.vue';
+import SavedChangesMessage from '../components/saved_changes_message.vue';
+import PublishToolbar from '../components/publish_toolbar.vue';
+import InvalidContentMessage from '../components/invalid_content_message.vue';
+import SubmitChangesError from '../components/submit_changes_error.vue';
export default {
components: {
diff --git a/app/assets/javascripts/static_site_editor/router/constants.js b/app/assets/javascripts/static_site_editor/router/constants.js
new file mode 100644
index 00000000000..b835d0b8867
--- /dev/null
+++ b/app/assets/javascripts/static_site_editor/router/constants.js
@@ -0,0 +1,2 @@
+// eslint-disable-next-line import/prefer-default-export
+export const HOME_ROUTE_NAME = 'home';
diff --git a/app/assets/javascripts/static_site_editor/router/index.js b/app/assets/javascripts/static_site_editor/router/index.js
new file mode 100644
index 00000000000..12692612bbc
--- /dev/null
+++ b/app/assets/javascripts/static_site_editor/router/index.js
@@ -0,0 +1,15 @@
+import Vue from 'vue';
+import VueRouter from 'vue-router';
+import routes from './routes';
+
+Vue.use(VueRouter);
+
+export default function createRouter(base) {
+ const router = new VueRouter({
+ base,
+ mode: 'history',
+ routes,
+ });
+
+ return router;
+}
diff --git a/app/assets/javascripts/static_site_editor/router/routes.js b/app/assets/javascripts/static_site_editor/router/routes.js
new file mode 100644
index 00000000000..72d944fb36d
--- /dev/null
+++ b/app/assets/javascripts/static_site_editor/router/routes.js
@@ -0,0 +1,10 @@
+import Home from '../pages/home.vue';
+import { HOME_ROUTE_NAME } from './constants';
+
+export default [
+ {
+ name: HOME_ROUTE_NAME,
+ path: '/',
+ component: Home,
+ },
+];
diff --git a/app/assets/javascripts/vue_shared/components/clone_dropdown.vue b/app/assets/javascripts/vue_shared/components/clone_dropdown.vue
index 7826c179889..8ebcebb9758 100644
--- a/app/assets/javascripts/vue_shared/components/clone_dropdown.vue
+++ b/app/assets/javascripts/vue_shared/components/clone_dropdown.vue
@@ -4,7 +4,6 @@ import {
GlNewDropdownHeader,
GlFormInputGroup,
GlButton,
- GlIcon,
GlTooltipDirective,
} from '@gitlab/ui';
import { __, sprintf } from '~/locale';
@@ -16,7 +15,6 @@ export default {
GlNewDropdownHeader,
GlFormInputGroup,
GlButton,
- GlIcon,
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -59,9 +57,9 @@ export default {
v-gl-tooltip.hover
:title="$options.copyURLTooltip"
:data-clipboard-text="sshLink"
- >
- <gl-icon name="copy-to-clipboard" :title="$options.copyURLTooltip" />
- </gl-button>
+ icon="copy-to-clipboard"
+ class="d-inline-flex"
+ />
</template>
</gl-form-input-group>
</div>
@@ -77,9 +75,9 @@ export default {
v-gl-tooltip.hover
:title="$options.copyURLTooltip"
:data-clipboard-text="httpLink"
- >
- <gl-icon name="copy-to-clipboard" :title="$options.copyURLTooltip" />
- </gl-button>
+ icon="copy-to-clipboard"
+ class="d-inline-flex"
+ />
</template>
</gl-form-input-group>
</div>
diff --git a/app/models/concerns/has_user_type.rb b/app/models/concerns/has_user_type.rb
index 9b78233e6c6..1347e0be637 100644
--- a/app/models/concerns/has_user_type.rb
+++ b/app/models/concerns/has_user_type.rb
@@ -10,10 +10,11 @@ module HasUserType
visual_review_bot: 3,
service_user: 4,
ghost: 5,
- project_bot: 6
+ project_bot: 6,
+ migration_bot: 7
}.with_indifferent_access.freeze
- BOT_USER_TYPES = %w[alert_bot project_bot support_bot visual_review_bot].freeze
+ BOT_USER_TYPES = %w[alert_bot project_bot support_bot visual_review_bot migration_bot].freeze
NON_INTERNAL_USER_TYPES = %w[human project_bot service_user].freeze
INTERNAL_USER_TYPES = (USER_TYPES.keys - NON_INTERNAL_USER_TYPES).freeze
diff --git a/app/models/user.rb b/app/models/user.rb
index 69ca42071fb..942bcf75a88 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -636,6 +636,16 @@ class User < ApplicationRecord
end
end
+ def migration_bot
+ email_pattern = "noreply+gitlab-migration-bot%s@#{Settings.gitlab.host}"
+
+ unique_internal(where(user_type: :migration_bot), 'migration-bot', email_pattern) do |u|
+ u.bio = 'The GitLab migration bot'
+ u.name = 'GitLab Migration Bot'
+ u.confirmed_at = Time.zone.now
+ end
+ end
+
# Return true if there is only single non-internal user in the deployment,
# ghost user is ignored.
def single_user?
diff --git a/app/policies/global_policy.rb b/app/policies/global_policy.rb
index b6cf945bf5a..03f5a863421 100644
--- a/app/policies/global_policy.rb
+++ b/app/policies/global_policy.rb
@@ -18,6 +18,7 @@ class GlobalPolicy < BasePolicy
condition(:private_instance_statistics, score: 0) { Gitlab::CurrentSettings.instance_statistics_visibility_private? }
condition(:project_bot, scope: :user) { @user&.project_bot? }
+ condition(:migration_bot, scope: :user) { @user&.migration_bot? }
rule { admin | (~private_instance_statistics & ~anonymous) }
.enable :read_instance_statistics
@@ -48,11 +49,14 @@ class GlobalPolicy < BasePolicy
rule { blocked | internal }.policy do
prevent :log_in
prevent :access_api
- prevent :access_git
prevent :receive_notifications
prevent :use_slash_commands
end
+ rule { blocked | (internal & ~migration_bot) }.policy do
+ prevent :access_git
+ end
+
rule { project_bot }.policy do
prevent :log_in
prevent :receive_notifications
diff --git a/app/views/profiles/keys/_form.html.haml b/app/views/profiles/keys/_form.html.haml
index 34e81285328..7709aa8f4b9 100644
--- a/app/views/profiles/keys/_form.html.haml
+++ b/app/views/profiles/keys/_form.html.haml
@@ -14,7 +14,7 @@
.col.form-group
= f.label :expires_at, s_('Profiles|Expires at'), class: 'label-bold'
- = f.date_field :expires_at, class: "form-control input-lg qa-key-expiry-field", min: Date.tomorrow
+ = f.date_field :expires_at, class: "form-control input-lg", min: Date.tomorrow, data: { qa_selector: 'key_expiry_date_field' }
.js-add-ssh-key-validation-warning.hide
.bs-callout.bs-callout-warning{ role: 'alert', aria_live: 'assertive' }
diff --git a/app/views/projects/static_site_editor/show.html.haml b/app/views/projects/static_site_editor/show.html.haml
index 8d2649be588..88c5378fc35 100644
--- a/app/views/projects/static_site_editor/show.html.haml
+++ b/app/views/projects/static_site_editor/show.html.haml
@@ -1 +1,4 @@
-#static-site-editor{ data: @config.payload }
+-# TODO: Remove after base URL is included in the model !30735
+- data = @config.payload.merge({ base_url: namespace_project_show_sse_path })
+
+#static-site-editor{ data: data }
diff --git a/changelogs/unreleased/213678-API-documentation.yml b/changelogs/unreleased/213678-API-documentation.yml
new file mode 100644
index 00000000000..2fb155b70db
--- /dev/null
+++ b/changelogs/unreleased/213678-API-documentation.yml
@@ -0,0 +1,5 @@
+---
+title: Remove deprecated Release Evidence endpoints documentation
+merge_request: 30978
+author:
+type: removed
diff --git a/changelogs/unreleased/216035-clone-dropdown-icons-alignment.yml b/changelogs/unreleased/216035-clone-dropdown-icons-alignment.yml
new file mode 100644
index 00000000000..ab7f1ab2df2
--- /dev/null
+++ b/changelogs/unreleased/216035-clone-dropdown-icons-alignment.yml
@@ -0,0 +1,5 @@
+---
+title: Fixed alignment of Snippet Clone copy buttons
+merge_request: 30897
+author:
+type: fixed
diff --git a/changelogs/unreleased/fj-add-migration-user.yml b/changelogs/unreleased/fj-add-migration-user.yml
new file mode 100644
index 00000000000..ac851add77d
--- /dev/null
+++ b/changelogs/unreleased/fj-add-migration-user.yml
@@ -0,0 +1,5 @@
+---
+title: Add migration bot user
+merge_request: 30738
+author:
+type: added
diff --git a/doc/.vale/gitlab/spelling-exceptions.txt b/doc/.vale/gitlab/spelling-exceptions.txt
index 995cbf9ab62..bbbb0ae0dad 100644
--- a/doc/.vale/gitlab/spelling-exceptions.txt
+++ b/doc/.vale/gitlab/spelling-exceptions.txt
@@ -201,6 +201,7 @@ namespaced
namespaces
Nanoc
NGINX
+Nurtch
OAuth
Okta
offboarded
@@ -277,6 +278,7 @@ resync
reverified
reverifies
reverify
+Rubix
runbook
runbooks
runit
diff --git a/doc/api/releases/index.md b/doc/api/releases/index.md
index d327a76b683..2e1e206ecfd 100644
--- a/doc/api/releases/index.md
+++ b/doc/api/releases/index.md
@@ -286,7 +286,6 @@ Example response:
],
"commit_path":"/root/awesome-app/commit/588440f66559714280628a4f9799f0c4eb880a4a",
"tag_path":"/root/awesome-app/-/tags/v0.11.1",
- "evidence_sha":"760d6cdfb0879c3ffedec13af470e0f71cf52c6cde4d",
"assets":{
"count":5,
"sources":[
@@ -314,9 +313,15 @@ Example response:
"url":"https://gitlab.example.com/root/awesome-app/-/tags/v0.11.1/binaries/linux-amd64",
"external":true
}
- ],
- "evidence_url":"https://gitlab.example.com/root/awesome-app/-/releases/v0.1/evidence.json"
+ ]
},
+ "evidences":[
+ {
+ sha: "760d6cdfb0879c3ffedec13af470e0f71cf52c6cde4d",
+ filepath: "https://gitlab.example.com/root/awesome-app/-/releases/v0.1/evidence.json",
+ collected_at: "2019-07-16T14:00:12.256Z"
+ }
+ ]
}
```
diff --git a/doc/user/clusters/applications.md b/doc/user/clusters/applications.md
index 69d057ad673..40f75008219 100644
--- a/doc/user/clusters/applications.md
+++ b/doc/user/clusters/applications.md
@@ -366,7 +366,7 @@ will also see ready-to-use DevOps Runbooks built with Nurtch's [Rubix library](h
More information on
creating executable runbooks can be found in [our Runbooks
-documentation](../project/clusters/runbooks/index.md#executable-runbooks). Note that
+documentation](../project/clusters/runbooks/index.md#configure-an-executable-runbook-with-gitlab). Note that
Ingress must be installed and have an IP address assigned before
JupyterHub can be installed.
diff --git a/doc/user/project/clusters/runbooks/index.md b/doc/user/project/clusters/runbooks/index.md
index 5575cd1d2d4..623833af894 100644
--- a/doc/user/project/clusters/runbooks/index.md
+++ b/doc/user/project/clusters/runbooks/index.md
@@ -4,11 +4,10 @@ Runbooks are a collection of documented procedures that explain how to
carry out a particular process, be it starting, stopping, debugging,
or troubleshooting a particular system.
-Using [Jupyter Notebooks](https://jupyter.org/) and the [Rubix library](https://github.com/Nurtch/rubix),
+Using [Jupyter Notebooks](https://jupyter.org/) and the
+[Rubix library](https://github.com/Nurtch/rubix),
users can get started writing their own executable runbooks.
-## Overview
-
Historically, runbooks took the form of a decision tree or a detailed
step-by-step guide depending on the condition or system.
@@ -22,121 +21,128 @@ pre-written code blocks or database queries against a given environment.
The JupyterHub app offered via GitLab’s Kubernetes integration now ships
with Nurtch’s Rubix library, providing a simple way to create DevOps
-runbooks. A sample runbook is provided, showcasing common operations. While Rubix makes it
-simple to create common Kubernetes and AWS workflows, you can also create them manually without
-Rubix.
+runbooks. A sample runbook is provided, showcasing common operations. While
+Rubix makes it simple to create common Kubernetes and AWS workflows, you can
+also create them manually without Rubix.
-**<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
+<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
Watch this [video](https://www.youtube.com/watch?v=Q_OqHIIUPjE)
-for an overview of how this is accomplished in GitLab!**
+for an overview of how this is accomplished in GitLab!
## Requirements
To create an executable runbook, you will need:
-1. **Kubernetes** - A Kubernetes cluster is required to deploy the rest of the applications.
- The simplest way to get started is to add a cluster using one of [GitLab's integrations](../add_remove_clusters.md#create-new-cluster).
-1. **Helm Tiller** - Helm is a package manager for Kubernetes and is required to install
- all the other applications. It is installed in its own pod inside the cluster which
- can run the Helm CLI in a safe environment.
-1. **Ingress** - Ingress can provide load balancing, SSL termination, and name-based
- virtual hosting. It acts as a web proxy for your applications.
-1. **JupyterHub** - [JupyterHub](https://jupyterhub.readthedocs.io/) is a multi-user service for managing notebooks across
- a team. Jupyter Notebooks provide a web-based interactive programming environment
- used for data analysis, visualization, and machine learning.
+- **Kubernetes** - A Kubernetes cluster is required to deploy the rest of the
+ applications. The simplest way to get started is to add a cluster using one
+ of [GitLab's integrations](../add_remove_clusters.md#create-new-cluster).
+- **Helm Tiller** - Helm is a package manager for Kubernetes and is required to
+ install all the other applications. It's installed in its own pod inside the
+ cluster which can run the Helm CLI in a safe environment.
+- **Ingress** - Ingress can provide load balancing, SSL termination, and name-based
+ virtual hosting. It acts as a web proxy for your applications.
+- **JupyterHub** - [JupyterHub](https://jupyterhub.readthedocs.io/) is a multi-user
+ service for managing notebooks across a team. Jupyter Notebooks provide a
+ web-based interactive programming environment used for data analysis,
+ visualization, and machine learning.
## Nurtch
-Nurtch is the company behind the [Rubix library](https://github.com/Nurtch/rubix). Rubix is
-an open-source Python library that makes it easy to perform common DevOps tasks inside Jupyter Notebooks.
-Tasks such as plotting Cloudwatch metrics and rolling your ECS/Kubernetes app are simplified
-down to a couple of lines of code. See the [Nurtch Documentation](http://docs.nurtch.com/en/latest/)
-for more information.
+Nurtch is the company behind the [Rubix library](https://github.com/Nurtch/rubix).
+Rubix is an open-source Python library that makes it easy to perform common
+DevOps tasks inside Jupyter Notebooks. Tasks such as plotting Cloudwatch metrics
+and rolling your ECS/Kubernetes app are simplified down to a couple of lines of
+code. See the [Nurtch Documentation](http://docs.nurtch.com/en/latest/) for more
+information.
## Configure an executable runbook with GitLab
Follow this step-by-step guide to configure an executable runbook in GitLab using
-the components outlined above and the preloaded demo runbook.
-
-### 1. Add a Kubernetes cluster
-
-Follow the steps outlined in [Create new cluster](../add_remove_clusters.md#create-new-cluster)
-to add a Kubernetes cluster to your project.
-
-### 2. Install Helm Tiller, Ingress, and JupyterHub
-
-Once the cluster has been provisioned in GKE, click the **Install** button next to the **Helm Tiller** app.
-
-![install helm](img/helm-install.png)
+the components outlined above and the pre-loaded demo runbook.
-Once Tiller has been installed successfully, click the **Install** button next to the **Ingress** app.
+1. Add a Kubernetes cluster to your project by following the steps outlined in
+ [Create new cluster](../add_remove_clusters.md#create-new-cluster).
+1. After the cluster has been provisioned in GKE, click the **Install** button
+ next to the **Helm Tiller** application to install Helm Tiller.
-![install ingress](img/ingress-install.png)
+ ![install helm](img/helm-install.png)
-Once Ingress has been installed successfully, click the **Install** button next to the **JupyterHub** app.
+1. After Helm Tiller has been installed successfully, click the **Install** button next
+ to the **Ingress** application.
-![install jupyterhub](img/jupyterhub-install.png)
+ ![install ingress](img/ingress-install.png)
-### 3. Login to JupyterHub and start the server
+1. After Ingress has been installed successfully, click the **Install** button next
+ to the **JupyterHub** application. You will need the **Jupyter Hostname** provided
+ here in the next step.
-Once JupyterHub has been installed successfully, navigate to the displayed **Jupyter Hostname** URL and click
-**Sign in with GitLab**. Authentication is automatically enabled for any user of the GitLab instance via OAuth2. This
-will redirect to GitLab in order to authorize JupyterHub to use your GitLab account. Click **Authorize**.
+ ![install JupyterHub](img/jupyterhub-install.png)
-![authorize jupyter](img/authorize-jupyter.png)
+1. After JupyterHub has been installed successfully, open the **Jupyter Hostname**
+ in your browser. Click the **Sign in with GitLab** button to log in to
+ JupyterHub and start the server. Authentication is enabled for any user of the
+ GitLab instance with OAuth2. This button redirects you to a page at GitLab
+ requesting authorization for JupyterHub to use your GitLab account.
-Once the application has been authorized you will taken back to the JupyterHub application. Click **Start My Server**.
-The server will take a couple of seconds to start.
+ ![authorize Jupyter](img/authorize-jupyter.png)
-### 4. Configure access
+1. Click **Authorize**, and you will be redirected to the JupyterHub application.
+1. Click **Start My Server**, and the server will start in a few seconds.
+1. To configure the runbook's access to your GitLab project, you must enter your
+ [GitLab Access Token](../../../profile/personal_access_tokens.md)
+ and your Project ID in the **Setup** section of the demo runbook:
-In order for the runbook to access your GitLab project, you will need to enter a
-[GitLab Access Token](../../../profile/personal_access_tokens.md)
-as well as your Project ID in the **Setup** section of the demo runbook.
+ 1. Double-click the **DevOps-Runbook-Demo** folder located on the left panel.
-Double-click the **DevOps-Runbook-Demo** folder located on the left panel.
+ ![demo runbook](img/demo-runbook.png)
-![demo runbook](img/demo-runbook.png)
+ 1. Double-click the `Nurtch-DevOps-Demo.ipynb` runbook.
-Double-click the "Nurtch-DevOps-Demo.ipynb" runbook.
+ ![sample runbook](img/sample-runbook.png)
-![sample runbook](img/sample-runbook.png)
+ Jupyter displays the runbook's contents in the right-hand side of the screen.
+ The **Setup** section displays your `PRIVATE_TOKEN` and your `PROJECT_ID`.
+ Enter these values, maintaining the single quotes as follows:
-The contents on the runbook will be displayed on the right side of the screen. Under the "Setup" section, you will find
-entries for both your `PRIVATE_TOKEN` and your `PROJECT_ID`. Enter both these values, conserving the single quotes as follows:
+ ```sql
+ PRIVATE_TOKEN = 'n671WNGecHugsdEDPsyo'
+ PROJECT_ID = '1234567'
+ ```
-```sql
-PRIVATE_TOKEN = 'n671WNGecHugsdEDPsyo'
-PROJECT_ID = '1234567'
-```
+ 1. Update the `VARIABLE_NAME` on the last line of this section to match the name of
+ the variable you're using for your access token. In this example, our variable
+ name is `PRIVATE_TOKEN`.
-Update the `VARIABLE_NAME` on the last line of this section to match the name of the variable you are using for your
-access token. In this example our variable name is `PRIVATE_TOKEN`.
+ ```sql
+ VARIABLE_VALUE = project.variables.get('PRIVATE_TOKEN').value
+ ```
-```sql
-VARIABLE_VALUE = project.variables.get('PRIVATE_TOKEN').value
-```
+1. To configure the operation of a runbook, create and configure variables:
-### 5. Configure an operation
+ NOTE: **Note:**
+ For this example, we are using the **Run SQL queries in Notebook** section in the
+ sample runbook to query a PostgreSQL database. The first four lines of the following
+ code block define the variables that are required for this query to function:
-For this example we'll use the "**Run SQL queries in Notebook**" section in the sample runbook to query
-a PostgreSQL database. The first 4 lines of the section define the variables that are required for this query to function.
+ ```sql
+ %env DB_USER={project.variables.get('DB_USER').value}
+ %env DB_PASSWORD={project.variables.get('DB_PASSWORD').value}
+ %env DB_ENDPOINT={project.variables.get('DB_ENDPOINT').value}
+ %env DB_NAME={project.variables.get('DB_NAME').value}
+ ```
-```sql
-%env DB_USER={project.variables.get('DB_USER').value}
-%env DB_PASSWORD={project.variables.get('DB_PASSWORD').value}
-%env DB_ENDPOINT={project.variables.get('DB_ENDPOINT').value}
-%env DB_NAME={project.variables.get('DB_NAME').value}
-```
+ 1. Navigate to **{settings}** **Settings >> CI/CD >> Variables** to create
+ the variables in your project.
-Create the matching variables in your project's **Settings >> CI/CD >> Variables**
+ ![GitLab variables](img/gitlab-variables.png)
-![gitlab variables](img/gitlab-variables.png)
+ 1. Click **Save variables**.
-Back in Jupyter, click the "Run SQL queries in Notebook" heading and the click *Run*. The results will be
-displayed in-line as follows:
+ 1. In Jupyter, click the **Run SQL queries in Notebook** heading, and then click
+ **Run**. The results are displayed inline as follows:
-![PostgreSQL query](img/postgres-query.png)
+ ![PostgreSQL query](img/postgres-query.png)
-You can try other operations such as running shell scripts or interacting with a Kubernetes cluster. Visit the
+You can try other operations, such as running shell scripts or interacting with a
+Kubernetes cluster. Visit the
[Nurtch Documentation](http://docs.nurtch.com/) for more information.
diff --git a/doc/user/project/integrations/prometheus.md b/doc/user/project/integrations/prometheus.md
index 0e18b678133..041a70067d4 100644
--- a/doc/user/project/integrations/prometheus.md
+++ b/doc/user/project/integrations/prometheus.md
@@ -931,6 +931,14 @@ Prerequisites for embedding from a Grafana instance:
1. In GitLab, paste the URL into a Markdown field and save. The chart will take a few moments to render.
![GitLab Rendered Grafana Panel](img/rendered_grafana_embed_v12_5.png)
+## Metrics dashboard visibility
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/201924) in GitLab 13.0.
+
+You can set the visibility of the metrics dashboard to **Only Project Members**
+or **Everyone With Access**. When set to **Everyone with Access**, the metrics
+dashboard, and all of the custom dashboard, YAML files, are visible to authenticated and non-authenticated users.
+
## Troubleshooting
When troubleshooting issues with a managed Prometheus app, it is often useful to
diff --git a/doc/user/project/operations/feature_flags.md b/doc/user/project/operations/feature_flags.md
index 1000eecd692..fb6b808c47c 100644
--- a/doc/user/project/operations/feature_flags.md
+++ b/doc/user/project/operations/feature_flags.md
@@ -43,10 +43,10 @@ To add a new feature flag:
1. Click on the **New Feature Flag** button.
1. Give it a name.
- NOTE: **Note:**
- A name can contain only lowercase letters, digits, underscores (`_`)
- and dashes (`-`), must start with a letter, and cannot end with a dash (`-`)
- or an underscore (`_`).
+ NOTE: **Note:**
+ A name can contain only lowercase letters, digits, underscores (`_`)
+ and dashes (`-`), must start with a letter, and cannot end with a dash (`-`)
+ or an underscore (`_`).
1. Give it a description (optional, 255 characters max).
1. Define environment [specs](#define-environment-specs). If you want the flag on by default, enable the catch-all [wildcard spec (`*`)](#define-environment-specs)
@@ -91,6 +91,41 @@ NOTE: **NOTE**
We'd highly recommend you to use the [Environment](../../../ci/environments.md)
feature in order to quickly assess which flag is enabled per environment.
+## Feature flag behavior change in 13.0
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/35555) in GitLab 13.0.
+
+Starting in GitLab 13.0, you can apply a feature flag strategy across multiple environment specs,
+without defining the strategy multiple times.
+
+This feature is under development and not ready for production use. It is
+deployed behind a feature flag that is **disabled by default**.
+[GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)
+can enable it for your instance.
+
+To enable it:
+
+```ruby
+Feature.enable(:feature_flags_new_version)
+```
+
+To disable it:
+
+```ruby
+Feature.disable(:feature_flags_new_version)
+```
+
+### Applying a strategy to environments
+
+After a strategy is defined, it applies to **All Environments** by default. To
+make a strategy apply to a specific environment spec:
+
+1. Click the **Add Environment** button.
+1. Create a new
+ [spec](../../../ci/environments.md#scoping-environments-with-specs).
+
+To apply the strategy to multiple environment specs, repeat these steps.
+
## Feature Flag strategies
GitLab Feature Flag adopts [Unleash](https://unleash.github.io)
@@ -155,12 +190,12 @@ To get the access credentials that your application will need to talk to GitLab:
1. Navigate to your project's **Operations > Feature Flags**.
1. Click on the **Configure** button to see the values:
- - **API URL**: URL where the client (application) connects to get a list of feature flags.
- - **Instance ID**: Unique token that authorizes the retrieval of the feature flags.
- - **Application name**: The name of the running environment. For instance,
- if the application runs for production server, application name would be
- `production` or similar. This value is used for
- [the environment spec evaluation](#define-environment-specs).
+ - **API URL**: URL where the client (application) connects to get a list of feature flags.
+ - **Instance ID**: Unique token that authorizes the retrieval of the feature flags.
+ - **Application name**: The name of the running environment. For instance,
+ if the application runs for a production server, application name would be
+ `production` or similar. This value is used for
+ [the environment spec evaluation](#define-environment-specs).
NOTE: **Note:**
The meaning of these fields might change over time. For example, we are not sure
diff --git a/qa/Gemfile b/qa/Gemfile
index 458baffcd40..b11d5b1b682 100644
--- a/qa/Gemfile
+++ b/qa/Gemfile
@@ -7,7 +7,8 @@ gem 'capybara-screenshot', '~> 1.0.23'
gem 'rake', '~> 12.3.0'
gem 'rspec', '~> 3.7'
gem 'selenium-webdriver', '~> 3.12'
-gem 'airborne', '~> 0.2.13'
+gem 'airborne', '~> 0.3.4'
+gem 'rest-client', '~> 2.1.0'
gem 'nokogiri', '~> 1.10.9'
gem 'rspec-retry', '~> 0.6.1'
gem 'rspec_junit_formatter', '~> 0.4.1'
diff --git a/qa/Gemfile.lock b/qa/Gemfile.lock
index 26c903599c9..6b996ca00f5 100644
--- a/qa/Gemfile.lock
+++ b/qa/Gemfile.lock
@@ -9,12 +9,12 @@ GEM
zeitwerk (~> 2.2)
addressable (2.7.0)
public_suffix (>= 2.0.2, < 5.0)
- airborne (0.2.13)
+ airborne (0.3.4)
activesupport
rack
- rack-test (~> 0.6, >= 0.6.2)
- rest-client (>= 1.7.3, < 3.0)
- rspec (~> 3.1)
+ rack-test (>= 1.1.0, < 2.0)
+ rest-client (>= 2.0.2, < 3.0)
+ rspec (~> 3.8)
byebug (9.1.0)
capybara (3.29.0)
addressable
@@ -34,11 +34,12 @@ GEM
debase-ruby_core_source (>= 0.10.2)
debase-ruby_core_source (0.10.6)
diff-lcs (1.3)
- domain_name (0.5.20170404)
+ domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
faker (1.9.3)
i18n (>= 0.7)
gitlab-qa (4.0.0)
+ http-accept (1.7.0)
http-cookie (1.0.3)
domain_name (~> 0.5)
i18n (1.8.2)
@@ -48,9 +49,9 @@ GEM
launchy (2.4.3)
addressable (~> 2.3)
method_source (0.9.0)
- mime-types (3.1)
+ mime-types (3.3.1)
mime-types-data (~> 3.2015)
- mime-types-data (3.2016.0521)
+ mime-types-data (3.2020.0425)
mini_mime (1.0.2)
mini_portile2 (2.4.0)
minitest (5.14.0)
@@ -67,30 +68,31 @@ GEM
byebug (~> 9.1)
pry (~> 0.10)
public_suffix (4.0.1)
- rack (2.0.7)
- rack-test (0.8.3)
+ rack (2.2.2)
+ rack-test (1.1.0)
rack (>= 1.0, < 3)
rake (12.3.0)
regexp_parser (1.6.0)
- rest-client (2.0.2)
+ rest-client (2.1.0)
+ http-accept (>= 1.7.0, < 2.0)
http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 4.0)
netrc (~> 0.8)
- rspec (3.7.0)
- rspec-core (~> 3.7.0)
- rspec-expectations (~> 3.7.0)
- rspec-mocks (~> 3.7.0)
- rspec-core (3.7.1)
- rspec-support (~> 3.7.0)
- rspec-expectations (3.7.0)
+ rspec (3.9.0)
+ rspec-core (~> 3.9.0)
+ rspec-expectations (~> 3.9.0)
+ rspec-mocks (~> 3.9.0)
+ rspec-core (3.9.2)
+ rspec-support (~> 3.9.3)
+ rspec-expectations (3.9.1)
diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.7.0)
- rspec-mocks (3.7.0)
+ rspec-support (~> 3.9.0)
+ rspec-mocks (3.9.1)
diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.7.0)
+ rspec-support (~> 3.9.0)
rspec-retry (0.6.1)
rspec-core (> 3.3)
- rspec-support (3.7.0)
+ rspec-support (3.9.3)
rspec_junit_formatter (0.4.1)
rspec-core (>= 2, < 4, != 2.12.0)
ruby-debug-ide (0.7.2)
@@ -101,11 +103,11 @@ GEM
rubyzip (>= 1.2.2)
thread_safe (0.3.6)
timecop (0.9.1)
- tzinfo (1.2.6)
+ tzinfo (1.2.7)
thread_safe (~> 0.1)
unf (0.1.4)
unf_ext
- unf_ext (0.0.7.4)
+ unf_ext (0.0.7.7)
xpath (3.2.0)
nokogiri (~> 1.8)
zeitwerk (2.3.0)
@@ -115,7 +117,7 @@ PLATFORMS
DEPENDENCIES
activesupport (~> 6.0.2.2)
- airborne (~> 0.2.13)
+ airborne (~> 0.3.4)
capybara (~> 3.29.0)
capybara-screenshot (~> 1.0.23)
debase (~> 0.2.4.1)
@@ -126,6 +128,7 @@ DEPENDENCIES
parallel_tests (~> 2.29)
pry-byebug (~> 3.5.1)
rake (~> 12.3.0)
+ rest-client (~> 2.1.0)
rspec (~> 3.7)
rspec-retry (~> 0.6.1)
rspec_junit_formatter (~> 0.4.1)
diff --git a/qa/qa/page/profile/ssh_keys.rb b/qa/qa/page/profile/ssh_keys.rb
index 082202f91ca..810877e21ad 100644
--- a/qa/qa/page/profile/ssh_keys.rb
+++ b/qa/qa/page/profile/ssh_keys.rb
@@ -5,6 +5,7 @@ module QA
module Profile
class SSHKeys < Page::Base
view 'app/views/profiles/keys/_form.html.haml' do
+ element :key_expiry_date_field
element :key_title_field
element :key_public_key_field
element :add_key_button
@@ -19,17 +20,26 @@ module QA
end
def add_key(public_key, title)
- fill_element :key_public_key_field, public_key
- fill_element :key_title_field, title
+ fill_element(:key_public_key_field, public_key)
+ fill_element(:key_title_field, title)
+ # Expire in 2 days just in case the key is created just before midnight
+ fill_expiry_date(Date.today + 2)
- click_element :add_key_button
+ click_element(:add_key_button)
+ end
+
+ def fill_expiry_date(date)
+ date = date.strftime('%m/%d/%Y') if date.is_a?(Date)
+ Date.strptime(date, '%m/%d/%Y') rescue ArgumentError raise "Expiry date must be in mm/dd/yyyy format"
+
+ fill_element(:key_expiry_date_field, date)
end
def remove_key(title)
click_link(title)
accept_alert do
- click_element :delete_key_button
+ click_element(:delete_key_button)
end
end
diff --git a/qa/qa/resource/ssh_key.rb b/qa/qa/resource/ssh_key.rb
index 3e130aef9e4..b948bf3969b 100644
--- a/qa/qa/resource/ssh_key.rb
+++ b/qa/qa/resource/ssh_key.rb
@@ -5,12 +5,16 @@ module QA
class SSHKey < Base
extend Forwardable
- attr_accessor :title
+ attr_reader :title
attribute :id
def_delegators :key, :private_key, :public_key, :md5_fingerprint
+ def initialize
+ self.title = Time.now.to_f
+ end
+
def key
@key ||= Runtime::Key::RSA.new
end
@@ -28,6 +32,10 @@ module QA
api_post
end
+ def title=(title)
+ @title = "E2E test key: #{title}"
+ end
+
def api_delete
QA::Runtime::Logger.debug("Deleting SSH key with title '#{title}' and fingerprint '#{md5_fingerprint}'")
diff --git a/qa/qa/runtime/api/client.rb b/qa/qa/runtime/api/client.rb
index b9a3c9184aa..d29571df981 100644
--- a/qa/qa/runtime/api/client.rb
+++ b/qa/qa/runtime/api/client.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-require 'airborne'
-
module QA
module Runtime
module API
diff --git a/qa/qa/specs/features/api/1_manage/rate_limits_spec.rb b/qa/qa/specs/features/api/1_manage/rate_limits_spec.rb
index 819739ac535..1bf435014af 100644
--- a/qa/qa/specs/features/api/1_manage/rate_limits_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/rate_limits_spec.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
+require 'airborne'
+
module QA
context 'Manage with IP rate limits', :requires_admin do
describe 'Users API' do
diff --git a/qa/qa/specs/features/api/1_manage/users_spec.rb b/qa/qa/specs/features/api/1_manage/users_spec.rb
index ba1ba204d24..fbc26e81b69 100644
--- a/qa/qa/specs/features/api/1_manage/users_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/users_spec.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
+require 'airborne'
+
module QA
context 'Manage' do
describe 'Users API' do
diff --git a/qa/qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb b/qa/qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb
index f14fcc5afce..58d716f759e 100644
--- a/qa/qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb
+++ b/qa/qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
+require 'airborne'
+
module QA
context 'Plan' do
include Support::Api
diff --git a/qa/qa/specs/features/api/3_create/repository/files_spec.rb b/qa/qa/specs/features/api/3_create/repository/files_spec.rb
index dc471128dae..92858ba4107 100644
--- a/qa/qa/specs/features/api/3_create/repository/files_spec.rb
+++ b/qa/qa/specs/features/api/3_create/repository/files_spec.rb
@@ -1,5 +1,6 @@
# frozen_string_literal: true
+require 'airborne'
require 'securerandom'
module QA
diff --git a/qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb b/qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb
index 5ba434a7781..3ad56e21ad4 100644
--- a/qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb
+++ b/qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb
@@ -1,5 +1,6 @@
# frozen_string_literal: true
+require 'airborne'
require 'securerandom'
require 'digest'
diff --git a/qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb
index 5f7a6981f23..0a577aa07f8 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb
@@ -3,6 +3,8 @@
module QA
context 'Plan', :orchestrated, :smtp do
describe 'Email Notification' do
+ include Support::Api
+
let(:user) do
Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1)
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/add_ssh_key_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/add_ssh_key_spec.rb
index 25866e12185..68bbc1719fc 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/add_ssh_key_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/add_ssh_key_spec.rb
@@ -12,7 +12,7 @@ module QA
resource.title = key_title
end
- expect(page).to have_content("Title: #{key_title}")
+ expect(page).to have_content(key.title)
expect(page).to have_content(key.md5_fingerprint)
Page::Main::Menu.perform(&:click_settings_link)
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb
index 9bc4dcbca2a..9b504ad76b4 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb
@@ -3,6 +3,8 @@
module QA
context 'Create', :requires_admin do
describe 'push after setting the file size limit via admin/application_settings' do
+ include Support::Api
+
before(:context) do
@project = Resource::Project.fabricate_via_api! do |p|
p.name = 'project-test-push-limit'
@@ -39,12 +41,10 @@ module QA
def set_file_size_limit(limit)
request = Runtime::API::Request.new(@api_client, '/application/settings')
- put request.url, receive_max_input_size: limit
+ response = put request.url, receive_max_input_size: limit
- expect_status(200)
- expect(json_body).to match(
- a_hash_including(receive_max_input_size: limit)
- )
+ expect(response.code).to eq(200)
+ expect(parse_body(response)[:receive_max_input_size]).to eq(limit)
end
def push_new_file(file_name, wait_for_push: true)
diff --git a/qa/qa/support/api.rb b/qa/qa/support/api.rb
index d39b4353191..f5e4d4e294b 100644
--- a/qa/qa/support/api.rb
+++ b/qa/qa/support/api.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
+require 'rest-client'
+
module QA
module Support
module Api
diff --git a/qa/spec/resource/ssh_key_spec.rb b/qa/spec/resource/ssh_key_spec.rb
new file mode 100644
index 00000000000..b2b5ec070e1
--- /dev/null
+++ b/qa/spec/resource/ssh_key_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+describe QA::Resource::SSHKey do
+ describe '#key' do
+ it 'generates a default key' do
+ expect(subject.key).to be_a(QA::Runtime::Key::RSA)
+ end
+ end
+
+ describe '#title' do
+ it 'generates a default title' do
+ expect(subject.title).to match(/E2E test key: \d+/)
+ end
+
+ it 'is possible to set the title' do
+ subject.title = 'I am in a title'
+
+ expect(subject.title).to eq('E2E test key: I am in a title')
+ end
+ end
+end
diff --git a/qa/spec/specs/helpers/quarantine_spec.rb b/qa/spec/specs/helpers/quarantine_spec.rb
index d5c6820f0a9..1f09c3f73ac 100644
--- a/qa/spec/specs/helpers/quarantine_spec.rb
+++ b/qa/spec/specs/helpers/quarantine_spec.rb
@@ -31,14 +31,6 @@ RSpec.configure do |c|
config.color_mode = :off
- # Load airborne again to avoid "undefined method `match_expected_default?'" errors
- # that happen because a hook calls a method added via a custom RSpec setting
- # that is removed when the RSpec configuration is sandboxed.
- # If this needs to be changed (e.g., to load other libraries as well), see
- # this discussion for alternative solutions:
- # https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/25223#note_143392053
- load 'airborne.rb'
-
ex.run
end
end
diff --git a/spec/factories/users.rb b/spec/factories/users.rb
index e834cd13d36..2f5cc404143 100644
--- a/spec/factories/users.rb
+++ b/spec/factories/users.rb
@@ -31,6 +31,10 @@ FactoryBot.define do
user_type { :project_bot }
end
+ trait :migration_bot do
+ user_type { :migration_bot }
+ end
+
trait :external do
external { true }
end
diff --git a/spec/javascripts/pipelines/pipeline_details_mediator_spec.js b/spec/frontend/pipelines/pipeline_details_mediator_spec.js
index 61ee2dc13ca..083e97666ed 100644
--- a/spec/javascripts/pipelines/pipeline_details_mediator_spec.js
+++ b/spec/frontend/pipelines/pipeline_details_mediator_spec.js
@@ -1,6 +1,7 @@
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import PipelineMediator from '~/pipelines/pipeline_details_mediator';
+import waitForPromises from 'helpers/wait_for_promises';
describe('PipelineMdediator', () => {
let mediator;
@@ -23,14 +24,13 @@ describe('PipelineMdediator', () => {
});
describe('request and store data', () => {
- it('should store received data', done => {
+ it('should store received data', () => {
mock.onGet('foo.json').reply(200, { id: '121123' });
mediator.fetchPipeline();
- setTimeout(() => {
+ return waitForPromises().then(() => {
expect(mediator.store.state.pipeline).toEqual({ id: '121123' });
- done();
- }, 0);
+ });
});
});
});
diff --git a/spec/frontend/static_site_editor/components/static_site_editor_spec.js b/spec/frontend/static_site_editor/pages/home_spec.js
index 5d4e3758557..82e39447ae6 100644
--- a/spec/frontend/static_site_editor/components/static_site_editor_spec.js
+++ b/spec/frontend/static_site_editor/pages/home_spec.js
@@ -4,7 +4,7 @@ import { GlSkeletonLoader } from '@gitlab/ui';
import createState from '~/static_site_editor/store/state';
-import StaticSiteEditor from '~/static_site_editor/components/static_site_editor.vue';
+import Home from '~/static_site_editor/pages/home.vue';
import EditArea from '~/static_site_editor/components/edit_area.vue';
import EditHeader from '~/static_site_editor/components/edit_header.vue';
import InvalidContentMessage from '~/static_site_editor/components/invalid_content_message.vue';
@@ -24,7 +24,7 @@ const localVue = createLocalVue();
localVue.use(Vuex);
-describe('StaticSiteEditor', () => {
+describe('static_site_editor/pages/home', () => {
let wrapper;
let store;
let loadContentActionMock;
@@ -68,7 +68,7 @@ describe('StaticSiteEditor', () => {
};
const buildWrapper = () => {
- wrapper = shallowMount(StaticSiteEditor, {
+ wrapper = shallowMount(Home, {
localVue,
store,
});
diff --git a/spec/frontend/vue_shared/components/__snapshots__/clone_dropdown_spec.js.snap b/spec/frontend/vue_shared/components/__snapshots__/clone_dropdown_spec.js.snap
index 4cd03a690e9..7dd324a61cd 100644
--- a/spec/frontend/vue_shared/components/__snapshots__/clone_dropdown_spec.js.snap
+++ b/spec/frontend/vue_shared/components/__snapshots__/clone_dropdown_spec.js.snap
@@ -44,18 +44,13 @@ exports[`Clone Dropdown Button rendering matches the snapshot 1`] = `
>
<gl-button-stub
category="tertiary"
+ class="d-inline-flex"
data-clipboard-text="ssh://foo.bar"
- icon=""
+ icon="copy-to-clipboard"
size="medium"
title="Copy URL"
variant="default"
- >
- <gl-icon-stub
- name="copy-to-clipboard"
- size="16"
- title="Copy URL"
- />
- </gl-button-stub>
+ />
</b-input-group-append-stub>
</b-input-group-stub>
</div>
@@ -94,18 +89,13 @@ exports[`Clone Dropdown Button rendering matches the snapshot 1`] = `
>
<gl-button-stub
category="tertiary"
+ class="d-inline-flex"
data-clipboard-text="http://foo.bar"
- icon=""
+ icon="copy-to-clipboard"
size="medium"
title="Copy URL"
variant="default"
- >
- <gl-icon-stub
- name="copy-to-clipboard"
- size="16"
- title="Copy URL"
- />
- </gl-button-stub>
+ />
</b-input-group-append-stub>
</b-input-group-stub>
</div>
diff --git a/spec/models/concerns/has_user_type_spec.rb b/spec/models/concerns/has_user_type_spec.rb
index cf12f263bd7..7ec29dde57b 100644
--- a/spec/models/concerns/has_user_type_spec.rb
+++ b/spec/models/concerns/has_user_type_spec.rb
@@ -4,8 +4,8 @@ require 'spec_helper'
describe User do
specify 'types consistency checks', :aggregate_failures do
- expect(described_class::USER_TYPES)
- .to include(*%i[human ghost alert_bot project_bot support_bot service_user visual_review_bot])
+ expect(described_class::USER_TYPES.keys)
+ .to match_array(%w[human ghost alert_bot project_bot support_bot service_user visual_review_bot migration_bot])
expect(described_class::USER_TYPES).to include(*described_class::BOT_USER_TYPES)
expect(described_class::USER_TYPES).to include(*described_class::NON_INTERNAL_USER_TYPES)
expect(described_class::USER_TYPES).to include(*described_class::INTERNAL_USER_TYPES)
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index b05311814d0..7649b09aa8e 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -4584,4 +4584,20 @@ describe User, :do_not_mock_admin_mode do
it_behaves_like 'does not require password to be present'
end
end
+
+ describe '#migration_bot' do
+ it 'creates the user if it does not exist' do
+ expect do
+ described_class.migration_bot
+ end.to change { User.where(user_type: :migration_bot).count }.by(1)
+ end
+
+ it 'does not create a new user if it already exists' do
+ described_class.migration_bot
+
+ expect do
+ described_class.migration_bot
+ end.not_to change { User.count }
+ end
+ end
end
diff --git a/spec/policies/global_policy_spec.rb b/spec/policies/global_policy_spec.rb
index ac7f5db980c..bd0722ce20a 100644
--- a/spec/policies/global_policy_spec.rb
+++ b/spec/policies/global_policy_spec.rb
@@ -6,6 +6,7 @@ describe GlobalPolicy do
include TermsHelper
let_it_be(:project_bot) { create(:user, :project_bot) }
+ let_it_be(:migration_bot) { create(:user, :migration_bot) }
let(:current_user) { create(:user) }
let(:user) { create(:user) }
@@ -155,6 +156,12 @@ describe GlobalPolicy do
it { is_expected.to be_allowed(:access_api) }
end
+ context 'migration bot' do
+ let(:current_user) { migration_bot }
+
+ it { is_expected.not_to be_allowed(:access_api) }
+ end
+
context 'when terms are enforced' do
before do
enforce_terms
@@ -244,6 +251,12 @@ describe GlobalPolicy do
it { is_expected.not_to be_allowed(:receive_notifications) }
end
+
+ context 'migration bot' do
+ let(:current_user) { migration_bot }
+
+ it { is_expected.not_to be_allowed(:receive_notifications) }
+ end
end
describe 'git access' do
@@ -263,6 +276,12 @@ describe GlobalPolicy do
it { is_expected.to be_allowed(:access_git) }
end
+ context 'migration bot' do
+ let(:current_user) { migration_bot }
+
+ it { is_expected.to be_allowed(:access_git) }
+ end
+
describe 'deactivated user' do
before do
current_user.deactivate
@@ -414,6 +433,12 @@ describe GlobalPolicy do
it { is_expected.to be_allowed(:use_slash_commands) }
end
+
+ context 'migration bot' do
+ let(:current_user) { migration_bot }
+
+ it { is_expected.not_to be_allowed(:use_slash_commands) }
+ end
end
describe 'create_snippet' do
@@ -440,5 +465,11 @@ describe GlobalPolicy do
it { is_expected.not_to be_allowed(:log_in) }
end
+
+ context 'migration bot' do
+ let(:current_user) { migration_bot }
+
+ it { is_expected.not_to be_allowed(:log_in) }
+ end
end
end
diff --git a/spec/views/admin/users/_user.html.haml_spec.rb b/spec/views/admin/users/_user.html.haml_spec.rb
index 0eaaa2d5304..de5a291a6f8 100644
--- a/spec/views/admin/users/_user.html.haml_spec.rb
+++ b/spec/views/admin/users/_user.html.haml_spec.rb
@@ -27,6 +27,16 @@ describe 'admin/users/_user.html.haml' do
expect(rendered).not_to have_selector('.table-action-buttons')
end
end
+
+ context 'when showing a `Migration User`' do
+ let(:user) { create(:user, user_type: :migration_bot) }
+
+ it 'does not render action buttons' do
+ render
+
+ expect(rendered).not_to have_selector('.table-action-buttons')
+ end
+ end
end
context 'when showing an external user' do