Commit 95b296f8 authored by Matija Čupić's avatar Matija Čupić

Change ExternalFile to retrieve local file from repository instead of GitLab project

CE mirror of 03c6094997023d9c8875ced421a6c9ef39a4af44
parent cd72189f
...@@ -15,7 +15,7 @@ module BlobViewer ...@@ -15,7 +15,7 @@ module BlobViewer
prepare! prepare!
@validation_message = Gitlab::Ci::YamlProcessor.validation_message(blob.data) @validation_message = Gitlab::Ci::YamlProcessor.validation_message(blob.data, project)
end end
def valid? def valid?
......
...@@ -980,6 +980,10 @@ class Repository ...@@ -980,6 +980,10 @@ class Repository
blob_data_at(sha, '.gitlab/route-map.yml') blob_data_at(sha, '.gitlab/route-map.yml')
end end
def fetch_file_for(sha, path_to_file)
blob_data_at(sha, path_to_file)
end
def gitlab_ci_yml_for(sha, path = '.gitlab-ci.yml') def gitlab_ci_yml_for(sha, path = '.gitlab-ci.yml')
blob_data_at(sha, path) blob_data_at(sha, path)
end end
......
...@@ -12,7 +12,7 @@ module Gitlab ...@@ -12,7 +12,7 @@ module Gitlab
.to_hash .to_hash
if project.present? if project.present?
processor = ::Gitlab::Ci::ExternalFiles::Processor.new(initial_config) processor = ::Gitlab::Ci::ExternalFiles::Processor.new(initial_config, project)
@config = processor.perform @config = processor.perform
else else
@config = initial_config @config = initial_config
......
...@@ -4,33 +4,38 @@ module Gitlab ...@@ -4,33 +4,38 @@ module Gitlab
module Ci module Ci
module ExternalFiles module ExternalFiles
class ExternalFile class ExternalFile
def initialize(value) def initialize(value, project)
@value = value @value = value
@project = project
end end
def content def content
if remote_url? if remote_url?
open(value).read open(value).read
else else
File.read(base_path) local_file_content
end end
end end
def valid? def valid?
remote_url? || File.exist?(base_path) remote_url? || local_file_content
end end
private private
attr_reader :value attr_reader :value, :project
def base_path
"#{Rails.root}/#{value}"
end
def remote_url? def remote_url?
::Gitlab::UrlSanitizer.valid?(value) ::Gitlab::UrlSanitizer.valid?(value)
end end
def local_file_content
project.repository.fetch_file_for(sha, value)
end
def sha
@sha ||= project.repository.commit.sha
end
end end
end end
end end
......
...@@ -2,12 +2,12 @@ module Gitlab ...@@ -2,12 +2,12 @@ module Gitlab
module Ci module Ci
module ExternalFiles module ExternalFiles
class Mapper class Mapper
def self.fetch_paths(values) def initialize(values, project)
paths = values.fetch(:includes, []) @paths = values.fetch(:includes, [])
normalize_paths(paths) @project = project
end end
def self.normalize_paths(paths) def process
if paths.is_a?(String) if paths.is_a?(String)
[build_external_file(paths)] [build_external_file(paths)]
else else
...@@ -15,8 +15,12 @@ module Gitlab ...@@ -15,8 +15,12 @@ module Gitlab
end end
end end
def self.build_external_file(path) private
::Gitlab::Ci::ExternalFiles::ExternalFile.new(path)
attr_reaer :paths, :project
def build_external_file(path)
::Gitlab::Ci::ExternalFiles::ExternalFile.new(path, project)
end end
end end
end end
......
...@@ -4,9 +4,9 @@ module Gitlab ...@@ -4,9 +4,9 @@ module Gitlab
class Processor class Processor
ExternalFileError = Class.new(StandardError) ExternalFileError = Class.new(StandardError)
def initialize(values) def initialize(values, project)
@values = values @values = values
@external_files = ::Gitlab::Ci::ExternalFiles::Mapper.fetch_paths(values) @external_files = ::Gitlab::Ci::ExternalFiles::Mapper.fetch_paths(values, project).process
end end
def perform def perform
......
...@@ -73,13 +73,13 @@ module Gitlab ...@@ -73,13 +73,13 @@ module Gitlab
end end
end end
def self.validation_message(content, opts = {}) def self.validation_message(content, project = nil, opts = {})
return 'Please provide content of .gitlab-ci.yml' if content.blank? return 'Please provide content of .gitlab-ci.yml' if content.blank?
begin begin
Gitlab::Ci::YamlProcessor.new(content, opts) Gitlab::Ci::YamlProcessor.new(content, project, opts)
nil nil
rescue ValidationError => e rescue ValidationError, ::Gitlab::Ci::ExternalFiles::Processor::ExternalFileError => e
e.message e.message
end end
end end
......
variables:
# AUTO_DEVOPS_DOMAIN is the application deployment domain and should be set as a variable at the group or project level.
AUTO_DEVOPS_DOMAIN: domain.example.com
POSTGRES_USER: user
POSTGRES_PASSWORD: testing-password
POSTGRES_ENABLED: "true"
POSTGRES_DB: $CI_ENVIRONMENT_SLUG
...@@ -127,6 +127,17 @@ describe Gitlab::Ci::Config do ...@@ -127,6 +127,17 @@ describe Gitlab::Ci::Config do
end end
context "when yml has valid 'includes' defined" do context "when yml has valid 'includes' defined" do
let(:http_file_content) do
<<~HEREDOC
variables:
AUTO_DEVOPS_DOMAIN: domain.example.com
POSTGRES_USER: user
POSTGRES_PASSWORD: testing-password
POSTGRES_ENABLED: "true"
POSTGRES_DB: $CI_ENVIRONMENT_SLUG
HEREDOC
end
let(:local_file_content) { File.read("#{Rails.root}/spec/ee/fixtures/gitlab/ci/external_files/.gitlab-ci-template-1.yml") }
let(:yml) do let(:yml) do
<<-EOS <<-EOS
includes: includes:
...@@ -139,7 +150,8 @@ describe Gitlab::Ci::Config do ...@@ -139,7 +150,8 @@ describe Gitlab::Ci::Config do
end end
before do before do
allow_any_instance_of(Kernel).to receive_message_chain(:open, :read).and_return(yml) allow_any_instance_of(::Gitlab::Ci::ExternalFiles::ExternalFile).to receive(:local_file_content).and_return(local_file_content)
allow_any_instance_of(Kernel).to receive_message_chain(:open, :read).and_return(http_file_content)
end end
it 'should return a composed hash' do it 'should return a composed hash' do
...@@ -167,7 +179,7 @@ describe Gitlab::Ci::Config do ...@@ -167,7 +179,7 @@ describe Gitlab::Ci::Config do
end end
end end
context "when config has invalid 'includes' defined" do context "when yml has invalid 'includes' defined" do
let(:yml) do let(:yml) do
<<-EOS <<-EOS
includes: invalid includes: invalid
......
require 'rails_helper' require 'rails_helper'
describe Gitlab::Ci::ExternalFiles::ExternalFile do describe Gitlab::Ci::ExternalFiles::ExternalFile do
let(:external_file) { described_class.new(value) } let(:project) { create(:project, :repository) }
let(:external_file) { described_class.new(value, project) }
describe "#valid?" do describe "#valid?" do
context 'when is a valid remote url' do context 'when is a valid remote url' do
let(:value) { 'https://gitlab.com/gitlab-org/gitlab-ce/blob/1234/.gitlab-ci-1.yml' } let(:value) { 'https://gitlab.com/gitlab-org/gitlab-ce/blob/1234/.gitlab-ci-1.yml' }
before do
allow_any_instance_of(described_class).to receive(:local_file_content).and_return("image: 'ruby2:2'")
end
it 'should return true' do it 'should return true' do
expect(external_file.valid?).to be_truthy expect(external_file.valid?).to be_truthy
end end
...@@ -54,8 +59,7 @@ describe Gitlab::Ci::ExternalFiles::ExternalFile do ...@@ -54,8 +59,7 @@ describe Gitlab::Ci::ExternalFiles::ExternalFile do
let(:value) { '/vendor/gitlab-ci-yml/non-existent-file.yml' } let(:value) { '/vendor/gitlab-ci-yml/non-existent-file.yml' }
before do before do
allow(File).to receive(:exists?).and_return(true) allow_any_instance_of(described_class).to receive(:local_file_content).and_return(external_file_content)
allow(File).to receive(:read).and_return(external_file_content)
end end
it 'should return the content of the file' do it 'should return the content of the file' do
......
require 'rails_helper' require 'rails_helper'
describe Gitlab::Ci::ExternalFiles::Mapper do describe Gitlab::Ci::ExternalFiles::Mapper do
describe '.fetch_paths' do let(:project) { create(:project, :repository) }
context 'when includes is defined as string' do
let(:values) { { includes: '/vendor/gitlab-ci-yml/non-existent-file.yml', image: 'ruby:2.2' } } describe '#process' do
subject { described_class.new(values, project).process }
context 'when includes keyword is defined as string' do
let(:values) do
{
includes: '/vendor/gitlab-ci-yml/non-existent-file.yml',
image: 'ruby:2.2'
}
end
it 'returns an array' do it 'returns an array' do
expect(described_class.fetch_paths(values)).to be_an(Array) expect(subject).to be_an(Array)
end end
it 'returns ExternalFile instances' do it 'returns ExternalFile instances' do
expect(described_class.fetch_paths(values).first).to be_an_instance_of(::Gitlab::Ci::ExternalFiles::ExternalFile) expect(subject.first).to be_an_instance_of(::Gitlab::Ci::ExternalFiles::ExternalFile)
end end
end end
context 'when includes is defined as an array' do context 'when includes is defined as an array' do
let(:values) { { includes: ['https://gitlab.com/gitlab-org/gitlab-ce/blob/1234/.gitlab-ci-1.yml', '/vendor/gitlab-ci-yml/template.yml'], image: 'ruby:2.2' } } let(:values) do
{
includes:
[
'https://gitlab.com/gitlab-org/gitlab-ce/blob/1234/.gitlab-ci-1.yml',
'/vendor/gitlab-ci-yml/template.yml'
],
image: 'ruby:2.2'
}
end
it 'returns an array' do it 'returns an array' do
expect(described_class.fetch_paths(values)).to be_an(Array) expect(subject).to be_an(Array)
end end
it 'returns ExternalFile instances' do it 'returns ExternalFile instances' do
paths = described_class.fetch_paths(values) expect(subject).to all(be_an_instance_of(::Gitlab::Ci::ExternalFiles::ExternalFile))
expect(paths).to all(be_an_instance_of(::Gitlab::Ci::ExternalFiles::ExternalFile))
end end
end end
context 'when includes is not defined' do context 'when includes is not defined' do
let(:values) { { image: 'ruby:2.2' } } let(:values) do
{ image: 'ruby:2.2' }
end
it 'returns an empty array' do it 'returns an empty array' do
expect(described_class.fetch_paths(values)).to be_empty expect(subject).to be_empty
end end
end end
end end
......
require 'rails_helper' require 'rails_helper'
describe Gitlab::Ci::ExternalFiles::Processor do describe Gitlab::Ci::ExternalFiles::Processor do
let(:processor) { described_class.new(values) } let(:project) { create(:project, :repository) }
let(:processor) { described_class.new(values, project) }
describe "#perform" do describe "#perform" do
context 'when no external files defined' do context 'when no external files defined' do
...@@ -77,8 +78,7 @@ describe Gitlab::Ci::ExternalFiles::Processor do ...@@ -77,8 +78,7 @@ describe Gitlab::Ci::ExternalFiles::Processor do
end end
before do before do
allow(File).to receive(:exists?).and_return(true) allow_any_instance_of(::Gitlab::Ci::ExternalFiles::ExternalFile).to receive(:local_file_content).and_return(external_file_content)
allow(File).to receive(:read).and_return(external_file_content)
end end
it 'should append the file to the values' do it 'should append the file to the values' do
...@@ -95,7 +95,6 @@ describe Gitlab::Ci::ExternalFiles::Processor do ...@@ -95,7 +95,6 @@ describe Gitlab::Ci::ExternalFiles::Processor do
let(:external_files) do let(:external_files) do
[ [
"/spec/ee/fixtures/gitlab/ci/external_files/.gitlab-ci-template-1.yml", "/spec/ee/fixtures/gitlab/ci/external_files/.gitlab-ci-template-1.yml",
"/spec/ee/fixtures/gitlab/ci/external_files/.gitlab-ci-template-2.yml",
'https://gitlab.com/gitlab-org/gitlab-ce/blob/1234/.gitlab-ci-1.yml' 'https://gitlab.com/gitlab-org/gitlab-ce/blob/1234/.gitlab-ci-1.yml'
] ]
end end
...@@ -111,11 +110,13 @@ describe Gitlab::Ci::ExternalFiles::Processor do ...@@ -111,11 +110,13 @@ describe Gitlab::Ci::ExternalFiles::Processor do
end end
before do before do
file_content = File.read("#{Rails.root}/spec/ee/fixtures/gitlab/ci/external_files/.gitlab-ci-template-1.yml")
allow_any_instance_of(::Gitlab::Ci::ExternalFiles::ExternalFile).to receive(:local_file_content).and_return(file_content)
allow_any_instance_of(Kernel).to receive_message_chain(:open, :read).and_return(remote_file_content) allow_any_instance_of(Kernel).to receive_message_chain(:open, :read).and_return(remote_file_content)
end end
it 'should append the files to the values' do it 'should append the files to the values' do
expect(processor.perform.keys).to match_array([:image, :variables, :stages, :before_script, :rspec]) expect(processor.perform.keys).to match_array([:image, :stages, :before_script, :rspec])
end end
it "should remove the 'includes' keyword" do it "should remove the 'includes' keyword" do
...@@ -129,8 +130,7 @@ describe Gitlab::Ci::ExternalFiles::Processor do ...@@ -129,8 +130,7 @@ describe Gitlab::Ci::ExternalFiles::Processor do
let(:external_file_content) { 'invalid content file ////' } let(:external_file_content) { 'invalid content file ////' }
before do before do
allow(File).to receive(:exists?).and_return(true) allow_any_instance_of(::Gitlab::Ci::ExternalFiles::ExternalFile).to receive(:local_file_content).and_return(external_file_content)
allow(File).to receive(:read).and_return(external_file_content)
end end
it 'should raise an error' do it 'should raise an error' do
......
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