Commit d7f44cc9 authored by Frédéric Caplette's avatar Frédéric Caplette

Merge branch 'suggest-pipeline-banner-to-pipeline-editor' into 'master'

Use Pipeline Editor to add new CI file from Suggest Pipeline banner

See merge request gitlab-org/gitlab!73514
parents d1fcae19 82418b00
......@@ -52,6 +52,7 @@ export default {
isFetchingCommitSha: false,
isNewCiConfigFile: false,
lastCommittedContent: '',
shouldSkipStartScreen: false,
showFailure: false,
showStartScreen: false,
showSuccess: false,
......@@ -60,7 +61,6 @@ export default {
successType: null,
};
},
apollo: {
initialCiFileContent: {
fetchPolicy: fetchPolicies.NETWORK_ONLY,
......@@ -103,7 +103,11 @@ export default {
}
if (!hasCIFile) {
this.showStartScreen = true;
if (this.shouldSkipStartScreen) {
this.setNewEmptyCiConfigFile();
} else {
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
......@@ -229,6 +233,7 @@ export default {
},
mounted() {
this.loadTemplateFromURL();
this.checkShouldSkipStartScreen();
},
methods: {
hideFailure() {
......@@ -293,6 +298,10 @@ export default {
this.setNewEmptyCiConfigFile();
}
},
checkShouldSkipStartScreen() {
const params = queryToObject(window.location.search);
this.shouldSkipStartScreen = Boolean(params?.add_new_config_file);
},
},
};
</script>
......
......@@ -4,9 +4,7 @@ import Tracking from '~/tracking';
import DismissibleContainer from '~/vue_shared/components/dismissible_container.vue';
import {
SP_TRACK_LABEL,
SP_LINK_TRACK_EVENT,
SP_SHOW_TRACK_EVENT,
SP_LINK_TRACK_VALUE,
SP_SHOW_TRACK_VALUE,
SP_HELP_CONTENT,
SP_HELP_URL,
......@@ -20,9 +18,7 @@ export default {
name: 'MRWidgetSuggestPipeline',
SP_ICON_NAME,
SP_TRACK_LABEL,
SP_LINK_TRACK_EVENT,
SP_SHOW_TRACK_EVENT,
SP_LINK_TRACK_VALUE,
SP_SHOW_TRACK_VALUE,
SP_HELP_CONTENT,
SP_HELP_URL,
......@@ -81,29 +77,14 @@ export default {
<div>
<gl-sprintf
:message="
s__(`mrWidget|%{prefixToLinkStart}No pipeline%{prefixToLinkEnd}
%{addPipelineLinkStart}Add the .gitlab-ci.yml file%{addPipelineLinkEnd}
to create one.`)
s__(`mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}`)
"
>
<template #prefixToLink="{ content }">
<template #boldHeader="{ content }">
<strong>
{{ content }}
</strong>
</template>
<template #addPipelineLink="{ content }">
<gl-link
:href="pipelinePath"
class="gl-ml-1"
data-testid="add-pipeline-link"
:data-track-property="humanAccess"
:data-track-value="$options.SP_LINK_TRACK_VALUE"
:data-track-action="$options.SP_LINK_TRACK_EVENT"
:data-track-label="$options.SP_TRACK_LABEL"
>
{{ content }}
</gl-link>
</template>
</gl-sprintf>
</div>
</template>
......@@ -115,9 +96,6 @@ export default {
</div>
<div class="col-md-7 order-md-first col-12">
<div class="ml-6 gl-pt-5">
<strong>
{{ s__('mrWidget|Are you adding technical debt or code vulnerabilities?') }}
</strong>
<p class="gl-mt-2">
<gl-sprintf :message="$options.SP_HELP_CONTENT">
<template #link="{ content }">
......@@ -142,7 +120,7 @@ export default {
:data-track-action="$options.SP_SHOW_TRACK_EVENT"
:data-track-label="$options.SP_TRACK_LABEL"
>
{{ __('Show me how to add a pipeline') }}
{{ __('Try out GitLab Pipelines') }}
</gl-button>
</div>
</div>
......
......@@ -17,14 +17,12 @@ export const AUTO_MERGE_STRATEGIES = [MWPS_MERGE_STRATEGY, MTWPS_MERGE_STRATEGY,
// SP - "Suggest Pipelines"
export const SP_TRACK_LABEL = 'no_pipeline_noticed';
export const SP_LINK_TRACK_EVENT = 'click_link';
export const SP_SHOW_TRACK_EVENT = 'click_button';
export const SP_LINK_TRACK_VALUE = 30;
export const SP_SHOW_TRACK_VALUE = 10;
export const SP_HELP_CONTENT = s__(
`mrWidget|Use %{linkStart}CI pipelines to test your code%{linkEnd} by simply adding a GitLab CI configuration file to your project. It only takes a minute to make your code more secure and robust.`,
`mrWidget|GitLab %{linkStart}CI/CD can automatically build, test, and deploy your application.%{linkEnd} It only takes a few minutes to get started, and we can help you create a pipeline configuration file.`,
);
export const SP_HELP_URL = 'https://about.gitlab.com/blog/2019/07/12/guide-to-ci-cd-pipelines/';
export const SP_HELP_URL = 'https://docs.gitlab.com/ee/ci/quick_start/';
export const SP_ICON_NAME = 'status_notfound';
export const MERGE_ACTIVE_STATUS_PHRASES = [
......
......@@ -64,14 +64,12 @@ class MergeRequestWidgetEntity < Grape::Entity
end
expose :merge_request_add_ci_config_path, if: ->(mr, _) { can_add_ci_config_path?(mr) } do |merge_request|
project_new_blob_path(
merge_request.source_project,
merge_request.source_branch,
file_name: '.gitlab-ci.yml',
commit_message: s_("CommitMessage|Add %{file_name}") % { file_name: Gitlab::FileDetector::PATTERNS[:gitlab_ci] },
mr_path: merge_request_path(merge_request),
suggest_gitlab_ci_yml: true
)
project = merge_request.source_project
params = {
branch_name: merge_request.source_branch,
add_new_config_file: true
}
project_ci_pipeline_editor_path(project, params)
end
expose :user_callouts_path do |_merge_request|
......@@ -177,7 +175,6 @@ class MergeRequestWidgetEntity < Grape::Entity
def can_add_ci_config_path?(merge_request)
merge_request.open? &&
merge_request.source_branch_exists? &&
merge_request.source_project&.uses_default_ci_config? &&
!merge_request.source_project.has_ci? &&
merge_request.commits_count > 0 &&
can?(current_user, :read_build, merge_request.source_project) &&
......
......@@ -31838,9 +31838,6 @@ msgstr ""
msgid "Show list"
msgstr ""
msgid "Show me how to add a pipeline"
msgstr ""
msgid "Show one file at a time"
msgstr ""
......@@ -36525,6 +36522,9 @@ msgstr ""
msgid "Try grouping with different labels"
msgstr ""
msgid "Try out GitLab Pipelines"
msgstr ""
msgid "Try to fork again"
msgstr ""
......@@ -41105,6 +41105,9 @@ msgstr ""
msgid "mrWidget| Please restore it or use a different %{missingBranchName} branch"
msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
msgstr ""
......@@ -41123,9 +41126,6 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
msgid "mrWidget|%{prefixToLinkStart}No pipeline%{prefixToLinkEnd} %{addPipelineLinkStart}Add the .gitlab-ci.yml file%{addPipelineLinkEnd} to create one."
msgstr ""
msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge."
msgstr ""
......@@ -41168,9 +41168,6 @@ msgstr ""
msgid "mrWidget|Approved by you and others"
msgstr ""
msgid "mrWidget|Are you adding technical debt or code vulnerabilities?"
msgstr ""
msgid "mrWidget|Cancel auto-merge"
msgstr ""
......@@ -41224,6 +41221,9 @@ msgstr ""
msgid "mrWidget|Failed to load deployment statistics"
msgstr ""
msgid "mrWidget|GitLab %{linkStart}CI/CD can automatically build, test, and deploy your application.%{linkEnd} It only takes a few minutes to get started, and we can help you create a pipeline configuration file."
msgstr ""
msgid "mrWidget|Hide %{widget} details"
msgstr ""
......@@ -41391,9 +41391,6 @@ msgstr ""
msgid "mrWidget|To merge, a Jira issue key must be mentioned in the title or description."
msgstr ""
msgid "mrWidget|Use %{linkStart}CI pipelines to test your code%{linkEnd} by simply adding a GitLab CI configuration file to your project. It only takes a minute to make your code more secure and robust."
msgstr ""
msgid "mrWidget|What is a merge train?"
msgstr ""
......
......@@ -16,7 +16,8 @@ RSpec.describe 'Merge request > User sees suggest pipeline', :js do
end
it 'shows the suggest pipeline widget and then allows dismissal correctly' do
expect(page).to have_content('Are you adding technical debt or code vulnerabilities?')
content = 'GitLab CI/CD can automatically build, test, and deploy your application'
expect(page).to have_content(content)
page.within '.mr-pipeline-suggest' do
find('[data-testid="close"]').click
......@@ -24,17 +25,16 @@ RSpec.describe 'Merge request > User sees suggest pipeline', :js do
wait_for_requests
expect(page).not_to have_content('Are you adding technical debt or code vulnerabilities?')
expect(page).not_to have_content(content)
# Reload so we know the user callout was registered
visit page.current_url
expect(page).not_to have_content('Are you adding technical debt or code vulnerabilities?')
expect(page).not_to have_content(content)
end
it 'runs tour from start to finish ensuring all nudges are executed' do
# nudge 1
expect(page).to have_content('Are you adding technical debt or code vulnerabilities?')
it 'takes the user to the pipeline editor with a pre-filled CI config file form' do
expect(page).to have_content('GitLab CI/CD can automatically build, test, and deploy your application')
page.within '.mr-pipeline-suggest' do
find('[data-testid="ok"]').click
......@@ -42,30 +42,14 @@ RSpec.describe 'Merge request > User sees suggest pipeline', :js do
wait_for_requests
# nudge 2
expect(page).to have_content('Choose Code Quality to add a pipeline that tests the quality of your code.')
# Drawer is open
expect(page).to have_content('This template creates a simple test pipeline. To use it:')
find('.js-gitlab-ci-yml-selector').click
# Editor shows template
expect(page).to have_content('This file is a template, and might need editing before it works on your project.')
wait_for_requests
within '.gitlab-ci-yml-selector' do
find('.dropdown-input-field').set('Jekyll')
find('.dropdown-content li', text: 'Jekyll').click
end
wait_for_requests
expect(page).not_to have_content('Choose Code Quality to add a pipeline that tests the quality of your code.')
# nudge 3
expect(page).to have_content('The template is ready!')
find('#commit-changes').click
wait_for_requests
# nudge 4
expect(page).to have_content("That's it, well done!")
# Commit form is shown
expect(page).to have_button('Commit changes')
end
context 'when feature setting is disabled' do
......
......@@ -411,4 +411,37 @@ describe('Pipeline editor app component', () => {
expect(findEditorHome().exists()).toBe(true);
});
});
describe('when add_new_config_file query param is present', () => {
const originalLocation = window.location.href;
beforeEach(() => {
setWindowLocation('?add_new_config_file=true');
mockCiConfigData.mockResolvedValue(mockCiConfigQueryResponse);
});
afterEach(() => {
setWindowLocation(originalLocation);
});
describe('when CI config file does not exist', () => {
beforeEach(async () => {
mockBlobContentData.mockResolvedValue(mockBlobContentQueryResponseNoCiFile);
mockLatestCommitShaQuery.mockResolvedValue(mockEmptyCommitShaResults);
mockGetTemplate.mockResolvedValue(mockCiTemplateQueryResponse);
await createComponentWithApollo();
jest
.spyOn(wrapper.vm.$apollo.queries.commitSha, 'startPolling')
.mockImplementation(jest.fn());
});
it('skips empty state and shows editor home component', () => {
expect(findEmptyState().exists()).toBe(false);
expect(findEditorHome().exists()).toBe(true);
});
});
});
});
import { GlLink, GlSprintf } from '@gitlab/ui';
import { GlSprintf } from '@gitlab/ui';
import { mount, shallowMount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import { mockTracking, triggerEvent, unmockTracking } from 'helpers/tracking_helper';
......@@ -7,9 +7,7 @@ import MrWidgetIcon from '~/vue_merge_request_widget/components/mr_widget_icon.v
import suggestPipelineComponent from '~/vue_merge_request_widget/components/mr_widget_suggest_pipeline.vue';
import {
SP_TRACK_LABEL,
SP_LINK_TRACK_EVENT,
SP_SHOW_TRACK_EVENT,
SP_LINK_TRACK_VALUE,
SP_SHOW_TRACK_VALUE,
SP_HELP_URL,
} from '~/vue_merge_request_widget/constants';
......@@ -52,15 +50,8 @@ describe('MRWidgetSuggestPipeline', () => {
mockAxios.restore();
});
it('renders add pipeline file link', () => {
const link = wrapper.find(GlLink);
expect(link.exists()).toBe(true);
expect(link.attributes().href).toBe(suggestProps.pipelinePath);
});
it('renders the expected text', () => {
const messageText = /\s*No pipeline\s*Add the .gitlab-ci.yml file\s*to create one./;
const messageText = /Looks like there's no pipeline here./;
expect(wrapper.text()).toMatch(messageText);
});
......@@ -109,18 +100,6 @@ describe('MRWidgetSuggestPipeline', () => {
});
});
it('send an event when add pipeline link is clicked', () => {
mockTrackingOnWrapper();
const link = wrapper.find('[data-testid="add-pipeline-link"]');
triggerEvent(link.element);
expect(trackingSpy).toHaveBeenCalledWith('_category_', SP_LINK_TRACK_EVENT, {
label: SP_TRACK_LABEL,
property: suggestProps.humanAccess,
value: SP_LINK_TRACK_VALUE.toString(),
});
});
it('send an event when ok button is clicked', () => {
mockTrackingOnWrapper();
const okBtn = findOkBtn();
......
......@@ -51,7 +51,7 @@ export default {
target_branch: 'main',
target_project_id: 19,
target_project_full_path: '/group2/project2',
merge_request_add_ci_config_path: '/group2/project2/new/pipeline',
merge_request_add_ci_config_path: '/root/group2/project2/-/ci/editor',
is_dismissed_suggest_pipeline: false,
user_callouts_path: 'some/callout/path',
suggest_pipeline_feature_id: 'suggest_pipeline',
......
......@@ -129,7 +129,7 @@ describe('MergeRequestStore', () => {
it('should set the add ci config path', () => {
store.setPaths({ ...mockData });
expect(store.mergeRequestAddCiConfigPath).toBe('/group2/project2/new/pipeline');
expect(store.mergeRequestAddCiConfigPath).toBe('/root/group2/project2/-/ci/editor');
});
it('should set humanAccess=Maintainer when user has that role', () => {
......
......@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe MergeRequestWidgetEntity do
include ProjectForksHelper
include Gitlab::Routing.url_helpers
let(:project) { create :project, :repository }
let(:resource) { create(:merge_request, source_project: project, target_project: project) }
......@@ -140,17 +141,15 @@ RSpec.describe MergeRequestWidgetEntity do
let(:role) { :developer }
it 'has add ci config path' do
expected_path = "/#{resource.project.full_path}/-/new/#{resource.source_branch}"
expected_path = project_ci_pipeline_editor_path(project)
expect(subject[:merge_request_add_ci_config_path]).to include(expected_path)
end
it 'has expected params' do
expected_params = {
commit_message: 'Add .gitlab-ci.yml',
file_name: '.gitlab-ci.yml',
suggest_gitlab_ci_yml: 'true',
mr_path: "/#{resource.project.full_path}/-/merge_requests/#{resource.iid}"
branch_name: resource.source_branch,
add_new_config_file: 'true'
}.with_indifferent_access
uri = Addressable::URI.parse(subject[:merge_request_add_ci_config_path])
......@@ -188,30 +187,6 @@ RSpec.describe MergeRequestWidgetEntity do
end
end
context 'when ci_config_path is customized' do
it 'has no path if ci_config_path is not set to our default setting' do
project.ci_config_path = 'not_default'
expect(subject[:merge_request_add_ci_config_path]).to be_nil
end
it 'has a path if ci_config_path unset' do
expect(subject[:merge_request_add_ci_config_path]).not_to be_nil
end
it 'has a path if ci_config_path is an empty string' do
project.ci_config_path = ''
expect(subject[:merge_request_add_ci_config_path]).not_to be_nil
end
it 'has a path if ci_config_path is set to our default file' do
project.ci_config_path = Gitlab::FileDetector::PATTERNS[:gitlab_ci]
expect(subject[:merge_request_add_ci_config_path]).not_to be_nil
end
end
context 'when build feature is disabled' do
before do
project.project_feature.update!(builds_access_level: ProjectFeature::DISABLED)
......
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