Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
fae5be5632
commit
0ac2fcc287
48 changed files with 391 additions and 316 deletions
|
@ -177,3 +177,7 @@ overrides:
|
|||
'@graphql-eslint/no-unused-variables': error
|
||||
'@graphql-eslint/no-unused-fragments': error
|
||||
'@graphql-eslint/no-duplicate-fields': error
|
||||
- files:
|
||||
- 'spec/contracts/consumer/**/*'
|
||||
rules:
|
||||
'@gitlab/require-i18n-strings': off
|
||||
|
|
|
@ -287,6 +287,7 @@ export default {
|
|||
:is-scroll-top-disabled="isScrollTopDisabled"
|
||||
:is-job-log-size-visible="isJobLogSizeVisible"
|
||||
:is-scrolling-down="isScrollingDown"
|
||||
:is-complete="isJobLogComplete"
|
||||
:job-log="jobLog"
|
||||
@scrollJobLogTop="scrollTop"
|
||||
@scrollJobLogBottom="scrollBottom"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { GlTooltipDirective, GlLink, GlButton, GlSearchBoxByClick } from '@gitlab/ui';
|
||||
import { scrollToElement } from '~/lib/utils/common_utils';
|
||||
import { scrollToElement, backOff } from '~/lib/utils/common_utils';
|
||||
import { numberToHumanSize } from '~/lib/utils/number_utils';
|
||||
import { __, s__, sprintf } from '~/locale';
|
||||
import HelpPopover from '~/vue_shared/components/help_popover.vue';
|
||||
|
@ -10,6 +10,7 @@ export default {
|
|||
i18n: {
|
||||
scrollToBottomButtonLabel: s__('Job|Scroll to bottom'),
|
||||
scrollToTopButtonLabel: s__('Job|Scroll to top'),
|
||||
scrollToNextFailureButtonLabel: s__('Job|Scroll to next failure'),
|
||||
showRawButtonLabel: s__('Job|Show complete raw'),
|
||||
searchPlaceholder: s__('Job|Search job log'),
|
||||
noResults: s__('Job|No search results found'),
|
||||
|
@ -55,6 +56,10 @@ export default {
|
|||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
isComplete: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
jobLog: {
|
||||
type: Array,
|
||||
required: true,
|
||||
|
@ -64,6 +69,8 @@ export default {
|
|||
return {
|
||||
searchTerm: '',
|
||||
searchResults: [],
|
||||
failureCount: null,
|
||||
failureIndex: 0,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
@ -75,13 +82,49 @@ export default {
|
|||
showJobLogSearch() {
|
||||
return this.glFeatures.jobLogSearch;
|
||||
},
|
||||
showJumpToFailures() {
|
||||
return this.glFeatures.jobLogJumpToFailures;
|
||||
},
|
||||
hasFailures() {
|
||||
return this.failureCount > 0;
|
||||
},
|
||||
shouldDisableJumpToFailures() {
|
||||
return !this.hasFailures;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.checkFailureCount();
|
||||
},
|
||||
methods: {
|
||||
checkFailureCount() {
|
||||
if (this.glFeatures.jobLogJumpToFailures) {
|
||||
backOff((next, stop) => {
|
||||
this.failureCount = document.querySelectorAll('.term-fg-l-red').length;
|
||||
|
||||
if (this.hasFailures || (this.isComplete && !this.hasFailures)) {
|
||||
stop();
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
handleScrollToNextFailure() {
|
||||
const failures = document.querySelectorAll('.term-fg-l-red');
|
||||
const nextFailure = failures[this.failureIndex];
|
||||
|
||||
if (nextFailure) {
|
||||
nextFailure.scrollIntoView({ block: 'center' });
|
||||
this.failureIndex = (this.failureIndex + 1) % failures.length;
|
||||
}
|
||||
},
|
||||
handleScrollToTop() {
|
||||
this.$emit('scrollJobLogTop');
|
||||
this.failureIndex = 0;
|
||||
},
|
||||
handleScrollToBottom() {
|
||||
this.$emit('scrollJobLogBottom');
|
||||
this.failureIndex = 0;
|
||||
},
|
||||
searchJobLog() {
|
||||
this.searchResults = [];
|
||||
|
@ -135,10 +178,10 @@ export default {
|
|||
};
|
||||
</script>
|
||||
<template>
|
||||
<div class="top-bar">
|
||||
<div class="top-bar gl-display-flex gl-justify-content-space-between">
|
||||
<!-- truncate information -->
|
||||
<div
|
||||
class="truncated-info gl-display-none gl-sm-display-block gl-float-left"
|
||||
class="truncated-info gl-display-none gl-sm-display-flex gl-flex-wrap gl-align-items-center"
|
||||
data-testid="log-truncated-info"
|
||||
>
|
||||
<template v-if="isJobLogSizeVisible">
|
||||
|
@ -154,7 +197,7 @@ export default {
|
|||
</div>
|
||||
<!-- eo truncate information -->
|
||||
|
||||
<div class="controllers gl-float-right">
|
||||
<div class="controllers">
|
||||
<template v-if="showJobLogSearch">
|
||||
<gl-search-box-by-click
|
||||
v-model="searchTerm"
|
||||
|
@ -187,6 +230,18 @@ export default {
|
|||
<!-- eo links -->
|
||||
|
||||
<!-- scroll buttons -->
|
||||
<gl-button
|
||||
v-if="showJumpToFailures"
|
||||
v-gl-tooltip
|
||||
:title="$options.i18n.scrollToNextFailureButtonLabel"
|
||||
:aria-label="$options.i18n.scrollToNextFailureButtonLabel"
|
||||
:disabled="shouldDisableJumpToFailures"
|
||||
class="btn-scroll gl-ml-3"
|
||||
data-testid="job-controller-scroll-to-failure"
|
||||
icon="soft-wrap"
|
||||
@click="handleScrollToNextFailure"
|
||||
/>
|
||||
|
||||
<div v-gl-tooltip :title="$options.i18n.scrollToTopButtonLabel" class="gl-ml-3">
|
||||
<gl-button
|
||||
:disabled="isScrollTopDisabled"
|
||||
|
|
|
@ -427,10 +427,10 @@
|
|||
padding-inline-start: 28px;
|
||||
margin-inline-start: 0 !important;
|
||||
|
||||
> input.task-list-item-checkbox {
|
||||
input.task-list-item-checkbox {
|
||||
position: absolute;
|
||||
inset-inline-start: 8px;
|
||||
top: 5px;
|
||||
inset-inline-start: $gl-padding-8;
|
||||
inset-block-start: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,17 +15,11 @@
|
|||
$stroke-size: 1px;
|
||||
|
||||
.right-arrow {
|
||||
@include gl-relative;
|
||||
height: $stroke-size;
|
||||
background-color: var(--gray-900, $gray-900);
|
||||
min-width: $gl-spacing-scale-7;
|
||||
|
||||
&-head {
|
||||
@include gl-absolute;
|
||||
top: -2*$stroke-size;
|
||||
left: calc(100% - #{5*$stroke-size});
|
||||
@include gl-p-1;
|
||||
@include gl-border-solid;
|
||||
top: -2 * $stroke-size;
|
||||
left: calc(100% - #{5 * $stroke-size});
|
||||
border-width: 0 $stroke-size $stroke-size 0;
|
||||
border-color: var(--gray-900, $gray-900);
|
||||
transform: rotate(-45deg);
|
||||
|
@ -41,14 +35,10 @@ $stroke-size: 1px;
|
|||
.rule-condition {
|
||||
@media (min-width: $breakpoint-lg) {
|
||||
flex-basis: 25%;
|
||||
flex-shrink: 0;
|
||||
@include gl-flex-shrink-0;
|
||||
}
|
||||
|
||||
@media (max-width: $breakpoint-lg) {
|
||||
@include gl-w-full;
|
||||
}
|
||||
}
|
||||
|
||||
.rule-action {
|
||||
min-width: 0;
|
||||
}
|
||||
|
|
|
@ -1,77 +1,24 @@
|
|||
@import 'mixins_and_variables_and_functions';
|
||||
|
||||
.description {
|
||||
ul,
|
||||
ol {
|
||||
/* We're changing list-style-position to inside because the default of
|
||||
* outside doesn't move negative margin to the left of the bullet. */
|
||||
list-style-position: inside;
|
||||
ul.task-list > li.task-list-item {
|
||||
margin-inline-start: 0.5rem !important; /* Override typography.scss */
|
||||
}
|
||||
|
||||
li {
|
||||
position: relative;
|
||||
/* In the browser, the li element comes after (to the right of) the bullet point, so hovering
|
||||
* over the left of the bullet point doesn't trigger a row hover. To trigger hovering on the
|
||||
* left, we're applying negative margin here to shift the li element left. */
|
||||
margin-inline-start: -1rem;
|
||||
padding-inline-start: 2.5rem;
|
||||
margin-inline-start: 2.25rem;
|
||||
|
||||
&.task-list-item > .drag-icon {
|
||||
inset-inline-start: -0.6rem;
|
||||
}
|
||||
|
||||
.drag-icon {
|
||||
position: absolute;
|
||||
inset-block-start: 0.3rem;
|
||||
inset-inline-start: 1rem;
|
||||
}
|
||||
|
||||
/* The inside bullet aligns itself to the bottom, which we see when text to the right of
|
||||
* a multi-line list item wraps. We fix this by aligning it to the top, and excluding
|
||||
* other elements. Targeting ::marker doesn't seem to work, instead we exclude custom elements
|
||||
* or anything with a class */
|
||||
> *:not(gl-emoji, code, [class]) {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
/* The inside bullet is treated like an element inside the li element, so when we have a
|
||||
* multi-paragraph list item, the text doesn't start on the right of the bullet because
|
||||
* it is a block level p element. We make it inline to fix this. */
|
||||
> p:first-of-type {
|
||||
display: inline-block;
|
||||
max-width: calc(100% - 1.5rem);
|
||||
}
|
||||
|
||||
/* We fix the other paragraphs not indenting to the
|
||||
* right of the bullet due to the inside bullet. */
|
||||
p ~ a,
|
||||
p ~ blockquote,
|
||||
p ~ code,
|
||||
p ~ details,
|
||||
p ~ dl,
|
||||
p ~ h1,
|
||||
p ~ h2,
|
||||
p ~ h3,
|
||||
p ~ h4,
|
||||
p ~ h5,
|
||||
p ~ h6,
|
||||
p ~ hr,
|
||||
p ~ ol,
|
||||
p ~ p,
|
||||
p ~ table:not(.code), /* We need :not(.code) to override typography.scss */
|
||||
p ~ ul,
|
||||
p ~ .markdown-code-block {
|
||||
margin-inline-start: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
ul.task-list {
|
||||
> li.task-list-item {
|
||||
/* We're using !important to override the same selector in typography.scss */
|
||||
margin-inline-start: -1rem !important;
|
||||
padding-inline-start: 2.5rem;
|
||||
|
||||
> input.task-list-item-checkbox {
|
||||
position: static;
|
||||
vertical-align: middle;
|
||||
margin-block-start: -2px;
|
||||
}
|
||||
inset-inline-start: -2.3rem;
|
||||
padding-inline-end: 1rem;
|
||||
width: 2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ class Projects::JobsController < Projects::ApplicationController
|
|||
before_action :authorize_create_proxy_build!, only: :proxy_websocket_authorize
|
||||
before_action :verify_proxy_request!, only: :proxy_websocket_authorize
|
||||
before_action :push_job_log_search, only: [:show]
|
||||
before_action :push_job_log_jump_to_failures, only: [:show]
|
||||
before_action :reject_if_build_artifacts_size_refreshing!, only: [:erase]
|
||||
|
||||
layout 'project'
|
||||
|
@ -252,4 +253,8 @@ class Projects::JobsController < Projects::ApplicationController
|
|||
def push_job_log_search
|
||||
push_frontend_feature_flag(:job_log_search, @project)
|
||||
end
|
||||
|
||||
def push_job_log_jump_to_failures
|
||||
push_frontend_feature_flag(:job_log_jump_to_failures, @project)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: job_log_jump_to_failures
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91098
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/368633
|
||||
milestone: '15.3'
|
||||
type: development
|
||||
group: group::pipeline execution
|
||||
default_enabled: false
|
|
@ -106,7 +106,7 @@ POST /groups/:id/protected_environments
|
|||
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](index.md#namespaced-path-encoding) maintained by the authenticated user. |
|
||||
| `name` | string | yes | The deployment tier of the protected environment. One of `production`, `staging`, `testing`, `development`, or `other`. Read more about [deployment tiers](../ci/environments/index.md#deployment-tier-of-environments).|
|
||||
| `deploy_access_levels` | array | yes | Array of access levels allowed to deploy, with each described by a hash. One of `user_id`, `group_id` or `access_level`. They take the form of `{user_id: integer}`, `{group_id: integer}` or `{access_level: integer}` respectively. |
|
||||
| `required_approval_count` | integer | no | The number of approvals required to deploy to this environment. This is part of Deployment Approvals, which isn't yet available for use. For details, see [issue](https://gitlab.com/gitlab-org/gitlab/-/issues/343864). |
|
||||
| `required_approval_count` | integer | no | The number of approvals required to deploy to this environment. |
|
||||
| `approval_rules` | array | no | Array of access levels allowed to approve, with each described by a hash. One of `user_id`, `group_id` or `access_level`. They take the form of `{user_id: integer}`, `{group_id: integer}` or `{access_level: integer}` respectively. You can also specify the number of required approvals from the specified entity with `required_approvals` field. See [Multiple approval rules](../ci/environments/deployment_approvals.md#multiple-approval-rules) for more information. |
|
||||
|
||||
The assignable `user_id` are the users who belong to the given group with the Maintainer role (or above).
|
||||
|
|
|
@ -709,7 +709,6 @@ args: {
|
|||
security: {
|
||||
authn_requests_signed: true, # enable signature on AuthNRequest
|
||||
want_assertions_signed: true, # enable the requirement of signed assertion
|
||||
embed_sign: true, # embedded signature or HTTP GET parameter signature
|
||||
metadata_signed: false, # enable signature on Metadata
|
||||
signature_method: 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256',
|
||||
digest_method: 'http://www.w3.org/2001/04/xmlenc#sha256',
|
||||
|
|
|
@ -601,7 +601,7 @@ The following variables allow configuration of global dependency scanning settin
|
|||
| `ADDITIONAL_CA_CERT_BUNDLE` | Bundle of CA certs to trust. The bundle of certificates provided here is also used by other tools during the scanning process, such as `git`, `yarn`, or `npm`. See [Using a custom SSL CA certificate authority](#using-a-custom-ssl-ca-certificate-authority) for more details. |
|
||||
| `DS_EXCLUDED_ANALYZERS` | Specify the analyzers (by name) to exclude from Dependency Scanning. For more information, see [Dependency Scanning Analyzers](analyzers.md). |
|
||||
| `DS_DEFAULT_ANALYZERS` | This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/287691) in GitLab 14.0 and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/333299) in 15.0. Use `DS_EXCLUDED_ANALYZERS` instead. |
|
||||
| `DS_EXCLUDED_PATHS` | Exclude files and directories from the scan based on the paths. A comma-separated list of patterns. Patterns can be globs, or file or folder paths (for example, `doc,spec`). Parent directories also match patterns. Default: `"spec, test, tests, tmp"`. |
|
||||
| `DS_EXCLUDED_PATHS` | Exclude files and directories from the scan based on the paths. A comma-separated list of patterns. Patterns can be globs (see [`doublestar.Match`](https://pkg.go.dev/github.com/bmatcuk/doublestar/v4@v4.0.2#Match) for supported patterns), or file or folder paths (for example, `doc,spec`). Parent directories also match patterns. Default: `"spec, test, tests, tmp"`. |
|
||||
| `DS_IMAGE_SUFFIX` | Suffix added to the image name. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/354796) in GitLab 14.10.) Automatically set to `"-fips"` when FIPS mode is enabled. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/357922) in GitLab 15.0.) |
|
||||
| `SECURE_ANALYZERS_PREFIX` | Override the name of the Docker registry providing the official default images (proxy). Read more about [customizing analyzers](analyzers.md). |
|
||||
| `SECURE_LOG_LEVEL` | Set the minimum logging level. Messages of this logging level or higher are output. From highest to lowest severity, the logging levels are: `fatal`, `error`, `warn`, `info`, `debug`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10880) in GitLab 13.1. Default: `info`. |
|
||||
|
|
34
doc/user/application_security/get-started-security.md
Normal file
34
doc/user/application_security/get-started-security.md
Normal file
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
stage: DevSecOps
|
||||
group: Technical writing
|
||||
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/#assignments
|
||||
---
|
||||
|
||||
# Get started with GitLab application security **(ULTIMATE)**
|
||||
|
||||
Complete the following steps to get the most from GitLab application security tools.
|
||||
|
||||
1. Enable [Secret Detection](secret_detection/index.md) scanning for your default branch.
|
||||
1. Enable [Dependency Scanning](dependency_scanning/index.md) for your default branch so you can start identifying existing
|
||||
vulnerable packages in your codebase.
|
||||
1. Add security scans to feature branch pipelines. The same scans should be enabled as are running
|
||||
on your default branch. Subsequent scans will show only new vulnerabilities by comparing the feature branch to the default branch results.
|
||||
1. Let your team get comfortable with [vulnerability reports](vulnerability_report/index.md) and
|
||||
establish a vulnerability triage workflow.
|
||||
1. Consider creating [labels](../project/labels.md) and [issue boards](../project/issue_board.md) to
|
||||
help manage issues created from vulnerabilities. Issue boards allow all stakeholders to have a
|
||||
common view of all issues.
|
||||
1. Create a [scan result policy](policies/index.md) to limit new vulnerabilities from being merged
|
||||
into your default branch.
|
||||
1. Monitor the [Security Dashboard](security_dashboard/index.md) trends to gauge success in
|
||||
remediating existing vulnerabilities and preventing the introduction of new ones.
|
||||
1. Enable other scan types such as [SAST](sast/index.md), [DAST](dast/index.md),
|
||||
[Fuzz testing](coverage_fuzzing/index.md), or [Container Scanning](container_scanning/index.md).
|
||||
Be sure to add the same scan types to both feature pipelines and default branch pipelines.
|
||||
1. Use [Compliance Pipelines](../../user/project/settings/index.md#compliance-pipeline-configuration)
|
||||
or [Scan Execution Policies](policies/scan-execution-policies.md) to enforce required scan types
|
||||
and ensure separation of duties between security and engineering.
|
||||
1. Consider enabling [Review Apps](../../development/testing_guide/review_apps.md) to allow for DAST
|
||||
and [Web API fuzzing](api_fuzzing/index.md) on ephemeral test environments.
|
||||
1. Enable [operational container scanning](../../user/clusters/agent/vulnerabilities.md) to scan
|
||||
container images in your production cluster for security vulnerabilities.
|
|
@ -4,31 +4,30 @@ return if Rails.env.production?
|
|||
|
||||
require 'pact/tasks/verification_task'
|
||||
|
||||
contracts = File.expand_path('../../../spec/contracts', __dir__)
|
||||
provider = File.expand_path('provider', contracts)
|
||||
contracts = File.expand_path('../../../spec/contracts/contracts/project/merge_request', __dir__)
|
||||
provider = File.expand_path('../../../spec/contracts/provider', __dir__)
|
||||
|
||||
# rubocop:disable Rails/RakeEnvironment
|
||||
namespace :contracts do
|
||||
namespace :merge_requests do
|
||||
Pact::VerificationTask.new(:diffs_batch) do |pact|
|
||||
pact.uri(
|
||||
"#{contracts}/contracts/project/merge_request/show/mergerequest#show-merge_request_diffs_batch_endpoint.json",
|
||||
pact_helper: "#{provider}/pact_helpers/project/merge_request/diffs_batch_helper.rb"
|
||||
"#{contracts}/show/mergerequest#show-merge_request_diffs_batch_endpoint.json",
|
||||
pact_helper: "#{provider}/pact_helpers/project/merge_request/show/diffs_batch_helper.rb"
|
||||
)
|
||||
end
|
||||
|
||||
Pact::VerificationTask.new(:diffs_metadata) do |pact|
|
||||
pact.uri(
|
||||
"#{contracts}/contracts/project/merge_request/show/" \
|
||||
"mergerequest#show-merge_request_diffs_metadata_endpoint.json",
|
||||
pact_helper: "#{provider}/pact_helpers/project/merge_request/diffs_metadata_helper.rb"
|
||||
"#{contracts}/show/mergerequest#show-merge_request_diffs_metadata_endpoint.json",
|
||||
pact_helper: "#{provider}/pact_helpers/project/merge_request/show/diffs_metadata_helper.rb"
|
||||
)
|
||||
end
|
||||
|
||||
Pact::VerificationTask.new(:discussions) do |pact|
|
||||
pact.uri(
|
||||
"#{contracts}/contracts/project/merge_request/show/mergerequest#show-merge_request_discussions_endpoint.json",
|
||||
pact_helper: "#{provider}/pact_helpers/project/merge_request/discussions_helper.rb"
|
||||
"#{contracts}/show/mergerequest#show-merge_request_discussions_endpoint.json",
|
||||
pact_helper: "#{provider}/pact_helpers/project/merge_request/show/discussions_helper.rb"
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ return if Rails.env.production?
|
|||
require 'pact/tasks/verification_task'
|
||||
|
||||
contracts = File.expand_path('../../../spec/contracts/contracts/project/pipeline_schedule', __dir__)
|
||||
provider = File.expand_path('../../../provider', contracts)
|
||||
provider = File.expand_path('../../../spec/contracts/provider', __dir__)
|
||||
|
||||
# rubocop:disable Rails/RakeEnvironment
|
||||
namespace :contracts do
|
||||
|
|
|
@ -4,36 +4,36 @@ return if Rails.env.production?
|
|||
|
||||
require 'pact/tasks/verification_task'
|
||||
|
||||
contracts = File.expand_path('../../../spec/contracts', __dir__)
|
||||
provider = File.expand_path('provider', contracts)
|
||||
contracts = File.expand_path('../../../spec/contracts/contracts/project/pipeline', __dir__)
|
||||
provider = File.expand_path('../../../spec/contracts/provider', __dir__)
|
||||
|
||||
# rubocop:disable Rails/RakeEnvironment
|
||||
namespace :contracts do
|
||||
namespace :pipelines do
|
||||
Pact::VerificationTask.new(:create_a_new_pipeline) do |pact|
|
||||
pact.uri(
|
||||
"#{contracts}/contracts/project/pipeline/new/pipelines#new-post_create_a_new_pipeline.json",
|
||||
pact_helper: "#{provider}/pact_helpers/project/pipeline/create_a_new_pipeline_helper.rb"
|
||||
"#{contracts}/new/pipelines#new-post_create_a_new_pipeline.json",
|
||||
pact_helper: "#{provider}/pact_helpers/project/pipeline/index/create_a_new_pipeline_helper.rb"
|
||||
)
|
||||
end
|
||||
|
||||
Pact::VerificationTask.new(:get_list_project_pipelines) do |pact|
|
||||
pact.uri(
|
||||
"#{contracts}/contracts/project/pipeline/index/pipelines#index-get_list_project_pipelines.json",
|
||||
pact_helper: "#{provider}/pact_helpers/project/pipeline/get_list_project_pipelines_helper.rb"
|
||||
"#{contracts}/index/pipelines#index-get_list_project_pipelines.json",
|
||||
pact_helper: "#{provider}/pact_helpers/project/pipeline/index/get_list_project_pipelines_helper.rb"
|
||||
)
|
||||
end
|
||||
|
||||
Pact::VerificationTask.new(:get_pipeline_header_data) do |pact|
|
||||
pact.uri(
|
||||
"#{contracts}/contracts/project/pipeline/show/pipelines#show-get_pipeline_header_data.json",
|
||||
"#{contracts}/show/pipelines#show-get_pipeline_header_data.json",
|
||||
pact_helper: "#{provider}/pact_helpers/project/pipeline/show/get_pipeline_header_data_helper.rb"
|
||||
)
|
||||
end
|
||||
|
||||
Pact::VerificationTask.new(:delete_pipeline) do |pact|
|
||||
pact.uri(
|
||||
"#{contracts}/contracts/project/pipeline/show/pipelines#show-delete_pipeline.json",
|
||||
"#{contracts}/show/pipelines#show-delete_pipeline.json",
|
||||
pact_helper: "#{provider}/pact_helpers/project/pipeline/show/delete_pipeline_helper.rb"
|
||||
)
|
||||
end
|
||||
|
|
|
@ -22656,6 +22656,9 @@ msgstr ""
|
|||
msgid "Job|Scroll to bottom"
|
||||
msgstr ""
|
||||
|
||||
msgid "Job|Scroll to next failure"
|
||||
msgstr ""
|
||||
|
||||
msgid "Job|Scroll to top"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
import { request } from 'axios';
|
||||
|
||||
export function getProjectPipelines(endpoint) {
|
||||
const { url } = endpoint;
|
||||
|
||||
return request({
|
||||
method: 'GET',
|
||||
baseURL: url,
|
||||
url: '/gitlab-org/gitlab-qa/-/pipelines.json',
|
||||
headers: { Accept: '*/*' },
|
||||
params: {
|
||||
scope: 'all',
|
||||
page: 1,
|
||||
},
|
||||
}).then((response) => response.data);
|
||||
}
|
|
@ -1,5 +1,3 @@
|
|||
/* eslint-disable @gitlab/require-i18n-strings */
|
||||
|
||||
import { Matchers } from '@pact-foundation/pact';
|
||||
|
||||
const body = {
|
||||
|
@ -73,8 +71,12 @@ const DiffsBatch = {
|
|||
body,
|
||||
},
|
||||
|
||||
request: {
|
||||
scenario: {
|
||||
state: 'a merge request with diffs exists',
|
||||
uponReceiving: 'a request for diff lines',
|
||||
},
|
||||
|
||||
request: {
|
||||
withRequest: {
|
||||
method: 'GET',
|
||||
path: '/gitlab-org/gitlab-qa/-/merge_requests/1/diffs_batch.json',
|
||||
|
@ -87,5 +89,3 @@ const DiffsBatch = {
|
|||
};
|
||||
|
||||
export { DiffsBatch };
|
||||
|
||||
/* eslint-enable @gitlab/require-i18n-strings */
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* eslint-disable @gitlab/require-i18n-strings */
|
||||
|
||||
import { Matchers } from '@pact-foundation/pact';
|
||||
|
||||
const body = {
|
||||
|
@ -81,8 +79,12 @@ const DiffsMetadata = {
|
|||
body,
|
||||
},
|
||||
|
||||
scenario: {
|
||||
state: 'a merge request exists',
|
||||
uponReceiving: 'a request for diffs metadata',
|
||||
},
|
||||
|
||||
request: {
|
||||
uponReceiving: 'a request for Diffs Metadata',
|
||||
withRequest: {
|
||||
method: 'GET',
|
||||
path: '/gitlab-org/gitlab-qa/-/merge_requests/1/diffs_metadata.json',
|
||||
|
@ -94,5 +96,3 @@ const DiffsMetadata = {
|
|||
};
|
||||
|
||||
export { DiffsMetadata };
|
||||
|
||||
/* eslint-enable @gitlab/require-i18n-strings */
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* eslint-disable @gitlab/require-i18n-strings */
|
||||
|
||||
import { Matchers } from '@pact-foundation/pact';
|
||||
|
||||
const body = Matchers.eachLike({
|
||||
|
@ -70,8 +68,12 @@ const Discussions = {
|
|||
body,
|
||||
},
|
||||
|
||||
request: {
|
||||
scenario: {
|
||||
state: 'a merge request with discussions exists',
|
||||
uponReceiving: 'a request for discussions',
|
||||
},
|
||||
|
||||
request: {
|
||||
withRequest: {
|
||||
method: 'GET',
|
||||
path: '/gitlab-org/gitlab-qa/-/merge_requests/1/discussions.json',
|
||||
|
@ -83,5 +85,3 @@ const Discussions = {
|
|||
};
|
||||
|
||||
export { Discussions };
|
||||
|
||||
/* eslint-enable @gitlab/require-i18n-strings */
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* eslint-disable @gitlab/require-i18n-strings */
|
||||
|
||||
import { Matchers } from '@pact-foundation/pact';
|
||||
import { REDIRECT_HTML } from '../../../helpers/common_regex_patterns';
|
||||
|
||||
|
@ -39,5 +37,3 @@ const NewProjectPipeline = {
|
|||
};
|
||||
|
||||
export { NewProjectPipeline };
|
||||
|
||||
/* eslint-enable @gitlab/require-i18n-strings */
|
||||
|
|
|
@ -6,6 +6,11 @@ const DeletePipeline = {
|
|||
},
|
||||
},
|
||||
|
||||
scenario: {
|
||||
state: 'a pipeline for a project exists',
|
||||
uponReceiving: 'a request to delete the pipeline',
|
||||
},
|
||||
|
||||
request: {
|
||||
method: 'POST',
|
||||
path: '/api/graphql',
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* eslint-disable @gitlab/require-i18n-strings */
|
||||
|
||||
import { Matchers } from '@pact-foundation/pact';
|
||||
import {
|
||||
URL,
|
||||
|
@ -225,8 +223,12 @@ const ProjectPipelines = {
|
|||
body,
|
||||
},
|
||||
|
||||
request: {
|
||||
scenario: {
|
||||
state: 'a few pipelines for a project exists',
|
||||
uponReceiving: 'a request for a list of project pipelines',
|
||||
},
|
||||
|
||||
request: {
|
||||
withRequest: {
|
||||
method: 'GET',
|
||||
path: '/gitlab-org/gitlab-qa/-/pipelines.json',
|
||||
|
@ -239,5 +241,3 @@ const ProjectPipelines = {
|
|||
};
|
||||
|
||||
export { ProjectPipelines };
|
||||
|
||||
/* eslint-enable @gitlab/require-i18n-strings */
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* eslint-disable @gitlab/require-i18n-strings */
|
||||
|
||||
import { Matchers } from '@pact-foundation/pact';
|
||||
import {
|
||||
JOB_STATUSES,
|
||||
|
@ -83,6 +81,11 @@ const PipelineHeaderData = {
|
|||
body,
|
||||
},
|
||||
|
||||
scenario: {
|
||||
state: 'a pipeline for a project exists',
|
||||
uponReceiving: 'a request for the pipeline header data',
|
||||
},
|
||||
|
||||
request: {
|
||||
method: 'POST',
|
||||
path: '/api/graphql',
|
||||
|
@ -95,5 +98,3 @@ const PipelineHeaderData = {
|
|||
};
|
||||
|
||||
export { PipelineHeaderData };
|
||||
|
||||
/* eslint-enable @gitlab/require-i18n-strings */
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* eslint-disable @gitlab/require-i18n-strings */
|
||||
|
||||
import { Matchers } from '@pact-foundation/pact';
|
||||
import { REDIRECT_HTML } from '../../../helpers/common_regex_patterns';
|
||||
|
||||
|
@ -44,5 +42,3 @@ const UpdatePipelineSchedule = {
|
|||
};
|
||||
|
||||
export { UpdatePipelineSchedule };
|
||||
|
||||
/* eslint-enable @gitlab/require-i18n-strings */
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { request } from 'axios';
|
||||
import axios from 'axios';
|
||||
|
||||
export function getDiffsMetadata(endpoint) {
|
||||
export async function getDiffsMetadata(endpoint) {
|
||||
const { url } = endpoint;
|
||||
|
||||
return request({
|
||||
return axios({
|
||||
method: 'GET',
|
||||
baseURL: url,
|
||||
url: '/gitlab-org/gitlab-qa/-/merge_requests/1/diffs_metadata.json',
|
||||
|
@ -11,10 +11,10 @@ export function getDiffsMetadata(endpoint) {
|
|||
}).then((response) => response.data);
|
||||
}
|
||||
|
||||
export function getDiscussions(endpoint) {
|
||||
export async function getDiscussions(endpoint) {
|
||||
const { url } = endpoint;
|
||||
|
||||
return request({
|
||||
return axios({
|
||||
method: 'GET',
|
||||
baseURL: url,
|
||||
url: '/gitlab-org/gitlab-qa/-/merge_requests/1/discussions.json',
|
||||
|
@ -22,10 +22,10 @@ export function getDiscussions(endpoint) {
|
|||
}).then((response) => response.data);
|
||||
}
|
||||
|
||||
export function getDiffsBatch(endpoint) {
|
||||
export async function getDiffsBatch(endpoint) {
|
||||
const { url } = endpoint;
|
||||
|
||||
return request({
|
||||
return axios({
|
||||
method: 'GET',
|
||||
baseURL: url,
|
||||
url: '/gitlab-org/gitlab-qa/-/merge_requests/1/diffs_batch.json?page=0',
|
|
@ -1,5 +1,20 @@
|
|||
import axios from 'axios';
|
||||
|
||||
export async function getProjectPipelines(endpoint) {
|
||||
const { url } = endpoint;
|
||||
|
||||
return axios({
|
||||
method: 'GET',
|
||||
baseURL: url,
|
||||
url: '/gitlab-org/gitlab-qa/-/pipelines.json',
|
||||
headers: { Accept: '*/*' },
|
||||
params: {
|
||||
scope: 'all',
|
||||
page: 1,
|
||||
},
|
||||
}).then((response) => response.data);
|
||||
}
|
||||
|
||||
export async function postProjectPipelines(endpoint) {
|
||||
const { url } = endpoint;
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* eslint-disable @gitlab/require-i18n-strings */
|
||||
|
||||
import { pactWith } from 'jest-pact';
|
||||
|
||||
import { DiffsBatch } from '../../../fixtures/project/merge_request/diffs_batch.fixture';
|
||||
|
@ -9,7 +7,7 @@ import {
|
|||
getDiffsBatch,
|
||||
getDiffsMetadata,
|
||||
getDiscussions,
|
||||
} from '../../../endpoints/project/merge_requests';
|
||||
} from '../../../resources/api/project/merge_requests';
|
||||
|
||||
const CONSUMER_NAME = 'MergeRequest#show';
|
||||
const CONSUMER_LOG = '../logs/consumer.log';
|
||||
|
@ -31,19 +29,19 @@ pactWith(
|
|||
describe(DIFFS_BATCH_PROVIDER_NAME, () => {
|
||||
beforeEach(() => {
|
||||
const interaction = {
|
||||
state: 'a merge request with diffs exists',
|
||||
...DiffsBatch.scenario,
|
||||
...DiffsBatch.request,
|
||||
willRespondWith: DiffsBatch.success,
|
||||
};
|
||||
provider.addInteraction(interaction);
|
||||
});
|
||||
|
||||
it('returns a successful body', () => {
|
||||
return getDiffsBatch({
|
||||
it('returns a successful body', async () => {
|
||||
const diffsBatch = await getDiffsBatch({
|
||||
url: provider.mockService.baseUrl,
|
||||
}).then((diffsBatch) => {
|
||||
expect(diffsBatch).toEqual(DiffsBatch.body);
|
||||
});
|
||||
|
||||
expect(diffsBatch).toEqual(DiffsBatch.body);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
@ -61,19 +59,19 @@ pactWith(
|
|||
describe(DISCUSSIONS_PROVIDER_NAME, () => {
|
||||
beforeEach(() => {
|
||||
const interaction = {
|
||||
state: 'a merge request with discussions exists',
|
||||
...Discussions.scenario,
|
||||
...Discussions.request,
|
||||
willRespondWith: Discussions.success,
|
||||
};
|
||||
provider.addInteraction(interaction);
|
||||
});
|
||||
|
||||
it('return a successful body', () => {
|
||||
return getDiscussions({
|
||||
it('return a successful body', async () => {
|
||||
const discussions = await getDiscussions({
|
||||
url: provider.mockService.baseUrl,
|
||||
}).then((discussions) => {
|
||||
expect(discussions).toEqual(Discussions.body);
|
||||
});
|
||||
|
||||
expect(discussions).toEqual(Discussions.body);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
@ -91,22 +89,20 @@ pactWith(
|
|||
describe(DIFFS_METADATA_PROVIDER_NAME, () => {
|
||||
beforeEach(() => {
|
||||
const interaction = {
|
||||
state: 'a merge request exists',
|
||||
...DiffsMetadata.scenario,
|
||||
...DiffsMetadata.request,
|
||||
willRespondWith: DiffsMetadata.success,
|
||||
};
|
||||
provider.addInteraction(interaction);
|
||||
});
|
||||
|
||||
it('return a successful body', () => {
|
||||
return getDiffsMetadata({
|
||||
it('return a successful body', async () => {
|
||||
const diffsMetadata = await getDiffsMetadata({
|
||||
url: provider.mockService.baseUrl,
|
||||
}).then((diffsMetadata) => {
|
||||
expect(diffsMetadata).toEqual(DiffsMetadata.body);
|
||||
});
|
||||
|
||||
expect(diffsMetadata).toEqual(DiffsMetadata.body);
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
/* eslint-enable @gitlab/require-i18n-strings */
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
/* eslint-disable @gitlab/require-i18n-strings */
|
||||
|
||||
import { pactWith } from 'jest-pact';
|
||||
|
||||
import { ProjectPipelines } from '../../../fixtures/project/pipeline/get_list_project_pipelines.fixture';
|
||||
import { getProjectPipelines } from '../../../endpoints/project/pipelines';
|
||||
import { getProjectPipelines } from '../../../resources/api/project/pipelines';
|
||||
|
||||
const CONSUMER_NAME = 'Pipelines#index';
|
||||
const CONSUMER_LOG = '../logs/consumer.log';
|
||||
|
@ -23,22 +21,20 @@ pactWith(
|
|||
describe(PROVIDER_NAME, () => {
|
||||
beforeEach(() => {
|
||||
const interaction = {
|
||||
state: 'a few pipelines for a project exists',
|
||||
...ProjectPipelines.scenario,
|
||||
...ProjectPipelines.request,
|
||||
willRespondWith: ProjectPipelines.success,
|
||||
};
|
||||
provider.addInteraction(interaction);
|
||||
});
|
||||
|
||||
it('returns a successful body', () => {
|
||||
return getProjectPipelines({
|
||||
it('returns a successful body', async () => {
|
||||
const pipelines = await getProjectPipelines({
|
||||
url: provider.mockService.baseUrl,
|
||||
}).then((pipelines) => {
|
||||
expect(pipelines).toEqual(ProjectPipelines.body);
|
||||
});
|
||||
|
||||
expect(pipelines).toEqual(ProjectPipelines.body);
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
/* eslint-enable @gitlab/require-i18n-strings */
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* eslint-disable @gitlab/require-i18n-strings */
|
||||
|
||||
import { pactWith } from 'jest-pact';
|
||||
|
||||
import { NewProjectPipeline } from '../../../fixtures/project/pipeline/create_a_new_pipeline.fixture';
|
||||
|
@ -41,5 +39,3 @@ pactWith(
|
|||
});
|
||||
},
|
||||
);
|
||||
|
||||
/* eslint-enable @gitlab/require-i18n-strings */
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* eslint-disable @gitlab/require-i18n-strings */
|
||||
|
||||
import { pactWith } from 'jest-pact';
|
||||
import { GraphQLInteraction } from '@pact-foundation/pact';
|
||||
|
||||
|
@ -32,8 +30,8 @@ pactWith(
|
|||
'app/assets/javascripts/pipelines/graphql/queries/get_pipeline_header_data.query.graphql',
|
||||
);
|
||||
const graphqlQuery = new GraphQLInteraction()
|
||||
.given('a pipeline for a project exists')
|
||||
.uponReceiving('a request for the pipeline header data')
|
||||
.given(PipelineHeaderData.scenario.state)
|
||||
.uponReceiving(PipelineHeaderData.scenario.uponReceiving)
|
||||
.withQuery(query)
|
||||
.withRequest(PipelineHeaderData.request)
|
||||
.withVariables(PipelineHeaderData.variables)
|
||||
|
@ -69,8 +67,8 @@ pactWith(
|
|||
'app/assets/javascripts/pipelines/graphql/mutations/delete_pipeline.mutation.graphql',
|
||||
);
|
||||
const graphqlQuery = new GraphQLInteraction()
|
||||
.given('a pipeline for a project exists')
|
||||
.uponReceiving('a request to delete the pipeline')
|
||||
.given(DeletePipeline.scenario.state)
|
||||
.uponReceiving(DeletePipeline.scenario.uponReceiving)
|
||||
.withQuery(query)
|
||||
.withRequest(DeletePipeline.request)
|
||||
.withVariables(DeletePipeline.variables)
|
||||
|
@ -89,5 +87,3 @@ pactWith(
|
|||
});
|
||||
},
|
||||
);
|
||||
|
||||
/* eslint-enable @gitlab/require-i18n-strings */
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* eslint-disable @gitlab/require-i18n-strings */
|
||||
|
||||
import { pactWith } from 'jest-pact';
|
||||
|
||||
import { UpdatePipelineSchedule } from '../../../fixtures/project/pipeline_schedule/update_pipeline_schedule.fixture';
|
||||
|
@ -41,5 +39,3 @@ pactWith(
|
|||
});
|
||||
},
|
||||
);
|
||||
|
||||
/* eslint-enable @gitlab/require-i18n-strings */
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
},
|
||||
"interactions": [
|
||||
{
|
||||
"description": "a request for Diffs Metadata",
|
||||
"description": "a request for diffs metadata",
|
||||
"providerState": "a merge request exists",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
|
@ -220,4 +220,4 @@
|
|||
"version": "2.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../../spec_helper'
|
||||
require_relative '../../../states/project/merge_request/diffs_batch_state'
|
||||
require_relative '../../../../spec_helper'
|
||||
require_relative '../../../../states/project/merge_request/show_state'
|
||||
|
||||
module Provider
|
||||
module DiffsBatchHelper
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../../spec_helper'
|
||||
require_relative '../../../states/project/merge_request/diffs_metadata_state'
|
||||
require_relative '../../../../spec_helper'
|
||||
require_relative '../../../../states/project/merge_request/show_state'
|
||||
|
||||
module Provider
|
||||
module DiffsMetadataHelper
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../../spec_helper'
|
||||
require_relative '../../../states/project/merge_request/discussions_state'
|
||||
require_relative '../../../../spec_helper'
|
||||
require_relative '../../../../states/project/merge_request/show_state'
|
||||
|
||||
module Provider
|
||||
module DiscussionsHelper
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../../spec_helper'
|
||||
require_relative '../../../states/project/pipeline/new_state'
|
||||
require_relative '../../../../spec_helper'
|
||||
require_relative '../../../../states/project/pipeline/new_state'
|
||||
|
||||
module Provider
|
||||
module CreateNewPipelineHelper
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../../spec_helper'
|
||||
require_relative '../../../states/project/pipeline/pipelines_state'
|
||||
require_relative '../../../../spec_helper'
|
||||
require_relative '../../../../states/project/pipeline/index_state'
|
||||
|
||||
module Provider
|
||||
module GetListProjectPipelinesHelper
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../../../spec_helper'
|
||||
require_relative '../../../../states/project/pipeline/pipeline_state'
|
||||
require_relative '../../../../states/project/pipeline/show_state'
|
||||
|
||||
module Provider
|
||||
module GetPipelinesHeaderDataHelper
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
Pact.provider_states_for "MergeRequest#show" do
|
||||
provider_state "a merge request with diffs exists" do
|
||||
set_up do
|
||||
user = User.find_by(name: Provider::UsersHelper::CONTRACT_USER_NAME)
|
||||
namespace = create(:namespace, name: 'gitlab-org')
|
||||
project = create(:project, :custom_repo, name: 'gitlab-qa', namespace: namespace, files: {})
|
||||
|
||||
project.add_maintainer(user)
|
||||
|
||||
merge_request = create(:merge_request_with_multiple_diffs, source_project: project)
|
||||
merge_request_diff = create(:merge_request_diff, merge_request: merge_request)
|
||||
|
||||
create(:merge_request_diff_file, :new_file, merge_request_diff: merge_request_diff)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,18 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
Pact.provider_states_for "MergeRequest#show" do
|
||||
provider_state "a merge request exists" do
|
||||
set_up do
|
||||
user = User.find_by(name: Provider::UsersHelper::CONTRACT_USER_NAME)
|
||||
namespace = create(:namespace, name: 'gitlab-org')
|
||||
project = create(:project, :custom_repo, name: 'gitlab-qa', namespace: namespace, files: {})
|
||||
|
||||
project.add_maintainer(user)
|
||||
|
||||
merge_request = create(:merge_request, source_project: project)
|
||||
merge_request_diff = create(:merge_request_diff, merge_request: merge_request)
|
||||
|
||||
create(:merge_request_diff_file, :new_file, merge_request_diff: merge_request_diff)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,17 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
Pact.provider_states_for "MergeRequest#show" do
|
||||
provider_state "a merge request with discussions exists" do
|
||||
set_up do
|
||||
user = User.find_by(name: Provider::UsersHelper::CONTRACT_USER_NAME)
|
||||
namespace = create(:namespace, name: 'gitlab-org')
|
||||
project = create(:project, name: 'gitlab-qa', namespace: namespace)
|
||||
|
||||
project.add_maintainer(user)
|
||||
|
||||
merge_request = create(:merge_request_with_diffs, source_project: project, author: user)
|
||||
|
||||
create(:discussion_note_on_merge_request, noteable: merge_request, project: project, author: user)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,47 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
Pact.provider_states_for "MergeRequest#show" do
|
||||
provider_state "a merge request with diffs exists" do
|
||||
set_up do
|
||||
user = User.find_by(name: Provider::UsersHelper::CONTRACT_USER_NAME)
|
||||
namespace = create(:namespace, name: 'gitlab-org')
|
||||
project = create(:project, :custom_repo, name: 'gitlab-qa', namespace: namespace, files: {})
|
||||
|
||||
project.add_maintainer(user)
|
||||
|
||||
merge_request = create(:merge_request_with_multiple_diffs, source_project: project)
|
||||
merge_request_diff = create(:merge_request_diff, merge_request: merge_request)
|
||||
|
||||
create(:merge_request_diff_file, :new_file, merge_request_diff: merge_request_diff)
|
||||
end
|
||||
end
|
||||
|
||||
provider_state "a merge request exists" do
|
||||
set_up do
|
||||
user = User.find_by(name: Provider::UsersHelper::CONTRACT_USER_NAME)
|
||||
namespace = create(:namespace, name: 'gitlab-org')
|
||||
project = create(:project, :custom_repo, name: 'gitlab-qa', namespace: namespace, files: {})
|
||||
|
||||
project.add_maintainer(user)
|
||||
|
||||
merge_request = create(:merge_request, source_project: project)
|
||||
merge_request_diff = create(:merge_request_diff, merge_request: merge_request)
|
||||
|
||||
create(:merge_request_diff_file, :new_file, merge_request_diff: merge_request_diff)
|
||||
end
|
||||
end
|
||||
|
||||
provider_state "a merge request with discussions exists" do
|
||||
set_up do
|
||||
user = User.find_by(name: Provider::UsersHelper::CONTRACT_USER_NAME)
|
||||
namespace = create(:namespace, name: 'gitlab-org')
|
||||
project = create(:project, name: 'gitlab-qa', namespace: namespace)
|
||||
|
||||
project.add_maintainer(user)
|
||||
|
||||
merge_request = create(:merge_request_with_diffs, source_project: project, author: user)
|
||||
|
||||
create(:discussion_note_on_merge_request, noteable: merge_request, project: project, author: user)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,27 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
Pact.provider_states_for "Pipelines#show" do
|
||||
provider_state "a pipeline for a project exists" do
|
||||
set_up do
|
||||
user = User.find_by(name: Provider::UsersHelper::CONTRACT_USER_NAME)
|
||||
namespace = create(:namespace, name: 'gitlab-org')
|
||||
project = create(:project, :repository, name: 'gitlab-qa', namespace: namespace, creator: user)
|
||||
scheduled_job = create(:ci_build, :scheduled)
|
||||
manual_job = create(:ci_build, :manual)
|
||||
|
||||
project.add_maintainer(user)
|
||||
|
||||
create(
|
||||
:ci_pipeline,
|
||||
:with_job,
|
||||
:success,
|
||||
iid: 1,
|
||||
project: project,
|
||||
user: user,
|
||||
duration: 10,
|
||||
finished_at: '2022-06-01T02:47:31.432Z',
|
||||
builds: [scheduled_job, manual_job]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -268,7 +268,7 @@ describe('IDE store getters', () => {
|
|||
currentProject: undefined,
|
||||
};
|
||||
|
||||
expect(getters.isOnDefaultBranch({}, localGetters)).toBeFalsy();
|
||||
expect(getters.isOnDefaultBranch({}, localGetters)).toBe(undefined);
|
||||
});
|
||||
|
||||
it("returns true when project's default branch matches current branch", () => {
|
||||
|
@ -279,7 +279,7 @@ describe('IDE store getters', () => {
|
|||
branchName: 'main',
|
||||
};
|
||||
|
||||
expect(getters.isOnDefaultBranch({}, localGetters)).toBeTruthy();
|
||||
expect(getters.isOnDefaultBranch({}, localGetters)).toBe(true);
|
||||
});
|
||||
|
||||
it("returns false when project's default branch doesn't match current branch", () => {
|
||||
|
@ -290,7 +290,7 @@ describe('IDE store getters', () => {
|
|||
branchName: 'feature',
|
||||
};
|
||||
|
||||
expect(getters.isOnDefaultBranch({}, localGetters)).toBeFalsy();
|
||||
expect(getters.isOnDefaultBranch({}, localGetters)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import { GlSearchBoxByClick } from '@gitlab/ui';
|
||||
import { mount } from '@vue/test-utils';
|
||||
import { nextTick } from 'vue';
|
||||
import JobLogControllers from '~/jobs/components/job_log_controllers.vue';
|
||||
import HelpPopover from '~/vue_shared/components/help_popover.vue';
|
||||
import { backoffMockImplementation } from 'helpers/backoff_helper';
|
||||
import * as commonUtils from '~/lib/utils/common_utils';
|
||||
import { mockJobLog } from '../mock_data';
|
||||
|
||||
const mockToastShow = jest.fn();
|
||||
|
@ -10,10 +11,15 @@ const mockToastShow = jest.fn();
|
|||
describe('Job log controllers', () => {
|
||||
let wrapper;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.spyOn(commonUtils, 'backOff').mockImplementation(backoffMockImplementation);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (wrapper?.destroy) {
|
||||
wrapper.destroy();
|
||||
}
|
||||
commonUtils.backOff.mockReset();
|
||||
});
|
||||
|
||||
const defaultProps = {
|
||||
|
@ -24,10 +30,11 @@ describe('Job log controllers', () => {
|
|||
isScrollBottomDisabled: false,
|
||||
isScrollingDown: true,
|
||||
isJobLogSizeVisible: true,
|
||||
isComplete: true,
|
||||
jobLog: mockJobLog,
|
||||
};
|
||||
|
||||
const createWrapper = (props, jobLogSearch = false) => {
|
||||
const createWrapper = (props, { jobLogSearch = false, jobLogJumpToFailures = false } = {}) => {
|
||||
wrapper = mount(JobLogControllers, {
|
||||
propsData: {
|
||||
...defaultProps,
|
||||
|
@ -36,6 +43,7 @@ describe('Job log controllers', () => {
|
|||
provide: {
|
||||
glFeatures: {
|
||||
jobLogSearch,
|
||||
jobLogJumpToFailures,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
|
@ -58,6 +66,7 @@ describe('Job log controllers', () => {
|
|||
const findScrollBottom = () => wrapper.find('[data-testid="job-controller-scroll-bottom"]');
|
||||
const findJobLogSearch = () => wrapper.findComponent(GlSearchBoxByClick);
|
||||
const findSearchHelp = () => wrapper.findComponent(HelpPopover);
|
||||
const findScrollFailure = () => wrapper.find('[data-testid="job-controller-scroll-to-failure"]');
|
||||
|
||||
describe('Truncate information', () => {
|
||||
describe('with isJobLogSizeVisible', () => {
|
||||
|
@ -109,9 +118,7 @@ describe('Job log controllers', () => {
|
|||
});
|
||||
|
||||
it('emits scrollJobLogTop event on click', async () => {
|
||||
findScrollTop().trigger('click');
|
||||
|
||||
await nextTick();
|
||||
await findScrollTop().trigger('click');
|
||||
|
||||
expect(wrapper.emitted().scrollJobLogTop).toHaveLength(1);
|
||||
});
|
||||
|
@ -131,9 +138,7 @@ describe('Job log controllers', () => {
|
|||
});
|
||||
|
||||
it('does not emit scrollJobLogTop event on click', async () => {
|
||||
findScrollTop().trigger('click');
|
||||
|
||||
await nextTick();
|
||||
await findScrollTop().trigger('click');
|
||||
|
||||
expect(wrapper.emitted().scrollJobLogTop).toBeUndefined();
|
||||
});
|
||||
|
@ -147,9 +152,7 @@ describe('Job log controllers', () => {
|
|||
});
|
||||
|
||||
it('emits scrollJobLogBottom event on click', async () => {
|
||||
findScrollBottom().trigger('click');
|
||||
|
||||
await nextTick();
|
||||
await findScrollBottom().trigger('click');
|
||||
|
||||
expect(wrapper.emitted().scrollJobLogBottom).toHaveLength(1);
|
||||
});
|
||||
|
@ -169,9 +172,7 @@ describe('Job log controllers', () => {
|
|||
});
|
||||
|
||||
it('does not emit scrollJobLogBottom event on click', async () => {
|
||||
findScrollBottom().trigger('click');
|
||||
|
||||
await nextTick();
|
||||
await findScrollBottom().trigger('click');
|
||||
|
||||
expect(wrapper.emitted().scrollJobLogBottom).toBeUndefined();
|
||||
});
|
||||
|
@ -201,6 +202,91 @@ describe('Job log controllers', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('scroll to failure button', () => {
|
||||
describe('with feature flag disabled', () => {
|
||||
it('does not display button', () => {
|
||||
createWrapper();
|
||||
|
||||
expect(findScrollFailure().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with red text failures on the page', () => {
|
||||
let firstFailure;
|
||||
let secondFailure;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.spyOn(document, 'querySelectorAll').mockReturnValueOnce(['mock-element']);
|
||||
|
||||
createWrapper({}, { jobLogJumpToFailures: true });
|
||||
|
||||
firstFailure = document.createElement('div');
|
||||
firstFailure.className = 'term-fg-l-red';
|
||||
document.body.appendChild(firstFailure);
|
||||
|
||||
secondFailure = document.createElement('div');
|
||||
secondFailure.className = 'term-fg-l-red';
|
||||
document.body.appendChild(secondFailure);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (firstFailure) {
|
||||
firstFailure.remove();
|
||||
firstFailure = null;
|
||||
}
|
||||
|
||||
if (secondFailure) {
|
||||
secondFailure.remove();
|
||||
secondFailure = null;
|
||||
}
|
||||
});
|
||||
|
||||
it('is enabled', () => {
|
||||
expect(findScrollFailure().props('disabled')).toBe(false);
|
||||
});
|
||||
|
||||
it('scrolls to each failure', async () => {
|
||||
jest.spyOn(firstFailure, 'scrollIntoView');
|
||||
|
||||
await findScrollFailure().trigger('click');
|
||||
|
||||
expect(firstFailure.scrollIntoView).toHaveBeenCalled();
|
||||
|
||||
await findScrollFailure().trigger('click');
|
||||
|
||||
expect(secondFailure.scrollIntoView).toHaveBeenCalled();
|
||||
|
||||
await findScrollFailure().trigger('click');
|
||||
|
||||
expect(firstFailure.scrollIntoView).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('with no red text failures on the page', () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(document, 'querySelectorAll').mockReturnValueOnce([]);
|
||||
|
||||
createWrapper({}, { jobLogJumpToFailures: true });
|
||||
});
|
||||
|
||||
it('is disabled', () => {
|
||||
expect(findScrollFailure().props('disabled')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the job log is not complete', () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(document, 'querySelectorAll').mockReturnValueOnce(['mock-element']);
|
||||
|
||||
createWrapper({ isComplete: false }, { jobLogJumpToFailures: true });
|
||||
});
|
||||
|
||||
it('is enabled', () => {
|
||||
expect(findScrollFailure().props('disabled')).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Job log search', () => {
|
||||
|
|
|
@ -316,7 +316,7 @@ describe('Actions menu', () => {
|
|||
});
|
||||
|
||||
it('is not disabled', () => {
|
||||
expect(findStarDashboardItem().attributes('disabled')).toBeFalsy();
|
||||
expect(findStarDashboardItem().attributes('disabled')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('is disabled when starring is taking place', async () => {
|
||||
|
|
Loading…
Reference in a new issue