Commit 7342dcc5 authored by Matija Čupić's avatar Matija Čupić

Implement required templates

Implements the backend logic for required templates.
parent 374fddfc
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddRequiredTemplateNameToApplicationSettings < ActiveRecord::Migration[5.1]
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
def change
add_column :application_settings, :required_instance_ci_template, :string, null: true
end
end
......@@ -225,6 +225,7 @@ ActiveRecord::Schema.define(version: 20190611161641) do
t.integer "elasticsearch_replicas", default: 1, null: false
t.text "encrypted_lets_encrypt_private_key"
t.text "encrypted_lets_encrypt_private_key_iv"
t.string "required_instance_ci_template"
t.boolean "dns_rebinding_protection_enabled", default: true, null: false
t.boolean "default_project_deletion_protection", default: false, null: false
t.boolean "lock_memberships_to_ldap", default: false, null: false
......
......@@ -30,6 +30,10 @@ module EE
attrs << :default_project_deletion_protection
end
if License.feature_available?(:required_ci_templates)
attrs << :required_instance_ci_template
end
attrs
end
end
......
......@@ -86,6 +86,7 @@ class License < ApplicationRecord
dependency_proxy
metrics_reports
custom_prometheus_metrics
required_ci_templates
]
EEP_FEATURES.freeze
......@@ -190,6 +191,7 @@ class License < ApplicationRecord
repository_size_limit
custom_project_templates
usage_quotas
required_ci_templates
].freeze
validate :valid_license
......
# frozen_string_literal: true
module EE
module Gitlab
module Ci
module Config
extend ::Gitlab::Utils::Override
override :rescue_errors
def rescue_errors
[*super, ::Gitlab::Ci::Config::Required::Processor::RequiredError]
end
override :build_config
def build_config(config, project:, sha:, user:)
process_required_includes(super)
end
def process_required_includes(config)
::Gitlab::Ci::Config::Required::Processor.new(config).perform
end
end
end
end
end
# frozen_string_literal: true
module Gitlab
module Ci
class Config
module Required
class Processor
RequiredError = Class.new(StandardError)
def initialize(config)
@config = config
end
def perform
return @config unless ::License.feature_available?(:required_ci_templates)
return @config unless required_ci_template_name
merge_required_template
end
def merge_required_template
raise RequiredError, "Required template '#{required_ci_template_name}' not found!" unless required_template
@config.deep_merge(required_template_hash)
end
private
def required_template_hash
Gitlab::Config::Loader::Yaml.new(required_template.content).load!
end
def required_template
::TemplateFinder.build(:gitlab_ci_ymls, nil, name: required_ci_template_name).execute
end
def required_ci_template_name
::Gitlab::CurrentSettings.current_application_settings.required_instance_ci_template
end
end
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Ci::Config do
let(:template_name) { 'test_template' }
let(:template_repository) { create(:project, :custom_repo, files: { "gitlab-ci/#{template_name}.yml" => template_yml }) }
let(:ci_yml) do
<<-EOS
sample_job:
script:
- echo 'test'
EOS
end
let(:template_yml) do
<<-EOS
sample_job:
script:
- echo 'not test'
EOS
end
subject { described_class.new(ci_yml) }
before do
stub_application_setting(file_template_project: template_repository, required_instance_ci_template: template_name)
stub_licensed_features(custom_file_templates: true, required_ci_templates: true)
end
it 'processes the required includes' do
expect(subject.to_hash[:sample_job][:script]).to eq(["echo 'not test'"])
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Ci::Config::Required::Processor do
subject { described_class.new(config).perform }
let(:config) { { image: 'ruby:2.5.3' } }
context 'when feature is available' do
before do
stub_licensed_features(required_ci_templates: true)
stub_application_setting(required_instance_ci_template: required_ci_template_name)
end
context 'when template is set' do
context 'when template can not be found' do
let(:required_ci_template_name) { 'invalid_template_name' }
it 'raises an error' do
expect { subject }.to raise_error(Gitlab::Ci::Config::Required::Processor::RequiredError)
end
end
context 'when template can be found' do
let(:required_ci_template_name) { 'Android' }
it 'merges the template content with the config' do
expect(subject).to include(image: 'openjdk:8-jdk')
end
end
end
context 'when template is not set' do
let(:required_ci_template_name) { nil }
it 'returns the unmodified config' do
expect(subject).to eq(config)
end
end
end
context 'when feature is not available' do
before do
stub_licensed_features(required_ci_templates: false)
end
it 'returns the unmodified config' do
expect(subject).to eq(config)
end
end
end
......@@ -8,6 +8,12 @@ module Gitlab
class Config
ConfigError = Class.new(StandardError)
RESCUE_ERRORS = [
Gitlab::Config::Loader::FormatError,
Extendable::ExtensionError,
External::Processor::IncludeError
].freeze
def initialize(config, project: nil, sha: nil, user: nil)
@config = Config::Extendable
.new(build_config(config, project: project, sha: sha, user: user))
......@@ -15,9 +21,7 @@ module Gitlab
@global = Entry::Global.new(@config)
@global.compose!
rescue Gitlab::Config::Loader::FormatError,
Extendable::ExtensionError,
External::Processor::IncludeError => e
rescue *rescue_errors => e
raise Config::ConfigError, e.message
end
......@@ -83,6 +87,13 @@ module Gitlab
user: user,
expandset: Set.new).perform
end
# Overriden in EE
def rescue_errors
RESCUE_ERRORS
end
end
end
end
Gitlab::Ci::Config.prepend(EE::Gitlab::Ci::Config)
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