Commit 64874a79 authored by Matija Čupić's avatar Matija Čupić

Add POST project CI lint API endpoint

parent c982e3c3
......@@ -46,5 +46,25 @@ module API
present result, with: Entities::Ci::Lint::Result, current_user: current_user
end
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Validation of .gitlab-ci.yml content' do
detail 'This feature was introduced in GitLab 13.6.'
end
params do
requires :content, type: String, desc: 'Content of .gitlab-ci.yml'
optional :dry_run, type: Boolean, default: false, desc: 'Run pipeline creation simulation, or only do static check.'
end
post ':id/ci/lint' do
authorize! :download_code, user_project
result = Gitlab::Ci::Lint
.new(project: user_project, current_user: current_user)
.validate(params[:content], dry_run: params[:dry_run])
status 200
present result, with: Entities::Ci::Lint::Result, current_user: current_user
end
end
end
end
......@@ -275,4 +275,167 @@ RSpec.describe API::Lint do
end
end
end
describe 'POST /projects/:id/ci/lint' do
subject(:ci_lint) { post api("/projects/#{project.id}/ci/lint", api_user), params: { dry_run: dry_run, content: yaml_content } }
let(:project) { create(:project, :repository) }
let(:dry_run) { nil }
let_it_be(:api_user) { create(:user) }
let_it_be(:yaml_content) do
{ include: { local: 'another-gitlab-ci.yml' }, test: { stage: 'test', script: 'echo 1' } }.to_yaml
end
let_it_be(:included_content) do
{ another_test: { stage: 'test', script: 'echo 1' } }.to_yaml
end
RSpec.shared_examples 'valid project config' do
it 'passes validation' do
ci_lint
included_config = YAML.safe_load(included_content, [Symbol])
root_config = YAML.safe_load(yaml_content, [Symbol])
expected_yaml = included_config.merge(root_config).except(:include).to_yaml
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_an Hash
expect(json_response['merged_yaml']).to eq(expected_yaml)
expect(json_response['valid']).to eq(true)
expect(json_response['errors']).to eq([])
end
end
RSpec.shared_examples 'invalid project config' do
it 'responds with errors about invalid configuration' do
ci_lint
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['merged_yaml']).to eq(yaml_content)
expect(json_response['valid']).to eq(false)
expect(json_response['errors']).to eq(['jobs config should contain at least one visible job'])
end
end
context 'when unauthenticated' do
let_it_be(:api_user) { nil }
it 'returns authentication error' do
ci_lint
expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'when authenticated as non-member' do
context 'when project is private' do
before do
project.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
end
it 'returns authentication error' do
ci_lint
expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'when project is public' do
before do
project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
end
context 'when running as dry run' do
let(:dry_run) { true }
it 'returns pipeline creation error' do
ci_lint
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['merged_yaml']).to eq(nil)
expect(json_response['valid']).to eq(false)
expect(json_response['errors']).to eq(['Insufficient permissions to create a new pipeline'])
end
end
context 'when running static validation' do
let(:dry_run) { false }
before do
project.repository.create_file(
project.creator,
'another-gitlab-ci.yml',
included_content,
message: 'Automatically created another-gitlab-ci.yml',
branch_name: 'master'
)
end
it_behaves_like 'valid project config'
end
end
end
context 'when authenticated as project guest' do
before do
project.add_guest(api_user)
end
it 'returns authentication error' do
ci_lint
expect(response).to have_gitlab_http_status(:forbidden)
end
end
context 'when authenticated as project developer' do
before do
project.add_developer(api_user)
end
context 'with valid .gitlab-ci.yml content' do
before do
project.repository.create_file(
project.creator,
'another-gitlab-ci.yml',
included_content,
message: 'Automatically created another-gitlab-ci.yml',
branch_name: 'master'
)
end
context 'when running as dry run' do
let(:dry_run) { true }
it_behaves_like 'valid project config'
end
context 'when running static validation' do
let(:dry_run) { false }
it_behaves_like 'valid project config'
end
end
context 'with invalid .gitlab-ci.yml content' do
let(:yaml_content) do
{ image: 'ruby:2.7', services: ['postgres'] }.to_yaml
end
context 'when running as dry run' do
let(:dry_run) { true }
it_behaves_like 'invalid project config'
end
context 'when running static validation' do
let(:dry_run) { false }
it_behaves_like 'invalid project config'
end
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