Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-10-03 18:08:19 +00:00
parent a99d0fa692
commit d83bbccfcd
61 changed files with 956 additions and 438 deletions

View File

@ -1 +1 @@
4c15523cf680c107c5aa2b8268674cd0345a6b78
7397b0e1c1a4a8fc0290347da1ddf7ac11547a18

View File

@ -158,7 +158,7 @@ const createAlert = function createAlert({
onDismiss();
}
this.$destroy();
this.$el.parentNode.removeChild(this.$el);
this.$el.parentNode?.removeChild(this.$el);
},
},
render(h) {

View File

@ -1,56 +0,0 @@
import $ from 'jquery';
import { loadCSSFile } from '../lib/utils/css_utils';
let instanceCount = 0;
class AutoWidthDropdownSelect {
constructor(selectElement) {
this.$selectElement = $(selectElement);
this.dropdownClass = `js-auto-width-select-dropdown-${instanceCount}`;
instanceCount += 1;
}
init() {
const { dropdownClass } = this;
import(/* webpackChunkName: 'select2' */ 'select2/select2')
.then(() => {
// eslint-disable-next-line promise/no-nesting
loadCSSFile(gon.select2_css_path)
.then(() => {
this.$selectElement.select2({
dropdownCssClass: dropdownClass,
...AutoWidthDropdownSelect.selectOptions(this.dropdownClass),
});
})
.catch(() => {});
})
.catch(() => {});
return this;
}
static selectOptions(dropdownClass) {
return {
dropdownCss() {
let resultantWidth = 'auto';
const $dropdown = $(`.${dropdownClass}`);
// We have to look at the parent because
// `offsetParent` on a `display: none;` is `null`
const offsetParentWidth = $(this).parent().offsetParent().width();
// Reset any width to let it naturally flow
$dropdown.css('width', 'auto');
if ($dropdown.outerWidth(false) > offsetParentWidth) {
resultantWidth = offsetParentWidth;
}
return {
width: resultantWidth,
maxWidth: offsetParentWidth,
};
},
};
}
}
export default AutoWidthDropdownSelect;

View File

@ -2,10 +2,7 @@ import $ from 'jquery';
import Pikaday from 'pikaday';
import GfmAutoComplete from 'ee_else_ce/gfm_auto_complete';
import Autosave from '~/autosave';
import AutoWidthDropdownSelect from '~/issuable/auto_width_dropdown_select';
import { loadCSSFile } from '~/lib/utils/css_utils';
import { parsePikadayDate, pikadayToString } from '~/lib/utils/datetime_utility';
import { select2AxiosTransport } from '~/lib/utils/select2_utils';
import { queryToObject, objectToQuery } from '~/lib/utils/url_utility';
import UsersSelect from '~/users_select';
import ZenMode from '~/zen_mode';
@ -118,12 +115,6 @@ export default class IssuableForm {
});
calendar.setDate(parsePikadayDate($issuableDueDate.val()));
}
this.$targetBranchSelect = $('.js-target-branch-select', this.form);
if (this.$targetBranchSelect.length) {
this.initTargetBranchDropdown();
}
}
initAutosave() {
@ -214,47 +205,4 @@ export default class IssuableForm {
addWip() {
this.titleField.val(`Draft: ${this.titleField.val()}`);
}
initTargetBranchDropdown() {
import(/* webpackChunkName: 'select2' */ 'select2/select2')
.then(() => {
// eslint-disable-next-line promise/no-nesting
loadCSSFile(gon.select2_css_path)
.then(() => {
this.$targetBranchSelect.select2({
...AutoWidthDropdownSelect.selectOptions('js-target-branch-select'),
ajax: {
url: this.$targetBranchSelect.data('endpoint'),
dataType: 'JSON',
quietMillis: 250,
data(search) {
return {
search,
};
},
results({ results }) {
return {
// `data` keys are translated so we can't just access them with a string based key
results: results[Object.keys(results)[0]].map((name) => ({
id: name,
text: name,
})),
};
},
transport: select2AxiosTransport,
},
initSelection(el, callback) {
const val = el.val();
callback({
id: val,
text: val,
});
},
});
})
.catch(() => {});
})
.catch(() => {});
}
}

View File

@ -834,6 +834,10 @@ $tabs-holder-z-index: 250;
@include gl-ml-auto;
@include gl-rounded-pill;
@include gl-w-9;
&.is-checked:hover {
background-color: $blue-500;
}
}
}

View File

@ -0,0 +1,15 @@
# frozen_string_literal: true
module RegistrationsTracking
extend ActiveSupport::Concern
included do
helper_method :glm_tracking_params
end
private
def glm_tracking_params
params.permit(:glm_source, :glm_content)
end
end

View File

@ -2,7 +2,7 @@
class Groups::RunnersController < Groups::ApplicationController
before_action :authorize_read_group_runners!, only: [:index, :show]
before_action :authorize_admin_group_runners!, only: [:edit, :update, :destroy, :pause, :resume]
before_action :authorize_update_runner!, only: [:edit, :update, :destroy, :pause, :resume]
before_action :runner, only: [:edit, :update, :destroy, :pause, :resume, :show]
before_action only: [:show] do
@ -37,7 +37,10 @@ class Groups::RunnersController < Groups::ApplicationController
private
def runner
@runner ||= Ci::RunnersFinder.new(current_user: current_user, params: { group: @group }).execute
group_params = { group: @group }
group_params[:membership] = :all_available if Feature.enabled?(:runners_finder_all_available, @group)
@runner ||= Ci::RunnersFinder.new(current_user: current_user, params: group_params).execute
.except(:limit, :offset)
.find(params[:id])
end
@ -45,6 +48,12 @@ class Groups::RunnersController < Groups::ApplicationController
def runner_params
params.require(:runner).permit(Ci::Runner::FORM_EDITABLE)
end
def authorize_update_runner!
return if can?(current_user, :admin_group_runners, group) && can?(current_user, :update_runner, runner)
render_404
end
end
Groups::RunnersController.prepend_mod

View File

@ -451,15 +451,16 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
return :failed
end
squashing = params.fetch(:squash, false)
merge_service = ::MergeRequests::MergeService.new(project: @project, current_user: current_user, params: merge_params)
unless merge_service.hooks_validation_pass?(@merge_request)
unless merge_service.hooks_validation_pass?(@merge_request, validate_squash_message: squashing)
return :hook_validation_error
end
return :sha_mismatch if params[:sha] != @merge_request.diff_head_sha
@merge_request.update(merge_error: nil, squash: params.fetch(:squash, false))
@merge_request.update(merge_error: nil, squash: squashing)
if auto_merge_requested?
if merge_request.auto_merge_enabled?

View File

@ -4,6 +4,7 @@ module Registrations
class WelcomeController < ApplicationController
include OneTrustCSP
include GoogleAnalyticsCSP
include RegistrationsTracking
layout 'minimal'
skip_before_action :authenticate_user!, :required_signup_info, :check_two_factor_requirement, only: [:show, :update]

View File

@ -8,6 +8,7 @@ class RegistrationsController < Devise::RegistrationsController
include OneTrustCSP
include BizibleCSP
include GoogleAnalyticsCSP
include RegistrationsTracking
layout 'devise'
@ -114,13 +115,18 @@ class RegistrationsController < Devise::RegistrationsController
def after_sign_up_path_for(user)
Gitlab::AppLogger.info(user_created_message(confirmed: user.confirmed?))
users_sign_up_welcome_path
users_sign_up_welcome_path(glm_tracking_params)
end
def after_inactive_sign_up_path_for(resource)
Gitlab::AppLogger.info(user_created_message)
return new_user_session_path(anchor: 'login-pane') if resource.blocked_pending_approval?
return dashboard_projects_path if Feature.enabled?(:soft_email_confirmation)
# when email confirmation is enabled, path to redirect is saved
# after user confirms and comes back, he will be redirected
store_location_for(:redirect, users_sign_up_welcome_path(glm_tracking_params))
return identity_verification_redirect_path if custom_confirmation_enabled?(resource)
users_almost_there_path(email: resource.email)

View File

@ -13,6 +13,13 @@ module Types
null: false,
description: 'Branch name, with wildcards, for the branch rules.'
field :is_default,
type: GraphQL::Types::Boolean,
null: false,
method: :default_branch?,
calls_gitaly: true,
description: "Check if this branch rule protects the project's default branch."
field :branch_protection,
type: Types::BranchRules::BranchProtectionType,
null: false,

View File

@ -6,12 +6,14 @@ module Ci
class BuildMetadata < Ci::ApplicationRecord
BuildTimeout = Struct.new(:value, :source)
include Ci::Partitionable
include Presentable
include ChronicDurationAttribute
include Gitlab::Utils::StrongMemoize
self.table_name = 'ci_builds_metadata'
self.primary_key = 'id'
partitionable scope: :build
belongs_to :build, class_name: 'CommitStatus'
belongs_to :project

View File

@ -19,7 +19,32 @@ module Ci
extend ActiveSupport::Concern
include ::Gitlab::Utils::StrongMemoize
module Testing
InclusionError = Class.new(StandardError)
PARTITIONABLE_MODELS = %w[
CommitStatus
Ci::BuildMetadata
Ci::Stage
Ci::JobArtifact
Ci::PipelineVariable
Ci::Pipeline
].freeze
def self.check_inclusion(klass)
return if PARTITIONABLE_MODELS.include?(klass.name)
raise Partitionable::Testing::InclusionError,
"#{klass} must be included in PARTITIONABLE_MODELS"
rescue InclusionError => e
Gitlab::ErrorTracking.track_and_raise_for_dev_exception(e)
end
end
included do
Partitionable::Testing.check_inclusion(self)
before_validation :set_partition_id, on: :create
validates :partition_id, presence: true
@ -37,6 +62,8 @@ module Ci
def partitionable(scope:)
define_method(:partition_scope_value) do
strong_memoize(:partition_scope_value) do
next Ci::Pipeline.current_partition_value if respond_to?(:importing?) && importing?
record = scope.to_proc.call(self)
record.respond_to?(:partition_id) ? record.partition_id : record
end

