Commit 1858fdc8 authored by Clement Ho's avatar Clement Ho

Merge branch '4753-tracing-mvc' into 'master'

Tracing MVC

Closes #4753

See merge request gitlab-org/gitlab-ee!7903
parents 51d88bb5 9296a40f
......@@ -542,4 +542,13 @@ module ProjectsHelper
network
]
end
def sidebar_operations_paths
%w[
environments
clusters
user
gcp
]
end
end
......@@ -195,7 +195,7 @@
= _('Charts')
- if project_nav_tab? :operations
= nav_link(controller: [:environments, :clusters, :user, :gcp, :feature_flags]) do
= nav_link(controller: sidebar_operations_paths) do
= link_to metrics_project_environments_path(@project), class: 'shortcuts-operations' do
.nav-icon-container
= sprite_icon('cloud-gear')
......@@ -203,7 +203,7 @@
= _('Operations')
%ul.sidebar-sub-level-items
= nav_link(controller: [:environments, :clusters, :user, :gcp, :feature_flags], html_options: { class: "fly-out-top-item" } ) do
= nav_link(controller: sidebar_operations_paths, html_options: { class: "fly-out-top-item" } ) do
= link_to metrics_project_environments_path(@project) do
%strong.fly-out-top-item-name
= _('Operations')
......@@ -215,6 +215,8 @@
%span
= _('Metrics')
= render_if_exists "layouts/nav/sidebar/tracing_link"
= nav_link(controller: :environments, action: [:index, :folder, :show, :new, :edit, :create, :update, :stop, :terminal]) do
= link_to project_environments_path(@project), title: _('Environments'), class: 'shortcuts-environments qa-operations-environments-link' do
%span
......@@ -345,6 +347,9 @@
= link_to project_settings_ci_cd_path(@project), title: _('CI / CD') do
%span
= _('CI / CD')
= render_if_exists 'projects/sidebar/settings_operations'
- if @project.pages_available?
= nav_link(controller: :pages) do
= link_to project_pages_path(@project), title: _('Pages') do
......
......@@ -2282,6 +2282,15 @@ ActiveRecord::Schema.define(version: 20181105201455) do
add_index "project_statistics", ["namespace_id"], name: "index_project_statistics_on_namespace_id", using: :btree
add_index "project_statistics", ["project_id"], name: "index_project_statistics_on_project_id", unique: true, using: :btree
create_table "project_tracing_settings", id: :bigserial, force: :cascade do |t|
t.datetime_with_timezone "created_at", null: false
t.datetime_with_timezone "updated_at", null: false
t.integer "project_id", null: false
t.string "external_url", null: false
end
add_index "project_tracing_settings", ["project_id"], name: "index_project_tracing_settings_on_project_id", unique: true, using: :btree
create_table "projects", force: :cascade do |t|
t.string "name"
t.string "path"
......@@ -3418,6 +3427,7 @@ ActiveRecord::Schema.define(version: 20181105201455) do
add_foreign_key "project_mirror_data", "projects", name: "fk_d1aad367d7", on_delete: :cascade
add_foreign_key "project_repository_states", "projects", on_delete: :cascade
add_foreign_key "project_statistics", "projects", on_delete: :cascade
add_foreign_key "project_tracing_settings", "projects", on_delete: :cascade
add_foreign_key "projects", "repositories", column: "pool_repository_id", name: "fk_6e5c14658a", on_delete: :nullify
add_foreign_key "prometheus_alert_events", "projects", on_delete: :cascade
add_foreign_key "prometheus_alert_events", "prometheus_alerts", on_delete: :cascade
......
# frozen_string_literal: true
module Projects
module Settings
class OperationsController < Projects::ApplicationController
before_action :check_license
before_action :authorize_update_environment!, only: [:create, :update]
before_action :authorize_read_environment!, only: [:show]
def show
@tracing_settings ||= ProjectTracingSetting.for_project(@project)
end
def update
result = EE::TracingSettingService.new(project, current_user, operations_params).execute
render_result(result)
end
def create
result = EE::TracingSettingService.new(project, current_user, operations_params).execute
@tracing_setting = project.tracing_setting
render_result(result)
end
private
def render_result(result)
respond_to do |format|
format.html do
if result[:status] == :success
flash[:notice] = _('Your changes have been saved')
else
flash[:alert] = _('Unable to save your changes')
end
redirect_to project_settings_operations_path(@project)
end
end
end
def operations_params
params.require(:tracing_settings).permit(:external_url)
end
def check_license
render_404 unless @project.feature_available?(:tracing, current_user)
end
end
end
end
# frozen_string_literal: true
class Projects::TracingsController < Projects::ApplicationController
before_action :check_license
before_action :authorize_read_environment!, only: [:show]
def show
end
private
def check_license
render_404 unless @project.feature_available?(:tracing, current_user)
end
end
......@@ -9,7 +9,10 @@ module EE
override :sidebar_settings_paths
def sidebar_settings_paths
super + %w(audit_events#index)
super + %w[
audit_events#index
operations#show
]
end
override :sidebar_repository_paths
......@@ -17,6 +20,14 @@ module EE
super + %w(path_locks)
end
override :sidebar_operations_paths
def sidebar_operations_paths
super + %w[
tracings
feature_flags
]
end
override :get_project_nav_tabs
def get_project_nav_tabs(project, current_user)
nav_tabs = super
......
......@@ -30,6 +30,7 @@ module EE
has_one :jenkins_deprecated_service
has_one :github_service
has_one :gitlab_slack_application_service
has_one :tracing_setting, class_name: 'ProjectTracingSetting'
has_many :approvers, as: :target, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :approver_groups, as: :target, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
......@@ -109,6 +110,10 @@ module EE
end
end
def tracing_external_url
self.tracing_setting.try(:external_url)
end
def latest_pipeline_with_security_reports
pipelines.newest_first(ref: default_branch).with_security_reports.first ||
pipelines.newest_first(ref: default_branch).with_legacy_security_reports.first
......
......@@ -88,6 +88,7 @@ class License < ActiveRecord::Base
pseudonymizer
prometheus_alerts
operations_dashboard
tracing
].freeze
# List all features available for early adopters,
......
# frozen_string_literal: true
class ProjectTracingSetting < ActiveRecord::Base
belongs_to :project
validates :external_url, length: { maximum: 255 }, public_url: true
def self.create_or_update(project, params)
self.transaction(requires_new: true) do
tracing_setting = self.for_project(project)
tracing_setting.update(params)
end
rescue ActiveRecord::RecordNotUnique
retry
end
def self.for_project(project)
self.where(project: project).first_or_initialize
end
end
# frozen_string_literal: true
module EE
class TracingSettingService < BaseService
ValidationError = Class.new(StandardError)
def execute
# Convert an empty string in tracing_external_url to nil
if params.has_key?(:external_url)
params[:external_url] = params[:external_url].presence
end
# Delete the row in project_tracing_settings table if external_row is to be
# set to nil since that is currently the only value in the table.
if params[:external_url].nil?
destroy
else
create_or_update
end
rescue ValidationError => e
error(e.message)
end
def create_or_update
if ProjectTracingSetting.create_or_update(project, params)
success
else
update_failed
end
end
def destroy
tracing_setting = ProjectTracingSetting.for_project(project)
if tracing_setting.persisted? && tracing_setting.destroy
success
else
destroy_failed
end
end
def update_failed
model_errors = project.errors.full_messages.to_sentence
error_message = model_errors.presence || 'Project tracing settings could not be updated!'
error(error_message)
end
def destroy_failed
model_errors = project.errors.full_messages.to_sentence
error_message = model_errors.presence || 'Project tracing settings could not be deleted!'
error(error_message)
end
end
end
- return unless @project.feature_available?(:tracing, current_user) && can?(current_user, :read_environment, @project)
- if project_nav_tab? :settings
= nav_link(controller: :tracings, action: [:show]) do
- if @project.tracing_external_url.present?
= link_to @project.tracing_external_url, target: "_blank", rel: 'noopener noreferrer' do
%span
= _('Tracing')
%i.strong.ml-1.fa.fa-external-link
- else
= link_to project_tracing_path(@project), title: _('Tracing') do
%span
= _('Tracing')
- @content_class = "limit-container-width" unless fluid_layout
- page_title _("Operations Settings")
- page_title _("Operations")
- has_jaeger_url = @project.tracing_external_url.present?
%section
%h4
= _("Jaeger tracing")
%p
- tracing_url = has_jaeger_url ? @project.tracing_external_url : project_tracing_path(@project)
- meta = has_jaeger_url ? 'rel="noopener noreferrer" target="_blank"' : ''
- icon = has_jaeger_url ? sprite_icon('external-link', size: 16, css_class: 'ml-1 vertical-align-middle') : ''
- tracing_start_tag = "<a href='#{tracing_url}' #{meta}>".html_safe
- tracing_end_tag = "#{icon}</a>".html_safe
= _("To open Jaeger and easily view tracing from GitLab, link the %{start_tag}Tracing%{end_tag} page to your server").html_safe % { start_tag: tracing_start_tag, end_tag: tracing_end_tag }
= form_for @tracing_settings, as: :tracing_settings, url: project_settings_operations_path(@project) do |f|
= form_errors(@tracing_settings)
.form-group
= f.label :external_url, _('Jaeger URL'), class: 'label-bold'
= f.url_field :external_url, class: 'form-control', placeholder: 'e.g. https://jaeger.mycompany.com'
%p.form-text.text-muted
- jaeger_help_url = "https://www.jaegertracing.io/docs/1.7/getting-started/"
- link_start_tag = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: jaeger_help_url }
- link_end_tag = "#{sprite_icon('external-link', size: 16, css_class: 'ml-1 vertical-align-middle')}</a>".html_safe
= _("For more information, please review %{link_start_tag}Jaeger's configuration doc%{link_end_tag}").html_safe % { link_start_tag: link_start_tag, link_end_tag: link_end_tag }
= f.submit _('Save changes'), class: 'btn btn-success'
- return unless @project.feature_available?(:tracing)
= nav_link(controller: [:operations]) do
= link_to project_settings_operations_path(@project), title: _('Operations') do
= _('Operations')
= link_to project_settings_operations_path(@project), title: _('Configure Tracing'), class: 'btn btn-success' do
= _('Add Jaeger URL')
- @content_class = "limit-container-width" unless fluid_layout
- page_title _("Tracing")
.border-top
.row.empty-state
.col-12
.svg-content
= image_tag 'illustrations/tracing_empty.svg', style: 'max-height: 254px'
.col-12
.text-content
%h4.text-left= _('Troubleshoot and monitor your application with tracing')
%p
- jaeger_help_url = "https://www.jaegertracing.io/docs/1.7/getting-started/"
- link_start_tag = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: jaeger_help_url }
- link_end_tag = "#{sprite_icon('external-link', size: 16, css_class: 'ml-1 vertical-align-middle')}</a>".html_safe
= _('To get started, link this page to your Jaeger server, or find out how to %{link_start_tag}install Jaeger%{link_end_tag}').html_safe % { link_start_tag: link_start_tag, link_end_tag: link_end_tag }
.text-center
= render 'tracing_button'
---
title: Add Tracing landing and settings page
merge_request: 7903
author:
type: added
......@@ -8,6 +8,13 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
constraints: { project_id: Gitlab::PathRegex.project_route_regex },
module: :projects,
as: :project) do
resource :tracing, only: [:show]
namespace :settings do
resource :operations, only: [:show, :update, :create]
end
resources :autocomplete_sources, only: [] do
collection do
get 'epics'
......
# frozen_string_literal: true
class AddTracingSettings < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
create_table :project_tracing_settings, id: :bigserial do |t|
t.timestamps_with_timezone null: false
t.references :project, null: false, foreign_key: { on_delete: :cascade }
t.string :external_url, null: false
t.index :project_id,
unique: true
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Projects::Settings::OperationsController do
set(:user) { create(:user) }
before do
sign_in(user)
end
describe 'GET show' do
shared_examples 'user without access to project' do |project_visibility|
let(:project) { create(:project, project_visibility) }
it 'returns 404' do
get :show, namespace_id: project.namespace, project_id: project
expect(response).to have_gitlab_http_status(:not_found)
end
end
shared_examples 'user with access to project' do |project_visibility|
let(:project) { create(:project, project_visibility) }
before do
project.add_reporter(user)
end
it 'renders ok' do
get :show, namespace_id: project.namespace, project_id: project
expect(response).to have_gitlab_http_status(200)
expect(response).to render_template(:show)
end
end
shared_examples 'user needs to login' do |project_visibility|
it 'redirects for private project' do
project = create(:project, project_visibility)
get :show, namespace_id: project.namespace, project_id: project
expect(response).to redirect_to(new_user_session_path)
end
end
context 'with a license' do
before do
stub_licensed_features(tracing: true)
end
context 'when logged in with correct permission' do
it_behaves_like 'user with access to project', :public
it_behaves_like 'user with access to project', :private
it_behaves_like 'user with access to project', :internal
end
context 'when logged in without correct permission' do
it_behaves_like 'user without access to project', :public
it_behaves_like 'user without access to project', :private
it_behaves_like 'user without access to project', :internal
end
context 'when user not logged in' do
before do
sign_out(user)
end
it_behaves_like 'user without access to project', :public
it_behaves_like 'user needs to login', :private
it_behaves_like 'user needs to login', :internal
end
end
context 'without license' do
before do
stub_licensed_features(tracing: false)
end
it_behaves_like 'user without access to project', :public
it_behaves_like 'user without access to project', :private
it_behaves_like 'user without access to project', :internal
end
end
describe 'PATCH update' do
let(:public_project) { create(:project, :public) }
let(:private_project) { create(:project, :private) }
let(:internal_project) { create(:project, :internal) }
before do
public_project.add_maintainer(user)
private_project.add_maintainer(user)
internal_project.add_maintainer(user)
end
shared_examples 'user without write access' do |project_visibility|
let(:project) { create(:project, project_visibility) }
it 'does not update tracing external_url' do
update_project(project, external_url: 'https://gitlab.com')
expect(project.tracing_setting).to be_nil
end
end
context 'with a license' do
before do
stub_licensed_features(tracing: true)
end
shared_examples 'user with write access' do |project_visibility, value_to_set, value_to_check|
let(:project) { create(:project, project_visibility) }
before do
project.add_maintainer(user)
end
it 'updates tracing external_url' do
update_project(project, external_url: value_to_set)
expect(project.tracing_setting.external_url).to eq(value_to_check)
end
end
context 'with authorized user' do
it_behaves_like 'user with write access', :public, 'https://gitlab.com', 'https://gitlab.com'
it_behaves_like 'user with write access', :private, 'https://gitlab.com', 'https://gitlab.com'
it_behaves_like 'user with write access', :internal, 'https://gitlab.com', 'https://gitlab.com'
end
context 'with unauthorized user' do
it_behaves_like 'user without write access', :public
it_behaves_like 'user without write access', :private
it_behaves_like 'user without write access', :internal
end
context 'with anonymous user' do
before do
sign_out(user)
end
it_behaves_like 'user without write access', :public
it_behaves_like 'user without write access', :private
it_behaves_like 'user without write access', :internal
end
context 'with existing tracing_setting' do
let(:project) { create(:project) }
before do
project.create_tracing_setting!(external_url: 'https://gitlab.com')
project.add_maintainer(user)
end
it 'unsets external_url with nil' do
update_project(project, external_url: nil)
expect(project.tracing_setting).to be_nil
end
it 'unsets external_url with empty string' do
update_project(project, external_url: '')
expect(project.tracing_setting).to be_nil
end
it 'fails validation with invalid url' do
expect do
update_project(project, external_url: "invalid")
end.not_to change(project.tracing_setting, :external_url)
end
it 'does not set external_url if not present in params' do
expect do
update_project(project, some_param: 'some_value')
end.not_to change(project.tracing_setting, :external_url)
end
end
context 'without existing tracing_setting' do
let(:project) { create(:project) }
before do
project.add_maintainer(user)
end
it 'fails validation with invalid url' do
update_project(project, external_url: "invalid")
expect(project.tracing_setting).to be_nil
end
it 'does not set external_url if not present in params' do
update_project(project, some_param: 'some_value')
expect(project.tracing_setting).to be_nil
end
end
end
context 'without a license' do
before do
stub_licensed_features(tracing: false)
end
it_behaves_like 'user without write access', :public
it_behaves_like 'user without write access', :private
it_behaves_like 'user without write access', :internal
end
private
def project_params(project, params = {})
{ namespace_id: project.namespace, project_id: project, tracing_settings: params }
end
def update_project(project, params)
patch :update, project_params(project, params)
project.reload
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Projects::TracingsController do
set(:user) { create(:user) }
describe 'GET show' do
describe 'with valid license' do
before do
stub_licensed_features(tracing: true)
end
shared_examples 'authorized user' do |visibility_level|
let(:project) { create(:project, visibility_level) }
before do
project.add_reporter(user)
sign_in(user)
end
it 'renders OK' do
get :show, namespace_id: project.namespace, project_id: project
expect(response).to have_gitlab_http_status(200)
expect(response).to render_template(:show)
end
end
it_behaves_like 'authorized user', :public
it_behaves_like 'authorized user', :internal
it_behaves_like 'authorized user', :private
shared_examples 'unauthorized user' do |visibility_level|
let(:project) { create(:project, visibility_level) }
before do
sign_in(user)
end
it 'returns 404' do
get :show, namespace_id: project.namespace, project_id: project
expect(response).to have_gitlab_http_status(:not_found)
end
end
it_behaves_like 'unauthorized user', :public
it_behaves_like 'unauthorized user', :internal
it_behaves_like 'unauthorized user', :private
end
context 'with invalid license' do
before do
stub_licensed_features(tracing: false)
sign_in(user)
end
shared_examples 'invalid license' do |visibility_level|
let(:project) { create(:project, visibility_level) }
before do
stub_licensed_features(tracing: false)
project.add_reporter(user)
sign_in(user)
end
it 'returns 404' do
get :show, namespace_id: project.namespace, project_id: project
expect(response).to have_gitlab_http_status(:not_found)
end
end
it_behaves_like 'invalid license', :public
it_behaves_like 'invalid license', :internal
it_behaves_like 'invalid license', :private
end
end
end
......@@ -67,6 +67,7 @@ project:
- software_license_policies
- project_registry
- packages
- tracing_setting
prometheus_metrics:
- project
- prometheus_alerts
......@@ -78,3 +79,5 @@ prometheus_alert_events:
epic_issues:
- issue
- epic
tracing_setting:
- project
---
ProjectTracingSetting:
- external_url
# frozen_string_literal: true
require 'spec_helper'
describe ProjectTracingSetting do
describe '#external_url' do
let(:project) { build(:project) }
let(:tracing_setting) { project.build_tracing_setting }
it 'accepts a valid url' do
tracing_setting.external_url = "https://gitlab.com"
expect(tracing_setting).to be_valid
expect { tracing_setting.save! }.not_to raise_error
end
it 'fails with an invalid url' do
tracing_setting.external_url = "gitlab.com"
expect(tracing_setting).not_to be_valid
end
it 'fails with a blank string' do
tracing_setting.external_url = " "
expect(tracing_setting).not_to be_valid
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe 'layouts/nav/sidebar/_project' do
let(:project) { create(:project, :repository) }
before do
assign(:project, project)
assign(:repository, project.repository)
allow(view).to receive(:current_ref).and_return('master')
stub_licensed_features(tracing: true)
end
describe 'Operations > Tracing' do
it 'is not visible when no valid license' do
allow(view).to receive(:can?).and_return(true)
stub_licensed_features(tracing: false)
render
expect(rendered).not_to have_text 'Tracing'
end
it 'is not visible to unauthorized user' do
render
expect(rendered).not_to have_text 'Tracing'
end
context 'with project.tracing_external_url' do
let(:tracing_url) { 'https://tracing.url' }
before do
allow(view).to receive(:can?).and_return(true)
allow(project).to receive(:tracing_external_url).and_return(tracing_url)
end
it 'links to project.tracing_external_url' do
render
expect(rendered).to have_link('Tracing', href: tracing_url)
end
end
context 'without project.tracing_external_url' do
before do
allow(view).to receive(:can?).and_return(true)
allow(project).to receive(:tracing_external_url).and_return(nil)
end
it 'links to Tracing page' do
render
expect(rendered).to have_link('Tracing', href: project_tracing_path(project))
end
end
end
describe 'Settings > Operations' do
it 'is not visible when no valid license' do
allow(view).to receive(:can?).and_return(true)
stub_licensed_features(tracing: false)
render
expect(rendered).not_to have_link project_settings_operations_path(project)
end
it 'is not visible to unauthorized user' do
render
expect(rendered).not_to have_link project_settings_operations_path(project)
end
it 'links to settings page' do
allow(view).to receive(:can?).and_return(true)
render
expect(rendered).to have_link('Operations', href: project_settings_operations_path(project))
end
end
end
......@@ -396,6 +396,9 @@ msgstr ""
msgid "Add Group Webhooks and GitLab Enterprise Edition."
msgstr ""
msgid "Add Jaeger URL"
msgstr ""
msgid "Add Kubernetes cluster"
msgstr ""
......@@ -2180,6 +2183,9 @@ msgstr ""
msgid "Configure Gitaly timeouts."
msgstr ""
msgid "Configure Tracing"
msgstr ""
msgid "Configure automatic git checks and housekeeping on repositories."
msgstr ""
......@@ -3490,6 +3496,9 @@ msgstr ""
msgid "For more information, go to the "
msgstr ""
msgid "For more information, please review %{link_start_tag}Jaeger's configuration doc%{link_end_tag}"
msgstr ""
msgid "For more information, see the documentation on %{deactivating_usage_ping_link_start}deactivating the usage ping%{deactivating_usage_ping_link_end}."
msgstr ""
......@@ -4481,6 +4490,12 @@ msgstr ""
msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
msgstr ""
msgid "Jaeger URL"
msgstr ""
msgid "Jaeger tracing"
msgstr ""
msgid "Jan"
msgstr ""
......@@ -5653,6 +5668,9 @@ msgstr ""
msgid "Operations Dashboard"
msgstr ""
msgid "Operations Settings"
msgstr ""
msgid "OperationsDashboard|Add a project to the dashboard"
msgstr ""
......@@ -8395,6 +8413,9 @@ msgstr ""
msgid "To get started you enter your FogBugz URL and login information below. In the next steps, you'll be able to map users and select the projects you want to import."
msgstr ""
msgid "To get started, link this page to your Jaeger server, or find out how to %{link_start_tag}install Jaeger%{link_end_tag}"
msgstr ""
msgid "To get started, please enter your Gitea Host URL and a %{link_to_personal_token}."
msgstr ""
......@@ -8419,6 +8440,9 @@ msgstr ""
msgid "To only use CI/CD features for an external repository, choose <strong>CI/CD for external repo</strong>."
msgstr ""
msgid "To open Jaeger and easily view tracing from GitLab, link the %{start_tag}Tracing%{end_tag} page to your server"
msgstr ""
msgid "To set up SAML authentication for your group through an identity provider like Azure, Okta, Onelogin, Ping Identity, or your custom SAML 2.0 provider:"
msgstr ""
......@@ -8491,6 +8515,9 @@ msgstr ""
msgid "Total: %{total}"
msgstr ""
msgid "Tracing"
msgstr ""
msgid "Track activity with Contribution Analytics."
msgstr ""
......@@ -8521,6 +8548,9 @@ msgstr ""
msgid "Triggers can force a specific branch or tag to get rebuilt with an API call. These tokens will impersonate their associated user including their access to projects and their project permissions."
msgstr ""
msgid "Troubleshoot and monitor your application with tracing"
msgstr ""
msgid "Try again"
msgstr ""
......@@ -8539,6 +8569,9 @@ msgstr ""
msgid "Unable to load the diff. %{button_try_again}"
msgstr ""
msgid "Unable to save your changes"
msgstr ""
msgid "Unable to sign you in to the group with SAML due to \"%{reason}\""
msgstr ""
......@@ -9217,6 +9250,9 @@ msgstr ""
msgid "Your changes have been committed. Commit %{commitId} %{commitStats}"
msgstr ""
msgid "Your changes have been saved"
msgstr ""
msgid "Your comment will not be visible to the public."
msgstr ""
......
......@@ -23,15 +23,23 @@ describe 'Import/Export attribute configuration' do
let(:safe_attributes_file) { 'spec/lib/gitlab/import_export/safe_model_attributes.yml' }
let(:safe_model_attributes) { YAML.load_file(safe_attributes_file) }
let(:ee_safe_attributes_file) { 'ee/spec/lib/gitlab/import_export/safe_model_attributes.yml' }
let(:ee_safe_model_attributes) { File.exist?(ee_safe_attributes_file) ? YAML.load_file(ee_safe_attributes_file) : {} }
it 'has no new columns' do
relation_names.each do |relation_name|
relation_class = relation_class_for_name(relation_name)
relation_attributes = relation_class.new.attributes.keys
expect(safe_model_attributes[relation_class.to_s]).not_to be_nil, "Expected exported class #{relation_class} to exist in safe_model_attributes"
current_attributes = parsed_attributes(relation_name, relation_attributes)
safe_attributes = safe_model_attributes[relation_class.to_s]
safe_attributes = safe_model_attributes[relation_class.to_s].dup || []
ee_safe_model_attributes[relation_class.to_s].to_a.each do |attribute|
safe_attributes << attribute
end
expect(safe_attributes).not_to be_nil, "Expected exported class #{relation_class} to exist in safe_model_attributes"
new_attributes = current_attributes - safe_attributes
expect(new_attributes).to be_empty, failure_message(relation_class.to_s, new_attributes)
......@@ -43,6 +51,7 @@ describe 'Import/Export attribute configuration' do
It looks like #{relation_class}, which is exported using the project Import/Export, has new attributes: #{new_attributes.join(',')}
Please add the attribute(s) to SAFE_MODEL_ATTRIBUTES if you consider this can be exported.
#{"If the model/associations are EE-specific, use `#{File.expand_path(ee_safe_attributes_file)}`.\n" if ee_safe_model_attributes.any?}
Otherwise, please blacklist the attribute(s) in IMPORT_EXPORT_CONFIG by adding it to its correspondent
model in the +excluded_attributes+ section.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment