提交 4d8a9aa5 编写于 作者: Z zhaoke

* Add command submit unit bug.

上级 d0e1397d
...@@ -2,19 +2,20 @@ package action ...@@ -2,19 +2,20 @@ package action
import ( import (
"fmt" "fmt"
"os"
"strconv"
"strings"
commConsts "github.com/easysoft/zentaoatf/internal/pkg/consts" commConsts "github.com/easysoft/zentaoatf/internal/pkg/consts"
commDomain "github.com/easysoft/zentaoatf/internal/pkg/domain" commDomain "github.com/easysoft/zentaoatf/internal/pkg/domain"
analysisHelper "github.com/easysoft/zentaoatf/internal/pkg/helper/analysis" analysisHelper "github.com/easysoft/zentaoatf/internal/pkg/helper/analysis"
configHelper "github.com/easysoft/zentaoatf/internal/pkg/helper/config" configHelper "github.com/easysoft/zentaoatf/internal/pkg/helper/config"
"github.com/easysoft/zentaoatf/internal/pkg/helper/zentao" zentaoHelper "github.com/easysoft/zentaoatf/internal/pkg/helper/zentao"
i118Utils "github.com/easysoft/zentaoatf/pkg/lib/i118" i118Utils "github.com/easysoft/zentaoatf/pkg/lib/i118"
logUtils "github.com/easysoft/zentaoatf/pkg/lib/log" logUtils "github.com/easysoft/zentaoatf/pkg/lib/log"
stdinUtils "github.com/easysoft/zentaoatf/pkg/lib/stdin" stdinUtils "github.com/easysoft/zentaoatf/pkg/lib/stdin"
stringUtils "github.com/easysoft/zentaoatf/pkg/lib/string" stringUtils "github.com/easysoft/zentaoatf/pkg/lib/string"
"github.com/fatih/color" "github.com/fatih/color"
"os"
"strconv"
"strings"
) )
var ( var (
...@@ -46,6 +47,13 @@ func CommitBug(files []string, productId int, noNeedConfirm bool) { ...@@ -46,6 +47,13 @@ func CommitBug(files []string, productId int, noNeedConfirm bool) {
lines := make([]string, 0) lines := make([]string, 0)
for _, cs := range report.FuncResult { for _, cs := range report.FuncResult {
if cs.Status != commConsts.PASS { if cs.Status != commConsts.PASS {
lines = append(lines, fmt.Sprintf("%d. %s %s", cs.Id, cs.Title, coloredStatus(cs.Status.String())))
ids = append(ids, strconv.Itoa(cs.Id))
}
}
for _, cs := range report.UnitResult {
if cs.Status != "pass" {
lines = append(lines, fmt.Sprintf("%d. %s %s", cs.Id, cs.Title, coloredStatus(cs.Status))) lines = append(lines, fmt.Sprintf("%d. %s %s", cs.Id, cs.Title, coloredStatus(cs.Status)))
ids = append(ids, strconv.Itoa(cs.Id)) ids = append(ids, strconv.Itoa(cs.Id))
} }
...@@ -83,8 +91,8 @@ func CommitBug(files []string, productId int, noNeedConfirm bool) { ...@@ -83,8 +91,8 @@ func CommitBug(files []string, productId int, noNeedConfirm bool) {
} }
} }
func coloredStatus(status commConsts.ResultStatus) string { func coloredStatus(status string) string {
temp := strings.ToLower(status.String()) temp := strings.ToLower(status)
switch temp { switch temp {
case "pass": case "pass":
...@@ -95,7 +103,7 @@ func coloredStatus(status commConsts.ResultStatus) string { ...@@ -95,7 +103,7 @@ func coloredStatus(status commConsts.ResultStatus) string {
return color.YellowString(i118Utils.Sprintf(temp)) return color.YellowString(i118Utils.Sprintf(temp))
} }
return status.String() return status
} }
func reportBug(resultDir string, caseId string, productId int) error { func reportBug(resultDir string, caseId string, productId int) error {
......
...@@ -112,8 +112,9 @@ type ZtfStep struct { ...@@ -112,8 +112,9 @@ type ZtfStep struct {
} }
type ZtfBug struct { type ZtfBug struct {
Title string `json:"title"` Title string `json:"title"`
Type string `json:"type"` Type string `json:"type"`
TestType commConsts.TestType `json:"testType"`
StepIds string `json:"ids"` // for to StepIds string `json:"ids"` // for to
......
...@@ -10,9 +10,11 @@ import ( ...@@ -10,9 +10,11 @@ import (
commConsts "github.com/easysoft/zentaoatf/internal/pkg/consts" commConsts "github.com/easysoft/zentaoatf/internal/pkg/consts"
commDomain "github.com/easysoft/zentaoatf/internal/pkg/domain" commDomain "github.com/easysoft/zentaoatf/internal/pkg/domain"
analysisHelper "github.com/easysoft/zentaoatf/internal/pkg/helper/analysis" analysisHelper "github.com/easysoft/zentaoatf/internal/pkg/helper/analysis"
serverDomain "github.com/easysoft/zentaoatf/internal/server/modules/v1/domain"
httpUtils "github.com/easysoft/zentaoatf/pkg/lib/http" httpUtils "github.com/easysoft/zentaoatf/pkg/lib/http"
i118Utils "github.com/easysoft/zentaoatf/pkg/lib/i118" i118Utils "github.com/easysoft/zentaoatf/pkg/lib/i118"
logUtils "github.com/easysoft/zentaoatf/pkg/lib/log" logUtils "github.com/easysoft/zentaoatf/pkg/lib/log"
stdinUtils "github.com/easysoft/zentaoatf/pkg/lib/stdin"
"github.com/fatih/color" "github.com/fatih/color"
"github.com/jinzhu/copier" "github.com/jinzhu/copier"
uuid "github.com/satori/go.uuid" uuid "github.com/satori/go.uuid"
...@@ -26,6 +28,9 @@ func CommitBug(ztfBug commDomain.ZtfBug, config commDomain.WorkspaceConf) (err e ...@@ -26,6 +28,9 @@ func CommitBug(ztfBug commDomain.ZtfBug, config commDomain.WorkspaceConf) (err e
Login(config) Login(config)
if ztfBug.TestType == commConsts.TestUnit {
return CommitUnitBug(&ztfBug, config)
}
ztfBug.Steps = strings.Replace(ztfBug.Steps, " ", " ", -1) ztfBug.Steps = strings.Replace(ztfBug.Steps, " ", " ", -1)
ztfBug.Steps = strings.Replace(ztfBug.Steps, "\n", "<br />", -1) ztfBug.Steps = strings.Replace(ztfBug.Steps, "\n", "<br />", -1)
...@@ -45,6 +50,44 @@ func CommitBug(ztfBug commDomain.ZtfBug, config commDomain.WorkspaceConf) (err e ...@@ -45,6 +50,44 @@ func CommitBug(ztfBug commDomain.ZtfBug, config commDomain.WorkspaceConf) (err e
return return
} }
func CommitUnitBug(ztfBug *commDomain.ZtfBug, config commDomain.WorkspaceConf) (err error) {
if ztfBug.Product == 0 {
logUtils.Info(color.RedString(i118Utils.Sprintf("ignore_bug_without_product")))
return
}
if ztfBug.Title == "" {
ztfBug.Title = stdinUtils.GetInput("\\w+", "",
i118Utils.Sprintf("pls_enter")+" "+i118Utils.Sprintf("bug_title"))
}
Login(config)
submitBugs := make([]*commDomain.ZentaoBug, 0)
ztfBug.Steps = strings.Replace(ztfBug.Steps, " ", "&nbsp;", -1)
ztfBug.Steps = strings.Replace(ztfBug.Steps, "\n", "<br />", -1)
ztfBug.Title = strings.Trim(ztfBug.Title, "-")
bug := commDomain.ZentaoBug{}
copier.Copy(&bug, ztfBug)
submitBugs = append(submitBugs, &bug)
generateCaseId(submitBugs, config)
for _, bug := range submitBugs {
uri := fmt.Sprintf("/products/%d/bugs", bug.Product)
url := GenApiUrl(uri, nil, config.Url)
_, err = httpUtils.Post(url, bug)
if err != nil {
err = ZentaoRequestErr(url, i118Utils.Sprintf("fail_to_report_bug", err.Error()))
return
}
logUtils.Info(color.GreenString(i118Utils.Sprintf("success_to_report_bug", bug.Case)))
}
return
}
func PrepareBug(workspacePath, seq string, caseIdStr string, productId int) (bug commDomain.ZtfBug) { func PrepareBug(workspacePath, seq string, caseIdStr string, productId int) (bug commDomain.ZtfBug) {
caseId, err := strconv.Atoi(caseIdStr) caseId, err := strconv.Atoi(caseIdStr)
...@@ -69,21 +112,23 @@ func PrepareBug(workspacePath, seq string, caseIdStr string, productId int) (bug ...@@ -69,21 +112,23 @@ func PrepareBug(workspacePath, seq string, caseIdStr string, productId int) (bug
if step.Status == commConsts.FAIL { if step.Status == commConsts.FAIL {
stepIds += step.Id + "_" stepIds += step.Id + "_"
} }
stepIds = strings.Trim(stepIds, "_")
stepsContent := GenBugStepText(step) stepsContent := GenBugStepText(step)
steps = append(steps, stepsContent) steps = append(steps, stepsContent)
stepsArray = append(stepsArray, map[string]interface{}{ stepsArray = append(stepsArray, map[string]interface{}{
"name": step.Name, "title": step.Name,
"status": step.Status, "status": step.Status,
"steps": stepsContent, "steps": stepsContent,
}) })
} }
bug = commDomain.ZtfBug{ bug = commDomain.ZtfBug{
Title: cs.Title, Title: cs.Title,
Case: cs.Id, TestType: "func",
Product: productId, Case: cs.Id,
Steps: strings.Join(steps, "\n"), Product: productId,
StepIds: stepIds, Steps: strings.Join(steps, "\n"),
StepIds: stepIds,
Uid: uuid.NewV4().String(), Uid: uuid.NewV4().String(),
Type: "codeerror", Severity: 3, Pri: 3, OpenedBuild: []string{"trunk"}, Type: "codeerror", Severity: 3, Pri: 3, OpenedBuild: []string{"trunk"},
...@@ -96,6 +141,54 @@ func PrepareBug(workspacePath, seq string, caseIdStr string, productId int) (bug ...@@ -96,6 +141,54 @@ func PrepareBug(workspacePath, seq string, caseIdStr string, productId int) (bug
return return
} }
if report.TestType == commConsts.TestFunc {
return
}
bugs := make([]map[string]interface{}, 0)
stepIds := ""
hasCaseId := true
if len(report.UnitResult) == report.UnitResult[len(report.UnitResult)-1].Id {
hasCaseId = false
}
for _, cs := range report.UnitResult {
if (caseId > 0 && cs.Id != caseId) || cs.Status == "pass" {
continue
}
stepIds += strconv.Itoa(cs.Id) + "_"
steps := ""
if cs.Failure != nil {
steps = cs.Failure.Desc
}
caseId = cs.Id
if !hasCaseId {
caseId = 0
}
bugMap := map[string]interface{}{
"title": cs.Title,
"status": cs.Status,
"steps": steps,
"caseId": caseId,
"id": cs.Id,
}
bugs = append(bugs, bugMap)
break
}
bugsJSon, _ := json.Marshal(bugs)
bug = commDomain.ZtfBug{
Title: report.Name,
TestType: "unit",
Case: caseId,
Product: productId,
Steps: string(bugsJSon),
StepIds: stepIds,
Uid: uuid.NewV4().String(),
Type: "codeerror", Severity: 3, Pri: 3, OpenedBuild: []string{"trunk"},
CaseVersion: "0", OldTaskID: "0",
}
return return
} }
...@@ -197,3 +290,25 @@ func LoadBugs(Product int, config commDomain.WorkspaceConf) (bugs []commDomain.Z ...@@ -197,3 +290,25 @@ func LoadBugs(Product int, config commDomain.WorkspaceConf) (bugs []commDomain.Z
} }
return return
} }
func generateCaseId(bugs []*commDomain.ZentaoBug, config commDomain.WorkspaceConf) (caseId int) {
if len(bugs) == 0 {
return
}
//查询所有case,标题相同则返回
casesResp, _ := ListCaseByProduct(config.Url, bugs[0].Product)
for _, bug := range bugs {
for _, cs := range casesResp.Cases {
if cs.Title == bug.Title {
bug.Case = cs.Id
break
}
}
if bug.Case == 0 {
caseInfo, _ := CreateCase(bug.Product, bug.Title, nil, serverDomain.TestScript{}, config)
bug.Case = caseInfo.Id
}
}
return
}
...@@ -75,6 +75,54 @@ func CommitCase(caseId int, title string, steps []commDomain.ZentaoCaseStep, scr ...@@ -75,6 +75,54 @@ func CommitCase(caseId int, title string, steps []commDomain.ZentaoCaseStep, scr
return return
} }
func CreateCase(productId int, title string, steps []commDomain.ZentaoCaseStep, script serverDomain.TestScript,
config commDomain.WorkspaceConf) (cs commDomain.ZtfCase, err error) {
err = Login(config)
if err != nil {
return
}
uri := fmt.Sprintf("/products/%d/testcases", productId)
url := GenApiUrl(uri, nil, config.Url)
requestObj := map[string]interface{}{
"type": "feature",
"title": title,
"steps": steps,
"script": script.Code,
"lang": script.Lang,
"pri": 3,
}
if steps == nil {
requestObj["steps"] = []commDomain.ZentaoCaseStep{}
}
jsonData, err := json.Marshal(requestObj)
if err != nil {
err = ZentaoRequestErr(url, commConsts.ResponseParseErr.Message)
return
}
if commConsts.Verbose {
logUtils.Infof(string(jsonData))
}
bytes, err := httpUtils.Post(url, requestObj)
if err != nil {
err = ZentaoRequestErr(url, err.Error())
return
}
err = json.Unmarshal(bytes, &cs)
if err != nil {
err = ZentaoRequestErr(url, commConsts.ResponseParseErr.Message)
return
}
logUtils.Infof(i118Utils.Sprintf("success_to_create_case", title) + "\n")
return
}
func GetCaseById(baseUrl string, caseId int) (cs commDomain.ZtfCase, err error) { func GetCaseById(baseUrl string, caseId int) (cs commDomain.ZtfCase, err error) {
uri := fmt.Sprintf("/testcases/%d", caseId) uri := fmt.Sprintf("/testcases/%d", caseId)
url := GenApiUrl(uri, nil, baseUrl) url := GenApiUrl(uri, nil, baseUrl)
...@@ -450,7 +498,9 @@ func GetCasesByTaskInDir(productId int, taskId int, workspacePath, scriptDir str ...@@ -450,7 +498,9 @@ func GetCasesByTaskInDir(productId int, taskId int, workspacePath, scriptDir str
func ListCaseByProduct(baseUrl string, productId int) (casesResp commDomain.ZtfRespTestCases, err error) { func ListCaseByProduct(baseUrl string, productId int) (casesResp commDomain.ZtfRespTestCases, err error) {
uri := fmt.Sprintf("/products/%d/testcases", productId) uri := fmt.Sprintf("/products/%d/testcases", productId)
url := GenApiUrl(uri, nil, baseUrl) url := GenApiUrl(uri, map[string]interface{}{
"limit": 10000,
}, baseUrl)
dataStr, err := httpUtils.Get(url) dataStr, err := httpUtils.Get(url)
if err != nil { if err != nil {
......
...@@ -666,6 +666,10 @@ ...@@ -666,6 +666,10 @@
{ {
"id": "must_provide_allure_report_dir", "id": "must_provide_allure_report_dir",
"translation": "Please provide report dir if using Allure Report Framework." "translation": "Please provide report dir if using Allure Report Framework."
},
{
"id": "bug_title",
"translation": "BUG Title"
} }
] ]
} }
...@@ -653,6 +653,10 @@ ...@@ -653,6 +653,10 @@
{ {
"id": "must_provide_allure_report_dir", "id": "must_provide_allure_report_dir",
"translation": "使用Allure报表框架时,需要指定报告所在的目录。" "translation": "使用Allure报表框架时,需要指定报告所在的目录。"
},
{
"id": "bug_title",
"translation": "缺陷标题"
} }
] ]
} }
...@@ -587,7 +587,7 @@ export default defineComponent({ ...@@ -587,7 +587,7 @@ export default defineComponent({
} }
} }
}); });
setting.isCheckAll = isChecked.length >= localRows.value.length; setting.isCheckAll = isChecked.length >= rowCheckbox.value.length;
// 回傳畫面上選上的資料 (Return the selected data on the screen) // 回傳畫面上選上的資料 (Return the selected data on the screen)
emit("return-checked-rows", isChecked); emit("return-checked-rows", isChecked);
}; };
......
...@@ -10,6 +10,7 @@ export default { ...@@ -10,6 +10,7 @@ export default {
'fullScreen': 'Toggle Fullscreen', 'fullScreen': 'Toggle Fullscreen',
'help': 'Help', 'help': 'Help',
'loading': 'Loading...', 'loading': 'Loading...',
'syncing': 'Syncing...',
'index': 'Index', 'index': 'Index',
'no': 'NO.', 'no': 'NO.',
......
...@@ -11,6 +11,7 @@ export default { ...@@ -11,6 +11,7 @@ export default {
'fullScreen': '切换全屏', 'fullScreen': '切换全屏',
'help': '帮助', 'help': '帮助',
'loading': '正在加载……', 'loading': '正在加载……',
'syncing': '同步中…',
'index': '索引', 'index': '索引',
'no': '编号', 'no': '编号',
......
...@@ -68,7 +68,7 @@ ...@@ -68,7 +68,7 @@
<div class="steps-contain"> <div class="steps-contain">
<div class="steps-select" v-for="(item,index) in steps" :key="index"> <div class="steps-select" v-for="(item,index) in steps" :key="index">
<input type="checkbox" :id="'cbox'+index" :value="index" :checked="item.checked" @click="stepSelect" /> <input type="checkbox" :id="'cbox'+index" :value="index" :checked="item.checked" @click="stepSelect" />
<label :for="'cbox'+index" :class="'steps-label step-' + item.status">{{item.name}}</label> <label :for="'cbox'+index" :class="'steps-label step-' + item.status">{{item.title}}</label>
</div> </div>
<textarea v-model="modelRef.steps" rows="6" /> <textarea v-model="modelRef.steps" rows="6" />
</div> </div>
......
...@@ -91,6 +91,13 @@ ...@@ -91,6 +91,13 @@
class="space-left rounded pure text-red" class="space-left rounded pure text-red"
:label="t('view_error')" :label="t('view_error')"
/> />
<Button
v-if="result.status === 'fail' && currProduct.id"
icon="bug"
@click="openBugForm(result)"
class="space-left rounded pure text-blue"
:label="t('submit_bug_to_zentao')"
/>
</template> </template>
</ListItem> </ListItem>
<div class="unit-result-info row gap-xl padding-bottom small"> <div class="unit-result-info row gap-xl padding-bottom small">
......
...@@ -3,8 +3,9 @@ ...@@ -3,8 +3,9 @@
:showModal="showModalRef" :showModal="showModalRef"
@onCancel="cancel" @onCancel="cancel"
@onOk="submit" @onOk="submit"
:okTitle="okTitle"
:title="t('sync-from-zentao')" :title="t('sync-from-zentao')"
:contentStyle="{ width: '600px' }" :contentStyle="{ width: '600px', overflow: 'hidden' }"
> >
<Form> <Form>
<FormItem labelWidth="140px" :label="t('module')"> <FormItem labelWidth="140px" :label="t('module')">
...@@ -58,8 +59,8 @@ ...@@ -58,8 +59,8 @@
:sortable="{}" :sortable="{}"
:hasCheckbox="true" :hasCheckbox="true"
:isCheckAll="true" :isCheckAll="true"
ref="tableRef"
@return-checked-rows="onCheckedRows" @return-checked-rows="onCheckedRows"
class="table-sync-from-zentao"
> >
<template #Type="record"> <template #Type="record">
{{ t('case_type_' + record.value.Type) }} {{ t('case_type_' + record.value.Type) }}
...@@ -69,7 +70,7 @@ ...@@ -69,7 +70,7 @@
</template> </template>
</Table> </Table>
<p v-else class="empty-tip"> <p v-else class="empty-tip">
{{ t("empty_data") }} {{ tableNotice }}
</p> </p>
</Form> </Form>
</ZModal> </ZModal>
...@@ -110,6 +111,9 @@ const disabled = ref(false); ...@@ -110,6 +111,9 @@ const disabled = ref(false);
const props = withDefaults(defineProps<FormWorkspaceProps>(), { const props = withDefaults(defineProps<FormWorkspaceProps>(), {
show: false, show: false,
}); });
const okTitle = ref(t('confirm'))
const tableNotice = ref(t('loading'))
watch(props, () => { watch(props, () => {
if(!props.show) disabled.value = false; if(!props.show) disabled.value = false;
modelRef.value.workspaceId = props.workspaceId; modelRef.value.workspaceId = props.workspaceId;
...@@ -156,6 +160,7 @@ const submit = () => { ...@@ -156,6 +160,7 @@ const submit = () => {
if(disabled.value) { if(disabled.value) {
return; return;
} }
okTitle.value = t('syncing');
disabled.value = true; disabled.value = true;
console.log("syncFromZentaoSubmit", console.log(selectedCases.value)); console.log("syncFromZentaoSubmit", console.log(selectedCases.value));
if (validate()) { if (validate()) {
...@@ -164,6 +169,7 @@ const submit = () => { ...@@ -164,6 +169,7 @@ const submit = () => {
}; };
const clearFormData = () => { const clearFormData = () => {
okTitle.value = t('confirm');
modelRef.value = {}; modelRef.value = {};
}; };
...@@ -178,14 +184,18 @@ const selectedCases = ref([] as number[]); ...@@ -178,14 +184,18 @@ const selectedCases = ref([] as number[]);
const cases = ref([]); const cases = ref([]);
const fetchCases = () => { const fetchCases = () => {
tableNotice.value = t('loading');
queryCase({ queryCase({
siteId: currSite.value.id, siteId: currSite.value.id,
productId: currProduct.value.id, productId: currProduct.value.id,
...modelRef.value, ...modelRef.value,
}).then((res) => { }).then((res) => {
tableNotice.value = t('empty_data');
res.data.forEach((item, index) => { res.data.forEach((item, index) => {
res.data[index].checked = true; res.data[index].checked = true;
selectedCases.value.push(item.Id); selectedCases.value.push(item.Id);
}, (err) => {
tableNotice.value = t('empty_data');
}); });
cases.value = res.data; cases.value = res.data;
}); });
...@@ -271,8 +281,6 @@ const setColumns = () => { ...@@ -271,8 +281,6 @@ const setColumns = () => {
}; };
setColumns(); setColumns();
const tableRef = ref({} as any);
const onCheckedRows = (rows: any[]) => { const onCheckedRows = (rows: any[]) => {
selectedCases.value = rows.map((item) => { selectedCases.value = rows.map((item) => {
return parseInt(item); return parseInt(item);
...@@ -282,4 +290,11 @@ const onCheckedRows = (rows: any[]) => { ...@@ -282,4 +290,11 @@ const onCheckedRows = (rows: any[]) => {
defineExpose({ defineExpose({
clearFormData, clearFormData,
}); });
</script> </script>
\ No newline at end of file
<style>
.table-sync-from-zentao{
overflow: auto;
max-height: 50vh;
}
</style>
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册