Commit 31843dbd authored by Chad Woolley's avatar Chad Woolley

Introduce StaticSiteEditorConfigService class

* Second iteration towards static site editor config file.
* Replaces CombinedConfig with StaticSiteEditorConfigService.
* Moves merge_requests_illustration_path to GeneratedConfig,
  and adds stub static_site_generator in FileConfig.
* Improves feature spec to assert on config values
parent 1922007e
...@@ -14,19 +14,27 @@ class Projects::StaticSiteEditorController < Projects::ApplicationController ...@@ -14,19 +14,27 @@ class Projects::StaticSiteEditorController < Projects::ApplicationController
end end
def show def show
config = Gitlab::StaticSiteEditor::Config::CombinedConfig.new( service_response = ::StaticSiteEditor::ConfigService.new(
@repository, container: project,
@ref, current_user: current_user,
@path, params: {
params[:return_url] ref: @ref,
) path: @path,
@data = config.data return_url: params[:return_url]
}
).execute
if service_response.success?
@data = service_response.payload
else
respond_422
end
end end
private private
def assign_ref_and_path def assign_ref_and_path
@ref, @path = extract_ref(params[:id]) @ref, @path = extract_ref(params.fetch(:id))
render_404 if @ref.blank? || @path.blank? render_404 if @ref.blank? || @path.blank?
end end
......
# frozen_string_literal: true
module StaticSiteEditor
class ConfigService < ::BaseContainerService
ValidationError = Class.new(StandardError)
def execute
@project = container
check_access!
ServiceResponse.success(payload: data)
rescue ValidationError => e
ServiceResponse.error(message: e.message)
end
private
attr_reader :project
def check_access!
unless can?(current_user, :download_code, project)
raise ValidationError, 'Insufficient permissions to read configuration'
end
end
def data
check_for_duplicate_keys!
generated_data.merge(file_data)
end
def generated_data
@generated_data ||= Gitlab::StaticSiteEditor::Config::GeneratedConfig.new(
project.repository,
params.fetch(:ref),
params.fetch(:path),
params[:return_url]
).data
end
def file_data
@file_data ||= Gitlab::StaticSiteEditor::Config::FileConfig.new.data
end
def check_for_duplicate_keys!
duplicate_keys = generated_data.keys & file_data.keys
raise ValidationError.new("Duplicate key(s) '#{duplicate_keys}' found.") if duplicate_keys.present?
end
end
end
# frozen_string_literal: true
module Gitlab
module StaticSiteEditor
module Config
class CombinedConfig
def initialize(repository, ref, path, return_url)
@repository = repository
@ref = ref
@path = path
@return_url = return_url
end
def data
generated_data = Gitlab::StaticSiteEditor::Config::GeneratedConfig.new(
@repository,
@ref,
@path,
@return_url
).data
file_data = Gitlab::StaticSiteEditor::Config::FileConfig.new.data
check_for_duplicate_keys(generated_data, file_data)
generated_data.merge(file_data)
end
private
def check_for_duplicate_keys(generated_data, file_data)
duplicate_keys = generated_data.keys & file_data.keys
raise StandardError.new("Duplicate key(s) '#{duplicate_keys}' found.") if duplicate_keys.present?
end
end
end
end
end
...@@ -5,9 +5,8 @@ module Gitlab ...@@ -5,9 +5,8 @@ module Gitlab
module Config module Config
class FileConfig class FileConfig
def data def data
merge_requests_illustration_path = ActionController::Base.helpers.image_path('illustrations/merge_requests.svg')
{ {
merge_requests_illustration_path: merge_requests_illustration_path static_site_generator: 'middleman'
} }
end end
end end
......
...@@ -14,6 +14,7 @@ module Gitlab ...@@ -14,6 +14,7 @@ module Gitlab
end end
def data def data
merge_requests_illustration_path = ActionController::Base.helpers.image_path('illustrations/merge_requests.svg')
{ {
branch: ref, branch: ref,
path: path, path: path,
...@@ -23,7 +24,8 @@ module Gitlab ...@@ -23,7 +24,8 @@ module Gitlab
namespace: project.namespace.full_path, namespace: project.namespace.full_path,
return_url: sanitize_url(return_url), return_url: sanitize_url(return_url),
is_supported_content: supported_content?.to_s, is_supported_content: supported_content?.to_s,
base_url: Gitlab::Routing.url_helpers.project_show_sse_path(project, full_path) base_url: Gitlab::Routing.url_helpers.project_show_sse_path(project, full_path),
merge_requests_illustration_path: merge_requests_illustration_path
} }
end end
......
...@@ -7,12 +7,6 @@ RSpec.describe Projects::StaticSiteEditorController do ...@@ -7,12 +7,6 @@ RSpec.describe Projects::StaticSiteEditorController do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let(:data) { instance_double(Hash) } let(:data) { instance_double(Hash) }
before do
allow_next_instance_of(Gitlab::StaticSiteEditor::Config::CombinedConfig) do |config|
allow(config).to receive(:data) { data }
end
end
describe 'GET show' do describe 'GET show' do
let(:default_params) do let(:default_params) do
{ {
...@@ -23,6 +17,16 @@ RSpec.describe Projects::StaticSiteEditorController do ...@@ -23,6 +17,16 @@ RSpec.describe Projects::StaticSiteEditorController do
} }
end end
let(:service_response) do
ServiceResponse.success(payload: data)
end
before do
allow_next_instance_of(::StaticSiteEditor::ConfigService) do |instance|
allow(instance).to receive(:execute).and_return(service_response)
end
end
context 'User roles' do context 'User roles' do
context 'anonymous' do context 'anonymous' do
before do before do
...@@ -74,6 +78,14 @@ RSpec.describe Projects::StaticSiteEditorController do ...@@ -74,6 +78,14 @@ RSpec.describe Projects::StaticSiteEditorController do
expect(response).to have_gitlab_http_status(:not_found) expect(response).to have_gitlab_http_status(:not_found)
end end
end end
context 'when invalid config file' do
let(:service_response) { ServiceResponse.error(message: 'invalid') }
it 'returns 422' do
expect(response).to have_gitlab_http_status(:unprocessable_entity)
end
end
end end
end end
end end
......
...@@ -13,7 +13,11 @@ RSpec.describe 'Static Site Editor' do ...@@ -13,7 +13,11 @@ RSpec.describe 'Static Site Editor' do
visit project_show_sse_path(project, 'master/README.md') visit project_show_sse_path(project, 'master/README.md')
end end
it 'renders Static Site Editor page' do it 'renders Static Site Editor page with generated and file attributes' do
expect(page).to have_selector('#static-site-editor') # assert generated config value is present
expect(page).to have_css('#static-site-editor[data-branch="master"]')
# assert file config value is present
expect(page).to have_css('#static-site-editor[data-static-site-generator="middleman"]')
end end
end end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::StaticSiteEditor::Config::CombinedConfig do
subject(:config) { described_class.new(repository, ref, path, return_url) }
let(:repository) { double(:repository) }
let(:ref) { double(:ref) }
let(:path) { double(:path) }
let(:return_url) { double(:return_url) }
let(:generated_data) { { generated: true } }
let(:file_data) { { file: true } }
describe '#data' do
subject { config.data }
before do
allow_next_instance_of(Gitlab::StaticSiteEditor::Config::GeneratedConfig) do |config|
allow(config).to receive(:data) { generated_data }
end
allow_next_instance_of(Gitlab::StaticSiteEditor::Config::FileConfig) do |config|
allow(config).to receive(:data) { file_data }
end
end
it 'returns merged generated data and config file data' do
is_expected.to eq({ generated: true, file: true })
end
it 'raises an exception if any keys would be overwritten by the merge' do
generated_data[:duplicate_key] = true
file_data[:duplicate_key] = true
expect { subject }.to raise_error(StandardError, /duplicate key.*duplicate_key.*found/i)
end
end
end
...@@ -9,9 +9,7 @@ RSpec.describe Gitlab::StaticSiteEditor::Config::FileConfig do ...@@ -9,9 +9,7 @@ RSpec.describe Gitlab::StaticSiteEditor::Config::FileConfig do
subject { config.data } subject { config.data }
it 'returns hardcoded data for now' do it 'returns hardcoded data for now' do
is_expected.to match( is_expected.to match(static_site_generator: 'middleman')
merge_requests_illustration_path: %r{illustrations/merge_requests}
)
end end
end end
end end
...@@ -20,17 +20,19 @@ RSpec.describe Gitlab::StaticSiteEditor::Config::GeneratedConfig do ...@@ -20,17 +20,19 @@ RSpec.describe Gitlab::StaticSiteEditor::Config::GeneratedConfig do
subject { config.data } subject { config.data }
it 'returns data for the frontend component' do it 'returns data for the frontend component' do
is_expected.to eq( is_expected
branch: 'master', .to match({
commit_id: repository.commit.id, branch: 'master',
namespace: 'namespace', commit_id: repository.commit.id,
path: 'README.md', namespace: 'namespace',
project: 'project', path: 'README.md',
project_id: project.id, project: 'project',
return_url: 'http://example.com', project_id: project.id,
is_supported_content: 'true', return_url: 'http://example.com',
base_url: '/namespace/project/-/sse/master%2FREADME.md' is_supported_content: 'true',
) base_url: '/namespace/project/-/sse/master%2FREADME.md',
merge_requests_illustration_path: %r{illustrations/merge_requests}
})
end end
context 'when namespace is a subgroup' do context 'when namespace is a subgroup' do
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe StaticSiteEditor::ConfigService do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
# params
let(:ref) { double(:ref) }
let(:path) { double(:path) }
let(:return_url) { double(:return_url) }
# stub data
let(:generated_data) { { generated: true } }
let(:file_data) { { file: true } }
describe '#execute' do
subject(:execute) do
described_class.new(
container: project,
current_user: user,
params: {
ref: ref,
path: path,
return_url: return_url
}
).execute
end
context 'when insufficient permission' do
it 'returns an error' do
expect(execute).to be_error
expect(execute.message).to eq('Insufficient permissions to read configuration')
end
end
context 'for developer' do
before do
project.add_developer(user)
allow_next_instance_of(Gitlab::StaticSiteEditor::Config::GeneratedConfig) do |config|
allow(config).to receive(:data) { generated_data }
end
allow_next_instance_of(Gitlab::StaticSiteEditor::Config::FileConfig) do |config|
allow(config).to receive(:data) { file_data }
end
end
it 'returns merged generated data and config file data' do
expect(execute).to be_success
expect(execute.payload).to eq(generated: true, file: true)
end
it 'returns an error if any keys would be overwritten by the merge' do
generated_data[:duplicate_key] = true
file_data[:duplicate_key] = true
expect(execute).to be_error
expect(execute.message).to match(/duplicate key.*duplicate_key.*found/i)
end
end
end
end
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