Commit bcf59315 authored by Miguel Rincon's avatar Miguel Rincon

Merge branch 'fc-lint-querry' into 'master'

Add graphql query for linting in editor app

See merge request gitlab-org/gitlab!49379
parents 10b803c2 4e40a01b
#import "~/pipelines/graphql/queries/pipeline_stages.fragment.graphql"
query getCiConfigData($content: String!) {
ciConfig(content: $content) {
errors
status
stages {
...PipelineStagesData
}
}
}
<script>
import { GlAlert, GlLoadingIcon, GlTab, GlTabs } from '@gitlab/ui';
import { __, s__, sprintf } from '~/locale';
import { redirectTo, mergeUrlParams, refreshCurrentPage } from '~/lib/utils/url_utility';
import { mergeUrlParams, redirectTo, refreshCurrentPage } from '~/lib/utils/url_utility';
import PipelineGraph from '~/pipelines/components/pipeline_graph/pipeline_graph.vue';
import CommitForm from './components/commit/commit_form.vue';
......@@ -9,24 +9,25 @@ import TextEditor from './components/text_editor.vue';
import commitCiFileMutation from './graphql/mutations/commit_ci_file.mutation.graphql';
import getBlobContent from './graphql/queries/blob_content.graphql';
import getCiConfigData from './graphql/queries/ci_config.graphql';
const MR_SOURCE_BRANCH = 'merge_request[source_branch]';
const MR_TARGET_BRANCH = 'merge_request[target_branch]';
const LOAD_FAILURE_NO_REF = 'LOAD_FAILURE_NO_REF';
const LOAD_FAILURE_NO_FILE = 'LOAD_FAILURE_NO_FILE';
const LOAD_FAILURE_UNKNOWN = 'LOAD_FAILURE_UNKNOWN';
const COMMIT_FAILURE = 'COMMIT_FAILURE';
const DEFAULT_FAILURE = 'DEFAULT_FAILURE';
const LOAD_FAILURE_NO_FILE = 'LOAD_FAILURE_NO_FILE';
const LOAD_FAILURE_NO_REF = 'LOAD_FAILURE_NO_REF';
const LOAD_FAILURE_UNKNOWN = 'LOAD_FAILURE_UNKNOWN';
export default {
components: {
CommitForm,
GlAlert,
GlLoadingIcon,
GlTab,
GlTabs,
PipelineGraph,
CommitForm,
TextEditor,
},
props: {
......@@ -55,14 +56,15 @@ export default {
},
data() {
return {
showFailureAlert: false,
ciConfigData: {},
content: '',
contentModel: '',
currentTabIndex: 0,
editorIsReady: false,
failureType: null,
failureReasons: [],
isSaving: false,
editorIsReady: false,
content: '',
contentModel: '',
showFailureAlert: false,
};
},
apollo: {
......@@ -85,18 +87,35 @@ export default {
this.handleBlobContentError(error);
},
},
ciConfigData: {
query: getCiConfigData,
// If content is not loaded, we can't lint the data
skip: ({ contentModel }) => {
return !contentModel;
},
variables() {
return {
content: this.contentModel,
};
},
update(data) {
return data?.ciConfig ?? {};
},
error() {
this.reportFailure(LOAD_FAILURE_UNKNOWN);
},
},
},
computed: {
isLoading() {
isBlobContentLoading() {
return this.$apollo.queries.content.loading;
},
isVisualizeTabActive() {
return this.currentTabIndex === 1;
},
defaultCommitMessage() {
return sprintf(this.$options.i18n.defaultCommitMessage, { sourcePath: this.ciConfigPath });
},
pipelineData() {
// Note data will loaded as part of https://gitlab.com/gitlab-org/gitlab/-/issues/263141
return {};
},
failure() {
switch (this.failureType) {
case LOAD_FAILURE_NO_REF:
......@@ -233,17 +252,17 @@ export default {
</ul>
</gl-alert>
<div class="gl-mt-4">
<gl-loading-icon v-if="isLoading" size="lg" class="gl-m-3" />
<gl-loading-icon v-if="isBlobContentLoading" size="lg" class="gl-m-3" />
<div v-else class="file-editor gl-mb-3">
<gl-tabs>
<gl-tabs v-model="currentTabIndex">
<!-- editor should be mounted when its tab is visible, so the container has a size -->
<gl-tab :title="$options.i18n.tabEdit" :lazy="!editorIsReady">
<!-- editor should be mounted only once, when the tab is displayed -->
<text-editor v-model="contentModel" @editor-ready="editorIsReady = true" />
</gl-tab>
<gl-tab :title="$options.i18n.tabGraph">
<pipeline-graph :pipeline-data="pipelineData" />
<gl-tab :title="$options.i18n.tabGraph" :lazy="!isVisualizeTabActive">
<pipeline-graph :pipeline-data="ciConfigData" />
</gl-tab>
</gl-tabs>
</div>
......
fragment PipelineStagesData on CiConfigStage {
name
groups {
name
jobs {
name
needs {
name
}
}
}
}
......@@ -12,6 +12,16 @@ job1:
- echo 'test'
`;
export const mockCiConfigQueryResponse = {
data: {
ciConfig: {
errors: [],
stages: [],
status: '',
},
},
};
export const mockLintResponse = {
valid: true,
errors: [],
......
......@@ -13,9 +13,10 @@ import waitForPromises from 'helpers/wait_for_promises';
import VueApollo from 'vue-apollo';
import createMockApollo from 'jest/helpers/mock_apollo_helper';
import { redirectTo, refreshCurrentPage, objectToQuery } from '~/lib/utils/url_utility';
import { objectToQuery, redirectTo, refreshCurrentPage } from '~/lib/utils/url_utility';
import {
mockCiConfigPath,
mockCiConfigQueryResponse,
mockCiYml,
mockCommitId,
mockCommitMessage,
......@@ -24,10 +25,11 @@ import {
mockNewMergeRequestPath,
} from './mock_data';
import TextEditor from '~/pipeline_editor/components/text_editor.vue';
import CommitForm from '~/pipeline_editor/components/commit/commit_form.vue';
import getCiConfig from '~/pipeline_editor/graphql/queries/ci_config.graphql';
import PipelineGraph from '~/pipelines/components/pipeline_graph/pipeline_graph.vue';
import PipelineEditorApp from '~/pipeline_editor/pipeline_editor_app.vue';
import CommitForm from '~/pipeline_editor/components/commit/commit_form.vue';
import TextEditor from '~/pipeline_editor/components/text_editor.vue';
const localVue = createLocalVue();
localVue.use(VueApollo);
......@@ -42,9 +44,10 @@ jest.mock('~/lib/utils/url_utility', () => ({
describe('~/pipeline_editor/pipeline_editor_app.vue', () => {
let wrapper;
let mockMutate;
let mockApollo;
let mockBlobContentData;
let mockCiConfigData;
let mockMutate;
const createComponent = ({
props = {},
......@@ -96,7 +99,8 @@ describe('~/pipeline_editor/pipeline_editor_app.vue', () => {
};
const createComponentWithApollo = ({ props = {}, mountFn = shallowMount } = {}) => {
mockApollo = createMockApollo([], {
const handlers = [[getCiConfig, mockCiConfigData]];
const resolvers = {
Query: {
blobContent() {
return {
......@@ -105,7 +109,9 @@ describe('~/pipeline_editor/pipeline_editor_app.vue', () => {
};
},
},
});
};
mockApollo = createMockApollo(handlers, resolvers);
const options = {
localVue,
......@@ -125,10 +131,12 @@ describe('~/pipeline_editor/pipeline_editor_app.vue', () => {
beforeEach(() => {
mockBlobContentData = jest.fn();
mockCiConfigData = jest.fn().mockResolvedValue(mockCiConfigQueryResponse);
});
afterEach(() => {
mockBlobContentData.mockReset();
mockCiConfigData.mockReset();
refreshCurrentPage.mockReset();
redirectTo.mockReset();
mockMutate.mockReset();
......@@ -177,12 +185,10 @@ describe('~/pipeline_editor/pipeline_editor_app.vue', () => {
beforeEach(async () => {
createComponent({ mountFn: mount });
wrapper.setData({
await wrapper.setData({
content: mockCiYml,
contentModel: mockCiYml,
});
await nextTick();
});
it('displays content after the query loads', () => {
......@@ -347,7 +353,7 @@ describe('~/pipeline_editor/pipeline_editor_app.vue', () => {
});
describe('displays fetch content errors', () => {
it('no error is show when data is set', async () => {
it('no error is shown when data is set', async () => {
mockBlobContentData.mockResolvedValue(mockCiYml);
createComponentWithApollo();
......
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