Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
bddd19ac33
commit
0b679004a6
|
@ -13,8 +13,12 @@ import {
|
|||
const ALLOWED_URL_HASHES = ['#diff', '#note'];
|
||||
|
||||
export default class Tracking {
|
||||
static queuedEvents = [];
|
||||
static nonInitializedQueue = [];
|
||||
static initialized = false;
|
||||
static definitionsLoaded = false;
|
||||
static definitionsManifest = {};
|
||||
static definitionsEventsQueue = [];
|
||||
static definitions = [];
|
||||
|
||||
/**
|
||||
* (Legacy) Determines if tracking is enabled at the user level.
|
||||
|
@ -54,13 +58,71 @@ export default class Tracking {
|
|||
}
|
||||
|
||||
if (!this.initialized) {
|
||||
this.queuedEvents.push(eventData);
|
||||
this.nonInitializedQueue.push(eventData);
|
||||
return false;
|
||||
}
|
||||
|
||||
return dispatchSnowplowEvent(...eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Preloads event definitions.
|
||||
*
|
||||
* @returns {undefined}
|
||||
*/
|
||||
static loadDefinitions() {
|
||||
// TODO: fetch definitions from the server and flush the queue
|
||||
// See https://gitlab.com/gitlab-org/gitlab/-/issues/358256
|
||||
this.definitionsLoaded = true;
|
||||
|
||||
while (this.definitionsEventsQueue.length) {
|
||||
this.dispatchFromDefinition(...this.definitionsEventsQueue.shift());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches a structured event with data from its event definition.
|
||||
*
|
||||
* @param {String} basename
|
||||
* @param {Object} eventData
|
||||
* @returns {undefined|Boolean}
|
||||
*/
|
||||
static definition(basename, eventData = {}) {
|
||||
if (!this.enabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(basename in this.definitionsManifest)) {
|
||||
throw new Error(`Missing Snowplow event definition "${basename}"`);
|
||||
}
|
||||
|
||||
return this.dispatchFromDefinition(basename, eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an event with data from a valid definition and sends it to
|
||||
* Snowplow. If the definitions are not loaded, it pushes the data to a queue.
|
||||
*
|
||||
* @param {String} basename
|
||||
* @param {Object} eventData
|
||||
* @returns {undefined|Boolean}
|
||||
*/
|
||||
static dispatchFromDefinition(basename, eventData) {
|
||||
if (!this.definitionsLoaded) {
|
||||
this.definitionsEventsQueue.push([basename, eventData]);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const eventDefinition = this.definitions.find((definition) => definition.key === basename);
|
||||
|
||||
return this.event(
|
||||
eventData.category ?? eventDefinition.category,
|
||||
eventData.action ?? eventDefinition.action,
|
||||
eventData,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches any event emitted before initialization.
|
||||
*
|
||||
|
@ -69,8 +131,8 @@ export default class Tracking {
|
|||
static flushPendingEvents() {
|
||||
this.initialized = true;
|
||||
|
||||
while (this.queuedEvents.length) {
|
||||
dispatchSnowplowEvent(...this.queuedEvents.shift());
|
||||
while (this.nonInitializedQueue.length) {
|
||||
dispatchSnowplowEvent(...this.nonInitializedQueue.shift());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
- if @page&.persisted?
|
||||
= link_to wiki_page_path(@wiki, @page, action: :history), class: "btn gl-button", role: "button", data: { qa_selector: 'page_history_button' } do
|
||||
= link_to wiki_page_path(@wiki, @page, action: :history), class: "btn gl-button btn-default", role: "button", data: { qa_selector: 'page_history_button' } do
|
||||
= s_("Wiki|Page history")
|
||||
- if can?(current_user, :create_wiki, @wiki.container)
|
||||
= link_to wiki_path(@wiki, action: :new), class: "btn gl-button btn-confirm-secondary", role: "button", data: { qa_selector: 'new_page_button' } do
|
||||
|
|
1
config/metrics/counts_28d/20210216184559_ci_templates_total_unique_counts_monthly.yml
Normal file → Executable file
1
config/metrics/counts_28d/20210216184559_ci_templates_total_unique_counts_monthly.yml
Normal file → Executable file
|
@ -168,6 +168,7 @@ options:
|
|||
- p_ci_templates_kaniko
|
||||
- p_ci_templates_qualys_iac_security
|
||||
- p_ci_templates_liquibase
|
||||
- p_ci_templates_matlab
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
key_path: redis_hll_counters.ci_templates.p_ci_templates_matlab_monthly
|
||||
description: ""
|
||||
product_section: ""
|
||||
product_stage: ""
|
||||
product_group: ""
|
||||
product_category: ""
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: "14.10"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/82914
|
||||
time_frame: 28d
|
||||
data_source: redis_hll
|
||||
data_category: optional
|
||||
instrumentation_class: RedisHLLMetric
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
options:
|
||||
events:
|
||||
- p_ci_templates_matlab
|
1
config/metrics/counts_7d/20210216184557_ci_templates_total_unique_counts_weekly.yml
Normal file → Executable file
1
config/metrics/counts_7d/20210216184557_ci_templates_total_unique_counts_weekly.yml
Normal file → Executable file
|
@ -168,6 +168,7 @@ options:
|
|||
- p_ci_templates_kaniko
|
||||
- p_ci_templates_qualys_iac_security
|
||||
- p_ci_templates_liquibase
|
||||
- p_ci_templates_matlab
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
key_path: redis_hll_counters.ci_templates.p_ci_templates_matlab_weekly
|
||||
description: ""
|
||||
product_section: ""
|
||||
product_stage: ""
|
||||
product_group: ""
|
||||
product_category: ""
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: "14.10"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/82914
|
||||
time_frame: 7d
|
||||
data_source: redis_hll
|
||||
data_category: optional
|
||||
instrumentation_class: RedisHLLMetric
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
options:
|
||||
events:
|
||||
- p_ci_templates_matlab
|
|
@ -430,7 +430,7 @@ to any of the [available reference architectures](#available-reference-architect
|
|||
> - Required domain knowledge: PostgreSQL, HAProxy, shared storage, distributed systems
|
||||
|
||||
GitLab supports [zero-downtime upgrades](../../update/zero_downtime.md).
|
||||
Single GitLab nodes can be updated with only a [few minutes of downtime](../../update/zero_downtime.md#single-node-deployment).
|
||||
Single GitLab nodes can be updated with only a [few minutes of downtime](../../update/index.md#upgrade-based-on-installation-method).
|
||||
To avoid this, we recommend to separate GitLab into several application nodes.
|
||||
As long as at least one of each component is online and capable of handling the instance's usage load, your team's productivity will not be interrupted during the update.
|
||||
|
||||
|
|
|
@ -15,14 +15,12 @@ there are the following requirements:
|
|||
sequence [and leave the database schema in a broken state](https://gitlab.com/gitlab-org/gitlab/-/issues/321542).
|
||||
- You have to use [post-deployment migrations](../development/database/post_deployment_migrations.md).
|
||||
- You are using PostgreSQL. Starting from GitLab 12.1, MySQL is not supported.
|
||||
- Multi-node GitLab instance. Single-node instances may experience brief interruptions
|
||||
[as services restart (Puma in particular)](#single-node-deployment).
|
||||
- You have set up a multi-node GitLab instance. Single-node instances do not support zero-downtime upgrades.
|
||||
|
||||
If you meet all the requirements above, follow these instructions in order. There are three sets of steps, depending on your deployment type:
|
||||
|
||||
| Deployment type | Description |
|
||||
| --------------------------------------------------------------- | ------------------------------------------------ |
|
||||
| [Single-node](#single-node-deployment) | GitLab CE/EE on a single node |
|
||||
| [Gitaly Cluster](#gitaly-cluster) | GitLab CE/EE using HA architecture for Gitaly Cluster |
|
||||
| [Multi-node / PostgreSQL HA](#use-postgresql-ha) | GitLab CE/EE using HA architecture for PostgreSQL |
|
||||
| [Multi-node / Redis HA](#use-redis-ha-using-sentinel) | GitLab CE/EE using HA architecture for Redis |
|
||||
|
@ -87,80 +85,6 @@ migrations this could potentially lead to hours of downtime, depending on the
|
|||
size of your database. To work around this you must use PostgreSQL and
|
||||
meet the other online upgrade requirements mentioned above.
|
||||
|
||||
## Single-node deployment
|
||||
|
||||
WARNING:
|
||||
You can only upgrade one minor release at a time.
|
||||
|
||||
Before following these instructions, note the following **important** information:
|
||||
|
||||
- You can only upgrade one minor release at a time. So from 13.6 to 13.7, not to 13.8.
|
||||
If you attempt more than one minor release, the upgrade may fail.
|
||||
- On single-node Omnibus deployments, updates with no downtime are not possible when
|
||||
using Puma because Puma always requires a complete restart. This is because the
|
||||
[phased restart](https://github.com/puma/puma/blob/master/README.md#clustered-mode)
|
||||
feature of Puma does not work with the way it is configured in GitLab all-in-one
|
||||
packages (cluster-mode with app preloading).
|
||||
- While it is possible to minimize downtime on a single-node instance by following
|
||||
these instructions, **it is not possible to always achieve true zero downtime
|
||||
updates**. Users may see some connections timeout or be refused for a few minutes,
|
||||
depending on which services need to restart.
|
||||
- On Omnibus deployments, the `/etc/gitlab/gitlab.rb` configuration file must **not** have
|
||||
`gitlab_rails['auto_migrate'] = true`.
|
||||
|
||||
1. Create an empty file at `/etc/gitlab/skip-auto-reconfigure`. This prevents upgrades from running `gitlab-ctl reconfigure`, which by default automatically stops GitLab, runs all database migrations, and restarts GitLab.
|
||||
|
||||
```shell
|
||||
sudo touch /etc/gitlab/skip-auto-reconfigure
|
||||
```
|
||||
|
||||
1. Update the GitLab package:
|
||||
|
||||
- For GitLab [Enterprise Edition](https://about.gitlab.com/pricing/):
|
||||
|
||||
```shell
|
||||
# Debian/Ubuntu
|
||||
sudo apt-get update
|
||||
sudo apt-get install gitlab-ee
|
||||
|
||||
# Centos/RHEL
|
||||
sudo yum install gitlab-ee
|
||||
```
|
||||
|
||||
- For GitLab Community Edition:
|
||||
|
||||
```shell
|
||||
# Debian/Ubuntu
|
||||
sudo apt-get update
|
||||
sudo apt-get install gitlab-ce
|
||||
|
||||
# Centos/RHEL
|
||||
sudo yum install gitlab-ce
|
||||
```
|
||||
|
||||
1. To get the regular migrations and latest code in place, run
|
||||
|
||||
```shell
|
||||
sudo SKIP_POST_DEPLOYMENT_MIGRATIONS=true gitlab-ctl reconfigure
|
||||
```
|
||||
|
||||
1. Once the node is updated and `reconfigure` finished successfully, run post-deployment migrations with
|
||||
|
||||
```shell
|
||||
sudo gitlab-rake db:migrate
|
||||
```
|
||||
|
||||
1. Hot reload `puma` and `sidekiq` services
|
||||
|
||||
```shell
|
||||
sudo gitlab-ctl hup puma
|
||||
sudo gitlab-ctl restart sidekiq
|
||||
```
|
||||
|
||||
If you do not want to run zero downtime upgrades in the future, make
|
||||
sure you remove `/etc/gitlab/skip-auto-reconfigure` after
|
||||
you've completed these steps.
|
||||
|
||||
## Multi-node / HA deployment
|
||||
|
||||
WARNING:
|
||||
|
|
|
@ -38,4 +38,4 @@ Merge request approval settings that can be set at an instance level are:
|
|||
See also the following, which are affected by instance-level rules:
|
||||
|
||||
- [Project merge request approval rules](../project/merge_requests/approvals/index.md).
|
||||
- [Group merge request approval rules](../group/index.md#group-approval-rules) available in GitLab 13.9 and later.
|
||||
- [Group merge request approval settings](../group/index.md#group-approval-settings) available in GitLab 13.9 and later.
|
||||
|
|
|
@ -190,6 +190,26 @@ of your GitLab instance (`.gitlab-ci.yml` if not set):
|
|||
|
||||
It is also possible to specify a [custom CI/CD configuration file for a specific project](../../../ci/pipelines/settings.md#specify-a-custom-cicd-configuration-file).
|
||||
|
||||
## Set CI/CD limits
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/352175) in GitLab 14.10.
|
||||
|
||||
You can configure some [CI/CD limits](../../../administration/instance_limits.md#cicd-limits)
|
||||
from the Admin Area:
|
||||
|
||||
1. On the top bar, select **Menu > Admin**.
|
||||
1. On the left sidebar, select **Settings > CI/CD**.
|
||||
1. Expand the **Continuous Integration and Deployment** section.
|
||||
1. In the **CI/CD limits** section, you can set the following limits:
|
||||
- **Maximum number of jobs in a single pipeline**
|
||||
- **Total number of jobs in currently active pipelines**
|
||||
- **Maximum number of active pipelines per project**
|
||||
- **Maximum number of pipeline subscriptions to and from a project**
|
||||
- **Maximum number of pipeline schedules**
|
||||
- **Maximum number of DAG dependencies that a job can have**
|
||||
- **Maximum number of runners registered per group**
|
||||
- **Maximum number of runners registered per project**
|
||||
|
||||
## Enable or disable the pipeline suggestion banner
|
||||
|
||||
By default, a banner displays in merge requests with no pipeline suggesting a
|
||||
|
|
|
@ -796,23 +796,25 @@ The group's new subgroups have push rules set for them based on either:
|
|||
- The closest parent group with push rules defined.
|
||||
- Push rules set at the instance level, if no parent groups have push rules defined.
|
||||
|
||||
## Group approval rules **(PREMIUM)**
|
||||
## Group approval settings **(PREMIUM)**
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/285458) in GitLab 13.9. [Deployed behind the `group_merge_request_approval_settings_feature_flag` flag](../../administration/feature_flags.md), disabled by default.
|
||||
> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/285410) in GitLab 14.5.
|
||||
> - [Feature flag `group_merge_request_approval_settings_feature_flag`](https://gitlab.com/gitlab-org/gitlab/-/issues/343872) removed in GitLab 14.9.
|
||||
|
||||
Group approval rules manage [project merge request approval rules](../project/merge_requests/approvals/index.md)
|
||||
at the top-level group level. These rules [cascade to all projects](../project/merge_requests/approvals/settings.md#settings-cascading)
|
||||
Group approval settings manage [project merge request approval settings](../project/merge_requests/approvals/settings.md)
|
||||
at the top-level group level. These settings [cascade to all projects](../project/merge_requests/approvals/settings.md#settings-cascading)
|
||||
that belong to the group.
|
||||
|
||||
To view the merge request approval rules for a group:
|
||||
To view the merge request approval settings for a group:
|
||||
|
||||
1. Go to the top-level group's **Settings > General** page.
|
||||
1. Expand the **Merge request approvals** section.
|
||||
1. Select the settings you want.
|
||||
1. Select **Save changes**.
|
||||
|
||||
Support for group-level settings for merge request approval rules is tracked in this [epic](https://gitlab.com/groups/gitlab-org/-/epics/4367).
|
||||
|
||||
## Related topics
|
||||
|
||||
- [Group wikis](../project/wiki/index.md)
|
||||
|
|
|
@ -91,49 +91,29 @@ in the template you fetched to customize your configuration.
|
|||
|
||||
## GitLab-managed Terraform state
|
||||
|
||||
[Terraform remote backends](https://www.terraform.io/docs/language/settings/backends/index.html)
|
||||
enable you to store the state file in a remote, shared store. GitLab uses the
|
||||
[Terraform HTTP backend](https://www.terraform.io/docs/language/settings/backends/http.html)
|
||||
to securely store the state files in local storage (the default) or
|
||||
[the remote store of your choice](../../../administration/terraform_state.md).
|
||||
|
||||
The GitLab-managed Terraform state backend can safely store your Terraform state. It spares you from setting up additional remote resources like
|
||||
Amazon S3 or Google Cloud Storage. Its features include:
|
||||
|
||||
- Supporting encryption of the state file both in transit and at rest.
|
||||
- Locking and unlocking state.
|
||||
- Remote Terraform plan and apply execution.
|
||||
|
||||
Read more about setting up and [using GitLab-managed Terraform states](terraform_state.md).
|
||||
Use the [GitLab-managed Terraform state](terraform_state.md) to store state
|
||||
files in local storage or in a remote store of your choice.
|
||||
|
||||
## Terraform module registry
|
||||
|
||||
GitLab can be used as a [Terraform module registry](../../packages/terraform_module_registry/index.md)
|
||||
to create and publish Terraform modules to a private registry specific to your
|
||||
top-level namespace.
|
||||
Use GitLab as a [Terraform module registry](../../packages/terraform_module_registry/index.md)
|
||||
to create and publish Terraform modules to a private registry.
|
||||
|
||||
## Terraform integration in merge requests
|
||||
|
||||
Collaborating around Infrastructure as Code (IaC) changes requires both code changes
|
||||
and expected infrastructure changes to be checked and approved. GitLab provides a
|
||||
solution to help collaboration around Terraform code changes and their expected
|
||||
effects using the merge request pages. This way users don't have to build custom
|
||||
tools or rely on 3rd party solutions to streamline their IaC workflows.
|
||||
|
||||
Read more on setting up and [using the merge request integrations](mr_integration.md).
|
||||
Use the [Terraform integration in merge requests](mr_integration.md)
|
||||
to collaborate on Terraform code changes and Infrastructure-as-Code
|
||||
workflows.
|
||||
|
||||
## The GitLab Terraform provider
|
||||
|
||||
WARNING:
|
||||
NOTE:
|
||||
The GitLab Terraform provider is released separately from GitLab.
|
||||
We are working on migrating the GitLab Terraform provider for GitLab.com.
|
||||
We are working on migrating the GitLab Terraform provider to GitLab.com.
|
||||
|
||||
You can use the [GitLab Terraform provider](https://github.com/gitlabhq/terraform-provider-gitlab)
|
||||
to manage various aspects of GitLab using Terraform. The provider is an open source project,
|
||||
owned by GitLab, where everyone can contribute.
|
||||
|
||||
The [documentation of the provider](https://registry.terraform.io/providers/gitlabhq/gitlab/latest/docs)
|
||||
is available as part of the official Terraform provider documentation.
|
||||
The [GitLab Terraform provider](https://github.com/gitlabhq/terraform-provider-gitlab) is a plugin for Terraform to facilitate
|
||||
managing of GitLab resources such as users, groups, and projects.
|
||||
Its documentation is available on [Terraform](https://registry.terraform.io/providers/gitlabhq/gitlab/latest/docs).
|
||||
|
||||
## Create a new cluster through IaC
|
||||
|
||||
|
|
|
@ -146,7 +146,7 @@ You can also enforce merge request approval settings:
|
|||
|
||||
- At the [instance level](../../../admin_area/merge_requests_approvals.md), which apply to all groups
|
||||
on an instance and, therefore, all projects.
|
||||
- On a [top-level group](../../../group/index.md#group-approval-rules), which apply to all subgroups
|
||||
- On a [top-level group](../../../group/index.md#group-approval-settings), which apply to all subgroups
|
||||
and projects.
|
||||
|
||||
If the settings are inherited by a group or project, they cannot be changed in the group or project
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
# To contribute improvements to CI/CD templates, please follow the Development guide at:
|
||||
# https://docs.gitlab.com/ee/development/cicd/templates.html
|
||||
# This specific template is located at:
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/MATLAB.gitlab-ci.yml
|
||||
|
||||
# Use this template to run MATLAB and Simulink as part of your CI/CD pipeline. The template has three jobs:
|
||||
# - `command`: Run MATLAB scripts, functions, and statements.
|
||||
# - `test`: Run tests authored using the MATLAB unit testing framework or Simulink Test.
|
||||
# - `test_artifacts_job`: Run MATLAB and Simulink tests, and generate test and coverage artifacts.
|
||||
#
|
||||
# You can copy and paste one or more jobs in this template into your `.gitlab-ci.yml` file.
|
||||
# You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword.
|
||||
#
|
||||
# - To run MATLAB and Simulink, MATLAB must be installed on the runner that will run the jobs.
|
||||
# The runner will use the topmost MATLAB version on the system path.
|
||||
# The build fails if the operating system cannot find MATLAB on the path.
|
||||
# - The jobs in this template use the `matlab -batch` syntax to start MATLAB. The `-batch` option is supported
|
||||
# in MATLAB R2019a and later.
|
||||
|
||||
# The `command` runs MATLAB scripts, functions, and statements. To use the job in your pipeline,
|
||||
# substitute `command` with the code you want to run.
|
||||
#
|
||||
command:
|
||||
script: matlab -batch command
|
||||
|
||||
# If the value of `command` is the name of a MATLAB script or function, do not specify the file extension.
|
||||
# For example, to run a script named `myscript.m` in the root of your repository, specify the `command` like this:
|
||||
#
|
||||
# "myscript"
|
||||
#
|
||||
# If you specify more than one script, function, or statement, use a comma or semicolon to separate them.
|
||||
# For example, to run `myscript.m` in a folder named `myfolder` located in the root of the repository,
|
||||
# you can specify the `command` like this:
|
||||
#
|
||||
# "addpath('myfolder'), myscript"
|
||||
#
|
||||
# MATLAB exits with exit code 0 if the specified script, function, or statement executes successfully without
|
||||
# error. Otherwise, MATLAB terminates with a nonzero exit code, which causes the job to fail. To have the
|
||||
# job fail in certain conditions, use the [`assert`][1] or [`error`][2] functions.
|
||||
#
|
||||
# [1] https://www.mathworks.com/help/matlab/ref/assert.html
|
||||
# [2] https://www.mathworks.com/help/matlab/ref/error.html
|
||||
|
||||
# The `test` runs the MATLAB and Simulink tests in your project. It calls the [`runtests`][3] function
|
||||
# to run the tests and then the [`assertSuccess`][4] method to fail the job if any of the tests fail.
|
||||
#
|
||||
test:
|
||||
script: matlab -batch "results = runtests('IncludeSubfolders',true), assertSuccess(results);"
|
||||
|
||||
# By default, the job includes any files in your [MATLAB Project][5] that have a `Test` label. If your repository
|
||||
# does not have a MATLAB project, then the job includes all tests in the root of your repository or in any of
|
||||
# its subfolders.
|
||||
#
|
||||
# [3] https://www.mathworks.com/help/matlab/ref/runtests.html
|
||||
# [4] https://www.mathworks.com/help/matlab/ref/matlab.unittest.testresult.assertsuccess.html
|
||||
# [5] https://www.mathworks.com/help/matlab/projects.html
|
||||
|
||||
# The `test_artifacts_job` runs your tests and additionally generates test and coverage artifacts.
|
||||
# It uses the plugin classes in the [`matlab.unittest.plugins`][6] package to generate a JUnit test results
|
||||
# report and a Cobertura code coverage report. Like the `run_tests` job, this job runs all the tests in your
|
||||
# project and fails the build if any of the tests fail.
|
||||
#
|
||||
test_artifacts_job:
|
||||
script: |
|
||||
matlab -batch "
|
||||
import matlab.unittest.TestRunner
|
||||
import matlab.unittest.Verbosity
|
||||
import matlab.unittest.plugins.CodeCoveragePlugin
|
||||
import matlab.unittest.plugins.XMLPlugin
|
||||
import matlab.unittest.plugins.codecoverage.CoberturaFormat
|
||||
|
||||
suite = testsuite(pwd,'IncludeSubfolders',true);
|
||||
|
||||
[~,~] = mkdir('artifacts');
|
||||
|
||||
runner = TestRunner.withTextOutput('OutputDetail',Verbosity.Detailed);
|
||||
runner.addPlugin(XMLPlugin.producingJUnitFormat('artifacts/results.xml'))
|
||||
runner.addPlugin(CodeCoveragePlugin.forFolder(pwd,'IncludingSubfolders',true, ...
|
||||
'Producing',CoberturaFormat('artifacts/cobertura.xml')))
|
||||
|
||||
results = runner.run(suite)
|
||||
assertSuccess(results);"
|
||||
|
||||
artifacts:
|
||||
reports:
|
||||
junit: "./artifacts/results.xml"
|
||||
cobertura: "./artifacts/cobertura.xml"
|
||||
paths:
|
||||
- "./artifacts"
|
||||
|
||||
# You can modify the contents of the `test_artifacts_job` depending on your goals. For more
|
||||
# information on how to customize the test runner and generate various test and coverage artifacts,
|
||||
# see [Generate Artifacts Using MATLAB Unit Test Plugins][7].
|
||||
#
|
||||
# [6] https://www.mathworks.com/help/matlab/ref/matlab.unittest.plugins-package.html
|
||||
# [7] https://www.mathworks.com/help/matlab/matlab_prog/generate-artifacts-using-matlab-unit-test-plugins.html
|
|
@ -619,3 +619,7 @@
|
|||
category: ci_templates
|
||||
redis_slot: ci_templates
|
||||
aggregation: weekly
|
||||
- name: p_ci_templates_matlab
|
||||
category: ci_templates
|
||||
redis_slot: ci_templates
|
||||
aggregation: weekly
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe "Admin Runners" do
|
||||
include StubENV
|
||||
include Spec::Support::Helpers::Features::RunnersHelpers
|
||||
|
||||
let_it_be(:admin) { create(:admin) }
|
||||
|
||||
before do
|
||||
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
|
||||
admin = create(:admin)
|
||||
sign_in(admin)
|
||||
gitlab_enable_admin_mode_sign_in(admin)
|
||||
|
||||
|
@ -20,48 +20,55 @@ RSpec.describe "Admin Runners" do
|
|||
let_it_be(:namespace) { create(:namespace) }
|
||||
let_it_be(:project) { create(:project, namespace: namespace, creator: user) }
|
||||
|
||||
context "runners registration" do
|
||||
before do
|
||||
visit admin_runners_path
|
||||
end
|
||||
|
||||
it_behaves_like "shows and resets runner registration token" do
|
||||
let(:dropdown_text) { 'Register an instance runner' }
|
||||
let(:registration_token) { Gitlab::CurrentSettings.runners_registration_token }
|
||||
end
|
||||
end
|
||||
|
||||
context "when there are runners" do
|
||||
it 'has all necessary texts' do
|
||||
context "with an instance runner" do
|
||||
let!(:instance_runner) { create(:ci_runner, :instance) }
|
||||
|
||||
before do
|
||||
visit admin_runners_path
|
||||
end
|
||||
|
||||
it_behaves_like 'shows runner in list' do
|
||||
let(:runner) { instance_runner }
|
||||
end
|
||||
|
||||
it_behaves_like 'pauses, resumes and deletes a runner' do
|
||||
let(:runner) { instance_runner }
|
||||
end
|
||||
|
||||
it 'shows an instance badge' do
|
||||
within_runner_row(instance_runner.id) do
|
||||
expect(page).to have_selector '.badge', text: 'shared'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with multiple runners" do
|
||||
before do
|
||||
create(:ci_runner, :instance, created_at: 1.year.ago, contacted_at: Time.zone.now)
|
||||
create(:ci_runner, :instance, created_at: 1.year.ago, contacted_at: 1.week.ago)
|
||||
create(:ci_runner, :instance, created_at: 1.year.ago, contacted_at: 1.year.ago)
|
||||
|
||||
visit admin_runners_path
|
||||
end
|
||||
|
||||
it 'has all necessary texts' do
|
||||
expect(page).to have_text "Register an instance runner"
|
||||
expect(page).to have_text "Online runners 1"
|
||||
expect(page).to have_text "Offline runners 2"
|
||||
expect(page).to have_text "Stale runners 1"
|
||||
end
|
||||
|
||||
it 'with an instance runner shows an instance badge' do
|
||||
runner = create(:ci_runner, :instance)
|
||||
|
||||
visit admin_runners_path
|
||||
|
||||
within "[data-testid='runner-row-#{runner.id}']" do
|
||||
expect(page).to have_selector '.badge', text: 'shared'
|
||||
end
|
||||
end
|
||||
|
||||
it 'with a group runner shows a group badge' do
|
||||
runner = create(:ci_runner, :group, groups: [group])
|
||||
|
||||
visit admin_runners_path
|
||||
|
||||
within "[data-testid='runner-row-#{runner.id}']" do
|
||||
expect(page).to have_selector '.badge', text: 'group'
|
||||
end
|
||||
end
|
||||
|
||||
it 'with a project runner shows a project badge' do
|
||||
runner = create(:ci_runner, :project, projects: [project])
|
||||
|
||||
visit admin_runners_path
|
||||
|
||||
within "[data-testid='runner-row-#{runner.id}']" do
|
||||
expect(page).to have_selector '.badge', text: 'specific'
|
||||
end
|
||||
end
|
||||
|
||||
it 'shows a job count' do
|
||||
|
@ -72,44 +79,8 @@ RSpec.describe "Admin Runners" do
|
|||
|
||||
visit admin_runners_path
|
||||
|
||||
within "[data-testid='runner-row-#{runner.id}'] [data-label='Jobs']" do
|
||||
expect(page).to have_content '2'
|
||||
end
|
||||
end
|
||||
|
||||
describe 'delete runner' do
|
||||
let!(:runner) { create(:ci_runner, description: 'runner-foo') }
|
||||
|
||||
before do
|
||||
visit admin_runners_path
|
||||
|
||||
within "[data-testid='runner-row-#{runner.id}']" do
|
||||
click_on 'Delete runner'
|
||||
end
|
||||
end
|
||||
|
||||
it 'shows a confirmation modal' do
|
||||
expect(page).to have_text "Delete runner ##{runner.id} (#{runner.short_sha})?"
|
||||
expect(page).to have_text "Are you sure you want to continue?"
|
||||
end
|
||||
|
||||
it 'deletes a runner' do
|
||||
within '.modal' do
|
||||
click_on 'Delete runner'
|
||||
end
|
||||
|
||||
expect(page.find('.gl-toast')).to have_text(/Runner .+ deleted/)
|
||||
expect(page).not_to have_content 'runner-foo'
|
||||
end
|
||||
|
||||
it 'cancels runner deletion' do
|
||||
within '.modal' do
|
||||
click_on 'Cancel'
|
||||
end
|
||||
|
||||
wait_for_requests
|
||||
|
||||
expect(page).to have_content 'runner-foo'
|
||||
within_runner_row(runner.id) do
|
||||
expect(find("[data-label='Jobs']")).to have_content '2'
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -249,7 +220,7 @@ RSpec.describe "Admin Runners" do
|
|||
expect(page).not_to have_content 'runner-paused'
|
||||
expect(page).to have_content 'runner-never-contacted'
|
||||
|
||||
within "[data-testid='runner-row-#{never_contacted.id}']" do
|
||||
within_runner_row(never_contacted.id) do
|
||||
expect(page).to have_selector '.badge', text: 'never contacted'
|
||||
end
|
||||
end
|
||||
|
@ -447,15 +418,7 @@ RSpec.describe "Admin Runners" do
|
|||
visit admin_runners_path
|
||||
end
|
||||
|
||||
it 'has all necessary texts including no runner message' do
|
||||
expect(page).to have_text "Register an instance runner"
|
||||
|
||||
expect(page).to have_text "Online runners 0"
|
||||
expect(page).to have_text "Offline runners 0"
|
||||
expect(page).to have_text "Stale runners 0"
|
||||
|
||||
expect(page).to have_text 'No runners found'
|
||||
end
|
||||
it_behaves_like "shows no runners"
|
||||
|
||||
it 'shows tabs with total counts equal to 0' do
|
||||
expect(page).to have_link('All 0')
|
||||
|
@ -484,17 +447,6 @@ RSpec.describe "Admin Runners" do
|
|||
expect(page).to have_current_path(admin_runners_path('paused[]': 'true') )
|
||||
end
|
||||
end
|
||||
|
||||
describe "runners registration" do
|
||||
before do
|
||||
visit admin_runners_path
|
||||
end
|
||||
|
||||
it_behaves_like "shows and resets runner registration token" do
|
||||
let(:dropdown_text) { 'Register an instance runner' }
|
||||
let(:registration_token) { Gitlab::CurrentSettings.runners_registration_token }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "Runner show page", :js do
|
||||
|
@ -644,57 +596,4 @@ RSpec.describe "Admin Runners" do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def search_bar_selector
|
||||
'[data-testid="runners-filtered-search"]'
|
||||
end
|
||||
|
||||
# The filters must be clicked first to be able to receive events
|
||||
# See: https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1493
|
||||
def focus_filtered_search
|
||||
page.within(search_bar_selector) do
|
||||
page.find('.gl-filtered-search-term-token').click
|
||||
end
|
||||
end
|
||||
|
||||
def input_filtered_search_keys(search_term)
|
||||
focus_filtered_search
|
||||
|
||||
page.within(search_bar_selector) do
|
||||
page.find('input').send_keys(search_term)
|
||||
click_on 'Search'
|
||||
end
|
||||
|
||||
wait_for_requests
|
||||
end
|
||||
|
||||
def open_filtered_search_suggestions(filter)
|
||||
focus_filtered_search
|
||||
|
||||
page.within(search_bar_selector) do
|
||||
click_on filter
|
||||
end
|
||||
|
||||
wait_for_requests
|
||||
end
|
||||
|
||||
def input_filtered_search_filter_is_only(filter, value)
|
||||
focus_filtered_search
|
||||
|
||||
page.within(search_bar_selector) do
|
||||
click_on filter
|
||||
|
||||
# For OPERATOR_IS_ONLY, clicking the filter
|
||||
# immediately preselects "=" operator
|
||||
|
||||
page.find('input').send_keys(value)
|
||||
page.find('input').send_keys(:enter)
|
||||
|
||||
click_on 'Search'
|
||||
end
|
||||
|
||||
wait_for_requests
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,10 +3,11 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe "Group Runners" do
|
||||
include Spec::Support::Helpers::Features::RunnersHelpers
|
||||
|
||||
let_it_be(:group_owner) { create(:user) }
|
||||
let_it_be(:group) { create(:group) }
|
||||
|
||||
let!(:group_registration_token) { group.runners_token }
|
||||
let_it_be(:project) { create(:project, group: group) }
|
||||
|
||||
before do
|
||||
group.add_owner(group_owner)
|
||||
|
@ -14,7 +15,9 @@ RSpec.describe "Group Runners" do
|
|||
end
|
||||
|
||||
describe "Group runners page", :js do
|
||||
describe "runners registration" do
|
||||
let!(:group_registration_token) { group.runners_token }
|
||||
|
||||
context "runners registration" do
|
||||
before do
|
||||
visit group_runners_path(group)
|
||||
end
|
||||
|
@ -24,5 +27,142 @@ RSpec.describe "Group Runners" do
|
|||
let(:registration_token) { group_registration_token }
|
||||
end
|
||||
end
|
||||
|
||||
context "with no runners" do
|
||||
before do
|
||||
visit group_runners_path(group)
|
||||
end
|
||||
|
||||
it_behaves_like "shows no runners"
|
||||
|
||||
it 'shows tabs with total counts equal to 0' do
|
||||
expect(page).to have_link('All 0')
|
||||
expect(page).to have_link('Group 0')
|
||||
expect(page).to have_link('Project 0')
|
||||
end
|
||||
end
|
||||
|
||||
context "with an online group runner" do
|
||||
let!(:group_runner) do
|
||||
create(:ci_runner, :group, groups: [group], description: 'runner-foo', contacted_at: Time.zone.now)
|
||||
end
|
||||
|
||||
before do
|
||||
visit group_runners_path(group)
|
||||
end
|
||||
|
||||
it_behaves_like 'shows runner in list' do
|
||||
let(:runner) { group_runner }
|
||||
end
|
||||
|
||||
it_behaves_like 'pauses, resumes and deletes a runner' do
|
||||
let(:runner) { group_runner }
|
||||
end
|
||||
|
||||
it 'shows a group badge' do
|
||||
within_runner_row(group_runner.id) do
|
||||
expect(page).to have_selector '.badge', text: 'group'
|
||||
end
|
||||
end
|
||||
|
||||
it 'can edit runner information' do
|
||||
within_runner_row(group_runner.id) do
|
||||
expect(find_link('Edit')[:href]).to end_with(edit_group_runner_path(group, group_runner))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with an online project runner" do
|
||||
let!(:project_runner) do
|
||||
create(:ci_runner, :project, projects: [project], description: 'runner-bar', contacted_at: Time.zone.now)
|
||||
end
|
||||
|
||||
before do
|
||||
visit group_runners_path(group)
|
||||
end
|
||||
|
||||
it_behaves_like 'shows runner in list' do
|
||||
let(:runner) { project_runner }
|
||||
end
|
||||
|
||||
it_behaves_like 'pauses, resumes and deletes a runner' do
|
||||
let(:runner) { project_runner }
|
||||
end
|
||||
|
||||
it 'shows a project (specific) badge' do
|
||||
within_runner_row(project_runner.id) do
|
||||
expect(page).to have_selector '.badge', text: 'specific'
|
||||
end
|
||||
end
|
||||
|
||||
it 'can edit runner information' do
|
||||
within_runner_row(project_runner.id) do
|
||||
expect(find_link('Edit')[:href]).to end_with(edit_group_runner_path(group, project_runner))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a multi-project runner' do
|
||||
let(:project) { create(:project, group: group) }
|
||||
let(:project_2) { create(:project, group: group) }
|
||||
let!(:runner) { create(:ci_runner, :project, projects: [project, project_2], description: 'group-runner') }
|
||||
|
||||
it 'user cannot remove the project runner' do
|
||||
visit group_runners_path(group)
|
||||
|
||||
within_runner_row(runner.id) do
|
||||
expect(page).to have_button 'Delete runner', disabled: true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'filtered search' do
|
||||
before do
|
||||
visit group_runners_path(group)
|
||||
end
|
||||
|
||||
it 'allows user to search by paused and status', :js do
|
||||
focus_filtered_search
|
||||
|
||||
page.within(search_bar_selector) do
|
||||
expect(page).to have_link('Paused')
|
||||
expect(page).to have_content('Status')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "Group runner edit page", :js do
|
||||
let!(:runner) do
|
||||
create(:ci_runner, :group, groups: [group], description: 'runner-foo', contacted_at: Time.zone.now)
|
||||
end
|
||||
|
||||
it 'user edits the runner to be protected' do
|
||||
visit edit_group_runner_path(group, runner)
|
||||
|
||||
expect(page.find_field('runner[access_level]')).not_to be_checked
|
||||
|
||||
check 'runner_access_level'
|
||||
click_button 'Save changes'
|
||||
|
||||
expect(page).to have_content 'Protected Yes'
|
||||
end
|
||||
|
||||
context 'when a runner has a tag' do
|
||||
before do
|
||||
runner.update!(tag_list: ['tag'])
|
||||
end
|
||||
|
||||
it 'user edits runner not to run untagged jobs' do
|
||||
visit edit_group_runner_path(group, runner)
|
||||
|
||||
expect(page.find_field('runner[run_untagged]')).to be_checked
|
||||
|
||||
uncheck 'runner_run_untagged'
|
||||
click_button 'Save changes'
|
||||
|
||||
expect(page).to have_content 'Can run untagged jobs No'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -129,6 +129,72 @@ describe('Tracking', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('.definition', () => {
|
||||
const TEST_VALID_BASENAME = '202108302307_default_click_button';
|
||||
const TEST_EVENT_DATA = { category: undefined, action: 'click_button' };
|
||||
let eventSpy;
|
||||
let dispatcherSpy;
|
||||
|
||||
beforeAll(() => {
|
||||
Tracking.definitionsManifest = {
|
||||
'202108302307_default_click_button': 'config/events/202108302307_default_click_button.yml',
|
||||
};
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
eventSpy = jest.spyOn(Tracking, 'event');
|
||||
dispatcherSpy = jest.spyOn(Tracking, 'dispatchFromDefinition');
|
||||
});
|
||||
|
||||
it('throws an error if the definition does not exists', () => {
|
||||
const basename = '20220230_default_missing_definition';
|
||||
const expectedError = new Error(`Missing Snowplow event definition "${basename}"`);
|
||||
|
||||
expect(() => Tracking.definition(basename)).toThrow(expectedError);
|
||||
});
|
||||
|
||||
it('dispatches an event from a definition present in the manifest', () => {
|
||||
Tracking.definition(TEST_VALID_BASENAME);
|
||||
|
||||
expect(dispatcherSpy).toHaveBeenCalledWith(TEST_VALID_BASENAME, {});
|
||||
});
|
||||
|
||||
it('push events to the queue if not loaded', () => {
|
||||
Tracking.definitionsLoaded = false;
|
||||
Tracking.definitionsEventsQueue = [];
|
||||
|
||||
const dispatched = Tracking.definition(TEST_VALID_BASENAME);
|
||||
|
||||
expect(dispatched).toBe(false);
|
||||
expect(Tracking.definitionsEventsQueue[0]).toStrictEqual([TEST_VALID_BASENAME, {}]);
|
||||
expect(eventSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('dispatch events when the definition is loaded', () => {
|
||||
const definition = { key: TEST_VALID_BASENAME, ...TEST_EVENT_DATA };
|
||||
Tracking.definitions = [{ ...definition }];
|
||||
Tracking.definitionsEventsQueue = [];
|
||||
Tracking.definitionsLoaded = true;
|
||||
|
||||
const dispatched = Tracking.definition(TEST_VALID_BASENAME);
|
||||
|
||||
expect(dispatched).not.toBe(false);
|
||||
expect(Tracking.definitionsEventsQueue).toEqual([]);
|
||||
expect(eventSpy).toHaveBeenCalledWith(definition.category, definition.action, {});
|
||||
});
|
||||
|
||||
it('lets defined event data takes precedence', () => {
|
||||
const definition = { key: TEST_VALID_BASENAME, category: undefined, action: 'click_button' };
|
||||
const eventData = { category: TEST_CATEGORY };
|
||||
Tracking.definitions = [{ ...definition }];
|
||||
Tracking.definitionsLoaded = true;
|
||||
|
||||
Tracking.definition(TEST_VALID_BASENAME, eventData);
|
||||
|
||||
expect(eventSpy).toHaveBeenCalledWith(TEST_CATEGORY, definition.action, eventData);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.enableFormTracking', () => {
|
||||
it('tells snowplow to enable form tracking, with only explicit contexts', () => {
|
||||
const config = { forms: { allow: ['form-class1'] }, fields: { allow: ['input-class1'] } };
|
||||
|
|
|
@ -6,11 +6,15 @@ RSpec.describe Gitlab::Auth::OAuth::User do
|
|||
include LdapHelpers
|
||||
|
||||
let(:oauth_user) { described_class.new(auth_hash) }
|
||||
let(:oauth_user_2) { described_class.new(auth_hash_2) }
|
||||
let(:gl_user) { oauth_user.gl_user }
|
||||
let(:gl_user_2) { oauth_user_2.gl_user }
|
||||
let(:uid) { 'my-uid' }
|
||||
let(:uid_2) { 'my-uid-2' }
|
||||
let(:dn) { 'uid=user1,ou=people,dc=example' }
|
||||
let(:provider) { 'my-provider' }
|
||||
let(:auth_hash) { OmniAuth::AuthHash.new(uid: uid, provider: provider, info: info_hash) }
|
||||
let(:auth_hash_2) { OmniAuth::AuthHash.new(uid: uid_2, provider: provider, info: info_hash) }
|
||||
let(:info_hash) do
|
||||
{
|
||||
nickname: '-john+gitlab-ETC%.git@gmail.com',
|
||||
|
@ -24,6 +28,7 @@ RSpec.describe Gitlab::Auth::OAuth::User do
|
|||
end
|
||||
|
||||
let(:ldap_user) { Gitlab::Auth::Ldap::Person.new(Net::LDAP::Entry.new, 'ldapmain') }
|
||||
let(:ldap_user_2) { Gitlab::Auth::Ldap::Person.new(Net::LDAP::Entry.new, 'ldapmain') }
|
||||
|
||||
describe '.find_by_uid_and_provider' do
|
||||
let(:dn) { 'CN=John Åström, CN=Users, DC=Example, DC=com' }
|
||||
|
@ -46,12 +51,12 @@ RSpec.describe Gitlab::Auth::OAuth::User do
|
|||
let!(:existing_user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'my-provider') }
|
||||
|
||||
it "finds an existing user based on uid and provider (facebook)" do
|
||||
expect( oauth_user.persisted? ).to be_truthy
|
||||
expect(oauth_user.persisted?).to be_truthy
|
||||
end
|
||||
|
||||
it 'returns false if user is not found in database' do
|
||||
allow(auth_hash).to receive(:uid).and_return('non-existing')
|
||||
expect( oauth_user.persisted? ).to be_falsey
|
||||
expect(oauth_user.persisted?).to be_falsey
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -78,15 +83,27 @@ RSpec.describe Gitlab::Auth::OAuth::User do
|
|||
context 'when signup is disabled' do
|
||||
before do
|
||||
stub_application_setting signup_enabled: false
|
||||
stub_omniauth_config(allow_single_sign_on: [provider])
|
||||
end
|
||||
|
||||
it 'creates the user' do
|
||||
stub_omniauth_config(allow_single_sign_on: [provider])
|
||||
|
||||
oauth_user.save # rubocop:disable Rails/SaveBang
|
||||
|
||||
expect(gl_user).to be_persisted
|
||||
end
|
||||
|
||||
it 'does not repeat the default user password' do
|
||||
oauth_user.save # rubocop:disable Rails/SaveBang
|
||||
oauth_user_2.save # rubocop:disable Rails/SaveBang
|
||||
|
||||
expect(gl_user.password).not_to eq(gl_user_2.password)
|
||||
end
|
||||
|
||||
it 'has the password length within specified range' do
|
||||
oauth_user.save # rubocop:disable Rails/SaveBang
|
||||
|
||||
expect(gl_user.password.length).to be_between(Devise.password_length.min, Devise.password_length.max)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user confirmation email is enabled' do
|
||||
|
@ -330,6 +347,12 @@ RSpec.describe Gitlab::Auth::OAuth::User do
|
|||
allow(ldap_user).to receive(:name) { 'John Doe' }
|
||||
allow(ldap_user).to receive(:email) { ['johndoe@example.com', 'john2@example.com'] }
|
||||
allow(ldap_user).to receive(:dn) { dn }
|
||||
|
||||
allow(ldap_user_2).to receive(:uid) { uid_2 }
|
||||
allow(ldap_user_2).to receive(:username) { uid_2 }
|
||||
allow(ldap_user_2).to receive(:name) { 'Beck Potter' }
|
||||
allow(ldap_user_2).to receive(:email) { ['beckpotter@example.com', 'beck2@example.com'] }
|
||||
allow(ldap_user_2).to receive(:dn) { dn }
|
||||
end
|
||||
|
||||
context "and no account for the LDAP user" do
|
||||
|
@ -340,6 +363,14 @@ RSpec.describe Gitlab::Auth::OAuth::User do
|
|||
oauth_user.save # rubocop:disable Rails/SaveBang
|
||||
end
|
||||
|
||||
it 'does not repeat the default user password' do
|
||||
allow(Gitlab::Auth::Ldap::Person).to receive(:find_by_uid).and_return(ldap_user_2)
|
||||
|
||||
oauth_user_2.save # rubocop:disable Rails/SaveBang
|
||||
|
||||
expect(gl_user.password).not_to eq(gl_user_2.password)
|
||||
end
|
||||
|
||||
it "creates a user with dual LDAP and omniauth identities" do
|
||||
expect(gl_user).to be_valid
|
||||
expect(gl_user.username).to eql uid
|
||||
|
@ -609,6 +640,7 @@ RSpec.describe Gitlab::Auth::OAuth::User do
|
|||
|
||||
context 'signup with SAML' do
|
||||
let(:provider) { 'saml' }
|
||||
let(:block_auto_created_users) { false }
|
||||
|
||||
before do
|
||||
stub_omniauth_config({
|
||||
|
@ -625,6 +657,13 @@ RSpec.describe Gitlab::Auth::OAuth::User do
|
|||
it_behaves_like 'not being blocked on creation' do
|
||||
let(:block_auto_created_users) { false }
|
||||
end
|
||||
|
||||
it 'does not repeat the default user password' do
|
||||
oauth_user.save # rubocop:disable Rails/SaveBang
|
||||
oauth_user_2.save # rubocop:disable Rails/SaveBang
|
||||
|
||||
expect(gl_user.password).not_to eq(gl_user_2.password)
|
||||
end
|
||||
end
|
||||
|
||||
context 'signup with omniauth only' do
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'MATLAB.gitlab-ci.yml' do
|
||||
subject(:template) { Gitlab::Template::GitlabCiYmlTemplate.find('MATLAB') }
|
||||
|
||||
describe 'the created pipeline' do
|
||||
let_it_be(:project) { create(:project, :auto_devops, :custom_repo, files: { 'README.md' => '' }) }
|
||||
|
||||
let(:user) { project.first_owner }
|
||||
let(:default_branch) { 'master' }
|
||||
let(:pipeline_branch) { default_branch }
|
||||
let(:service) { Ci::CreatePipelineService.new(project, user, ref: pipeline_branch ) }
|
||||
let(:pipeline) { service.execute!(:push).payload }
|
||||
let(:build_names) { pipeline.builds.pluck(:name) }
|
||||
|
||||
before do
|
||||
stub_ci_pipeline_yaml_file(template.content)
|
||||
end
|
||||
|
||||
it 'creates all jobs' do
|
||||
expect(build_names).to include('command', 'test', 'test_artifacts_job')
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,68 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Spec
|
||||
module Support
|
||||
module Helpers
|
||||
module Features
|
||||
module RunnersHelpers
|
||||
def within_runner_row(runner_id)
|
||||
within "[data-testid='runner-row-#{runner_id}']" do
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
||||
def search_bar_selector
|
||||
'[data-testid="runners-filtered-search"]'
|
||||
end
|
||||
|
||||
# The filters must be clicked first to be able to receive events
|
||||
# See: https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1493
|
||||
def focus_filtered_search
|
||||
page.within(search_bar_selector) do
|
||||
page.find('.gl-filtered-search-term-token').click
|
||||
end
|
||||
end
|
||||
|
||||
def input_filtered_search_keys(search_term)
|
||||
focus_filtered_search
|
||||
|
||||
page.within(search_bar_selector) do
|
||||
page.find('input').send_keys(search_term)
|
||||
click_on 'Search'
|
||||
end
|
||||
|
||||
wait_for_requests
|
||||
end
|
||||
|
||||
def open_filtered_search_suggestions(filter)
|
||||
focus_filtered_search
|
||||
|
||||
page.within(search_bar_selector) do
|
||||
click_on filter
|
||||
end
|
||||
|
||||
wait_for_requests
|
||||
end
|
||||
|
||||
def input_filtered_search_filter_is_only(filter, value)
|
||||
focus_filtered_search
|
||||
|
||||
page.within(search_bar_selector) do
|
||||
click_on filter
|
||||
|
||||
# For OPERATOR_IS_ONLY, clicking the filter
|
||||
# immediately preselects "=" operator
|
||||
|
||||
page.find('input').send_keys(value)
|
||||
page.find('input').send_keys(:enter)
|
||||
|
||||
click_on 'Search'
|
||||
end
|
||||
|
||||
wait_for_requests
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
RSpec.shared_examples 'shows and resets runner registration token' do
|
||||
include Spec::Support::Helpers::ModalHelpers
|
||||
include Spec::Support::Helpers::Features::RunnersHelpers
|
||||
|
||||
before do
|
||||
click_on dropdown_text
|
||||
|
@ -60,3 +61,81 @@ RSpec.shared_examples 'shows and resets runner registration token' do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.shared_examples 'shows no runners' do
|
||||
it 'shows counts with 0' do
|
||||
expect(page).to have_text "Online runners 0"
|
||||
expect(page).to have_text "Offline runners 0"
|
||||
expect(page).to have_text "Stale runners 0"
|
||||
end
|
||||
|
||||
it 'shows "no runners" message' do
|
||||
expect(page).to have_text 'No runners found'
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.shared_examples 'shows runner in list' do
|
||||
it 'does not show empty state' do
|
||||
expect(page).not_to have_content 'No runners found'
|
||||
end
|
||||
|
||||
it 'shows runner row' do
|
||||
within_runner_row(runner.id) do
|
||||
expect(page).to have_text "##{runner.id}"
|
||||
expect(page).to have_text runner.short_sha
|
||||
expect(page).to have_text runner.description
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.shared_examples 'pauses, resumes and deletes a runner' do
|
||||
include Spec::Support::Helpers::ModalHelpers
|
||||
|
||||
it 'pauses and resumes runner' do
|
||||
within_runner_row(runner.id) do
|
||||
click_button "Pause"
|
||||
|
||||
expect(page).to have_text 'paused'
|
||||
expect(page).to have_button 'Resume'
|
||||
expect(page).not_to have_button 'Pause'
|
||||
|
||||
click_button "Resume"
|
||||
|
||||
expect(page).not_to have_text 'paused'
|
||||
expect(page).not_to have_button 'Resume'
|
||||
expect(page).to have_button 'Pause'
|
||||
end
|
||||
end
|
||||
|
||||
describe 'deletes runner' do
|
||||
before do
|
||||
within_runner_row(runner.id) do
|
||||
click_on 'Delete runner'
|
||||
end
|
||||
end
|
||||
|
||||
it 'shows a confirmation modal' do
|
||||
expect(page).to have_text "Delete runner ##{runner.id} (#{runner.short_sha})?"
|
||||
expect(page).to have_text "Are you sure you want to continue?"
|
||||
end
|
||||
|
||||
it 'deletes a runner' do
|
||||
within_modal do
|
||||
click_on 'Delete runner'
|
||||
end
|
||||
|
||||
expect(page.find('.gl-toast')).to have_text(/Runner .+ deleted/)
|
||||
expect(page).not_to have_content runner.description
|
||||
end
|
||||
|
||||
it 'cancels runner deletion' do
|
||||
within_modal do
|
||||
click_on 'Cancel'
|
||||
end
|
||||
|
||||
wait_for_requests
|
||||
|
||||
expect(page).to have_content runner.description
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue