diff --git a/src/forge/Server/api.js b/src/forge/Server/api.js index 52dc9dca4..acf0679af 100644 --- a/src/forge/Server/api.js +++ b/src/forge/Server/api.js @@ -3,8 +3,8 @@ import fetch from './fetch'; // 获取列表 export function getList(params, owner, repo) { return fetch({ - // url: `/api/v1/${owner}/${repo}/sonarqubes/issues_search.json`, - url: `/api/issues/search?components=kingchanx-fluid-cloudnative_fluid&s=FILE_LINE&issueStatuses=CONFIRMED%2COPEN&&additionalFields=_all&timeZone=Asia%2FShanghai`, + url: `/api/v1/${owner}/${repo}/sonarqubes/issues_search.json?s=FILE_LINE`, + // url: `/api/issues/search?components=kingchanx-fluid-cloudnative_fluid&s=FILE_LINE&issueStatuses=CONFIRMED%2COPEN&&additionalFields=_all&timeZone=Asia%2FShanghai`, method: 'get', params }); @@ -12,25 +12,25 @@ export function getList(params, owner, repo) { // 代码片段 -export function getCodeSnippets(key) { +export function getCodeSnippets(key, owner, repo) { return fetch({ - url: `/api/sources/issue_snippets?issueKey=${ key }`, + url: `/api/v1/${owner}/${repo}/sonarqubes/sources_issue_snippet.json?issueKey=${ key }`, method: 'get', }); } // 问题分析 -export function getProblemDetail(key) { +export function getProblemDetail(key, owner, repo) { return fetch({ - url: `/api/rules/show?key=${ key }`, + url: `/api/v1/${owner}/${repo}/sonarqubes/rules_show.json?key=${ key }`, method: 'get', }); } // 数据汇总 -export function getProblemData(component, keys) { +export function getProblemData(owner, repo , keys) { return fetch({ - url: `/api/measures/component?component=${ component }&metricKeys=${ keys }`, + url: `/api/v1/${owner}/${repo}/sonarqubes/measures_component.json?component=${ owner }-${ repo }&metricKeys=${ keys }`, method: 'get', }); } @@ -41,4 +41,29 @@ export function initSonar(open, owner, repo) { url: `/api/v1/${owner}/${repo}/sonarqubes/sonar_initialize.json?has_actions=${ open }`, method: 'post', }); -} \ No newline at end of file +} + +// 开始分析 +export function startAlalyze( branch , owner, repo) { + return fetch({ + url: `/api/v1/${owner}/${repo}/sonarqubes/insert_file.json?branch=${ branch }`, + method: 'post', + }); +} + +// // 获取action任务列表 +// export function getActionList(owner, repo ) { +// return fetch({ +// url: `/api/v1/${owner}/${repo}/actions`, +// method: 'get', +// }); +// } + +// 获取action任务列表 +export function getActionList(owner, repo ) { + return fetch({ + url: `/api/v1/${owner}/${repo}/actions/runs?workflow=SonarScanner.yaml`, + method: 'get', + }); +} + diff --git a/src/forge/Server/constants/quality.js b/src/forge/Server/constants/quality.js index 2cf44037a..c44461377 100644 --- a/src/forge/Server/constants/quality.js +++ b/src/forge/Server/constants/quality.js @@ -32,4 +32,4 @@ export const maintainabilityIcon = { LOW: low, MEDIUM: medium, HIGH: high -} \ No newline at end of file +} diff --git a/src/forge/Server/quality/detail.jsx b/src/forge/Server/quality/detail.jsx index 172f9f122..8adbadd68 100644 --- a/src/forge/Server/quality/detail.jsx +++ b/src/forge/Server/quality/detail.jsx @@ -39,7 +39,7 @@ function issueDetail(props){ useEffect(() => { if (selectedIssue) { - getCodeSnippets(selectedIssue.key).then(res => { + getCodeSnippets(selectedIssue.key, owner, projectsId).then(res => { processIssues(res[selectedIssue.component].sources, issues[selectedIssue.component]) setSnippetsDetail(res[selectedIssue.component]); }) @@ -160,7 +160,7 @@ function issueDetail(props){ } function detail() { - getProblemDetail(selectedIssue.rule).then(res => { + getProblemDetail( selectedIssue.rule, owner, projectsId).then(res => { setIssueInfo(res?.rule) setDetailVisible(true) }) diff --git a/src/forge/Server/quality/detail.scss b/src/forge/Server/quality/detail.scss index a49bfb454..69991a2a9 100644 --- a/src/forge/Server/quality/detail.scss +++ b/src/forge/Server/quality/detail.scss @@ -169,6 +169,13 @@ margin-bottom: 10px; cursor: pointer; word-break: break-word; + span { + font-weight: 400; + font-size: 14px; + color: #466AFF; + margin-left: 16px; + cursor: pointer; + } } .selected-issue { border: 1px solid rgb(253, 162, 155); diff --git a/src/forge/Server/quality/index.jsx b/src/forge/Server/quality/index.jsx index f1fae6bec..5549b0c03 100644 --- a/src/forge/Server/quality/index.jsx +++ b/src/forge/Server/quality/index.jsx @@ -1,9 +1,9 @@ import React, { useState, useEffect, Fragment } from "react"; -import { getList, getCodeSnippets, getProblemDetail, getProblemData, initSonar } from "../api"; +import { getList, getProblemDetail, getProblemData, initSonar, startAlalyze, getActionList } from "../api"; import './detail.scss'; import ProblemDetail from "./component/ProblemDetail"; import { issueType, maintainability, issueTypeIcon, maintainabilityIcon } from "../constants/quality"; -import { Divider, Pagination, Button } from 'antd'; +import { Divider, Pagination, Button, message, Spin } from 'antd'; import { formatNumber, formatNumberWithCommas } from '../../Utils/utils'; import logo from '../img/logo4-1.png'; import labelIcon from '../img/quality/label.png'; @@ -12,6 +12,15 @@ import repeat from '../img/quality/repeat.png'; import cover from '../img/quality/cover.png'; import { Link } from "react-router-dom"; + +const actionStatus = { + success: 1, + failure: 2, + waiting: 5, + running: 6, + none: 7 +} + function IssueList(props) { const [issues, setIssues] = useState({}); const [baseInfo, setBaseInfo] = useState({}); @@ -25,7 +34,9 @@ function IssueList(props) { const [selectedTag, setSelectedTag] = useState([]); const [pageNum, setPageNum] = useState(1); const [pageSize, setPageSize] = useState(10); - const [isopen, setIsopen] = useState(false); + const [loading, setLoading] = useState(false); + const [pageLoading, setPageLoading] = useState(true); + const [analysisStatus, setAnalysisStatus] = useState(status.none); const { projectDetail, history } = props; const metricKeys = 'lines,coverage,lines_to_cover,duplicated_lines_density,maintainability_issues,vulnerabilities,bugs,code_smells'; const facets = 'impactSeverities,tags,types'; @@ -43,19 +54,36 @@ function IssueList(props) { if (projectDetail) { const { author, name } = projectDetail; document.title = `代码质量分析-${author.name}/${name}`; - getIssueList(author.name, name); + setPageLoading(true) + getActionList(owner, projectsId).then(res => { + setPageLoading(false) + if (res.runs.length === 0) { + setAnalysisStatus(actionStatus.none) + } else { + setAnalysisStatus(res.runs[0].status) + if (res.runs[0].status) { + getData() + getIssueList() + } + } + }) } - getProblemData('kingchanx-fluid-cloudnative_fluid', metricKeys).then(res => { - const measures = res.component.measures; - const result = {}; - measures.forEach(measure => { - result[measure.metric] = measure.value; - }); - setBaseData(result); - }); }, [projectDetail]); - const getIssueList = (owner, name) => { + const getData = () => { + getProblemData(owner, projectsId, metricKeys).then(res => { + if (res.status === 0) { + const measures = res.component.measures; + const result = {}; + measures.forEach(measure => { + result[measure.metric] = measure.value; + }); + setBaseData(result); + } + }); + } + + const getIssueList = () => { let params = { facets: facets, types: selectedType.join(','), @@ -64,7 +92,9 @@ function IssueList(props) { p: pageNum, ps: pageSize }; - getList(params, owner, name).then(res => { + setPageLoading(true) + getList(params, owner, projectsId).then(res => { + setPageLoading(false) const issues = res.issues.reduce((acc, issue) => { if (acc[issue.component]) { acc[issue.component].push(issue); @@ -86,16 +116,22 @@ function IssueList(props) { }; useEffect(() => { - setPageNum(1) + if (pageNum === 1) { + getIssueList() + } else { + setPageNum(1) + } }, [selectedType, selectedSeverity, selectedTag]); useEffect(() => { - getIssueList(); + if (projectDetail && analysisStatus === actionStatus.success) { + getIssueList() + } }, [pageNum, pageSize]); const detail = (e) => { setSelectedIssue(e); - getProblemDetail(e.rule).then(res => { + getProblemDetail(e.rule, owner, projectsId).then(res => { setIssueInfo(res?.rule); setDetailVisible(true); }); @@ -159,90 +195,124 @@ function IssueList(props) { } const openAnalysis = () => { - initSonar(true, owner, projectsId) + setLoading(true) + initSonar(true, owner, projectsId).then(res => { + if (res.status === 0) { + startAlalyze(projectDetail.default_branch, owner, projectsId).then(res1=> { + if (res1.status === 0) { + message.success('创建分析成功,请等待分析完成') + setAnalysisStatus(actionStatus.waiting) + } + setLoading(false) + }) + } else { + setLoading(false) + } + }) + } + + const getStatusButton = () => { + switch (analysisStatus) { + case actionStatus.none: + return + case actionStatus.waiting: + case actionStatus.running: + return + case actionStatus.failure: + return
代码正在分析中,请重试
+ +欢迎使用代码质量分析工具
-代码分析结果
-欢迎使用代码质量分析工具
+代码分析结果
+- {e.message} - detail(e)}>问题分析 - L{e.line} -
-
- {issueType[e.type]}
-
{maintainability[e.impacts[0].severity]}
- {e.debt}工作
-
- {e.tags && e.tags.length > 0 &&
}
- {e.tags && e.tags.map((tag, index) => (
-
- {tag}{index < e.tags.length - 1 ? ',' : ''}
-
- ))}
-
-
+ {e.message} + { ele.stopPropagation();detail(e)}}>问题分析 + L{e.line} +
+
+ {issueType[e.type]}
+
{maintainability[e.impacts[0].severity]}
+ {e.debt}工作
+
+ {e.tags && e.tags.length > 0 &&
}
+ {e.tags && e.tags.map((tag, index) => (
+
+ {tag}{index < e.tags.length - 1 ? ',' : ''}
+
+ ))}
+
+