Commit b1a56a95 authored by Paul Slaughter's avatar Paul Slaughter

Merge branch 'cleanup-code-quality-walkthrough-experiment' into 'master'

Cleanup Code Quality Walkthrough experiment

See merge request gitlab-org/gitlab!82106
parents 74bfc5ac 2333b6ec
......@@ -2,7 +2,6 @@
import $ from 'jquery';
import initPopover from '~/blob/suggest_gitlab_ci_yml';
import initCodeQualityWalkthrough from '~/code_quality_walkthrough';
import createFlash from '~/flash';
import { disableButtonIfEmptyField, setCookie } from '~/lib/utils/common_utils';
import Tracking from '~/tracking';
......@@ -39,13 +38,6 @@ const initPopovers = () => {
}
};
const initCodeQualityWalkthroughStep = () => {
const codeQualityWalkthroughEl = document.querySelector('.js-code-quality-walkthrough');
if (codeQualityWalkthroughEl) {
initCodeQualityWalkthrough(codeQualityWalkthroughEl);
}
};
export const initUploadForm = () => {
const uploadBlobForm = $('.js-upload-blob-form');
if (uploadBlobForm.length) {
......@@ -84,7 +76,6 @@ export default () => {
previewMarkdownPath,
});
initPopovers();
initCodeQualityWalkthroughStep();
})
.catch((e) =>
createFlash({
......
<script>
import { GlPopover, GlSprintf, GlButton, GlAlert } from '@gitlab/ui';
import { STEPS, STEPSTATES } from '../constants';
import {
isWalkthroughEnabled,
getExperimentSettings,
setExperimentSettings,
track,
} from '../utils';
export default {
target: '#js-code-quality-walkthrough',
components: {
GlPopover,
GlSprintf,
GlButton,
GlAlert,
},
props: {
step: {
type: String,
required: true,
},
link: {
type: String,
required: false,
default: null,
},
},
data() {
return {
dismissedSettings: getExperimentSettings(),
currentStep: STEPSTATES[this.step],
};
},
computed: {
isPopoverVisible() {
return (
[
STEPS.commitCiFile,
STEPS.runningPipeline,
STEPS.successPipeline,
STEPS.failedPipeline,
].includes(this.step) &&
isWalkthroughEnabled() &&
!this.isDismissed
);
},
isAlertVisible() {
return this.step === STEPS.troubleshootJob && isWalkthroughEnabled() && !this.isDismissed;
},
isDismissed() {
return this.dismissedSettings[this.step];
},
title() {
return this.currentStep?.title || '';
},
body() {
return this.currentStep?.body || '';
},
buttonText() {
return this.currentStep?.buttonText || '';
},
buttonLink() {
return [STEPS.successPipeline, STEPS.failedPipeline].includes(this.step) ? this.link : '';
},
placement() {
return this.currentStep?.placement || 'bottom';
},
offset() {
return this.currentStep?.offset || 0;
},
},
created() {
this.trackDisplayed();
},
updated() {
this.trackDisplayed();
},
methods: {
onDismiss() {
this.$set(this.dismissedSettings, this.step, true);
setExperimentSettings(this.dismissedSettings);
const action = [STEPS.successPipeline, STEPS.failedPipeline].includes(this.step)
? 'view_logs'
: 'dismissed';
this.trackAction(action);
},
trackDisplayed() {
if (this.isPopoverVisible || this.isAlertVisible) {
this.trackAction('displayed');
}
},
trackAction(action) {
track(`${this.step}_${action}`);
},
},
};
</script>
<template>
<div>
<gl-popover
v-if="isPopoverVisible"
:key="step"
:target="$options.target"
:placement="placement"
:offset="offset"
show
triggers="manual"
container="viewport"
>
<template #title>
<gl-sprintf :message="title">
<template #emoji="{ content }">
<gl-emoji class="gl-mr-2" :data-name="content"
/></template>
</gl-sprintf>
</template>
<gl-sprintf :message="body">
<template #strong="{ content }">
<strong>{{ content }}</strong>
</template>
<template #lineBreak>
<div class="gl-mt-5"></div>
</template>
<template #emoji="{ content }">
<gl-emoji :data-name="content" />
</template>
</gl-sprintf>
<div class="gl-mt-2 gl-text-right">
<gl-button category="tertiary" variant="link" :href="buttonLink" @click="onDismiss">
{{ buttonText }}
</gl-button>
</div>
</gl-popover>
<gl-alert
v-if="isAlertVisible"
variant="tip"
:title="title"
:primary-button-text="buttonText"
:primary-button-link="link"
class="gl-my-5"
@primaryAction="trackAction('clicked')"
@dismiss="onDismiss"
>
{{ body }}
</gl-alert>
</div>
</template>
import { s__ } from '~/locale';
export const EXPERIMENT_NAME = 'code_quality_walkthrough';
export const STEPS = {
commitCiFile: 'commit_ci_file',
runningPipeline: 'running_pipeline',
successPipeline: 'success_pipeline',
failedPipeline: 'failed_pipeline',
troubleshootJob: 'troubleshoot_job',
};
export const STEPSTATES = {
[STEPS.commitCiFile]: {
title: s__("codeQualityWalkthrough|Let's start by creating a new CI file."),
body: s__(
'codeQualityWalkthrough|To begin with code quality, we first need to create a new CI file using our code editor. We added a code quality template in the code editor to help you get started %{emojiStart}wink%{emojiEnd} .%{lineBreak}Take some time to review the template, when you are ready, use the %{strongStart}commit changes%{strongEnd} button at the bottom of the page.',
),
buttonText: s__('codeQualityWalkthrough|Got it'),
placement: 'right',
offset: 90,
},
[STEPS.runningPipeline]: {
title: s__(
'codeQualityWalkthrough|Congrats! Your first pipeline is running %{emojiStart}zap%{emojiEnd}',
),
body: s__(
"codeQualityWalkthrough|Your pipeline can take a few minutes to run. If you enabled email notifications, you'll receive an email with your pipeline status. In the meantime, why don't you get some coffee? You earned it!",
),
buttonText: s__('codeQualityWalkthrough|Got it'),
offset: 97,
},
[STEPS.successPipeline]: {
title: s__(
"codeQualityWalkthrough|Well done! You've just automated your code quality review. %{emojiStart}raised_hands%{emojiEnd}",
),
body: s__(
'codeQualityWalkthrough|A code quality job will now run every time you or your team members commit changes to your project. You can view the results of the code quality job in the job logs.',
),
buttonText: s__('codeQualityWalkthrough|View the logs'),
offset: 98,
},
[STEPS.failedPipeline]: {
title: s__(
"codeQualityWalkthrough|Something went wrong. %{emojiStart}thinking%{emojiEnd} Let's fix it.",
),
body: s__(
"codeQualityWalkthrough|Your job failed. No worries - this happens. Let's view the logs, and see how we can fix it.",
),
buttonText: s__('codeQualityWalkthrough|View the logs'),
offset: 98,
},
[STEPS.troubleshootJob]: {
title: s__('codeQualityWalkthrough|Troubleshoot your code quality job'),
body: s__(
'codeQualityWalkthrough|Not sure how to fix your failed job? We have compiled some tips on how to troubleshoot code quality jobs in the documentation.',
),
buttonText: s__('codeQualityWalkthrough|Read the documentation'),
},
};
export const PIPELINE_STATUSES = {
running: 'running',
successWithWarnings: 'success-with-warnings',
success: 'success',
failed: 'failed',
};
import Vue from 'vue';
import Step from './components/step.vue';
export default (el) =>
new Vue({
el,
render(createElement) {
return createElement(Step, {
props: {
step: el.dataset.step,
},
});
},
});
import { TRACKING_CONTEXT_SCHEMA } from '~/experimentation/constants';
import { getExperimentData } from '~/experimentation/utils';
import { setCookie, getCookie } from '~/lib/utils/common_utils';
import { getParameterByName } from '~/lib/utils/url_utility';
import Tracking from '~/tracking';
import { EXPERIMENT_NAME } from './constants';
export function getExperimentSettings() {
return JSON.parse(getCookie(EXPERIMENT_NAME) || '{}');
}
export function setExperimentSettings(settings) {
setCookie(EXPERIMENT_NAME, settings);
}
export function isWalkthroughEnabled() {
return getParameterByName(EXPERIMENT_NAME);
}
export function track(action) {
const { data } = getExperimentSettings();
if (data) {
Tracking.event(EXPERIMENT_NAME, action, {
context: {
schema: TRACKING_CONTEXT_SCHEMA,
data,
},
});
}
}
export function startCodeQualityWalkthrough() {
const data = getExperimentData(EXPERIMENT_NAME);
if (data) {
setExperimentSettings({ data });
}
}
......@@ -3,7 +3,6 @@ import { GlLoadingIcon, GlIcon, GlSafeHtmlDirective as SafeHtml, GlAlert } from
import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
import { throttle, isEmpty } from 'lodash';
import { mapGetters, mapState, mapActions } from 'vuex';
import CodeQualityWalkthrough from '~/code_quality_walkthrough/components/step.vue';
import { isScrolledToBottom } from '~/lib/utils/scroll_utils';
import { __, sprintf } from '~/locale';
import CiHeader from '~/vue_shared/components/header_ci_component.vue';
......@@ -33,7 +32,6 @@ export default {
GlLoadingIcon,
SharedRunner: () => import('ee_component/jobs/components/shared_runner_limit_block.vue'),
GlAlert,
CodeQualityWalkthrough,
},
directives: {
SafeHtml,
......@@ -69,11 +67,6 @@ export default {
required: false,
default: null,
},
codeQualityHelpUrl: {
type: String,
required: false,
default: null,
},
},
computed: {
...mapState([
......@@ -123,9 +116,6 @@ export default {
return this.shouldRenderCalloutMessage && !this.hasUnmetPrerequisitesFailure;
},
shouldRenderCodeQualityWalkthrough() {
return this.job.status.group === 'failed-with-warnings';
},
itemName() {
return sprintf(__('Job %{jobName}'), { jobName: this.job.name });
},
......@@ -224,11 +214,6 @@ export default {
>
<div v-safe-html="job.callout_message"></div>
</gl-alert>
<code-quality-walkthrough
v-if="shouldRenderCodeQualityWalkthrough"
step="troubleshoot_job"
:link="codeQualityHelpUrl"
/>
</header>
<!-- EO Header Section -->
......
......@@ -14,7 +14,6 @@ const initializeJobPage = (element) => {
const {
artifactHelpUrl,
deploymentHelpUrl,
codeQualityHelpUrl,
runnerSettingsUrl,
subscriptionsMoreMinutesUrl,
endpoint,
......@@ -39,7 +38,6 @@ const initializeJobPage = (element) => {
props: {
artifactHelpUrl,
deploymentHelpUrl,
codeQualityHelpUrl,
runnerSettingsUrl,
subscriptionsMoreMinutesUrl,
endpoint,
......
<script>
import { GlEmptyState, GlButton } from '@gitlab/ui';
import { startCodeQualityWalkthrough, track } from '~/code_quality_walkthrough/utils';
import GitlabExperiment from '~/experimentation/components/gitlab_experiment.vue';
import { getExperimentData } from '~/experimentation/utils';
import { GlEmptyState } from '@gitlab/ui';
import { s__ } from '~/locale';
import PipelinesCiTemplates from './pipelines_ci_templates.vue';
export default {
i18n: {
codeQualityTitle: s__('Pipelines|Improve code quality with GitLab CI/CD'),
codeQualityDescription: s__(`Pipelines|To keep your codebase simple,
readable, and accessible to contributors, use GitLab CI/CD
to analyze your code quality with every push to your project.`),
codeQualityBtnText: s__('Pipelines|Add a code quality job'),
noCiDescription: s__('Pipelines|This project is not currently set up to run pipelines.'),
},
name: 'PipelinesEmptyState',
components: {
GlEmptyState,
GlButton,
GitlabExperiment,
PipelinesCiTemplates,
},
props: {
......@@ -31,11 +21,6 @@ export default {
type: Boolean,
required: true,
},
codeQualityPagePath: {
type: String,
required: false,
default: null,
},
ciRunnerSettingsPath: {
type: String,
required: false,
......@@ -47,41 +32,12 @@ export default {
default: true,
},
},
computed: {
isCodeQualityExperimentActive() {
return this.canSetCi && Boolean(getExperimentData('code_quality_walkthrough'));
},
},
mounted() {
startCodeQualityWalkthrough();
},
methods: {
trackClick() {
track('cta_clicked');
},
},
};
</script>
<template>
<div>
<gitlab-experiment v-if="isCodeQualityExperimentActive" name="code_quality_walkthrough">
<template #control><pipelines-ci-templates /></template>
<template #candidate>
<gl-empty-state
:title="$options.i18n.codeQualityTitle"
:svg-path="emptyStateSvgPath"
:description="$options.i18n.codeQualityDescription"
>
<template #actions>
<gl-button :href="codeQualityPagePath" variant="confirm" @click="trackClick()">
{{ $options.i18n.codeQualityBtnText }}
</gl-button>
</template>
</gl-empty-state>
</template>
</gitlab-experiment>
<pipelines-ci-templates
v-else-if="canSetCi"
v-if="canSetCi"
:ci-runner-settings-path="ciRunnerSettingsPath"
:any-runners-available="anyRunnersAvailable"
/>
......
......@@ -102,11 +102,6 @@ export default {
type: Object,
required: true,
},
codeQualityPagePath: {
type: String,
required: false,
default: null,
},
ciRunnerSettingsPath: {
type: String,
required: false,
......@@ -385,7 +380,6 @@ export default {
v-else-if="stateToRender === $options.stateMap.emptyState"
:empty-state-svg-path="emptyStateSvgPath"
:can-set-ci="canCreatePipeline"
:code-quality-page-path="codeQualityPagePath"
:ci-runner-settings-path="ciRunnerSettingsPath"
:any-runners-available="anyRunnersAvailable"
/>
......
<script>
import CodeQualityWalkthrough from '~/code_quality_walkthrough/components/step.vue';
import { PIPELINE_STATUSES } from '~/code_quality_walkthrough/constants';
import { CHILD_VIEW } from '~/pipelines/constants';
import CiBadge from '~/vue_shared/components/ci_badge_link.vue';
import PipelinesTimeago from './time_ago.vue';
export default {
components: {
CodeQualityWalkthrough,
CiBadge,
PipelinesTimeago,
},
......@@ -28,20 +25,6 @@ export default {
isChildView() {
return this.viewType === CHILD_VIEW;
},
shouldRenderCodeQualityWalkthrough() {
return Object.values(PIPELINE_STATUSES).includes(this.pipelineStatus.group);
},
codeQualityStep() {
const prefix = [PIPELINE_STATUSES.successWithWarnings, PIPELINE_STATUSES.failed].includes(
this.pipelineStatus.group,
)
? 'failed'
: this.pipelineStatus.group;
return `${prefix}_pipeline`;
},
codeQualityBuildPath() {
return this.pipeline?.details?.code_quality_build_path;
},
},
};
</script>
......@@ -49,7 +32,6 @@ export default {
<template>
<div>
<ci-badge
id="js-code-quality-walkthrough"
class="gl-mb-3"
:status="pipelineStatus"
:show-text="!isChildView"
......@@ -57,10 +39,5 @@ export default {
data-qa-selector="pipeline_commit_status"
/>
<pipelines-timeago class="gl-mt-3" :pipeline="pipeline" />
<code-quality-walkthrough
v-if="shouldRenderCodeQualityWalkthrough"
:step="codeQualityStep"
:link="codeQualityBuildPath"
/>
</div>
</template>
......@@ -37,7 +37,6 @@ export const initPipelinesIndex = (selector = '#pipelines-list-vue') => {
resetCachePath,
projectId,
params,
codeQualityPagePath,
ciRunnerSettingsPath,
anyRunnersAvailable,
} = el.dataset;
......@@ -77,7 +76,6 @@ export const initPipelinesIndex = (selector = '#pipelines-list-vue') => {
resetCachePath,
projectId,
params: JSON.parse(params),
codeQualityPagePath,
ciRunnerSettingsPath,
anyRunnersAvailable: parseBoolean(anyRunnersAvailable),
},
......
......@@ -35,7 +35,6 @@ class Projects::BlobController < Projects::ApplicationController
before_action :editor_variables, except: [:show, :preview, :diff]
before_action :validate_diff_params, only: :diff
before_action :set_last_commit_sha, only: [:edit, :update]
before_action :track_experiment, only: :create
track_redis_hll_event :create, :update, name: 'g_edit_by_sfe'
......@@ -54,7 +53,7 @@ class Projects::BlobController < Projects::ApplicationController
def create
create_commit(Files::CreateService, success_notice: _("The file has been successfully created."),
success_path: -> { create_success_path },
success_path: -> { project_blob_path(@project, File.join(@branch_name, @file_path)) },
failure_view: :new,
failure_path: project_new_blob_path(@project, @ref))
end
......@@ -282,20 +281,6 @@ class Projects::BlobController < Projects::ApplicationController
def visitor_id
current_user&.id
end
def create_success_path
if params[:code_quality_walkthrough]
project_pipelines_path(@project, code_quality_walkthrough: true)
else
project_blob_path(@project, File.join(@branch_name, @file_path))
end
end
def track_experiment
return unless params[:code_quality_walkthrough]
experiment(:code_quality_walkthrough, namespace: @project.root_ancestor).track(:commit_created)
end
end
Projects::BlobController.prepend_mod
......@@ -51,7 +51,6 @@ class Projects::PipelinesController < Projects::ApplicationController
respond_to do |format|
format.html do
enable_code_quality_walkthrough_experiment
enable_runners_availability_section_experiment
end
format.json do
......@@ -220,7 +219,7 @@ class Projects::PipelinesController < Projects::ApplicationController
PipelineSerializer
.new(project: @project, current_user: @current_user)
.with_pagination(request, response)
.represent(@pipelines, disable_coverage: true, preload: true, code_quality_walkthrough: params[:code_quality_walkthrough].present?)
.represent(@pipelines, disable_coverage: true, preload: true)
end
def render_show
......@@ -305,20 +304,6 @@ class Projects::PipelinesController < Projects::ApplicationController
params.permit(:scope, :username, :ref, :status, :source)
end
def enable_code_quality_walkthrough_experiment
experiment(:code_quality_walkthrough, namespace: project.root_ancestor) do |e|
e.exclude! unless current_user
e.exclude! unless can?(current_user, :create_pipeline, project)
e.exclude! unless project.root_ancestor.recent?
e.exclude! if @pipelines_count.to_i > 0
e.exclude! if helpers.has_gitlab_ci?(project)
e.control {}
e.candidate {}
e.publish_to_database
end
end
def enable_runners_availability_section_experiment
return unless current_user
return unless can?(current_user, :create_pipeline, project)
......
......@@ -14,8 +14,7 @@ module Ci
"build_stage" => @build.stage,
"log_state" => '',
"build_options" => javascript_build_options,
"retry_outdated_job_docs_url" => help_page_path('ci/pipelines/settings', anchor: 'retry-outdated-jobs'),
"code_quality_help_url" => help_page_path('user/project/merge_requests/code_quality', anchor: 'troubleshooting')
"retry_outdated_job_docs_url" => help_page_path('ci/pipelines/settings', anchor: 'retry-outdated-jobs')
}
end
......
......@@ -98,7 +98,6 @@ module Ci
has_gitlab_ci: has_gitlab_ci?(project).to_s,
pipeline_editor_path: can?(current_user, :create_pipeline, project) && project_ci_pipeline_editor_path(project),
suggested_ci_templates: suggested_ci_templates.to_json,
code_quality_page_path: project.present(current_user: current_user).add_code_quality_ci_yml_path,
ci_runner_settings_path: project_settings_ci_cd_path(project, ci_runner_templates: true, anchor: 'js-runners-settings')
}
......
......@@ -137,17 +137,6 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
ide_edit_path(project, default_branch_or_main, 'README.md')
end
def add_code_quality_ci_yml_path
add_special_file_path(
file_name: ci_config_path_or_default,
commit_message: s_("CommitMessage|Add %{file_name} and create a code quality job") % { file_name: ci_config_path_or_default },
additional_params: {
template: 'Code-Quality',
code_quality_walkthrough: true
}
)
end
def license_short_name
license = repository.license
license&.nickname || license&.name || 'LICENSE'
......
......@@ -10,11 +10,6 @@ class PipelineDetailsEntity < Ci::PipelineEntity
expose :details do
expose :manual_actions, using: BuildActionEntity
expose :scheduled_actions, using: BuildActionEntity
expose :code_quality_build_path, if: -> (_, options) { options[:code_quality_walkthrough] } do |pipeline|
next unless code_quality_build = pipeline.builds.finished.find_by_name('code_quality')
project_job_path(pipeline.project, code_quality_build, code_quality_walkthrough: true)
end
end
expose :triggered_by_pipeline, as: :triggered_by, with: TriggeredPipelineEntity
......
- breadcrumb_title _("Repository")
- page_title _("New File"), @path.presence, @ref
%h3.page-title.blob-new-page-title#js-code-quality-walkthrough
%h3.page-title.blob-new-page-title
= _('New file')
.js-code-quality-walkthrough{ data: { step: 'commit_ci_file' } }
.file-editor
= form_tag(project_create_blob_path(@project, @id), method: :post, class: 'js-edit-blob-form js-new-blob-form js-quick-submit js-requires-input', data: blob_editor_paths(@project)) do
= render 'projects/blob/editor', ref: @ref
= render 'shared/new_commit_form', placeholder: "Add new file"
- if params[:code_quality_walkthrough]
= hidden_field_tag 'code_quality_walkthrough', 'true'
= hidden_field_tag 'content', '', id: 'file-content'
= render 'projects/commit_button', ref: @ref,
cancel_path: project_tree_path(@project, @id)
......
......@@ -4,7 +4,7 @@
= render_if_exists "shared/shared_runners_minutes_limit_flash_message"
- list_url = project_pipelines_path(@project, format: :json, code_quality_walkthrough: params[:code_quality_walkthrough])
- list_url = project_pipelines_path(@project, format: :json)
- add_page_startup_api_call list_url
#pipelines-list-vue{ data: pipelines_list_data(@project, list_url) }
description: "Commit CI file dismissed"
category: "`code_quality_walkthrough`"
action: commit_ci_file_dismissed
label_description: ""
property_description: ""
value_description: ""
extra_properties:
identifiers:
product_section: growth
product_stage: growth
product_group: group::activation
product_category:
milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/58900
distributions:
- ce
- ee
tiers:
- free
- premium
- ultimate
description: "Commit CI file displayed"
category: "`code_quality_walkthrough`"
action: commit_ci_file_displayed
label_description: ""
property_description: ""
value_description: ""
extra_properties:
identifiers:
product_section: growth
product_stage: growth
product_group: group::activation
product_category:
milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/58900
distributions:
- ce
- ee
tiers:
- free
- premium
- ultimate
description: "Commit created"
category: "`code_quality_walkthrough`"
action: commit_created
label_description: ""
property_description: ""
value_description: ""
extra_properties:
identifiers:
product_section: growth
product_stage: growth
product_group: group::activation
product_category:
milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/58900
distributions:
- ce
- ee
tiers:
- free
- premium
- ultimate
description: "Click empty state CTA"
category: "`code_quality_walkthrough`"
action: cta_clicked
label_description: ""
property_description: ""
value_description: ""
extra_properties:
identifiers:
product_section: growth
product_stage: growth
product_group: group::activation
product_category:
milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/58900
distributions:
- ce
- ee
tiers:
- free
- premium
- ultimate
description: "Show failed pipeline"
category: "`code_quality_walkthrough`"
action: failed_pipeline_displayed
label_description: ""
property_description: ""
value_description: ""
extra_properties:
identifiers:
product_section: growth
product_stage: growth
product_group: group::activation
product_category:
milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/58900
distributions:
- ce
- ee
tiers:
- free
- premium
- ultimate
description: "Show failed pipeline logs"
category: "`code_quality_walkthrough`"
action: failed_pipeline_view_logs
label_description: ""
property_description: ""
value_description: ""
extra_properties:
identifiers:
product_section: growth
product_stage: growth
product_group: group::activation
product_category:
milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/58900
distributions:
- ce
- ee
tiers:
- free
- premium
- ultimate
description: "Dismiss running pipeline"
category: "`code_quality_walkthrough`"
action: running_pipeline_dismissed
label_description: ""
property_description: ""
value_description: ""
extra_properties:
identifiers:
product_section: growth
product_stage: growth
product_group: group::activation
product_category:
milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/58900
distributions:
- ce
- ee
tiers:
- free
- premium
- ultimate
description: "Show running pipeline"
category: "`code_quality_walkthrough`"
action: running_pipeline_displayed
label_description: ""
property_description: ""
value_description: ""
extra_properties:
identifiers:
product_section: growth
product_stage: growth
product_group: group::activation
product_category:
milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/58900
distributions:
- ce
- ee
tiers:
- free
- premium
- ultimate
description: "Show succeeded pipeline"
category: "`code_quality_walkthrough`"
action: success_pipeline_displayed
label_description: ""
property_description: ""
value_description: ""
extra_properties:
identifiers:
product_section: growth
product_stage: growth
product_group: group::activation
product_category:
milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/58900
distributions:
- ce
- ee
tiers:
- free
- premium
- ultimate
description: "Show succeeded pipeline logs"
category: "`code_quality_walkthrough`"
action: success_pipeline_view_logs
label_description: ""
property_description: ""
value_description: ""
extra_properties:
identifiers:
product_section: growth
product_stage: growth
product_group: group::activation
product_category:
milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/58900
distributions:
- ce
- ee
tiers:
- free
- premium
- ultimate
---
name: code_quality_walkthrough
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/58900
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/327229
milestone: "13.12"
type: experiment
group: group::activation
default_enabled: false
......@@ -8891,9 +8891,6 @@ msgstr ""
msgid "CommitMessage|Add %{file_name}"
msgstr ""
msgid "CommitMessage|Add %{file_name} and create a code quality job"
msgstr ""
msgid "CommitWidget|authored"
msgstr ""
......@@ -26927,9 +26924,6 @@ msgstr ""
msgid "Pipelines|API"
msgstr ""
msgid "Pipelines|Add a code quality job"
msgstr ""
msgid "Pipelines|Are you sure you want to run this pipeline?"
msgstr ""
......@@ -26990,9 +26984,6 @@ msgstr ""
msgid "Pipelines|If you are unsure, please ask a project maintainer to review it for you."
msgstr ""
msgid "Pipelines|Improve code quality with GitLab CI/CD"
msgstr ""
msgid "Pipelines|Install GitLab Runner"
msgstr ""
......@@ -27098,9 +27089,6 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
msgid "Pipelines|To keep your codebase simple, readable, and accessible to contributors, use GitLab CI/CD to analyze your code quality with every push to your project."
msgstr ""
msgid "Pipelines|Token"
msgstr ""
......@@ -43329,45 +43317,6 @@ msgstr ""
msgid "closed issue"
msgstr ""
msgid "codeQualityWalkthrough|A code quality job will now run every time you or your team members commit changes to your project. You can view the results of the code quality job in the job logs."
msgstr ""
msgid "codeQualityWalkthrough|Congrats! Your first pipeline is running %{emojiStart}zap%{emojiEnd}"
msgstr ""
msgid "codeQualityWalkthrough|Got it"
msgstr ""
msgid "codeQualityWalkthrough|Let's start by creating a new CI file."
msgstr ""
msgid "codeQualityWalkthrough|Not sure how to fix your failed job? We have compiled some tips on how to troubleshoot code quality jobs in the documentation."
msgstr ""
msgid "codeQualityWalkthrough|Read the documentation"
msgstr ""
msgid "codeQualityWalkthrough|Something went wrong. %{emojiStart}thinking%{emojiEnd} Let's fix it."
msgstr ""
msgid "codeQualityWalkthrough|To begin with code quality, we first need to create a new CI file using our code editor. We added a code quality template in the code editor to help you get started %{emojiStart}wink%{emojiEnd} .%{lineBreak}Take some time to review the template, when you are ready, use the %{strongStart}commit changes%{strongEnd} button at the bottom of the page."
msgstr ""
msgid "codeQualityWalkthrough|Troubleshoot your code quality job"
msgstr ""
msgid "codeQualityWalkthrough|View the logs"
msgstr ""
msgid "codeQualityWalkthrough|Well done! You've just automated your code quality review. %{emojiStart}raised_hands%{emojiEnd}"
msgstr ""
msgid "codeQualityWalkthrough|Your job failed. No worries - this happens. Let's view the logs, and see how we can fix it."
msgstr ""
msgid "codeQualityWalkthrough|Your pipeline can take a few minutes to run. If you enabled email notifications, you'll receive an email with your pipeline status. In the meantime, why don't you get some coffee? You earned it!"
msgstr ""
msgid "collect usage information"
msgstr ""
......
......@@ -525,24 +525,5 @@ RSpec.describe Projects::BlobController do
expect(response).to redirect_to(project_blob_path(project, 'master/docs/EXAMPLE_FILE'))
end
context 'when code_quality_walkthrough param is present' do
let(:default_params) { super().merge(code_quality_walkthrough: true) }
it 'redirects to the pipelines page' do
request
expect(response).to redirect_to(project_pipelines_path(project, code_quality_walkthrough: true))
end
it 'creates an "commit_created" experiment tracking event' do
experiment = double(track: true)
expect(controller).to receive(:experiment).with(:code_quality_walkthrough, namespace: project.root_ancestor).and_return(experiment)
request
expect(experiment).to have_received(:track).with(:commit_created)
end
end
end
end
......@@ -292,10 +292,6 @@ RSpec.describe Projects::PipelinesController do
subject { project.namespace }
context 'code_quality_walkthrough experiment' do
it_behaves_like 'tracks assignment and records the subject', :code_quality_walkthrough, :namespace
end
context 'runners_availability_section experiment' do
it_behaves_like 'tracks assignment and records the subject', :runners_availability_section, :namespace
end
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`When the code_quality_walkthrough URL parameter is present Code Quality Walkthrough Step component commit_ci_file step renders a popover 1`] = `
<div>
<gl-popover-stub
container="viewport"
cssclasses=""
offset="90"
placement="right"
show=""
target="#js-code-quality-walkthrough"
triggers="manual"
>
<gl-sprintf-stub
message="To begin with code quality, we first need to create a new CI file using our code editor. We added a code quality template in the code editor to help you get started %{emojiStart}wink%{emojiEnd} .%{lineBreak}Take some time to review the template, when you are ready, use the %{strongStart}commit changes%{strongEnd} button at the bottom of the page."
/>
<div
class="gl-mt-2 gl-text-right"
>
<gl-button-stub
buttontextclasses=""
category="tertiary"
href=""
icon=""
size="medium"
variant="link"
>
Got it
</gl-button-stub>
</div>
</gl-popover-stub>
<!---->
</div>
`;
exports[`When the code_quality_walkthrough URL parameter is present Code Quality Walkthrough Step component failed_pipeline step renders a popover 1`] = `
<div>
<gl-popover-stub
container="viewport"
cssclasses=""
offset="98"
placement="bottom"
show=""
target="#js-code-quality-walkthrough"
triggers="manual"
>
<gl-sprintf-stub
message="Your job failed. No worries - this happens. Let's view the logs, and see how we can fix it."
/>
<div
class="gl-mt-2 gl-text-right"
>
<gl-button-stub
buttontextclasses=""
category="tertiary"
href="/group/project/-/jobs/:id?code_quality_walkthrough=true"
icon=""
size="medium"
variant="link"
>
View the logs
</gl-button-stub>
</div>
</gl-popover-stub>
<!---->
</div>
`;
exports[`When the code_quality_walkthrough URL parameter is present Code Quality Walkthrough Step component running_pipeline step renders a popover 1`] = `
<div>
<gl-popover-stub
container="viewport"
cssclasses=""
offset="97"
placement="bottom"
show=""
target="#js-code-quality-walkthrough"
triggers="manual"
>
<gl-sprintf-stub
message="Your pipeline can take a few minutes to run. If you enabled email notifications, you'll receive an email with your pipeline status. In the meantime, why don't you get some coffee? You earned it!"
/>
<div
class="gl-mt-2 gl-text-right"
>
<gl-button-stub
buttontextclasses=""
category="tertiary"
href=""
icon=""
size="medium"
variant="link"
>
Got it
</gl-button-stub>
</div>
</gl-popover-stub>
<!---->
</div>
`;
exports[`When the code_quality_walkthrough URL parameter is present Code Quality Walkthrough Step component success_pipeline step renders a popover 1`] = `
<div>
<gl-popover-stub
container="viewport"
cssclasses=""
offset="98"
placement="bottom"
show=""
target="#js-code-quality-walkthrough"
triggers="manual"
>
<gl-sprintf-stub
message="A code quality job will now run every time you or your team members commit changes to your project. You can view the results of the code quality job in the job logs."
/>
<div
class="gl-mt-2 gl-text-right"
>
<gl-button-stub
buttontextclasses=""
category="tertiary"
href="/group/project/-/jobs/:id?code_quality_walkthrough=true"
icon=""
size="medium"
variant="link"
>
View the logs
</gl-button-stub>
</div>
</gl-popover-stub>
<!---->
</div>
`;
exports[`When the code_quality_walkthrough URL parameter is present Code Quality Walkthrough Step component troubleshoot_job step renders an alert 1`] = `
<div>
<!---->
<gl-alert-stub
class="gl-my-5"
dismissible="true"
dismisslabel="Dismiss"
primarybuttontext="Read the documentation"
secondarybuttonlink=""
secondarybuttontext=""
title="Troubleshoot your code quality job"
variant="tip"
>
Not sure how to fix your failed job? We have compiled some tips on how to troubleshoot code quality jobs in the documentation.
</gl-alert-stub>
</div>
`;
import { GlButton, GlPopover } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import Cookies from 'js-cookie';
import Step from '~/code_quality_walkthrough/components/step.vue';
import { EXPERIMENT_NAME, STEPS } from '~/code_quality_walkthrough/constants';
import { TRACKING_CONTEXT_SCHEMA } from '~/experimentation/constants';
import { getParameterByName } from '~/lib/utils/url_utility';
import Tracking from '~/tracking';
jest.mock('~/lib/utils/url_utility', () => ({
...jest.requireActual('~/lib/utils/url_utility'),
getParameterByName: jest.fn(),
}));
let wrapper;
function factory({ step, link }) {
wrapper = shallowMount(Step, {
propsData: { step, link },
});
}
afterEach(() => {
wrapper.destroy();
});
const dummyLink = '/group/project/-/jobs/:id?code_quality_walkthrough=true';
const dummyContext = 'experiment_context';
const findButton = () => wrapper.findComponent(GlButton);
const findPopover = () => wrapper.findComponent(GlPopover);
describe('When the code_quality_walkthrough URL parameter is missing', () => {
beforeEach(() => {
getParameterByName.mockReturnValue(false);
});
it('does not render the component', () => {
factory({
step: STEPS.commitCiFile,
});
expect(findPopover().exists()).toBe(false);
});
});
describe('When the code_quality_walkthrough URL parameter is present', () => {
beforeEach(() => {
getParameterByName.mockReturnValue(true);
Cookies.set(EXPERIMENT_NAME, { data: dummyContext });
});
afterEach(() => {
Cookies.remove(EXPERIMENT_NAME);
});
describe('When mounting the component', () => {
beforeEach(() => {
jest.spyOn(Tracking, 'event');
factory({
step: STEPS.commitCiFile,
});
});
it('tracks an event', () => {
expect(Tracking.event).toHaveBeenCalledWith(
EXPERIMENT_NAME,
`${STEPS.commitCiFile}_displayed`,
{
context: {
schema: TRACKING_CONTEXT_SCHEMA,
data: dummyContext,
},
},
);
});
});
describe('When updating the component', () => {
beforeEach(() => {
factory({
step: STEPS.runningPipeline,
});
jest.spyOn(Tracking, 'event');
wrapper.setProps({ step: STEPS.successPipeline });
});
it('tracks an event', () => {
expect(Tracking.event).toHaveBeenCalledWith(
EXPERIMENT_NAME,
`${STEPS.successPipeline}_displayed`,
{
context: {
schema: TRACKING_CONTEXT_SCHEMA,
data: dummyContext,
},
},
);
});
});
describe('When dismissing a popover', () => {
beforeEach(() => {
factory({
step: STEPS.commitCiFile,
});
jest.spyOn(Cookies, 'set');
jest.spyOn(Tracking, 'event');
findButton().vm.$emit('click');
});
it('sets a cookie', () => {
expect(Cookies.set).toHaveBeenCalledWith(
EXPERIMENT_NAME,
{ commit_ci_file: true, data: dummyContext },
{ expires: 365, secure: false },
);
});
it('removes the popover', () => {
expect(findPopover().exists()).toBe(false);
});
it('tracks an event', () => {
expect(Tracking.event).toHaveBeenCalledWith(
EXPERIMENT_NAME,
`${STEPS.commitCiFile}_dismissed`,
{
context: {
schema: TRACKING_CONTEXT_SCHEMA,
data: dummyContext,
},
},
);
});
});
describe('Code Quality Walkthrough Step component', () => {
describe.each(Object.values(STEPS))('%s step', (step) => {
it(`renders ${step === STEPS.troubleshootJob ? 'an alert' : 'a popover'}`, () => {
const options = { step };
if ([STEPS.successPipeline, STEPS.failedPipeline].includes(step)) {
options.link = dummyLink;
}
factory(options);
expect(wrapper.element).toMatchSnapshot();
});
});
});
});
......@@ -34,7 +34,6 @@ describe('Job App', () => {
const props = {
artifactHelpUrl: 'help/artifact',
deploymentHelpUrl: 'help/deployment',
codeQualityHelpPath: '/help/code_quality',
runnerSettingsUrl: 'settings/ci-cd/runners',
terminalPath: 'jobs/123/terminal',
projectPath: 'user-name/project-name',
......
......@@ -10,7 +10,6 @@ import { TEST_HOST } from 'helpers/test_constants';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import Api from '~/api';
import { getExperimentData, getExperimentVariant } from '~/experimentation/utils';
import createFlash from '~/flash';
import axios from '~/lib/utils/axios_utils';
import NavigationControls from '~/pipelines/components/pipelines_list/nav_controls.vue';
......@@ -25,11 +24,6 @@ import TablePagination from '~/vue_shared/components/pagination/table_pagination
import { stageReply, users, mockSearch, branches } from './mock_data';
jest.mock('~/flash');
jest.mock('~/experimentation/utils', () => ({
...jest.requireActual('~/experimentation/utils'),
getExperimentData: jest.fn().mockReturnValue(false),
getExperimentVariant: jest.fn().mockReturnValue('control'),
}));
const mockProjectPath = 'twitter/flight';
const mockProjectId = '21';
......@@ -50,7 +44,6 @@ describe('Pipelines', () => {
ciLintPath: '/ci/lint',
resetCachePath: `${mockProjectPath}/settings/ci_cd/reset_cache`,
newPipelinePath: `${mockProjectPath}/pipelines/new`,
codeQualityPagePath: `${mockProjectPath}/-/new/master?commit_message=Add+.gitlab-ci.yml+and+create+a+code+quality+job&file_name=.gitlab-ci.yml&template=Code-Quality`,
ciRunnerSettingsPath: `${mockProjectPath}/-/settings/ci_cd#js-runners-settings`,
};
......@@ -557,35 +550,6 @@ describe('Pipelines', () => {
expect(wrapper.findComponent(PipelinesCiTemplates).exists()).toBe(true);
});
describe('when the code_quality_walkthrough experiment is active', () => {
beforeAll(() => {
getExperimentData.mockImplementation((name) => name === 'code_quality_walkthrough');
});
describe('the control state', () => {
beforeAll(() => {
getExperimentVariant.mockReturnValue('control');
});
it('renders the CI/CD templates', () => {
expect(wrapper.findComponent(PipelinesCiTemplates).exists()).toBe(true);
});
});
describe('the candidate state', () => {
beforeAll(() => {
getExperimentVariant.mockReturnValue('candidate');
});
it('renders another CTA button', () => {
expect(findEmptyState().findComponent(GlButton).text()).toBe('Add a code quality job');
expect(findEmptyState().findComponent(GlButton).attributes('href')).toBe(
paths.codeQualityPagePath,
);
});
});
});
it('does not render filtered search', () => {
expect(findFilteredSearch().exists()).toBe(false);
});
......
......@@ -120,7 +120,6 @@ RSpec.describe Ci::PipelinesHelper do
:has_gitlab_ci,
:pipeline_editor_path,
:suggested_ci_templates,
:code_quality_page_path,
:ci_runner_settings_path])
end
......
......@@ -747,10 +747,4 @@ RSpec.describe ProjectPresenter do
end
end
end
describe '#add_code_quality_ci_yml_path' do
subject { presenter.add_code_quality_ci_yml_path }
it { is_expected.to match(/code_quality_walkthrough=true.*template=Code-Quality/) }
end
end
......@@ -70,20 +70,6 @@ RSpec.describe PipelineDetailsEntity do
expect(subject[:flags][:retryable]).to eq false
end
end
it 'does not contain code_quality_build_path in details' do
expect(subject[:details]).not_to include :code_quality_build_path
end
context 'when option code_quality_walkthrough is set and pipeline is a success' do
let(:entity) do
described_class.represent(pipeline, request: request, code_quality_walkthrough: true)
end
it 'contains details.code_quality_build_path' do
expect(subject[:details]).to include :code_quality_build_path
end
end
end
context 'when pipeline is cancelable' do
......
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