View File

@ -95,6 +95,10 @@ class ProtectedBranch < ApplicationRecord
def self.downcase_humanized_name
name.underscore.humanize.downcase
end
def default_branch?
name == project.default_branch
end
end
ProtectedBranch.prepend_mod_with('ProtectedBranch')

View File

@ -9,12 +9,12 @@ module MergeRequests
attr_reader :merge_request
# Overridden in EE.
def hooks_validation_pass?(_merge_request)
def hooks_validation_pass?(merge_request, validate_squash_message: false)
true
end
# Overridden in EE.
def hooks_validation_error(_merge_request)
def hooks_validation_error(merge_request, validate_squash_message: false)
# No-op
end

View File

@ -11,7 +11,7 @@ module Packages
def build_empty_structure
Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
xml.public_send(self.class::ROOT_TAG, self.class::ROOT_ATTRIBUTES) # rubocop:disable GitlabSecurity/PublicSend
xml.method_missing(self.class::ROOT_TAG, self.class::ROOT_ATTRIBUTES)
end.to_xml
end
end

View File

@ -9,6 +9,7 @@ module Packages
xmlns: 'http://linux.duke.edu/metadata/repo',
'xmlns:rpm': 'http://linux.duke.edu/metadata/rpm'
}.freeze
ALLOWED_DATA_VALUE_KEYS = %i[checksum open-checksum location timestamp size open-size].freeze
# Expected `data` structure
#
@ -48,9 +49,9 @@ module Packages
end
def build_file_info(info, xml)
info.each do |key, attributes|
info.slice(*ALLOWED_DATA_VALUE_KEYS).each do |key, attributes|
value = attributes.delete(:value)
xml.public_send(key, value, attributes) # rubocop:disable GitlabSecurity/PublicSend
xml.method_missing(key, value, attributes)
end
end
end

View File

@ -9,7 +9,7 @@
.signup-page
= render 'devise/shared/signup_box',
url: registration_path(resource_name),
url: registration_path(resource_name, glm_tracking_params.to_hash),
button_text: _('Register'),
borderless: Feature.enabled?(:restyle_login_page, @project),
show_omniauth_providers: omniauth_enabled? && button_based_providers_enabled?

View File

@ -17,7 +17,9 @@
%p.gl-text-center= html_escape(_('%{gitlab_experience_text}. We won\'t share this information with anyone.')) % { gitlab_experience_text: gitlab_experience_text }
- else
%p.gl-text-center= html_escape(_('%{gitlab_experience_text}. Don\'t worry, this information isn\'t shared outside of your self-managed GitLab instance.')) % { gitlab_experience_text: gitlab_experience_text }
= gitlab_ui_form_for(current_user, url: users_sign_up_welcome_path, html: { class: 'card gl-w-full! gl-p-5 js-users-signup-welcome', 'aria-live' => 'assertive' }) do |f|
= gitlab_ui_form_for(current_user,
url: users_sign_up_welcome_path(glm_tracking_params),
html: { class: 'card gl-w-full! gl-p-5 js-users-signup-welcome', 'aria-live' => 'assertive' }) do |f|
.devise-errors
= render 'devise/shared/error_messages', resource: current_user
.row

View File

@ -0,0 +1,27 @@
# frozen_string_literal: true
class ScheduleUpdateCiPipelineArtifactsLockedStatus < Gitlab::Database::Migration[2.0]
disable_ddl_transaction!
MIGRATION = 'UpdateCiPipelineArtifactsUnknownLockedStatus'
DELAY_INTERVAL = 2.minutes
BATCH_SIZE = 1_000
SUB_BATCH_SIZE = 500
restrict_gitlab_migration gitlab_schema: :gitlab_ci
def up
queue_batched_background_migration(
MIGRATION,
:ci_pipeline_artifacts,
:id,
job_interval: DELAY_INTERVAL,
batch_size: BATCH_SIZE,
sub_batch_size: SUB_BATCH_SIZE
)
end
def down
delete_batched_background_migration(MIGRATION, :ci_pipeline_artifacts, :id, [])
end
end

View File

@ -0,0 +1 @@
5ec9b3f36a986cbb86c8005a4425307f0f4399a4a4030460e715370630cb9490

View File

@ -48,9 +48,9 @@ settings and automation to ensure that whatever a compliance team has configured
stays configured and working correctly. These features can help you automate
compliance:
- [**Compliance frameworks**](../user/project/settings/index.md#compliance-frameworks) (for groups): Create a custom
- [**Compliance frameworks**](../user/group/manage.md#compliance-frameworks) (for groups): Create a custom
compliance framework at the group level to describe the type of compliance requirements any child project needs to follow.
- [**Compliance pipelines**](../user/project/settings/index.md#compliance-pipeline-configuration) (for groups): Define a
- [**Compliance pipelines**](../user/group/manage.md#configure-a-compliance-pipeline) (for groups): Define a
pipeline configuration to run for any projects with a given compliance framework.
## Audit management

View File

@ -10258,6 +10258,7 @@ List of branch rules for a project, grouped by branch name.
| ---- | ---- | ----------- |
| <a id="branchrulebranchprotection"></a>`branchProtection` | [`BranchProtection!`](#branchprotection) | Branch protections configured for this branch rule. |
| <a id="branchrulecreatedat"></a>`createdAt` | [`Time!`](#time) | Timestamp of when the branch rule was created. |
| <a id="branchruleisdefault"></a>`isDefault` | [`Boolean!`](#boolean) | Check if this branch rule protects the project's default branch. |
| <a id="branchrulename"></a>`name` | [`String!`](#string) | Branch name, with wildcards, for the branch rules. |
| <a id="branchruleupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp of when the branch rule was last updated. |

View File

@ -359,14 +359,25 @@ We first create a unique index including the `(id, partition_id)`.
Then, we drop the primary key constraint and use the new index created to set
the new primary key constraint.
We must set the primary key explicitly as `ActiveRecord` does not support composite primary keys.
`ActiveRecord` [does not support](https://github.com/rails/rails/blob/6-1-stable/activerecord/lib/active_record/attribute_methods/primary_key.rb#L126)
composite primary keys, so we must force it to treat the `id` column as a primary key:
```ruby
class Model
class Model < ApplicationRecord
self.primary_key = 'id'
end
```
The application layer is now ignorant of the database structure and all of the
existing queries from `ActiveRecord` continue to use the `id` column to access
the data. There is some risk to this approach because it is possible to
construct application code that results in duplicate models with the same `id`
value, but on a different `partition_id`. To mitigate this risk we must ensure
that all inserts use the database sequence to populate the `id` since they are
[guaranteed](https://www.postgresql.org/docs/12/sql-createsequence.html#id-1.9.3.81.7)
to allocate distinct values and rewrite the access patterns to include the
`partition_id` value. Manually assigning the ids during inserts must be avoided.
### Foreign keys
Foreign keys must reference columns that either are a primary key or form a

View File

@ -379,7 +379,7 @@ start. Jobs in the current stage are not stopped and continue to run.
- If a job does not specify a [`stage`](#stage), the job is assigned the `test` stage.
- If a stage is defined but no jobs use it, the stage is not visible in the pipeline,
which can help [compliance pipeline configurations](../../user/project/settings/index.md#compliance-pipeline-configuration):
which can help [compliance pipeline configurations](../../user/group/manage.md#configure-a-compliance-pipeline):
- Stages can be defined in the compliance configuration but remain hidden if not used.
- The defined stages become visible when developers use them in job definitions.

View File

@ -147,10 +147,14 @@ between your computer and GitLab.
git clone https://gitlab.com/gitlab-tests/sample-project.git
```
1. GitLab requests your username and password:
- If you have 2FA enabled for your account, you must [clone using a token](#clone-using-a-token)
with `read_repository` or `write_repository` permissions instead of your account's password.
- If you don't have 2FA enabled, use your account's password.
1. GitLab requests your username and password.
If you have enabled two-factor authentication (2FA) on your account, you cannot use your account password. Instead, you can do one of the following:
- [Clone using a token](#clone-using-a-token) with `read_repository` or `write_repository` permissions.
- Install [Git Credential Manager](../user/profile/account/two_factor_authentication.md#git-credential-manager).
If you have not enabled 2FA, use your account password.
1. To view the files, go to the new directory:

View File

@ -244,7 +244,7 @@ To enable or disable the banner:
> [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/352316) from GitLab Premium to GitLab Ultimate in 15.0.
NOTE:
An alternative [compliance solution](../../project/settings/index.md#compliance-pipeline-configuration)
An alternative [compliance solution](../../group/manage.md#configure-a-compliance-pipeline)
is available. We recommend this alternative solution because it provides greater flexibility,
allowing required pipelines to be assigned to specific compliance framework labels.

View File

@ -19,10 +19,17 @@ The Security Configuration page lists the following for the security testing and
- Whether or not it is available.
- A configuration button or a link to its configuration guide.
The status of each security control is determined by the project's latest default branch
[CI pipeline](../../../ci/pipelines/index.md).
If a job with the expected security report artifact exists in the pipeline, the feature's status is
_enabled_.
The status of each security control is determined by the following process:
1. Check for a [CI pipeline](../../../ci/pipelines/index.md) in the most recent commit on the default branch.
1. If no CI pipelines exist, then consider all security scanners disabled. Show the **Not enabled** status.
1. If a pipeline is found, then inspect the CI YAML for each job in the CI/CD pipeline. If a
job in the pipeline defines an [`artifacts:reports` keyword](../../../ci/yaml/artifacts_reports.md)
for a security scanner, then consider the security scanner enabled. Show the **Enabled** status.
Failed pipelines and jobs are included in this process. If a scanner is configured but the job fails,
that scanner is still considered enabled. This process also determines the scanners and statuses
returned through [our API](../../../api/graphql/reference/index.md#securityscanners).
If the latest pipeline used [Auto DevOps](../../../topics/autodevops/index.md),
all security features are configured by default.

View File

@ -36,7 +36,7 @@ The following steps will help you get the most from GitLab application security
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).
1. Use [Compliance Pipelines](../../user/project/settings/index.md#compliance-pipeline-configuration)
1. Use [Compliance Pipelines](../group/manage.md#configure-a-compliance-pipeline)
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

View File

@ -446,7 +446,7 @@ Security and compliance teams must ensure that security scans:
GitLab provides two methods of accomplishing this, each with advantages and disadvantages.
- [Compliance framework pipelines](../project/settings/index.md#compliance-pipeline-configuration)
- [Compliance framework pipelines](../group/manage.md#configure-a-compliance-pipeline)
are recommended when:
- Scan execution enforcement is required for any scanner that uses a GitLab template, such as SAST IaC, DAST, Dependency Scanning,

View File

@ -15,7 +15,7 @@ with a long, random job name. In the unlikely event of a job name collision, the
any pre-existing job in the pipeline. If a policy is created at the group-level, it will apply to every child
project or sub-group. A group-level policy cannot be edited from a child project or sub-group.
This feature has some overlap with [compliance framework pipelines](../../project/settings/index.md#compliance-pipeline-configuration),
This feature has some overlap with [compliance framework pipelines](../../group/manage.md#configure-a-compliance-pipeline),
as we have not [unified the user experience for these two features](https://gitlab.com/groups/gitlab-org/-/epics/7312).
For details on the similarities and differences between these features, see
[Enforce scan execution](../index.md#enforce-scan-execution).

View File

@ -72,7 +72,7 @@ The following is a list of violations that are either:
When you select a row, a drawer is shown that provides further details about the merge
request:
- Project name and [compliance framework label](../../project/settings/index.md#compliance-frameworks),
- Project name and [compliance framework label](../../project/settings/index.md#add-a-compliance-framework-to-a-project),
if the project has one assigned.
- Link to the merge request.
- The merge request's branch path in the format `[source] into [target]`.

View File

@ -376,6 +376,186 @@ To enable delayed deletion of projects in a group:
NOTE:
In GitLab 13.11 and above the group setting for delayed project deletion is inherited by subgroups. As discussed in [Cascading settings](../../development/cascading_settings.md) inheritance can be overridden, unless enforced by an ancestor.
## Compliance frameworks **(PREMIUM)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/276221) in GitLab 13.9.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/287779) in GitLab 13.12.
You can create a compliance framework that is a label to identify that your project has certain compliance
requirements or needs additional oversight. The label can optionally enforce
[compliance pipeline configuration](#configure-a-compliance-pipeline) to the projects on which it is
[applied](../project/settings/index.md#add-a-compliance-framework-to-a-project).
Group owners can create, edit, and delete compliance frameworks:
1. On the top bar, select **Main menu > Groups > View all groups** and find your group.
1. On the left sidebar, select **Settings** > **General**.
1. Expand the **Compliance frameworks** section.
1. Create, edit, or delete compliance frameworks.
### Configure a compliance pipeline **(ULTIMATE)**
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3156) in GitLab 13.9, disabled behind `ff_evaluate_group_level_compliance_pipeline` [feature flag](../../administration/feature_flags.md).
> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/300324) in GitLab 13.11.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/331231) in GitLab 14.2.
Group owners can configure a compliance pipeline in a project separate to other projects. By default, the compliance
pipeline configuration (`.gitlab-ci.yml` file) is run instead of the pipeline configuration of labeled projects.
However, the compliance pipeline configuration can reference the `.gitlab-ci.yml` file of the labeled projects so that:
- The compliance pipeline can also run jobs of labeled project pipelines. This allows for centralized control of
pipeline configuration.
- Jobs and variables defined in the compliance pipeline can't be changed by variables in the labeled project's
`.gitlab-ci.yml` file.
See [example configuration](#example-configuration) for help configuring a compliance pipeline that runs jobs from
labeled project pipeline configuration.
To configure a compliance pipeline:
1. On the top bar, select **Main menu > Groups > View all groups** and find your group.
1. On the left sidebar, select **Settings** > **General**.
1. Expand the **Compliance frameworks** section.
1. In **Compliance pipeline configuration (optional)**, add the path to the compliance framework configuration. Use the
`path/file.y[a]ml@group-name/project-name` format. For example:
- `.compliance-ci.yml@gitlab-org/gitlab`.
- `.compliance-ci.yaml@gitlab-org/gitlab`.
This configuration is inherited by projects where the compliance framework label is
[applied](../project/settings/index.md#add-a-compliance-framework-to-a-project). In projects with the applied compliance
framework label, the compliance pipeline configuration is run instead of the labeled project's own pipeline configuration.
The user running the pipeline in the labeled project must at least have the Reporter role on the compliance project.
When used to enforce scan execution, this feature has some overlap with
[scan execution policies](../application_security/policies/scan-execution-policies.md). We have not
[unified the user experience for these two features](https://gitlab.com/groups/gitlab-org/-/epics/7312). For details on
the similarities and differences between these features, see [Enforce scan execution](../application_security/index.md#enforce-scan-execution).
#### Example configuration
The following example `.compliance-gitlab-ci.yml` includes the `include` keyword to ensure labeled project pipeline
configuration is also executed.
```yaml
# Allows compliance team to control the ordering and interweaving of stages/jobs.
# Stages without jobs defined will remain hidden.
stages:
- pre-compliance
- build
- test
- pre-deploy-compliance
- deploy
- post-compliance
variables: # Can be overridden by setting a job-specific variable in project's local .gitlab-ci.yml
FOO: sast
sast: # None of these attributes can be overridden by a project's local .gitlab-ci.yml
variables:
FOO: sast
image: ruby:2.6
stage: pre-compliance
rules:
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"
when: never
- when: always # or when: on_success
allow_failure: false
before_script:
- "# No before scripts."
script:
- echo "running $FOO"
after_script:
- "# No after scripts."
sanity check:
image: ruby:2.6
stage: pre-deploy-compliance
rules:
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"
when: never
- when: always # or when: on_success
allow_failure: false
before_script:
- "# No before scripts."
script:
- echo "running $FOO"
after_script:
- "# No after scripts."
audit trail:
image: ruby:2.7
stage: post-compliance
rules:
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"
when: never
- when: always # or when: on_success
allow_failure: false
before_script:
- "# No before scripts."
script:
- echo "running $FOO"
after_script:
- "# No after scripts."
include: # Execute individual project's configuration (if project contains .gitlab-ci.yml)
project: '$CI_PROJECT_PATH'
file: '$CI_CONFIG_PATH'
ref: '$CI_COMMIT_REF_NAME' # Must be defined or MR pipelines always use the use default branch
```
### Ensure compliance jobs are always run
Compliance pipelines [use GitLab CI/CD](../../ci/index.md) to give you an incredible amount of flexibility
for defining any sort of compliance jobs you like. Depending on your goals, these jobs
can be configured to be:
- Modified by users.
- Non-modifiable.
Generally, if a value in a compliance job:
- Is set, it cannot be changed or overridden by project-level configurations.
- Is not set, a project-level configuration may set.
Either might be wanted or not depending on your use case.
There are a few best practices for ensuring that these jobs are always run exactly
as you define them and that downstream, project-level pipeline configurations
cannot change them:
- Add [a `rules:when:always` block](../../ci/yaml/index.md#when) to each of your compliance jobs. This ensures they are
non-modifiable and are always run.
- Explicitly set any [variables](../../ci/yaml/index.md#variables) the job references. This:
- Ensures that project-level pipeline configurations do not set them and alter their
behavior.
- Includes any jobs that drive the logic of your job.
- Explicitly set the [container image](../../ci/yaml/index.md#image) to run the job in. This ensures that your script
steps execute in the correct environment.
- Explicitly set any relevant GitLab pre-defined [job keywords](../../ci/yaml/index.md#job-keywords).
This ensures that your job uses the settings you intend and that they are not overridden by
project-level pipelines.
### Avoid parent and child pipelines in GitLab 14.7 and earlier
NOTE:
This advice does not apply to GitLab 14.8 and later because [a fix](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78878) added
compatibility for combining compliance pipelines, and parent and child pipelines.
Compliance pipelines start on the run of _every_ pipeline in a labeled project. This means that if a pipeline in the labeled project
triggers a child pipeline, the compliance pipeline runs first. This can trigger the parent pipeline, instead of the child pipeline.
Therefore, in projects with compliance frameworks, we recommend replacing
[parent-child pipelines](../../ci/pipelines/downstream_pipelines.md#parent-child-pipelines) with the following:
- Direct [`include`](../../ci/yaml/index.md#include) statements that provide the parent pipeline with child pipeline configuration.
- Child pipelines placed in another project that are run using the [trigger API](../../ci/triggers/index.md) rather than the parent-child
pipeline feature.
This alternative ensures the compliance pipeline does not re-start the parent pipeline.
## Disable email notifications
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/23585) in GitLab 12.2.
@ -560,9 +740,7 @@ Changes to [group wikis](../project/wiki/group.md) do not appear in group activi
You can view the most recent actions taken in a group, either in your browser or in an RSS feed:
1. On the top bar, select **Main menu > Groups > View all groups**.
1. Select **Your Groups**.
1. Find the group and select it.
1. On the top bar, select **Main menu > Groups > View all groups** and find your group.
1. On the left sidebar, select **Group information > Activity**.
To view the activity feed in Atom format, select the

View File

@ -166,7 +166,7 @@ The following table lists project permissions available for each role:
| [Projects](project/index.md):<br>Rename project | | | | ✓ | ✓ |
| [Projects](project/index.md):<br>Share (invite) projects with groups | | | | ✓ (*7*) | ✓ (*7*) |
| [Projects](project/index.md):<br>View 2FA status of members | | | | ✓ | ✓ |
| [Projects](project/index.md):<br>Assign project to a [compliance framework](project/settings/index.md#compliance-frameworks) | | | | | ✓ |
| [Projects](project/index.md):<br>Assign project to a [compliance framework](project/settings/index.md#add-a-compliance-framework-to-a-project) | | | | | ✓ |
| [Projects](project/index.md):<br>Archive project | | | | | ✓ |
| [Projects](project/index.md):<br>Change project visibility level | | | | | ✓ |
| [Projects](project/index.md):<br>Delete project | | | | | ✓ |

View File

@ -452,11 +452,10 @@ This error occurs in the following scenarios:
[enforce 2FA for all users](../../../security/two_factor_authentication.md#enforce-2fa-for-all-users) setting.
- You do not have 2FA enabled, but an administrator has disabled the
[password authentication enabled for Git over HTTP(S)](../../admin_area/settings/sign_in_restrictions.md#password-authentication-enabled)
setting. If LDAP is:
- Configured, an [LDAP password](../../../administration/auth/ldap/index.md)
or a [personal access token](../personal_access_tokens.md)
must be used to authenticate Git requests over HTTP(S).
- Not configured, you must use a [personal access token](../personal_access_tokens.md).
setting. You can authenticate Git requests:
- Over HTTP(S) using a [personal access token](../personal_access_tokens.md).
- In your browser using [Git Credential Manager](#git-credential-manager).
- If you have configured LDAP, over HTTP(S) using an [LDAP password](../../../administration/auth/ldap/index.md).
### Error: "invalid pin code"

View File

@ -43,187 +43,21 @@ To assign topics to a project:
If you're an instance administrator, you can administer all project topics from the
[Admin Area's Topics page](../../admin_area/index.md#administering-topics).
## Compliance frameworks **(PREMIUM)**
## Add a compliance framework to a project **(PREMIUM)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/276221) in GitLab 13.9.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/287779) in GitLab 13.12.
[Compliance frameworks](../../group/manage.md#compliance-frameworks) can be assigned to projects within group that has a
compliance framework using either:
You can create a compliance framework label to identify that your project has certain compliance
requirements or needs additional oversight. The label can optionally apply
[compliance pipeline configuration](#compliance-pipeline-configuration).
Group owners can create, edit, and delete compliance frameworks:
1. On the top bar, select **Main menu > Groups** and find your group.
1. On the left sidebar, select **Settings** > **General**.
1. Expand the **Compliance frameworks** section.
Compliance frameworks created can then be assigned to projects within the group using:
- The GitLab UI, using the project settings page.
- The GitLab UI:
1. On the top bar, select **Main menu > Projects > View all projects** and find your project.
1. On the left sidebar, select **Settings** > **General**.
1. Expand the **Compliance frameworks** section.
1. Select a compliance framework.
1. Select **Save changes**.
- In [GitLab 14.2](https://gitlab.com/gitlab-org/gitlab/-/issues/333249) and later, using the
[GraphQL API](../../../api/graphql/reference/index.md#mutationprojectsetcomplianceframework).
NOTE:
Creating compliance frameworks on subgroups with GraphQL causes the framework to be
created on the root ancestor if the user has the correct permissions. The GitLab UI presents a
read-only view to discourage this behavior.
### Compliance pipeline configuration **(ULTIMATE)**
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3156) in GitLab 13.9, disabled behind `ff_evaluate_group_level_compliance_pipeline` [feature flag](../../../administration/feature_flags.md).
> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/300324) in GitLab 13.11.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/331231) in GitLab 14.2.
Compliance framework pipelines allow group owners to define
a compliance pipeline in a separate repository that gets
executed in place of the local project's `.gitlab-ci.yml` file. As part of this pipeline, an
`include` statement can reference the local project's `.gitlab-ci.yml` file. This way, the compliance
pipeline jobs can run alongside the project-specific jobs any time the pipeline runs.
Jobs and variables defined in the compliance
pipeline can't be changed by variables in the local project's `.gitlab-ci.yml` file.
When you set up the compliance framework, use the **Compliance pipeline configuration** box to link
the compliance framework to specific CI/CD configuration. Use the
`path/file.y[a]ml@group-name/project-name` format. For example:
- `.compliance-ci.yml@gitlab-org/gitlab`.
- `.compliance-ci.yaml@gitlab-org/gitlab`.
This configuration is inherited by projects where the compliance framework label is applied. The
result forces projects with the label to run the compliance CI/CD configuration in addition to
the project's own CI/CD configuration. When a project with a compliance framework label executes a
pipeline, it evaluates configuration in the following order:
1. Compliance pipeline configuration.
1. Project-specific pipeline configuration.
The user running the pipeline in the project must at least have the Reporter role on the compliance
project.
Example `.compliance-gitlab-ci.yml`:
```yaml
# Allows compliance team to control the ordering and interweaving of stages/jobs.
# Stages without jobs defined will remain hidden.
stages:
- pre-compliance
- build
- test
- pre-deploy-compliance
- deploy
- post-compliance
variables: # Can be overridden by setting a job-specific variable in project's local .gitlab-ci.yml
FOO: sast
sast: # None of these attributes can be overridden by a project's local .gitlab-ci.yml
variables:
FOO: sast
image: ruby:2.6
stage: pre-compliance
rules:
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"
when: never
- when: always # or when: on_success
allow_failure: false
before_script:
- "# No before scripts."
script:
- echo "running $FOO"
after_script:
- "# No after scripts."
sanity check:
image: ruby:2.6
stage: pre-deploy-compliance
rules:
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"
when: never
- when: always # or when: on_success
allow_failure: false
before_script:
- "# No before scripts."
script:
- echo "running $FOO"
after_script:
- "# No after scripts."
audit trail:
image: ruby:2.6
stage: post-compliance
rules:
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"
when: never
- when: always # or when: on_success
allow_failure: false
before_script:
- "# No before scripts."
script:
- echo "running $FOO"
after_script:
- "# No after scripts."
include: # Execute individual project's configuration (if project contains .gitlab-ci.yml)
project: '$CI_PROJECT_PATH'
file: '$CI_CONFIG_PATH'
ref: '$CI_COMMIT_REF_NAME' # Must be defined or MR pipelines always use the use default branch
```
When used to enforce scan execution, this feature has some overlap with [scan execution policies](../../application_security/policies/scan-execution-policies.md),
as we have not [unified the user experience for these two features](https://gitlab.com/groups/gitlab-org/-/epics/7312).
For details on the similarities and differences between these features, see
[Enforce scan execution](../../application_security/index.md#enforce-scan-execution).
### Ensure compliance jobs are always run
Compliance pipelines use GitLab CI/CD to give you an incredible amount of flexibility
for defining any sort of compliance jobs you like. Depending on your goals, these jobs
can be configured to be:
- Modified by users.
- Non-modifiable.
At a high-level, if a value in a compliance job:
- Is set, it cannot be changed or overridden by project-level configurations.
- Is not set, a project-level configuration may set.
Either might be wanted or not depending on your use case.
There are a few best practices for ensuring that these jobs are always run exactly
as you define them and that downstream, project-level pipeline configurations
cannot change them:
- Add a `rules:when:always` block to each of your compliance jobs. This ensures they are
non-modifiable and are always run.
- Explicitly set any variables the job references. This:
- Ensures that project-level pipeline configurations do not set them and alter their
behavior.
- Includes any jobs that drive the logic of your job.
- Explicitly set the container image file to run the job in. This ensures that your script
steps execute in the correct environment.
- Explicitly set any relevant GitLab pre-defined [job keywords](../../../ci/yaml/index.md#job-keywords).
This ensures that your job uses the settings you intend and that they are not overridden by
project-level pipelines.
### Avoid parent and child pipelines in GitLab 14.7 and earlier
NOTE:
This advice does not apply to GitLab 14.8 and later because [a fix](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78878) added
compatibility for combining compliance pipelines, and parent and child pipelines.
Compliance pipelines start on the run of _every_ pipeline in a relevant project. This means that if a pipeline in the relevant project
triggers a child pipeline, the compliance pipeline runs first. This can trigger the parent pipeline, instead of the child pipeline.
Therefore, in projects with compliance frameworks, we recommend replacing
[parent-child pipelines](../../../ci/pipelines/downstream_pipelines.md#parent-child-pipelines) with the following:
- Direct [`include`](../../../ci/yaml/index.md#include) statements that provide the parent pipeline with child pipeline configuration.
- Child pipelines placed in another project that are run using the [trigger API](../../../ci/triggers/index.md) rather than the parent-child
pipeline feature.
This alternative ensures the compliance pipeline does not re-start the parent pipeline.
[GraphQL API](../../../api/graphql/reference/index.md#mutationprojectsetcomplianceframework). If you create
compliance frameworks on subgroups with GraphQL, the framework is created on the root ancestor if the user has the
correct permissions. The GitLab UI presents a read-only view to discourage this behavior.
## Configure project visibility, features, and permissions

View File

@ -26,30 +26,32 @@ Storage types that add to the total namespace storage are:
- Wiki
- Snippets
If your total namespace storage exceeds the available namespace storage quota, all projects under the namespace are locked. A locked project will not be able to push to the repository, run pipelines and jobs, or build and push packages.
If your total namespace storage exceeds the available namespace storage quota, all projects under the namespace are locked.
A locked project cannot push to the repository, run pipelines and jobs, or build and push packages.
To prevent exceeding the namespace storage quota, you can:
1. Reduce storage consumption by following the suggestions in the [Manage Your Storage Usage](#manage-your-storage-usage) section of this page.
1. Apply for [GitLab for Education](https://about.gitlab.com/solutions/education/join/), [GitLab for Open Source](https://about.gitlab.com/solutions/open-source/join/), or [GitLab for Startups](https://about.gitlab.com/solutions/startups/) if you meet the eligibility requirements.
1. Consider using a [self-managed instance](../subscriptions/self_managed/index.md) of GitLab which does not have these limits on the free tier.
1. [Purchase additional storage](../subscriptions/gitlab_com/index.md#purchase-more-storage-and-transfer) units at $60/year for 10GB of storage.
1. [Start a trial](https://about.gitlab.com/free-trial/) or [upgrade to GitLab Premium or Ultimate](https://about.gitlab.com/pricing) which include higher limits and features that enable growing teams to ship faster without sacrificing on quality.
1. [Talk to an expert](https://page.gitlab.com/usage_limits_help.html) to learn more about your options and ask questions.
- Reduce storage consumption by following the suggestions in the [Manage Your Storage Usage](#manage-your-storage-usage) section of this page.
- Apply for [GitLab for Education](https://about.gitlab.com/solutions/education/join/), [GitLab for Open Source](https://about.gitlab.com/solutions/open-source/join/), or [GitLab for Startups](https://about.gitlab.com/solutions/startups/) if you meet the eligibility requirements.
- Consider using a [self-managed instance](../subscriptions/self_managed/index.md) of GitLab which does not have these limits on the free tier.
- [Purchase additional storage](../subscriptions/gitlab_com/index.md#purchase-more-storage-and-transfer) units at $60/year for 10GB of storage.
- [Start a trial](https://about.gitlab.com/free-trial/) or [upgrade to GitLab Premium or Ultimate](https://about.gitlab.com/pricing) which include higher limits and features that enable growing teams to ship faster without sacrificing on quality.
- [Talk to an expert](https://page.gitlab.com/usage_limits_help.html) to learn more about your options and ask questions.
### Namespace storage limit enforcement schedule
Storage limits for GitLab SaaS Free tier namespaces will not be enforced prior to 2022-10-19. Storage limits for GitLab SaaS Paid tier namespaces will not be enforced for prior to 2023-02-15. Enforcement will not occur until all storage types are accurately measured, including deduplication of forks for [Git](https://gitlab.com/gitlab-org/gitlab/-/issues/371671) and [LFS](https://gitlab.com/gitlab-org/gitlab/-/issues/370242).
Impacted users are notified via email and in-app notifications at least 60 days prior to enforcement.
Impacted users are notified by email and through in-app notifications at least 60 days prior to enforcement.
### Project storage limit
Projects on GitLab SaaS have a 10GB storage limit on their Git repository and LFS storage.
Once namespace-level storage limits are enforced, the project limit will be removed. A namespace has either a namespace-level storage limit or a project-level storage limit, but not both.
After namespace-level storage limits are enforced, the project limit is removed. A namespace has either a namespace-level storage limit or a project-level storage limit, but not both.
When a project's repository and LFS reaches the quota, the project is locked. You cannot push changes to a locked project. To monitor the size of each
repository in a namespace, including a breakdown for each project, you can
When a project's repository and LFS reaches the quota, the project is locked.
You cannot push changes to a locked project. To monitor the size of each
repository in a namespace, including a breakdown for each project,
[view storage usage](#view-storage-usage). To allow a project's repository and LFS to exceed the free quota
you must purchase additional storage. For more details, see [Excess storage usage](#excess-storage-usage).
@ -66,7 +68,7 @@ Prerequisites:
1. From the left sidebar, select **Settings > Usage Quotas**.
1. Select the **Storage** tab.
The statistics are displayed. Select any title to view details. The information on this page
Select any title to view details. The information on this page
is updated every 90 minutes.
If your namespace shows `'Not applicable.'`, push a commit to any project in the

View File

@ -0,0 +1,24 @@
# frozen_string_literal: true
module Gitlab
module BackgroundMigration
# The `ci_pipeline_artifacts.locked` column was added in
# https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97194 to
# speed up the finding of expired, pipeline artifacts. By default,
# the value is "unknown" (2), but the correct value should be the
# value of the associated `ci_pipelines.locked` value. This class
# does an UPDATE join to make the values match.
class UpdateCiPipelineArtifactsUnknownLockedStatus < BatchedMigrationJob
def perform
connection.exec_query(<<~SQL)
UPDATE ci_pipeline_artifacts
SET locked = ci_pipelines.locked
FROM ci_pipelines
WHERE ci_pipeline_artifacts.id BETWEEN #{start_id} AND #{end_id}
AND ci_pipeline_artifacts.locked = 2
AND ci_pipelines.id = ci_pipeline_artifacts.pipeline_id;
SQL
end
end
end
end

View File

@ -9847,7 +9847,7 @@ msgstr ""
msgid "ComplianceFrameworks|No compliance frameworks are set up yet"
msgstr ""
msgid "ComplianceFrameworks|Required format: %{codeStart}path/file.y[a]ml@group-name/project-name%{codeEnd}. %{linkStart}Learn more.%{linkEnd}"
msgid "ComplianceFrameworks|Required format: %{codeStart}path/file.y[a]ml@group-name/project-name%{codeEnd}. %{linkStart}What is a compliance pipeline configuration?%{linkEnd}"
msgstr ""
msgid "ComplianceFrameworks|Unable to save this compliance framework. Please try again"
@ -19041,7 +19041,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}Learn more.%{linkEnd}"
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
msgstr ""
msgid "GroupSettings|Configure limits on the number of repositories users can download in a given time."

View File

@ -18,9 +18,10 @@ module QA
/Dockerfile\.assets/
)
def initialize(mr_diff, mr_labels)
def initialize(mr_diff, mr_labels, additional_group_spec_list)
@mr_diff = mr_diff
@mr_labels = mr_labels
@additional_group_spec_list = additional_group_spec_list
end
# Specific specs to run
@ -80,6 +81,9 @@ module QA
# @return [Array]
attr_reader :mr_labels
# @return [Hash<String, Array<String>>]
attr_reader :additional_group_spec_list
# Are the changed files only qa specs?
#
# @return [Boolean] whether the changes files are only qa specs
@ -101,6 +105,13 @@ module QA
mr_labels.find { |label| label =~ /^devops::/ }&.delete_prefix('devops::')
end
# Extract group name from MR labels
#
# @return [String] a group name
def group_name_from_mr_labels
mr_labels.find { |label| label =~ /^group::/ }&.delete_prefix('group::')
end
# Get qa spec directories for devops stage
#
# @return [Array] qa spec directories
@ -108,7 +119,15 @@ module QA
devops_stage = devops_stage_from_mr_labels
return unless devops_stage
Dir.glob("qa/specs/**/*/").select { |dir| dir =~ %r{\d+_#{devops_stage}/$} }
spec_dirs = stage_specs(devops_stage)
grp_name = group_name_from_mr_labels
return spec_dirs if grp_name.nil?
additional_grp_specs = additional_group_spec_list[grp_name]
return spec_dirs if additional_grp_specs.nil?
spec_dirs + stage_specs(*additional_grp_specs)
end
# Changes to gitlab dependencies
@ -122,7 +141,15 @@ module QA
#
# @return [Array<String>]
def changed_files
@changed_files ||= mr_diff.map { |change| change[:path] } # rubocop:disable Rails/Pluck
@changed_files ||= mr_diff.map { |change| change[:path] }
end
# Devops stage specs
#
# @param [Array<String>] devops_stages
# @return [Array]
def stage_specs(*devops_stages)
Dir.glob("qa/specs/**/*/").select { |dir| dir =~ %r{\d+_(#{devops_stages.join('|')})/$} }
end
end
end

View File

@ -1,9 +1,10 @@
# frozen_string_literal: true
RSpec.describe QA::Tools::Ci::QaChanges do
subject(:qa_changes) { described_class.new(mr_diff, mr_labels) }
subject(:qa_changes) { described_class.new(mr_diff, mr_labels, additional_group_spec_list) }
let(:mr_labels) { [] }
let(:additional_group_spec_list) { [] }
before do
allow(File).to receive(:directory?).and_return(false)
@ -75,6 +76,43 @@ RSpec.describe QA::Tools::Ci::QaChanges do
)
end
end
context "when configured to run tests from other stages" do
let(:additional_group_spec_list) do
{
'foo' => %w[create],
'bar' => %w[monitor verify]
}
end
context "with a single extra stage configured for the group name" do
let(:mr_labels) { %w[devops::manage group::foo] }
it ".qa_tests return specs for both devops stage and create stage" do
expect(qa_changes.qa_tests.split(" ")).to include(
"qa/specs/features/browser_ui/1_manage/",
"qa/specs/features/api/1_manage/",
"qa/specs/features/browser_ui/3_create/",
"qa/specs/features/api/3_create/"
)
end
end
context "with a multiple extra stages configured for the group name" do
let(:mr_labels) { %w[devops::manage group::bar] }
it ".qa_tests return specs for both devops stage and multiple other stages" do
expect(qa_changes.qa_tests.split(" ")).to include(
"qa/specs/features/browser_ui/1_manage/",
"qa/specs/features/api/1_manage/",
"qa/specs/features/browser_ui/8_monitor/",
"qa/specs/features/api/8_monitor/",
"qa/specs/features/browser_ui/4_verify/",
"qa/specs/features/api/4_verify/"
)
end
end
end
end
context "with quarantine changes" do

View File

@ -13,8 +13,10 @@ namespace :ci do
diff = mr_diff
labels = mr_labels
# Assign mapping of groups to tests in stages other than the groups defined stage
additional_group_spec_list = { 'gitaly' => %w[create] }
qa_changes = QA::Tools::Ci::QaChanges.new(diff, labels)
qa_changes = QA::Tools::Ci::QaChanges.new(diff, labels, additional_group_spec_list)
logger = qa_changes.logger
logger.info("Analyzing merge request changes")

View File

@ -8,9 +8,11 @@ RSpec.describe Groups::RunnersController do
let_it_be(:project) { create(:project, group: group) }
let!(:runner) { create(:ci_runner, :group, groups: [group]) }
let!(:runner_project) { create(:ci_runner, :project, projects: [project]) }
let!(:project_runner) { create(:ci_runner, :project, projects: [project]) }
let!(:instance_runner) { create(:ci_runner, :instance) }
let(:params_runner_project) { { group_id: group, id: runner_project } }
let(:params_runner_project) { { group_id: group, id: project_runner } }
let(:params_runner_instance) { { group_id: group, id: instance_runner } }
let(:params) { { group_id: group, id: runner } }
before do
@ -70,8 +72,33 @@ RSpec.describe Groups::RunnersController do
expect(response).to render_template(:show)
end
context 'when runners_finder_all_available is enabled' do
before do
stub_feature_flags(runners_finder_all_available: true)
end
it 'renders show with 200 status code instance runner' do
get :show, params: { group_id: group, id: instance_runner }
expect(response).to have_gitlab_http_status(:ok)
expect(response).to render_template(:show)
end
end
context 'when runners_finder_all_available is disabled' do
before do
stub_feature_flags(runners_finder_all_available: false)
end
it 'renders show with a 404 instance runner' do
get :show, params: { group_id: group, id: instance_runner }
expect(response).to have_gitlab_http_status(:not_found)
end
end
it 'renders show with 200 status code project runner' do
get :show, params: { group_id: group, id: runner_project }
get :show, params: { group_id: group, id: project_runner }
expect(response).to have_gitlab_http_status(:ok)
expect(response).to render_template(:show)
@ -89,8 +116,14 @@ RSpec.describe Groups::RunnersController do
expect(response).to have_gitlab_http_status(:not_found)
end
it 'renders a 404 instance runner' do
get :show, params: { group_id: group, id: instance_runner }
expect(response).to have_gitlab_http_status(:not_found)
end
it 'renders a 404 project runner' do
get :show, params: { group_id: group, id: runner_project }
get :show, params: { group_id: group, id: project_runner }
expect(response).to have_gitlab_http_status(:not_found)
end
@ -103,15 +136,21 @@ RSpec.describe Groups::RunnersController do
group.add_owner(user)
end
it 'renders show with 200 status code' do
it 'renders edit with 200 status code' do
get :edit, params: { group_id: group, id: runner }
expect(response).to have_gitlab_http_status(:ok)
expect(response).to render_template(:edit)
end
it 'renders show with 200 status code project runner' do
get :edit, params: { group_id: group, id: runner_project }
it 'renders a 404 instance runner' do
get :edit, params: { group_id: group, id: instance_runner }
expect(response).to have_gitlab_http_status(:not_found)
end
it 'renders edit with 200 status code project runner' do
get :edit, params: { group_id: group, id: project_runner }
expect(response).to have_gitlab_http_status(:ok)
expect(response).to render_template(:edit)
@ -130,7 +169,7 @@ RSpec.describe Groups::RunnersController do
end
it 'renders a 404 project runner' do
get :edit, params: { group_id: group, id: runner_project }
get :edit, params: { group_id: group, id: project_runner }
expect(response).to have_gitlab_http_status(:not_found)
end
@ -154,15 +193,26 @@ RSpec.describe Groups::RunnersController do
expect(runner.reload.description).to eq(new_desc)
end
it 'does not update the instance runner' do
new_desc = instance_runner.description.swapcase
expect do
post :update, params: params_runner_instance.merge(runner: { description: new_desc } )
end.to not_change { instance_runner.ensure_runner_queue_value }
.and not_change { instance_runner.description }
expect(response).to have_gitlab_http_status(:not_found)
end
it 'updates the project runner, ticks the queue, and redirects project runner' do
new_desc = runner_project.description.swapcase
new_desc = project_runner.description.swapcase
expect do
post :update, params: params_runner_project.merge(runner: { description: new_desc } )
end.to change { runner_project.ensure_runner_queue_value }
end.to change { project_runner.ensure_runner_queue_value }
expect(response).to have_gitlab_http_status(:found)
expect(runner_project.reload.description).to eq(new_desc)
expect(project_runner.reload.description).to eq(new_desc)
end
end
@ -182,15 +232,26 @@ RSpec.describe Groups::RunnersController do
expect(runner.reload.description).to eq(old_desc)
end
it 'rejects the update and responds 404 instance runner' do
old_desc = instance_runner.description
expect do
post :update, params: params_runner_instance.merge(runner: { description: old_desc.swapcase } )
end.not_to change { instance_runner.ensure_runner_queue_value }
expect(response).to have_gitlab_http_status(:not_found)
expect(instance_runner.reload.description).to eq(old_desc)
end
it 'rejects the update and responds 404 project runner' do
old_desc = runner_project.description
old_desc = project_runner.description
expect do
post :update, params: params_runner_project.merge(runner: { description: old_desc.swapcase } )
end.not_to change { runner_project.ensure_runner_queue_value }
end.not_to change { project_runner.ensure_runner_queue_value }
expect(response).to have_gitlab_http_status(:not_found)
expect(runner_project.reload.description).to eq(old_desc)
expect(project_runner.reload.description).to eq(old_desc)
end
end
end

View File

@ -3,5 +3,9 @@
FactoryBot.define do
factory :ci_build_metadata, class: 'Ci::BuildMetadata' do
build { association(:ci_build, strategy: :build, metadata: instance) }
after(:build) do |metadata|
metadata.build&.valid?
end
end
end

View File

@ -424,79 +424,79 @@ FactoryBot.define do
trait :codequality_report do
after(:build) do |build|
build.job_artifacts << create(:ci_job_artifact, :codequality, job: build)
build.job_artifacts << build(:ci_job_artifact, :codequality, job: build)
end
end
trait :sast_report do
after(:build) do |build|
build.job_artifacts << create(:ci_job_artifact, :sast, job: build)
build.job_artifacts << build(:ci_job_artifact, :sast, job: build)
end
end
trait :secret_detection_report do
after(:build) do |build|
build.job_artifacts << create(:ci_job_artifact, :secret_detection, job: build)
build.job_artifacts << build(:ci_job_artifact, :secret_detection, job: build)
end
end
trait :test_reports do
after(:build) do |build|
build.job_artifacts << create(:ci_job_artifact, :junit, job: build)
build.job_artifacts << build(:ci_job_artifact, :junit, job: build)
end
end
trait :test_reports_with_attachment do
after(:build) do |build|
build.job_artifacts << create(:ci_job_artifact, :junit_with_attachment, job: build)
build.job_artifacts << build(:ci_job_artifact, :junit_with_attachment, job: build)
end
end
trait :broken_test_reports do
after(:build) do |build|
build.job_artifacts << create(:ci_job_artifact, :junit_with_corrupted_data, job: build)
build.job_artifacts << build(:ci_job_artifact, :junit_with_corrupted_data, job: build)
end
end
trait :test_reports_with_duplicate_failed_test_names do
after(:build) do |build|
build.job_artifacts << create(:ci_job_artifact, :junit_with_duplicate_failed_test_names, job: build)
build.job_artifacts << build(:ci_job_artifact, :junit_with_duplicate_failed_test_names, job: build)
end
end
trait :test_reports_with_three_failures do
after(:build) do |build|
build.job_artifacts << create(:ci_job_artifact, :junit_with_three_failures, job: build)
build.job_artifacts << build(:ci_job_artifact, :junit_with_three_failures, job: build)
end
end
trait :accessibility_reports do
after(:build) do |build|
build.job_artifacts << create(:ci_job_artifact, :accessibility, job: build)
build.job_artifacts << build(:ci_job_artifact, :accessibility, job: build)
end
end
trait :coverage_reports do
after(:build) do |build|
build.job_artifacts << create(:ci_job_artifact, :cobertura, job: build)
build.job_artifacts << build(:ci_job_artifact, :cobertura, job: build)
end
end
trait :codequality_reports do
after(:build) do |build|
build.job_artifacts << create(:ci_job_artifact, :codequality, job: build)
build.job_artifacts << build(:ci_job_artifact, :codequality, job: build)
end
end
trait :codequality_reports_without_degradation do
after(:build) do |build|
build.job_artifacts << create(:ci_job_artifact, :codequality_without_errors, job: build)
build.job_artifacts << build(:ci_job_artifact, :codequality_without_errors, job: build)
end
end
trait :terraform_reports do
after(:build) do |build|
build.job_artifacts << create(:ci_job_artifact, :terraform, job: build)
build.job_artifacts << build(:ci_job_artifact, :terraform, job: build)
end
end

View File

@ -8,6 +8,7 @@ FactoryBot.define do
sha { 'b83d6e391c22777fca1ed3012fce84f633d7fed0' }
status { 'pending' }
add_attribute(:protected) { false }
partition_id { 1234 }
project
@ -53,6 +54,7 @@ FactoryBot.define do
end
factory :ci_pipeline do
partition_id { 1234 }
transient { ci_ref_presence { true } }
before(:create) do |pipeline, evaluator|

View File

@ -3,29 +3,100 @@
require 'spec_helper'
RSpec.describe "User creates milestone", :js do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:developer) { create(:user) }
let_it_be(:inherited_guest) { create(:user) }
let_it_be(:inherited_developer) { create(:user) }
let_it_be(:group) { create(:group, :public) }
shared_examples 'creates milestone' do
specify do
title = "v2.3"
fill_in("Title", with: title)
fill_in("Description", with: "# Description header")
click_button("Create milestone")
expect(page).to have_content(title)
.and have_content("Issues")
.and have_header_with_correct_id_and_link(1, "Description header", "description-header")
visit(activity_project_path(project))
expect(page).to have_content("#{user.name} #{user.to_reference} opened milestone")
end
end
shared_examples 'renders not found' do
specify do
expect(page).to have_title('Not Found')
expect(page).to have_content('Page Not Found')
end
end
before_all do
group.add_guest(inherited_guest)
group.add_developer(inherited_developer)
end
before do
project.add_developer(user)
sign_in(user)
visit(new_project_milestone_path(project))
end
it "creates milestone" do
title = "v2.3"
context 'when project is public' do
let_it_be(:project) { create(:project, :public, group: group) }
fill_in("Title", with: title)
fill_in("Description", with: "# Description header")
click_button("Create milestone")
context 'and issues and merge requests are private' do
before_all do
project.project_feature.update!(
issues_access_level: ProjectFeature::PRIVATE,
merge_requests_access_level: ProjectFeature::PRIVATE
)
end
expect(page).to have_content(title)
.and have_content("Issues")
.and have_header_with_correct_id_and_link(1, "Description header", "description-header")
context 'when user is an inherited member from the group' do
context 'and user is a guest' do
let(:user) { inherited_guest }
visit(activity_project_path(project))
it_behaves_like 'renders not found'
end
expect(page).to have_content("#{user.name} #{user.to_reference} opened milestone")
context 'and user is a developer' do
let(:user) { inherited_developer }
it_behaves_like 'creates milestone'
end
end
end
end
context 'when project is private' do
let_it_be(:project) { create(:project, :private, group: group) }
context 'and user is a direct project member' do
before_all do
project.add_developer(developer)
end
context 'when user is a developer' do
let(:user) { developer }
it_behaves_like 'creates milestone'
end
end
context 'and user is an inherited member from the group' do
context 'when user is a guest' do
let(:user) { inherited_guest }
it_behaves_like 'renders not found'
end
context 'when user is a developer' do
let(:user) { inherited_developer }
it_behaves_like 'creates milestone'
end
end
end
end

View File

@ -285,6 +285,13 @@ describe('Flash', () => {
expect(document.querySelector('.gl-alert')).toBeNull();
});
it('does not crash if calling .dismiss() twice', () => {
alert = createAlert({ message: mockMessage });
alert.dismiss();
expect(() => alert.dismiss()).not.toThrow();
});
it('calls onDismiss when dismissed', () => {
const dismissHandler = jest.fn();

View File

@ -10,6 +10,7 @@ RSpec.describe GitlabSchema.types['BranchRule'] do
let(:fields) do
%i[
name
isDefault
branch_protection
created_at
updated_at

View File

@ -0,0 +1,62 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::BackgroundMigration::UpdateCiPipelineArtifactsUnknownLockedStatus do
describe '#perform' do
let(:batch_table) { :ci_pipeline_artifacts }
let(:batch_column) { :id }
let(:sub_batch_size) { 1 }
let(:pause_ms) { 0 }
let(:connection) { Ci::ApplicationRecord.connection }
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:pipelines) { table(:ci_pipelines, database: :ci) }
let(:pipeline_artifacts) { table(:ci_pipeline_artifacts, database: :ci) }
let(:namespace) { namespaces.create!(name: 'name', path: 'path') }
let(:project) do
projects
.create!(name: "project", path: "project", namespace_id: namespace.id, project_namespace_id: namespace.id)
end
let(:unlocked) { 0 }
let(:locked) { 1 }
let(:unknown) { 2 }
let(:unlocked_pipeline) { pipelines.create!(locked: unlocked) }
let(:locked_pipeline) { pipelines.create!(locked: locked) }
# rubocop:disable Layout/LineLength
let!(:locked_artifact) { pipeline_artifacts.create!(project_id: project.id, pipeline_id: locked_pipeline.id, size: 1024, file_type: 0, file_format: 'gzip', file: 'a.gz', locked: unknown) }
let!(:unlocked_artifact_1) { pipeline_artifacts.create!(project_id: project.id, pipeline_id: unlocked_pipeline.id, size: 2048, file_type: 1, file_format: 'raw', file: 'b', locked: unknown) }
let!(:unlocked_artifact_2) { pipeline_artifacts.create!(project_id: project.id, pipeline_id: unlocked_pipeline.id, size: 4096, file_type: 2, file_format: 'gzip', file: 'c.gz', locked: unknown) }
let!(:already_unlocked_artifact) { pipeline_artifacts.create!(project_id: project.id, pipeline_id: unlocked_pipeline.id, size: 8192, file_type: 3, file_format: 'raw', file: 'd', locked: unlocked) }
let!(:already_locked_artifact) { pipeline_artifacts.create!(project_id: project.id, pipeline_id: locked_pipeline.id, size: 8192, file_type: 3, file_format: 'raw', file: 'd', locked: locked) }
# rubocop:enable Layout/LineLength
subject do
described_class.new(
start_id: locked_artifact.id,
end_id: already_locked_artifact.id,
batch_table: batch_table,
batch_column: batch_column,
sub_batch_size: sub_batch_size,
pause_ms: pause_ms,
connection: connection
).perform
end
it 'updates ci_pipeline_artifacts with unknown lock status' do
subject
expect(locked_artifact.reload.locked).to eq(locked)
expect(unlocked_artifact_1.reload.locked).to eq(unlocked)
expect(unlocked_artifact_2.reload.locked).to eq(unlocked)
expect(already_unlocked_artifact.reload.locked).to eq(unlocked)
expect(already_locked_artifact.reload.locked).to eq(locked)
end
end
end

View File

@ -0,0 +1,31 @@
# frozen_string_literal: true
require 'spec_helper'
require_migration!
RSpec.describe ScheduleUpdateCiPipelineArtifactsLockedStatus, migration: :gitlab_ci do
let_it_be(:migration) { described_class::MIGRATION }
describe '#up' do
it 'schedules background jobs for each batch of ci_pipeline_artifacts' do
migrate!
expect(migration).to have_scheduled_batched_migration(
gitlab_schema: :gitlab_ci,
table_name: :ci_pipeline_artifacts,
column_name: :id,
batch_size: described_class::BATCH_SIZE,
sub_batch_size: described_class::SUB_BATCH_SIZE
)
end
end
describe '#down' do
it 'deletes all batched migration records' do
migrate!
schema_migrate_down!
expect(migration).not_to have_scheduled_batched_migration
end
end
end

View File

@ -14,8 +14,8 @@ RSpec.describe Ci::BuildMetadata do
status: 'success')
end
let(:build) { create(:ci_build, pipeline: pipeline) }
let(:metadata) { build.metadata }
let(:job) { create(:ci_build, pipeline: pipeline) }
let(:metadata) { job.metadata }
it_behaves_like 'having unique enum values'
@ -35,7 +35,7 @@ RSpec.describe Ci::BuildMetadata do
context 'when project timeout is set' do
context 'when runner is assigned to the job' do
before do
build.update!(runner: runner)
job.update!(runner: runner)
end
context 'when runner timeout is not set' do
@ -59,13 +59,13 @@ RSpec.describe Ci::BuildMetadata do
context 'when job timeout is set' do
context 'when job timeout is higher than project timeout' do
let(:build) { create(:ci_build, pipeline: pipeline, options: { job_timeout: 3000 }) }
let(:job) { create(:ci_build, pipeline: pipeline, options: { job_timeout: 3000 }) }
it_behaves_like 'sets timeout', 'job_timeout_source', 3000
end
context 'when job timeout is lower than project timeout' do
let(:build) { create(:ci_build, pipeline: pipeline, options: { job_timeout: 1000 }) }
let(:job) { create(:ci_build, pipeline: pipeline, options: { job_timeout: 1000 }) }
it_behaves_like 'sets timeout', 'job_timeout_source', 1000
end
@ -73,18 +73,18 @@ RSpec.describe Ci::BuildMetadata do
context 'when both runner and job timeouts are set' do
before do
build.update!(runner: runner)
job.update!(runner: runner)
end
context 'when job timeout is higher than runner timeout' do
let(:build) { create(:ci_build, pipeline: pipeline, options: { job_timeout: 3000 }) }
let(:job) { create(:ci_build, pipeline: pipeline, options: { job_timeout: 3000 }) }
let(:runner) { create(:ci_runner, maximum_timeout: 2100) }
it_behaves_like 'sets timeout', 'runner_timeout_source', 2100
end
context 'when job timeout is lower than runner timeout' do
let(:build) { create(:ci_build, pipeline: pipeline, options: { job_timeout: 1900 }) }
let(:job) { create(:ci_build, pipeline: pipeline, options: { job_timeout: 1900 }) }
let(:runner) { create(:ci_runner, maximum_timeout: 2100) }
it_behaves_like 'sets timeout', 'job_timeout_source', 1900
@ -135,20 +135,51 @@ RSpec.describe Ci::BuildMetadata do
describe 'set_cancel_gracefully' do
it 'sets cancel_gracefully' do
build.set_cancel_gracefully
job.set_cancel_gracefully
expect(build.cancel_gracefully?).to be true
expect(job.cancel_gracefully?).to be true
end
it 'returns false' do
expect(build.cancel_gracefully?).to be false
expect(job.cancel_gracefully?).to be false
end
end
context 'loose foreign key on ci_builds_metadata.project_id' do
it_behaves_like 'cleanup by a loose foreign key' do
let!(:parent) { create(:project) }
let!(:model) { create(:ci_build_metadata, project: parent) }
let!(:parent) { project }
let!(:model) { metadata }
end
end
describe 'partitioning' do
context 'with job' do
let(:status) { build(:commit_status, partition_id: 123) }
let(:metadata) { build(:ci_build_metadata, build: status) }
it 'copies the partition_id from job' do
expect { metadata.valid? }.to change(metadata, :partition_id).to(123)
end
context 'when it is already set' do
let(:metadata) { build(:ci_build_metadata, build: status, partition_id: 125) }
it 'does not change the partition_id value' do
expect { metadata.valid? }.not_to change(metadata, :partition_id)
end
end
end
context 'without job' do
subject(:metadata) do
build(:ci_build_metadata, build: nil)
end
it { is_expected.to validate_presence_of(:partition_id) }
it 'does not change the partition_id value' do
expect { metadata.valid? }.not_to change(metadata, :partition_id)
end
end
end
end

View File

@ -320,10 +320,10 @@ RSpec.describe Ci::Build do
let(:artifact_scope) { Ci::JobArtifact.where(file_type: 'archive') }
let!(:build_1) { create(:ci_build, :artifacts) }
let!(:build_2) { create(:ci_build, :codequality_reports) }
let!(:build_3) { create(:ci_build, :test_reports) }
let!(:build_4) { create(:ci_build, :artifacts) }
let!(:build_1) { create(:ci_build, :artifacts, pipeline: pipeline) }
let!(:build_2) { create(:ci_build, :codequality_reports, pipeline: pipeline) }
let!(:build_3) { create(:ci_build, :test_reports, pipeline: pipeline) }
let!(:build_4) { create(:ci_build, :artifacts, pipeline: pipeline) }
it 'returns artifacts matching the given scope' do
expect(builds).to contain_exactly(build_1, build_4)

View File

@ -5488,7 +5488,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe 'partitioning' do
let(:pipeline) { build(:ci_pipeline) }
let(:pipeline) { build(:ci_pipeline, partition_id: nil) }
before do
allow(described_class).to receive(:current_partition_value) { 123 }

View File

@ -0,0 +1,26 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Ci::Partitionable do
describe 'partitionable models inclusion' do
let(:ci_model) { Class.new(Ci::ApplicationRecord) }
subject { ci_model.include(described_class) }
it 'raises an exception' do
expect { subject }
.to raise_error(/must be included in PARTITIONABLE_MODELS/)
end
context 'when is included in the models list' do
before do
stub_const("#{described_class}::Testing::PARTITIONABLE_MODELS", [ci_model.name])
end
it 'does not raise exceptions' do
expect { subject }.not_to raise_error
end
end
end
end

View File

@ -435,4 +435,28 @@ RSpec.describe ProtectedBranch do
expect(described_class.downcase_humanized_name).to eq 'protected branch'
end
end
describe '.default_branch?' do
before do
allow(subject.project).to receive(:default_branch).and_return(branch)
end
context 'when the name matches the default branch' do
let(:branch) { subject.name }
it { is_expected.to be_default_branch }
end
context 'when the name does not match the default branch' do
let(:branch) { "#{subject.name}qwerty" }
it { is_expected.not_to be_default_branch }
end
context 'when a wildcard name matches the default branch' do
let(:branch) { "#{subject.name}*" }
it { is_expected.not_to be_default_branch }
end
end
end

View File

@ -21,27 +21,24 @@ RSpec.describe 'getting list of branch rules for a project' do
let(:branch_rules_data) { graphql_data_at('project', 'branchRules', 'edges') }
let(:variables) { { path: project.full_path } }
let(:fields) do
<<~QUERY
pageInfo {
hasNextPage
hasPreviousPage
}
edges {
cursor
node {
#{all_graphql_fields_for('branch_rules'.classify)}
}
}
QUERY
end
# fields must use let as the all_graphql_fields_for also configures some spies
let(:fields) { all_graphql_fields_for('BranchRule') }
let(:query) do
<<~GQL
query($path: ID!, $n: Int, $cursor: String) {
project(fullPath: $path) {
branchRules(first: $n, after: $cursor) { #{fields} }
branchRules(first: $n, after: $cursor) {
pageInfo {
hasNextPage
hasPreviousPage
}
edges {
cursor
node {
#{fields}
}
}
}
}
}
GQL
@ -55,7 +52,9 @@ RSpec.describe 'getting list of branch rules for a project' do
it_behaves_like 'a working graphql query'
it { expect(branch_rules_data).to be_empty }
it 'hides branch rules data' do
expect(branch_rules_data).to be_empty
end
end
context 'when the user does have read_protected_branch abilities' do
@ -66,12 +65,17 @@ RSpec.describe 'getting list of branch rules for a project' do
it_behaves_like 'a working graphql query'
it 'includes a name' do
it 'returns branch rules data' do
expect(branch_rules_data.dig(0, 'node', 'name')).to be_present
end
it 'includes created_at and updated_at' do
expect(branch_rules_data.dig(0, 'node', 'isDefault')).to be(true).or be(false)
expect(branch_rules_data.dig(0, 'node', 'branchProtection')).to be_present
expect(branch_rules_data.dig(0, 'node', 'createdAt')).to be_present
expect(branch_rules_data.dig(0, 'node', 'updatedAt')).to be_present
expect(branch_rules_data.dig(1, 'node', 'name')).to be_present
expect(branch_rules_data.dig(1, 'node', 'isDefault')).to be(true).or be(false)
expect(branch_rules_data.dig(1, 'node', 'branchProtection')).to be_present
expect(branch_rules_data.dig(1, 'node', 'createdAt')).to be_present
expect(branch_rules_data.dig(1, 'node', 'updatedAt')).to be_present
end
@ -82,16 +86,16 @@ RSpec.describe 'getting list of branch rules for a project' do
{ path: project.full_path, n: branch_rule_limit, cursor: last_cursor }
end
it_behaves_like 'a working graphql query' do
it 'only returns N branch_rules' do
expect(branch_rules_data.size).to eq(branch_rule_limit)
expect(has_next_page).to be_truthy
expect(has_prev_page).to be_falsey
post_graphql(query, current_user: current_user, variables: next_variables)
expect(branch_rules_data.size).to eq(branch_rule_limit)
expect(has_next_page).to be_falsey
expect(has_prev_page).to be_truthy
end
it_behaves_like 'a working graphql query'
it 'returns pagination information' do
expect(branch_rules_data.size).to eq(branch_rule_limit)
expect(has_next_page).to be_truthy
expect(has_prev_page).to be_falsey
post_graphql(query, current_user: current_user, variables: next_variables)
expect(branch_rules_data.size).to eq(branch_rule_limit)
expect(has_next_page).to be_falsey
expect(has_prev_page).to be_truthy
end
context 'when no limit is provided' do

View File

@ -182,7 +182,8 @@ RSpec.describe Ci::JobArtifacts::CreateService do
end
context 'with job partitioning' do
let(:job) { create(:ci_build, project: project, partition_id: 123) }
let(:pipeline) { create(:ci_pipeline, project: project, partition_id: 123) }
let(:job) { create(:ci_build, pipeline: pipeline) }
it 'sets partition_id on artifacts' do
expect { subject }.to change { Ci::JobArtifact.count }

View File

@ -62,5 +62,25 @@ RSpec.describe Packages::Rpm::RepositoryMetadata::BuildRepomdXml do
end
end
end
context 'when data values has unexpected keys' do
let(:data) do
{
filelists: described_class::ALLOWED_DATA_VALUE_KEYS.each_with_object({}) do |key, result|
result[:"#{key}-wrong"] = { value: 'value' }
end
}
end
it 'ignores wrong keys' do
result = Nokogiri::XML::Document.parse(subject).remove_namespaces!
data.each do |tag_name, tag_attributes|
tag_attributes.each_key do |key|
expect(result.at("//repomd/data[@type=\"#{tag_name}\"]/#{key}")).to be_nil
end
end
end
end
end
end

View File

@ -0,0 +1,46 @@
# frozen_string_literal: true
module PartitioningTesting
module CascadeCheck
extend ActiveSupport::Concern
included do
after_create :check_partition_cascade_value
end
def check_partition_cascade_value
raise 'Partition value not found' unless partition_scope_value
raise 'Default value detected' if partition_id == 100
return if partition_id == partition_scope_value
raise "partition_id was expected to equal #{partition_scope_value} but it was #{partition_id}."
end
end
module DefaultPartitionValue
extend ActiveSupport::Concern
class_methods do
def current_partition_value
current = super
if current == 100
54321
else
current
end
end
end
end
end
Ci::Partitionable::Testing::PARTITIONABLE_MODELS.each do |klass|
model = klass.safe_constantize
if klass == 'Ci::Pipeline'
model.prepend(PartitioningTesting::DefaultPartitionValue)
else
model.include(PartitioningTesting::CascadeCheck)
end
end

View File

@ -11,6 +11,7 @@ RSpec.describe 'registrations/welcome/show' do
allow(view).to receive(:in_trial_flow?).and_return(false)
allow(view).to receive(:user_has_memberships?).and_return(false)
allow(view).to receive(:in_oauth_flow?).and_return(false)
allow(view).to receive(:glm_tracking_params).and_return({})
render
end