diff options
62 files changed, 1132 insertions, 426 deletions
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index 7b0f0a221f8..86016519ba8 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -13.2.0-rc2 +74fa51387fbc4ac199309f5c0461d4cdde2a1a2f diff --git a/app/assets/javascripts/ide/lib/editor.js b/app/assets/javascripts/ide/lib/editor.js index a70611413ae..6e90968f008 100644 --- a/app/assets/javascripts/ide/lib/editor.js +++ b/app/assets/javascripts/ide/lib/editor.js @@ -45,7 +45,10 @@ export default class Editor { setupThemes(); registerLanguages(...languages); - registerSchemas(...schemas); + + if (gon.features?.schemaLinting) { + registerSchemas(...schemas); + } this.debouncedUpdate = debounce(() => { this.updateDimensions(); diff --git a/app/assets/javascripts/performance_bar/components/request_selector.vue b/app/assets/javascripts/performance_bar/components/request_selector.vue index 115b2ff08ac..c22a648d17f 100644 --- a/app/assets/javascripts/performance_bar/components/request_selector.vue +++ b/app/assets/javascripts/performance_bar/components/request_selector.vue @@ -45,7 +45,7 @@ export default { }; </script> <template> - <div id="peek-request-selector" data-qa-selector="request_dropdown"> + <div id="peek-request-selector" data-qa-selector="request_dropdown" class="view"> <select v-model="currentRequestId"> <option v-for="request in requests" diff --git a/app/assets/javascripts/vue_shared/components/remove_member_modal.vue b/app/assets/javascripts/vue_shared/components/remove_member_modal.vue index 08b5fff780c..88d1b15aee3 100644 --- a/app/assets/javascripts/vue_shared/components/remove_member_modal.vue +++ b/app/assets/javascripts/vue_shared/components/remove_member_modal.vue @@ -62,6 +62,7 @@ export default { :action-cancel="$options.actionCancel" :action-primary="actionPrimary" :title="actionText" + data-qa-selector="remove_member_modal_content" @primary="submitForm" > <form ref="form" :action="modalData.memberPath" method="post"> diff --git a/app/controllers/ide_controller.rb b/app/controllers/ide_controller.rb index 2bf7bdd1ae0..2c17f5b5542 100644 --- a/app/controllers/ide_controller.rb +++ b/app/controllers/ide_controller.rb @@ -8,6 +8,7 @@ class IdeController < ApplicationController before_action do push_frontend_feature_flag(:build_service_proxy) + push_frontend_feature_flag(:schema_linting) end def index diff --git a/app/helpers/operations_helper.rb b/app/helpers/operations_helper.rb index 419fdd521c2..42871e56a9d 100644 --- a/app/helpers/operations_helper.rb +++ b/app/helpers/operations_helper.rb @@ -15,7 +15,7 @@ module OperationsHelper end end - def alerts_settings_data + def alerts_settings_data(disabled: false) { 'prometheus_activated' => prometheus_service.manual_configuration?.to_s, 'activated' => alerts_service.activated?.to_s, @@ -28,7 +28,8 @@ module OperationsHelper 'prometheus_url' => notify_project_prometheus_alerts_url(@project, format: :json), 'url' => alerts_service.url, 'alerts_setup_url' => help_page_path('user/project/integrations/generic_alerts.md', anchor: 'setting-up-generic-alerts'), - 'alerts_usage_url' => project_alert_management_index_path(@project) + 'alerts_usage_url' => project_alert_management_index_path(@project), + 'disabled' => disabled.to_s } end end diff --git a/app/models/ci/job_artifact.rb b/app/models/ci/job_artifact.rb index d2aa336d12f..d20fdce10ef 100644 --- a/app/models/ci/job_artifact.rb +++ b/app/models/ci/job_artifact.rb @@ -35,6 +35,7 @@ module Ci license_scanning: 'gl-license-scanning-report.json', performance: 'performance.json', browser_performance: 'browser-performance.json', + load_performance: 'load-performance.json', metrics: 'metrics.txt', lsif: 'lsif.json', dotenv: '.env', @@ -75,6 +76,7 @@ module Ci license_scanning: :raw, performance: :raw, browser_performance: :raw, + load_performance: :raw, terraform: :raw, requirements: :raw, coverage_fuzzing: :raw @@ -96,6 +98,7 @@ module Ci metrics performance browser_performance + load_performance sast secret_detection requirements @@ -196,7 +199,8 @@ module Ci secret_detection: 21, ## EE-specific requirements: 22, ## EE-specific coverage_fuzzing: 23, ## EE-specific - browser_performance: 24 ## EE-specific + browser_performance: 24, ## EE-specific + load_performance: 25 ## EE-specific } enum file_format: { diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index 7d13adb22f0..7a7dbda8026 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -447,6 +447,10 @@ module Ci end end + def triggered_pipelines_with_preloads + triggered_pipelines.preload(:source_job) + end + def legacy_stages if ::Gitlab::Ci::Features.composite_status?(project) legacy_stages_using_composite_status diff --git a/app/serializers/pipeline_serializer.rb b/app/serializers/pipeline_serializer.rb index 21d49c6c292..bfd6851647f 100644 --- a/app/serializers/pipeline_serializer.rb +++ b/app/serializers/pipeline_serializer.rb @@ -60,8 +60,8 @@ class PipelineSerializer < BaseSerializer }, pending_builds: :project, project: [:route, { namespace: :route }], - triggered_by_pipeline: [:project, :user], - triggered_pipelines: [:project, :user] + triggered_by_pipeline: [{ project: [:route, { namespace: :route }] }, :user], + triggered_pipelines: [{ project: [:route, { namespace: :route }] }, :user, :source_job] } ] end diff --git a/app/serializers/triggered_pipeline_entity.rb b/app/serializers/triggered_pipeline_entity.rb index fd7e4454abf..47f51a6d76a 100644 --- a/app/serializers/triggered_pipeline_entity.rb +++ b/app/serializers/triggered_pipeline_entity.rb @@ -11,6 +11,12 @@ class TriggeredPipelineEntity < Grape::Entity expose :coverage expose :source + expose :source_job do + expose :name do |pipeline| + pipeline.source_job&.name + end + end + expose :path do |pipeline| project_pipeline_path(pipeline.project, pipeline) end @@ -27,7 +33,7 @@ class TriggeredPipelineEntity < Grape::Entity as: :triggered_by, with: TriggeredPipelineEntity, if: -> (_, opts) { can_read_details? && expand_for_path?(opts) } - expose :triggered_pipelines, + expose :triggered_pipelines_with_preloads, as: :triggered, using: TriggeredPipelineEntity, if: -> (_, opts) { can_read_details? && expand_for_path?(opts) } diff --git a/app/views/projects/services/alerts/_help.html.haml b/app/views/projects/services/alerts/_help.html.haml index 318d46e962a..7abd198bea5 100644 --- a/app/views/projects/services/alerts/_help.html.haml +++ b/app/views/projects/services/alerts/_help.html.haml @@ -1,7 +1 @@ -.js-alerts-service-settings{ data: { activated: @service.activated?.to_s, - form_path: scoped_integration_path(@service), - authorization_key: @service.token, - url: @service.url || _('<namespace / project>'), - disabled: 'true', - alerts_setup_url: help_page_path('user/project/integrations/generic_alerts.md', anchor: 'setting-up-generic-alerts'), - alerts_usage_url: help_page_path('user/project/operations/alert_management.md') } } +.js-alerts-service-settings{ data: alerts_settings_data(disabled: true) } diff --git a/changelogs/unreleased/john_long-support-multiple-mailbox-email-check.yml b/changelogs/unreleased/john_long-support-multiple-mailbox-email-check.yml new file mode 100644 index 00000000000..a566fb73d2c --- /dev/null +++ b/changelogs/unreleased/john_long-support-multiple-mailbox-email-check.yml @@ -0,0 +1,5 @@ +--- +title: Support multiple mailboxes incoming email check +merge_request: 35639 +author: +type: fixed diff --git a/changelogs/unreleased/render-job-details-on-downstream-pipelines.yml b/changelogs/unreleased/render-job-details-on-downstream-pipelines.yml new file mode 100644 index 00000000000..eb939b76873 --- /dev/null +++ b/changelogs/unreleased/render-job-details-on-downstream-pipelines.yml @@ -0,0 +1,5 @@ +--- +title: Render source job info in TriggeredPipelineEntity +merge_request: 35232 +author: +type: added diff --git a/db/migrate/20200707095849_add_load_performance_to_plan_limits.rb b/db/migrate/20200707095849_add_load_performance_to_plan_limits.rb new file mode 100644 index 00000000000..df95956f089 --- /dev/null +++ b/db/migrate/20200707095849_add_load_performance_to_plan_limits.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class AddLoadPerformanceToPlanLimits < ActiveRecord::Migration[6.0] + DOWNTIME = false + + def change + add_column :plan_limits, "ci_max_artifact_size_load_performance", :integer, default: 0, null: false + end +end diff --git a/db/structure.sql b/db/structure.sql index 9c48e97aaf7..8393b4fb730 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -13815,7 +13815,8 @@ CREATE TABLE public.plan_limits ( ci_max_artifact_size_secret_detection integer DEFAULT 0 NOT NULL, ci_max_artifact_size_requirements integer DEFAULT 0 NOT NULL, ci_max_artifact_size_coverage_fuzzing integer DEFAULT 0 NOT NULL, - ci_max_artifact_size_browser_performance integer DEFAULT 0 NOT NULL + ci_max_artifact_size_browser_performance integer DEFAULT 0 NOT NULL, + ci_max_artifact_size_load_performance integer DEFAULT 0 NOT NULL ); CREATE SEQUENCE public.plan_limits_id_seq @@ -23648,5 +23649,6 @@ COPY "schema_migrations" (version) FROM STDIN; 20200706170536 20200707071941 20200707094341 +20200707095849 \. diff --git a/doc/ci/pipelines/job_artifacts.md b/doc/ci/pipelines/job_artifacts.md index c2aad1ac6e4..1b6378c904d 100644 --- a/doc/ci/pipelines/job_artifacts.md +++ b/doc/ci/pipelines/job_artifacts.md @@ -257,6 +257,17 @@ as artifacts. The collected Browser Performance report will be uploaded to GitLab as an artifact and will be automatically shown in merge requests. +#### `artifacts:reports:load_performance` **(PREMIUM)** + +> - Introduced in [GitLab 13.2](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35260) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.2. +> - Requires GitLab Runner 11.5 and above. + +The `load_performance` report collects [Load Performance Testing metrics](../../user/project/merge_requests/load_performance_testing.md) +as artifacts. + +The report is uploaded to GitLab as an artifact and is +shown in merge requests automatically. + #### `artifacts:reports:metrics` **(PREMIUM)** > Introduced in GitLab 11.10. diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index 62dadaed9f5..68bbe74e2a4 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -117,7 +117,7 @@ The following table lists available parameters for jobs: | [`when`](#when) | When to run job. Also available: `when:manual` and `when:delayed`. | | [`environment`](#environment) | Name of an environment to which the job deploys. Also available: `environment:name`, `environment:url`, `environment:on_stop`, `environment:auto_stop_in` and `environment:action`. | | [`cache`](#cache) | List of files that should be cached between subsequent runs. Also available: `cache:paths`, `cache:key`, `cache:untracked`, and `cache:policy`. | -| [`artifacts`](#artifacts) | List of files and directories to attach to a job on success. Also available: `artifacts:paths`, `artifacts:exclude`, `artifacts:expose_as`, `artifacts:name`, `artifacts:untracked`, `artifacts:when`, `artifacts:expire_in`, `artifacts:reports`, `artifacts:reports:junit`, `artifacts:reports:cobertura`, and `artifacts:reports:terraform`.<br><br>In GitLab [Enterprise Edition](https://about.gitlab.com/pricing/), these are available: `artifacts:reports:codequality`, `artifacts:reports:sast`, `artifacts:reports:dependency_scanning`, `artifacts:reports:container_scanning`, `artifacts:reports:dast`, `artifacts:reports:license_scanning`, `artifacts:reports:license_management` (removed in GitLab 13.0), `artifacts:reports:performance` and `artifacts:reports:metrics`. | +| [`artifacts`](#artifacts) | List of files and directories to attach to a job on success. Also available: `artifacts:paths`, `artifacts:exclude`, `artifacts:expose_as`, `artifacts:name`, `artifacts:untracked`, `artifacts:when`, `artifacts:expire_in`, `artifacts:reports`, `artifacts:reports:junit`, `artifacts:reports:cobertura`, and `artifacts:reports:terraform`.<br><br>In GitLab [Enterprise Edition](https://about.gitlab.com/pricing/), these are available: `artifacts:reports:codequality`, `artifacts:reports:sast`, `artifacts:reports:dependency_scanning`, `artifacts:reports:container_scanning`, `artifacts:reports:dast`, `artifacts:reports:license_scanning`, `artifacts:reports:license_management` (removed in GitLab 13.0), `artifacts:reports:performance`, `artifacts:reports:load_performance`, and `artifacts:reports:metrics`. | | [`dependencies`](#dependencies) | Restrict which artifacts are passed to a specific job by providing a list of jobs to fetch artifacts from. | | [`coverage`](#coverage) | Code coverage settings for a given job. | | [`retry`](#retry) | When and how many times a job can be auto-retried in case of a failure. | @@ -3148,7 +3148,8 @@ These are the available report types: | [`artifacts:reports:dast`](../pipelines/job_artifacts.md#artifactsreportsdast-ultimate) **(ULTIMATE)** | The `dast` report collects Dynamic Application Security Testing vulnerabilities. | | [`artifacts:reports:license_management`](../pipelines/job_artifacts.md#artifactsreportslicense_management-ultimate) **(ULTIMATE)** | The `license_management` report collects Licenses (*removed from GitLab 13.0*). | | [`artifacts:reports:license_scanning`](../pipelines/job_artifacts.md#artifactsreportslicense_scanning-ultimate) **(ULTIMATE)** | The `license_scanning` report collects Licenses. | -| [`artifacts:reports:performance`](../pipelines/job_artifacts.md#artifactsreportsperformance-premium) **(PREMIUM)** | The `performance` report collects Browser Performance metrics. | +| [`artifacts:reports:performance`](../pipelines/job_artifacts.md#artifactsreportsperformance-premium) **(PREMIUM)** | The `performance` report collects Browser Performance metrics. | +| [`artifacts:reports:load_performance`](../pipelines/job_artifacts.md#artifactsreportsload_performance-premium) **(PREMIUM)** | The `load_performance` report collects load performance metrics. | | [`artifacts:reports:metrics`](../pipelines/job_artifacts.md#artifactsreportsmetrics-premium) **(PREMIUM)** | The `metrics` report collects Metrics. | #### `dependencies` diff --git a/doc/development/README.md b/doc/development/README.md index 88abc638ac6..ab86c252948 100644 --- a/doc/development/README.md +++ b/doc/development/README.md @@ -101,6 +101,7 @@ Complementary reads: - [Windows Development on GCP](windows.md) - [Code Intelligence](code_intelligence/index.md) - [Approval Rules](approval_rules.md) +- [Feature categorization](feature_categorization/index.md) ## Performance guides diff --git a/doc/development/feature_categorization/index.md b/doc/development/feature_categorization/index.md new file mode 100644 index 00000000000..bcd5e16cc2b --- /dev/null +++ b/doc/development/feature_categorization/index.md @@ -0,0 +1,130 @@ +# Feature Categorization + +> [Introduced](https://gitlab.com/groups/gitlab-com/gl-infra/-/epics/269) in GitLab 13.2. + +Each Sidekiq worker, controller action, or (eventually) API endpoint +must declare a `feature_category` attribute. This attribute maps each +of these to a [feature +category](https://about.gitlab.com/handbook/product/product-categories/). This +is done for error budgeting, alert routing, and team attribution. + +The list of feature categories can be found in the file `config/feature_categories.yml`. +This file is generated from the +[`stages.yml`](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/stages.yml) +data file used in the GitLab Handbook and other GitLab resources. + +## Updating `config/feature_categories.yml` + +Occasionally new features will be added to GitLab stages, groups, and +product categories. When this occurs, you can automatically update +`config/feature_categories.yml` by running +`scripts/update-feature-categories`. This script will fetch and parse +[`stages.yml`](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/stages.yml) +and generate a new version of the file, which needs to be committed to +the repository. + +The [Scalabilitity +team](https://about.gitlab.com/handbook/engineering/infrastructure/team/scalability) +currently maintains the `stages.yml` file. They will automatically be +notified on Slack when the file becomes outdated. + +## Sidekiq workers + +The declaration uses the `feature_category` class method, as shown below. + +```ruby +class SomeScheduledTaskWorker + include ApplicationWorker + + # Declares that this worker is part of the + # `continuous_integration` feature category + feature_category :continuous_integration + + # ... +end +``` + +The feature categories specified using `feature_category` should be +defined in +[`config/feature_categories.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/feature_categories.yml). If +not, the specs will fail. + +### Excluding Sidekiq workers from feature categorization + +A few Sidekiq workers, that are used across all features, cannot be mapped to a +single category. These should be declared as such using the `feature_category_not_owned!` +declaration, as shown below: + +```ruby +class SomeCrossCuttingConcernWorker + include ApplicationWorker + + # Declares that this worker does not map to a feature category + feature_category_not_owned! + + # ... +end +``` + +## Rails controllers + +Specifying feature categories on controller actions can be done using +the `feature_category` class method. + +A feature category can be specified on an entire controller +using: + +```ruby +class Projects::MergeRequestsController < ApplicationController + feature_category :source_code_management +end +``` + +The feature category can be limited to a list of actions using the +`only` argument, actions can be excluded using the `except` argument. + +```ruby +class Projects::MergeRequestsController < ApplicationController + feature_category :code_testing, only: [:metrics_reports] + feature_category :source_code_management, except: [:test_reports, :coverage_reports] +end +``` + +`except` and `only` arguments can not be combined. + +When specifying `except` all other actions will get the specified +category assigned. + +The assignment can also be scoped using `if` and `unless` procs: + +```ruby +class Projects::MergeRequestsController < ApplicationController + feature_category :source_code_management, + unless: -> (action) { action.include?("reports") } + if: -> (action) { action.include?("widget") } +end +``` + +In this case, both procs need to be satisfied for the action to get +the category assigned. + +### Excluding controller actions from feature categorization + +In the rare case an action cannot be tied to a feature category this +can be done using the `not_owned` feature category. + +```ruby +class Admin::LogsController < ApplicationController + feature_category :not_owned +end +``` + +### Ensuring feature categories are valid + +The `spec/controllers/every_controller_spec.rb` will iterate over all +defined routes, and check the controller to see if a category is +assigned to all actions. + +The spec also validates if the used feature categories are known. And +if the actions used in `only` and `except` configuration still exist +as routes. diff --git a/doc/development/sidekiq_style_guide.md b/doc/development/sidekiq_style_guide.md index 86979c18a57..04c310288d2 100644 --- a/doc/development/sidekiq_style_guide.md +++ b/doc/development/sidekiq_style_guide.md @@ -378,55 +378,10 @@ We use the following approach to determine whether a worker is CPU-bound: - Note that these values should not be used over small sample sizes, but rather over fairly large aggregates. -## Feature Categorization +## Feature category -Each Sidekiq worker, or one of its ancestor classes, must declare a -`feature_category` attribute. This attribute maps each worker to a feature -category. This is done for error budgeting, alert routing, and team attribution -for Sidekiq workers. - -The declaration uses the `feature_category` class method, as shown below. - -```ruby -class SomeScheduledTaskWorker - include ApplicationWorker - - # Declares that this worker is part of the - # `continuous_integration` feature category - feature_category :continuous_integration - - # ... -end -``` - -The list of value values can be found in the file `config/feature_categories.yml`. -This file is, in turn generated from the [`stages.yml` from the GitLab Company Handbook -source](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/stages.yml). - -### Updating `config/feature_categories.yml` - -Occasionally new features will be added to GitLab stages. When this occurs, you -can automatically update `config/feature_categories.yml` by running -`scripts/update-feature-categories`. This script will fetch and parse -[`stages.yml`](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/stages.yml) -and generate a new version of the file, which needs to be checked into source control. - -### Excluding Sidekiq workers from feature categorization - -A few Sidekiq workers, that are used across all features, cannot be mapped to a -single category. These should be declared as such using the `feature_category_not_owned!` - declaration, as shown below: - -```ruby -class SomeCrossCuttingConcernWorker - include ApplicationWorker - - # Declares that this worker does not map to a feature category - feature_category_not_owned! - - # ... -end -``` +All Sidekiq workers must define a known [feature +category](feature_categorization/index.md#sidekiq-workers). ## Job weights diff --git a/doc/topics/autodevops/customize.md b/doc/topics/autodevops/customize.md index 57851565e23..046db7a944b 100644 --- a/doc/topics/autodevops/customize.md +++ b/doc/topics/autodevops/customize.md @@ -364,7 +364,8 @@ The following table lists variables used to disable jobs. | `DAST_DISABLED` | From GitLab 11.0, used to disable the `dast` job. If the variable is present, the job won't be created. | | `DEPENDENCY_SCANNING_DISABLED` | From GitLab 11.0, used to disable the `dependency_scanning` job. If the variable is present, the job won't be created. | | `LICENSE_MANAGEMENT_DISABLED` | From GitLab 11.0, used to disable the `license_management` job. If the variable is present, the job won't be created. | -| `PERFORMANCE_DISABLED` | From GitLab 11.0, used to disable the `performance` job. If the variable is present, the job won't be created. | +| `PERFORMANCE_DISABLED` | From GitLab 11.0, used to disable the browser `performance` job. If the variable is present, the job won't be created. | +| `LOAD_PERFORMANCE_DISABLED` | From GitLab 13.2, used to disable the `load_performance` job. If the variable is present, the job won't be created. | | `REVIEW_DISABLED` | From GitLab 11.0, used to disable the `review` and the manual `review:stop` job. If the variable is present, these jobs won't be created. | | `SAST_DISABLED` | From GitLab 11.0, used to disable the `sast` job. If the variable is present, the job won't be created. | | `TEST_DISABLED` | From GitLab 11.0, used to disable the `test` job. If the variable is present, the job won't be created. | diff --git a/doc/topics/git/partial_clone.md b/doc/topics/git/partial_clone.md index 25619b9d2a6..de25c8a3283 100644 --- a/doc/topics/git/partial_clone.md +++ b/doc/topics/git/partial_clone.md @@ -84,7 +84,7 @@ Updating files: 100% (28/28), done. $ cd www-gitlab-com -$ git sparse-checkout init --cone +$ git sparse-checkout init --clone $ git sparse-checkout add data remote: Enumerating objects: 301, done. diff --git a/doc/user/project/merge_requests/img/load_performance_testing.png b/doc/user/project/merge_requests/img/load_performance_testing.png Binary files differnew file mode 100644 index 00000000000..3a58e9c28d4 --- /dev/null +++ b/doc/user/project/merge_requests/img/load_performance_testing.png diff --git a/doc/user/project/merge_requests/load_performance_testing.md b/doc/user/project/merge_requests/load_performance_testing.md new file mode 100644 index 00000000000..3239269109d --- /dev/null +++ b/doc/user/project/merge_requests/load_performance_testing.md @@ -0,0 +1,197 @@ +--- +stage: Verify +group: Testing +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers +type: reference, howto +--- + +# Load Performance Testing **(PREMIUM)** + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10683) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.2. + +With Load Performance Testing, you can test the impact of any pending code changes +to your application's backend in [GitLab CI/CD](../../../ci/README.md). + +GitLab uses [k6](https://k6.io/), a free and open source +tool, for measuring the system performance of applications under +load. + +Unlike [Browser Performance Testing](browser_performance_testing.md), which is +used to measure how web sites perform in client browsers, Load Performance Testing +can be used to perform various types of [load tests](https://k6.io/docs/#use-cases) +against application endpoints such as APIs, Web Controllers, and so on. +This can be used to test how the backend or the server performs at scale. + +For example, you can use Load Performance Testing to perform many concurrent +GET calls to a popular API endpoint in your application to see how it performs. + +## How Load Performance Testing works + +First, define a job in your `.gitlab-ci.yml` file that generates the +[Load Performance report artifact](../../../ci/pipelines/job_artifacts.md#artifactsreportsload_performance-premium). +GitLab checks this report, compares key load performance metrics +between the source and target branches, and then shows the information in a merge request widget: + +![Load Performance Widget](img/load_performance_testing.png) + +Next, you need to configure the test environment and write the k6 test. + +The key performance metrics that the merge request widget shows after the test completes are: + +- Checks: The percentage pass rate of the [checks](https://k6.io/docs/using-k6/checks) configured in the k6 test. +- TTFB P90: The 90th percentile of how long it took to start receiving responses, aka the [Time to First Byte](https://en.wikipedia.org/wiki/Time_to_first_byte) (TTFB). +- TTFB P95: The 95th percentile for TTFB. +- RPS: The average requests per second (RPS) rate the test was able to achieve. + +NOTE: **Note:** +If the Load Performance report has no data to compare, such as when you add the +Load Performance job in your `.gitlab-ci.yml` for the very first time, +the Load Performance report widget won't show. It must have run at least +once on the target branch (`master`, for example), before it will display in a +merge request targeting that branch. + +## Configure the Load Performance Testing job + +Configuring your Load Performance Testing job can be broken down into several distinct parts: + +- Determine the test parameters such as throughput, and so on. +- Set up the target test environment for load performance testing. +- Design and write the k6 test. + +### Determine the test parameters + +The first thing you need to do is determine the [type of load test](https://k6.io/docs/test-types/introduction) +you want to run, and how it will run (for example, the number of users, throughput, and so on). + +Refer to the [k6 docs](https://k6.io/docs/), especially the [k6 testing guides](https://k6.io/docs/testing-guides), +for guidance on the above and more. + +### Test Environment setup + +A large part of the effort around load performance testing is to prepare the target test environment +for high loads. You should ensure it's able to handle the +[throughput](https://k6.io/blog/monthly-visits-concurrent-users) it will be tested with. + +It's also typically required to have representative test data in the target environment +for the load performance test to use. + +We strongly recommend [not running these tests against a production environment](https://k6.io/our-beliefs#load-test-in-a-pre-production-environment). + +### Write the load performance test + +After the environment is prepared, you can write the k6 test itself. k6 is a flexible +tool and can be used to run [many kinds of performance tests](https://k6.io/docs/test-types/introduction). +Refer to the [k6 documentation](https://k6.io/docs/) for detailed information on how to write tests. + +### Configure the test in GitLab CI/CD + +When your k6 test is ready, the next step is to configure the load performance +testing job in GitLab CI/CD. The easiest way to do this is to use the +[`Verify/Load-Performance-Testing.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Verify/Load-Performance-Testing.gitlab-ci.yml) +template that is included with GitLab. + +NOTE: **Note:** +For large scale k6 tests you need to ensure the GitLab Runner instance performing the actual +test is able to handle running the test. Refer to [k6's guidance](https://k6.io/docs/testing-guides/running-large-tests#hardware-considerations) +for spec details. The [default shared GitLab.com runners](../../gitlab_com/#linux-shared-runners) +likely have insufficient specs to handle most large k6 tests. + +This template runs the +[k6 Docker container](https://hub.docker.com/r/loadimpact/k6/) in the job and provides several ways to customize the +job. + +An example configuration workflow: + +1. Set up a GitLab Runner that can run Docker containers, such as a Runner using the + [Docker-in-Docker workflow](../../../ci/docker/using_docker_build.md#use-docker-in-docker-workflow-with-docker-executor). +1. Configure the default Load Performance Testing CI job in your `.gitlab-ci.yml` file. + You need to include the template and configure it with variables: + + ```yaml + include: + template: Verify/Load-Performance-Testing.gitlab-ci.yml + + load_performance: + variables: + K6_TEST_FILE: <PATH TO K6 TEST FILE IN PROJECT> + ``` + +The above example creates a `load_performance` job in your CI/CD pipeline that runs +the k6 test. + +NOTE: **Note:** +For Kubernetes setups a different template should be used: [`Jobs/Load-Performance-Testing.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/Load-Performance-Testing.gitlab-ci.yml). + +k6 has [various options](https://k6.io/docs/using-k6/options) to configure how it will run tests, such as what throughput (RPS) to run with, +how long the test should run, and so on. Almost all options can be configured in the test itself, but as +you can also pass command line options via the `K6_OPTIONS` variable. + +For example, you can override the duration of the test with a CLI option: + +```yaml + include: + template: Verify/Load-Performance-Testing.gitlab-ci.yml + + load_performance: + variables: + K6_TEST_FILE: <PATH TO K6 TEST FILE IN PROJECT> + K6_OPTIONS: '--duration 30s' +``` + +GitLab only displays the key performance metrics in the MR widget if k6's results are saved +via [summary export](https://k6.io/docs/results-visualization/json#summary-export) +as a [Load Performance report artifact](../../../ci/pipelines/job_artifacts.md#artifactsreportsload_performance-premium). +The latest Load Performance artifact available is always used. + +If [GitLab Pages](../pages/index.md) is enabled, you can view the report directly in your browser. + +### Load Performance testing in Review Apps + +The CI/CD YAML configuration example above works for testing against static environments, +but it can be extended to work with [review apps](../../../ci/review_apps) or +[dynamic environments](../../../ci/environments) with a few extra steps. + +The best approach is to capture the dynamic URL into a custom environment variable that +is then [inherited](../../../ci/variables/README.md#inherit-environment-variables) +by the `load_performance` job. The k6 test script to be run should then be configured to +use that environment URL, such as: ``http.get(`${__ENV.ENVIRONMENT_URL`})``. + +For example: + +1. In the `review` job: + 1. Capture the dynamic URL and save it into a `.env` file, e.g. `echo "ENVIRONMENT_URL=$CI_ENVIRONMENT_URL" >> review.env`. + 1. Set the `.env` file to be an [`artifacts:reports:dotenv` report](../../../ci/variables/README.md#inherit-environment-variables). +1. Set the `load_performance` job to depend on the review job, so it inherits the environment variable. +1. Configure the k6 test script to use the environment variable in it's steps. + +Your `.gitlab-ci.yml` file might be similar to: + +```yaml +stages: + - deploy + - performance + +include: + template: Verify/Load-Performance-Testing.gitlab-ci.yml + +review: + stage: deploy + environment: + name: review/$CI_COMMIT_REF_NAME + url: http://$CI_ENVIRONMENT_SLUG.example.com + script: + - run_deploy_script + - echo "ENVIRONMENT_URL=$CI_ENVIRONMENT_URL" >> review.env + artifacts: + reports: + dotenv: + review.env + rules: + - if: '$CI_COMMIT_BRANCH' # Modify to match your pipeline rules, or use `only/except` if needed. + +load_performance: + dependencies: + - review + rules: + - if: '$CI_COMMIT_BRANCH' # Modify to match your pipeline rules, or use `only/except` if needed. +``` diff --git a/doc/user/project/static_site_editor/index.md b/doc/user/project/static_site_editor/index.md index 15c3bd5522e..8653bb5001a 100644 --- a/doc/user/project/static_site_editor/index.md +++ b/doc/user/project/static_site_editor/index.md @@ -9,6 +9,7 @@ description: "The static site editor enables users to edit content on static web > - WYSIWYG editor [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214559) in GitLab 13.0. > - Support for adding images through the WYSIWYG editor [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216640) in GitLab 13.1. > - Markdown front matter hidden on the WYSIWYG editor [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216834) in GitLab 13.1. +> - Support for `*.md.erb` files [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/223171) in GitLab 13.2. DANGER: **Danger:** In GitLab 13.0, we [introduced breaking changes](https://gitlab.com/gitlab-org/gitlab/-/issues/213282) @@ -100,5 +101,4 @@ company and a new feature has been added to the company product. ## Limitations -- Currently, the Static Site Editor only works for files ending in `.md`. For example, it will not work for a file `index.html.md.erb` while it works for `index.html.md`. - The Static Site Editor still cannot be quickly added to existing Middleman sites. Follow this [epic](https://gitlab.com/groups/gitlab-org/-/epics/2784) for updates. diff --git a/lib/gitlab/ci/config/entry/reports.rb b/lib/gitlab/ci/config/entry/reports.rb index 8be18c059a3..0ae65f43723 100644 --- a/lib/gitlab/ci/config/entry/reports.rb +++ b/lib/gitlab/ci/config/entry/reports.rb @@ -13,7 +13,7 @@ module Gitlab ALLOWED_KEYS = %i[junit codequality sast secret_detection dependency_scanning container_scanning - dast performance browser_performance license_management license_scanning metrics lsif + dast performance browser_performance load_performance license_management license_scanning metrics lsif dotenv cobertura terraform accessibility cluster_applications requirements coverage_fuzzing].freeze @@ -34,6 +34,7 @@ module Gitlab validates :dast, array_of_strings_or_string: true validates :performance, array_of_strings_or_string: true validates :browser_performance, array_of_strings_or_string: true + validates :load_performance, array_of_strings_or_string: true validates :license_management, array_of_strings_or_string: true validates :license_scanning, array_of_strings_or_string: true validates :metrics, array_of_strings_or_string: true diff --git a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml index e37cd14d1d1..bcd1e092191 100644 --- a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml @@ -12,6 +12,7 @@ # * code_quality: CODE_QUALITY_DISABLED # * license_management: LICENSE_MANAGEMENT_DISABLED # * performance: PERFORMANCE_DISABLED +# * load_performance: LOAD_PERFORMANCE_DISABLED # * sast: SAST_DISABLED # * secret_detection: SECRET_DETECTION_DISABLED # * dependency_scanning: DEPENDENCY_SCANNING_DISABLED diff --git a/lib/gitlab/ci/templates/Jobs/Load-Performance-Testing.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Load-Performance-Testing.gitlab-ci.yml new file mode 100644 index 00000000000..b437ddbd734 --- /dev/null +++ b/lib/gitlab/ci/templates/Jobs/Load-Performance-Testing.gitlab-ci.yml @@ -0,0 +1,29 @@ +load_performance: + stage: performance + image: docker:19.03.11 + allow_failure: true + variables: + DOCKER_TLS_CERTDIR: "" + K6_IMAGE: loadimpact/k6 + K6_VERSION: 0.26.2 + K6_TEST_FILE: github.com/loadimpact/k6/samples/http_get.js + K6_OPTIONS: '' + services: + - docker:19.03.11-dind + script: + - | + if ! docker info &>/dev/null; then + if [ -z "$DOCKER_HOST" -a "$KUBERNETES_PORT" ]; then + export DOCKER_HOST='tcp://localhost:2375' + fi + fi + - docker run --rm -v "$(pwd)":/k6 -w /k6 $K6_IMAGE:$K6_VERSION run $K6_TEST_FILE --summary-export=load-performance.json $K6_OPTIONS + artifacts: + reports: + load_performance: load-performance.json + rules: + - if: '$CI_KUBERNETES_ACTIVE == null || $CI_KUBERNETES_ACTIVE == ""' + when: never + - if: '$LOAD_PERFORMANCE_DISABLED' + when: never + - if: '$CI_COMMIT_TAG || $CI_COMMIT_BRANCH' diff --git a/lib/gitlab/ci/templates/Verify/Load-Performance-Testing.gitlab-ci.yml b/lib/gitlab/ci/templates/Verify/Load-Performance-Testing.gitlab-ci.yml new file mode 100644 index 00000000000..d39bd234020 --- /dev/null +++ b/lib/gitlab/ci/templates/Verify/Load-Performance-Testing.gitlab-ci.yml @@ -0,0 +1,23 @@ +# Read more about the feature here: https://docs.gitlab.com/ee/user/project/merge_requests/load_performance_testing.html + +stages: + - build + - test + - deploy + - performance + +load_performance: + stage: performance + image: docker:git + variables: + K6_IMAGE: loadimpact/k6 + K6_VERSION: 0.26.2 + K6_TEST_FILE: github.com/loadimpact/k6/samples/http_get.js + K6_OPTIONS: '' + services: + - docker:stable-dind + script: + - docker run --rm -v "$(pwd)":/k6 -w /k6 $K6_IMAGE:$K6_VERSION run $K6_TEST_FILE --summary-export=load-performance.json $K6_OPTIONS + artifacts: + reports: + load_performance: load-performance.json diff --git a/lib/system_check/incoming_email/imap_authentication_check.rb b/lib/system_check/incoming_email/imap_authentication_check.rb index 613c2296375..056021d460c 100644 --- a/lib/system_check/incoming_email/imap_authentication_check.rb +++ b/lib/system_check/incoming_email/imap_authentication_check.rb @@ -28,9 +28,12 @@ module SystemCheck private def try_connect_imap - imap = Net::IMAP.new(config[:host], port: config[:port], ssl: config[:ssl]) - imap.starttls if config[:start_tls] - imap.login(config[:email], config[:password]) + config.each do |mailbox| + $stdout.puts "Checking #{mailbox[:email]}" + imap = Net::IMAP.new(mailbox[:host], port: mailbox[:port], ssl: mailbox[:ssl]) + imap.starttls if mailbox[:start_tls] + imap.login(mailbox[:email], mailbox[:password]) + end true rescue => error @error = error @@ -51,7 +54,7 @@ module SystemCheck erb.filename = mail_room_config_path config_file = YAML.load(erb.result) - config_file.dig(:mailboxes, 0) + config_file[:mailboxes] end end end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index ddd3429c495..058eb4fe0d2 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -986,9 +986,6 @@ msgstr "" msgid "<code>Protected</code> to expose them to protected branches or tags only." msgstr "" -msgid "<namespace / project>" -msgstr "" - msgid "<no name set>" msgstr "" @@ -27247,6 +27244,9 @@ msgstr "" msgid "ciReport|Browser performance test metrics: No changes" msgstr "" +msgid "ciReport|Checks" +msgstr "" + msgid "ciReport|Code quality" msgstr "" @@ -27307,6 +27307,12 @@ msgstr "" msgid "ciReport|Learn more about interacting with security reports" msgstr "" +msgid "ciReport|Load performance test metrics: " +msgstr "" + +msgid "ciReport|Load performance test metrics: No changes" +msgstr "" + msgid "ciReport|Loading %{reportName} report" msgstr "" @@ -27322,6 +27328,9 @@ msgstr "" msgid "ciReport|No code quality issues found" msgstr "" +msgid "ciReport|RPS" +msgstr "" + msgid "ciReport|Resolve with merge request" msgstr "" @@ -27349,6 +27358,12 @@ msgstr "" msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code." msgstr "" +msgid "ciReport|TTFB P90" +msgstr "" + +msgid "ciReport|TTFB P95" +msgstr "" + msgid "ciReport|There was an error creating the issue. Please try again." msgstr "" diff --git a/qa/qa/fixtures/monitored_auto_devops/.gitlab-ci.yml b/qa/qa/fixtures/monitored_auto_devops/.gitlab-ci.yml deleted file mode 100644 index 052ba1c14fb..00000000000 --- a/qa/qa/fixtures/monitored_auto_devops/.gitlab-ci.yml +++ /dev/null @@ -1,338 +0,0 @@ -# This is stripped down version of the .gitlab-ci.yml found -# here: https://gitlab.com/joshlambert/autodevops-deploy. -# -# It performs only the deploy stage. - -image: alpine:latest - -variables: - # AUTO_DEVOPS_DOMAIN is the application deployment domain and should be set as a variable at the group or project level. - AUTO_DEVOPS_DOMAIN: $AUTO_DEVOPS_DOMAIN - - POSTGRES_USER: user - POSTGRES_PASSWORD: testing-password - POSTGRES_ENABLED: 'false' - POSTGRES_DB: $CI_ENVIRONMENT_SLUG - - KUBERNETES_VERSION: 1.11.6 - HELM_VERSION: 2.12.2 - - DOCKER_DRIVER: overlay2 - -stages: - - production - -# This job continuously deploys to production on every push to `master`. - -production: - stage: production - tags: - - qa - script: - - check_kube_domain - - install_dependencies - - download_chart - - ensure_namespace - - initialize_tiller - - create_secret - - deploy - environment: - name: production - url: http://$CI_PROJECT_PATH_SLUG.$AUTO_DEVOPS_DOMAIN - artifacts: - paths: [environment_url.txt] - only: - refs: - - master - kubernetes: active - -# --------------------------------------------------------------------------- - -.auto_devops: &auto_devops | - # Auto DevOps variables and functions - [[ "$TRACE" ]] && set -x - auto_database_url=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${CI_ENVIRONMENT_SLUG}-postgres:5432/${POSTGRES_DB} - export DATABASE_URL=${DATABASE_URL-$auto_database_url} - export CI_APPLICATION_REPOSITORY=$CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG - export CI_APPLICATION_TAG=$CI_COMMIT_SHA - export CI_CONTAINER_NAME=ci_job_build_${CI_JOB_ID} - export TILLER_NAMESPACE=$KUBE_NAMESPACE - # Extract "MAJOR.MINOR" from CI_SERVER_VERSION and generate "MAJOR-MINOR-stable" for Security Products - export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/') - - - function get_replicas() { - track="${1:-stable}" - percentage="${2:-100}" - - env_track=$( echo $track | tr -s '[:lower:]' '[:upper:]' ) - env_slug=$( echo ${CI_ENVIRONMENT_SLUG//-/_} | tr -s '[:lower:]' '[:upper:]' ) - - if [[ "$track" == "stable" ]] || [[ "$track" == "rollout" ]]; then - # for stable track get number of replicas from `PRODUCTION_REPLICAS` - eval new_replicas=\$${env_slug}_REPLICAS - if [[ -z "$new_replicas" ]]; then - new_replicas=$REPLICAS - fi - else - # for all tracks get number of replicas from `CANARY_PRODUCTION_REPLICAS` - eval new_replicas=\$${env_track}_${env_slug}_REPLICAS - if [[ -z "$new_replicas" ]]; then - eval new_replicas=\${env_track}_REPLICAS - fi - fi - - replicas="${new_replicas:-1}" - replicas="$(($replicas * $percentage / 100))" - - # always return at least one replicas - if [[ $replicas -gt 0 ]]; then - echo "$replicas" - else - echo 1 - fi - } - - - # Extracts variables prefixed with K8S_SECRET_ - # and creates a Kubernetes secret. - # - # e.g. If we have the following environment variables: - # K8S_SECRET_A=value1 - # K8S_SECRET_B=multi\ word\ value - # - # Then we will create a secret with the following key-value pairs: - # data: - # A: dmFsdWUxCg== - # B: bXVsdGkgd29yZCB2YWx1ZQo= - function create_application_secret() { - track="${1-stable}" - export APPLICATION_SECRET_NAME=$(application_secret_name "$track") - - env | sed -n "s/^K8S_SECRET_\(.*\)$/\1/p" > k8s_prefixed_variables - - kubectl create secret \ - -n "$KUBE_NAMESPACE" generic "$APPLICATION_SECRET_NAME" \ - --from-env-file k8s_prefixed_variables -o yaml --dry-run | - kubectl replace -n "$KUBE_NAMESPACE" --force -f - - - export APPLICATION_SECRET_CHECKSUM=$(cat k8s_prefixed_variables | sha256sum | cut -d ' ' -f 1) - - rm k8s_prefixed_variables - } - - function deploy_name() { - name="$CI_ENVIRONMENT_SLUG" - track="${1-stable}" - - if [[ "$track" != "stable" ]]; then - name="$name-$track" - fi - - echo $name - } - - function application_secret_name() { - track="${1-stable}" - name=$(deploy_name "$track") - - echo "${name}-secret" - } - - - function deploy() { - track="${1-stable}" - percentage="${2:-100}" - name=$(deploy_name "$track") - - replicas="1" - service_enabled="true" - postgres_enabled="$POSTGRES_ENABLED" - - # if track is different than stable, - # re-use all attached resources - if [[ "$track" != "stable" ]]; then - service_enabled="false" - postgres_enabled="false" - fi - - replicas=$(get_replicas "$track" "$percentage") - - if [[ "$CI_PROJECT_VISIBILITY" != "public" ]]; then - secret_name='gitlab-registry' - else - secret_name='' - fi - - create_application_secret "$track" - - env_slug=$(echo ${CI_ENVIRONMENT_SLUG//-/_} | tr -s '[:lower:]' '[:upper:]') - eval env_ADDITIONAL_HOSTS=\$${env_slug}_ADDITIONAL_HOSTS - if [ -n "$env_ADDITIONAL_HOSTS" ]; then - additional_hosts="{$env_ADDITIONAL_HOSTS}" - elif [ -n "$ADDITIONAL_HOSTS" ]; then - additional_hosts="{$ADDITIONAL_HOSTS}" - fi - - if [[ -n "$DB_INITIALIZE" && -z "$(helm ls -q "^$name$")" ]]; then - echo "Deploying first release with database initialization..." - helm upgrade --install \ - --wait \ - --set service.enabled="$service_enabled" \ - --set releaseOverride="$CI_ENVIRONMENT_SLUG" \ - --set image.repository="registry.gitlab.com/joshlambert/ruby-gke/master" \ - --set image.tag="63492726c2264a0277141d6a6573c3d22ecd7de3" \ - --set image.pullPolicy=IfNotPresent \ - --set image.secrets[0].name="$secret_name" \ - --set application.track="$track" \ - --set application.database_url="$DATABASE_URL" \ - --set application.secretName="$APPLICATION_SECRET_NAME" \ - --set application.secretChecksum="$APPLICATION_SECRET_CHECKSUM" \ - --set service.url="$CI_ENVIRONMENT_URL" \ - --set service.additionalHosts="$additional_hosts" \ - --set replicaCount="$replicas" \ - --set postgresql.enabled="$postgres_enabled" \ - --set postgresql.nameOverride="postgres" \ - --set postgresql.postgresUser="$POSTGRES_USER" \ - --set postgresql.postgresPassword="$POSTGRES_PASSWORD" \ - --set postgresql.postgresDatabase="$POSTGRES_DB" \ - --set application.initializeCommand="$DB_INITIALIZE" \ - --set gitlab.app="$CI_PROJECT_PATH_SLUG" \ - --set gitlab.env="$CI_ENVIRONMENT_SLUG" \ - --namespace="$KUBE_NAMESPACE" \ - "$name" \ - chart/ - - echo "Deploying second release..." - helm upgrade --reuse-values \ - --wait \ - --set application.initializeCommand="" \ - --set application.migrateCommand="$DB_MIGRATE" \ - --namespace="$KUBE_NAMESPACE" \ - "$name" \ - chart/ - else - echo "Deploying new release..." - helm upgrade --install \ - --wait \ - --set service.enabled="$service_enabled" \ - --set releaseOverride="$CI_ENVIRONMENT_SLUG" \ - --set image.repository="registry.gitlab.com/joshlambert/ruby-gke/master" \ - --set image.tag="63492726c2264a0277141d6a6573c3d22ecd7de3" \ - --set image.pullPolicy=IfNotPresent \ - --set image.secrets[0].name="$secret_name" \ - --set application.track="$track" \ - --set application.database_url="$DATABASE_URL" \ - --set application.secretName="$APPLICATION_SECRET_NAME" \ - --set application.secretChecksum="$APPLICATION_SECRET_CHECKSUM" \ - --set service.url="$CI_ENVIRONMENT_URL" \ - --set service.additionalHosts="$additional_hosts" \ - --set replicaCount="$replicas" \ - --set postgresql.enabled="$postgres_enabled" \ - --set postgresql.nameOverride="postgres" \ - --set postgresql.postgresUser="$POSTGRES_USER" \ - --set postgresql.postgresPassword="$POSTGRES_PASSWORD" \ - --set postgresql.postgresDatabase="$POSTGRES_DB" \ - --set application.migrateCommand="$DB_MIGRATE" \ - --set gitlab.app="$CI_PROJECT_PATH_SLUG" \ - --set gitlab.env="$CI_ENVIRONMENT_SLUG" \ - --namespace="$KUBE_NAMESPACE" \ - "$name" \ - chart/ - fi - - kubectl rollout status -n "$KUBE_NAMESPACE" -w "deployment/$name" - } - - - function install_dependencies() { - apk add -U openssl curl tar gzip bash ca-certificates git - wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub - wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.23-r3/glibc-2.23-r3.apk - apk add glibc-2.23-r3.apk - rm glibc-2.23-r3.apk - - curl "https://kubernetes-helm.storage.googleapis.com/helm-v${HELM_VERSION}-linux-amd64.tar.gz" | tar zx - mv linux-amd64/helm /usr/bin/ - mv linux-amd64/tiller /usr/bin/ - helm version --client - tiller -version - - curl -L -o /usr/bin/kubectl "https://storage.googleapis.com/kubernetes-release/release/v${KUBERNETES_VERSION}/bin/linux/amd64/kubectl" - chmod +x /usr/bin/kubectl - kubectl version --client - } - - function download_chart() { - if [[ ! -d chart ]]; then - auto_chart=${AUTO_DEVOPS_CHART:-gitlab/auto-deploy-app} - auto_chart_name=$(basename $auto_chart) - auto_chart_name=${auto_chart_name%.tgz} - else - auto_chart="chart" - auto_chart_name="chart" - fi - - helm init --client-only - helm repo add gitlab https://charts.gitlab.io - if [[ ! -d "$auto_chart" ]]; then - helm fetch ${auto_chart} --untar - fi - if [ "$auto_chart_name" != "chart" ]; then - mv ${auto_chart_name} chart - fi - - helm dependency update chart/ - helm dependency build chart/ - } - - function ensure_namespace() { - kubectl describe namespace "$KUBE_NAMESPACE" || kubectl create namespace "$KUBE_NAMESPACE" - } - - function check_kube_domain() { - if [ -z ${AUTO_DEVOPS_DOMAIN+x} ]; then - echo "In order to deploy or use Review Apps, AUTO_DEVOPS_DOMAIN variable must be set" - echo "You can do it in Auto DevOps project settings or defining a secret variable at group or project level" - echo "You can also manually add it in .gitlab-ci.yml" - false - else - true - fi - } - - function initialize_tiller() { - echo "Checking Tiller..." - - export HELM_HOST="localhost:44134" - tiller -listen ${HELM_HOST} -alsologtostderr > /dev/null 2>&1 & - echo "Tiller is listening on ${HELM_HOST}" - - if ! helm version --debug; then - echo "Failed to init Tiller." - return 1 - fi - echo "" - } - - function create_secret() { - echo "Create secret..." - if [[ "$CI_PROJECT_VISIBILITY" == "public" ]]; then - return - fi - - kubectl create secret -n "$KUBE_NAMESPACE" \ - docker-registry gitlab-registry \ - --docker-server="$CI_REGISTRY" \ - --docker-username="$CI_REGISTRY_USER" \ - --docker-password="$CI_REGISTRY_PASSWORD" \ - --docker-email="$GITLAB_USER_EMAIL" \ - -o yaml --dry-run | kubectl replace -n "$KUBE_NAMESPACE" --force -f - - } - - function persist_environment_url() { - echo $CI_ENVIRONMENT_URL > environment_url.txt - } - -before_script: - - *auto_devops diff --git a/qa/qa/page/group/sub_menus/members.rb b/qa/qa/page/group/sub_menus/members.rb index 33c4caaddcb..895da639c02 100644 --- a/qa/qa/page/group/sub_menus/members.rb +++ b/qa/qa/page/group/sub_menus/members.rb @@ -7,6 +7,10 @@ module QA class Members < Page::Base include Page::Component::UsersSelect + view 'app/assets/javascripts/vue_shared/components/remove_member_modal.vue' do + element :remove_member_modal_content + end + view 'app/views/shared/members/_invite_member.html.haml' do element :member_select_field element :invite_member_button @@ -32,10 +36,12 @@ module QA end def remove_member(username) - page.accept_confirm do - within_element(:member_row, text: username) do - click_element :delete_member_button - end + within_element(:member_row, text: username) do + click_element :delete_member_button + end + + within_element(:remove_member_modal_content) do + click_button("Remove member") end end end diff --git a/qa/qa/page/project/job/show.rb b/qa/qa/page/project/job/show.rb index 971b8c5e5f8..6243dc92b45 100644 --- a/qa/qa/page/project/job/show.rb +++ b/qa/qa/page/project/job/show.rb @@ -23,6 +23,9 @@ module QA raise "Timed out waiting for the build trace to load" unless loaded? raise "Timed out waiting for the status to be a valid completed state" unless completed?(timeout: timeout) + job_log = find_element(:job_log_content).text + QA::Runtime::Logger.debug(" \n\n ------- Job log: ------- \n\n #{job_log} \n -------") + passed? end diff --git a/spec/fixtures/api/schemas/public_api/v4/packages/composer/index.json b/spec/fixtures/api/schemas/public_api/v4/packages/composer/index.json new file mode 100644 index 00000000000..2245b39cabe --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/packages/composer/index.json @@ -0,0 +1,29 @@ +{ + "type": "object", + "required": ["packages", "provider-includes", "providers-url"], + "properties": { + "packages": { + "type": "array", + "items": { "type": "integer" } + }, + "providers-url": { + "type": "string" + }, + "provider-includes": { + "type": "object", + "required": ["p/%hash%.json"], + "properties": { + "p/%hash%.json": { + "type": "object", + "required": ["sha256"], + "properties": { + "sha256": { + "type": "string" + } + } + } + } + } + }, + "additionalProperties": false +} diff --git a/spec/fixtures/api/schemas/public_api/v4/packages/composer/package.json b/spec/fixtures/api/schemas/public_api/v4/packages/composer/package.json new file mode 100644 index 00000000000..324a8a4e00c --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/packages/composer/package.json @@ -0,0 +1,65 @@ +{ + "type": "object", + "required": [ + "packages" + ], + "properties": { + "packages": { + "type": "object", + "propertyNames": { + "pattern": "^[A-Za-z_]+" + }, + "patternProperties": { + "^[A-Za-z_]+": { + "type": "object", + "propertyNames": { + "pattern": "^[A-Za-z_0-9.]+" + }, + "patternProperties": { + "^[A-Za-z_0-9.]+": { + "type": "object", + "required": [ + "dist", + "uid", + "version" + ], + "properties": { + "uid": { + "type": "integer" + }, + "version": { + "type": "string" + }, + "dist": { + "type": "object", + "required": [ + "type", + "url", + "reference", + "shasum" + ], + "properties": { + "type": { + "type": "string" + }, + "url": { + "type": "string" + }, + "reference": { + "type": "string" + }, + "shasum": { + "type": "string" + } + } + } + } + } + } + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false +} diff --git a/spec/fixtures/api/schemas/public_api/v4/packages/composer/provider.json b/spec/fixtures/api/schemas/public_api/v4/packages/composer/provider.json new file mode 100644 index 00000000000..5335fa9ad64 --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/packages/composer/provider.json @@ -0,0 +1,25 @@ +{ + "type": "object", + "required": ["providers"], + "properties": { + "providers": { + "type": "object", + "propertyNames": { + "pattern": "^[A-Za-z_]+" + }, + "patternProperties": { + "^[A-Za-z_]+": { + "type": "object", + "required": ["sha256"], + "properties": { + "sha256": { + "type": "string" + } + } + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false +} diff --git a/spec/fixtures/api/schemas/public_api/v4/packages/group_package.json b/spec/fixtures/api/schemas/public_api/v4/packages/group_package.json new file mode 100644 index 00000000000..f18e314a287 --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/packages/group_package.json @@ -0,0 +1,33 @@ +{ + "type": "object", + "required": ["name", "version", "package_type", "_links", "project_id", "project_path"], + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "package_type": { + "type": "string" + }, + "_links": { + "type": "object", + "required": ["web_path"], + "properties": { + "details": { + "type": "string" + } + } + }, + "created_at": { + "type": "string" + }, + "project_id": { + "type": "integer" + }, + "project_path": { + "type": "string" + } + } +} diff --git a/spec/fixtures/api/schemas/public_api/v4/packages/group_packages.json b/spec/fixtures/api/schemas/public_api/v4/packages/group_packages.json new file mode 100644 index 00000000000..3169bbc8f25 --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/packages/group_packages.json @@ -0,0 +1,4 @@ +{ + "type": "array", + "items": { "$ref": "./group_package.json" } +} diff --git a/spec/fixtures/api/schemas/public_api/v4/packages/npm_package.json b/spec/fixtures/api/schemas/public_api/v4/packages/npm_package.json new file mode 100644 index 00000000000..d7e8a872abe --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/packages/npm_package.json @@ -0,0 +1,8 @@ +{ + "type": "object", + "required" : ["name", "versions"], + "properties" : { + "name": { "type": "string" }, + "versions": { "type": "object" } + } +} diff --git a/spec/fixtures/api/schemas/public_api/v4/packages/npm_package_tags.json b/spec/fixtures/api/schemas/public_api/v4/packages/npm_package_tags.json new file mode 100644 index 00000000000..db64fe1de23 --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/packages/npm_package_tags.json @@ -0,0 +1,7 @@ +{ + "type": "object", + "properties" : { + "$tag": { "type": "string" }, + "$version": { "type": "string" } + } +} diff --git a/spec/fixtures/api/schemas/public_api/v4/packages/npm_package_version.json b/spec/fixtures/api/schemas/public_api/v4/packages/npm_package_version.json new file mode 100644 index 00000000000..3e74dc0a1c2 --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/packages/npm_package_version.json @@ -0,0 +1,46 @@ +{ + "type": "object", + "required": ["name", "version", "dist"], + "properties" : { + "name": { "type": "string" }, + "version": { "type": "string" }, + "dist": { + "type": "object", + "required": ["shasum", "tarball"], + "properties" : { + "shasum": { "type": "string" }, + "tarball": { "type": "string" } + } + }, + "dependencies": { + "type": "object", + "patternProperties": { + ".{1,}": { "type": "string" } + } + }, + "devDependencies": { + "type": "object", + "patternProperties": { + ".{1,}": { "type": "string" } + } + }, + "bundleDependencies": { + "type": "object", + "patternProperties": { + ".{1,}": { "type": "string" } + } + }, + "peerDependencies": { + "type": "object", + "patternProperties": { + ".{1,}": { "type": "string" } + } + }, + "deprecated": { + "type": "object", + "patternProperties": { + ".{1,}": { "type": "string" } + } + } + } +} diff --git a/spec/fixtures/api/schemas/public_api/v4/packages/nuget/dependency_group.json b/spec/fixtures/api/schemas/public_api/v4/packages/nuget/dependency_group.json new file mode 100644 index 00000000000..87dc2794b61 --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/packages/nuget/dependency_group.json @@ -0,0 +1,22 @@ +{ + "type": "object", + "required": ["@id", "@type", "dependencies"], + "properties": { + "@id": { "type": "string" }, + "@type": { "const": "PackageDependencyGroup" }, + "targetFramework": { "type": "string" }, + "dependencies": { + "type": "array", + "items": { + "type": "object", + "required": ["@id", "@type", "id", "range"], + "properties": { + "@id": { "type": "string" }, + "@type": { "const": "PackageDependency" }, + "id": { "type": "string" }, + "range": { "type": "string" } + } + } + } + } +} diff --git a/spec/fixtures/api/schemas/public_api/v4/packages/nuget/download_versions.json b/spec/fixtures/api/schemas/public_api/v4/packages/nuget/download_versions.json new file mode 100644 index 00000000000..ab40dfbbc4c --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/packages/nuget/download_versions.json @@ -0,0 +1,10 @@ +{ + "type": "object", + "required": ["versions"], + "properties": { + "versions": { + "type": "array", + "items": { "type": "string" } + } + } +} diff --git a/spec/fixtures/api/schemas/public_api/v4/packages/nuget/package_metadata.json b/spec/fixtures/api/schemas/public_api/v4/packages/nuget/package_metadata.json new file mode 100644 index 00000000000..1244cbe474e --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/packages/nuget/package_metadata.json @@ -0,0 +1,28 @@ +{ + "type": "object", + "required": ["@id", "packageContent", "catalogEntry"], + "properties": { + "@id": { "type": "string" }, + "packageContent": { "type": "string" }, + "catalogEntry": { + "type": "object", + "required": ["@id", "authors", "dependencyGroups", "id", "packageContent", "summary", "version"], + "properties": { + "@id": { "type": "string" }, + "authors": { "const": "" }, + "id": { "type": "string" }, + "packageContent": { "type": "string" }, + "summary": { "const": "" }, + "tags": { "type": "string" }, + "projectUrl": { "type": "string" }, + "licenseUrl": { "type": "string" }, + "iconUrl": { "type": "string" }, + "version": { "type": "string" }, + "dependencyGroups": { + "type": "array", + "items": { "$ref": "./dependency_group.json" } + } + } + } + } +} diff --git a/spec/fixtures/api/schemas/public_api/v4/packages/nuget/packages_metadata.json b/spec/fixtures/api/schemas/public_api/v4/packages/nuget/packages_metadata.json new file mode 100644 index 00000000000..724df5a437d --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/packages/nuget/packages_metadata.json @@ -0,0 +1,54 @@ +{ + "type": "object", + "required": ["count", "items"], + "properties": { + "count": { "const": 0 }, + "items": { + "type": "array", + "items": { + "type": "object", + "required": ["lower", "upper", "count", "items"], + "properties": { + "lower": { "type": "string" }, + "upper": { "type": "string" }, + "count": { "type": "integer" }, + "items": { + "type": "array", + "items": { + "type": "object", + "required": ["@id", "packageContent", "catalogEntry"], + "properties": { + "@id": { "type": "string" }, + "packageContent": { "type": "string" }, + "catalogEntry": { + "type": "object", + "required": ["@id", "authors", "dependencyGroups", "id", "packageContent", "summary", "version"], + "properties": { + "@id": { "type": "string" }, + "authors": { "const": "" }, + "id": { "type": "string" }, + "packageContent": { "type": "string" }, + "summary": { "const": "" }, + "tags": { "type": "string" }, + "projectUrl": { "type": "string" }, + "licenseUrl": { "type": "string" }, + "iconUrl": { "type": "string" }, + "version": { "type": "string" }, + "dependencyGroups": { + "type": "array", + "items": { "$ref": "./dependency_group.json" } + } + } + } + } + } + } + } + } + } + } +} + + + + diff --git a/spec/fixtures/api/schemas/public_api/v4/packages/nuget/search.json b/spec/fixtures/api/schemas/public_api/v4/packages/nuget/search.json new file mode 100644 index 00000000000..73d0927e24c --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/packages/nuget/search.json @@ -0,0 +1,39 @@ +{ + "type": "object", + "required": ["totalHits", "data"], + "properties": { + "totalHits": { "type": "integer" }, + "data": { + "type": "array", + "items": { + "type": "object", + "required": ["@type", "authors", "id", "summary", "title", "totalDownloads", "verified", "versions"], + "properties": { + "@type": { "const": "Package" }, + "authors": { "const": "" }, + "id": { "type": "string" }, + "summary": { "const": "" }, + "title": { "type": "string" }, + "totalDownloads": { "const": 0 }, + "verified": { "const": true }, + "tags": { "type": "string" }, + "projectUrl": { "type": "string" }, + "licenseUrl": { "type": "string" }, + "iconUrl": { "type": "string" }, + "versions": { + "type": "array", + "items": { + "type": "object", + "required": ["@id", "version", "downloads"], + "properties": { + "@id": { "type": "string" }, + "version": { "type": "string" }, + "downloads": { "const": 0 } + } + } + } + } + } + } + } +} diff --git a/spec/fixtures/api/schemas/public_api/v4/packages/nuget/service_index.json b/spec/fixtures/api/schemas/public_api/v4/packages/nuget/service_index.json new file mode 100644 index 00000000000..405018f8c37 --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/packages/nuget/service_index.json @@ -0,0 +1,19 @@ +{ + "type": "object", + "required": ["version", "resources"], + "properties": { + "version": { "const": "3.0.0" }, + "resources": { + "type": "array", + "items": { + "type": "object", + "required": ["@id", "@type", "comment"], + "properties": { + "@id": { "type": "string" }, + "@type": { "type": "string" }, + "comment": { "type": "string" } + } + } + } + } +} diff --git a/spec/fixtures/api/schemas/public_api/v4/packages/package.json b/spec/fixtures/api/schemas/public_api/v4/packages/package.json new file mode 100644 index 00000000000..757e5fd26b6 --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/packages/package.json @@ -0,0 +1,41 @@ +{ + "type": "object", + "required": [ + "name", + "version", + "package_type", + "_links", + "versions" + ], + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "package_type": { + "type": "string" + }, + "_links": { + "type": "object", + "required": [ + "web_path" + ], + "properties": { + "details": { + "type": "string" + } + } + }, + "created_at": { + "type": "string" + }, + "versions": { + "type": "array", + "items": { + "$ref": "package_version.json" + } + } + } +} diff --git a/spec/fixtures/api/schemas/public_api/v4/packages/package_files.json b/spec/fixtures/api/schemas/public_api/v4/packages/package_files.json new file mode 100644 index 00000000000..f057adba65c --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/packages/package_files.json @@ -0,0 +1,13 @@ +{ + "type": "array", + "items": { + "type": "object", + "required" : ["id", "package_id", "file_name"], + "properties" : { + "id": { "type": "integer" }, + "package_id": { "type": "integer" }, + "file_name": { "type": "string" }, + "file_sha1": { "type": "string" } + } + } +} diff --git a/spec/fixtures/api/schemas/public_api/v4/packages/package_version.json b/spec/fixtures/api/schemas/public_api/v4/packages/package_version.json new file mode 100644 index 00000000000..72f2a2121ad --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/packages/package_version.json @@ -0,0 +1,19 @@ +{ + "type": "object", + "required": [ + "version", + "created_at", + "pipeline" + ], + "properties": { + "version": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "pipeline": { + "$ref": "../pipeline.json" + } + } +} diff --git a/spec/fixtures/api/schemas/public_api/v4/packages/package_with_build.json b/spec/fixtures/api/schemas/public_api/v4/packages/package_with_build.json new file mode 100644 index 00000000000..de3ef94138e --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/packages/package_with_build.json @@ -0,0 +1,10 @@ +{ + "type": "object", + "required": ["name", "version", "package_type", "pipeline"], + "properties": { + "name": { "type": "string" }, + "version": { "type": "string" }, + "package_type": { "type": "string" }, + "pipeline": { "$ref": "../pipeline.json" } + } +} diff --git a/spec/fixtures/api/schemas/public_api/v4/packages/packages.json b/spec/fixtures/api/schemas/public_api/v4/packages/packages.json new file mode 100644 index 00000000000..66364da4fdb --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/packages/packages.json @@ -0,0 +1,4 @@ +{ + "type": "array", + "items": { "$ref": "./package.json" } +} diff --git a/spec/fixtures/api/schemas/public_api/v4/pipeline.json b/spec/fixtures/api/schemas/public_api/v4/pipeline.json new file mode 100644 index 00000000000..f83844a115d --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/pipeline.json @@ -0,0 +1,27 @@ +{ + "type": "object", + "required": ["id", "sha", "ref", "status", "created_at", "updated_at", "web_url"], + "properties": { + "id": { + "type": "integer" + }, + "sha": { + "type": "string" + }, + "ref": { + "type": "string" + }, + "status": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "web_url": { + "type": "string" + } + } +} diff --git a/spec/frontend/ide/lib/editor_spec.js b/spec/frontend/ide/lib/editor_spec.js index 0952facf3ee..5f28309422d 100644 --- a/spec/frontend/ide/lib/editor_spec.js +++ b/spec/frontend/ide/lib/editor_spec.js @@ -200,6 +200,20 @@ describe('Multi-file editor library', () => { }); describe('schemas', () => { + let originalGon; + + beforeEach(() => { + originalGon = window.gon; + window.gon = { features: { schemaLinting: true } }; + + delete Editor.editorInstance; + instance = Editor.create(); + }); + + afterEach(() => { + window.gon = originalGon; + }); + it('registers custom schemas defined with Monaco', () => { expect(monacoLanguages.yaml.yamlDefaults.diagnosticsOptions).toMatchObject({ schemas: [{ fileMatch: ['*.gitlab-ci.yml'] }], diff --git a/spec/helpers/operations_helper_spec.rb b/spec/helpers/operations_helper_spec.rb index 40f92c538e0..7050a7b9290 100644 --- a/spec/helpers/operations_helper_spec.rb +++ b/spec/helpers/operations_helper_spec.rb @@ -39,7 +39,8 @@ RSpec.describe OperationsHelper do 'prometheus_authorization_key' => nil, 'prometheus_api_url' => nil, 'prometheus_activated' => 'false', - 'prometheus_url' => notify_project_prometheus_alerts_url(project, format: :json) + 'prometheus_url' => notify_project_prometheus_alerts_url(project, format: :json), + 'disabled' => 'false' ) end end diff --git a/spec/lib/gitlab/ci/config/entry/reports_spec.rb b/spec/lib/gitlab/ci/config/entry/reports_spec.rb index 3a6e228ce97..98105ebcd55 100644 --- a/spec/lib/gitlab/ci/config/entry/reports_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/reports_spec.rb @@ -46,6 +46,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Reports do :performance | 'performance.json' :browser_performance | 'browser-performance.json' :browser_performance | 'performance.json' + :load_performance | 'load-performance.json' :lsif | 'lsif.json' :dotenv | 'build.dotenv' :cobertura | 'cobertura-coverage.xml' diff --git a/spec/lib/gitlab/ci/templates/Verify/load_performance_testing_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/Verify/load_performance_testing_gitlab_ci_yaml_spec.rb new file mode 100644 index 00000000000..9711df55226 --- /dev/null +++ b/spec/lib/gitlab/ci/templates/Verify/load_performance_testing_gitlab_ci_yaml_spec.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Verify/Load-Performance-Testing.gitlab-ci.yml' do + subject(:template) do + <<~YAML + stages: + - test + - performance + + include: + - template: 'Verify/Load-Performance-Testing.gitlab-ci.yml' + + placeholder: + script: + - keep pipeline validator happy by having a job when stages are intentionally empty + YAML + end + + describe 'the created pipeline' do + let(:user) { create(:admin) } + let(:project) { create(:project, :repository) } + + let(:default_branch) { 'master' } + let(:pipeline_ref) { default_branch } + let(:service) { Ci::CreatePipelineService.new(project, user, ref: pipeline_ref) } + let(:pipeline) { service.execute!(:push) } + let(:build_names) { pipeline.builds.pluck(:name) } + + before do + stub_ci_pipeline_yaml_file(template) + + allow_any_instance_of(Ci::BuildScheduleWorker).to receive(:perform).and_return(true) + allow(project).to receive(:default_branch).and_return(default_branch) + end + + it 'has no errors' do + expect(pipeline.errors).to be_empty + end + + shared_examples_for 'load_performance job on tag or branch' do + it 'by default' do + expect(build_names).to include('load_performance') + end + end + + context 'on master' do + it_behaves_like 'load_performance job on tag or branch' + end + + context 'on another branch' do + let(:pipeline_ref) { 'feature' } + + it_behaves_like 'load_performance job on tag or branch' + end + + context 'on tag' do + let(:pipeline_ref) { 'v1.0.0' } + + it_behaves_like 'load_performance job on tag or branch' + end + + context 'on merge request' do + let(:service) { MergeRequests::CreatePipelineService.new(project, user) } + let(:merge_request) { create(:merge_request, :simple, source_project: project) } + let(:pipeline) { service.execute(merge_request) } + + it 'has no jobs' do + expect(pipeline).to be_merge_request_event + expect(build_names).to be_empty + end + end + end +end diff --git a/spec/models/plan_limits_spec.rb b/spec/models/plan_limits_spec.rb index 4b67d4f2964..831fd0dcbc3 100644 --- a/spec/models/plan_limits_spec.rb +++ b/spec/models/plan_limits_spec.rb @@ -191,6 +191,7 @@ RSpec.describe PlanLimits do ci_max_artifact_size_license_scanning ci_max_artifact_size_performance ci_max_artifact_size_browser_performance + ci_max_artifact_size_load_performance ci_max_artifact_size_metrics ci_max_artifact_size_metrics_referee ci_max_artifact_size_network_referee diff --git a/spec/serializers/pipeline_details_entity_spec.rb b/spec/serializers/pipeline_details_entity_spec.rb index 55bb9720957..35ce7c7175c 100644 --- a/spec/serializers/pipeline_details_entity_spec.rb +++ b/spec/serializers/pipeline_details_entity_spec.rb @@ -157,20 +157,30 @@ RSpec.describe PipelineDetailsEntity do context 'when pipeline triggered other pipeline' do let(:pipeline) { create(:ci_empty_pipeline) } - let(:build) { create(:ci_build, pipeline: pipeline) } + let(:build) { create(:ci_build, name: 'child', stage: 'test', pipeline: pipeline) } + let(:bridge) { create(:ci_bridge, name: 'cross-project', stage: 'build', pipeline: pipeline) } + let(:child_pipeline) { create(:ci_pipeline, project: pipeline.project) } + let(:cross_project_pipeline) { create(:ci_pipeline) } before do - create(:ci_sources_pipeline, source_job: build) - create(:ci_sources_pipeline, source_job: build) + create(:ci_sources_pipeline, source_job: build, pipeline: child_pipeline) + create(:ci_sources_pipeline, source_job: bridge, pipeline: cross_project_pipeline) end - it 'contains an information about depedent pipeline' do + it 'contains an information about dependent pipeline', :aggregate_failures do expect(subject[:triggered]).to be_a(Array) expect(subject[:triggered].length).to eq(2) expect(subject[:triggered].first[:path]).not_to be_nil expect(subject[:triggered].first[:details]).not_to be_nil expect(subject[:triggered].first[:details][:status]).not_to be_nil expect(subject[:triggered].first[:project]).not_to be_nil + + source_jobs = subject[:triggered] + .index_by { |pipeline| pipeline[:id] } + .transform_values { |pipeline| pipeline.fetch(:source_job) } + + expect(source_jobs[cross_project_pipeline.id][:name]).to eq('cross-project') + expect(source_jobs[child_pipeline.id][:name]).to eq('child') end end end diff --git a/spec/serializers/pipeline_serializer_spec.rb b/spec/serializers/pipeline_serializer_spec.rb index cdff5f0e001..c1386ac4eb2 100644 --- a/spec/serializers/pipeline_serializer_spec.rb +++ b/spec/serializers/pipeline_serializer_spec.rb @@ -211,6 +211,33 @@ RSpec.describe PipelineSerializer do end end + context 'with triggered pipelines' do + let(:ref) { 'feature' } + + before do + pipeline_1 = create(:ci_pipeline) + build_1 = create(:ci_build, pipeline: pipeline_1) + create(:ci_sources_pipeline, source_job: build_1) + + pipeline_2 = create(:ci_pipeline) + build_2 = create(:ci_build, pipeline: pipeline_2) + create(:ci_sources_pipeline, source_job: build_2) + end + + it 'verifies number of queries', :request_store do + recorded = ActiveRecord::QueryRecorder.new { subject } + + # 99 queries by default + 2 related to preloading + # :source_pipeline and :source_job + # Existing numbers are high and require performance optimization + # https://gitlab.com/gitlab-org/gitlab/-/issues/225156 + expected_queries = Gitlab.ee? ? 101 : 92 + + expect(recorded.count).to be_within(2).of(expected_queries) + expect(recorded.cached_count).to eq(0) + end + end + def create_pipeline(status) create(:ci_empty_pipeline, project: project, diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb index 690b6c7b9d4..02fc0fd4a43 100644 --- a/spec/services/ci/retry_build_service_spec.rb +++ b/spec/services/ci/retry_build_service_spec.rb @@ -33,7 +33,7 @@ RSpec.describe Ci::RetryBuildService do job_artifacts_sast job_artifacts_secret_detection job_artifacts_dependency_scanning job_artifacts_container_scanning job_artifacts_dast job_artifacts_license_management job_artifacts_license_scanning - job_artifacts_performance job_artifacts_browser_performance + job_artifacts_performance job_artifacts_browser_performance job_artifacts_load_performance job_artifacts_lsif job_artifacts_terraform job_artifacts_cluster_applications job_artifacts_codequality job_artifacts_metrics scheduled_at job_variables waiting_for_resource_at job_artifacts_metrics_referee |