Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
22e60f1c61
commit
b158645575
57 changed files with 917 additions and 306 deletions
|
@ -3,7 +3,6 @@ import SecretValues from '~/behaviors/secret_values';
|
|||
import AjaxVariableList from '~/ci_variable_list/ajax_variable_list';
|
||||
import registrySettingsApp from '~/registry/settings/registry_settings_bundle';
|
||||
import initVariableList from '~/ci_variable_list';
|
||||
import DueDateSelectors from '~/due_date_select';
|
||||
import initDeployKeys from '~/deploy_keys';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
|
@ -41,9 +40,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
autoDevOpsExtraSettings.classList.toggle('hidden', !target.checked);
|
||||
});
|
||||
|
||||
// eslint-disable-next-line no-new
|
||||
new DueDateSelectors();
|
||||
|
||||
registrySettingsApp();
|
||||
initDeployKeys();
|
||||
});
|
||||
|
|
|
@ -47,7 +47,7 @@ class Clusters::ApplicationsController < Clusters::BaseController
|
|||
end
|
||||
|
||||
def cluster_application_params
|
||||
params.permit(:application, :hostname, :pages_domain_id, :email, :stack, :modsecurity_enabled, :modsecurity_mode, :host, :port, :protocol)
|
||||
params.permit(:application, :hostname, :pages_domain_id, :email, :stack, :modsecurity_enabled, :modsecurity_mode, :host, :port, :protocol, :waf_log_enabled, :cilium_log_enabled)
|
||||
end
|
||||
|
||||
def cluster_application_destroy_params
|
||||
|
|
|
@ -7,6 +7,6 @@ class Projects::DeployTokensController < Projects::ApplicationController
|
|||
@token = @project.deploy_tokens.find(params[:id])
|
||||
@token.revoke!
|
||||
|
||||
redirect_to project_settings_ci_cd_path(project, anchor: 'js-deploy-tokens')
|
||||
redirect_to project_settings_repository_path(project, anchor: 'js-deploy-tokens')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -48,33 +48,6 @@ module Projects
|
|||
redirect_to namespace_project_settings_ci_cd_path
|
||||
end
|
||||
|
||||
def create_deploy_token
|
||||
result = Projects::DeployTokens::CreateService.new(@project, current_user, deploy_token_params).execute
|
||||
@new_deploy_token = result[:deploy_token]
|
||||
|
||||
if result[:status] == :success
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
# IMPORTANT: It's a security risk to expose the token value more than just once here!
|
||||
json = API::Entities::DeployTokenWithToken.represent(@new_deploy_token).as_json
|
||||
render json: json, status: result[:http_status]
|
||||
end
|
||||
format.html do
|
||||
flash.now[:notice] = s_('DeployTokens|Your new project deploy token has been created.')
|
||||
render :show
|
||||
end
|
||||
end
|
||||
else
|
||||
respond_to do |format|
|
||||
format.json { render json: { message: result[:message] }, status: result[:http_status] }
|
||||
format.html do
|
||||
flash.now[:alert] = result[:message]
|
||||
render :show
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def update_params
|
||||
|
@ -93,10 +66,6 @@ module Projects
|
|||
end
|
||||
end
|
||||
|
||||
def deploy_token_params
|
||||
params.require(:deploy_token).permit(:name, :expires_at, :read_repository, :read_registry, :write_registry, :username)
|
||||
end
|
||||
|
||||
def run_autodevops_pipeline(service)
|
||||
return unless service.run_auto_devops_pipeline?
|
||||
|
||||
|
@ -116,7 +85,6 @@ module Projects
|
|||
def define_variables
|
||||
define_runners_variables
|
||||
define_ci_variables
|
||||
define_deploy_token_variables
|
||||
define_triggers_variables
|
||||
define_badges_variables
|
||||
define_auto_devops_variables
|
||||
|
@ -168,12 +136,6 @@ module Projects
|
|||
@auto_devops = @project.auto_devops || ProjectAutoDevops.new
|
||||
end
|
||||
|
||||
def define_deploy_token_variables
|
||||
@deploy_tokens = @project.deploy_tokens.active
|
||||
|
||||
@new_deploy_token = DeployToken.new
|
||||
end
|
||||
|
||||
def define_deploy_keys
|
||||
@deploy_keys = DeployKeysPresenter.new(@project, current_user: current_user)
|
||||
end
|
||||
|
|
|
@ -4,7 +4,10 @@ module Projects
|
|||
module Settings
|
||||
class RepositoryController < Projects::ApplicationController
|
||||
before_action :authorize_admin_project!
|
||||
before_action :remote_mirror, only: [:show]
|
||||
before_action :define_variables, only: [:create_deploy_token]
|
||||
before_action do
|
||||
push_frontend_feature_flag(:ajax_new_deploy_token, @project)
|
||||
end
|
||||
|
||||
def show
|
||||
render_show
|
||||
|
@ -24,15 +27,47 @@ module Projects
|
|||
redirect_to project_settings_repository_path(project)
|
||||
end
|
||||
|
||||
def create_deploy_token
|
||||
result = Projects::DeployTokens::CreateService.new(@project, current_user, deploy_token_params).execute
|
||||
@new_deploy_token = result[:deploy_token]
|
||||
|
||||
if result[:status] == :success
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
# IMPORTANT: It's a security risk to expose the token value more than just once here!
|
||||
json = API::Entities::DeployTokenWithToken.represent(@new_deploy_token).as_json
|
||||
render json: json, status: result[:http_status]
|
||||
end
|
||||
format.html do
|
||||
flash.now[:notice] = s_('DeployTokens|Your new project deploy token has been created.')
|
||||
render :show
|
||||
end
|
||||
end
|
||||
else
|
||||
respond_to do |format|
|
||||
format.json { render json: { message: result[:message] }, status: result[:http_status] }
|
||||
format.html do
|
||||
flash.now[:alert] = result[:message]
|
||||
render :show
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def render_show
|
||||
define_protected_refs
|
||||
remote_mirror
|
||||
define_variables
|
||||
|
||||
render 'show'
|
||||
end
|
||||
|
||||
def define_variables
|
||||
define_deploy_token_variables
|
||||
define_protected_refs
|
||||
remote_mirror
|
||||
end
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def define_protected_refs
|
||||
@protected_branches = @project.protected_branches.order(:name).page(params[:page])
|
||||
|
@ -51,6 +86,10 @@ module Projects
|
|||
@remote_mirror = project.remote_mirrors.first_or_initialize
|
||||
end
|
||||
|
||||
def deploy_token_params
|
||||
params.require(:deploy_token).permit(:name, :expires_at, :read_repository, :read_registry, :write_registry, :username)
|
||||
end
|
||||
|
||||
def access_levels_options
|
||||
{
|
||||
create_access_levels: levels_for_dropdown,
|
||||
|
@ -74,6 +113,12 @@ module Projects
|
|||
{ open_branches: ProtectableDropdown.new(@project, :branches).hash }
|
||||
end
|
||||
|
||||
def define_deploy_token_variables
|
||||
@deploy_tokens = @project.deploy_tokens.active
|
||||
|
||||
@new_deploy_token ||= DeployToken.new
|
||||
end
|
||||
|
||||
def load_gon_index
|
||||
gon.push(protectable_tags_for_dropdown)
|
||||
gon.push(protectable_branches_for_dropdown)
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
module EnvironmentsHelper
|
||||
include ActionView::Helpers::AssetUrlHelper
|
||||
prepend_if_ee('::EE::EnvironmentsHelper') # rubocop: disable Cop/InjectEnterpriseEditionModule
|
||||
|
||||
def environments_list_data
|
||||
{
|
||||
|
@ -65,3 +64,5 @@ module EnvironmentsHelper
|
|||
can?(current_user, :destroy_environment, environment)
|
||||
end
|
||||
end
|
||||
|
||||
EnvironmentsHelper.prepend_if_ee('::EE::EnvironmentsHelper')
|
||||
|
|
62
app/models/alert_management/alert.rb
Normal file
62
app/models/alert_management/alert.rb
Normal file
|
@ -0,0 +1,62 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module AlertManagement
|
||||
class Alert < ApplicationRecord
|
||||
include AtomicInternalId
|
||||
include ShaAttribute
|
||||
|
||||
belongs_to :project
|
||||
belongs_to :issue, optional: true
|
||||
has_internal_id :iid, scope: :project, init: ->(s) { s.project.alert_management_alerts.maximum(:iid) }
|
||||
|
||||
self.table_name = 'alert_management_alerts'
|
||||
|
||||
sha_attribute :fingerprint
|
||||
|
||||
HOSTS_MAX_LENGTH = 255
|
||||
|
||||
validates :title, length: { maximum: 200 }, presence: true
|
||||
validates :description, length: { maximum: 1_000 }
|
||||
validates :service, length: { maximum: 100 }
|
||||
validates :monitoring_tool, length: { maximum: 100 }
|
||||
validates :project, presence: true
|
||||
validates :events, presence: true
|
||||
validates :severity, presence: true
|
||||
validates :status, presence: true
|
||||
validates :started_at, presence: true
|
||||
validates :fingerprint, uniqueness: { scope: :project }, allow_blank: true
|
||||
validate :hosts_length
|
||||
|
||||
enum severity: {
|
||||
critical: 0,
|
||||
high: 1,
|
||||
medium: 2,
|
||||
low: 3,
|
||||
info: 4,
|
||||
unknown: 5
|
||||
}
|
||||
|
||||
enum status: {
|
||||
triggered: 0,
|
||||
acknowledged: 1,
|
||||
resolved: 2,
|
||||
ignored: 3
|
||||
}
|
||||
|
||||
def fingerprint=(value)
|
||||
if value.blank?
|
||||
super(nil)
|
||||
else
|
||||
super(Digest::SHA1.hexdigest(value.to_s))
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def hosts_length
|
||||
return unless hosts
|
||||
|
||||
errors.add(:hosts, "hosts array is over #{HOSTS_MAX_LENGTH} chars") if hosts.join.length > HOSTS_MAX_LENGTH
|
||||
end
|
||||
end
|
||||
end
|
|
@ -4,6 +4,7 @@ module Clusters
|
|||
module Applications
|
||||
class Fluentd < ApplicationRecord
|
||||
VERSION = '2.4.0'
|
||||
CILIUM_CONTAINER_NAME = 'cilium-monitor'
|
||||
|
||||
self.table_name = 'clusters_applications_fluentd'
|
||||
|
||||
|
@ -18,6 +19,8 @@ module Clusters
|
|||
|
||||
enum protocol: { tcp: 0, udp: 1 }
|
||||
|
||||
validate :has_at_least_one_log_enabled?
|
||||
|
||||
def chart
|
||||
'stable/fluentd'
|
||||
end
|
||||
|
@ -39,6 +42,12 @@ module Clusters
|
|||
|
||||
private
|
||||
|
||||
def has_at_least_one_log_enabled?
|
||||
if !waf_log_enabled && !cilium_log_enabled
|
||||
errors.add(:base, _("At least one logging option is required to be enabled"))
|
||||
end
|
||||
end
|
||||
|
||||
def content_values
|
||||
YAML.load_file(chart_values_file).deep_merge!(specification)
|
||||
end
|
||||
|
@ -62,7 +71,7 @@ module Clusters
|
|||
program fluentd
|
||||
hostname ${kubernetes_host}
|
||||
protocol #{protocol}
|
||||
packet_size 65535
|
||||
packet_size 131072
|
||||
<buffer kubernetes_host>
|
||||
</buffer>
|
||||
<format>
|
||||
|
@ -85,7 +94,7 @@ module Clusters
|
|||
<source>
|
||||
@type tail
|
||||
@id in_tail_container_logs
|
||||
path /var/log/containers/*#{Ingress::MODSECURITY_LOG_CONTAINER_NAME}*.log
|
||||
path #{path_to_logs}
|
||||
pos_file /var/log/fluentd-containers.log.pos
|
||||
tag kubernetes.*
|
||||
read_from_head true
|
||||
|
@ -96,6 +105,13 @@ module Clusters
|
|||
</source>
|
||||
EOF
|
||||
end
|
||||
|
||||
def path_to_logs
|
||||
path = []
|
||||
path << "/var/log/containers/*#{Ingress::MODSECURITY_LOG_CONTAINER_NAME}*.log" if waf_log_enabled
|
||||
path << "/var/log/containers/*#{CILIUM_CONTAINER_NAME}*.log" if cilium_log_enabled
|
||||
path.join(',')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
module InternalIdEnums
|
||||
def self.usage_resources
|
||||
# when adding new resource, make sure it doesn't conflict with EE usage_resources
|
||||
{ issues: 0, merge_requests: 1, deployments: 2, milestones: 3, epics: 4, ci_pipelines: 5, operations_feature_flags: 6, operations_user_lists: 7 }
|
||||
{ issues: 0, merge_requests: 1, deployments: 2, milestones: 3, epics: 4, ci_pipelines: 5, operations_feature_flags: 6, operations_user_lists: 7, alert_management_alerts: 8 }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ class Issue < ApplicationRecord
|
|||
has_many :sent_notifications, as: :noteable
|
||||
|
||||
has_one :sentry_issue
|
||||
has_one :alert_management_alert, class_name: 'AlertManagement::Alert'
|
||||
|
||||
accepts_nested_attributes_for :sentry_issue
|
||||
|
||||
|
|
|
@ -257,6 +257,8 @@ class Project < ApplicationRecord
|
|||
has_many :prometheus_alert_events, inverse_of: :project
|
||||
has_many :self_managed_prometheus_alert_events, inverse_of: :project
|
||||
|
||||
has_many :alert_management_alerts, class_name: 'AlertManagement::Alert', inverse_of: :project
|
||||
|
||||
# Container repositories need to remove data from the container registry,
|
||||
# which is not managed by the DB. Hence we're still using dependent: :destroy
|
||||
# here.
|
||||
|
@ -2368,7 +2370,7 @@ class Project < ApplicationRecord
|
|||
end
|
||||
|
||||
def deploy_token_create_url(opts = {})
|
||||
Gitlab::Routing.url_helpers.create_deploy_token_project_settings_ci_cd_path(self, opts)
|
||||
Gitlab::Routing.url_helpers.create_deploy_token_project_settings_repository_path(self, opts)
|
||||
end
|
||||
|
||||
def deploy_token_revoke_url_for(token)
|
||||
|
|
|
@ -19,4 +19,6 @@ class ClusterApplicationEntity < Grape::Entity
|
|||
expose :host, if: -> (e, _) { e.respond_to?(:host) }
|
||||
expose :port, if: -> (e, _) { e.respond_to?(:port) }
|
||||
expose :protocol, if: -> (e, _) { e.respond_to?(:protocol) }
|
||||
expose :waf_log_enabled, if: -> (e, _) { e.respond_to?(:waf_log_enabled) }
|
||||
expose :cilium_log_enabled, if: -> (e, _) { e.respond_to?(:cilium_log_enabled) }
|
||||
end
|
||||
|
|
|
@ -5,6 +5,8 @@ module Clusters
|
|||
class BaseService
|
||||
InvalidApplicationError = Class.new(StandardError)
|
||||
|
||||
FLUENTD_KNOWN_ATTRS = %i[host protocol port waf_log_enabled cilium_log_enabled].freeze
|
||||
|
||||
attr_reader :cluster, :current_user, :params
|
||||
|
||||
def initialize(cluster, user, params = {})
|
||||
|
@ -35,17 +37,7 @@ module Clusters
|
|||
application.modsecurity_mode = params[:modsecurity_mode] || 0
|
||||
end
|
||||
|
||||
if application.has_attribute?(:host)
|
||||
application.host = params[:host]
|
||||
end
|
||||
|
||||
if application.has_attribute?(:protocol)
|
||||
application.protocol = params[:protocol]
|
||||
end
|
||||
|
||||
if application.has_attribute?(:port)
|
||||
application.port = params[:port]
|
||||
end
|
||||
apply_fluentd_related_attributes(application)
|
||||
|
||||
if application.respond_to?(:oauth_application)
|
||||
application.oauth_application = create_oauth_application(application, request)
|
||||
|
@ -111,6 +103,12 @@ module Clusters
|
|||
|
||||
::Applications::CreateService.new(current_user, oauth_application_params).execute(request)
|
||||
end
|
||||
|
||||
def apply_fluentd_related_attributes(application)
|
||||
FLUENTD_KNOWN_ATTRS.each do |attr|
|
||||
application[attr] = params[attr] if application.has_attribute?(attr)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
- expanded = expanded_by_default?
|
||||
- general_expanded = @project.errors.empty? ? expanded : true
|
||||
- deploy_token_description = s_('DeployTokens|Deploy tokens allow access to your repository and registry images.')
|
||||
|
||||
%section.settings#js-general-pipeline-settings.no-animate{ class: ('expanded' if general_expanded) }
|
||||
.settings-header
|
||||
|
@ -52,8 +51,6 @@
|
|||
.settings-content
|
||||
= render 'ci/variables/index', save_endpoint: project_variables_path(@project)
|
||||
|
||||
= render "shared/deploy_tokens/index", group_or_project: @project, description: deploy_token_description
|
||||
|
||||
= render @deploy_keys
|
||||
|
||||
%section.settings.no-animate#js-pipeline-triggers{ class: ('expanded' if expanded) }
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
- breadcrumb_title _("Repository Settings")
|
||||
- page_title _("Repository")
|
||||
- @content_class = "limit-container-width" unless fluid_layout
|
||||
- deploy_token_description = s_('DeployTokens|Deploy tokens allow access to your repository and registry images.')
|
||||
|
||||
= render "projects/default_branch/show"
|
||||
= render_if_exists "projects/push_rules/index"
|
||||
|
@ -11,6 +12,7 @@
|
|||
-# Those are used throughout the actual views. These `shared` views are then
|
||||
-# reused in EE.
|
||||
= render "projects/settings/repository/protected_branches"
|
||||
= render "shared/deploy_tokens/index", group_or_project: @project, description: deploy_token_description
|
||||
= render "projects/cleanup/show"
|
||||
|
||||
= render_if_exists 'shared/promotions/promote_repository_features'
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add table for Alert Management alerts
|
||||
merge_request: 29864
|
||||
author:
|
||||
type: added
|
5
changelogs/unreleased/ph-214480-copyUploadLinks.yml
Normal file
5
changelogs/unreleased/ph-214480-copyUploadLinks.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fixed copy as GFM not copying upload links
|
||||
merge_request: 29683
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Remove obsolete columns from resource_milestone_events
|
||||
merge_request: 28536
|
||||
author:
|
||||
type: other
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Update Fluentd model to support multiple logs
|
||||
merge_request: 29458
|
||||
author:
|
||||
type: changed
|
|
@ -73,7 +73,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
|
|||
resource :ci_cd, only: [:show, :update], controller: 'ci_cd' do
|
||||
post :reset_cache
|
||||
put :reset_registration_token
|
||||
post :create_deploy_token, path: 'deploy_token/create'
|
||||
post :create_deploy_token, path: 'deploy_token/create', to: 'repository#create_deploy_token'
|
||||
end
|
||||
|
||||
resource :operations, only: [:show, :update] do
|
||||
|
@ -87,7 +87,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
|
|||
resource :repository, only: [:show], controller: :repository do
|
||||
# TODO: Removed this "create_deploy_token" route after change was made in app/helpers/ci_variables_helper.rb:14
|
||||
# See MR comment for more detail: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/27059#note_311585356
|
||||
post :create_deploy_token, path: 'deploy_token/create', to: 'ci_cd#create_deploy_token'
|
||||
post :create_deploy_token, path: 'deploy_token/create'
|
||||
post :cleanup
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddGroupIdToVulnerabilityExports < ActiveRecord::Migration[6.0]
|
||||
DOWNTIME = false
|
||||
|
||||
def change
|
||||
add_column :vulnerability_exports, :group_id, :integer
|
||||
change_column_null :vulnerability_exports, :project_id, true
|
||||
end
|
||||
end
|
|
@ -0,0 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddGroupIdIndexAndFkToVulnerabilityExports < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
DOWNTIME = false
|
||||
GROUP_ID_INDEX_NAME = 'index_vulnerability_exports_on_group_id_not_null'
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
add_concurrent_index(:vulnerability_exports, :group_id, where: 'group_id IS NOT NULL', name: GROUP_ID_INDEX_NAME)
|
||||
add_concurrent_foreign_key(:vulnerability_exports, :namespaces, column: :group_id)
|
||||
end
|
||||
|
||||
def down
|
||||
remove_foreign_key(:vulnerability_exports, column: :group_id)
|
||||
remove_concurrent_index_by_name(:vulnerability_exports, GROUP_ID_INDEX_NAME)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ChangeProjectIndexOnVulnerabilityExports < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
DOWNTIME = false
|
||||
OLD_INDEX_NAME = 'index_vulnerability_exports_on_project_id_and_id'
|
||||
NEW_INDEX_NAME = 'index_vulnerability_exports_on_project_id_not_null'
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
add_concurrent_index(:vulnerability_exports, :project_id, where: 'project_id IS NOT NULL', name: NEW_INDEX_NAME)
|
||||
remove_concurrent_index_by_name(:vulnerability_exports, OLD_INDEX_NAME)
|
||||
end
|
||||
|
||||
def down
|
||||
add_concurrent_index(:vulnerability_exports, [:project_id, :id], unique: true, name: OLD_INDEX_NAME)
|
||||
remove_concurrent_index_by_name(:vulnerability_exports, NEW_INDEX_NAME)
|
||||
end
|
||||
end
|
44
db/migrate/20200417044453_create_alert_management_alerts.rb
Normal file
44
db/migrate/20200417044453_create_alert_management_alerts.rb
Normal file
|
@ -0,0 +1,44 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CreateAlertManagementAlerts < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
DOWNTIME = false
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
unless table_exists?(:alert_management_alerts)
|
||||
create_table :alert_management_alerts do |t|
|
||||
t.timestamps_with_timezone
|
||||
t.datetime_with_timezone :started_at, null: false
|
||||
t.datetime_with_timezone :ended_at
|
||||
t.integer :events, default: 1, null: false
|
||||
t.integer :iid, null: false
|
||||
t.integer :severity, default: 0, null: false, limit: 2
|
||||
t.integer :status, default: 0, null: false, limit: 2
|
||||
t.binary :fingerprint
|
||||
t.bigint :issue_id, index: true
|
||||
t.bigint :project_id, null: false
|
||||
t.text :title, null: false
|
||||
t.text :description
|
||||
t.text :service
|
||||
t.text :monitoring_tool
|
||||
t.text :hosts, array: true, null: false, default: [] # rubocop:disable Migration/AddLimitToTextColumns
|
||||
t.jsonb :payload, null: false, default: {}
|
||||
|
||||
t.index %w(project_id iid), name: 'index_alert_management_alerts_on_project_id_and_iid', unique: true, using: :btree
|
||||
t.index %w(project_id fingerprint), name: 'index_alert_management_alerts_on_project_id_and_fingerprint', unique: true, using: :btree
|
||||
end
|
||||
end
|
||||
|
||||
add_text_limit :alert_management_alerts, :title, 200
|
||||
add_text_limit :alert_management_alerts, :description, 1000
|
||||
add_text_limit :alert_management_alerts, :service, 100
|
||||
add_text_limit :alert_management_alerts, :monitoring_tool, 100
|
||||
end
|
||||
|
||||
def down
|
||||
drop_table :alert_management_alerts
|
||||
end
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddForeignKeysForAlertManagementAlerts < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
DOWNTIME = false
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
add_concurrent_foreign_key :alert_management_alerts, :projects, column: :project_id, on_delete: :cascade
|
||||
add_concurrent_foreign_key :alert_management_alerts, :issues, column: :issue_id, on_delete: :nullify
|
||||
end
|
||||
|
||||
def down
|
||||
remove_foreign_key_if_exists :alert_management_alerts, column: :project_id
|
||||
remove_foreign_key_if_exists :alert_management_alerts, column: :issue_id
|
||||
end
|
||||
end
|
|
@ -0,0 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class RemoveReferenceColumnsFromResourceMilestoneEvents < ActiveRecord::Migration[6.0]
|
||||
DOWNTIME = false
|
||||
|
||||
def change
|
||||
remove_column :resource_milestone_events, :reference, :text
|
||||
remove_column :resource_milestone_events, :reference_html, :text
|
||||
remove_column :resource_milestone_events, :cached_markdown_version, :integer
|
||||
end
|
||||
end
|
|
@ -24,6 +24,40 @@ CREATE SEQUENCE public.abuse_reports_id_seq
|
|||
|
||||
ALTER SEQUENCE public.abuse_reports_id_seq OWNED BY public.abuse_reports.id;
|
||||
|
||||
CREATE TABLE public.alert_management_alerts (
|
||||
id bigint NOT NULL,
|
||||
created_at timestamp with time zone NOT NULL,
|
||||
updated_at timestamp with time zone NOT NULL,
|
||||
started_at timestamp with time zone NOT NULL,
|
||||
ended_at timestamp with time zone,
|
||||
events integer DEFAULT 1 NOT NULL,
|
||||
iid integer NOT NULL,
|
||||
severity smallint DEFAULT 0 NOT NULL,
|
||||
status smallint DEFAULT 0 NOT NULL,
|
||||
fingerprint bytea,
|
||||
issue_id bigint,
|
||||
project_id bigint NOT NULL,
|
||||
title text NOT NULL,
|
||||
description text,
|
||||
service text,
|
||||
monitoring_tool text,
|
||||
hosts text[] DEFAULT '{}'::text[] NOT NULL,
|
||||
payload jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
CONSTRAINT check_2df3e2fdc1 CHECK ((char_length(monitoring_tool) <= 100)),
|
||||
CONSTRAINT check_5e9e57cadb CHECK ((char_length(description) <= 1000)),
|
||||
CONSTRAINT check_bac14dddde CHECK ((char_length(service) <= 100)),
|
||||
CONSTRAINT check_d1d1c2d14c CHECK ((char_length(title) <= 200))
|
||||
);
|
||||
|
||||
CREATE SEQUENCE public.alert_management_alerts_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
ALTER SEQUENCE public.alert_management_alerts_id_seq OWNED BY public.alert_management_alerts.id;
|
||||
|
||||
CREATE TABLE public.alerts_service_data (
|
||||
id bigint NOT NULL,
|
||||
service_id integer NOT NULL,
|
||||
|
@ -5597,9 +5631,6 @@ CREATE TABLE public.resource_milestone_events (
|
|||
milestone_id bigint,
|
||||
action smallint NOT NULL,
|
||||
state smallint NOT NULL,
|
||||
cached_markdown_version integer,
|
||||
reference text,
|
||||
reference_html text,
|
||||
created_at timestamp with time zone NOT NULL
|
||||
);
|
||||
|
||||
|
@ -6661,10 +6692,11 @@ CREATE TABLE public.vulnerability_exports (
|
|||
finished_at timestamp with time zone,
|
||||
status character varying(255) NOT NULL,
|
||||
file character varying(255),
|
||||
project_id bigint NOT NULL,
|
||||
project_id bigint,
|
||||
author_id bigint NOT NULL,
|
||||
file_store integer,
|
||||
format smallint DEFAULT 0 NOT NULL
|
||||
format smallint DEFAULT 0 NOT NULL,
|
||||
group_id integer
|
||||
);
|
||||
|
||||
CREATE SEQUENCE public.vulnerability_exports_id_seq
|
||||
|
@ -7014,6 +7046,8 @@ ALTER SEQUENCE public.zoom_meetings_id_seq OWNED BY public.zoom_meetings.id;
|
|||
|
||||
ALTER TABLE ONLY public.abuse_reports ALTER COLUMN id SET DEFAULT nextval('public.abuse_reports_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY public.alert_management_alerts ALTER COLUMN id SET DEFAULT nextval('public.alert_management_alerts_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY public.alerts_service_data ALTER COLUMN id SET DEFAULT nextval('public.alerts_service_data_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY public.allowed_email_domains ALTER COLUMN id SET DEFAULT nextval('public.allowed_email_domains_id_seq'::regclass);
|
||||
|
@ -7623,6 +7657,9 @@ ALTER TABLE ONLY public.zoom_meetings ALTER COLUMN id SET DEFAULT nextval('publi
|
|||
ALTER TABLE ONLY public.abuse_reports
|
||||
ADD CONSTRAINT abuse_reports_pkey PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE ONLY public.alert_management_alerts
|
||||
ADD CONSTRAINT alert_management_alerts_pkey PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE ONLY public.alerts_service_data
|
||||
ADD CONSTRAINT alerts_service_data_pkey PRIMARY KEY (id);
|
||||
|
||||
|
@ -8686,6 +8723,12 @@ CREATE UNIQUE INDEX idx_vulnerability_issue_links_on_vulnerability_id_and_link_t
|
|||
|
||||
CREATE INDEX index_abuse_reports_on_user_id ON public.abuse_reports USING btree (user_id);
|
||||
|
||||
CREATE INDEX index_alert_management_alerts_on_issue_id ON public.alert_management_alerts USING btree (issue_id);
|
||||
|
||||
CREATE UNIQUE INDEX index_alert_management_alerts_on_project_id_and_fingerprint ON public.alert_management_alerts USING btree (project_id, fingerprint);
|
||||
|
||||
CREATE UNIQUE INDEX index_alert_management_alerts_on_project_id_and_iid ON public.alert_management_alerts USING btree (project_id, iid);
|
||||
|
||||
CREATE INDEX index_alerts_service_data_on_service_id ON public.alerts_service_data USING btree (service_id);
|
||||
|
||||
CREATE INDEX index_allowed_email_domains_on_group_id ON public.allowed_email_domains USING btree (group_id);
|
||||
|
@ -10442,7 +10485,9 @@ CREATE INDEX index_vulnerabilities_on_updated_by_id ON public.vulnerabilities US
|
|||
|
||||
CREATE INDEX index_vulnerability_exports_on_author_id ON public.vulnerability_exports USING btree (author_id);
|
||||
|
||||
CREATE UNIQUE INDEX index_vulnerability_exports_on_project_id_and_id ON public.vulnerability_exports USING btree (project_id, id);
|
||||
CREATE INDEX index_vulnerability_exports_on_group_id_not_null ON public.vulnerability_exports USING btree (group_id) WHERE (group_id IS NOT NULL);
|
||||
|
||||
CREATE INDEX index_vulnerability_exports_on_project_id_not_null ON public.vulnerability_exports USING btree (project_id) WHERE (project_id IS NOT NULL);
|
||||
|
||||
CREATE INDEX index_vulnerability_feedback_on_author_id ON public.vulnerability_feedback USING btree (author_id);
|
||||
|
||||
|
@ -10639,6 +10684,9 @@ ALTER TABLE ONLY public.geo_container_repository_updated_events
|
|||
ALTER TABLE ONLY public.users_star_projects
|
||||
ADD CONSTRAINT fk_22cd27ddfc FOREIGN KEY (project_id) REFERENCES public.projects(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY public.alert_management_alerts
|
||||
ADD CONSTRAINT fk_2358b75436 FOREIGN KEY (issue_id) REFERENCES public.issues(id) ON DELETE SET NULL;
|
||||
|
||||
ALTER TABLE ONLY public.ci_stages
|
||||
ADD CONSTRAINT fk_2360681d1d FOREIGN KEY (project_id) REFERENCES public.projects(id) ON DELETE CASCADE;
|
||||
|
||||
|
@ -10894,6 +10942,9 @@ ALTER TABLE ONLY public.issues
|
|||
ALTER TABLE ONLY public.epics
|
||||
ADD CONSTRAINT fk_9d480c64b2 FOREIGN KEY (start_date_sourcing_epic_id) REFERENCES public.epics(id) ON DELETE SET NULL;
|
||||
|
||||
ALTER TABLE ONLY public.alert_management_alerts
|
||||
ADD CONSTRAINT fk_9e49e5c2b7 FOREIGN KEY (project_id) REFERENCES public.projects(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY public.ci_pipeline_schedules
|
||||
ADD CONSTRAINT fk_9ea99f58d2 FOREIGN KEY (owner_id) REFERENCES public.users(id) ON DELETE SET NULL;
|
||||
|
||||
|
@ -10975,6 +11026,9 @@ ALTER TABLE ONLY public.design_management_versions
|
|||
ALTER TABLE ONLY public.geo_event_log
|
||||
ADD CONSTRAINT fk_c1f241c70d FOREIGN KEY (upload_deleted_event_id) REFERENCES public.geo_upload_deleted_events(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY public.vulnerability_exports
|
||||
ADD CONSTRAINT fk_c3d3cb5d0f FOREIGN KEY (group_id) REFERENCES public.namespaces(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY public.geo_event_log
|
||||
ADD CONSTRAINT fk_c4b1c1f66e FOREIGN KEY (repository_deleted_event_id) REFERENCES public.geo_repository_deleted_events(id) ON DELETE CASCADE;
|
||||
|
||||
|
@ -13212,6 +13266,7 @@ COPY "schema_migrations" (version) FROM STDIN;
|
|||
20200331132103
|
||||
20200331195952
|
||||
20200331220930
|
||||
20200401091051
|
||||
20200401095430
|
||||
20200401211005
|
||||
20200402123926
|
||||
|
@ -13257,6 +13312,9 @@ COPY "schema_migrations" (version) FROM STDIN;
|
|||
20200411125656
|
||||
20200413072059
|
||||
20200413230056
|
||||
20200414112444
|
||||
20200414114611
|
||||
20200414115801
|
||||
20200414144547
|
||||
20200415153154
|
||||
20200415160722
|
||||
|
@ -13266,5 +13324,7 @@ COPY "schema_migrations" (version) FROM STDIN;
|
|||
20200416111111
|
||||
20200416120128
|
||||
20200416120354
|
||||
20200417044453
|
||||
20200421233150
|
||||
\.
|
||||
|
||||
|
|
|
@ -58,6 +58,12 @@ On different cloud vendors a best effort like for like can be used.
|
|||
From 1 to 1,000 users, a single-node [Omnibus](https://docs.gitlab.com/omnibus/) setup with frequent backups is adequate.
|
||||
Please refer to the [installation documentation](../../install/README.md) and [backup/restore documentation](https://docs.gitlab.com/omnibus/settings/backups.html#backup-and-restore-omnibus-gitlab-configuration).
|
||||
|
||||
| Users | Configuration[^8] | GCP type | AWS type[^9] |
|
||||
|-------|----------------------|---------------|--------------|
|
||||
| 100 | 2 vCPU, 7.2GB Memory | n1-standard-2 | c5.2xlarge |
|
||||
| 500 | 4 vCPU, 15GB Memory | n1-standard-4 | m5.xlarge |
|
||||
| 1000 | 8 vCPU, 30GB Memory | n1-standard-8 | m5.2xlarge |
|
||||
|
||||
This solution is appropriate for many teams that have a single server at their disposal. With automatic backup of the GitLab repositories, configuration, and the database, this can be an optimal solution if you don't have strict availability requirements.
|
||||
|
||||
You can also optionally configure GitLab to use an [external PostgreSQL service](../external_database.md) or an [external object storage service](../high_availability/object_storage.md) for added performance and reliability at a relatively low complexity cost.
|
||||
|
|
|
@ -50,6 +50,10 @@ module Banzai
|
|||
Addressable::URI.join(Gitlab.config.gitlab.base_url, path).to_s
|
||||
end
|
||||
|
||||
if html_attr.name == 'href'
|
||||
html_attr.parent.set_attribute('data-link', 'true')
|
||||
end
|
||||
|
||||
html_attr.parent.add_class('gfm')
|
||||
end
|
||||
|
||||
|
|
|
@ -4,14 +4,12 @@ module Gitlab
|
|||
module JiraImport
|
||||
class IssueSerializer
|
||||
attr_reader :jira_issue, :project, :params, :formatter
|
||||
attr_accessor :metadata
|
||||
|
||||
def initialize(project, jira_issue, params = {})
|
||||
@jira_issue = jira_issue
|
||||
@project = project
|
||||
@params = params
|
||||
@formatter = Gitlab::ImportFormatter.new
|
||||
@metadata = []
|
||||
end
|
||||
|
||||
def execute
|
||||
|
@ -38,7 +36,7 @@ module Gitlab
|
|||
body << formatter.author_line(jira_issue.reporter.displayName)
|
||||
body << formatter.assignee_line(jira_issue.assignee.displayName) if jira_issue.assignee
|
||||
body << jira_issue.description
|
||||
body << add_metadata
|
||||
body << MetadataCollector.new(jira_issue).execute
|
||||
|
||||
body.join
|
||||
end
|
||||
|
@ -51,50 +49,6 @@ module Gitlab
|
|||
Issuable::STATE_ID_MAP[:opened]
|
||||
end
|
||||
end
|
||||
|
||||
def add_metadata
|
||||
add_field(%w(issuetype name), 'Issue type')
|
||||
add_field(%w(priority name), 'Priority')
|
||||
add_labels
|
||||
add_field('environment', 'Environment')
|
||||
add_field('duedate', 'Due date')
|
||||
add_parent
|
||||
add_versions
|
||||
|
||||
return if metadata.empty?
|
||||
|
||||
metadata.join("\n").prepend("\n\n---\n\n**Issue metadata**\n\n")
|
||||
end
|
||||
|
||||
def add_field(keys, field_label)
|
||||
value = fields.dig(*keys)
|
||||
return if value.blank?
|
||||
|
||||
metadata << "- #{field_label}: #{value}"
|
||||
end
|
||||
|
||||
def add_labels
|
||||
return if fields['labels'].blank?
|
||||
|
||||
metadata << "- Labels: #{fields['labels'].join(', ')}"
|
||||
end
|
||||
|
||||
def add_parent
|
||||
parent_issue_key = fields.dig('parent', 'key')
|
||||
return if parent_issue_key.blank?
|
||||
|
||||
metadata << "- Parent issue: [#{parent_issue_key}] #{fields['parent']['fields']['summary']}"
|
||||
end
|
||||
|
||||
def add_versions
|
||||
return if fields['fixVersions'].blank?
|
||||
|
||||
metadata << "- Fix versions: #{fields['fixVersions'].map { |version| version['name'] }.join(', ')}"
|
||||
end
|
||||
|
||||
def fields
|
||||
jira_issue.fields
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
60
lib/gitlab/jira_import/metadata_collector.rb
Normal file
60
lib/gitlab/jira_import/metadata_collector.rb
Normal file
|
@ -0,0 +1,60 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module JiraImport
|
||||
class MetadataCollector
|
||||
attr_accessor :jira_issue, :metadata
|
||||
|
||||
def initialize(jira_issue)
|
||||
@jira_issue = jira_issue
|
||||
@metadata = []
|
||||
end
|
||||
|
||||
def execute
|
||||
add_field(%w(issuetype name), 'Issue type')
|
||||
add_field(%w(priority name), 'Priority')
|
||||
add_labels
|
||||
add_field('environment', 'Environment')
|
||||
add_field('duedate', 'Due date')
|
||||
add_parent
|
||||
add_versions
|
||||
|
||||
return if metadata.empty?
|
||||
|
||||
metadata.join("\n").prepend("\n\n---\n\n**Issue metadata**\n\n")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def add_field(keys, field_label)
|
||||
value = fields.dig(*keys)
|
||||
return if value.blank?
|
||||
|
||||
metadata << "- #{field_label}: #{value}"
|
||||
end
|
||||
|
||||
def add_labels
|
||||
return if fields['labels'].blank?
|
||||
|
||||
metadata << "- Labels: #{fields['labels'].join(', ')}"
|
||||
end
|
||||
|
||||
def add_parent
|
||||
parent_issue_key = fields.dig('parent', 'key')
|
||||
return if parent_issue_key.blank?
|
||||
|
||||
metadata << "- Parent issue: [#{parent_issue_key}] #{fields['parent']['fields']['summary']}"
|
||||
end
|
||||
|
||||
def add_versions
|
||||
return if fields['fixVersions'].blank?
|
||||
|
||||
metadata << "- Fix versions: #{fields['fixVersions'].map { |version| version['name'] }.join(', ')}"
|
||||
end
|
||||
|
||||
def fields
|
||||
jira_issue.fields
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -2632,6 +2632,9 @@ msgstr ""
|
|||
msgid "At least one approval from a code owner is required to change files matching the respective CODEOWNER rules."
|
||||
msgstr ""
|
||||
|
||||
msgid "At least one logging option is required to be enabled"
|
||||
msgstr ""
|
||||
|
||||
msgid "At least one of group_id or project_id must be specified"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
source 'https://rubygems.org'
|
||||
|
||||
gem 'gitlab-qa'
|
||||
gem 'activesupport', '6.0.2' # This should stay in sync with the root's Gemfile
|
||||
gem 'activesupport', '~> 6.0.2.2' # This should stay in sync with the root's Gemfile
|
||||
gem 'capybara', '~> 3.29.0'
|
||||
gem 'capybara-screenshot', '~> 1.0.23'
|
||||
gem 'rake', '~> 12.3.0'
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
activesupport (6.0.2)
|
||||
activesupport (6.0.2.2)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 0.7, < 2)
|
||||
minitest (~> 5.1)
|
||||
|
@ -114,7 +114,7 @@ PLATFORMS
|
|||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
activesupport (= 6.0.2)
|
||||
activesupport (~> 6.0.2.2)
|
||||
airborne (~> 0.2.13)
|
||||
capybara (~> 3.29.0)
|
||||
capybara-screenshot (~> 1.0.23)
|
||||
|
|
|
@ -9,6 +9,15 @@ module QA
|
|||
element :assignee_link
|
||||
end
|
||||
|
||||
view 'app/views/projects/issues/export_csv/_button.html.haml' do
|
||||
element :export_as_csv_button
|
||||
end
|
||||
|
||||
view 'app/views/projects/issues/export_csv/_modal.html.haml' do
|
||||
element :export_issues_button
|
||||
element :export_issues_modal
|
||||
end
|
||||
|
||||
view 'app/views/projects/issues/_issue.html.haml' do
|
||||
element :issue
|
||||
element :issue_link, 'link_to issue.title' # rubocop:disable QA/ElementWithPattern
|
||||
|
@ -34,6 +43,18 @@ module QA
|
|||
click_element :closed_issues_link
|
||||
end
|
||||
|
||||
def click_export_as_csv_button
|
||||
click_element(:export_as_csv_button)
|
||||
end
|
||||
|
||||
def click_export_issues_button
|
||||
click_element(:export_issues_button)
|
||||
end
|
||||
|
||||
def export_issues_modal
|
||||
find_element(:export_issues_modal)
|
||||
end
|
||||
|
||||
def has_assignee_link_count?(count)
|
||||
all_elements(:assignee_link, count: count)
|
||||
end
|
||||
|
|
|
@ -13,20 +13,10 @@ module QA
|
|||
element :variables_settings_content
|
||||
end
|
||||
|
||||
view 'app/views/shared/deploy_tokens/_index.html.haml' do
|
||||
element :deploy_tokens_settings
|
||||
end
|
||||
|
||||
view 'app/views/projects/deploy_keys/_index.html.haml' do
|
||||
element :deploy_keys_settings
|
||||
end
|
||||
|
||||
def expand_deploy_tokens(&block)
|
||||
expand_section(:deploy_tokens_settings) do
|
||||
Settings::DeployTokens.perform(&block)
|
||||
end
|
||||
end
|
||||
|
||||
def expand_deploy_keys(&block)
|
||||
expand_section(:deploy_keys_settings) do
|
||||
Settings::DeployKeys.perform(&block)
|
||||
|
|
|
@ -15,6 +15,16 @@ module QA
|
|||
element :mirroring_repositories_settings_section
|
||||
end
|
||||
|
||||
view 'app/views/shared/deploy_tokens/_index.html.haml' do
|
||||
element :deploy_tokens_settings
|
||||
end
|
||||
|
||||
def expand_deploy_tokens(&block)
|
||||
expand_section(:deploy_tokens_settings) do
|
||||
Settings::DeployTokens.perform(&block)
|
||||
end
|
||||
end
|
||||
|
||||
def expand_protected_branches(&block)
|
||||
expand_section(:protected_branches_settings) do
|
||||
ProtectedBranches.perform(&block)
|
||||
|
|
|
@ -6,16 +6,16 @@ module QA
|
|||
attr_accessor :name, :expires_at
|
||||
|
||||
attribute :username do
|
||||
Page::Project::Settings::CICD.perform do |cicd_page|
|
||||
cicd_page.expand_deploy_tokens do |token|
|
||||
Page::Project::Settings::Repository.perform do |repository_page|
|
||||
repository_page.expand_deploy_tokens do |token|
|
||||
token.token_username
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
attribute :password do
|
||||
Page::Project::Settings::CICD.perform do |cicd_page|
|
||||
cicd_page.expand_deploy_tokens do |token|
|
||||
Page::Project::Settings::Repository.perform do |repository_page|
|
||||
repository_page.expand_deploy_tokens do |token|
|
||||
token.token_password
|
||||
end
|
||||
end
|
||||
|
@ -31,10 +31,10 @@ module QA
|
|||
def fabricate!
|
||||
project.visit!
|
||||
|
||||
Page::Project::Menu.perform(&:go_to_ci_cd_settings)
|
||||
Page::Project::Menu.perform(&:go_to_repository_settings)
|
||||
|
||||
Page::Project::Settings::CICD.perform do |cicd|
|
||||
cicd.expand_deploy_tokens do |page|
|
||||
Page::Project::Settings::Repository.perform do |setting|
|
||||
setting.expand_deploy_tokens do |page|
|
||||
page.fill_token_name(name)
|
||||
page.fill_token_expires_at(expires_at)
|
||||
page.fill_scopes(read_repository: true, read_registry: false)
|
||||
|
|
|
@ -266,84 +266,4 @@ describe Projects::Settings::CiCdController do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST create_deploy_token' do
|
||||
context 'when ajax_new_deploy_token feature flag is disabled for the project' do
|
||||
before do
|
||||
stub_feature_flags(ajax_new_deploy_token: { enabled: false, thing: project })
|
||||
end
|
||||
|
||||
it_behaves_like 'a created deploy token' do
|
||||
let(:entity) { project }
|
||||
let(:create_entity_params) { { namespace_id: project.namespace, project_id: project } }
|
||||
let(:deploy_token_type) { DeployToken.deploy_token_types[:project_type] }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when ajax_new_deploy_token feature flag is enabled for the project' do
|
||||
let(:good_deploy_token_params) do
|
||||
{
|
||||
name: 'name',
|
||||
expires_at: 1.day.from_now.to_s,
|
||||
username: 'deployer',
|
||||
read_repository: '1',
|
||||
deploy_token_type: DeployToken.deploy_token_types[:project_type]
|
||||
}
|
||||
end
|
||||
let(:request_params) do
|
||||
{
|
||||
namespace_id: project.namespace.to_param,
|
||||
project_id: project.to_param,
|
||||
deploy_token: deploy_token_params
|
||||
}
|
||||
end
|
||||
|
||||
subject { post :create_deploy_token, params: request_params, format: :json }
|
||||
|
||||
context('a good request') do
|
||||
let(:deploy_token_params) { good_deploy_token_params }
|
||||
let(:expected_response) do
|
||||
{
|
||||
'id' => be_a(Integer),
|
||||
'name' => deploy_token_params[:name],
|
||||
'username' => deploy_token_params[:username],
|
||||
'expires_at' => Time.parse(deploy_token_params[:expires_at]),
|
||||
'token' => be_a(String),
|
||||
'scopes' => deploy_token_params.inject([]) do |scopes, kv|
|
||||
key, value = kv
|
||||
key.to_s.start_with?('read_') && !value.to_i.zero? ? scopes << key.to_s : scopes
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
it 'creates the deploy token' do
|
||||
subject
|
||||
|
||||
expect(response).to have_gitlab_http_status(:created)
|
||||
expect(response).to match_response_schema('public_api/v4/deploy_token')
|
||||
expect(json_response).to match(expected_response)
|
||||
end
|
||||
end
|
||||
|
||||
context('a bad request') do
|
||||
let(:deploy_token_params) { good_deploy_token_params.except(:read_repository) }
|
||||
let(:expected_response) { { 'message' => "Scopes can't be blank" } }
|
||||
|
||||
it 'does not create the deploy token' do
|
||||
subject
|
||||
|
||||
expect(response).to have_gitlab_http_status(:bad_request)
|
||||
expect(json_response).to match(expected_response)
|
||||
end
|
||||
end
|
||||
|
||||
context('an invalid request') do
|
||||
let(:deploy_token_params) { good_deploy_token_params.except(:name) }
|
||||
|
||||
it 'raises a validation error' do
|
||||
expect { subject }.to raise_error(ActiveRecord::StatementInvalid)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -32,4 +32,84 @@ describe Projects::Settings::RepositoryController do
|
|||
expect(RepositoryCleanupWorker).to have_received(:perform_async).once
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST create_deploy_token' do
|
||||
context 'when ajax_new_deploy_token feature flag is disabled for the project' do
|
||||
before do
|
||||
stub_feature_flags(ajax_new_deploy_token: { enabled: false, thing: project })
|
||||
end
|
||||
|
||||
it_behaves_like 'a created deploy token' do
|
||||
let(:entity) { project }
|
||||
let(:create_entity_params) { { namespace_id: project.namespace, project_id: project } }
|
||||
let(:deploy_token_type) { DeployToken.deploy_token_types[:project_type] }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when ajax_new_deploy_token feature flag is enabled for the project' do
|
||||
let(:good_deploy_token_params) do
|
||||
{
|
||||
name: 'name',
|
||||
expires_at: 1.day.from_now.to_s,
|
||||
username: 'deployer',
|
||||
read_repository: '1',
|
||||
deploy_token_type: DeployToken.deploy_token_types[:project_type]
|
||||
}
|
||||
end
|
||||
let(:request_params) do
|
||||
{
|
||||
namespace_id: project.namespace.to_param,
|
||||
project_id: project.to_param,
|
||||
deploy_token: deploy_token_params
|
||||
}
|
||||
end
|
||||
|
||||
subject { post :create_deploy_token, params: request_params, format: :json }
|
||||
|
||||
context('a good request') do
|
||||
let(:deploy_token_params) { good_deploy_token_params }
|
||||
let(:expected_response) do
|
||||
{
|
||||
'id' => be_a(Integer),
|
||||
'name' => deploy_token_params[:name],
|
||||
'username' => deploy_token_params[:username],
|
||||
'expires_at' => Time.parse(deploy_token_params[:expires_at]),
|
||||
'token' => be_a(String),
|
||||
'scopes' => deploy_token_params.inject([]) do |scopes, kv|
|
||||
key, value = kv
|
||||
key.to_s.start_with?('read_') && !value.to_i.zero? ? scopes << key.to_s : scopes
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
it 'creates the deploy token' do
|
||||
subject
|
||||
|
||||
expect(response).to have_gitlab_http_status(:created)
|
||||
expect(response).to match_response_schema('public_api/v4/deploy_token')
|
||||
expect(json_response).to match(expected_response)
|
||||
end
|
||||
end
|
||||
|
||||
context('a bad request') do
|
||||
let(:deploy_token_params) { good_deploy_token_params.except(:read_repository) }
|
||||
let(:expected_response) { { 'message' => "Scopes can't be blank" } }
|
||||
|
||||
it 'does not create the deploy token' do
|
||||
subject
|
||||
|
||||
expect(response).to have_gitlab_http_status(:bad_request)
|
||||
expect(json_response).to match(expected_response)
|
||||
end
|
||||
end
|
||||
|
||||
context('an invalid request') do
|
||||
let(:deploy_token_params) { good_deploy_token_params.except(:name) }
|
||||
|
||||
it 'raises a validation error' do
|
||||
expect { subject }.to raise_error(ActiveRecord::StatementInvalid)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
34
spec/factories/alert_management/alerts.rb
Normal file
34
spec/factories/alert_management/alerts.rb
Normal file
|
@ -0,0 +1,34 @@
|
|||
# frozen_string_literal: true
|
||||
require 'ffaker'
|
||||
|
||||
FactoryBot.define do
|
||||
factory :alert_management_alert, class: 'AlertManagement::Alert' do
|
||||
project
|
||||
title { FFaker::Lorem.sentence }
|
||||
started_at { Time.current }
|
||||
|
||||
trait :with_issue do
|
||||
issue
|
||||
end
|
||||
|
||||
trait :with_fingerprint do
|
||||
fingerprint { SecureRandom.hex }
|
||||
end
|
||||
|
||||
trait :with_service do
|
||||
service { FFaker::App.name }
|
||||
end
|
||||
|
||||
trait :with_monitoring_tool do
|
||||
monitoring_tool { FFaker::App.name }
|
||||
end
|
||||
|
||||
trait :with_host do
|
||||
hosts { FFaker::Internet.public_ip_v4_address }
|
||||
end
|
||||
|
||||
trait :resolved do
|
||||
status { :resolved }
|
||||
end
|
||||
end
|
||||
end
|
|
@ -142,6 +142,8 @@ FactoryBot.define do
|
|||
|
||||
factory :clusters_applications_fluentd, class: 'Clusters::Applications::Fluentd' do
|
||||
host { 'example.com' }
|
||||
waf_log_enabled { true }
|
||||
cilium_log_enabled { true }
|
||||
cluster factory: %i(cluster with_installed_helm provided_by_gcp)
|
||||
|
||||
trait :no_helm_installed do
|
||||
|
|
|
@ -172,6 +172,12 @@ describe 'Copy as GFM', :js do
|
|||
'![Image](https://example.com/image.png)'
|
||||
)
|
||||
|
||||
verify_media_with_partial_path(
|
||||
'[test.txt](/uploads/a123/image.txt)',
|
||||
|
||||
project_media_uri(@project, '/uploads/a123/image.txt')
|
||||
)
|
||||
|
||||
verify_media_with_partial_path(
|
||||
'![Image](/uploads/a123/image.png)',
|
||||
|
||||
|
|
|
@ -7,22 +7,6 @@ describe 'Projects > Settings > CI / CD settings' do
|
|||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:role) { :maintainer }
|
||||
|
||||
context 'Deploy tokens' do
|
||||
let!(:deploy_token) { create(:deploy_token, projects: [project]) }
|
||||
|
||||
before do
|
||||
project.add_role(user, role)
|
||||
sign_in(user)
|
||||
stub_container_registry_config(enabled: true)
|
||||
stub_feature_flags(ajax_new_deploy_token: { enabled: false, thing: project })
|
||||
visit project_settings_ci_cd_path(project)
|
||||
end
|
||||
|
||||
it_behaves_like 'a deploy token in settings' do
|
||||
let(:entity_type) { 'project' }
|
||||
end
|
||||
end
|
||||
|
||||
context 'Deploy Keys', :js do
|
||||
let_it_be(:private_deploy_key) { create(:deploy_key, title: 'private_deploy_key', public: false) }
|
||||
let_it_be(:public_deploy_key) { create(:another_deploy_key, title: 'public_deploy_key', public: true) }
|
||||
|
|
|
@ -25,6 +25,20 @@ describe 'Projects > Settings > Repository settings' do
|
|||
context 'for maintainer' do
|
||||
let(:role) { :maintainer }
|
||||
|
||||
context 'Deploy tokens' do
|
||||
let!(:deploy_token) { create(:deploy_token, projects: [project]) }
|
||||
|
||||
before do
|
||||
stub_container_registry_config(enabled: true)
|
||||
stub_feature_flags(ajax_new_deploy_token: { enabled: false, thing: project })
|
||||
visit project_settings_repository_path(project)
|
||||
end
|
||||
|
||||
it_behaves_like 'a deploy token in settings' do
|
||||
let(:entity_type) { 'project' }
|
||||
end
|
||||
end
|
||||
|
||||
context 'remote mirror settings' do
|
||||
before do
|
||||
visit project_settings_repository_path(project)
|
||||
|
|
|
@ -12,7 +12,7 @@ describe 'Repository Settings > User sees revoke deploy token modal', :js do
|
|||
project.add_role(user, role)
|
||||
sign_in(user)
|
||||
stub_feature_flags(ajax_new_deploy_token: { enabled: false, thing: project })
|
||||
visit(project_settings_ci_cd_path(project))
|
||||
visit(project_settings_repository_path(project))
|
||||
click_link('Revoke')
|
||||
end
|
||||
|
||||
|
|
|
@ -42,6 +42,8 @@
|
|||
"host": {"type": ["string", "null"]},
|
||||
"port": {"type": ["integer", "514"]},
|
||||
"protocol": {"type": ["integer", "0"]},
|
||||
"waf_log_enabled": {"type": ["boolean", "true"]},
|
||||
"cilium_log_enabled": {"type": ["boolean", "true"]},
|
||||
"update_available": { "type": ["boolean", "null"] },
|
||||
"can_uninstall": { "type": "boolean" },
|
||||
"available_domains": {
|
||||
|
|
|
@ -51,6 +51,7 @@ describe Banzai::Filter::UploadLinkFilter do
|
|||
|
||||
expect(doc.at_css('a')['href']).to eq(absolute_path)
|
||||
expect(doc.at_css('a').classes).to include('gfm')
|
||||
expect(doc.at_css('a')['data-link']).to eq('true')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -59,11 +60,13 @@ describe Banzai::Filter::UploadLinkFilter do
|
|||
|
||||
expect(doc.at_css('a')['href']).to eq(relative_path)
|
||||
expect(doc.at_css('a').classes).to include('gfm')
|
||||
expect(doc.at_css('a')['data-link']).to eq('true')
|
||||
|
||||
doc = filter(nested(link(upload_path)))
|
||||
|
||||
expect(doc.at_css('a')['href']).to eq(relative_path)
|
||||
expect(doc.at_css('a').classes).to include('gfm')
|
||||
expect(doc.at_css('a')['data-link']).to eq('true')
|
||||
end
|
||||
|
||||
it 'rebuilds relative URL for an image' do
|
||||
|
@ -71,11 +74,13 @@ describe Banzai::Filter::UploadLinkFilter do
|
|||
|
||||
expect(doc.at_css('img')['src']).to eq(relative_path)
|
||||
expect(doc.at_css('img').classes).to include('gfm')
|
||||
expect(doc.at_css('img')['data-link']).not_to eq('true')
|
||||
|
||||
doc = filter(nested(image(upload_path)))
|
||||
|
||||
expect(doc.at_css('img')['src']).to eq(relative_path)
|
||||
expect(doc.at_css('img').classes).to include('gfm')
|
||||
expect(doc.at_css('img')['data-link']).not_to eq('true')
|
||||
end
|
||||
|
||||
it 'does not modify absolute URL' do
|
||||
|
@ -83,6 +88,7 @@ describe Banzai::Filter::UploadLinkFilter do
|
|||
|
||||
expect(doc.at_css('a')['href']).to eq 'http://example.com'
|
||||
expect(doc.at_css('a').classes).not_to include('gfm')
|
||||
expect(doc.at_css('a')['data-link']).not_to eq('true')
|
||||
end
|
||||
|
||||
it 'supports unescaped Unicode filenames' do
|
||||
|
@ -91,6 +97,7 @@ describe Banzai::Filter::UploadLinkFilter do
|
|||
|
||||
expect(doc.at_css('a')['href']).to eq("/#{project.full_path}/uploads/%ED%95%9C%EA%B8%80.png")
|
||||
expect(doc.at_css('a').classes).to include('gfm')
|
||||
expect(doc.at_css('a')['data-link']).to eq('true')
|
||||
end
|
||||
|
||||
it 'supports escaped Unicode filenames' do
|
||||
|
@ -100,6 +107,7 @@ describe Banzai::Filter::UploadLinkFilter do
|
|||
|
||||
expect(doc.at_css('img')['src']).to eq("/#{project.full_path}/uploads/%ED%95%9C%EA%B8%80.png")
|
||||
expect(doc.at_css('img').classes).to include('gfm')
|
||||
expect(doc.at_css('img')['data-link']).not_to eq('true')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -118,6 +126,7 @@ describe Banzai::Filter::UploadLinkFilter do
|
|||
|
||||
expect(doc.at_css('a')['href']).to eq(absolute_path)
|
||||
expect(doc.at_css('a').classes).to include('gfm')
|
||||
expect(doc.at_css('a')['data-link']).to eq('true')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -126,6 +135,7 @@ describe Banzai::Filter::UploadLinkFilter do
|
|||
|
||||
expect(doc.at_css('a')['href']).to eq(relative_path)
|
||||
expect(doc.at_css('a').classes).to include('gfm')
|
||||
expect(doc.at_css('a')['data-link']).to eq('true')
|
||||
end
|
||||
|
||||
it 'rewrites the link correctly for subgroup' do
|
||||
|
@ -135,6 +145,7 @@ describe Banzai::Filter::UploadLinkFilter do
|
|||
|
||||
expect(doc.at_css('a')['href']).to eq(relative_path)
|
||||
expect(doc.at_css('a').classes).to include('gfm')
|
||||
expect(doc.at_css('a')['data-link']).to eq('true')
|
||||
end
|
||||
|
||||
it 'does not modify absolute URL' do
|
||||
|
@ -142,6 +153,7 @@ describe Banzai::Filter::UploadLinkFilter do
|
|||
|
||||
expect(doc.at_css('a')['href']).to eq 'http://example.com'
|
||||
expect(doc.at_css('a').classes).not_to include('gfm')
|
||||
expect(doc.at_css('a')['data-link']).not_to eq('true')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -159,6 +171,7 @@ describe Banzai::Filter::UploadLinkFilter do
|
|||
|
||||
expect(doc.at_css('a')['href']).to eq(absolute_path)
|
||||
expect(doc.at_css('a').classes).to include('gfm')
|
||||
expect(doc.at_css('a')['data-link']).to eq('true')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -178,6 +191,7 @@ describe Banzai::Filter::UploadLinkFilter do
|
|||
|
||||
expect(doc.at_css('a')['href']).to eq(absolute_path)
|
||||
expect(doc.at_css('a').classes).to include('gfm')
|
||||
expect(doc.at_css('a')['data-link']).to eq('true')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -186,6 +200,7 @@ describe Banzai::Filter::UploadLinkFilter do
|
|||
|
||||
expect(doc.at_css('a')['href']).to eq(gitlab_root + relative_path)
|
||||
expect(doc.at_css('a').classes).to include('gfm')
|
||||
expect(doc.at_css('a')['data-link']).to eq('true')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -194,6 +209,7 @@ describe Banzai::Filter::UploadLinkFilter do
|
|||
|
||||
expect(doc.at_css('a')['href']).to eq(relative_path)
|
||||
expect(doc.at_css('a').classes).to include('gfm')
|
||||
expect(doc.at_css('a')['data-link']).to eq('true')
|
||||
end
|
||||
|
||||
it 'does not modify absolute URL' do
|
||||
|
@ -201,6 +217,7 @@ describe Banzai::Filter::UploadLinkFilter do
|
|||
|
||||
expect(doc.at_css('a')['href']).to eq 'http://example.com'
|
||||
expect(doc.at_css('a').classes).not_to include('gfm')
|
||||
expect(doc.at_css('a')['data-link']).not_to eq('true')
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ issues:
|
|||
- related_vulnerabilities
|
||||
- user_mentions
|
||||
- system_note_metadata
|
||||
- alert_management_alert
|
||||
events:
|
||||
- author
|
||||
- project
|
||||
|
@ -481,6 +482,7 @@ project:
|
|||
- daily_report_results
|
||||
- jira_imports
|
||||
- compliance_framework_setting
|
||||
- alert_management_alerts
|
||||
award_emoji:
|
||||
- awardable
|
||||
- user
|
||||
|
|
|
@ -18,22 +18,12 @@ describe Gitlab::JiraImport::IssueSerializer do
|
|||
let(:parent_field) do
|
||||
{ 'key' => 'FOO-2', 'id' => '1050', 'fields' => { 'summary' => 'parent issue FOO' } }
|
||||
end
|
||||
let(:issue_type_field) { { 'name' => 'Task' } }
|
||||
let(:fix_versions_field) { [{ 'name' => '1.0' }, { 'name' => '1.1' }] }
|
||||
let(:priority_field) { { 'name' => 'Medium' } }
|
||||
let(:labels_field) { %w(bug backend) }
|
||||
let(:environment_field) { 'staging' }
|
||||
let(:duedate_field) { '2020-03-01' }
|
||||
|
||||
let(:fields) do
|
||||
{
|
||||
'parent' => parent_field,
|
||||
'issuetype' => issue_type_field,
|
||||
'fixVersions' => fix_versions_field,
|
||||
'priority' => priority_field,
|
||||
'labels' => labels_field,
|
||||
'environment' => environment_field,
|
||||
'duedate' => duedate_field
|
||||
'priority' => priority_field
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -68,13 +58,8 @@ describe Gitlab::JiraImport::IssueSerializer do
|
|||
|
||||
**Issue metadata**
|
||||
|
||||
- Issue type: Task
|
||||
- Priority: Medium
|
||||
- Labels: bug, backend
|
||||
- Environment: staging
|
||||
- Due date: 2020-03-01
|
||||
- Parent issue: [FOO-2] parent issue FOO
|
||||
- Fix versions: 1.0, 1.1
|
||||
MD
|
||||
end
|
||||
|
||||
|
@ -91,54 +76,6 @@ describe Gitlab::JiraImport::IssueSerializer do
|
|||
author_id: project.creator_id
|
||||
)
|
||||
end
|
||||
|
||||
context 'when some metadata fields are missing' do
|
||||
let(:assignee) { nil }
|
||||
let(:parent_field) { nil }
|
||||
let(:fix_versions_field) { [] }
|
||||
let(:labels_field) { [] }
|
||||
let(:environment_field) { nil }
|
||||
let(:duedate_field) { '2020-03-01' }
|
||||
|
||||
it 'skips the missing fields' do
|
||||
expected_description = <<~MD
|
||||
*Created by: Reporter*
|
||||
|
||||
basic description
|
||||
|
||||
---
|
||||
|
||||
**Issue metadata**
|
||||
|
||||
- Issue type: Task
|
||||
- Priority: Medium
|
||||
- Due date: 2020-03-01
|
||||
MD
|
||||
|
||||
expect(subject[:description]).to eq(expected_description.strip)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when all metadata fields are missing' do
|
||||
let(:assignee) { nil }
|
||||
let(:parent_field) { nil }
|
||||
let(:issue_type_field) { nil }
|
||||
let(:fix_versions_field) { [] }
|
||||
let(:priority_field) { nil }
|
||||
let(:labels_field) { [] }
|
||||
let(:environment_field) { nil }
|
||||
let(:duedate_field) { nil }
|
||||
|
||||
it 'skips the whole metadata secction' do
|
||||
expected_description = <<~MD
|
||||
*Created by: Reporter*
|
||||
|
||||
basic description
|
||||
MD
|
||||
|
||||
expect(subject[:description]).to eq(expected_description.strip)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with done status' do
|
||||
|
|
110
spec/lib/gitlab/jira_import/metadata_collector_spec.rb
Normal file
110
spec/lib/gitlab/jira_import/metadata_collector_spec.rb
Normal file
|
@ -0,0 +1,110 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::JiraImport::MetadataCollector do
|
||||
describe '#execute' do
|
||||
let(:key) { 'PROJECT-5' }
|
||||
let(:summary) { 'some title' }
|
||||
let(:description) { 'basic description' }
|
||||
let(:created_at) { '2020-01-01 20:00:00' }
|
||||
let(:updated_at) { '2020-01-10 20:00:00' }
|
||||
let(:assignee) { double(displayName: 'Solver') }
|
||||
let(:jira_status) { 'new' }
|
||||
|
||||
let(:parent_field) do
|
||||
{ 'key' => 'FOO-2', 'id' => '1050', 'fields' => { 'summary' => 'parent issue FOO' } }
|
||||
end
|
||||
let(:issue_type_field) { { 'name' => 'Task' } }
|
||||
let(:fix_versions_field) { [{ 'name' => '1.0' }, { 'name' => '1.1' }] }
|
||||
let(:priority_field) { { 'name' => 'Medium' } }
|
||||
let(:labels_field) { %w(bug backend) }
|
||||
let(:environment_field) { 'staging' }
|
||||
let(:duedate_field) { '2020-03-01' }
|
||||
|
||||
let(:fields) do
|
||||
{
|
||||
'parent' => parent_field,
|
||||
'issuetype' => issue_type_field,
|
||||
'fixVersions' => fix_versions_field,
|
||||
'priority' => priority_field,
|
||||
'labels' => labels_field,
|
||||
'environment' => environment_field,
|
||||
'duedate' => duedate_field
|
||||
}
|
||||
end
|
||||
let(:jira_issue) do
|
||||
double(
|
||||
id: '1234',
|
||||
key: key,
|
||||
summary: summary,
|
||||
description: description,
|
||||
created: created_at,
|
||||
updated: updated_at,
|
||||
assignee: assignee,
|
||||
reporter: double(displayName: 'Reporter'),
|
||||
status: double(statusCategory: { 'key' => jira_status }),
|
||||
fields: fields
|
||||
)
|
||||
end
|
||||
|
||||
subject { described_class.new(jira_issue).execute }
|
||||
|
||||
context 'when all metadata fields are present' do
|
||||
it 'skips writes all fields' do
|
||||
expected_result = <<~MD
|
||||
---
|
||||
|
||||
**Issue metadata**
|
||||
|
||||
- Issue type: Task
|
||||
- Priority: Medium
|
||||
- Labels: bug, backend
|
||||
- Environment: staging
|
||||
- Due date: 2020-03-01
|
||||
- Parent issue: [FOO-2] parent issue FOO
|
||||
- Fix versions: 1.0, 1.1
|
||||
MD
|
||||
|
||||
expect(subject.strip).to eq(expected_result.strip)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when some metadata fields are missing' do
|
||||
let(:assignee) { nil }
|
||||
let(:parent_field) { nil }
|
||||
let(:fix_versions_field) { [] }
|
||||
let(:labels_field) { [] }
|
||||
let(:environment_field) { nil }
|
||||
|
||||
it 'skips the missing fields' do
|
||||
expected_result = <<~MD
|
||||
---
|
||||
|
||||
**Issue metadata**
|
||||
|
||||
- Issue type: Task
|
||||
- Priority: Medium
|
||||
- Due date: 2020-03-01
|
||||
MD
|
||||
|
||||
expect(subject.strip).to eq(expected_result.strip)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when all metadata fields are missing' do
|
||||
let(:assignee) { nil }
|
||||
let(:parent_field) { nil }
|
||||
let(:issue_type_field) { nil }
|
||||
let(:fix_versions_field) { [] }
|
||||
let(:priority_field) { nil }
|
||||
let(:labels_field) { [] }
|
||||
let(:environment_field) { nil }
|
||||
let(:duedate_field) { nil }
|
||||
|
||||
it 'returns nil' do
|
||||
expect(subject).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
119
spec/models/alert_management/alert_spec.rb
Normal file
119
spec/models/alert_management/alert_spec.rb
Normal file
|
@ -0,0 +1,119 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe AlertManagement::Alert do
|
||||
describe 'associations' do
|
||||
it { is_expected.to belong_to(:project) }
|
||||
it { is_expected.to belong_to(:issue) }
|
||||
end
|
||||
|
||||
describe 'validations' do
|
||||
it { is_expected.to validate_presence_of(:title) }
|
||||
it { is_expected.to validate_presence_of(:events) }
|
||||
it { is_expected.to validate_presence_of(:severity) }
|
||||
it { is_expected.to validate_presence_of(:status) }
|
||||
it { is_expected.to validate_presence_of(:started_at) }
|
||||
|
||||
it { is_expected.to validate_length_of(:title).is_at_most(200) }
|
||||
it { is_expected.to validate_length_of(:description).is_at_most(1000) }
|
||||
it { is_expected.to validate_length_of(:service).is_at_most(100) }
|
||||
it { is_expected.to validate_length_of(:monitoring_tool).is_at_most(100) }
|
||||
|
||||
describe 'fingerprint' do
|
||||
let_it_be(:fingerprint) { 'fingerprint' }
|
||||
let_it_be(:existing_alert) { create(:alert_management_alert, fingerprint: fingerprint) }
|
||||
let(:new_alert) { build(:alert_management_alert, fingerprint: fingerprint, project: project) }
|
||||
|
||||
subject { new_alert }
|
||||
|
||||
context 'adding an alert with the same fingerprint' do
|
||||
context 'same project' do
|
||||
let(:project) { existing_alert.project }
|
||||
|
||||
it { is_expected.not_to be_valid }
|
||||
end
|
||||
|
||||
context 'different project' do
|
||||
let(:project) { create(:project) }
|
||||
|
||||
it { is_expected.to be_valid }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'hosts' do
|
||||
subject(:alert) { build(:alert_management_alert, hosts: hosts) }
|
||||
|
||||
context 'over 255 total chars' do
|
||||
let(:hosts) { ['111.111.111.111'] * 18 }
|
||||
|
||||
it { is_expected.not_to be_valid }
|
||||
end
|
||||
|
||||
context 'under 255 chars' do
|
||||
let(:hosts) { ['111.111.111.111'] * 17 }
|
||||
|
||||
it { is_expected.to be_valid }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'enums' do
|
||||
let(:severity_values) do
|
||||
{ critical: 0, high: 1, medium: 2, low: 3, info: 4, unknown: 5 }
|
||||
end
|
||||
|
||||
let(:status_values) do
|
||||
{ triggered: 0, acknowledged: 1, resolved: 2, ignored: 3 }
|
||||
end
|
||||
|
||||
it { is_expected.to define_enum_for(:severity).with_values(severity_values) }
|
||||
it { is_expected.to define_enum_for(:status).with_values(status_values) }
|
||||
end
|
||||
|
||||
describe 'fingerprint setter' do
|
||||
let(:alert) { build(:alert_management_alert) }
|
||||
|
||||
subject(:set_fingerprint) { alert.fingerprint = fingerprint }
|
||||
|
||||
let(:fingerprint) { 'test' }
|
||||
|
||||
it 'sets to the SHA1 of the value' do
|
||||
expect { set_fingerprint }
|
||||
.to change { alert.fingerprint }
|
||||
.from(nil)
|
||||
.to(Digest::SHA1.hexdigest(fingerprint))
|
||||
end
|
||||
|
||||
describe 'testing length of 40' do
|
||||
where(:input) do
|
||||
[
|
||||
'test',
|
||||
'another test',
|
||||
'a' * 1000,
|
||||
12345
|
||||
]
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:fingerprint) { input }
|
||||
|
||||
it 'sets the fingerprint to 40 chars' do
|
||||
set_fingerprint
|
||||
expect(alert.fingerprint.size).to eq(40)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'blank value given' do
|
||||
let(:fingerprint) { '' }
|
||||
|
||||
it 'does not set the fingerprint' do
|
||||
expect { set_fingerprint }
|
||||
.not_to change { alert.fingerprint }
|
||||
.from(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -3,7 +3,9 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Clusters::Applications::Fluentd do
|
||||
let(:fluentd) { create(:clusters_applications_fluentd) }
|
||||
let(:waf_log_enabled) { true }
|
||||
let(:cilium_log_enabled) { true }
|
||||
let(:fluentd) { create(:clusters_applications_fluentd, waf_log_enabled: waf_log_enabled, cilium_log_enabled: cilium_log_enabled) }
|
||||
|
||||
include_examples 'cluster application core specs', :clusters_applications_fluentd
|
||||
include_examples 'cluster application status specs', :clusters_applications_fluentd
|
||||
|
@ -47,4 +49,36 @@ describe Clusters::Applications::Fluentd do
|
|||
expect(values).to include('output.conf', 'general.conf')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#values' do
|
||||
let(:modsecurity_log_path) { "/var/log/containers/*#{Clusters::Applications::Ingress::MODSECURITY_LOG_CONTAINER_NAME}*.log" }
|
||||
let(:cilium_log_path) { "/var/log/containers/*#{described_class::CILIUM_CONTAINER_NAME}*.log" }
|
||||
|
||||
subject { fluentd.values }
|
||||
|
||||
context 'with both logs variables set to false' do
|
||||
let(:waf_log_enabled) { false }
|
||||
let(:cilium_log_enabled) { false }
|
||||
|
||||
it "raises ActiveRecord::RecordInvalid" do
|
||||
expect {subject}.to raise_error(ActiveRecord::RecordInvalid)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with both logs variables set to true' do
|
||||
it { is_expected.to include("#{modsecurity_log_path},#{cilium_log_path}") }
|
||||
end
|
||||
|
||||
context 'with waf_log_enabled set to true' do
|
||||
let(:cilium_log_enabled) { false }
|
||||
|
||||
it { is_expected.to include(modsecurity_log_path) }
|
||||
end
|
||||
|
||||
context 'with cilium_log_enabled set to true' do
|
||||
let(:waf_log_enabled) { false }
|
||||
|
||||
it { is_expected.to include(cilium_log_path) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -14,6 +14,7 @@ describe Issue do
|
|||
it { is_expected.to have_many(:assignees) }
|
||||
it { is_expected.to have_many(:user_mentions).class_name("IssueUserMention") }
|
||||
it { is_expected.to have_one(:sentry_issue) }
|
||||
it { is_expected.to have_one(:alert_management_alert) }
|
||||
end
|
||||
|
||||
describe 'modules' do
|
||||
|
|
|
@ -110,6 +110,7 @@ describe Project do
|
|||
it { is_expected.to have_many(:source_pipelines) }
|
||||
it { is_expected.to have_many(:prometheus_alert_events) }
|
||||
it { is_expected.to have_many(:self_managed_prometheus_alert_events) }
|
||||
it { is_expected.to have_many(:alert_management_alerts) }
|
||||
it { is_expected.to have_many(:jira_imports) }
|
||||
|
||||
it_behaves_like 'model with repository' do
|
||||
|
|
|
@ -800,9 +800,8 @@ describe 'project routing' do
|
|||
|
||||
it_behaves_like 'redirecting a legacy project path', "/gitlab/gitlabhq/settings/repository", "/gitlab/gitlabhq/-/settings/repository"
|
||||
|
||||
# TODO: remove this test as part of https://gitlab.com/gitlab-org/gitlab/issues/207079 (12.9)
|
||||
it 'to ci_cd#create_deploy_token' do
|
||||
expect(post('gitlab/gitlabhq/-/settings/ci_cd/deploy_token/create')).to route_to('projects/settings/ci_cd#create_deploy_token', namespace_id: 'gitlab', project_id: 'gitlabhq')
|
||||
it 'to repository#create_deploy_token' do
|
||||
expect(post('gitlab/gitlabhq/-/settings/ci_cd/deploy_token/create')).to route_to('projects/settings/repository#create_deploy_token', namespace_id: 'gitlab', project_id: 'gitlabhq')
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -77,5 +77,17 @@ describe ClusterApplicationEntity do
|
|||
expect(subject[:pages_domain]).to eq(id: pages_domain.id, domain: pages_domain.domain)
|
||||
end
|
||||
end
|
||||
|
||||
context 'for fluentd application' do
|
||||
let(:application) { build(:clusters_applications_fluentd, :installed) }
|
||||
|
||||
it 'includes host, port, protocol and log fields' do
|
||||
expect(subject[:port]).to eq(514)
|
||||
expect(subject[:host]).to eq("example.com")
|
||||
expect(subject[:protocol]).to eq("tcp")
|
||||
expect(subject[:waf_log_enabled]).to be true
|
||||
expect(subject[:cilium_log_enabled]).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue