diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-08-09 09:11:48 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-08-09 09:11:48 +0300 |
commit | 0ac2fcc287b33c4f6940391c5632d5f90735eff9 (patch) | |
tree | e947bc856dbbd57149bd35f6922c6e08d8676f2c | |
parent | fae5be5632becf76659bf9d85e19d9bedb675c89 (diff) |
Add latest changes from gitlab-org/gitlab@master
48 files changed, 391 insertions, 316 deletions
diff --git a/.eslintrc.yml b/.eslintrc.yml index 22dae35187e..5e6755edaa5 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -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 diff --git a/app/assets/javascripts/jobs/components/job_app.vue b/app/assets/javascripts/jobs/components/job_app.vue index f9e6c64aad1..d5ee3423d70 100644 --- a/app/assets/javascripts/jobs/components/job_app.vue +++ b/app/assets/javascripts/jobs/components/job_app.vue @@ -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" diff --git a/app/assets/javascripts/jobs/components/job_log_controllers.vue b/app/assets/javascripts/jobs/components/job_log_controllers.vue index 5e89dd5acc2..9f5dbe70331 100644 --- a/app/assets/javascripts/jobs/components/job_log_controllers.vue +++ b/app/assets/javascripts/jobs/components/job_log_controllers.vue @@ -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" diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss index 031f5dc45ca..b62d12a3971 100644 --- a/app/assets/stylesheets/framework/typography.scss +++ b/app/assets/stylesheets/framework/typography.scss @@ -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; } } } diff --git a/app/assets/stylesheets/page_bundles/escalation_policies.scss b/app/assets/stylesheets/page_bundles/escalation_policies.scss index 6f3873fea0c..84c62ba93dd 100644 --- a/app/assets/stylesheets/page_bundles/escalation_policies.scss +++ b/app/assets/stylesheets/page_bundles/escalation_policies.scss @@ -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; -} diff --git a/app/assets/stylesheets/page_bundles/issues_show.scss b/app/assets/stylesheets/page_bundles/issues_show.scss index c664e0a734e..9876003e652 100644 --- a/app/assets/stylesheets/page_bundles/issues_show.scss +++ b/app/assets/stylesheets/page_bundles/issues_show.scss @@ -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; } } } diff --git a/app/controllers/projects/jobs_controller.rb b/app/controllers/projects/jobs_controller.rb index ad59f421c06..8570bbf1dbd 100644 --- a/app/controllers/projects/jobs_controller.rb +++ b/app/controllers/projects/jobs_controller.rb @@ -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 diff --git a/config/feature_flags/development/job_log_jump_to_failures.yml b/config/feature_flags/development/job_log_jump_to_failures.yml new file mode 100644 index 00000000000..45d11c82fe9 --- /dev/null +++ b/config/feature_flags/development/job_log_jump_to_failures.yml @@ -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 diff --git a/doc/api/group_protected_environments.md b/doc/api/group_protected_environments.md index 8ebd0dcd99a..0f1527f8968 100644 --- a/doc/api/group_protected_environments.md +++ b/doc/api/group_protected_environments.md @@ -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). diff --git a/doc/integration/saml.md b/doc/integration/saml.md index 6dd9f6e72c5..0c517d07f41 100644 --- a/doc/integration/saml.md +++ b/doc/integration/saml.md @@ -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', diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md index 532698d28e3..c4672e61c99 100644 --- a/doc/user/application_security/dependency_scanning/index.md +++ b/doc/user/application_security/dependency_scanning/index.md @@ -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`. | diff --git a/doc/user/application_security/get-started-security.md b/doc/user/application_security/get-started-security.md new file mode 100644 index 00000000000..4c2b971b5fa --- /dev/null +++ b/doc/user/application_security/get-started-security.md @@ -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. diff --git a/lib/tasks/contracts/merge_requests.rake b/lib/tasks/contracts/merge_requests.rake index 2fdd2beb4ee..fdcea804640 100644 --- a/lib/tasks/contracts/merge_requests.rake +++ b/lib/tasks/contracts/merge_requests.rake @@ -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 diff --git a/lib/tasks/contracts/pipeline_schedules.rake b/lib/tasks/contracts/pipeline_schedules.rake index b6d331448e2..136577730c8 100644 --- a/lib/tasks/contracts/pipeline_schedules.rake +++ b/lib/tasks/contracts/pipeline_schedules.rake @@ -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 diff --git a/lib/tasks/contracts/pipelines.rake b/lib/tasks/contracts/pipelines.rake index 75955822242..75d381e1f8d 100644 --- a/lib/tasks/contracts/pipelines.rake +++ b/lib/tasks/contracts/pipelines.rake @@ -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 diff --git a/locale/gitlab.pot b/locale/gitlab.pot index cc522a763b2..923a24a4dfd 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -22656,6 +22656,9 @@ msgstr "" msgid "Job|Scroll to bottom" msgstr "" +msgid "Job|Scroll to next failure" +msgstr "" + msgid "Job|Scroll to top" msgstr "" diff --git a/spec/contracts/consumer/endpoints/project/pipelines.js b/spec/contracts/consumer/endpoints/project/pipelines.js deleted file mode 100644 index 33758dee75b..00000000000 --- a/spec/contracts/consumer/endpoints/project/pipelines.js +++ /dev/null @@ -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); -} diff --git a/spec/contracts/consumer/fixtures/project/merge_request/diffs_batch.fixture.js b/spec/contracts/consumer/fixtures/project/merge_request/diffs_batch.fixture.js index b53e4bb335d..673aad721b3 100644 --- a/spec/contracts/consumer/fixtures/project/merge_request/diffs_batch.fixture.js +++ b/spec/contracts/consumer/fixtures/project/merge_request/diffs_batch.fixture.js @@ -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 */ diff --git a/spec/contracts/consumer/fixtures/project/merge_request/diffs_metadata.fixture.js b/spec/contracts/consumer/fixtures/project/merge_request/diffs_metadata.fixture.js index 39dbcf78ee7..2fee4a02023 100644 --- a/spec/contracts/consumer/fixtures/project/merge_request/diffs_metadata.fixture.js +++ b/spec/contracts/consumer/fixtures/project/merge_request/diffs_metadata.fixture.js @@ -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 */ diff --git a/spec/contracts/consumer/fixtures/project/merge_request/discussions.fixture.js b/spec/contracts/consumer/fixtures/project/merge_request/discussions.fixture.js index af0962a01cb..8c392395e1c 100644 --- a/spec/contracts/consumer/fixtures/project/merge_request/discussions.fixture.js +++ b/spec/contracts/consumer/fixtures/project/merge_request/discussions.fixture.js @@ -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 */ diff --git a/spec/contracts/consumer/fixtures/project/pipeline/create_a_new_pipeline.fixture.js b/spec/contracts/consumer/fixtures/project/pipeline/create_a_new_pipeline.fixture.js index a732189e6fb..68063d2fb0c 100644 --- a/spec/contracts/consumer/fixtures/project/pipeline/create_a_new_pipeline.fixture.js +++ b/spec/contracts/consumer/fixtures/project/pipeline/create_a_new_pipeline.fixture.js @@ -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 */ diff --git a/spec/contracts/consumer/fixtures/project/pipeline/delete_pipeline.fixture.js b/spec/contracts/consumer/fixtures/project/pipeline/delete_pipeline.fixture.js index 4dbb694064b..2e3e7355b99 100644 --- a/spec/contracts/consumer/fixtures/project/pipeline/delete_pipeline.fixture.js +++ b/spec/contracts/consumer/fixtures/project/pipeline/delete_pipeline.fixture.js @@ -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', diff --git a/spec/contracts/consumer/fixtures/project/pipeline/get_list_project_pipelines.fixture.js b/spec/contracts/consumer/fixtures/project/pipeline/get_list_project_pipelines.fixture.js index 8a7663325b9..a982e927572 100644 --- a/spec/contracts/consumer/fixtures/project/pipeline/get_list_project_pipelines.fixture.js +++ b/spec/contracts/consumer/fixtures/project/pipeline/get_list_project_pipelines.fixture.js @@ -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 */ diff --git a/spec/contracts/consumer/fixtures/project/pipeline/get_pipeline_header_data.fixture.js b/spec/contracts/consumer/fixtures/project/pipeline/get_pipeline_header_data.fixture.js index f51ed9c2c74..b14a230d2e0 100644 --- a/spec/contracts/consumer/fixtures/project/pipeline/get_pipeline_header_data.fixture.js +++ b/spec/contracts/consumer/fixtures/project/pipeline/get_pipeline_header_data.fixture.js @@ -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 */ diff --git a/spec/contracts/consumer/fixtures/project/pipeline_schedule/update_pipeline_schedule.fixture.js b/spec/contracts/consumer/fixtures/project/pipeline_schedule/update_pipeline_schedule.fixture.js index acdc94d5c6e..acfab14851a 100644 --- a/spec/contracts/consumer/fixtures/project/pipeline_schedule/update_pipeline_schedule.fixture.js +++ b/spec/contracts/consumer/fixtures/project/pipeline_schedule/update_pipeline_schedule.fixture.js @@ -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 */ diff --git a/spec/contracts/consumer/endpoints/project/merge_requests.js b/spec/contracts/consumer/resources/api/project/merge_requests.js index 38773e5fb10..e52743cede2 100644 --- a/spec/contracts/consumer/endpoints/project/merge_requests.js +++ b/spec/contracts/consumer/resources/api/project/merge_requests.js @@ -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', diff --git a/spec/contracts/consumer/resources/api/project/pipelines.js b/spec/contracts/consumer/resources/api/project/pipelines.js index f58a7a5fb0f..8c6f5199666 100644 --- a/spec/contracts/consumer/resources/api/project/pipelines.js +++ b/spec/contracts/consumer/resources/api/project/pipelines.js @@ -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; diff --git a/spec/contracts/consumer/specs/project/merge_request/show.spec.js b/spec/contracts/consumer/specs/project/merge_request/show.spec.js index 8c6e029cb12..4183e19435a 100644 --- a/spec/contracts/consumer/specs/project/merge_request/show.spec.js +++ b/spec/contracts/consumer/specs/project/merge_request/show.spec.js @@ -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 */ diff --git a/spec/contracts/consumer/specs/project/pipeline/index.spec.js b/spec/contracts/consumer/specs/project/pipeline/index.spec.js index 1c0358a3e28..1453435d637 100644 --- a/spec/contracts/consumer/specs/project/pipeline/index.spec.js +++ b/spec/contracts/consumer/specs/project/pipeline/index.spec.js @@ -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 */ diff --git a/spec/contracts/consumer/specs/project/pipeline/new.spec.js b/spec/contracts/consumer/specs/project/pipeline/new.spec.js index 621b31af52d..c3824d5979e 100644 --- a/spec/contracts/consumer/specs/project/pipeline/new.spec.js +++ b/spec/contracts/consumer/specs/project/pipeline/new.spec.js @@ -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 */ diff --git a/spec/contracts/consumer/specs/project/pipeline/show.spec.js b/spec/contracts/consumer/specs/project/pipeline/show.spec.js index 2c5ba964e2e..be6abb78eb5 100644 --- a/spec/contracts/consumer/specs/project/pipeline/show.spec.js +++ b/spec/contracts/consumer/specs/project/pipeline/show.spec.js @@ -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 */ diff --git a/spec/contracts/consumer/specs/project/pipeline_schedule/edit.spec.js b/spec/contracts/consumer/specs/project/pipeline_schedule/edit.spec.js index 7d89825bcd4..117e6754255 100644 --- a/spec/contracts/consumer/specs/project/pipeline_schedule/edit.spec.js +++ b/spec/contracts/consumer/specs/project/pipeline_schedule/edit.spec.js @@ -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 */ diff --git a/spec/contracts/contracts/project/merge_request/show/mergerequest#show-merge_request_diffs_metadata_endpoint.json b/spec/contracts/contracts/project/merge_request/show/mergerequest#show-merge_request_diffs_metadata_endpoint.json index b98a0127e54..c59a3d55f43 100644 --- a/spec/contracts/contracts/project/merge_request/show/mergerequest#show-merge_request_diffs_metadata_endpoint.json +++ b/spec/contracts/contracts/project/merge_request/show/mergerequest#show-merge_request_diffs_metadata_endpoint.json @@ -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" } } -}
\ No newline at end of file +} diff --git a/spec/contracts/provider/pact_helpers/project/merge_request/diffs_batch_helper.rb b/spec/contracts/provider/pact_helpers/project/merge_request/show/diffs_batch_helper.rb index 7d1fbe91e86..f94ce47b1f3 100644 --- a/spec/contracts/provider/pact_helpers/project/merge_request/diffs_batch_helper.rb +++ b/spec/contracts/provider/pact_helpers/project/merge_request/show/diffs_batch_helper.rb @@ -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 diff --git a/spec/contracts/provider/pact_helpers/project/merge_request/diffs_metadata_helper.rb b/spec/contracts/provider/pact_helpers/project/merge_request/show/diffs_metadata_helper.rb index 5f0c58d18d4..61567214b7a 100644 --- a/spec/contracts/provider/pact_helpers/project/merge_request/diffs_metadata_helper.rb +++ b/spec/contracts/provider/pact_helpers/project/merge_request/show/diffs_metadata_helper.rb @@ -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 diff --git a/spec/contracts/provider/pact_helpers/project/merge_request/discussions_helper.rb b/spec/contracts/provider/pact_helpers/project/merge_request/show/discussions_helper.rb index 0f4244ba40a..fa76ce8889a 100644 --- a/spec/contracts/provider/pact_helpers/project/merge_request/discussions_helper.rb +++ b/spec/contracts/provider/pact_helpers/project/merge_request/show/discussions_helper.rb @@ -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 diff --git a/spec/contracts/provider/pact_helpers/project/pipeline/create_a_new_pipeline_helper.rb b/spec/contracts/provider/pact_helpers/project/pipeline/index/create_a_new_pipeline_helper.rb index e7d9b1452d3..247a7c4ca8e 100644 --- a/spec/contracts/provider/pact_helpers/project/pipeline/create_a_new_pipeline_helper.rb +++ b/spec/contracts/provider/pact_helpers/project/pipeline/index/create_a_new_pipeline_helper.rb @@ -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 diff --git a/spec/contracts/provider/pact_helpers/project/pipeline/get_list_project_pipelines_helper.rb b/spec/contracts/provider/pact_helpers/project/pipeline/index/get_list_project_pipelines_helper.rb index 5307468b7c6..80cbbe3b4dd 100644 --- a/spec/contracts/provider/pact_helpers/project/pipeline/get_list_project_pipelines_helper.rb +++ b/spec/contracts/provider/pact_helpers/project/pipeline/index/get_list_project_pipelines_helper.rb @@ -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 diff --git a/spec/contracts/provider/pact_helpers/project/pipeline/show/get_pipeline_header_data_helper.rb b/spec/contracts/provider/pact_helpers/project/pipeline/show/get_pipeline_header_data_helper.rb index 4bc7dff2ef9..bc8c04cc455 100644 --- a/spec/contracts/provider/pact_helpers/project/pipeline/show/get_pipeline_header_data_helper.rb +++ b/spec/contracts/provider/pact_helpers/project/pipeline/show/get_pipeline_header_data_helper.rb @@ -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 diff --git a/spec/contracts/provider/states/project/merge_request/diffs_batch_state.rb b/spec/contracts/provider/states/project/merge_request/diffs_batch_state.rb deleted file mode 100644 index ac20c17c187..00000000000 --- a/spec/contracts/provider/states/project/merge_request/diffs_batch_state.rb +++ /dev/null @@ -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 diff --git a/spec/contracts/provider/states/project/merge_request/diffs_metadata_state.rb b/spec/contracts/provider/states/project/merge_request/diffs_metadata_state.rb deleted file mode 100644 index 8754232690c..00000000000 --- a/spec/contracts/provider/states/project/merge_request/diffs_metadata_state.rb +++ /dev/null @@ -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 diff --git a/spec/contracts/provider/states/project/merge_request/discussions_state.rb b/spec/contracts/provider/states/project/merge_request/discussions_state.rb deleted file mode 100644 index 2d64f85eedf..00000000000 --- a/spec/contracts/provider/states/project/merge_request/discussions_state.rb +++ /dev/null @@ -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 diff --git a/spec/contracts/provider/states/project/merge_request/show_state.rb b/spec/contracts/provider/states/project/merge_request/show_state.rb new file mode 100644 index 00000000000..46f322f723a --- /dev/null +++ b/spec/contracts/provider/states/project/merge_request/show_state.rb @@ -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 diff --git a/spec/contracts/provider/states/project/pipeline/pipelines_state.rb b/spec/contracts/provider/states/project/pipeline/index_state.rb index 639c25e9894..639c25e9894 100644 --- a/spec/contracts/provider/states/project/pipeline/pipelines_state.rb +++ b/spec/contracts/provider/states/project/pipeline/index_state.rb diff --git a/spec/contracts/provider/states/project/pipeline/pipeline_state.rb b/spec/contracts/provider/states/project/pipeline/pipeline_state.rb deleted file mode 100644 index d1a4cd34bdd..00000000000 --- a/spec/contracts/provider/states/project/pipeline/pipeline_state.rb +++ /dev/null @@ -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 diff --git a/spec/frontend/ide/stores/getters_spec.js b/spec/frontend/ide/stores/getters_spec.js index 53d161ae5c9..24661e21cd0 100644 --- a/spec/frontend/ide/stores/getters_spec.js +++ b/spec/frontend/ide/stores/getters_spec.js @@ -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); }); }); diff --git a/spec/frontend/jobs/components/job_log_controllers_spec.js b/spec/frontend/jobs/components/job_log_controllers_spec.js index cc97d111c06..4075abd24d5 100644 --- a/spec/frontend/jobs/components/job_log_controllers_spec.js +++ b/spec/frontend/jobs/components/job_log_controllers_spec.js @@ -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', () => { diff --git a/spec/frontend/monitoring/components/dashboard_actions_menu_spec.js b/spec/frontend/monitoring/components/dashboard_actions_menu_spec.js index d74f959ac0f..281f0f4e4fe 100644 --- a/spec/frontend/monitoring/components/dashboard_actions_menu_spec.js +++ b/spec/frontend/monitoring/components/dashboard_actions_menu_spec.js @@ -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 () => { |