Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
a7364a0474
commit
254f79fb35
41 changed files with 463 additions and 43 deletions
|
@ -28,7 +28,6 @@ import initUserPopovers from '~/user_popovers';
|
|||
import { mergeUrlParams } from '~/lib/utils/url_utility';
|
||||
import IssueAssignees from '~/vue_shared/components/issue/issue_assignees.vue';
|
||||
import { isScopedLabel } from '~/lib/utils/common_utils';
|
||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
|
||||
import { convertToCamelCase } from '~/lib/utils/text_utility';
|
||||
|
||||
|
@ -37,6 +36,7 @@ export default {
|
|||
openedAgo: __('opened %{timeAgoString} by %{user}'),
|
||||
openedAgoJira: __('opened %{timeAgoString} by %{user} in Jira'),
|
||||
},
|
||||
inject: ['scopedLabelsAvailable'],
|
||||
components: {
|
||||
IssueAssignees,
|
||||
GlLink,
|
||||
|
@ -50,7 +50,6 @@ export default {
|
|||
GlTooltip,
|
||||
SafeHtml,
|
||||
},
|
||||
mixins: [glFeatureFlagsMixin()],
|
||||
props: {
|
||||
issuable: {
|
||||
type: Object,
|
||||
|
@ -85,9 +84,6 @@ export default {
|
|||
|
||||
return this.issuableLink({ milestone_title: title });
|
||||
},
|
||||
scopedLabelsAvailable() {
|
||||
return this.glFeatures.scopedLabels;
|
||||
},
|
||||
hasWeight() {
|
||||
return isNumber(this.issuable.weight);
|
||||
},
|
||||
|
|
|
@ -41,10 +41,13 @@ function mountIssuablesListApp() {
|
|||
}
|
||||
|
||||
document.querySelectorAll('.js-issuables-list').forEach(el => {
|
||||
const { canBulkEdit, emptyStateMeta = {}, ...data } = el.dataset;
|
||||
const { canBulkEdit, emptyStateMeta = {}, scopedLabelsAvailable, ...data } = el.dataset;
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
provide: {
|
||||
scopedLabelsAvailable: parseBoolean(scopedLabelsAvailable),
|
||||
},
|
||||
render(createElement) {
|
||||
return createElement(IssuablesListApp, {
|
||||
props: {
|
||||
|
|
|
@ -8,9 +8,6 @@ module IssuableActions
|
|||
before_action :authorize_destroy_issuable!, only: :destroy
|
||||
before_action :check_destroy_confirmation!, only: :destroy
|
||||
before_action :authorize_admin_issuable!, only: :bulk_update
|
||||
before_action only: :show do
|
||||
push_frontend_feature_flag(:scoped_labels, type: :licensed, default_enabled: true)
|
||||
end
|
||||
before_action do
|
||||
push_frontend_feature_flag(:not_issuable_queries, @project, default_enabled: true)
|
||||
end
|
||||
|
|
|
@ -57,10 +57,6 @@ class Projects::IssuesController < Projects::ApplicationController
|
|||
record_experiment_user(:invite_members_version_b)
|
||||
end
|
||||
|
||||
before_action only: :index do
|
||||
push_frontend_feature_flag(:scoped_labels, @project, type: :licensed)
|
||||
end
|
||||
|
||||
around_action :allow_gitaly_ref_name_caching, only: [:discussions]
|
||||
|
||||
respond_to :html
|
||||
|
|
|
@ -214,7 +214,7 @@ class Projects::PipelinesController < Projects::ApplicationController
|
|||
def config_variables
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
render json: Ci::ListConfigVariablesService.new(@project).execute(params[:sha])
|
||||
render json: Ci::ListConfigVariablesService.new(@project, current_user).execute(params[:sha])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -13,6 +13,8 @@ class Projects::ServicesController < Projects::ApplicationController
|
|||
before_action :redirect_deprecated_prometheus_service, only: [:update]
|
||||
before_action only: :edit do
|
||||
push_frontend_feature_flag(:jira_issues_integration, @project, type: :licensed, default_enabled: true)
|
||||
push_frontend_feature_flag(:jira_vulnerabilities_integration, @project, type: :licensed, default_enabled: true)
|
||||
push_frontend_feature_flag(:jira_for_vulnerabilities, @project, type: :development, default_enabled: false)
|
||||
end
|
||||
|
||||
respond_to :html
|
||||
|
|
|
@ -170,6 +170,11 @@ module IssuesHelper
|
|||
submit_as_spam_path: mark_as_spam_project_issue_path(project, issuable)
|
||||
}
|
||||
end
|
||||
|
||||
# Overridden in EE
|
||||
def scoped_labels_available?(parent)
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
IssuesHelper.prepend_if_ee('EE::IssuesHelper')
|
||||
|
|
|
@ -416,6 +416,7 @@ class ApplicationSetting < ApplicationRecord
|
|||
attr_encrypted :slack_app_verification_token, encryption_options_base_truncated_aes_256_gcm
|
||||
attr_encrypted :ci_jwt_signing_key, encryption_options_base_truncated_aes_256_gcm
|
||||
attr_encrypted :secret_detection_token_revocation_token, encryption_options_base_truncated_aes_256_gcm
|
||||
attr_encrypted :cloud_license_auth_token, encryption_options_base_truncated_aes_256_gcm
|
||||
|
||||
before_validation :ensure_uuid!
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ class JiraService < IssueTrackerService
|
|||
|
||||
# TODO: we can probably just delegate as part of
|
||||
# https://gitlab.com/gitlab-org/gitlab/issues/29404
|
||||
data_field :username, :password, :url, :api_url, :jira_issue_transition_id, :project_key, :issues_enabled
|
||||
data_field :username, :password, :url, :api_url, :jira_issue_transition_id, :project_key, :issues_enabled, :vulnerabilities_enabled, :vulnerabilities_issuetype
|
||||
|
||||
before_update :reset_password
|
||||
after_commit :update_deployment_type, on: [:create, :update], if: :update_deployment_type?
|
||||
|
|
|
@ -6,7 +6,10 @@ module Ci
|
|||
config = project.ci_config_for(sha)
|
||||
return {} unless config
|
||||
|
||||
result = Gitlab::Ci::YamlProcessor.new(config).execute
|
||||
result = Gitlab::Ci::YamlProcessor.new(config, project: project,
|
||||
user: current_user,
|
||||
sha: sha).execute
|
||||
|
||||
result.valid? ? result.variables_with_data : {}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -26,11 +26,27 @@ module Projects
|
|||
project.set_repository_writable!
|
||||
end
|
||||
|
||||
if result && block_given?
|
||||
yield
|
||||
end
|
||||
|
||||
result
|
||||
rescue Gitlab::Git::CommandError => e
|
||||
logger.error("Repository #{project.full_path} failed to upgrade (PROJECT_ID=#{project.id}). Git operation failed: #{e.inspect}")
|
||||
|
||||
rollback_migration!
|
||||
|
||||
false
|
||||
rescue OpenSSL::Cipher::CipherError => e
|
||||
logger.error("Repository #{project.full_path} failed to upgrade (PROJECT_ID=#{project.id}). There is a problem with encrypted attributes: #{e.inspect}")
|
||||
|
||||
rollback_migration!
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def rollback_migration!
|
||||
rollback_folder_move
|
||||
project.storage_version = nil
|
||||
project.set_repository_writable!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -21,14 +21,32 @@ module Projects
|
|||
project.storage_version = ::Project::HASHED_STORAGE_FEATURES[:repository]
|
||||
end
|
||||
|
||||
project.repository_read_only = false
|
||||
project.save!(validate: false)
|
||||
|
||||
if result && block_given?
|
||||
yield
|
||||
project.transaction do
|
||||
project.save!(validate: false)
|
||||
project.set_repository_writable!
|
||||
end
|
||||
|
||||
result
|
||||
rescue Gitlab::Git::CommandError => e
|
||||
logger.error("Repository #{project.full_path} failed to rollback (PROJECT_ID=#{project.id}). Git operation failed: #{e.inspect}")
|
||||
|
||||
rollback_migration!
|
||||
|
||||
false
|
||||
rescue OpenSSL::Cipher::CipherError => e
|
||||
logger.error("Repository #{project.full_path} failed to rollback (PROJECT_ID=#{project.id}). There is a problem with encrypted attributes: #{e.inspect}")
|
||||
|
||||
rollback_migration!
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def rollback_migration!
|
||||
rollback_folder_move
|
||||
project.storage_version = ::Project::HASHED_STORAGE_FEATURES[:repository]
|
||||
project.set_repository_writable!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
'can-bulk-edit': @can_bulk_update.to_json,
|
||||
'empty-state-meta': { svg_path: image_path('illustrations/issues.svg') },
|
||||
'sort-key': @sort,
|
||||
type: 'issues' } }
|
||||
type: 'issues',
|
||||
'scoped-labels-available': scoped_labels_available?(@group).to_json } }
|
||||
- else
|
||||
= render 'shared/issues'
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
'empty-state-meta': data_empty_state_meta.to_json,
|
||||
'can-bulk-edit': @can_bulk_update.to_json,
|
||||
'sort-key': @sort,
|
||||
type: type } }
|
||||
type: type,
|
||||
'scoped-labels-available': scoped_labels_available?(@project).to_json } }
|
||||
- else
|
||||
- empty_state_path = local_assigns.fetch(:empty_state_path, 'shared/empty_states/issues')
|
||||
%ul.content-list.issues-list.issuable-list{ class: ("manual-ordering" if @sort == 'relative_position') }
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix pipeline security tab filters not showing
|
||||
merge_request: 47294
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: "Hashed Storage: make migration and rollback resilient to exceptions"
|
||||
merge_request: 46178
|
||||
author:
|
||||
type: fixed
|
5
changelogs/unreleased/30101-fix-includes.yml
Normal file
5
changelogs/unreleased/30101-fix-includes.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix config variables when having includes
|
||||
merge_request: 47189
|
||||
author:
|
||||
type: fixed
|
5
changelogs/unreleased/issue-277354.yml
Normal file
5
changelogs/unreleased/issue-277354.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix duplicate epic iids and add uniqueness constraint
|
||||
merge_request: 47081
|
||||
author:
|
||||
type: fixed
|
5
changelogs/unreleased/vij-add-cloud-license-token.yml
Normal file
5
changelogs/unreleased/vij-add-cloud-license-token.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add cloud_license_auth_token column to application_settings
|
||||
merge_request: 47396
|
||||
author:
|
||||
type: added
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
name: jira_for_vulnerabilities
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46982
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/276893
|
||||
type: development
|
||||
group: group::threat insights
|
||||
default_enabled: false
|
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddVulnerabilitiesEnabledAndIssuetypeToJiraTrackerData < ActiveRecord::Migration[6.0]
|
||||
DOWNTIME = false
|
||||
|
||||
# rubocop:disable Migration/AddLimitToTextColumns
|
||||
# limit is added in 20201105143312_add_text_limit_to_jira_tracker_data_issuetype.rb
|
||||
def change
|
||||
add_column :jira_tracker_data, :vulnerabilities_issuetype, :text
|
||||
add_column :jira_tracker_data, :vulnerabilities_enabled, :boolean, default: false, null: false
|
||||
end
|
||||
# rubocop:enable Migration/AddLimitToTextColumns
|
||||
end
|
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddTextLimitToJiraTrackerDataIssuetype < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
DOWNTIME = false
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
add_text_limit :jira_tracker_data, :vulnerabilities_issuetype, 255
|
||||
end
|
||||
|
||||
def down
|
||||
remove_text_limit :jira_tracker_data, :vulnerabilities_issuetype
|
||||
end
|
||||
end
|
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddCloudLicenseAuthTokenToSettings < ActiveRecord::Migration[6.0]
|
||||
DOWNTIME = false
|
||||
|
||||
# rubocop:disable Migration/AddLimitToTextColumns
|
||||
# limit is added in 20201111110918_add_cloud_license_auth_token_application_settings_text_limit
|
||||
def change
|
||||
add_column :application_settings, :encrypted_cloud_license_auth_token, :text
|
||||
add_column :application_settings, :encrypted_cloud_license_auth_token_iv, :text
|
||||
end
|
||||
# rubocop:enable Migration/AddLimitToTextColumns
|
||||
end
|
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddCloudLicenseAuthTokenApplicationSettingsTextLimit < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
DOWNTIME = false
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
add_text_limit :application_settings, :encrypted_cloud_license_auth_token_iv, 255
|
||||
end
|
||||
|
||||
def down
|
||||
remove_text_limit :application_settings, :encrypted_cloud_license_auth_token_iv
|
||||
end
|
||||
end
|
121
db/post_migrate/20201106134950_deduplicate_epic_iids.rb
Normal file
121
db/post_migrate/20201106134950_deduplicate_epic_iids.rb
Normal file
|
@ -0,0 +1,121 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class DeduplicateEpicIids < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
DOWNTIME = false
|
||||
INDEX_NAME = 'index_epics_on_group_id_and_iid'
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
class Epic < ActiveRecord::Base
|
||||
end
|
||||
|
||||
class InternalId < ActiveRecord::Base
|
||||
class << self
|
||||
def generate_next(subject, scope, usage, init)
|
||||
InternalIdGenerator.new(subject, scope, usage, init).generate
|
||||
end
|
||||
end
|
||||
|
||||
# Increments #last_value and saves the record
|
||||
#
|
||||
# The operation locks the record and gathers a `ROW SHARE` lock (in PostgreSQL).
|
||||
# As such, the increment is atomic and safe to be called concurrently.
|
||||
def increment_and_save!
|
||||
update_and_save { self.last_value = (last_value || 0) + 1 }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def update_and_save(&block)
|
||||
lock!
|
||||
yield
|
||||
save!
|
||||
last_value
|
||||
end
|
||||
end
|
||||
|
||||
# See app/models/internal_id
|
||||
class InternalIdGenerator
|
||||
attr_reader :subject, :scope, :scope_attrs, :usage, :init
|
||||
|
||||
def initialize(subject, scope, usage, init = nil)
|
||||
@subject = subject
|
||||
@scope = scope
|
||||
@usage = usage
|
||||
@init = init
|
||||
|
||||
raise ArgumentError, 'Scope is not well-defined, need at least one column for scope (given: 0)' if scope.empty? || usage.to_s != 'epics'
|
||||
end
|
||||
|
||||
# Generates next internal id and returns it
|
||||
# init: Block that gets called to initialize InternalId record if not present
|
||||
# Make sure to not throw exceptions in the absence of records (if this is expected).
|
||||
def generate
|
||||
subject.transaction do
|
||||
# Create a record in internal_ids if one does not yet exist
|
||||
# and increment its last value
|
||||
#
|
||||
# Note this will acquire a ROW SHARE lock on the InternalId record
|
||||
record.increment_and_save!
|
||||
end
|
||||
end
|
||||
|
||||
def record
|
||||
@record ||= (lookup || create_record)
|
||||
end
|
||||
|
||||
def lookup
|
||||
InternalId.find_by(**scope, usage: usage_value)
|
||||
end
|
||||
|
||||
def usage_value
|
||||
4 # see Enums::InternalId - this is the value for epics
|
||||
end
|
||||
|
||||
# Create InternalId record for (scope, usage) combination, if it doesn't exist
|
||||
#
|
||||
# We blindly insert without synchronization. If another process
|
||||
# was faster in doing this, we'll realize once we hit the unique key constraint
|
||||
# violation. We can safely roll-back the nested transaction and perform
|
||||
# a lookup instead to retrieve the record.
|
||||
def create_record
|
||||
raise ArgumentError, 'Cannot initialize without init!' unless init
|
||||
|
||||
instance = subject.is_a?(::Class) ? nil : subject
|
||||
|
||||
subject.transaction(requires_new: true) do
|
||||
InternalId.create!(
|
||||
**scope,
|
||||
usage: usage_value,
|
||||
last_value: init.call(instance, scope) || 0
|
||||
)
|
||||
end
|
||||
rescue ActiveRecord::RecordNotUnique
|
||||
lookup
|
||||
end
|
||||
end
|
||||
|
||||
def up
|
||||
duplicate_epic_ids = ApplicationRecord.connection.execute('SELECT iid, group_id, COUNT(*) FROM epics GROUP BY iid, group_id HAVING COUNT(*) > 1;')
|
||||
|
||||
duplicate_epic_ids.each do |dup|
|
||||
Epic.where(iid: dup['iid'], group_id: dup['group_id']).last(dup['count'] - 1).each do |epic|
|
||||
new_iid = InternalId.generate_next(epic,
|
||||
{ namespace_id: epic.group_id },
|
||||
:epics, ->(instance, _) { instance.class.where(group_id: epic.group_id).maximum(:iid) }
|
||||
)
|
||||
|
||||
epic.update!(iid: new_iid)
|
||||
end
|
||||
end
|
||||
|
||||
add_concurrent_index :epics, [:group_id, :iid], unique: true, name: INDEX_NAME
|
||||
end
|
||||
|
||||
def down
|
||||
# only remove the index, as we do not want to create the duplicates back
|
||||
remove_concurrent_index :epics, [:group_id, :iid], name: INDEX_NAME
|
||||
end
|
||||
end
|
1
db/schema_migrations/20201105143211
Normal file
1
db/schema_migrations/20201105143211
Normal file
|
@ -0,0 +1 @@
|
|||
b614435cdb654ebbd11bcc5ac0ed69352219e51b368d8f10c0b2998c5258caf9
|
1
db/schema_migrations/20201105143312
Normal file
1
db/schema_migrations/20201105143312
Normal file
|
@ -0,0 +1 @@
|
|||
decdc314dbcf6b8ac2ce140f81f9d342efca0d98bbeff10c7a041568a67b63f3
|
1
db/schema_migrations/20201106134950
Normal file
1
db/schema_migrations/20201106134950
Normal file
|
@ -0,0 +1 @@
|
|||
f6e4e62dbd992fc8283f3d7872bb33f1b6bea1b366806caf8f7a65140584c0c1
|
1
db/schema_migrations/20201111110318
Normal file
1
db/schema_migrations/20201111110318
Normal file
|
@ -0,0 +1 @@
|
|||
4168c39fe93b1c11d8080e07167f79c8234c74a7b274332174d9e861f2084ada
|
1
db/schema_migrations/20201111110918
Normal file
1
db/schema_migrations/20201111110918
Normal file
|
@ -0,0 +1 @@
|
|||
f5705da7bce46d98ca798c85f08d8a6a0577839aabacd0ba9b50e0b7351a4e96
|
|
@ -9342,6 +9342,8 @@ CREATE TABLE application_settings (
|
|||
domain_denylist text,
|
||||
domain_allowlist text,
|
||||
new_user_signups_cap integer,
|
||||
encrypted_cloud_license_auth_token text,
|
||||
encrypted_cloud_license_auth_token_iv text,
|
||||
CONSTRAINT app_settings_registry_exp_policies_worker_capacity_positive CHECK ((container_registry_expiration_policies_worker_capacity >= 0)),
|
||||
CONSTRAINT check_2dba05b802 CHECK ((char_length(gitpod_url) <= 255)),
|
||||
CONSTRAINT check_51700b31b5 CHECK ((char_length(default_branch_name) <= 255)),
|
||||
|
@ -9351,7 +9353,8 @@ CREATE TABLE application_settings (
|
|||
CONSTRAINT check_9c6c447a13 CHECK ((char_length(maintenance_mode_message) <= 255)),
|
||||
CONSTRAINT check_d03919528d CHECK ((char_length(container_registry_vendor) <= 255)),
|
||||
CONSTRAINT check_d820146492 CHECK ((char_length(spam_check_endpoint_url) <= 255)),
|
||||
CONSTRAINT check_e5aba18f02 CHECK ((char_length(container_registry_version) <= 255))
|
||||
CONSTRAINT check_e5aba18f02 CHECK ((char_length(container_registry_version) <= 255)),
|
||||
CONSTRAINT check_ef6176834f CHECK ((char_length(encrypted_cloud_license_auth_token_iv) <= 255))
|
||||
);
|
||||
|
||||
CREATE SEQUENCE application_settings_id_seq
|
||||
|
@ -13192,6 +13195,9 @@ CREATE TABLE jira_tracker_data (
|
|||
project_key text,
|
||||
issues_enabled boolean DEFAULT false NOT NULL,
|
||||
deployment_type smallint DEFAULT 0 NOT NULL,
|
||||
vulnerabilities_issuetype text,
|
||||
vulnerabilities_enabled boolean DEFAULT false NOT NULL,
|
||||
CONSTRAINT check_0bf84b76e9 CHECK ((char_length(vulnerabilities_issuetype) <= 255)),
|
||||
CONSTRAINT check_214cf6a48b CHECK ((char_length(project_key) <= 255))
|
||||
);
|
||||
|
||||
|
@ -20735,6 +20741,8 @@ CREATE INDEX index_epics_on_group_id ON epics USING btree (group_id);
|
|||
|
||||
CREATE UNIQUE INDEX index_epics_on_group_id_and_external_key ON epics USING btree (group_id, external_key) WHERE (external_key IS NOT NULL);
|
||||
|
||||
CREATE UNIQUE INDEX index_epics_on_group_id_and_iid ON epics USING btree (group_id, iid);
|
||||
|
||||
CREATE INDEX index_epics_on_group_id_and_iid_varchar_pattern ON epics USING btree (group_id, ((iid)::character varying) varchar_pattern_ops);
|
||||
|
||||
CREATE INDEX index_epics_on_iid ON epics USING btree (iid);
|
||||
|
|
|
@ -24036,9 +24036,6 @@ msgstr ""
|
|||
msgid "SecurityReports|Scan details"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|Scanner"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|Security Dashboard"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -83,6 +83,8 @@ FactoryBot.define do
|
|||
jira_issue_transition_id { '56-1' }
|
||||
issues_enabled { false }
|
||||
project_key { nil }
|
||||
vulnerabilities_enabled { false }
|
||||
vulnerabilities_issuetype { nil }
|
||||
end
|
||||
|
||||
before(:create) do |service, evaluator|
|
||||
|
@ -90,7 +92,8 @@ FactoryBot.define do
|
|||
create(:jira_tracker_data, service: service,
|
||||
url: evaluator.url, api_url: evaluator.api_url, jira_issue_transition_id: evaluator.jira_issue_transition_id,
|
||||
username: evaluator.username, password: evaluator.password, issues_enabled: evaluator.issues_enabled,
|
||||
project_key: evaluator.project_key
|
||||
project_key: evaluator.project_key, vulnerabilities_enabled: evaluator.vulnerabilities_enabled,
|
||||
vulnerabilities_issuetype: evaluator.vulnerabilities_issuetype
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -38,7 +38,7 @@ describe('Issuable component', () => {
|
|||
let DateOrig;
|
||||
let wrapper;
|
||||
|
||||
const factory = (props = {}, scopedLabels = false) => {
|
||||
const factory = (props = {}, scopedLabelsAvailable = false) => {
|
||||
wrapper = shallowMount(Issuable, {
|
||||
propsData: {
|
||||
issuable: simpleIssue,
|
||||
|
@ -46,9 +46,7 @@ describe('Issuable component', () => {
|
|||
...props,
|
||||
},
|
||||
provide: {
|
||||
glFeatures: {
|
||||
scopedLabels,
|
||||
},
|
||||
scopedLabelsAvailable,
|
||||
},
|
||||
stubs: {
|
||||
'gl-sprintf': GlSprintf,
|
||||
|
|
|
@ -34,13 +34,13 @@ RSpec.describe Resolvers::MergeRequestsResolver do
|
|||
|
||||
context 'no arguments' do
|
||||
it 'returns all merge requests' do
|
||||
result = resolve_mr(project, {})
|
||||
result = resolve_mr(project)
|
||||
|
||||
expect(result).to contain_exactly(merge_request_1, merge_request_2, merge_request_3, merge_request_4, merge_request_5, merge_request_6, merge_request_with_milestone)
|
||||
end
|
||||
|
||||
it 'returns only merge requests that the current user can see' do
|
||||
result = resolve_mr(project, {}, user: build(:user))
|
||||
result = resolve_mr(project, user: build(:user))
|
||||
|
||||
expect(result).to be_empty
|
||||
end
|
||||
|
@ -236,10 +236,10 @@ RSpec.describe Resolvers::MergeRequestsResolver do
|
|||
end
|
||||
|
||||
def resolve_mr_single(project, iid)
|
||||
resolve_mr(project, { iids: iid }, resolver: described_class.single)
|
||||
resolve_mr(project, resolver: described_class.single, iids: iid)
|
||||
end
|
||||
|
||||
def resolve_mr(project, args, resolver: described_class, user: current_user)
|
||||
def resolve_mr(project, resolver: described_class, user: current_user, **args)
|
||||
resolve(resolver, obj: project, args: args, ctx: { current_user: user })
|
||||
end
|
||||
end
|
||||
|
|
36
spec/migrations/deduplicate_epic_iids_spec.rb
Normal file
36
spec/migrations/deduplicate_epic_iids_spec.rb
Normal file
|
@ -0,0 +1,36 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require Rails.root.join('db', 'post_migrate', '20201106134950_deduplicate_epic_iids.rb')
|
||||
|
||||
RSpec.describe DeduplicateEpicIids, :migration, schema: 20201106082723 do
|
||||
let(:routes) { table(:routes) }
|
||||
let(:epics) { table(:epics) }
|
||||
let(:users) { table(:users) }
|
||||
let(:namespaces) { table(:namespaces) }
|
||||
|
||||
let!(:group) { create_group('foo') }
|
||||
let!(:user) { users.create!(email: 'test@example.com', projects_limit: 100, username: 'test') }
|
||||
let!(:dup_epic1) { epics.create!(iid: 1, title: 'epic 1', group_id: group.id, author_id: user.id, created_at: Time.now, updated_at: Time.now, title_html: 'any') }
|
||||
let!(:dup_epic2) { epics.create!(iid: 1, title: 'epic 2', group_id: group.id, author_id: user.id, created_at: Time.now, updated_at: Time.now, title_html: 'any') }
|
||||
let!(:dup_epic3) { epics.create!(iid: 1, title: 'epic 3', group_id: group.id, author_id: user.id, created_at: Time.now, updated_at: Time.now, title_html: 'any') }
|
||||
|
||||
it 'deduplicates epic iids', :aggregate_failures do
|
||||
duplicate_epics_count = epics.where(iid: 1, group_id: group.id).count
|
||||
expect(duplicate_epics_count).to eq 3
|
||||
|
||||
migrate!
|
||||
|
||||
duplicate_epics_count = epics.where(iid: 1, group_id: group.id).count
|
||||
expect(duplicate_epics_count).to eq 1
|
||||
expect(dup_epic1.reload.iid).to eq 1
|
||||
expect(dup_epic2.reload.iid).to eq 2
|
||||
expect(dup_epic3.reload.iid).to eq 3
|
||||
end
|
||||
|
||||
def create_group(path)
|
||||
namespaces.create!(name: path, path: path, type: 'Group').tap do |namespace|
|
||||
routes.create!(path: namespace.path, name: namespace.name, source_id: namespace.id, source_type: 'Namespace')
|
||||
end
|
||||
end
|
||||
end
|
|
@ -25,7 +25,7 @@ RSpec.describe MigrateDiscussionIdOnPromotedEpics do
|
|||
end
|
||||
|
||||
def create_epic
|
||||
epics.create!(author_id: user.id, iid: 1,
|
||||
epics.create!(author_id: user.id, iid: epics.maximum(:iid).to_i + 1,
|
||||
group_id: namespace.id,
|
||||
title: 'Epic with discussion',
|
||||
title_html: 'Epic with discussion')
|
||||
|
|
|
@ -665,6 +665,20 @@ RSpec.describe ApplicationSetting do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#cloud_license_auth_token' do
|
||||
it { is_expected.to allow_value(nil).for(:cloud_license_auth_token) }
|
||||
|
||||
it 'is encrypted' do
|
||||
subject.cloud_license_auth_token = 'token-from-customers-dot'
|
||||
|
||||
aggregate_failures do
|
||||
expect(subject.encrypted_cloud_license_auth_token).to be_present
|
||||
expect(subject.encrypted_cloud_license_auth_token_iv).to be_present
|
||||
expect(subject.encrypted_cloud_license_auth_token).not_to eq(subject.cloud_license_auth_token)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'static objects external storage' do
|
||||
|
|
|
@ -3,8 +3,9 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Ci::ListConfigVariablesService do
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
let(:service) { described_class.new(project) }
|
||||
let(:project) { create(:project, :repository) }
|
||||
let(:user) { project.creator }
|
||||
let(:service) { described_class.new(project, user) }
|
||||
let(:result) { YAML.dump(ci_config) }
|
||||
|
||||
subject { service.execute(sha) }
|
||||
|
@ -38,6 +39,40 @@ RSpec.describe Ci::ListConfigVariablesService do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when config has includes' do
|
||||
let(:sha) { 'master' }
|
||||
let(:ci_config) do
|
||||
{
|
||||
include: [{ local: 'other_file.yml' }],
|
||||
variables: {
|
||||
KEY1: { value: 'val 1', description: 'description 1' }
|
||||
},
|
||||
test: {
|
||||
stage: 'test',
|
||||
script: 'echo'
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
before do
|
||||
allow_next_instance_of(Repository) do |repository|
|
||||
allow(repository).to receive(:blob_data_at).with(sha, 'other_file.yml') do
|
||||
<<~HEREDOC
|
||||
variables:
|
||||
KEY2:
|
||||
value: 'val 2'
|
||||
description: 'description 2'
|
||||
HEREDOC
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns variable list' do
|
||||
expect(subject['KEY1']).to eq({ value: 'val 1', description: 'description 1' })
|
||||
expect(subject['KEY2']).to eq({ value: 'val 2', description: 'description 2' })
|
||||
end
|
||||
end
|
||||
|
||||
context 'when sending an invalid sha' do
|
||||
let(:sha) { 'invalid-sha' }
|
||||
let(:ci_config) { nil }
|
||||
|
|
|
@ -77,6 +77,42 @@ RSpec.describe Projects::HashedStorage::MigrateRepositoryService do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when exception happens' do
|
||||
it 'handles OpenSSL::Cipher::CipherError' do
|
||||
expect(project).to receive(:ensure_runners_token).and_raise(OpenSSL::Cipher::CipherError)
|
||||
|
||||
expect { service.execute }.not_to raise_exception
|
||||
end
|
||||
|
||||
it 'ensures rollback when OpenSSL::Cipher::CipherError' do
|
||||
expect(project).to receive(:ensure_runners_token).and_raise(OpenSSL::Cipher::CipherError)
|
||||
expect(service).to receive(:rollback_folder_move).and_call_original
|
||||
|
||||
service.execute
|
||||
project.reload
|
||||
|
||||
expect(project.legacy_storage?).to be_truthy
|
||||
expect(project.repository_read_only?).to be_falsey
|
||||
end
|
||||
|
||||
it 'handles Gitlab::Git::CommandError' do
|
||||
expect(project).to receive(:write_repository_config).and_raise(Gitlab::Git::CommandError)
|
||||
|
||||
expect { service.execute }.not_to raise_exception
|
||||
end
|
||||
|
||||
it 'ensures rollback when Gitlab::Git::CommandError' do
|
||||
expect(project).to receive(:write_repository_config).and_raise(Gitlab::Git::CommandError)
|
||||
expect(service).to receive(:rollback_folder_move).and_call_original
|
||||
|
||||
service.execute
|
||||
project.reload
|
||||
|
||||
expect(project.legacy_storage?).to be_truthy
|
||||
expect(project.repository_read_only?).to be_falsey
|
||||
end
|
||||
end
|
||||
|
||||
context 'when one move fails' do
|
||||
it 'rollsback repositories to original name' do
|
||||
allow(service).to receive(:move_repository).and_call_original
|
||||
|
|
|
@ -77,6 +77,42 @@ RSpec.describe Projects::HashedStorage::RollbackRepositoryService, :clean_gitlab
|
|||
end
|
||||
end
|
||||
|
||||
context 'when exception happens' do
|
||||
it 'handles OpenSSL::Cipher::CipherError' do
|
||||
expect(project).to receive(:ensure_runners_token).and_raise(OpenSSL::Cipher::CipherError)
|
||||
|
||||
expect { service.execute }.not_to raise_exception
|
||||
end
|
||||
|
||||
it 'ensures rollback when OpenSSL::Cipher::CipherError' do
|
||||
expect(project).to receive(:ensure_runners_token).and_raise(OpenSSL::Cipher::CipherError)
|
||||
expect(service).to receive(:rollback_folder_move).and_call_original
|
||||
|
||||
service.execute
|
||||
project.reload
|
||||
|
||||
expect(project.hashed_storage?(:repository)).to be_truthy
|
||||
expect(project.repository_read_only?).to be_falsey
|
||||
end
|
||||
|
||||
it 'handles Gitlab::Git::CommandError' do
|
||||
expect(project).to receive(:write_repository_config).and_raise(Gitlab::Git::CommandError)
|
||||
|
||||
expect { service.execute }.not_to raise_exception
|
||||
end
|
||||
|
||||
it 'ensures rollback when Gitlab::Git::CommandError' do
|
||||
expect(project).to receive(:write_repository_config).and_raise(Gitlab::Git::CommandError)
|
||||
expect(service).to receive(:rollback_folder_move).and_call_original
|
||||
|
||||
service.execute
|
||||
project.reload
|
||||
|
||||
expect(project.hashed_storage?(:repository)).to be_truthy
|
||||
expect(project.repository_read_only?).to be_falsey
|
||||
end
|
||||
end
|
||||
|
||||
context 'when one move fails' do
|
||||
it 'rolls repositories back to original name' do
|
||||
allow(service).to receive(:move_repository).and_call_original
|
||||
|
|
Loading…
Reference in a new issue