Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
459939f27f
commit
f0809fbc2c
1
Gemfile
1
Gemfile
|
|
@ -341,7 +341,6 @@ group :development do
|
|||
|
||||
# Better errors handler
|
||||
gem 'better_errors', '~> 2.7.1'
|
||||
gem 'binding_of_caller', '~> 0.8.0'
|
||||
|
||||
# thin instead webrick
|
||||
gem 'thin', '~> 1.7.0'
|
||||
|
|
|
|||
|
|
@ -135,8 +135,6 @@ GEM
|
|||
rack (>= 0.9.0)
|
||||
bindata (2.4.3)
|
||||
binding_ninja (0.2.3)
|
||||
binding_of_caller (0.8.0)
|
||||
debug_inspector (>= 0.0.1)
|
||||
bootsnap (1.4.6)
|
||||
msgpack (~> 1.0)
|
||||
bootstrap_form (4.2.0)
|
||||
|
|
@ -218,7 +216,6 @@ GEM
|
|||
octokit (~> 4.7)
|
||||
terminal-table (~> 1)
|
||||
database_cleaner (1.7.0)
|
||||
debug_inspector (0.0.3)
|
||||
debugger-ruby_core_source (1.3.8)
|
||||
deckar01-task_list (2.3.1)
|
||||
html-pipeline
|
||||
|
|
@ -1263,7 +1260,6 @@ DEPENDENCIES
|
|||
benchmark-ips (~> 2.3.0)
|
||||
benchmark-memory (~> 0.1)
|
||||
better_errors (~> 2.7.1)
|
||||
binding_of_caller (~> 0.8.0)
|
||||
bootsnap (~> 1.4.6)
|
||||
bootstrap_form (~> 4.2.0)
|
||||
brakeman (~> 4.2)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
/* Wait for.... The methods can be used:
|
||||
- with a callback (preferred),
|
||||
waitFor(action)
|
||||
|
||||
- with then (discouraged),
|
||||
await waitFor().then(action);
|
||||
|
||||
- with await,
|
||||
await waitFor;
|
||||
action();
|
||||
*/
|
||||
|
||||
const CSS_LOADED_EVENT = 'CSSLoaded';
|
||||
const DOM_LOADED_EVENT = 'DOMContentLoaded';
|
||||
const STARTUP_LINK_LOADED_EVENT = 'CSSStartupLinkLoaded';
|
||||
|
||||
const isStartupLinkLoaded = ({ dataset }) => dataset.startupcss === 'loaded';
|
||||
|
||||
export const handleLoadedEvents = (action = () => {}) => {
|
||||
let isCssLoaded = false;
|
||||
let eventsList = [CSS_LOADED_EVENT, DOM_LOADED_EVENT];
|
||||
return ({ type } = {}) => {
|
||||
eventsList = eventsList.filter(e => e !== type);
|
||||
if (isCssLoaded) {
|
||||
return;
|
||||
}
|
||||
if (!eventsList.length) {
|
||||
isCssLoaded = true;
|
||||
action();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export const handleStartupEvents = (action = () => {}) => {
|
||||
if (!gon.features.startupCss) {
|
||||
return action;
|
||||
}
|
||||
const startupLinks = Array.from(document.querySelectorAll('link[data-startupcss]'));
|
||||
return () => {
|
||||
if (startupLinks.every(isStartupLinkLoaded)) {
|
||||
action();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export const waitForStartupLinks = () => {
|
||||
let eventListener;
|
||||
const promise = new Promise(resolve => {
|
||||
eventListener = handleStartupEvents(resolve);
|
||||
document.addEventListener(STARTUP_LINK_LOADED_EVENT, eventListener);
|
||||
}).then(() => {
|
||||
document.dispatchEvent(new CustomEvent(CSS_LOADED_EVENT));
|
||||
document.removeEventListener(STARTUP_LINK_LOADED_EVENT, eventListener);
|
||||
});
|
||||
document.dispatchEvent(new CustomEvent(STARTUP_LINK_LOADED_EVENT));
|
||||
return promise;
|
||||
};
|
||||
|
||||
export const waitForCSSLoaded = (action = () => {}) => {
|
||||
let eventListener;
|
||||
const promise = new Promise(resolve => {
|
||||
eventListener = handleLoadedEvents(resolve);
|
||||
document.addEventListener(DOM_LOADED_EVENT, eventListener, { once: true });
|
||||
document.addEventListener(CSS_LOADED_EVENT, eventListener, { once: true });
|
||||
}).then(action);
|
||||
waitForStartupLinks();
|
||||
return promise;
|
||||
};
|
||||
|
|
@ -1,18 +1,17 @@
|
|||
import Vue from 'vue';
|
||||
import { GlColumnChart } from '@gitlab/ui/dist/charts';
|
||||
import { waitForCSSLoaded } from '../../../../helpers/startup_css_helper';
|
||||
import { __ } from '~/locale';
|
||||
import CodeCoverage from '../components/code_coverage.vue';
|
||||
import SeriesDataMixin from './series_data_mixin';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
waitForCSSLoaded(() => {
|
||||
const languagesContainer = document.getElementById('js-languages-chart');
|
||||
const codeCoverageContainer = document.getElementById('js-code-coverage-chart');
|
||||
const monthContainer = document.getElementById('js-month-chart');
|
||||
const weekdayContainer = document.getElementById('js-weekday-chart');
|
||||
const hourContainer = document.getElementById('js-hour-chart');
|
||||
|
||||
const LANGUAGE_CHART_HEIGHT = 300;
|
||||
|
||||
const reorderWeekDays = (weekDays, firstDayOfWeek = 0) => {
|
||||
if (firstDayOfWeek === 0) {
|
||||
return weekDays;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ module AuthenticatesWithTwoFactor
|
|||
return handle_locked_user(user) unless user.can?(:log_in)
|
||||
|
||||
session[:otp_user_id] = user.id
|
||||
session[:user_updated_at] = user.updated_at
|
||||
session[:user_password_hash] = Digest::SHA256.hexdigest(user.encrypted_password)
|
||||
push_frontend_feature_flag(:webauthn)
|
||||
|
||||
if user.two_factor_webauthn_enabled?
|
||||
|
|
@ -47,7 +47,7 @@ module AuthenticatesWithTwoFactor
|
|||
def authenticate_with_two_factor
|
||||
user = self.resource = find_user
|
||||
return handle_locked_user(user) unless user.can?(:log_in)
|
||||
return handle_changed_user(user) if user_changed?(user)
|
||||
return handle_changed_user(user) if user_password_changed?(user)
|
||||
|
||||
if user_params[:otp_attempt].present? && session[:otp_user_id]
|
||||
authenticate_with_two_factor_via_otp(user)
|
||||
|
|
@ -76,7 +76,7 @@ module AuthenticatesWithTwoFactor
|
|||
|
||||
def clear_two_factor_attempt!
|
||||
session.delete(:otp_user_id)
|
||||
session.delete(:user_updated_at)
|
||||
session.delete(:user_password_hash)
|
||||
session.delete(:challenge)
|
||||
end
|
||||
|
||||
|
|
@ -142,7 +142,6 @@ module AuthenticatesWithTwoFactor
|
|||
gon.push(webauthn: { options: get_options.to_json })
|
||||
end
|
||||
end
|
||||
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
def handle_two_factor_success(user)
|
||||
|
|
@ -168,13 +167,9 @@ module AuthenticatesWithTwoFactor
|
|||
|
||||
# If user has been updated since we validated the password,
|
||||
# the password might have changed.
|
||||
def user_changed?(user)
|
||||
return false unless session[:user_updated_at]
|
||||
def user_password_changed?(user)
|
||||
return false unless session[:user_password_hash]
|
||||
|
||||
# See: https://gitlab.com/gitlab-org/gitlab/-/issues/244638
|
||||
# Rounding errors happen when the user is updated, as the Rails ActiveRecord
|
||||
# object has higher precision than what is stored in the database, therefore
|
||||
# using .to_i to force truncation to the timestamp
|
||||
user.updated_at.to_i != session[:user_updated_at].to_i
|
||||
Digest::SHA256.hexdigest(user.encrypted_password) != session[:user_password_hash]
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ require 'digest/md5'
|
|||
require 'uri'
|
||||
|
||||
module ApplicationHelper
|
||||
include StartupCssHelper
|
||||
|
||||
# See https://docs.gitlab.com/ee/development/ee_features.html#code-in-app-views
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def render_if_exists(partial, locals = {})
|
||||
|
|
@ -235,10 +237,6 @@ module ApplicationHelper
|
|||
"#{request.path}?#{options.compact.to_param}"
|
||||
end
|
||||
|
||||
def use_startup_css?
|
||||
(Feature.enabled?(:startup_css) || params[:startup_css] == 'true' || cookies['startup_css'] == 'true') && !Rails.env.test?
|
||||
end
|
||||
|
||||
def stylesheet_link_tag_defer(path)
|
||||
if use_startup_css?
|
||||
stylesheet_link_tag(path, media: "print", crossorigin: ActionController::Base.asset_host ? 'anonymous' : nil)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module StartupCssHelper
|
||||
def use_startup_css?
|
||||
(Feature.enabled?(:startup_css) || params[:startup_css] == 'true' || cookies['startup_css'] == 'true') && !Rails.env.test?
|
||||
end
|
||||
end
|
||||
|
|
@ -203,7 +203,7 @@ class CommitStatus < ApplicationRecord
|
|||
common_name = name.to_s.gsub(%r{\d+[\s:\/\\]+\d+\s*}, '')
|
||||
|
||||
# 'rspec:linux: [aws, max memory]' => 'rspec:linux'
|
||||
common_name.gsub!(%r{: \[.*, .*\]\s*\z}, '') if Gitlab::Ci::Features.new_matrix_job_names_enabled?
|
||||
common_name.gsub!(%r{: \[.*, .*\]\s*\z}, '')
|
||||
|
||||
common_name.strip!
|
||||
common_name
|
||||
|
|
|
|||
|
|
@ -896,12 +896,12 @@ class Project < ApplicationRecord
|
|||
end
|
||||
|
||||
def repository
|
||||
@repository ||= Repository.new(full_path, self, shard: repository_storage, disk_path: disk_path)
|
||||
@repository ||= Gitlab::GlRepository::PROJECT.repository_for(self)
|
||||
end
|
||||
|
||||
def design_repository
|
||||
strong_memoize(:design_repository) do
|
||||
DesignManagement::Repository.new(self)
|
||||
Gitlab::GlRepository::DESIGN.repository_for(self)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -275,7 +275,7 @@ class Snippet < ApplicationRecord
|
|||
|
||||
override :repository
|
||||
def repository
|
||||
@repository ||= Repository.new(full_path, self, shard: repository_storage, disk_path: disk_path, repo_type: Gitlab::GlRepository::SNIPPET)
|
||||
@repository ||= Gitlab::GlRepository::SNIPPET.repository_for(self)
|
||||
end
|
||||
|
||||
override :repository_size_checker
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ class Wiki
|
|||
|
||||
override :repository
|
||||
def repository
|
||||
@repository ||= Repository.new(full_path, container, shard: repository_storage, disk_path: disk_path, repo_type: Gitlab::GlRepository::WIKI)
|
||||
@repository ||= Gitlab::GlRepository::WIKI.repository_for(container)
|
||||
end
|
||||
|
||||
def repository_storage
|
||||
|
|
|
|||
|
|
@ -3,5 +3,8 @@
|
|||
= javascript_tag nonce: true do
|
||||
:plain
|
||||
document.querySelectorAll('link[media="print"]').forEach(linkTag => {
|
||||
linkTag.addEventListener('load', function() {this.media='all'}, {once: true});
|
||||
linkTag.setAttribute('data-startupcss', 'loading');
|
||||
const startupLinkLoadedEvent = new CustomEvent('CSSStartupLinkLoaded');
|
||||
linkTag.addEventListener('load',function(){this.media='all';this.setAttribute('data-startupcss', 'loaded');document.dispatchEvent(startupLinkLoadedEvent);},{once: true});
|
||||
})
|
||||
- return unless use_startup_css?
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add target_id column to audit_events table
|
||||
merge_request: 40954
|
||||
author:
|
||||
type: other
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Initialise charts when container display property is set
|
||||
merge_request: 40787
|
||||
author:
|
||||
type: fixed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Change 2FA to verify password hash instead of timestamp
|
||||
merge_request: 41366
|
||||
author:
|
||||
type: changed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Convert spec_helper to fast_spec_helper
|
||||
merge_request: 41755
|
||||
author: gaga5lala
|
||||
type: other
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Parallel matrix jobs show relevant variables in job name
|
||||
merge_request: 41080
|
||||
author:
|
||||
type: added
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
name: ci_matrix_job_names
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39985
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/239012
|
||||
group: 'group::continuous integration'
|
||||
type: development
|
||||
default_enabled: false
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddTargetIdToAuditEvents < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::SchemaHelpers
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
DOWNTIME = false
|
||||
SOURCE_TABLE_NAME = 'audit_events'
|
||||
PARTITIONED_TABLE_NAME = 'audit_events_part_5fc467ac26'
|
||||
TRIGGER_FUNCTION_NAME = 'table_sync_function_2be879775d'
|
||||
|
||||
def up
|
||||
with_lock_retries do
|
||||
add_column(SOURCE_TABLE_NAME, :target_id, :bigint)
|
||||
add_column(PARTITIONED_TABLE_NAME, :target_id, :bigint)
|
||||
|
||||
create_trigger_function(TRIGGER_FUNCTION_NAME, replace: true) do
|
||||
<<~SQL
|
||||
IF (TG_OP = 'DELETE') THEN
|
||||
DELETE FROM #{PARTITIONED_TABLE_NAME} where id = OLD.id;
|
||||
ELSIF (TG_OP = 'UPDATE') THEN
|
||||
UPDATE #{PARTITIONED_TABLE_NAME}
|
||||
SET author_id = NEW.author_id,
|
||||
type = NEW.type,
|
||||
entity_id = NEW.entity_id,
|
||||
entity_type = NEW.entity_type,
|
||||
details = NEW.details,
|
||||
ip_address = NEW.ip_address,
|
||||
author_name = NEW.author_name,
|
||||
entity_path = NEW.entity_path,
|
||||
target_details = NEW.target_details,
|
||||
target_type = NEW.target_type,
|
||||
target_id = NEW.target_id,
|
||||
created_at = NEW.created_at
|
||||
WHERE #{PARTITIONED_TABLE_NAME}.id = NEW.id;
|
||||
ELSIF (TG_OP = 'INSERT') THEN
|
||||
INSERT INTO #{PARTITIONED_TABLE_NAME} (id,
|
||||
author_id,
|
||||
type,
|
||||
entity_id,
|
||||
entity_type,
|
||||
details,
|
||||
ip_address,
|
||||
author_name,
|
||||
entity_path,
|
||||
target_details,
|
||||
target_type,
|
||||
target_id,
|
||||
created_at)
|
||||
VALUES (NEW.id,
|
||||
NEW.author_id,
|
||||
NEW.type,
|
||||
NEW.entity_id,
|
||||
NEW.entity_type,
|
||||
NEW.details,
|
||||
NEW.ip_address,
|
||||
NEW.author_name,
|
||||
NEW.entity_path,
|
||||
NEW.target_details,
|
||||
NEW.target_type,
|
||||
NEW.target_id,
|
||||
NEW.created_at);
|
||||
END IF;
|
||||
RETURN NULL;
|
||||
SQL
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
with_lock_retries do
|
||||
remove_column SOURCE_TABLE_NAME, :target_id
|
||||
|
||||
create_trigger_function(TRIGGER_FUNCTION_NAME, replace: true) do
|
||||
<<~SQL
|
||||
IF (TG_OP = 'DELETE') THEN
|
||||
DELETE FROM #{PARTITIONED_TABLE_NAME} where id = OLD.id;
|
||||
ELSIF (TG_OP = 'UPDATE') THEN
|
||||
UPDATE #{PARTITIONED_TABLE_NAME}
|
||||
SET author_id = NEW.author_id,
|
||||
type = NEW.type,
|
||||
entity_id = NEW.entity_id,
|
||||
entity_type = NEW.entity_type,
|
||||
details = NEW.details,
|
||||
ip_address = NEW.ip_address,
|
||||
author_name = NEW.author_name,
|
||||
entity_path = NEW.entity_path,
|
||||
target_details = NEW.target_details,
|
||||
target_type = NEW.target_type,
|
||||
created_at = NEW.created_at
|
||||
WHERE #{PARTITIONED_TABLE_NAME}.id = NEW.id;
|
||||
ELSIF (TG_OP = 'INSERT') THEN
|
||||
INSERT INTO #{PARTITIONED_TABLE_NAME} (id,
|
||||
author_id,
|
||||
type,
|
||||
entity_id,
|
||||
entity_type,
|
||||
details,
|
||||
ip_address,
|
||||
author_name,
|
||||
entity_path,
|
||||
target_details,
|
||||
target_type,
|
||||
created_at)
|
||||
VALUES (NEW.id,
|
||||
NEW.author_id,
|
||||
NEW.type,
|
||||
NEW.entity_id,
|
||||
NEW.entity_type,
|
||||
NEW.details,
|
||||
NEW.ip_address,
|
||||
NEW.author_name,
|
||||
NEW.entity_path,
|
||||
NEW.target_details,
|
||||
NEW.target_type,
|
||||
NEW.created_at);
|
||||
END IF;
|
||||
RETURN NULL;
|
||||
SQL
|
||||
end
|
||||
|
||||
remove_column PARTITIONED_TABLE_NAME, :target_id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
19c90689d0af6adb017dbd7127c6cd147d9c92581118dbfd99c87bc6a6dda3be
|
||||
|
|
@ -30,6 +30,7 @@ ELSIF (TG_OP = 'UPDATE') THEN
|
|||
entity_path = NEW.entity_path,
|
||||
target_details = NEW.target_details,
|
||||
target_type = NEW.target_type,
|
||||
target_id = NEW.target_id,
|
||||
created_at = NEW.created_at
|
||||
WHERE audit_events_part_5fc467ac26.id = NEW.id;
|
||||
ELSIF (TG_OP = 'INSERT') THEN
|
||||
|
|
@ -44,6 +45,7 @@ ELSIF (TG_OP = 'INSERT') THEN
|
|||
entity_path,
|
||||
target_details,
|
||||
target_type,
|
||||
target_id,
|
||||
created_at)
|
||||
VALUES (NEW.id,
|
||||
NEW.author_id,
|
||||
|
|
@ -56,6 +58,7 @@ ELSIF (TG_OP = 'INSERT') THEN
|
|||
NEW.entity_path,
|
||||
NEW.target_details,
|
||||
NEW.target_type,
|
||||
NEW.target_id,
|
||||
NEW.created_at);
|
||||
END IF;
|
||||
RETURN NULL;
|
||||
|
|
@ -78,6 +81,7 @@ CREATE TABLE public.audit_events_part_5fc467ac26 (
|
|||
target_details text,
|
||||
created_at timestamp without time zone NOT NULL,
|
||||
target_type text,
|
||||
target_id bigint,
|
||||
CONSTRAINT check_492aaa021d CHECK ((char_length(entity_path) <= 5500)),
|
||||
CONSTRAINT check_83ff8406e2 CHECK ((char_length(author_name) <= 255)),
|
||||
CONSTRAINT check_97a8c868e7 CHECK ((char_length(target_type) <= 255)),
|
||||
|
|
@ -9518,6 +9522,7 @@ CREATE TABLE public.audit_events (
|
|||
entity_path text,
|
||||
target_details text,
|
||||
target_type text,
|
||||
target_id bigint,
|
||||
CONSTRAINT check_492aaa021d CHECK ((char_length(entity_path) <= 5500)),
|
||||
CONSTRAINT check_82294106dd CHECK ((char_length(target_type) <= 255)),
|
||||
CONSTRAINT check_83ff8406e2 CHECK ((char_length(author_name) <= 255)),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
---
|
||||
stage: Manage
|
||||
group: Compliance
|
||||
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
|
||||
description: 'Learn how to create evidence artifacts typically requested by a 3rd party auditor.'
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -3594,18 +3594,20 @@ deploystacks:
|
|||
This generates 10 parallel `deploystacks` jobs, each with different values for `PROVIDER` and `STACK`:
|
||||
|
||||
```plaintext
|
||||
deploystacks 1/10 with PROVIDER=aws and STACK=monitoring
|
||||
deploystacks 2/10 with PROVIDER=aws and STACK=app1
|
||||
deploystacks 3/10 with PROVIDER=aws and STACK=app2
|
||||
deploystacks 4/10 with PROVIDER=ovh and STACK=monitoring
|
||||
deploystacks 5/10 with PROVIDER=ovh and STACK=backup
|
||||
deploystacks 6/10 with PROVIDER=ovh and STACK=app
|
||||
deploystacks 7/10 with PROVIDER=gcp and STACK=data
|
||||
deploystacks 8/10 with PROVIDER=gcp and STACK=processing
|
||||
deploystacks 9/10 with PROVIDER=vultr and STACK=data
|
||||
deploystacks 10/10 with PROVIDER=vultr and STACK=processing
|
||||
deploystacks: [aws, monitoring]
|
||||
deploystacks: [aws, app1]
|
||||
deploystacks: [aws, app2]
|
||||
deploystacks: [ovh, monitoring]
|
||||
deploystacks: [ovh, backup]
|
||||
deploystacks: [ovh, app]
|
||||
deploystacks: [gcp, data]
|
||||
deploystacks: [gcp, processing]
|
||||
deploystacks: [vultr, data]
|
||||
deploystacks: [vultr, processing]
|
||||
```
|
||||
|
||||
Job naming style [was improved](https://gitlab.com/gitlab-org/gitlab/-/issues/230452) in GitLab 13.4.
|
||||
|
||||
### `trigger`
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/8997) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.8.
|
||||
|
|
|
|||
|
|
@ -265,10 +265,16 @@ This documentation gives an overview of the report JSON format,
|
|||
as well as recommendations and examples to help integrators set its fields.
|
||||
The format is extensively described in the documentation of
|
||||
[SAST](../../user/application_security/sast/index.md#reports-json-format),
|
||||
[DAST](../../user/application_security/dast/#reports),
|
||||
[Dependency Scanning](../../user/application_security/dependency_scanning/index.md#reports-json-format),
|
||||
and [Container Scanning](../../user/application_security/container_scanning/index.md#reports-json-format).
|
||||
|
||||
The DAST variant of the report JSON format is not documented at the moment.
|
||||
You can find the schemas for these scanners here:
|
||||
|
||||
- [SAST](https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/blob/master/dist/sast-report-format.json)
|
||||
- [DAST](https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/blob/master/dist/dast-report-format.json)
|
||||
- [Dependency Scanning](https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/blob/master/dist/dependency-scanning-report-format.json)
|
||||
- [Container Scanning](https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/blob/master/dist/container-scanning-report-format.json)
|
||||
|
||||
### Version
|
||||
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ module Backup
|
|||
private
|
||||
|
||||
def dump_consecutive
|
||||
Project.includes(:route).find_each(batch_size: 1000) do |project|
|
||||
Project.includes(:route, :group, namespace: :owner).find_each(batch_size: 1000) do |project|
|
||||
dump_project(project)
|
||||
end
|
||||
end
|
||||
|
|
@ -178,7 +178,7 @@ module Backup
|
|||
end
|
||||
end
|
||||
|
||||
Project.for_repository_storage(storage).includes(:route).find_each(batch_size: 100) do |project|
|
||||
Project.for_repository_storage(storage).includes(:route, :group, namespace: :owner).find_each(batch_size: 100) do |project|
|
||||
break unless errors.empty?
|
||||
|
||||
queue.push(project)
|
||||
|
|
|
|||
|
|
@ -49,16 +49,6 @@ module Gitlab
|
|||
end
|
||||
|
||||
def name
|
||||
if Gitlab::Ci::Features.new_matrix_job_names_enabled?
|
||||
name_with_variable_details
|
||||
else
|
||||
old_name
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def name_with_variable_details
|
||||
vars = variables
|
||||
.values
|
||||
.compact
|
||||
|
|
@ -67,9 +57,7 @@ module Gitlab
|
|||
"#{job_name}: [#{vars}]"
|
||||
end
|
||||
|
||||
def old_name
|
||||
"#{job_name} #{instance}/#{total}"
|
||||
end
|
||||
private
|
||||
|
||||
attr_reader :job_name, :instance, :variables, :total
|
||||
end
|
||||
|
|
|
|||
|
|
@ -67,10 +67,6 @@ module Gitlab
|
|||
Feature.enabled?(:project_transactionless_destroy, project, default_enabled: false)
|
||||
end
|
||||
|
||||
def self.new_matrix_job_names_enabled?
|
||||
::Feature.enabled?(:ci_matrix_job_names, default_enabled: false)
|
||||
end
|
||||
|
||||
def self.coverage_report_view?(project)
|
||||
::Feature.enabled?(:coverage_report_view, project)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,19 +7,19 @@ module Gitlab
|
|||
PROJECT = RepoType.new(
|
||||
name: :project,
|
||||
access_checker_class: Gitlab::GitAccessProject,
|
||||
repository_resolver: -> (project) { project&.repository }
|
||||
repository_resolver: -> (project) { ::Repository.new(project.full_path, project, shard: project.repository_storage, disk_path: project.disk_path) }
|
||||
).freeze
|
||||
WIKI = RepoType.new(
|
||||
name: :wiki,
|
||||
access_checker_class: Gitlab::GitAccessWiki,
|
||||
repository_resolver: -> (container) { container&.wiki&.repository },
|
||||
repository_resolver: -> (container) { ::Repository.new(container.wiki.full_path, container, shard: container.wiki.repository_storage, disk_path: container.wiki.disk_path, repo_type: WIKI) },
|
||||
project_resolver: -> (container) { container.is_a?(Project) ? container : nil },
|
||||
suffix: :wiki
|
||||
).freeze
|
||||
SNIPPET = RepoType.new(
|
||||
name: :snippet,
|
||||
access_checker_class: Gitlab::GitAccessSnippet,
|
||||
repository_resolver: -> (snippet) { snippet&.repository },
|
||||
repository_resolver: -> (snippet) { ::Repository.new(snippet.full_path, snippet, shard: snippet.repository_storage, disk_path: snippet.disk_path, repo_type: SNIPPET) },
|
||||
container_class: Snippet,
|
||||
project_resolver: -> (snippet) { snippet&.project },
|
||||
guest_read_ability: :read_snippet
|
||||
|
|
|
|||
|
|
@ -57,6 +57,8 @@ module Gitlab
|
|||
end
|
||||
|
||||
def repository_for(container)
|
||||
return unless container
|
||||
|
||||
repository_resolver.call(container)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
module Gitlab
|
||||
module GonHelper
|
||||
include StartupCssHelper
|
||||
include WebpackHelper
|
||||
|
||||
def add_gon_variables
|
||||
|
|
@ -48,6 +49,9 @@ module Gitlab
|
|||
push_frontend_feature_flag(:snippets_edit_vue, default_enabled: false)
|
||||
push_frontend_feature_flag(:webperf_experiment, default_enabled: false)
|
||||
push_frontend_feature_flag(:snippets_binary_blob, default_enabled: false)
|
||||
|
||||
# Startup CSS feature is a special one as it can be enabled by means of cookies and params
|
||||
gon.push({ features: { 'startupCss' => use_startup_css? } }, true)
|
||||
end
|
||||
|
||||
# Exposes the state of a feature flag to the frontend code.
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ RSpec.describe 'Database schema' do
|
|||
approvals: %w[user_id],
|
||||
approver_groups: %w[target_id],
|
||||
approvers: %w[target_id user_id],
|
||||
audit_events: %w[author_id entity_id],
|
||||
audit_events_part_5fc467ac26: %w[author_id entity_id],
|
||||
audit_events: %w[author_id entity_id target_id],
|
||||
audit_events_part_5fc467ac26: %w[author_id entity_id target_id],
|
||||
award_emoji: %w[awardable_id user_id],
|
||||
aws_roles: %w[role_external_id],
|
||||
boards: %w[milestone_id],
|
||||
|
|
|
|||
|
|
@ -0,0 +1,123 @@
|
|||
import {
|
||||
handleLoadedEvents,
|
||||
waitForCSSLoaded,
|
||||
} from '../../../app/assets/javascripts/helpers/startup_css_helper';
|
||||
|
||||
describe('handleLoadedEvents', () => {
|
||||
let mock;
|
||||
beforeEach(() => {
|
||||
mock = jest.fn();
|
||||
});
|
||||
|
||||
it('should not call the callback on wrong conditions', () => {
|
||||
const resolverToCall = handleLoadedEvents(mock);
|
||||
resolverToCall({ type: 'UnrelatedEvent' });
|
||||
resolverToCall({ type: 'UnrelatedEvent' });
|
||||
resolverToCall({ type: 'UnrelatedEvent' });
|
||||
resolverToCall({ type: 'UnrelatedEvent' });
|
||||
resolverToCall({ type: 'CSSLoaded' });
|
||||
resolverToCall();
|
||||
expect(mock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call the callback when all the events have been triggered', () => {
|
||||
const resolverToCall = handleLoadedEvents(mock);
|
||||
resolverToCall();
|
||||
resolverToCall({ type: 'DOMContentLoaded' });
|
||||
resolverToCall({ type: 'CSSLoaded' });
|
||||
resolverToCall();
|
||||
expect(mock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('waitForCSSLoaded', () => {
|
||||
let mock;
|
||||
beforeEach(() => {
|
||||
mock = jest.fn();
|
||||
});
|
||||
|
||||
describe('with startup css disabled', () => {
|
||||
beforeEach(() => {
|
||||
gon.features = {
|
||||
startupCss: false,
|
||||
};
|
||||
});
|
||||
|
||||
it('should call CssLoaded when the conditions are met', async () => {
|
||||
const docAddListener = jest.spyOn(document, 'addEventListener');
|
||||
const docRemoveListener = jest.spyOn(document, 'removeEventListener');
|
||||
const docDispatch = jest.spyOn(document, 'dispatchEvent');
|
||||
const events = waitForCSSLoaded(mock);
|
||||
|
||||
expect(docAddListener).toHaveBeenCalledTimes(3);
|
||||
expect(docDispatch.mock.calls[0][0].type).toBe('CSSStartupLinkLoaded');
|
||||
|
||||
document.dispatchEvent(new CustomEvent('DOMContentLoaded'));
|
||||
await events;
|
||||
|
||||
expect(docDispatch).toHaveBeenCalledTimes(3);
|
||||
expect(docDispatch.mock.calls[2][0].type).toBe('CSSLoaded');
|
||||
expect(docRemoveListener).toHaveBeenCalledTimes(1);
|
||||
expect(mock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with startup css enabled', () => {
|
||||
let docAddListener;
|
||||
let docRemoveListener;
|
||||
let docDispatch;
|
||||
|
||||
beforeEach(() => {
|
||||
docAddListener = jest.spyOn(document, 'addEventListener');
|
||||
docRemoveListener = jest.spyOn(document, 'removeEventListener');
|
||||
docDispatch = jest.spyOn(document, 'dispatchEvent');
|
||||
gon.features = {
|
||||
startupCss: true,
|
||||
};
|
||||
});
|
||||
|
||||
it('should call CssLoaded if the assets are cached', async () => {
|
||||
const events = waitForCSSLoaded(mock);
|
||||
const fixtures = `
|
||||
<link href="one.css" data-startupcss="loaded">
|
||||
<link href="two.css" data-startupcss="loaded">
|
||||
`;
|
||||
setFixtures(fixtures);
|
||||
|
||||
expect(docAddListener).toHaveBeenCalledTimes(3);
|
||||
expect(docDispatch.mock.calls[0][0].type).toBe('CSSStartupLinkLoaded');
|
||||
|
||||
document.dispatchEvent(new CustomEvent('DOMContentLoaded'));
|
||||
await events;
|
||||
|
||||
expect(docDispatch).toHaveBeenCalledTimes(3);
|
||||
expect(docDispatch.mock.calls[2][0].type).toBe('CSSLoaded');
|
||||
expect(docRemoveListener).toHaveBeenCalledTimes(1);
|
||||
expect(mock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should wait to call CssLoaded until the assets are loaded', async () => {
|
||||
const events = waitForCSSLoaded(mock);
|
||||
const fixtures = `
|
||||
<link href="one.css" data-startupcss="loading">
|
||||
<link href="two.css" data-startupcss="loading">
|
||||
`;
|
||||
setFixtures(fixtures);
|
||||
|
||||
expect(docAddListener).toHaveBeenCalledTimes(3);
|
||||
expect(docDispatch.mock.calls[0][0].type).toBe('CSSStartupLinkLoaded');
|
||||
|
||||
document
|
||||
.querySelectorAll('[data-startupcss="loading"]')
|
||||
.forEach(elem => elem.setAttribute('data-startupcss', 'loaded'));
|
||||
document.dispatchEvent(new CustomEvent('DOMContentLoaded'));
|
||||
document.dispatchEvent(new CustomEvent('CSSStartupLinkLoaded'));
|
||||
await events;
|
||||
|
||||
expect(docDispatch).toHaveBeenCalledTimes(4);
|
||||
expect(docDispatch.mock.calls[3][0].type).toBe('CSSLoaded');
|
||||
expect(docRemoveListener).toHaveBeenCalledTimes(1);
|
||||
expect(mock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require 'fast_spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Ci::Config::Normalizer::MatrixStrategy do
|
||||
describe '.applies_to?' do
|
||||
|
|
@ -39,114 +39,53 @@ RSpec.describe Gitlab::Ci::Config::Normalizer::MatrixStrategy do
|
|||
|
||||
it { expect(subject.size).to eq(4) }
|
||||
|
||||
context 'with new_matrix_job_names_enabled ff disabled' do
|
||||
before do
|
||||
stub_feature_flags(ci_matrix_job_names: false)
|
||||
end
|
||||
|
||||
it 'has attributes' do
|
||||
expect(subject.map(&:attributes)).to match_array(
|
||||
[
|
||||
{
|
||||
name: 'test 1/4',
|
||||
instance: 1,
|
||||
parallel: { total: 4 },
|
||||
variables: {
|
||||
'PROVIDER' => 'aws',
|
||||
'STACK' => 'app1'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'test 2/4',
|
||||
instance: 2,
|
||||
parallel: { total: 4 },
|
||||
variables: {
|
||||
'PROVIDER' => 'aws',
|
||||
'STACK' => 'app2'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'test 3/4',
|
||||
instance: 3,
|
||||
parallel: { total: 4 },
|
||||
variables: {
|
||||
'PROVIDER' => 'ovh',
|
||||
'STACK' => 'app'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'test 4/4',
|
||||
instance: 4,
|
||||
parallel: { total: 4 },
|
||||
variables: {
|
||||
'PROVIDER' => 'gcp',
|
||||
'STACK' => 'app'
|
||||
}
|
||||
it 'has attributes' do
|
||||
expect(subject.map(&:attributes)).to match_array(
|
||||
[
|
||||
{
|
||||
name: 'test: [aws, app1]',
|
||||
instance: 1,
|
||||
parallel: { total: 4 },
|
||||
variables: {
|
||||
'PROVIDER' => 'aws',
|
||||
'STACK' => 'app1'
|
||||
}
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
it 'has parallelized name' do
|
||||
expect(subject.map(&:name)).to match_array(
|
||||
['test 1/4', 'test 2/4', 'test 3/4', 'test 4/4']
|
||||
)
|
||||
end
|
||||
},
|
||||
{
|
||||
name: 'test: [aws, app2]',
|
||||
instance: 2,
|
||||
parallel: { total: 4 },
|
||||
variables: {
|
||||
'PROVIDER' => 'aws',
|
||||
'STACK' => 'app2'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'test: [ovh, app]',
|
||||
instance: 3,
|
||||
parallel: { total: 4 },
|
||||
variables: {
|
||||
'PROVIDER' => 'ovh',
|
||||
'STACK' => 'app'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'test: [gcp, app]',
|
||||
instance: 4,
|
||||
parallel: { total: 4 },
|
||||
variables: {
|
||||
'PROVIDER' => 'gcp',
|
||||
'STACK' => 'app'
|
||||
}
|
||||
}
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
context 'with new_matrix_job_names_enabled ff enabled' do
|
||||
before do
|
||||
stub_feature_flags(ci_matrix_job_names: true)
|
||||
end
|
||||
|
||||
it 'has attributes' do
|
||||
expect(subject.map(&:attributes)).to match_array(
|
||||
[
|
||||
{
|
||||
name: 'test: [aws, app1]',
|
||||
instance: 1,
|
||||
parallel: { total: 4 },
|
||||
variables: {
|
||||
'PROVIDER' => 'aws',
|
||||
'STACK' => 'app1'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'test: [aws, app2]',
|
||||
instance: 2,
|
||||
parallel: { total: 4 },
|
||||
variables: {
|
||||
'PROVIDER' => 'aws',
|
||||
'STACK' => 'app2'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'test: [ovh, app]',
|
||||
instance: 3,
|
||||
parallel: { total: 4 },
|
||||
variables: {
|
||||
'PROVIDER' => 'ovh',
|
||||
'STACK' => 'app'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'test: [gcp, app]',
|
||||
instance: 4,
|
||||
parallel: { total: 4 },
|
||||
variables: {
|
||||
'PROVIDER' => 'gcp',
|
||||
'STACK' => 'app'
|
||||
}
|
||||
}
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
it 'has parallelized name' do
|
||||
expect(subject.map(&:name)).to match_array(
|
||||
['test: [aws, app1]', 'test: [aws, app2]', 'test: [gcp, app]', 'test: [ovh, app]']
|
||||
)
|
||||
end
|
||||
it 'has parallelized name' do
|
||||
expect(subject.map(&:name)).to match_array(
|
||||
['test: [aws, app1]', 'test: [aws, app2]', 'test: [gcp, app]', 'test: [ovh, app]']
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require 'fast_spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Ci::Config::Normalizer do
|
||||
let(:job_name) { :rspec }
|
||||
|
|
@ -185,6 +185,13 @@ RSpec.describe Gitlab::Ci::Config::Normalizer do
|
|||
}
|
||||
end
|
||||
|
||||
let(:expanded_job_names) do
|
||||
[
|
||||
'rspec: [A, B]',
|
||||
'rspec: [A, C]'
|
||||
]
|
||||
end
|
||||
|
||||
it 'does not have original job' do
|
||||
is_expected.not_to include(job_name)
|
||||
end
|
||||
|
|
@ -215,45 +222,12 @@ RSpec.describe Gitlab::Ci::Config::Normalizer do
|
|||
expect(configs).to all(match(a_hash_including(original_config)))
|
||||
end
|
||||
|
||||
context 'with new_matrix_job_names_enabled ff enabled' do
|
||||
let(:expanded_job_names) do
|
||||
[
|
||||
'rspec: [A, B]',
|
||||
'rspec: [A, C]'
|
||||
]
|
||||
end
|
||||
|
||||
before do
|
||||
stub_feature_flags(ci_matrix_job_names: true)
|
||||
end
|
||||
|
||||
it 'has parallelized jobs' do
|
||||
is_expected.to include(*expanded_job_names.map(&:to_sym))
|
||||
end
|
||||
|
||||
it_behaves_like 'parallel dependencies'
|
||||
it_behaves_like 'parallel needs'
|
||||
it 'has parallelized jobs' do
|
||||
is_expected.to include(*expanded_job_names.map(&:to_sym))
|
||||
end
|
||||
|
||||
context 'with new_matrix_job_names_enabled ff disabled' do
|
||||
let(:expanded_job_names) do
|
||||
[
|
||||
'rspec 1/2',
|
||||
'rspec 2/2'
|
||||
]
|
||||
end
|
||||
|
||||
before do
|
||||
stub_feature_flags(ci_matrix_job_names: false)
|
||||
end
|
||||
|
||||
it 'has parallelized jobs' do
|
||||
is_expected.to include(*expanded_job_names.map(&:to_sym))
|
||||
end
|
||||
|
||||
it_behaves_like 'parallel dependencies'
|
||||
it_behaves_like 'parallel needs'
|
||||
end
|
||||
it_behaves_like 'parallel dependencies'
|
||||
it_behaves_like 'parallel needs'
|
||||
end
|
||||
|
||||
context 'when parallel config does not matches a factory' do
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ RSpec.describe Gitlab::GlRepository::RepoType do
|
|||
let(:expected_identifier) { "project-#{expected_id}" }
|
||||
let(:expected_suffix) { '' }
|
||||
let(:expected_container) { project }
|
||||
let(:expected_repository) { expected_container.repository }
|
||||
let(:expected_repository) { ::Repository.new(project.full_path, project, shard: project.repository_storage, disk_path: project.disk_path, repo_type: Gitlab::GlRepository::PROJECT) }
|
||||
end
|
||||
|
||||
it 'knows its type' do
|
||||
|
|
@ -46,7 +46,7 @@ RSpec.describe Gitlab::GlRepository::RepoType do
|
|||
let(:expected_identifier) { "wiki-#{expected_id}" }
|
||||
let(:expected_suffix) { '.wiki' }
|
||||
let(:expected_container) { project }
|
||||
let(:expected_repository) { expected_container.wiki.repository }
|
||||
let(:expected_repository) { ::Repository.new(project.wiki.full_path, project, shard: project.wiki.repository_storage, disk_path: project.wiki.disk_path, repo_type: Gitlab::GlRepository::WIKI) }
|
||||
end
|
||||
|
||||
it 'knows its type' do
|
||||
|
|
@ -75,7 +75,7 @@ RSpec.describe Gitlab::GlRepository::RepoType do
|
|||
let(:expected_id) { personal_snippet.id }
|
||||
let(:expected_identifier) { "snippet-#{expected_id}" }
|
||||
let(:expected_suffix) { '' }
|
||||
let(:expected_repository) { personal_snippet.repository }
|
||||
let(:expected_repository) { ::Repository.new(personal_snippet.full_path, personal_snippet, shard: personal_snippet.repository_storage, disk_path: personal_snippet.disk_path, repo_type: Gitlab::GlRepository::SNIPPET) }
|
||||
let(:expected_container) { personal_snippet }
|
||||
end
|
||||
|
||||
|
|
@ -104,7 +104,7 @@ RSpec.describe Gitlab::GlRepository::RepoType do
|
|||
let(:expected_id) { project_snippet.id }
|
||||
let(:expected_identifier) { "snippet-#{expected_id}" }
|
||||
let(:expected_suffix) { '' }
|
||||
let(:expected_repository) { project_snippet.repository }
|
||||
let(:expected_repository) { ::Repository.new(project_snippet.full_path, project_snippet, shard: project_snippet.repository_storage, disk_path: project_snippet.disk_path, repo_type: Gitlab::GlRepository::SNIPPET) }
|
||||
let(:expected_container) { project_snippet }
|
||||
end
|
||||
|
||||
|
|
@ -133,10 +133,14 @@ RSpec.describe Gitlab::GlRepository::RepoType do
|
|||
let(:expected_identifier) { "design-#{project.id}" }
|
||||
let(:expected_id) { project.id }
|
||||
let(:expected_suffix) { '.design' }
|
||||
let(:expected_repository) { project.design_repository }
|
||||
let(:expected_repository) { ::DesignManagement::Repository.new(project) }
|
||||
let(:expected_container) { project }
|
||||
end
|
||||
|
||||
it 'uses the design access checker' do
|
||||
expect(described_class.access_checker_class).to eq(::Gitlab::GitAccessDesign)
|
||||
end
|
||||
|
||||
it 'knows its type' do
|
||||
aggregate_failures do
|
||||
expect(described_class).to be_design
|
||||
|
|
|
|||
|
|
@ -31,15 +31,4 @@ RSpec.describe ::Gitlab::GlRepository do
|
|||
expect { described_class.parse("project-foo") }.to raise_error(ArgumentError)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DESIGN' do
|
||||
it 'uses the design access checker' do
|
||||
expect(described_class::DESIGN.access_checker_class).to eq(::Gitlab::GitAccessDesign)
|
||||
end
|
||||
|
||||
it 'builds a design repository' do
|
||||
expect(described_class::DESIGN.repository_resolver.call(create(:project)))
|
||||
.to be_a(::DesignManagement::Repository)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1179,7 +1179,7 @@ RSpec.describe API::Internal::Base do
|
|||
let(:gl_repository) { "snippet-#{personal_snippet.id}" }
|
||||
|
||||
it 'does not try to notify that project moved' do
|
||||
allow(Gitlab::GlRepository).to receive(:parse).and_return([personal_snippet, nil, Gitlab::GlRepository::PROJECT])
|
||||
allow(Gitlab::GlRepository).to receive(:parse).and_return([personal_snippet, nil, Gitlab::GlRepository::SNIPPET])
|
||||
|
||||
expect(Gitlab::Checks::ProjectMoved).not_to receive(:fetch_message)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require 'fast_spec_helper'
|
||||
|
||||
require 'rubocop'
|
||||
require 'rubocop/rspec/support'
|
||||
|
||||
require_relative '../../../../rubocop/cop/migration/update_column_in_batches'
|
||||
|
||||
RSpec.describe RuboCop::Cop::Migration::UpdateColumnInBatches do
|
||||
RSpec.describe RuboCop::Cop::Migration::UpdateColumnInBatches, type: :rubocop do
|
||||
let(:cop) { described_class.new }
|
||||
let(:tmp_rails_root) { Rails.root.join('tmp', 'rails_root') }
|
||||
let(:tmp_rails_root) { rails_root_join('tmp', 'rails_root') }
|
||||
let(:migration_code) do
|
||||
<<-END
|
||||
def up
|
||||
|
|
@ -27,7 +27,7 @@ RSpec.describe RuboCop::Cop::Migration::UpdateColumnInBatches do
|
|||
FileUtils.rm_rf(tmp_rails_root)
|
||||
end
|
||||
|
||||
let(:spec_filepath) { tmp_rails_root.join('spec', 'migrations', 'my_super_migration_spec.rb') }
|
||||
let(:spec_filepath) { File.join(tmp_rails_root, 'spec', 'migrations', 'my_super_migration_spec.rb') }
|
||||
|
||||
context 'outside of a migration' do
|
||||
it 'does not register any offenses' do
|
||||
|
|
@ -83,31 +83,31 @@ RSpec.describe RuboCop::Cop::Migration::UpdateColumnInBatches do
|
|||
end
|
||||
|
||||
context 'in a migration' do
|
||||
let(:migration_filepath) { tmp_rails_root.join('db', 'migrate', '20121220064453_my_super_migration.rb') }
|
||||
let(:migration_filepath) { File.join(tmp_rails_root, 'db', 'migrate', '20121220064453_my_super_migration.rb') }
|
||||
|
||||
it_behaves_like 'a migration file with no spec file'
|
||||
it_behaves_like 'a migration file with a spec file'
|
||||
end
|
||||
|
||||
context 'in a post migration' do
|
||||
let(:migration_filepath) { tmp_rails_root.join('db', 'post_migrate', '20121220064453_my_super_migration.rb') }
|
||||
let(:migration_filepath) { File.join(tmp_rails_root, 'db', 'post_migrate', '20121220064453_my_super_migration.rb') }
|
||||
|
||||
it_behaves_like 'a migration file with no spec file'
|
||||
it_behaves_like 'a migration file with a spec file'
|
||||
end
|
||||
|
||||
context 'EE migrations' do
|
||||
let(:spec_filepath) { tmp_rails_root.join('ee', 'spec', 'migrations', 'my_super_migration_spec.rb') }
|
||||
let(:spec_filepath) { File.join(tmp_rails_root, 'ee', 'spec', 'migrations', 'my_super_migration_spec.rb') }
|
||||
|
||||
context 'in a migration' do
|
||||
let(:migration_filepath) { tmp_rails_root.join('ee', 'db', 'migrate', '20121220064453_my_super_migration.rb') }
|
||||
let(:migration_filepath) { File.join(tmp_rails_root, 'ee', 'db', 'migrate', '20121220064453_my_super_migration.rb') }
|
||||
|
||||
it_behaves_like 'a migration file with no spec file'
|
||||
it_behaves_like 'a migration file with a spec file'
|
||||
end
|
||||
|
||||
context 'in a post migration' do
|
||||
let(:migration_filepath) { tmp_rails_root.join('ee', 'db', 'post_migrate', '20121220064453_my_super_migration.rb') }
|
||||
let(:migration_filepath) { File.join(tmp_rails_root, 'ee', 'db', 'post_migrate', '20121220064453_my_super_migration.rb') }
|
||||
|
||||
it_behaves_like 'a migration file with no spec file'
|
||||
it_behaves_like 'a migration file with a spec file'
|
||||
|
|
|
|||
|
|
@ -17,5 +17,9 @@ RSpec.shared_examples 'a repo type' do
|
|||
it 'finds the repository for the repo type' do
|
||||
expect(described_class.repository_for(expected_container)).to eq(expected_repository)
|
||||
end
|
||||
|
||||
it 'returns nil when container is nil' do
|
||||
expect(described_class.repository_for(nil)).to eq(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue