Skip to content
代码片段 群组 项目
未验证 提交 537c20cf 编辑于 作者: Max Fan's avatar Max Fan 提交者: GitLab
浏览文件

Merge branch '482497-add-new-rca-location' into 'master'

No related branches found
No related tags found
无相关合并请求
显示
98 个添加47 个删除
......@@ -34,7 +34,6 @@ export const initJobDetails = () => {
pipelineTestReportUrl,
logViewerPath,
duoFeaturesEnabled,
jobGid,
} = el.dataset;
const fullScreenAPIAvailable = document.fullscreenEnabled;
......@@ -59,7 +58,6 @@ export const initJobDetails = () => {
aiRootCauseAnalysisAvailable: parseBoolean(aiRootCauseAnalysisAvailable),
duoFeaturesEnabled: parseBoolean(duoFeaturesEnabled),
pipelineTestReportUrl,
jobGid,
},
render(h) {
return h(JobApp, {
......
......@@ -137,13 +137,6 @@ export default {
jobConfirmationMessage() {
return this.job.status?.action?.confirmation_message;
},
jobFailed() {
const { status } = this.job;
const failedGroups = ['failed', 'failed-with-warnings'];
return failedGroups.includes(status.group);
},
},
watch: {
// Once the job log is loaded,
......@@ -326,8 +319,14 @@ export default {
@enterFullscreen="enterFullscreen"
@exitFullscreen="exitFullscreen"
/>
<log :search-results="searchResults" />
<root-cause-analysis-button :job-failed="jobFailed" />
<root-cause-analysis-button
:job-id="job.id"
:job-status-group="job.status.group"
:can-troubleshoot-job="glAbilities.troubleshootJobWithAi"
/>
</div>
<!-- EO job log -->
......
......@@ -7,6 +7,7 @@ import CiIcon from '~/vue_shared/components/ci_icon/ci_icon.vue';
import SafeHtml from '~/vue_shared/directives/safe_html';
import { BRIDGE_KIND } from '~/ci/pipeline_details/graph/constants';
import RetryMrFailedJobMutation from '~/ci/merge_requests/graphql/mutations/retry_mr_failed_job.mutation.graphql';
import RootCauseAnalysisButton from 'ee_else_ce/ci/job_details/components/root_cause_analysis_button.vue';
export default {
components: {
......@@ -14,6 +15,7 @@ export default {
GlButton,
GlLink,
GlTooltip,
RootCauseAnalysisButton,
},
directives: {
GlTooltip: GlTooltipDirective,
......@@ -24,6 +26,10 @@ export default {
type: Object,
required: true,
},
canTroubleshootJob: {
type: Boolean,
required: true,
},
},
data() {
return {
......@@ -34,8 +40,14 @@ export default {
canRetryJob() {
return this.job.retryable && this.job.userPermissions.updateBuild && !this.isBridgeJob;
},
detailedStatus() {
return this.job?.detailedStatus;
},
detailsPath() {
return this.job?.detailedStatus?.detailsPath;
return this.detailedStatus?.detailsPath;
},
statusGroup() {
return this.detailedStatus?.group;
},
isBridgeJob() {
return this.job.kind === BRIDGE_KIND;
......@@ -100,16 +112,23 @@ export default {
>{{ job.name }}</gl-link
>
</div>
<div class="col-3 gl-flex gl-items-center" data-testid="job-stage-name">
<div class="col-2 gl-flex gl-items-center" data-testid="job-stage-name">
{{ job.stage.name }}
</div>
<div class="col-3 gl-flex gl-items-center">
<div class="col-2 gl-flex gl-items-center">
<gl-link :href="detailsPath" data-testid="job-id-link">#{{ parsedJobId }}</gl-link>
</div>
<gl-tooltip v-if="!canRetryJob" :target="() => $refs.retryBtn" placement="top">
{{ tooltipErrorText }}
</gl-tooltip>
<div class="col-2 gl-text-right">
<div class="col-4 gl-text-right">
<root-cause-analysis-button
class="gl-mr-2"
:job-gid="job.id"
:job-status-group="statusGroup"
:can-troubleshoot-job="canTroubleshootJob"
/>
<span ref="retryBtn">
<gl-button
v-gl-tooltip
......
......@@ -54,6 +54,7 @@ export default {
failedJobs: [],
isActive: false,
isLoadingMore: false,
canTroubleshootJob: false,
};
},
apollo: {
......@@ -75,6 +76,7 @@ export default {
},
result({ data }) {
const pipeline = data?.project?.pipeline;
this.canTroubleshootJob = pipeline?.troubleshootJobWithAi || false;
if (pipeline?.jobs?.count) {
this.$emit('failed-jobs-count', pipeline.jobs.count);
......@@ -150,8 +152,8 @@ export default {
},
columns: [
{ text: JOB_NAME_HEADER, class: 'col-4' },
{ text: STAGE_HEADER, class: 'col-3' },
{ text: JOB_ID_HEADER, class: 'col-3' },
{ text: STAGE_HEADER, class: 'col-2' },
{ text: JOB_ID_HEADER, class: 'col-2' },
],
i18n: {
maximumJobLimitAlert: {
......@@ -200,6 +202,7 @@ export default {
v-for="job in failedJobs"
:key="job.id"
:job="job"
:can-troubleshoot-job="canTroubleshootJob"
@job-retried="retryJob"
/>
</div>
......
......@@ -4,6 +4,7 @@ query getPipelineFailedJobs($fullPath: ID!, $pipelineIid: ID!) {
pipeline(iid: $pipelineIid) {
id
active
troubleshootJobWithAi
jobs(statuses: [FAILED], retried: false) {
count
nodes {
......
......@@ -14,8 +14,7 @@ def jobs_data(project, build)
"runner_settings_url" => project_runners_path(build.project, anchor: 'js-runners-settings'),
"retry_outdated_job_docs_url" => help_page_path('ci/pipelines/settings.md', anchor: 'prevent-outdated-deployment-jobs'),
"pipeline_test_report_url" => test_report_project_pipeline_path(project, build.pipeline),
"log_viewer_path" => viewer_project_job_path(project, build),
"job_gid" => build.to_gid.to_s
"log_viewer_path" => viewer_project_job_path(project, build)
}
end
......
......@@ -9,7 +9,6 @@ export default {
CeJobLogTopBar,
},
mixins: [glFeatureFlagMixin()],
inject: ['jobGid'],
props: {
size: {
type: Number,
......
<script>
import { GlButton } from '@gitlab/ui';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import glAbilitiesMixin from '~/vue_shared/mixins/gl_abilities_mixin';
import { sendDuoChatCommand } from 'ee/ai/utils';
import { TYPENAME_CI_BUILD } from '~/graphql_shared/constants';
import { convertToGraphQLId } from '~/graphql_shared/utils';
export default {
components: {
GlButton,
},
mixins: [glAbilitiesMixin(), glFeatureFlagMixin()],
inject: ['jobGid'],
props: {
jobFailed: {
canTroubleshootJob: {
type: Boolean,
required: true,
},
jobStatusGroup: {
type: String,
required: true,
},
jobId: {
type: Number,
required: false,
default: null,
},
jobGid: {
type: String,
required: false,
default: false,
default: '',
},
},
computed: {
resourceId() {
return this.jobGid || convertToGraphQLId(TYPENAME_CI_BUILD, this.jobId);
},
jobFailed() {
const failedGroups = ['failed', 'failed-with-warnings'];
return failedGroups.includes(this.jobStatusGroup);
},
},
methods: {
callDuo() {
sendDuoChatCommand({
question: '/troubleshoot',
resourceId: this.jobGid,
resourceId: this.resourceId,
});
},
},
......@@ -29,9 +50,8 @@ export default {
</script>
<template>
<gl-button
v-if="glAbilities.troubleshootJobWithAi && jobFailed"
v-if="jobFailed && canTroubleshootJob"
icon="duo-chat"
class="gl-mr-3"
variant="confirm"
data-testid="rca-duo-button"
@click="callDuo"
......
......@@ -11,23 +11,16 @@ describe('Root cause analysis button', () => {
let wrapper;
const defaultProps = {
jobFailed: true,
jobStatusGroup: 'failed',
canTroubleshootJob: true,
};
const jobGid = 'gid://gitlab/Ci::Build/123';
const createComponent = (props) => {
wrapper = shallowMountExtended(RootCauseAnalysisButton, {
propsData: {
...defaultProps,
...props,
},
provide: {
glAbilities: {
troubleshootJobWithAi: true,
},
jobGid,
},
});
};
......@@ -40,19 +33,40 @@ describe('Root cause analysis button', () => {
});
it('should not display the Troubleshoot button when no failure is detected', () => {
createComponent({ jobFailed: false });
createComponent({ jobStatusGroup: 'canceled' });
expect(findTroubleshootButton().exists()).toBe(false);
});
it('sends a call to the sendDuoChatCommand utility function', () => {
createComponent();
it('should not display the Troubleshoot button when user cannot troubleshoot', () => {
createComponent({ canTroubleshootJob: false });
expect(findTroubleshootButton().exists()).toBe(false);
});
describe('with jobId', () => {
it('sends a call to the sendDuoChatCommand utility function with convereted ID', () => {
createComponent({ jobId: 123 });
wrapper.findComponent(GlButton).vm.$emit('click');
expect(sendDuoChatCommand).toHaveBeenCalledWith({
question: '/troubleshoot',
resourceId: 'gid://gitlab/Ci::Build/123',
});
});
});
describe('with jobGid', () => {
it('sends a call to the sendDuoChatCommand utility function with normal GID', () => {
createComponent({ jobGid: 'gid://gitlab/Ci::Build/11781' });
wrapper.findComponent(GlButton).vm.$emit('click');
wrapper.findComponent(GlButton).vm.$emit('click');
expect(sendDuoChatCommand).toHaveBeenCalledWith({
question: '/troubleshoot',
resourceId: jobGid,
expect(sendDuoChatCommand).toHaveBeenCalledWith({
question: '/troubleshoot',
resourceId: 'gid://gitlab/Ci::Build/11781',
});
});
});
});
......@@ -24,7 +24,6 @@ describe('EE JobLogTopBar', () => {
...props,
},
provide: {
jobGid: 'gid://gitlab/Ci::Build/123',
glAbilities: {
troubleshootJobWithAi: false,
},
......
......@@ -56,6 +56,7 @@ const createFailedJobsMock = (nodes, active = false) => {
id: 'gid://gitlab/Project/20',
pipeline: {
active,
troubleshootJobWithAi: true,
id: 'gid://gitlab/Pipeline/20',
jobs: {
count: nodes.length,
......
......@@ -29,8 +29,7 @@
"runner_settings_url" => "/#{project.full_path}/-/runners#js-runners-settings",
"retry_outdated_job_docs_url" => "/help/ci/pipelines/settings.md#prevent-outdated-deployment-jobs",
"pipeline_test_report_url" => "/#{project.full_path}/-/pipelines/#{job.pipeline.id}/test_report",
"log_viewer_path" => "/#{project.full_path}/-/jobs/#{job.id}/viewer",
"job_gid" => "gid://gitlab/Ci::Build/#{job.id}"
"log_viewer_path" => "/#{project.full_path}/-/jobs/#{job.id}/viewer"
})
end
......
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册