diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-07-20 12:55:51 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-07-20 12:55:51 +0300 |
commit | e8d2c2579383897a1dd7f9debd359abe8ae8373d (patch) | |
tree | c42be41678c2586d49a75cabce89322082698334 /app/assets/javascripts/pipeline_editor | |
parent | fc845b37ec3a90aaa719975f607740c22ba6a113 (diff) |
Add latest changes from gitlab-org/gitlab@14-1-stable-eev14.1.0-rc42
Diffstat (limited to 'app/assets/javascripts/pipeline_editor')
15 files changed, 189 insertions, 55 deletions
diff --git a/app/assets/javascripts/pipeline_editor/components/commit/commit_form.vue b/app/assets/javascripts/pipeline_editor/components/commit/commit_form.vue index f6e88738002..f1fe8cf10fd 100644 --- a/app/assets/javascripts/pipeline_editor/components/commit/commit_form.vue +++ b/app/assets/javascripts/pipeline_editor/components/commit/commit_form.vue @@ -103,6 +103,7 @@ export default { v-model="targetBranch" class="gl-font-monospace!" required + data-qa-selector="target_branch_field" /> <gl-form-checkbox v-if="!isCurrentBranchTarget" diff --git a/app/assets/javascripts/pipeline_editor/components/editor/ci_config_merged_preview.vue b/app/assets/javascripts/pipeline_editor/components/editor/ci_config_merged_preview.vue index 455990f2791..853e839a7ab 100644 --- a/app/assets/javascripts/pipeline_editor/components/editor/ci_config_merged_preview.vue +++ b/app/assets/javascripts/pipeline_editor/components/editor/ci_config_merged_preview.vue @@ -2,14 +2,14 @@ import { GlIcon } from '@gitlab/ui'; import { uniqueId } from 'lodash'; import { s__ } from '~/locale'; -import EditorLite from '~/vue_shared/components/editor_lite.vue'; +import SourceEditor from '~/vue_shared/components/source_editor.vue'; export default { i18n: { viewOnlyMessage: s__('Pipelines|Merged YAML is view only'), }, components: { - EditorLite, + SourceEditor, GlIcon, }, inject: ['ciConfigPath'], @@ -41,7 +41,7 @@ export default { {{ $options.i18n.viewOnlyMessage }} </div> <div class="gl-mt-3 gl-border-solid gl-border-gray-100 gl-border-1"> - <editor-lite + <source-editor ref="editor" :value="mergedYaml" :file-name="ciConfigPath" diff --git a/app/assets/javascripts/pipeline_editor/components/editor/ci_editor_header.vue b/app/assets/javascripts/pipeline_editor/components/editor/ci_editor_header.vue new file mode 100644 index 00000000000..b4e9ab81d38 --- /dev/null +++ b/app/assets/javascripts/pipeline_editor/components/editor/ci_editor_header.vue @@ -0,0 +1,38 @@ +<script> +import { GlButton } from '@gitlab/ui'; +import { __ } from '~/locale'; +import Tracking from '~/tracking'; +import { pipelineEditorTrackingOptions, TEMPLATE_REPOSITORY_URL } from '../../constants'; + +export default { + i18n: { + browseTemplates: __('Browse templates'), + }, + TEMPLATE_REPOSITORY_URL, + components: { + GlButton, + }, + mixins: [Tracking.mixin()], + methods: { + trackTemplateBrowsing() { + const { label, actions } = pipelineEditorTrackingOptions; + + this.track(actions.browse_templates, { label }); + }, + }, +}; +</script> + +<template> + <div class="gl-bg-gray-10 gl-p-3 gl-border-solid gl-border-gray-100 gl-border-1"> + <gl-button + :href="$options.TEMPLATE_REPOSITORY_URL" + size="small" + icon="external-link" + target="_blank" + @click="trackTemplateBrowsing" + > + {{ $options.i18n.browseTemplates }} + </gl-button> + </div> +</template> diff --git a/app/assets/javascripts/pipeline_editor/components/editor/text_editor.vue b/app/assets/javascripts/pipeline_editor/components/editor/text_editor.vue index d373f74a5c4..77ede396496 100644 --- a/app/assets/javascripts/pipeline_editor/components/editor/text_editor.vue +++ b/app/assets/javascripts/pipeline_editor/components/editor/text_editor.vue @@ -1,13 +1,13 @@ <script> import { EDITOR_READY_EVENT } from '~/editor/constants'; -import { CiSchemaExtension } from '~/editor/extensions/editor_ci_schema_ext'; -import EditorLite from '~/vue_shared/components/editor_lite.vue'; +import { CiSchemaExtension } from '~/editor/extensions/source_editor_ci_schema_ext'; +import SourceEditor from '~/vue_shared/components/source_editor.vue'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import getCommitSha from '../../graphql/queries/client/commit_sha.graphql'; export default { components: { - EditorLite, + SourceEditor, }, mixins: [glFeatureFlagMixin()], inject: ['ciConfigPath', 'projectPath', 'projectNamespace', 'defaultBranch'], @@ -43,8 +43,8 @@ export default { }; </script> <template> - <div class="gl-border-solid gl-border-gray-100 gl-border-1"> - <editor-lite + <div class="gl-border-solid gl-border-gray-100 gl-border-1 gl-border-t-none!"> + <source-editor ref="editor" :file-name="ciConfigPath" v-bind="$attrs" diff --git a/app/assets/javascripts/pipeline_editor/components/file_nav/branch_switcher.vue b/app/assets/javascripts/pipeline_editor/components/file_nav/branch_switcher.vue index 05b87abecd5..ee6d4ff7c4d 100644 --- a/app/assets/javascripts/pipeline_editor/components/file_nav/branch_switcher.vue +++ b/app/assets/javascripts/pipeline_editor/components/file_nav/branch_switcher.vue @@ -158,6 +158,12 @@ export default { const updatedPath = setUrlParams({ branch_name: newBranch }); historyPushState(updatedPath); + this.$emit('updateCommitSha', { newBranch }); + + // refetching the content will cause a lot of components to re-render, + // including the text editor which uses the commit sha to register the CI schema + // so we need to make sure the commit sha is updated first + await this.$nextTick(); this.$emit('refetchContent'); }, async setSearchTerm(newSearchTerm) { @@ -205,6 +211,7 @@ export default { :header-text="$options.i18n.dropdownHeader" :text="currentBranch" icon="branch" + data-qa-selector="branch_selector_button" > <gl-search-box-by-type :debounce="$options.inputDebounce" @input="setSearchTerm" /> <gl-dropdown-section-header> @@ -222,6 +229,7 @@ export default { :key="branch" :is-checked="currentBranch === branch" :is-check-item="true" + data-qa-selector="menu_branch_button" @click="selectBranch(branch)" > {{ branch }} diff --git a/app/assets/javascripts/pipeline_editor/components/header/pipeline_status.vue b/app/assets/javascripts/pipeline_editor/components/header/pipeline_status.vue index 368a026bdaa..6af3361e7e6 100644 --- a/app/assets/javascripts/pipeline_editor/components/header/pipeline_status.vue +++ b/app/assets/javascripts/pipeline_editor/components/header/pipeline_status.vue @@ -66,6 +66,7 @@ export default { }, data() { return { + commitSha: '', hasError: false, }; }, diff --git a/app/assets/javascripts/pipeline_editor/components/header/validation_segment.vue b/app/assets/javascripts/pipeline_editor/components/header/validation_segment.vue index d1534655a00..8bffd893473 100644 --- a/app/assets/javascripts/pipeline_editor/components/header/validation_segment.vue +++ b/app/assets/javascripts/pipeline_editor/components/header/validation_segment.vue @@ -87,7 +87,7 @@ export default { <template> <div> <template v-if="isLoading"> - <gl-loading-icon inline /> + <gl-loading-icon size="sm" inline /> {{ $options.i18n.loading }} </template> diff --git a/app/assets/javascripts/pipeline_editor/components/pipeline_editor_tabs.vue b/app/assets/javascripts/pipeline_editor/components/pipeline_editor_tabs.vue index c3dcc00af6e..e463fcf379d 100644 --- a/app/assets/javascripts/pipeline_editor/components/pipeline_editor_tabs.vue +++ b/app/assets/javascripts/pipeline_editor/components/pipeline_editor_tabs.vue @@ -16,6 +16,7 @@ import { } from '../constants'; import getAppStatus from '../graphql/queries/client/app_status.graphql'; import CiConfigMergedPreview from './editor/ci_config_merged_preview.vue'; +import CiEditorHeader from './editor/ci_editor_header.vue'; import TextEditor from './editor/text_editor.vue'; import CiLint from './lint/ci_lint.vue'; import EditorTab from './ui/editor_tab.vue'; @@ -49,6 +50,7 @@ export default { }, components: { CiConfigMergedPreview, + CiEditorHeader, CiLint, EditorTab, GlAlert, @@ -107,6 +109,7 @@ export default { data-testid="editor-tab" @click="setCurrentTab($options.tabConstants.CREATE_TAB)" > + <ci-editor-header /> <text-editor :value="ciFileContent" v-on="$listeners" /> </editor-tab> <editor-tab diff --git a/app/assets/javascripts/pipeline_editor/constants.js b/app/assets/javascripts/pipeline_editor/constants.js index 1467abd7289..d05b06d16db 100644 --- a/app/assets/javascripts/pipeline_editor/constants.js +++ b/app/assets/javascripts/pipeline_editor/constants.js @@ -33,3 +33,13 @@ export const BRANCH_PAGINATION_LIMIT = 20; export const BRANCH_SEARCH_DEBOUNCE = '500'; export const STARTER_TEMPLATE_NAME = 'Getting-Started'; + +export const pipelineEditorTrackingOptions = { + label: 'pipeline_editor', + actions: { + browse_templates: 'browse_templates', + }, +}; + +export const TEMPLATE_REPOSITORY_URL = + 'https://gitlab.com/gitlab-org/gitlab-foss/tree/master/lib/gitlab/ci/templates'; diff --git a/app/assets/javascripts/pipeline_editor/graphql/mutations/update_commit_sha.mutation.graphql b/app/assets/javascripts/pipeline_editor/graphql/mutations/update_commit_sha.mutation.graphql new file mode 100644 index 00000000000..dce17cad808 --- /dev/null +++ b/app/assets/javascripts/pipeline_editor/graphql/mutations/update_commit_sha.mutation.graphql @@ -0,0 +1,3 @@ +mutation updateCommitSha($commitSha: String) { + updateCommitSha(commitSha: $commitSha) @client +} diff --git a/app/assets/javascripts/pipeline_editor/graphql/queries/blob_content.graphql b/app/assets/javascripts/pipeline_editor/graphql/queries/blob_content.graphql index 9f1b5b13088..5500244b430 100644 --- a/app/assets/javascripts/pipeline_editor/graphql/queries/blob_content.graphql +++ b/app/assets/javascripts/pipeline_editor/graphql/queries/blob_content.graphql @@ -1,5 +1,11 @@ -query getBlobContent($projectPath: ID!, $path: String, $ref: String!) { - blobContent(projectPath: $projectPath, path: $path, ref: $ref) @client { - rawData +query getBlobContent($projectPath: ID!, $path: String!, $ref: String) { + project(fullPath: $projectPath) { + repository { + blobs(paths: [$path], ref: $ref) { + nodes { + rawBlob + } + } + } } } diff --git a/app/assets/javascripts/pipeline_editor/graphql/queries/ci_config.graphql b/app/assets/javascripts/pipeline_editor/graphql/queries/ci_config.graphql index 30c18a96536..df7de6a1f54 100644 --- a/app/assets/javascripts/pipeline_editor/graphql/queries/ci_config.graphql +++ b/app/assets/javascripts/pipeline_editor/graphql/queries/ci_config.graphql @@ -1,7 +1,7 @@ #import "~/pipelines/graphql/fragments/pipeline_stages_connection.fragment.graphql" -query getCiConfigData($projectPath: ID!, $content: String!) { - ciConfig(projectPath: $projectPath, content: $content) { +query getCiConfigData($projectPath: ID!, $sha: String, $content: String!) { + ciConfig(projectPath: $projectPath, sha: $sha, content: $content) { errors mergedYaml status diff --git a/app/assets/javascripts/pipeline_editor/graphql/queries/latest_commit_sha.query.graphql b/app/assets/javascripts/pipeline_editor/graphql/queries/latest_commit_sha.query.graphql new file mode 100644 index 00000000000..219c23bb22b --- /dev/null +++ b/app/assets/javascripts/pipeline_editor/graphql/queries/latest_commit_sha.query.graphql @@ -0,0 +1,12 @@ +query getLatestCommitSha($projectPath: ID!, $ref: String) { + project(fullPath: $projectPath) { + pipelines(ref: $ref) { + nodes { + id + sha + path + commitPath + } + } + } +} diff --git a/app/assets/javascripts/pipeline_editor/graphql/resolvers.js b/app/assets/javascripts/pipeline_editor/graphql/resolvers.js index 8cead7f3315..2bec2006e95 100644 --- a/app/assets/javascripts/pipeline_editor/graphql/resolvers.js +++ b/app/assets/javascripts/pipeline_editor/graphql/resolvers.js @@ -1,20 +1,10 @@ import produce from 'immer'; -import Api from '~/api'; import axios from '~/lib/utils/axios_utils'; +import getCommitShaQuery from './queries/client/commit_sha.graphql'; import getCurrentBranchQuery from './queries/client/current_branch.graphql'; import getLastCommitBranchQuery from './queries/client/last_commit_branch.query.graphql'; export const resolvers = { - Query: { - blobContent(_, { projectPath, path, ref }) { - return { - __typename: 'BlobContent', - rawData: Api.getRawFile(projectPath, path, { ref }).then(({ data }) => { - return data; - }), - }; - }, - }, Mutation: { lintCI: (_, { endpoint, content, dry_run }) => { return axios.post(endpoint, { content, dry_run }).then(({ data }) => ({ @@ -42,7 +32,15 @@ export const resolvers = { __typename: 'CiLintContent', })); }, - updateCurrentBranch: (_, { currentBranch = undefined }, { cache }) => { + updateCommitSha: (_, { commitSha }, { cache }) => { + cache.writeQuery({ + query: getCommitShaQuery, + data: produce(cache.readQuery({ query: getCommitShaQuery }), (draftData) => { + draftData.commitSha = commitSha; + }), + }); + }, + updateCurrentBranch: (_, { currentBranch }, { cache }) => { cache.writeQuery({ query: getCurrentBranchQuery, data: produce(cache.readQuery({ query: getCurrentBranchQuery }), (draftData) => { @@ -50,7 +48,7 @@ export const resolvers = { }), }); }, - updateLastCommitBranch: (_, { lastCommitBranch = undefined }, { cache }) => { + updateLastCommitBranch: (_, { lastCommitBranch }, { cache }) => { cache.writeQuery({ query: getLastCommitBranchQuery, data: produce(cache.readQuery({ query: getLastCommitBranchQuery }), (draftData) => { diff --git a/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue b/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue index c24e6523352..0e8a6805a59 100644 --- a/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue +++ b/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue @@ -1,7 +1,7 @@ <script> import { GlLoadingIcon } from '@gitlab/ui'; import { fetchPolicies } from '~/lib/graphql'; -import httpStatusCodes from '~/lib/utils/http_status'; +import { queryToObject } from '~/lib/utils/url_utility'; import { s__ } from '~/locale'; import { unwrapStagesWithNeeds } from '~/pipelines/components/unwrapping_utils'; @@ -16,12 +16,15 @@ import { LOAD_FAILURE_UNKNOWN, STARTER_TEMPLATE_NAME, } from './constants'; +import updateCommitShaMutation from './graphql/mutations/update_commit_sha.mutation.graphql'; import getBlobContent from './graphql/queries/blob_content.graphql'; import getCiConfigData from './graphql/queries/ci_config.graphql'; import getAppStatus from './graphql/queries/client/app_status.graphql'; +import getCommitSha from './graphql/queries/client/commit_sha.graphql'; import getCurrentBranch from './graphql/queries/client/current_branch.graphql'; import getIsNewCiConfigFile from './graphql/queries/client/is_new_ci_config_file.graphql'; import getTemplate from './graphql/queries/get_starter_template.query.graphql'; +import getLatestCommitShaQuery from './graphql/queries/latest_commit_sha.query.graphql'; import PipelineEditorHome from './pipeline_editor_home.vue'; export default { @@ -42,6 +45,7 @@ export default { }, data() { return { + starterTemplateName: STARTER_TEMPLATE_NAME, ciConfigData: {}, failureType: null, failureReasons: [], @@ -76,22 +80,40 @@ export default { }; }, update(data) { - return data?.blobContent?.rawData; + return data?.project?.repository?.blobs?.nodes[0]?.rawBlob; }, result({ data }) { - const fileContent = data?.blobContent?.rawData ?? ''; + const nodes = data?.project?.repository?.blobs?.nodes; + if (!nodes) { + this.reportFailure(LOAD_FAILURE_UNKNOWN); + } else { + const rawBlob = nodes[0]?.rawBlob; + const fileContent = rawBlob ?? ''; - this.lastCommittedContent = fileContent; - this.currentCiFileContent = fileContent; + this.lastCommittedContent = fileContent; + this.currentCiFileContent = fileContent; - // make sure to reset the start screen flag during a refetch - // e.g. when switching branches - if (fileContent.length) { - this.showStartScreen = false; + // If rawBlob is defined and returns a string, it means that there is + // a CI config file with empty content. If `rawBlob` is not defined + // at all, it means there was no file found. + const hasCIFile = rawBlob === '' || fileContent.length > 0; + + if (!fileContent.length) { + this.setAppStatus(EDITOR_APP_STATUS_EMPTY); + } + + if (!hasCIFile) { + this.showStartScreen = true; + } else if (fileContent.length) { + // If the file content is > 0, then we make sure to reset the + // start screen flag during a refetch + // e.g. when switching branches + this.showStartScreen = false; + } } }, - error(error) { - this.handleBlobContentError(error); + error() { + this.reportFailure(LOAD_FAILURE_UNKNOWN); }, watchLoading(isLoading) { if (isLoading) { @@ -107,6 +129,7 @@ export default { variables() { return { projectPath: this.projectFullPath, + sha: this.commitSha, content: this.currentCiFileContent, }; }, @@ -132,6 +155,9 @@ export default { appStatus: { query: getAppStatus, }, + commitSha: { + query: getCommitSha, + }, currentBranch: { query: getCurrentBranch, }, @@ -143,7 +169,7 @@ export default { variables() { return { projectPath: this.projectFullPath, - templateName: STARTER_TEMPLATE_NAME, + templateName: this.starterTemplateName, }; }, skip({ isNewCiConfigFile }) { @@ -186,23 +212,10 @@ export default { } }, }, + mounted() { + this.loadTemplateFromURL(); + }, methods: { - handleBlobContentError(error = {}) { - const { networkError } = error; - - const { response } = networkError; - // 404 for missing CI file - // 400 for blank projects with no repository - if ( - response?.status === httpStatusCodes.NOT_FOUND || - response?.status === httpStatusCodes.BAD_REQUEST - ) { - this.setAppStatus(EDITOR_APP_STATUS_EMPTY); - this.showStartScreen = true; - } else { - this.reportFailure(LOAD_FAILURE_UNKNOWN); - } - }, hideFailure() { this.showFailure = false; }, @@ -244,6 +257,38 @@ export default { updateCiConfig(ciFileContent) { this.currentCiFileContent = ciFileContent; }, + async updateCommitSha({ newBranch }) { + let fetchResults; + + try { + fetchResults = await this.$apollo.query({ + query: getLatestCommitShaQuery, + variables: { + projectPath: this.projectFullPath, + ref: newBranch, + }, + }); + } catch { + this.showFetchError(); + return; + } + + if (fetchResults.errors?.length > 0) { + this.showFetchError(); + return; + } + + const pipelineNodes = fetchResults?.data?.project?.pipelines?.nodes ?? []; + if (pipelineNodes.length === 0) { + return; + } + + const commitSha = pipelineNodes[0].sha; + this.$apollo.mutate({ + mutation: updateCommitShaMutation, + variables: { commitSha }, + }); + }, updateOnCommit({ type }) { this.reportSuccess(type); @@ -257,6 +302,14 @@ export default { // if the user has made changes to the file that are unsaved. this.lastCommittedContent = this.currentCiFileContent; }, + loadTemplateFromURL() { + const templateName = queryToObject(window.location.search)?.template; + + if (templateName) { + this.starterTemplateName = templateName; + this.setNewEmptyCiConfigFile(); + } + }, }, }; </script> @@ -288,6 +341,7 @@ export default { @showError="showErrorAlert" @refetchContent="refetchContent" @updateCiConfig="updateCiConfig" + @updateCommitSha="updateCommitSha" /> <confirm-unsaved-changes-dialog :has-unsaved-changes="hasUnsavedChanges" /> </div> |