Skip to content
代码片段 群组 项目
未验证 提交 31db9d50 编辑于 作者: Marius Bobin's avatar Marius Bobin
浏览文件

Suggest checking the partitioning doc when adding CI tables

New CI tables that reference large tables should be
should be partitioned from the start.
上级 37d8bac2
No related branches found
No related tags found
无相关合并请求
# frozen_string_literal: true
SEE_DB_DOC = "See the [database dictionary documentation](https://docs.gitlab.com/ee/development/database/database_dictionary.html)."
PARTITIONING_COMMENT = <<~SUGGEST_COMMENT
When adding new CI tables, consider [partitioning](https://docs.gitlab.com/ee/development/cicd/cicd_tables.html) the table
from the start if it references any of the larger CI tables: `ci_pipelines`, `ci_stages`, `ci_builds`, `p_ci_builds_metadata`, `ci_job_artifacts`, `ci_pipeline_variables`.
SUGGEST_COMMENT
def check_database_dictionary_yaml(database_dictionary)
return unless database_dictionary.ci_schema?
# `p_` prefix is used by the partitioned tables, so we can assume that the table is already partitioned
return if database_dictionary.table_name.to_s.start_with?('p_')
mr_line = database_dictionary.raw.lines.find_index { |line| line.start_with?('table_name:') }
return unless mr_line
markdown(PARTITIONING_COMMENT, file: database_dictionary.path, line: mr_line.succ)
rescue Psych::Exception
# YAML could not be parsed, fail the build.
fail "#{helper.html_link(database_ditionary.path)} isn't valid YAML! #{SEE_DB_DOC}" # rubocop:disable Style/SignalException
rescue StandardError => e
warn "There was a problem trying to check the database dictionary file. Exception: #{e.class.name} - #{e.message}"
end
def added_database_dictionary_files
database_dictionary.database_dictionary_files(change_type: :added)
end
added_database_dictionary_files.each do |database_dictionary|
check_database_dictionary_yaml(database_dictionary)
end
# frozen_string_literal: true
require_relative '../../tooling/danger/database_dictionary'
module Danger
class DatabaseDictionary < Plugin
# Put the helper code somewhere it can be tested
include Tooling::Danger::DatabaseDictionary
end
end
# frozen_string_literal: true
require 'gitlab-dangerfiles'
require 'gitlab/dangerfiles/spec_helper'
require_relative '../../../tooling/danger/database_dictionary'
RSpec.describe Tooling::Danger::DatabaseDictionary, feature_category: :shared do
include_context "with dangerfile"
let(:fake_danger) { DangerSpecHelper.fake_danger.include(described_class) }
subject(:database_dictionary) { fake_danger.new(helper: fake_helper) }
describe '#database_dictionary_files' do
let(:database_dictionary_files) do
[
'db/docs/ci_pipelines.yml',
'db/docs/projects.yml'
]
end
let(:other_files) do
[
'app/models/model.rb',
'app/assets/javascripts/file.js'
]
end
shared_examples 'an array of Found objects' do |change_type|
it 'returns an array of Found objects' do
expect(database_dictionary.database_dictionary_files(change_type: change_type))
.to contain_exactly(
an_instance_of(described_class::Found),
an_instance_of(described_class::Found)
)
expect(database_dictionary.database_dictionary_files(change_type: change_type).map(&:path))
.to eq(database_dictionary_files)
end
end
shared_examples 'an empty array' do |change_type|
it 'returns an array of Found objects' do
expect(database_dictionary.database_dictionary_files(change_type: change_type)).to be_empty
end
end
describe 'retrieves added database dictionary files' do
context 'with added added database dictionary files' do
let(:added_files) { database_dictionary_files }
include_examples 'an array of Found objects', :added
end
context 'without added added database dictionary files' do
let(:added_files) { other_files }
include_examples 'an empty array', :added
end
end
describe 'retrieves modified database dictionary files' do
context 'with modified modified database dictionary files' do
let(:modified_files) { database_dictionary_files }
include_examples 'an array of Found objects', :modified
end
context 'without modified modified database dictionary files' do
let(:modified_files) { other_files }
include_examples 'an empty array', :modified
end
end
describe 'retrieves deleted database dictionary files' do
context 'with deleted deleted database dictionary files' do
let(:deleted_files) { database_dictionary_files }
include_examples 'an array of Found objects', :deleted
end
context 'without deleted deleted database dictionary files' do
let(:deleted_files) { other_files }
include_examples 'an empty array', :deleted
end
end
end
describe described_class::Found do
let(:database_dictionary_path) { 'db/docs/ci_pipelines.yml' }
let(:gitlab_schema) { 'gitlab_ci' }
let(:yaml) do
{
'table_name' => 'ci_pipelines',
'classes' => ['Ci::Pipeline'],
'feature_categories' => ['continuous_integration'],
'description' => 'TODO',
'introduced_by_url' => 'https://gitlab.com/gitlab-org/gitlab/-/commit/c6ae290cea4b88ecaa9cfe0bc9d88e8fd32070c1',
'milestone' => '9.0',
'gitlab_schema' => gitlab_schema
}
end
let(:raw_yaml) { YAML.dump(yaml) }
subject(:found) { described_class.new(database_dictionary_path) }
before do
allow(File).to receive(:read).and_call_original
allow(File).to receive(:read).with(database_dictionary_path).and_return(raw_yaml)
end
described_class::ATTRIBUTES.each do |attribute|
describe "##{attribute}" do
it 'returns value from the YAML' do
expect(found.public_send(attribute)).to eq(yaml[attribute])
end
end
end
describe '#raw' do
it 'returns the raw YAML' do
expect(found.raw).to eq(raw_yaml)
end
end
describe '#ci_schema?' do
it { expect(found.ci_schema?).to be_truthy }
context 'with main schema' do
let(:gitlab_schema) { 'gitlab_main' }
it { expect(found.ci_schema?).to be_falsey }
end
end
describe '#main_schema?' do
it { expect(found.main_schema?).to be_falsey }
context 'with main schema' do
let(:gitlab_schema) { 'gitlab_main' }
it { expect(found.main_schema?).to be_truthy }
end
end
end
end
# frozen_string_literal: true
require 'yaml'
module Tooling
module Danger
module DatabaseDictionary
DICTIONARY_PATH_REGEXP = %r{db/docs/.*\.yml}
# `change_type` can be:
# - :added
# - :modified
# - :deleted
def database_dictionary_files(change_type:)
files = helper.public_send("#{change_type}_files") # rubocop:disable GitlabSecurity/PublicSend
files.filter_map { |path| Found.new(path) if path =~ DICTIONARY_PATH_REGEXP }
end
class Found
ATTRIBUTES = %w[
table_name classes feature_categories description introduced_by_url milestone gitlab_schema
].freeze
attr_reader :path
def initialize(path)
@path = path
end
ATTRIBUTES.each do |attribute|
define_method(attribute) do
yaml[attribute]
end
end
def raw
@raw ||= File.read(path)
end
def ci_schema?
gitlab_schema == 'gitlab_ci'
end
def main_schema?
gitlab_schema == 'gitlab_main'
end
private
def yaml
@yaml ||= YAML.safe_load(raw)
end
end
end
end
end
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册