Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
40cdcdd45b
commit
fe289cff8b
57 changed files with 620 additions and 416 deletions
|
@ -404,7 +404,6 @@ RSpec/LeakyConstantDeclaration:
|
|||
- 'spec/support/shared_examples/quick_actions/issuable/issuable_quick_actions_shared_examples.rb'
|
||||
- 'spec/support_specs/helpers/active_record/query_recorder_spec.rb'
|
||||
- 'spec/support_specs/matchers/exceed_query_limit_helpers_spec.rb'
|
||||
- 'spec/uploaders/content_type_whitelist_spec.rb'
|
||||
- 'spec/uploaders/records_uploads_spec.rb'
|
||||
|
||||
RSpec/EmptyLineAfterHook:
|
||||
|
|
|
@ -13,7 +13,7 @@ import {
|
|||
} from '@gitlab/ui';
|
||||
import createFlash from '~/flash';
|
||||
import { s__ } from '~/locale';
|
||||
import { joinPaths } from '~/lib/utils/url_utility';
|
||||
import { joinPaths, visitUrl } from '~/lib/utils/url_utility';
|
||||
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
|
||||
import getAlerts from '../graphql/queries/getAlerts.query.graphql';
|
||||
import { ALERTS_STATUS, ALERTS_STATUS_TABS, ALERTS_SEVERITY_LABELS } from '../constants';
|
||||
|
@ -165,6 +165,9 @@ export default {
|
|||
projectPath: this.projectPath,
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
this.$apollo.queries.alerts.refetch();
|
||||
})
|
||||
.catch(() => {
|
||||
createFlash(
|
||||
s__(
|
||||
|
@ -173,13 +176,12 @@ export default {
|
|||
);
|
||||
});
|
||||
},
|
||||
handleRowClick({ iid }) {
|
||||
window.location.assign(joinPaths(window.location.pathname, iid, 'details'));
|
||||
navigateToAlertDetails({ iid }) {
|
||||
return visitUrl(joinPaths(window.location.pathname, iid, 'details'));
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="alertManagementEnabled" class="alert-management-list">
|
||||
|
@ -209,7 +211,7 @@ export default {
|
|||
:busy="loading"
|
||||
stacked="md"
|
||||
:tbody-tr-class="$options.bodyTrClass"
|
||||
@row-clicked="handleRowClick"
|
||||
@row-clicked="navigateToAlertDetails"
|
||||
>
|
||||
<template #cell(severity)="{ item }">
|
||||
<div
|
||||
|
|
|
@ -60,7 +60,7 @@ export default {
|
|||
footer-primary-button-variant="danger"
|
||||
@submit="onSubmit"
|
||||
>
|
||||
<template slot="header">
|
||||
<template #header>
|
||||
<h4 class="modal-title d-flex mw-100">
|
||||
Stopping
|
||||
<span v-gl-tooltip :title="environment.name" class="text-truncate ml-1 mr-1 flex-fill">
|
||||
|
|
|
@ -45,6 +45,6 @@
|
|||
%button.btn.btn-transparent
|
||||
= icon('check', class: 'icon')
|
||||
.description
|
||||
%strong.title = _('Report abuse')
|
||||
%strong.title= _('Report abuse')
|
||||
%p.text
|
||||
= _('Report %{display_issuable_type} that are abusive, inappropriate or spam.') % { display_issuable_type: display_issuable_type.pluralize }
|
||||
|
|
5
changelogs/unreleased/217992.yml
Normal file
5
changelogs/unreleased/217992.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Use visitUrl in Alert management
|
||||
merge_request: 32414
|
||||
author:
|
||||
type: other
|
5
changelogs/unreleased/leaky-constant-fix-2.yml
Normal file
5
changelogs/unreleased/leaky-constant-fix-2.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add class stubs and fix leaky constant alert in content whitelist spec
|
||||
merge_request: 31946
|
||||
author: Rajendra Kadam
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Update deprecated slot syntax in ./app/assets/javascripts/environments/components/stop_environment_modal.vue
|
||||
merge_request: 32012
|
||||
author: Gilang Gumilar
|
||||
type: other
|
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddSectionToApprovalMergeRequestRule < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
DOWNTIME = false
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
unless column_exists?(:approval_merge_request_rules, :section)
|
||||
add_column :approval_merge_request_rules, :section, :text
|
||||
end
|
||||
|
||||
add_text_limit :approval_merge_request_rules, :section, 255
|
||||
end
|
||||
|
||||
def down
|
||||
remove_column :approval_merge_request_rules, :section
|
||||
end
|
||||
end
|
|
@ -479,7 +479,9 @@ CREATE TABLE public.approval_merge_request_rules (
|
|||
code_owner boolean DEFAULT false NOT NULL,
|
||||
name character varying NOT NULL,
|
||||
rule_type smallint DEFAULT 1 NOT NULL,
|
||||
report_type smallint
|
||||
report_type smallint,
|
||||
section text,
|
||||
CONSTRAINT check_6fca5928b2 CHECK ((char_length(section) <= 255))
|
||||
);
|
||||
|
||||
CREATE TABLE public.approval_merge_request_rules_approved_approvers (
|
||||
|
@ -13832,6 +13834,7 @@ COPY "schema_migrations" (version) FROM STDIN;
|
|||
20200512164334
|
||||
20200513160930
|
||||
20200513171959
|
||||
20200513224143
|
||||
20200513234502
|
||||
20200513235347
|
||||
20200513235532
|
||||
|
|
|
@ -110,7 +110,6 @@ The `dotenv` report collects a set of environment variables as artifacts.
|
|||
|
||||
The collected variables are registered as runtime-created variables of the job,
|
||||
which is useful to [set dynamic environment URLs after a job finishes](../environments/index.md#set-dynamic-environment-urls-after-a-job-finishes).
|
||||
It's not available for download through the web interface.
|
||||
|
||||
There are a couple of limitations on top of the [original dotenv rules](https://github.com/motdotla/dotenv#rules).
|
||||
|
||||
|
@ -151,7 +150,7 @@ The `codequality` report collects [CodeQuality issues](../../user/project/merge_
|
|||
as artifacts.
|
||||
|
||||
The collected Code Quality report will be uploaded to GitLab as an artifact and will
|
||||
be summarized in merge requests. It's not available for download through the web interface.
|
||||
be summarized in merge requests.
|
||||
|
||||
#### `artifacts:reports:sast` **(ULTIMATE)**
|
||||
|
||||
|
@ -163,7 +162,7 @@ as artifacts.
|
|||
|
||||
The collected SAST report will be uploaded to GitLab as an artifact and will be summarized
|
||||
in the merge requests and pipeline view. It's also used to provide data for security
|
||||
dashboards. It's not available for download through the web interface.
|
||||
dashboards.
|
||||
|
||||
#### `artifacts:reports:dependency_scanning` **(ULTIMATE)**
|
||||
|
||||
|
@ -175,7 +174,7 @@ as artifacts.
|
|||
|
||||
The collected Dependency Scanning report will be uploaded to GitLab as an artifact and will
|
||||
be summarized in the merge requests and pipeline view. It's also used to provide data for security
|
||||
dashboards. It's not available for download through the web interface.
|
||||
dashboards.
|
||||
|
||||
#### `artifacts:reports:container_scanning` **(ULTIMATE)**
|
||||
|
||||
|
@ -187,7 +186,7 @@ as artifacts.
|
|||
|
||||
The collected Container Scanning report will be uploaded to GitLab as an artifact and will
|
||||
be summarized in the merge requests and pipeline view. It's also used to provide data for security
|
||||
dashboards. It's not available for download through the web interface.
|
||||
dashboards.
|
||||
|
||||
#### `artifacts:reports:dast` **(ULTIMATE)**
|
||||
|
||||
|
@ -199,7 +198,7 @@ as artifacts.
|
|||
|
||||
The collected DAST report will be uploaded to GitLab as an artifact and will
|
||||
be summarized in the merge requests and pipeline view. It's also used to provide data for security
|
||||
dashboards. It's not available for download through the web interface.
|
||||
dashboards.
|
||||
|
||||
#### `artifacts:reports:license_management` **(ULTIMATE)**
|
||||
|
||||
|
@ -216,7 +215,7 @@ as artifacts.
|
|||
|
||||
The collected License Compliance report will be uploaded to GitLab as an artifact and will
|
||||
be summarized in the merge requests and pipeline view. It's also used to provide data for security
|
||||
dashboards. It's not available for download through the web interface.
|
||||
dashboards.
|
||||
|
||||
#### `artifacts:reports:license_scanning` **(ULTIMATE)**
|
||||
|
||||
|
@ -239,7 +238,7 @@ The `performance` report collects [Performance metrics](../../user/project/merge
|
|||
as artifacts.
|
||||
|
||||
The collected Performance report will be uploaded to GitLab as an artifact and will
|
||||
be automatically shown in merge requests. It's not available for download through the web interface.
|
||||
be automatically shown in merge requests.
|
||||
|
||||
#### `artifacts:reports:metrics` **(PREMIUM)**
|
||||
|
||||
|
@ -249,7 +248,7 @@ The `metrics` report collects [Metrics](../metrics_reports.md)
|
|||
as artifacts.
|
||||
|
||||
The collected Metrics report will be uploaded to GitLab as an artifact and will
|
||||
be automatically shown in merge requests. It's not available for download through the web interface.
|
||||
be automatically shown in merge requests.
|
||||
|
||||
## Browsing artifacts
|
||||
|
||||
|
@ -277,16 +276,16 @@ one HTML file that you can view directly online when
|
|||
|
||||
## Downloading artifacts
|
||||
|
||||
If you need to download the whole archive, there are buttons in various places
|
||||
If you need to download an artifact or the whole archive, there are buttons in various places
|
||||
in the GitLab UI to do this:
|
||||
|
||||
1. While on the pipelines page, you can see the download icon for each job's
|
||||
artifacts archive in the right corner:
|
||||
artifacts and archive in the right corner:
|
||||
|
||||
![Job artifacts in Pipelines page](img/job_artifacts_pipelines_page.png)
|
||||
|
||||
1. While on the **Jobs** page, you can see the download icon for each job's
|
||||
artifacts archive in the right corner:
|
||||
artifacts and archive in the right corner:
|
||||
|
||||
![Job artifacts in Builds page](img/job_artifacts_builds_page.png)
|
||||
|
||||
|
|
|
@ -550,6 +550,24 @@ You can also
|
|||
[configure the text editor of your choice](https://errata-ai.github.io/vale/#local-use-by-a-single-writer)
|
||||
to display the results.
|
||||
|
||||
Vale's test results are not currently displayed in CI, but may be displayed in the future.
|
||||
|
||||
##### Disable a Vale test
|
||||
|
||||
You can disable a specific Vale linting rule or all Vale linting rules for any portion of a document:
|
||||
|
||||
- To disable a specific rule, add a `<!-- vale gitlab.rulename = NO -->` tag
|
||||
before the text, and a `<!-- vale gitlab.rulename = YES -->` tag after the text,
|
||||
replacing `rulename` with the filename of a test in the [GitLab styles](https://gitlab.com/gitlab-org/gitlab/-/tree/master/doc/.linting/vale/styles/gitlab) directory.
|
||||
- To disable all Vale linting rules, add a `<!-- vale off -->` tag before the text,
|
||||
and a `<!-- vale on -->` tag after the text.
|
||||
|
||||
Whenever possible, exclude only the problematic rule and line(s).
|
||||
In some cases, such as list items, you may need to disable linting for the entire
|
||||
list until ["Ignore comments are not honored in a Markdown file"](https://github.com/errata-ai/vale/issues/175) is resolved.
|
||||
|
||||
For more information, see [Vale's documentation](https://errata-ai.gitbook.io/vale/getting-started/markup#markup-based-configuration).
|
||||
|
||||
## Danger Bot
|
||||
|
||||
GitLab uses [Danger](https://github.com/danger/danger) for some elements in
|
||||
|
|
|
@ -308,12 +308,14 @@ tenses, words, and phrases:
|
|||
appropriate way.
|
||||
- Exceptions to this rule include commonly accepted technical terms, such as
|
||||
CI/CD and TCP/IP.
|
||||
- We discourage use of Latin abbreviations, such as "e.g.," "i.e.," or "etc.,"
|
||||
- <!-- vale gitlab.LatinTerms = NO -->
|
||||
We discourage use of Latin abbreviations, such as "e.g.," "i.e.," or "etc.,"
|
||||
as even native users of English might misunderstand them.
|
||||
- Instead of "i.e.," use "that is."
|
||||
- Instead of "e.g.," use "for example," "such as," "for instance," or "like."
|
||||
- Instead of "etc.," either use "and so on" or consider editing it out, since
|
||||
it can be vague.
|
||||
<!-- vale gitlab.rulename = NO -->
|
||||
- Avoid using the word *currently* when talking about the product or its
|
||||
features. The documentation describes the product as it is, and not as it
|
||||
will be at some indeterminate point in the future.
|
||||
|
@ -379,6 +381,8 @@ tenses, words, and phrases:
|
|||
| Requests to localhost are not allowed | Requests to localhost aren't allowed |
|
||||
| Specified URL cannot be used | Specified URL can't be used |
|
||||
|
||||
<!-- vale on -->
|
||||
|
||||
## Text
|
||||
|
||||
- [Write in Markdown](#markdown).
|
||||
|
@ -1308,7 +1312,7 @@ a helpful link back to how the feature was developed.
|
|||
```
|
||||
|
||||
NOTE: **Note:**
|
||||
Version text must be on its own line and surounded by blank lines to render correctly.
|
||||
Version text must be on its own line and surrounded by blank lines to render correctly.
|
||||
|
||||
### Versions in the past or future
|
||||
|
||||
|
|
|
@ -238,6 +238,53 @@ the view for code in a library.
|
|||
In such rare cases it's reasonable to use CSS selectors in page object methods,
|
||||
with a comment explaining why an `element` can't be added.
|
||||
|
||||
### Define Page concerns
|
||||
|
||||
Some pages share common behaviors, and/or are prepended with EE-specific modules that adds EE-specific methods.
|
||||
|
||||
These modules must:
|
||||
|
||||
1. Extend from the `QA::Page::PageConcern` module, with `extend QA::Page::PageConcern`.
|
||||
1. Override the `self.prepended` method if they need to `include`/`prepend` other modules themselves, and/or define
|
||||
`view` or `elements`.
|
||||
1. Call `super` as the first thing in `self.prepended`.
|
||||
1. Include/prepend other modules and define their `view`/`elements` in a `base.class_eval` block to ensure they're
|
||||
defined in the class that prepends the module.
|
||||
|
||||
These steps ensure the sanity selectors check will detect problems properly.
|
||||
|
||||
For example, `qa/qa/ee/page/merge_request/show.rb` adds EE-specific methods to `qa/qa/page/merge_request/show.rb` (with
|
||||
`QA::Page::MergeRequest::Show.prepend_if_ee('QA::EE::Page::MergeRequest::Show')`) and following is how it's implemented
|
||||
(only showing the relevant part and refering to the 4 steps described above with inline comments):
|
||||
|
||||
```ruby
|
||||
module QA
|
||||
module EE
|
||||
module Page
|
||||
module MergeRequest
|
||||
module Show
|
||||
extend QA::Page::PageConcern # 1.
|
||||
|
||||
def self.prepended(base) # 2.
|
||||
super # 3.
|
||||
|
||||
base.class_eval do # 4.
|
||||
prepend Page::Component::LicenseManagement
|
||||
|
||||
view 'app/assets/javascripts/vue_merge_request_widget/components/states/sha_mismatch.vue' do
|
||||
element :head_mismatch, "The source branch HEAD has recently changed."
|
||||
end
|
||||
|
||||
[...]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
## Running the test locally
|
||||
|
||||
During development, you can run the `qa:selectors` test by running
|
||||
|
|
|
@ -469,7 +469,12 @@ vulnerabilities in your groups, projects and pipelines. Read more about the
|
|||
Once a vulnerability is found, you can interact with it. Read more on how to
|
||||
[interact with the vulnerabilities](../index.md#interacting-with-the-vulnerabilities).
|
||||
|
||||
## Vulnerabilities database update
|
||||
## Vulnerabilities database
|
||||
|
||||
Vulnerabilities contained within the vulnerability database can be searched
|
||||
and viewed at the [GitLab vulnerability advisory database](https://advisories.gitlab.com).
|
||||
|
||||
### Vulnerabilities database update
|
||||
|
||||
For more information about the vulnerabilities database update, check the
|
||||
[maintenance table](../index.md#maintenance-and-update-of-the-vulnerabilities-database).
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
---
|
||||
description: "GitLab - Incident Management. GitLab offers solutions for handling incidents in your applications and services"
|
||||
stage: Monitor
|
||||
group: Health
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
|
||||
|
@ -8,141 +7,106 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
# Incident Management
|
||||
|
||||
GitLab offers solutions for handling incidents in your applications and services,
|
||||
from setting up an alert with Prometheus, to receiving a notification via a
|
||||
monitoring tool like Slack, and automatically setting up Zoom calls with your
|
||||
support team.
|
||||
from setting up an alert with Prometheus, to receiving a notification through a
|
||||
monitoring tool like Slack, and [setting up Zoom calls](#zoom-integration-in-issues) with your
|
||||
support team. Incidents can display [metrics](#embed-metrics-in-incidents-and-issues)
|
||||
and [logs](#view-logs-from-metrics-panel).
|
||||
|
||||
## Configuring incidents **(ULTIMATE)**
|
||||
## Configure incidents **(ULTIMATE)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/4925) in GitLab Ultimate 11.11.
|
||||
|
||||
The Incident Management features can be enabled and disabled via your project's
|
||||
**Settings > Operations > Incidents**.
|
||||
You can enable or disable Incident Management features in your project's
|
||||
**{settings}** **Settings > Operations > Incidents**. Issues can be created for
|
||||
each alert triggered, and separate email notifications can be sent to users with
|
||||
[Developer permissions](../permissions.md). Appropriately configured alerts include an
|
||||
[embedded chart](../project/integrations/prometheus.md#embedding-metrics-based-on-alerts-in-incident-issues)
|
||||
for the query corresponding to the alert. You can also configure GitLab to
|
||||
[close issues](../project/integrations/prometheus.md#taking-action-on-incidents-ultimate)
|
||||
when you receive notification that the alert is resolved.
|
||||
|
||||
![Incident Management Settings](img/incident_management_settings.png)
|
||||
|
||||
### Automatically create issues from alerts
|
||||
### Create issues from alerts
|
||||
|
||||
GitLab issues can automatically be created as a result of an alert notification.
|
||||
An issue created this way will contain the error information to help you further
|
||||
debug it.
|
||||
You can create GitLab issues from an alert notification. These issues contain
|
||||
information about the alerts to help you diagnose the source of the alerts.
|
||||
|
||||
### Issue templates
|
||||
|
||||
You can create your own [issue templates](../project/description_templates.md#creating-issue-templates)
|
||||
that can be [used within Incident Management](../project/integrations/prometheus.md#taking-action-on-incidents-ultimate).
|
||||
|
||||
To select your issue template for use within Incident Management:
|
||||
|
||||
1. Visit your project's **Settings > Operations > Incidents**.
|
||||
1. Visit your project's **{settings}** **Settings > Operations > Incidents**.
|
||||
1. Select the **Create an issue** checkbox for GitLab to create an issue from
|
||||
the incident.
|
||||
1. Select the template from the **Issue Template** dropdown.
|
||||
You can create your own [issue templates](../project/description_templates.md#creating-issue-templates)
|
||||
to [use within Incident Management](../project/integrations/prometheus.md#taking-action-on-incidents-ultimate).
|
||||
1. Click **Save changes**.
|
||||
|
||||
## Alerting
|
||||
## Notify developers of alerts
|
||||
|
||||
GitLab can react to the alerts that your applications and services may be
|
||||
triggering by automatically creating issues, and alerting developers via email.
|
||||
GitLab can react to the alerts triggered from your applications and services
|
||||
by creating issues and alerting developers through email. GitLab sends these emails
|
||||
to [owners and maintainers](../permissions.md) of the project. They contain details
|
||||
of the alert, and a link for more information.
|
||||
|
||||
The emails will be sent to [owners and maintainers](../permissions.md) of the project and will contain details on the alert as well as a link to see more information.
|
||||
### Configure Prometheus alerts
|
||||
|
||||
### Prometheus alerts
|
||||
You can set up Prometheus alerts in:
|
||||
|
||||
Prometheus alerts can be set up in both:
|
||||
|
||||
- [GitLab-managed Prometheus](../project/integrations/prometheus.md#setting-up-alerts-for-prometheus-metrics) and
|
||||
- [GitLab-managed Prometheus](../project/integrations/prometheus.md#setting-up-alerts-for-prometheus-metrics) installations.
|
||||
- [Self-managed Prometheus](../project/integrations/prometheus.md#external-prometheus-instances) installations.
|
||||
|
||||
#### Alert Bot user
|
||||
Prometheus alerts are created by the special Alert Bot user. You can't remove this
|
||||
user, but it does not count toward your license limit.
|
||||
|
||||
Behind the scenes, Prometheus alerts are created by the special Alert Bot user creating issues. This user cannot be removed but does not count toward the license limit count.
|
||||
### Configure external generic alerts
|
||||
|
||||
### Alert endpoint
|
||||
GitLab can accept alerts from any source through a generic webhook receiver. When
|
||||
[configuring the generic alerts integration](../project/integrations/generic_alerts.md),
|
||||
GitLab creates a unique endpoint which receives a JSON-formatted, customizable payload.
|
||||
|
||||
GitLab can accept alerts from any source via a generic webhook receiver. When
|
||||
you set up the generic alerts integration, a unique endpoint will
|
||||
be created which can receive a payload in JSON format.
|
||||
## Embed metrics in incidents and issues
|
||||
|
||||
[Read more on setting this up, including how to customize the payload](../project/integrations/generic_alerts.md).
|
||||
|
||||
### Recovery alerts
|
||||
|
||||
GitLab can [automatically close issues](../project/integrations/prometheus.md#taking-action-on-incidents-ultimate)
|
||||
that have been automatically created when you receive notification that the
|
||||
alert is resolved.
|
||||
|
||||
## Embedded metrics
|
||||
|
||||
Metrics can be embedded anywhere where GitLab Markdown is used, for example,
|
||||
descriptions and comments on issues and merge requests.
|
||||
|
||||
This can be useful for when you're sharing metrics, such as for discussing
|
||||
an incident or performance issues, so you can output the dashboard directly
|
||||
You can embed metrics anywhere GitLab Markdown is used, such as descriptions,
|
||||
comments on issues, and merge requests. Embedding metrics helps you share them
|
||||
when discussing incidents or performance issues. You can output the dashboard directly
|
||||
into any issue, merge request, epic, or any other Markdown text field in GitLab
|
||||
by simply [copying and pasting the link to the metrics dashboard](../project/integrations/prometheus.md#embedding-gitlab-managed-kubernetes-metrics).
|
||||
by [copying and pasting the link to the metrics dashboard](../project/integrations/prometheus.md#embedding-gitlab-managed-kubernetes-metrics).
|
||||
|
||||
TIP: **Tip:**
|
||||
Both GitLab-hosted and Grafana metrics can also be
|
||||
[embedded in issue templates](../project/integrations/prometheus.md#embedding-metrics-in-issue-templates).
|
||||
You can embed both
|
||||
[GitLab-hosted metrics](../project/integrations/prometheus.md#embedding-metric-charts-within-gitlab-flavored-markdown) and
|
||||
[Grafana metrics](../project/integrations/prometheus.md#embedding-grafana-charts)
|
||||
in incidents and issue templates.
|
||||
|
||||
### GitLab-hosted metrics
|
||||
|
||||
Learn how to embed [GitLab hosted metric charts](../project/integrations/prometheus.md#embedding-metric-charts-within-gitlab-flavored-markdown).
|
||||
|
||||
#### Context menu
|
||||
### Context menu
|
||||
|
||||
From each of the embedded metrics panels, you can access more details
|
||||
about the data you are viewing from a context menu.
|
||||
about the data you're viewing from a context menu. You can access the context menu
|
||||
by clicking the **{ellipsis_v}** **More actions** dropdown box above the
|
||||
upper right corner of the panel. The options are:
|
||||
|
||||
You can access the context menu by clicking the **{ellipsis_v}** **More actions**
|
||||
dropdown box above the upper right corner of the panel:
|
||||
- [View logs](#view-logs-from-metrics-panel).
|
||||
- **Download CSV** - Data from embedded charts can be
|
||||
[downloaded as CSV](../project/integrations/prometheus.md#downloading-data-as-csv).
|
||||
|
||||
The options are:
|
||||
|
||||
- [View logs](#view-logs)
|
||||
- [Download CSV](#download-csv)
|
||||
|
||||
##### View logs
|
||||
#### View logs from metrics panel
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/201846) in GitLab Ultimate 12.8.
|
||||
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25455) to [GitLab Core](https://about.gitlab.com/pricing/) 12.9.
|
||||
|
||||
This can be useful if you are triaging an application incident and need to
|
||||
[explore logs](../project/integrations/prometheus.md#view-logs-ultimate)
|
||||
from across your application. It also helps you to understand
|
||||
what is affecting your application's performance and quickly resolve any problems.
|
||||
|
||||
##### Download CSV
|
||||
|
||||
Data from embedded charts can be [downloaded as CSV](../project/integrations/prometheus.md#downloading-data-as-csv).
|
||||
|
||||
### Grafana metrics
|
||||
|
||||
Learn how to embed [Grafana hosted metric charts](../project/integrations/prometheus.md#embedding-grafana-charts).
|
||||
Viewing logs from a metrics panel can be useful if you're triaging an application
|
||||
incident and need to [explore logs](../project/integrations/prometheus.md#view-logs-ultimate)
|
||||
from across your application. These logs help you understand what is affecting
|
||||
your application's performance and resolve any problems.
|
||||
|
||||
## Slack integration
|
||||
|
||||
Slack slash commands allow you to control GitLab and view content right inside
|
||||
Slack, without having to leave it.
|
||||
Slack slash commands allow you to control GitLab and view GitLab content without leaving Slack.
|
||||
|
||||
Learn how to [set up Slack slash commands](../project/integrations/slack_slash_commands.md)
|
||||
and how to [use them](../../integration/slash_commands.md).
|
||||
and how to [use the available slash commands](../../integration/slash_commands.md).
|
||||
|
||||
### Slash commands
|
||||
## Zoom integration in issues
|
||||
|
||||
Please refer to a list of [available slash commands](../../integration/slash_commands.md) and associated descriptions.
|
||||
|
||||
## Zoom in issues
|
||||
|
||||
In order to communicate synchronously for incidents management, GitLab allows you to
|
||||
associate a Zoom meeting with an issue. Once you start a Zoom call for a fire-fight,
|
||||
you need a way to associate the conference call with an issue, so that your team
|
||||
members can join swiftly without requesting a link.
|
||||
|
||||
Read more how to [add or remove a zoom meeting](../project/issues/associate_zoom_meeting.md).
|
||||
|
||||
### Configuring Incidents
|
||||
|
||||
Incident Management features can be easily enabled & disabled via the Project settings page. Head to Project -> Settings -> Operations -> Incidents.
|
||||
|
||||
#### Auto-creation
|
||||
|
||||
You can automatically create GitLab issues from an Alert notification. Issues created this way contain error information to help you debug the error. Appropriately configured alerts include an [embedded chart](../project/integrations/prometheus.md#embedding-metrics-based-on-alerts-in-incident-issues) for the query corresponding to the alert.
|
||||
GitLab enables you to [associate a Zoom meeting with an issue](../project/issues/associate_zoom_meeting.md)
|
||||
for synchronous communication during incident management. After starting a Zoom
|
||||
call for an incident, you can associate the conference call with an issue, so your
|
||||
team members can join without requesting a link.
|
||||
|
|
|
@ -1725,6 +1725,15 @@ msgstr ""
|
|||
msgid "After a successful password update, you will be redirected to the login page where you can log in with your new password."
|
||||
msgstr ""
|
||||
|
||||
msgid "After that, you will not to be able to use merge approvals or code quality as well as many other features."
|
||||
msgstr ""
|
||||
|
||||
msgid "After that, you will not to be able to use merge approvals or epics as well as many other features."
|
||||
msgstr ""
|
||||
|
||||
msgid "After that, you will not to be able to use merge approvals or epics as well as many security features."
|
||||
msgstr ""
|
||||
|
||||
msgid "Alert"
|
||||
msgid_plural "Alerts"
|
||||
msgstr[0] ""
|
||||
|
@ -25014,7 +25023,7 @@ msgstr ""
|
|||
msgid "YouTube"
|
||||
msgstr ""
|
||||
|
||||
msgid "Your %{strong}%{plan_name}%{strong_close} subscription for %{strong}%{namespace_name}%{strong_close} will expire on %{strong}%{expires_on}%{strong_close}. After that, you will not to be able to create issues or merge requests as well as many other features."
|
||||
msgid "Your %{strong}%{plan_name}%{strong_close} subscription for %{strong}%{namespace_name}%{strong_close} will expire on %{strong}%{expires_on}%{strong_close}."
|
||||
msgstr ""
|
||||
|
||||
msgid "Your %{strong}%{plan_name}%{strong_close} subscription will expire on %{strong}%{expires_on}%{strong_close}. After that, you will not to be able to create issues or merge requests as well as many other features."
|
||||
|
|
3
qa/qa.rb
3
qa/qa.rb
|
@ -162,6 +162,7 @@ module QA
|
|||
autoload :Base, 'qa/page/base'
|
||||
autoload :View, 'qa/page/view'
|
||||
autoload :Element, 'qa/page/element'
|
||||
autoload :PageConcern, 'qa/page/page_concern'
|
||||
autoload :Validator, 'qa/page/validator'
|
||||
autoload :Validatable, 'qa/page/validatable'
|
||||
|
||||
|
@ -248,7 +249,6 @@ module QA
|
|||
end
|
||||
|
||||
module Settings
|
||||
autoload :Common, 'qa/page/project/settings/common'
|
||||
autoload :Advanced, 'qa/page/project/settings/advanced'
|
||||
autoload :Main, 'qa/page/project/settings/main'
|
||||
autoload :Repository, 'qa/page/project/settings/repository'
|
||||
|
@ -409,6 +409,7 @@ module QA
|
|||
autoload :Breadcrumbs, 'qa/page/component/breadcrumbs'
|
||||
autoload :CiBadgeLink, 'qa/page/component/ci_badge_link'
|
||||
autoload :ClonePanel, 'qa/page/component/clone_panel'
|
||||
autoload :DesignManagement, 'qa/page/component/design_management'
|
||||
autoload :LazyLoader, 'qa/page/component/lazy_loader'
|
||||
autoload :LegacyClonePanel, 'qa/page/component/legacy_clone_panel'
|
||||
autoload :Dropzone, 'qa/page/component/dropzone'
|
||||
|
|
|
@ -4,7 +4,11 @@ module QA
|
|||
module Page
|
||||
module Component
|
||||
module Breadcrumbs
|
||||
extend QA::Page::PageConcern
|
||||
|
||||
def self.included(base)
|
||||
super
|
||||
|
||||
base.view 'app/views/layouts/nav/_breadcrumbs.html.haml' do
|
||||
element :breadcrumb_links_content
|
||||
end
|
||||
|
|
|
@ -4,6 +4,8 @@ module QA
|
|||
module Page
|
||||
module Component
|
||||
module CiBadgeLink
|
||||
extend QA::Page::PageConcern
|
||||
|
||||
COMPLETED_STATUSES = %w[passed failed canceled blocked skipped manual].freeze # excludes created, pending, running
|
||||
INCOMPLETE_STATUSES = %w[pending created running].freeze
|
||||
|
||||
|
@ -27,6 +29,8 @@ module QA
|
|||
end
|
||||
|
||||
def self.included(base)
|
||||
super
|
||||
|
||||
base.view 'app/assets/javascripts/vue_shared/components/ci_badge_link.vue' do
|
||||
element :status_badge
|
||||
end
|
||||
|
|
|
@ -4,7 +4,11 @@ module QA
|
|||
module Page
|
||||
module Component
|
||||
module ClonePanel
|
||||
extend QA::Page::PageConcern
|
||||
|
||||
def self.included(base)
|
||||
super
|
||||
|
||||
base.view 'app/views/projects/buttons/_clone.html.haml' do
|
||||
element :clone_dropdown
|
||||
element :clone_options
|
||||
|
|
|
@ -4,7 +4,11 @@ module QA
|
|||
module Page
|
||||
module Component
|
||||
module ConfirmModal
|
||||
extend QA::Page::PageConcern
|
||||
|
||||
def self.included(base)
|
||||
super
|
||||
|
||||
base.view 'app/views/shared/_confirm_modal.html.haml' do
|
||||
element :confirm_modal
|
||||
element :confirm_input
|
||||
|
|
|
@ -4,7 +4,11 @@ module QA
|
|||
module Page
|
||||
module Component
|
||||
module CustomMetric
|
||||
extend QA::Page::PageConcern
|
||||
|
||||
def self.included(base)
|
||||
super
|
||||
|
||||
base.view 'app/assets/javascripts/custom_metrics/components/custom_metrics_form_fields.vue' do
|
||||
element :custom_metric_prometheus_title_field
|
||||
element :custom_metric_prometheus_query_field
|
||||
|
|
|
@ -4,8 +4,12 @@ module QA
|
|||
module Page
|
||||
module Component
|
||||
module DesignManagement
|
||||
def self.prepended(page)
|
||||
page.module_eval do
|
||||
extend QA::Page::PageConcern
|
||||
|
||||
def self.included(base)
|
||||
super
|
||||
|
||||
base.class_eval do
|
||||
view 'app/assets/javascripts/design_management/components/design_notes/design_discussion.vue' do
|
||||
element :design_discussion_content
|
||||
end
|
||||
|
|
|
@ -4,7 +4,11 @@ module QA
|
|||
module Page
|
||||
module Component
|
||||
module GroupsFilter
|
||||
extend QA::Page::PageConcern
|
||||
|
||||
def self.included(base)
|
||||
super
|
||||
|
||||
base.view 'app/views/shared/groups/_search_form.html.haml' do
|
||||
element :groups_filter
|
||||
end
|
||||
|
|
|
@ -5,7 +5,11 @@ module QA
|
|||
module Component
|
||||
module Issuable
|
||||
module Common
|
||||
extend QA::Page::PageConcern
|
||||
|
||||
def self.included(base)
|
||||
super
|
||||
|
||||
base.view 'app/assets/javascripts/issue_show/components/title.vue' do
|
||||
element :edit_button
|
||||
element :title, required: true
|
||||
|
|
|
@ -4,7 +4,11 @@ module QA
|
|||
module Page
|
||||
module Component
|
||||
module LazyLoader
|
||||
extend QA::Page::PageConcern
|
||||
|
||||
def self.included(base)
|
||||
super
|
||||
|
||||
base.view 'app/assets/javascripts/lazy_loader.js' do
|
||||
element :js_lazy_loaded
|
||||
end
|
||||
|
|
|
@ -4,7 +4,11 @@ module QA
|
|||
module Page
|
||||
module Component
|
||||
module LegacyClonePanel
|
||||
extend QA::Page::PageConcern
|
||||
|
||||
def self.included(base)
|
||||
super
|
||||
|
||||
base.view 'app/views/shared/_clone_panel.html.haml' do
|
||||
element :clone_dropdown
|
||||
element :clone_options_dropdown, '.clone-options-dropdown' # rubocop:disable QA/ElementWithPattern
|
||||
|
|
|
@ -4,7 +4,11 @@ module QA
|
|||
module Page
|
||||
module Component
|
||||
module Note
|
||||
extend QA::Page::PageConcern
|
||||
|
||||
def self.included(base)
|
||||
super
|
||||
|
||||
base.view 'app/assets/javascripts/notes/components/comment_form.vue' do
|
||||
element :note_dropdown
|
||||
element :discussion_option
|
||||
|
|
|
@ -5,8 +5,12 @@ module QA
|
|||
module Component
|
||||
module WebIDE
|
||||
module Alert
|
||||
def self.prepended(page)
|
||||
page.module_eval do
|
||||
extend QA::Page::PageConcern
|
||||
|
||||
def self.prepended(base)
|
||||
super
|
||||
|
||||
base.class_eval do
|
||||
view 'app/assets/javascripts/ide/components/error_message.vue' do
|
||||
element :flash_alert
|
||||
end
|
||||
|
|
|
@ -5,7 +5,11 @@ module QA
|
|||
module File
|
||||
module Shared
|
||||
module CommitButton
|
||||
extend QA::Page::PageConcern
|
||||
|
||||
def self.included(base)
|
||||
super
|
||||
|
||||
base.view 'app/views/projects/_commit_button.html.haml' do
|
||||
element :commit_button
|
||||
end
|
||||
|
|
|
@ -5,7 +5,11 @@ module QA
|
|||
module File
|
||||
module Shared
|
||||
module CommitMessage
|
||||
extend QA::Page::PageConcern
|
||||
|
||||
def self.included(base)
|
||||
super
|
||||
|
||||
base.view 'app/views/shared/_commit_message_container.html.haml' do
|
||||
element :commit_message, "text_area_tag 'commit_message'" # rubocop:disable QA/ElementWithPattern
|
||||
end
|
||||
|
|
|
@ -5,7 +5,11 @@ module QA
|
|||
module File
|
||||
module Shared
|
||||
module Editor
|
||||
extend QA::Page::PageConcern
|
||||
|
||||
def self.included(base)
|
||||
super
|
||||
|
||||
base.view 'app/views/projects/blob/_editor.html.haml' do
|
||||
element :editor
|
||||
end
|
||||
|
|
|
@ -5,9 +5,12 @@ module QA
|
|||
module Group
|
||||
module SubMenus
|
||||
module Common
|
||||
extend QA::Page::PageConcern
|
||||
include QA::Page::SubMenus::Common
|
||||
|
||||
def self.included(base)
|
||||
super
|
||||
|
||||
base.class_eval do
|
||||
view 'app/views/layouts/nav/sidebar/_group.html.haml' do
|
||||
element :group_sidebar
|
||||
|
|
|
@ -1,20 +1,22 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module QA
|
||||
module Page::Main
|
||||
class Terms < Page::Base
|
||||
view 'app/views/layouts/terms.html.haml' do
|
||||
element :user_avatar, required: true
|
||||
end
|
||||
module Page
|
||||
module Main
|
||||
class Terms < Page::Base
|
||||
view 'app/views/layouts/terms.html.haml' do
|
||||
element :user_avatar, required: true
|
||||
end
|
||||
|
||||
view 'app/views/users/terms/index.html.haml' do
|
||||
element :terms_content, required: true
|
||||
view 'app/views/users/terms/index.html.haml' do
|
||||
element :terms_content, required: true
|
||||
|
||||
element :accept_terms_button
|
||||
end
|
||||
element :accept_terms_button
|
||||
end
|
||||
|
||||
def accept_terms
|
||||
click_element :accept_terms_button, Page::Main::Menu
|
||||
def accept_terms
|
||||
click_element :accept_terms_button, Page::Main::Menu
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
16
qa/qa/page/page_concern.rb
Normal file
16
qa/qa/page/page_concern.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
module QA
|
||||
module Page
|
||||
module PageConcern
|
||||
def included(base)
|
||||
unless base.is_a?(Class)
|
||||
raise "Expected #{self} to be prepended to a class, but #{base} is a module!"
|
||||
end
|
||||
|
||||
unless base.ancestors.include?(::QA::Page::Base)
|
||||
raise "Expected #{self} to be prepended to a class that inherits from ::QA::Page::Base, but #{base} doesn't!"
|
||||
end
|
||||
end
|
||||
alias_method :prepended, :included
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,51 +1,55 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module QA::Page
|
||||
module Project::Job
|
||||
class Show < QA::Page::Base
|
||||
include Component::CiBadgeLink
|
||||
module QA
|
||||
module Page
|
||||
module Project
|
||||
module Job
|
||||
class Show < QA::Page::Base
|
||||
include Component::CiBadgeLink
|
||||
|
||||
view 'app/assets/javascripts/jobs/components/log/log.vue' do
|
||||
element :job_log_content
|
||||
end
|
||||
view 'app/assets/javascripts/jobs/components/log/log.vue' do
|
||||
element :job_log_content
|
||||
end
|
||||
|
||||
view 'app/assets/javascripts/jobs/components/stages_dropdown.vue' do
|
||||
element :pipeline_path
|
||||
end
|
||||
view 'app/assets/javascripts/jobs/components/stages_dropdown.vue' do
|
||||
element :pipeline_path
|
||||
end
|
||||
|
||||
view 'app/assets/javascripts/jobs/components/sidebar.vue' do
|
||||
element :retry_button
|
||||
end
|
||||
view 'app/assets/javascripts/jobs/components/sidebar.vue' do
|
||||
element :retry_button
|
||||
end
|
||||
|
||||
def successful?(timeout: 60)
|
||||
raise "Timed out waiting for the build trace to load" unless loaded?
|
||||
raise "Timed out waiting for the status to be a valid completed state" unless completed?(timeout: timeout)
|
||||
def successful?(timeout: 60)
|
||||
raise "Timed out waiting for the build trace to load" unless loaded?
|
||||
raise "Timed out waiting for the status to be a valid completed state" unless completed?(timeout: timeout)
|
||||
|
||||
passed?
|
||||
end
|
||||
passed?
|
||||
end
|
||||
|
||||
# Reminder: You may wish to wait for a particular job status before checking output
|
||||
def output(wait: 5)
|
||||
result = ''
|
||||
# Reminder: You may wish to wait for a particular job status before checking output
|
||||
def output(wait: 5)
|
||||
result = ''
|
||||
|
||||
wait_until(reload: false, max_duration: wait, sleep_interval: 1) do
|
||||
result = find_element(:job_log_content).text
|
||||
wait_until(reload: false, max_duration: wait, sleep_interval: 1) do
|
||||
result = find_element(:job_log_content).text
|
||||
|
||||
result.include?('Job')
|
||||
end
|
||||
result.include?('Job')
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
def retry!
|
||||
click_element :retry_button
|
||||
end
|
||||
def retry!
|
||||
click_element :retry_button
|
||||
end
|
||||
|
||||
private
|
||||
private
|
||||
|
||||
def loaded?(wait: 60)
|
||||
wait_until(reload: true, max_duration: wait, sleep_interval: 1) do
|
||||
has_element?(:job_log_content, wait: 1)
|
||||
def loaded?(wait: 60)
|
||||
wait_until(reload: true, max_duration: wait, sleep_interval: 1) do
|
||||
has_element?(:job_log_content, wait: 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,41 +1,45 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module QA::Page
|
||||
module Project::Pipeline
|
||||
class Index < QA::Page::Base
|
||||
view 'app/assets/javascripts/pipelines/components/pipeline_url.vue' do
|
||||
element :pipeline_url_link
|
||||
end
|
||||
module QA
|
||||
module Page
|
||||
module Project
|
||||
module Pipeline
|
||||
class Index < QA::Page::Base
|
||||
view 'app/assets/javascripts/pipelines/components/pipeline_url.vue' do
|
||||
element :pipeline_url_link
|
||||
end
|
||||
|
||||
view 'app/assets/javascripts/pipelines/components/pipelines_table_row.vue' do
|
||||
element :pipeline_commit_status
|
||||
element :pipeline_retry_button
|
||||
end
|
||||
view 'app/assets/javascripts/pipelines/components/pipelines_table_row.vue' do
|
||||
element :pipeline_commit_status
|
||||
element :pipeline_retry_button
|
||||
end
|
||||
|
||||
def click_on_latest_pipeline
|
||||
all_elements(:pipeline_url_link, minimum: 1, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME).first.click
|
||||
end
|
||||
def click_on_latest_pipeline
|
||||
all_elements(:pipeline_url_link, minimum: 1, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME).first.click
|
||||
end
|
||||
|
||||
def wait_for_latest_pipeline_success
|
||||
wait_for_latest_pipeline_status { has_text?('passed') }
|
||||
end
|
||||
def wait_for_latest_pipeline_success
|
||||
wait_for_latest_pipeline_status { has_text?('passed') }
|
||||
end
|
||||
|
||||
def wait_for_latest_pipeline_completion
|
||||
wait_for_latest_pipeline_status { has_text?('passed') || has_text?('failed') }
|
||||
end
|
||||
def wait_for_latest_pipeline_completion
|
||||
wait_for_latest_pipeline_status { has_text?('passed') || has_text?('failed') }
|
||||
end
|
||||
|
||||
def wait_for_latest_pipeline_status
|
||||
wait_until(reload: false, max_duration: 360) do
|
||||
within_element_by_index(:pipeline_commit_status, 0) { yield }
|
||||
end
|
||||
end
|
||||
def wait_for_latest_pipeline_status
|
||||
wait_until(reload: false, max_duration: 360) do
|
||||
within_element_by_index(:pipeline_commit_status, 0) { yield }
|
||||
end
|
||||
end
|
||||
|
||||
def wait_for_latest_pipeline_success_or_retry
|
||||
wait_for_latest_pipeline_completion
|
||||
def wait_for_latest_pipeline_success_or_retry
|
||||
wait_for_latest_pipeline_completion
|
||||
|
||||
if has_text?('failed')
|
||||
click_element :pipeline_retry_button
|
||||
wait_for_latest_pipeline_success
|
||||
if has_text?('failed')
|
||||
click_element :pipeline_retry_button
|
||||
wait_for_latest_pipeline_success
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,74 +1,78 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module QA::Page
|
||||
module Project::Pipeline
|
||||
class Show < QA::Page::Base
|
||||
include Component::CiBadgeLink
|
||||
module QA
|
||||
module Page
|
||||
module Project
|
||||
module Pipeline
|
||||
class Show < QA::Page::Base
|
||||
include Component::CiBadgeLink
|
||||
|
||||
view 'app/assets/javascripts/vue_shared/components/header_ci_component.vue' do
|
||||
element :pipeline_header, /header class.*ci-header-container.*/ # rubocop:disable QA/ElementWithPattern
|
||||
end
|
||||
view 'app/assets/javascripts/vue_shared/components/header_ci_component.vue' do
|
||||
element :pipeline_header, /header class.*ci-header-container.*/ # rubocop:disable QA/ElementWithPattern
|
||||
end
|
||||
|
||||
view 'app/assets/javascripts/pipelines/components/graph/graph_component.vue' do
|
||||
element :pipeline_graph, /class.*pipeline-graph.*/ # rubocop:disable QA/ElementWithPattern
|
||||
end
|
||||
view 'app/assets/javascripts/pipelines/components/graph/graph_component.vue' do
|
||||
element :pipeline_graph, /class.*pipeline-graph.*/ # rubocop:disable QA/ElementWithPattern
|
||||
end
|
||||
|
||||
view 'app/assets/javascripts/pipelines/components/graph/job_item.vue' do
|
||||
element :job_component, /class.*ci-job-component.*/ # rubocop:disable QA/ElementWithPattern
|
||||
element :job_link
|
||||
end
|
||||
view 'app/assets/javascripts/pipelines/components/graph/job_item.vue' do
|
||||
element :job_component, /class.*ci-job-component.*/ # rubocop:disable QA/ElementWithPattern
|
||||
element :job_link
|
||||
end
|
||||
|
||||
view 'app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue' do
|
||||
element :linked_pipeline_button
|
||||
end
|
||||
view 'app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue' do
|
||||
element :linked_pipeline_button
|
||||
end
|
||||
|
||||
view 'app/assets/javascripts/vue_shared/components/ci_icon.vue' do
|
||||
element :status_icon, 'ci-status-icon-${status}' # rubocop:disable QA/ElementWithPattern
|
||||
end
|
||||
view 'app/assets/javascripts/vue_shared/components/ci_icon.vue' do
|
||||
element :status_icon, 'ci-status-icon-${status}' # rubocop:disable QA/ElementWithPattern
|
||||
end
|
||||
|
||||
view 'app/views/projects/pipelines/_info.html.haml' do
|
||||
element :pipeline_badges
|
||||
end
|
||||
view 'app/views/projects/pipelines/_info.html.haml' do
|
||||
element :pipeline_badges
|
||||
end
|
||||
|
||||
def running?(wait: 0)
|
||||
within('.ci-header-container') do
|
||||
page.has_content?('running', wait: wait)
|
||||
end
|
||||
end
|
||||
def running?(wait: 0)
|
||||
within('.ci-header-container') do
|
||||
page.has_content?('running', wait: wait)
|
||||
end
|
||||
end
|
||||
|
||||
def has_build?(name, status: :success, wait: nil)
|
||||
within('.pipeline-graph') do
|
||||
within('.ci-job-component', text: name) do
|
||||
has_selector?(".ci-status-icon-#{status}", { wait: wait }.compact)
|
||||
def has_build?(name, status: :success, wait: nil)
|
||||
within('.pipeline-graph') do
|
||||
within('.ci-job-component', text: name) do
|
||||
has_selector?(".ci-status-icon-#{status}", { wait: wait }.compact)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def has_job?(job_name)
|
||||
has_element?(:job_link, text: job_name)
|
||||
end
|
||||
|
||||
def has_no_job?(job_name)
|
||||
has_no_element?(:job_link, text: job_name)
|
||||
end
|
||||
|
||||
def has_tag?(tag_name)
|
||||
within_element(:pipeline_badges) do
|
||||
has_selector?('.badge', text: tag_name)
|
||||
end
|
||||
end
|
||||
|
||||
def click_job(job_name)
|
||||
click_element(:job_link, text: job_name)
|
||||
end
|
||||
|
||||
def click_linked_job(project_name)
|
||||
click_element(:linked_pipeline_button, text: /#{project_name}/)
|
||||
end
|
||||
|
||||
def click_on_first_job
|
||||
first('.js-pipeline-graph-job-link', wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME).click
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def has_job?(job_name)
|
||||
has_element?(:job_link, text: job_name)
|
||||
end
|
||||
|
||||
def has_no_job?(job_name)
|
||||
has_no_element?(:job_link, text: job_name)
|
||||
end
|
||||
|
||||
def has_tag?(tag_name)
|
||||
within_element(:pipeline_badges) do
|
||||
has_selector?('.badge', text: tag_name)
|
||||
end
|
||||
end
|
||||
|
||||
def click_job(job_name)
|
||||
click_element(:job_link, text: job_name)
|
||||
end
|
||||
|
||||
def click_linked_job(project_name)
|
||||
click_element(:linked_pipeline_button, text: /#{project_name}/)
|
||||
end
|
||||
|
||||
def click_on_first_job
|
||||
first('.js-pipeline-graph-job-link', wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME).click
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,7 +5,7 @@ module QA
|
|||
module Project
|
||||
module Settings
|
||||
class CICD < Page::Base
|
||||
include Common
|
||||
include QA::Page::Settings::Common
|
||||
|
||||
view 'app/views/projects/settings/ci_cd/show.html.haml' do
|
||||
element :autodevops_settings_content
|
||||
|
|
|
@ -5,7 +5,7 @@ module QA
|
|||
module Project
|
||||
module Settings
|
||||
class CiVariables < Page::Base
|
||||
include Common
|
||||
include QA::Page::Settings::Common
|
||||
|
||||
view 'app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue' do
|
||||
element :ci_variable_key_field
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module QA
|
||||
module Page
|
||||
module Project
|
||||
module Settings
|
||||
module Common
|
||||
include QA::Page::Settings::Common
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -5,7 +5,7 @@ module QA
|
|||
module Project
|
||||
module Settings
|
||||
class GeneralPipelines < Page::Base
|
||||
include Common
|
||||
include QA::Page::Settings::Common
|
||||
|
||||
view 'app/views/projects/settings/ci_cd/_form.html.haml' do
|
||||
element :build_coverage_regex_field
|
||||
|
|
|
@ -5,7 +5,7 @@ module QA
|
|||
module Project
|
||||
module Settings
|
||||
class Main < Page::Base
|
||||
include Common
|
||||
include QA::Page::Settings::Common
|
||||
include Component::Select2
|
||||
include SubMenus::Project
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ module QA
|
|||
module Project
|
||||
module Settings
|
||||
class MergeRequest < QA::Page::Base
|
||||
include Common
|
||||
include QA::Page::Settings::Common
|
||||
|
||||
view 'app/views/projects/edit.html.haml' do
|
||||
element :save_merge_request_changes
|
||||
|
|
|
@ -5,7 +5,7 @@ module QA
|
|||
module Project
|
||||
module Settings
|
||||
class Operations < Page::Base
|
||||
include Common
|
||||
include QA::Page::Settings::Common
|
||||
|
||||
view 'app/views/projects/settings/operations/_incidents.html.haml' do
|
||||
element :incidents_settings_content
|
||||
|
|
|
@ -5,7 +5,7 @@ module QA
|
|||
module Project
|
||||
module Settings
|
||||
class Repository < Page::Base
|
||||
include Common
|
||||
include QA::Page::Settings::Common
|
||||
|
||||
view 'app/views/projects/protected_branches/shared/_index.html.haml' do
|
||||
element :protected_branches_settings
|
||||
|
|
|
@ -5,10 +5,14 @@ module QA
|
|||
module Project
|
||||
module SubMenus
|
||||
module CiCd
|
||||
include Page::Project::SubMenus::Common
|
||||
extend QA::Page::PageConcern
|
||||
|
||||
def self.included(base)
|
||||
super
|
||||
|
||||
base.class_eval do
|
||||
include QA::Page::Project::SubMenus::Common
|
||||
|
||||
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
|
||||
element :link_pipelines
|
||||
end
|
||||
|
|
|
@ -5,6 +5,7 @@ module QA
|
|||
module Project
|
||||
module SubMenus
|
||||
module Common
|
||||
extend QA::Page::PageConcern
|
||||
include QA::Page::SubMenus::Common
|
||||
|
||||
private
|
||||
|
|
|
@ -5,10 +5,14 @@ module QA
|
|||
module Project
|
||||
module SubMenus
|
||||
module Issues
|
||||
include Page::Project::SubMenus::Common
|
||||
extend QA::Page::PageConcern
|
||||
|
||||
def self.included(base)
|
||||
super
|
||||
|
||||
base.class_eval do
|
||||
include QA::Page::Project::SubMenus::Common
|
||||
|
||||
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
|
||||
element :issue_boards_link
|
||||
element :issues_item
|
||||
|
|
|
@ -5,10 +5,14 @@ module QA
|
|||
module Project
|
||||
module SubMenus
|
||||
module Operations
|
||||
include Page::Project::SubMenus::Common
|
||||
extend QA::Page::PageConcern
|
||||
|
||||
def self.included(base)
|
||||
super
|
||||
|
||||
base.class_eval do
|
||||
include QA::Page::Project::SubMenus::Common
|
||||
|
||||
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
|
||||
element :operations_link
|
||||
element :operations_environments_link
|
||||
|
|
|
@ -5,10 +5,14 @@ module QA
|
|||
module Project
|
||||
module SubMenus
|
||||
module Project
|
||||
include Common
|
||||
extend QA::Page::PageConcern
|
||||
|
||||
def self.included(base)
|
||||
super
|
||||
|
||||
base.class_eval do
|
||||
include QA::Page::Project::SubMenus::Common
|
||||
|
||||
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
|
||||
element :project_link
|
||||
end
|
||||
|
|
|
@ -5,10 +5,14 @@ module QA
|
|||
module Project
|
||||
module SubMenus
|
||||
module Repository
|
||||
include Page::Project::SubMenus::Common
|
||||
extend QA::Page::PageConcern
|
||||
|
||||
def self.included(base)
|
||||
super
|
||||
|
||||
base.class_eval do
|
||||
include QA::Page::Project::SubMenus::Common
|
||||
|
||||
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
|
||||
element :project_menu_repo
|
||||
element :branches_link
|
||||
|
@ -44,5 +48,3 @@ module QA
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
QA::Page::Project::SubMenus::Repository.prepend_if_ee('QA::EE::Page::Project::SubMenus::Repository')
|
||||
|
|
|
@ -5,10 +5,14 @@ module QA
|
|||
module Project
|
||||
module SubMenus
|
||||
module Settings
|
||||
include Page::Project::SubMenus::Common
|
||||
extend QA::Page::PageConcern
|
||||
|
||||
def self.included(base)
|
||||
super
|
||||
|
||||
base.class_eval do
|
||||
include QA::Page::Project::SubMenus::Common
|
||||
|
||||
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
|
||||
element :settings_item
|
||||
element :link_members_settings
|
||||
|
|
|
@ -1,53 +1,55 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module QA::Page
|
||||
module Search
|
||||
class Results < QA::Page::Base
|
||||
view 'app/views/search/_category.html.haml' do
|
||||
element :code_tab
|
||||
element :projects_tab
|
||||
end
|
||||
|
||||
view 'app/views/search/results/_blob_data.html.haml' do
|
||||
element :result_item_content
|
||||
element :file_title_content
|
||||
element :file_text_content
|
||||
end
|
||||
|
||||
view 'app/views/shared/projects/_project.html.haml' do
|
||||
element :project
|
||||
end
|
||||
|
||||
def switch_to_code
|
||||
switch_to_tab(:code_tab)
|
||||
end
|
||||
|
||||
def switch_to_projects
|
||||
switch_to_tab(:projects_tab)
|
||||
end
|
||||
|
||||
def has_file_in_project?(file_name, project_name)
|
||||
has_element?(:result_item_content, text: "#{project_name}: #{file_name}")
|
||||
end
|
||||
|
||||
def has_file_with_content?(file_name, file_text)
|
||||
within_element_by_index(:result_item_content, 0) do
|
||||
break false unless has_element?(:file_title_content, text: file_name)
|
||||
|
||||
has_element?(:file_text_content, text: file_text)
|
||||
module QA
|
||||
module Page
|
||||
module Search
|
||||
class Results < QA::Page::Base
|
||||
view 'app/views/search/_category.html.haml' do
|
||||
element :code_tab
|
||||
element :projects_tab
|
||||
end
|
||||
end
|
||||
|
||||
def has_project?(project_name)
|
||||
has_element?(:project, project_name: project_name)
|
||||
end
|
||||
view 'app/views/search/results/_blob_data.html.haml' do
|
||||
element :result_item_content
|
||||
element :file_title_content
|
||||
element :file_text_content
|
||||
end
|
||||
|
||||
private
|
||||
view 'app/views/shared/projects/_project.html.haml' do
|
||||
element :project
|
||||
end
|
||||
|
||||
def switch_to_tab(tab)
|
||||
retry_until do
|
||||
click_element(tab)
|
||||
has_active_element?(tab)
|
||||
def switch_to_code
|
||||
switch_to_tab(:code_tab)
|
||||
end
|
||||
|
||||
def switch_to_projects
|
||||
switch_to_tab(:projects_tab)
|
||||
end
|
||||
|
||||
def has_file_in_project?(file_name, project_name)
|
||||
has_element?(:result_item_content, text: "#{project_name}: #{file_name}")
|
||||
end
|
||||
|
||||
def has_file_with_content?(file_name, file_text)
|
||||
within_element_by_index(:result_item_content, 0) do
|
||||
break false unless has_element?(:file_title_content, text: file_name)
|
||||
|
||||
has_element?(:file_text_content, text: file_text)
|
||||
end
|
||||
end
|
||||
|
||||
def has_project?(project_name)
|
||||
has_element?(:project, project_name: project_name)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def switch_to_tab(tab)
|
||||
retry_until do
|
||||
click_element(tab)
|
||||
has_active_element?(tab)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,83 +2,87 @@
|
|||
|
||||
require 'rspec/core'
|
||||
|
||||
module QA::Specs::Helpers
|
||||
module Quarantine
|
||||
include RSpec::Core::Pending
|
||||
module QA
|
||||
module Specs
|
||||
module Helpers
|
||||
module Quarantine
|
||||
include RSpec::Core::Pending
|
||||
|
||||
extend self
|
||||
extend self
|
||||
|
||||
def configure_rspec
|
||||
RSpec.configure do |config|
|
||||
config.before(:context, :quarantine) do
|
||||
Quarantine.skip_or_run_quarantined_contexts(config.inclusion_filter.rules, self.class)
|
||||
end
|
||||
def configure_rspec
|
||||
RSpec.configure do |config|
|
||||
config.before(:context, :quarantine) do
|
||||
Quarantine.skip_or_run_quarantined_contexts(config.inclusion_filter.rules, self.class)
|
||||
end
|
||||
|
||||
config.before do |example|
|
||||
Quarantine.skip_or_run_quarantined_tests_or_contexts(config.inclusion_filter.rules, example)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Skip the entire context if a context is quarantined. This avoids running
|
||||
# before blocks unnecessarily.
|
||||
def skip_or_run_quarantined_contexts(filters, example)
|
||||
return unless example.metadata.key?(:quarantine)
|
||||
|
||||
skip_or_run_quarantined_tests_or_contexts(filters, example)
|
||||
end
|
||||
|
||||
# Skip tests in quarantine unless we explicitly focus on them.
|
||||
def skip_or_run_quarantined_tests_or_contexts(filters, example)
|
||||
if filters.key?(:quarantine)
|
||||
included_filters = filters_other_than_quarantine(filters)
|
||||
|
||||
# If :quarantine is focused, skip the test/context unless its metadata
|
||||
# includes quarantine and any other filters
|
||||
# E.g., Suppose a test is tagged :smoke and :quarantine, and another is tagged
|
||||
# :ldap and :quarantine. If we wanted to run just quarantined smoke tests
|
||||
# using `--tag quarantine --tag smoke`, without this check we'd end up
|
||||
# running that ldap test as well because of the :quarantine metadata.
|
||||
# We could use an exclusion filter, but this way the test report will list
|
||||
# the quarantined tests when they're not run so that we're aware of them
|
||||
skip("Only running tests tagged with :quarantine and any of #{included_filters.keys}") if should_skip_when_focused?(example.metadata, included_filters)
|
||||
else
|
||||
if example.metadata.key?(:quarantine)
|
||||
quarantine_message = %w(In quarantine)
|
||||
quarantine_tag = example.metadata[:quarantine]
|
||||
|
||||
if !!quarantine_tag
|
||||
quarantine_message << case quarantine_tag
|
||||
when String
|
||||
": #{quarantine_tag}"
|
||||
when Hash
|
||||
": #{quarantine_tag[:issue]}"
|
||||
else
|
||||
''
|
||||
end
|
||||
config.before do |example|
|
||||
Quarantine.skip_or_run_quarantined_tests_or_contexts(config.inclusion_filter.rules, example)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
skip(quarantine_message.join(' ').strip)
|
||||
# Skip the entire context if a context is quarantined. This avoids running
|
||||
# before blocks unnecessarily.
|
||||
def skip_or_run_quarantined_contexts(filters, example)
|
||||
return unless example.metadata.key?(:quarantine)
|
||||
|
||||
skip_or_run_quarantined_tests_or_contexts(filters, example)
|
||||
end
|
||||
|
||||
# Skip tests in quarantine unless we explicitly focus on them.
|
||||
def skip_or_run_quarantined_tests_or_contexts(filters, example)
|
||||
if filters.key?(:quarantine)
|
||||
included_filters = filters_other_than_quarantine(filters)
|
||||
|
||||
# If :quarantine is focused, skip the test/context unless its metadata
|
||||
# includes quarantine and any other filters
|
||||
# E.g., Suppose a test is tagged :smoke and :quarantine, and another is tagged
|
||||
# :ldap and :quarantine. If we wanted to run just quarantined smoke tests
|
||||
# using `--tag quarantine --tag smoke`, without this check we'd end up
|
||||
# running that ldap test as well because of the :quarantine metadata.
|
||||
# We could use an exclusion filter, but this way the test report will list
|
||||
# the quarantined tests when they're not run so that we're aware of them
|
||||
skip("Only running tests tagged with :quarantine and any of #{included_filters.keys}") if should_skip_when_focused?(example.metadata, included_filters)
|
||||
else
|
||||
if example.metadata.key?(:quarantine)
|
||||
quarantine_message = %w(In quarantine)
|
||||
quarantine_tag = example.metadata[:quarantine]
|
||||
|
||||
if !!quarantine_tag
|
||||
quarantine_message << case quarantine_tag
|
||||
when String
|
||||
": #{quarantine_tag}"
|
||||
when Hash
|
||||
": #{quarantine_tag[:issue]}"
|
||||
else
|
||||
''
|
||||
end
|
||||
end
|
||||
|
||||
skip(quarantine_message.join(' ').strip)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def filters_other_than_quarantine(filter)
|
||||
filter.reject { |key, _| key == :quarantine }
|
||||
end
|
||||
|
||||
# Checks if a test or context should be skipped.
|
||||
#
|
||||
# Returns true if
|
||||
# - the metadata does not includes the :quarantine tag
|
||||
# or if
|
||||
# - the metadata includes the :quarantine tag
|
||||
# - and the filter includes other tags that aren't in the metadata
|
||||
def should_skip_when_focused?(metadata, included_filters)
|
||||
return true unless metadata.key?(:quarantine)
|
||||
return false if included_filters.empty?
|
||||
|
||||
(metadata.keys & included_filters.keys).empty?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def filters_other_than_quarantine(filter)
|
||||
filter.reject { |key, _| key == :quarantine }
|
||||
end
|
||||
|
||||
# Checks if a test or context should be skipped.
|
||||
#
|
||||
# Returns true if
|
||||
# - the metadata does not includes the :quarantine tag
|
||||
# or if
|
||||
# - the metadata includes the :quarantine tag
|
||||
# - and the filter includes other tags that aren't in the metadata
|
||||
def should_skip_when_focused?(metadata, included_filters)
|
||||
return true unless metadata.key?(:quarantine)
|
||||
return false if included_filters.empty?
|
||||
|
||||
(metadata.keys & included_filters.keys).empty?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
GlIcon,
|
||||
GlTab,
|
||||
} from '@gitlab/ui';
|
||||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
|
||||
import createFlash from '~/flash';
|
||||
import AlertManagementList from '~/alert_management/components/alert_management_list.vue';
|
||||
|
@ -18,6 +19,11 @@ import mockAlerts from '../mocks/alerts.json';
|
|||
|
||||
jest.mock('~/flash');
|
||||
|
||||
jest.mock('~/lib/utils/url_utility', () => ({
|
||||
visitUrl: jest.fn().mockName('visitUrlMock'),
|
||||
joinPaths: jest.requireActual('~/lib/utils/url_utility').joinPaths,
|
||||
}));
|
||||
|
||||
describe('AlertManagementList', () => {
|
||||
let wrapper;
|
||||
|
||||
|
@ -220,12 +226,10 @@ describe('AlertManagementList', () => {
|
|||
loading: false,
|
||||
});
|
||||
|
||||
window.location.assign = jest.fn();
|
||||
|
||||
findAlerts()
|
||||
.at(0)
|
||||
.trigger('click');
|
||||
expect(window.location.assign).toHaveBeenCalledWith('/1527542/details');
|
||||
expect(visitUrl).toHaveBeenCalledWith('/1527542/details');
|
||||
});
|
||||
|
||||
describe('handle date fields', () => {
|
||||
|
|
|
@ -3,16 +3,20 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe ContentTypeWhitelist do
|
||||
class DummyUploader < CarrierWave::Uploader::Base
|
||||
include ContentTypeWhitelist::Concern
|
||||
|
||||
def content_type_whitelist
|
||||
%w[image/png image/jpeg]
|
||||
end
|
||||
end
|
||||
|
||||
let_it_be(:model) { build_stubbed(:user) }
|
||||
let_it_be(:uploader) { DummyUploader.new(model, :dummy) }
|
||||
let!(:uploader) do
|
||||
stub_const('DummyUploader', Class.new(CarrierWave::Uploader::Base))
|
||||
|
||||
DummyUploader.class_eval do
|
||||
include ContentTypeWhitelist::Concern
|
||||
|
||||
def content_type_whitelist
|
||||
%w[image/png image/jpeg]
|
||||
end
|
||||
end
|
||||
|
||||
DummyUploader.new(model, :dummy)
|
||||
end
|
||||
|
||||
context 'upload whitelisted file content type' do
|
||||
let(:path) { File.join('spec', 'fixtures', 'rails_sample.jpg') }
|
||||
|
|
Loading…
Reference in a new issue