Commit af6a7a19 authored by Alper Akgun's avatar Alper Akgun

Merge branch '292658-include-keyword-for-cilint-graphql' into 'master'

Add project scope to ci clint graphql endpoint

See merge request gitlab-org/gitlab!50418
parents cfb5cecd 1201f46a
#import "~/pipelines/graphql/queries/pipeline_stages_connection.fragment.graphql"
query getCiConfigData($content: String!) {
ciConfig(content: $content) {
query getCiConfigData($projectPath: ID!, $content: String!) {
ciConfig(projectPath: $projectPath, content: $content) {
errors
status
stages {
......
......@@ -105,6 +105,7 @@ export default {
},
variables() {
return {
projectPath: this.projectPath,
content: this.contentModel,
};
},
......
......@@ -3,14 +3,27 @@
module Resolvers
module Ci
class ConfigResolver < BaseResolver
include Gitlab::Graphql::Authorize::AuthorizeResource
include ResolvesProject
type Types::Ci::Config::ConfigType, null: true
authorize :read_pipeline
argument :project_path, GraphQL::ID_TYPE,
required: true,
description: 'The project of the CI config'
argument :content, GraphQL::STRING_TYPE,
required: true,
description: 'Contents of .gitlab-ci.yml'
def resolve(content:)
result = ::Gitlab::Ci::YamlProcessor.new(content).execute
def resolve(project_path:, content:)
project = authorized_find!(project_path: project_path)
result = ::Gitlab::Ci::YamlProcessor.new(content, project: project,
user: current_user,
sha: project.repository.commit.sha).execute
response = if result.errors.empty?
{
......@@ -55,6 +68,10 @@ module Resolvers
.group_by { |group| group[:stage] }
.map { |name, groups| { name: name, groups: groups } }
end
def find_object(project_path:)
resolve_project(full_path: project_path)
end
end
end
end
---
title: Add project scope to ci clint graphql endpoint
merge_request: 50418
author:
type: fixed
......@@ -19387,6 +19387,11 @@ type Query {
Contents of .gitlab-ci.yml
"""
content: String!
"""
The project of the CI config
"""
projectPath: ID!
): CiConfig
"""
......
......@@ -56517,6 +56517,20 @@
"name": "ciConfig",
"description": "Get linted and processed contents of a CI config. Should not be requested more than once per request.",
"args": [
{
"name": "projectPath",
"description": "The project of the CI config",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "content",
"description": "Contents of .gitlab-ci.yml",
......@@ -142,7 +142,7 @@ describe('~/pipeline_editor/pipeline_editor_app.vue', () => {
beforeEach(() => {
mockBlobContentData = jest.fn();
mockCiConfigData = jest.fn().mockResolvedValue(mockCiConfigQueryResponse);
mockCiConfigData = jest.fn();
});
afterEach(() => {
......@@ -413,9 +413,13 @@ describe('~/pipeline_editor/pipeline_editor_app.vue', () => {
});
});
describe('displays fetch content errors', () => {
it('no error is shown when data is set', async () => {
describe('when queries are called', () => {
beforeEach(() => {
mockBlobContentData.mockResolvedValue(mockCiYml);
mockCiConfigData.mockResolvedValue(mockCiConfigQueryResponse);
});
it('no error is shown when data is set', async () => {
createComponentWithApollo();
await waitForPromises();
......@@ -424,6 +428,17 @@ describe('~/pipeline_editor/pipeline_editor_app.vue', () => {
expect(findEditorLite().attributes('value')).toBe(mockCiYml);
});
it('ci config query is called with correct variables', async () => {
createComponentWithApollo();
await waitForPromises();
expect(mockCiConfigData).toHaveBeenCalledWith({
content: mockCiYml,
projectPath: mockProjectPath,
});
});
it('shows a 404 error message', async () => {
mockBlobContentData.mockRejectedValueOnce({
response: {
......
......@@ -13,6 +13,15 @@ RSpec.describe Resolvers::Ci::ConfigResolver do
allow(::Gitlab::Ci::YamlProcessor).to receive(:new).and_return(yaml_processor_double)
end
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :repository, creator: user, namespace: user.namespace) }
subject(:response) do
resolve(described_class,
args: { project_path: project.full_path, content: content },
ctx: { current_user: user })
end
context 'with a valid .gitlab-ci.yml' do
let(:fake_result) do
::Gitlab::Ci::YamlProcessor::Result.new(
......@@ -27,8 +36,6 @@ RSpec.describe Resolvers::Ci::ConfigResolver do
end
it 'lints the ci config file' do
response = resolve(described_class, args: { content: content }, ctx: {})
expect(response[:status]).to eq(:valid)
expect(response[:errors]).to be_empty
end
......@@ -46,8 +53,6 @@ RSpec.describe Resolvers::Ci::ConfigResolver do
end
it 'responds with errors about invalid syntax' do
response = resolve(described_class, args: { content: content }, ctx: {})
expect(response[:status]).to eq(:invalid)
expect(response[:errors]).to eq(['Invalid configuration format'])
end
......
......@@ -7,7 +7,8 @@ RSpec.describe 'Query.ciConfig' do
subject(:post_graphql_query) { post_graphql(query, current_user: user) }
let(:user) { create(:user) }
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :repository, creator: user, namespace: user.namespace) }
let_it_be(:content) do
File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci_includes.yml'))
......@@ -16,7 +17,7 @@ RSpec.describe 'Query.ciConfig' do
let(:query) do
%(
query {
ciConfig(content: "#{content}") {
ciConfig(projectPath: "#{project.full_path}", content: "#{content}") {
status
errors
stages {
......@@ -47,13 +48,15 @@ RSpec.describe 'Query.ciConfig' do
)
end
before do
post_graphql_query
it_behaves_like 'a working graphql query' do
before do
post_graphql_query
end
end
it_behaves_like 'a working graphql query'
it 'returns the correct structure' do
post_graphql_query
expect(graphql_data['ciConfig']).to eq(
"status" => "VALID",
"errors" => [],
......@@ -114,4 +117,75 @@ RSpec.describe 'Query.ciConfig' do
}
)
end
context 'when the config file includes other files' do
let_it_be(:content) do
YAML.dump(
include: 'other_file.yml',
rspec: {
script: 'rspec'
}
)
end
before do
allow_next_instance_of(Repository) do |repository|
allow(repository).to receive(:blob_data_at).with(an_instance_of(String), 'other_file.yml') do
YAML.dump(
build: {
script: 'build'
}
)
end
end
post_graphql_query
end
it_behaves_like 'a working graphql query'
it 'returns the correct structure with included files' do
expect(graphql_data['ciConfig']).to eq(
"status" => "VALID",
"errors" => [],
"stages" =>
{
"nodes" =>
[
{
"name" => "test",
"groups" =>
{
"nodes" =>
[
{
"name" => "build",
"size" => 1,
"jobs" =>
{
"nodes" =>
[
{ "name" => "build", "groupName" => "build", "stage" => "test", "needs" => { "nodes" => [] } }
]
}
},
{
"name" => "rspec",
"size" => 1,
"jobs" =>
{
"nodes" =>
[
{ "name" => "rspec", "groupName" => "rspec", "stage" => "test", "needs" => { "nodes" => [] } }
]
}
}
]
}
}
]
}
)
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