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

* Add command submit unit bug.

上级 d0e1397d
......@@ -2,19 +2,20 @@ package action
import (
"fmt"
"os"
"strconv"
"strings"
commConsts "github.com/easysoft/zentaoatf/internal/pkg/consts"
commDomain "github.com/easysoft/zentaoatf/internal/pkg/domain"
analysisHelper "github.com/easysoft/zentaoatf/internal/pkg/helper/analysis"
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"
logUtils "github.com/easysoft/zentaoatf/pkg/lib/log"
stdinUtils "github.com/easysoft/zentaoatf/pkg/lib/stdin"
stringUtils "github.com/easysoft/zentaoatf/pkg/lib/string"
"github.com/fatih/color"
"os"
"strconv"
"strings"
)
var (
......@@ -46,6 +47,13 @@ func CommitBug(files []string, productId int, noNeedConfirm bool) {
lines := make([]string, 0)
for _, cs := range report.FuncResult {
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)))
ids = append(ids, strconv.Itoa(cs.Id))
}
......@@ -83,8 +91,8 @@ func CommitBug(files []string, productId int, noNeedConfirm bool) {
}
}
func coloredStatus(status commConsts.ResultStatus) string {
temp := strings.ToLower(status.String())
func coloredStatus(status string) string {
temp := strings.ToLower(status)
switch temp {
case "pass":
......@@ -95,7 +103,7 @@ func coloredStatus(status commConsts.ResultStatus) string {
return color.YellowString(i118Utils.Sprintf(temp))
}
return status.String()
return status
}
func reportBug(resultDir string, caseId string, productId int) error {
......
......@@ -112,8 +112,9 @@ type ZtfStep struct {
}
type ZtfBug struct {
Title string `json:"title"`
Type string `json:"type"`
Title string `json:"title"`
Type string `json:"type"`
TestType commConsts.TestType `json:"testType"`
StepIds string `json:"ids"` // for to
......
......@@ -10,9 +10,11 @@ import (
commConsts "github.com/easysoft/zentaoatf/internal/pkg/consts"
commDomain "github.com/easysoft/zentaoatf/internal/pkg/domain"
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"
i118Utils "github.com/easysoft/zentaoatf/pkg/lib/i118"
logUtils "github.com/easysoft/zentaoatf/pkg/lib/log"
stdinUtils "github.com/easysoft/zentaoatf/pkg/lib/stdin"
"github.com/fatih/color"
"github.com/jinzhu/copier"
uuid "github.com/satori/go.uuid"
......@@ -26,6 +28,9 @@ func CommitBug(ztfBug commDomain.ZtfBug, config commDomain.WorkspaceConf) (err e
Login(config)
if ztfBug.TestType == commConsts.TestUnit {
return CommitUnitBug(&ztfBug, config)
}
ztfBug.Steps = strings.Replace(ztfBug.Steps, " ", " ", -1)
ztfBug.Steps = strings.Replace(ztfBug.Steps, "\n", "<br />", -1)
......@@ -45,6 +50,44 @@ func CommitBug(ztfBug commDomain.ZtfBug, config commDomain.WorkspaceConf) (err e
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) {
caseId, err := strconv.Atoi(caseIdStr)
......@@ -69,21 +112,23 @@ func PrepareBug(workspacePath, seq string, caseIdStr string, productId int) (bug
if step.Status == commConsts.FAIL {
stepIds += step.Id + "_"
}
stepIds = strings.Trim(stepIds, "_")
stepsContent := GenBugStepText(step)
steps = append(steps, stepsContent)
stepsArray = append(stepsArray, map[string]interface{}{
"name": step.Name,
"title": step.Name,
"status": step.Status,
"steps": stepsContent,
})
}
bug = commDomain.ZtfBug{
Title: cs.Title,
Case: cs.Id,
Product: productId,
Steps: strings.Join(steps, "\n"),
StepIds: stepIds,
Title: cs.Title,
TestType: "func",
Case: cs.Id,
Product: productId,
Steps: strings.Join(steps, "\n"),
StepIds: stepIds,
Uid: uuid.NewV4().String(),
Type: "codeerror", Severity: 3, Pri: 3, OpenedBuild: []string{"trunk"},
......@@ -96,6 +141,54 @@ func PrepareBug(workspacePath, seq string, caseIdStr string, productId int) (bug
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
}
......@@ -197,3 +290,25 @@ func LoadBugs(Product int, config commDomain.WorkspaceConf) (bugs []commDomain.Z
}
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
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) {
uri := fmt.Sprintf("/testcases/%d", caseId)
url := GenApiUrl(uri, nil, baseUrl)
......@@ -450,7 +498,9 @@ func GetCasesByTaskInDir(productId int, taskId int, workspacePath, scriptDir str
func ListCaseByProduct(baseUrl string, productId int) (casesResp commDomain.ZtfRespTestCases, err error) {
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)
if err != nil {
......
......@@ -666,6 +666,10 @@
{
"id": "must_provide_allure_report_dir",
"translation": "Please provide report dir if using Allure Report Framework."
},
{
"id": "bug_title",
"translation": "BUG Title"
}
]
}
......@@ -653,6 +653,10 @@
{
"id": "must_provide_allure_report_dir",
"translation": "使用Allure报表框架时,需要指定报告所在的目录。"
},
{
"id": "bug_title",
"translation": "缺陷标题"
}
]
}
......@@ -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)
emit("return-checked-rows", isChecked);
};
......
......@@ -10,6 +10,7 @@ export default {
'fullScreen': 'Toggle Fullscreen',
'help': 'Help',
'loading': 'Loading...',
'syncing': 'Syncing...',
'index': 'Index',
'no': 'NO.',
......
......@@ -11,6 +11,7 @@ export default {
'fullScreen': '切换全屏',
'help': '帮助',
'loading': '正在加载……',
'syncing': '同步中…',
'index': '索引',
'no': '编号',
......
......@@ -68,7 +68,7 @@
<div class="steps-contain">
<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" />
<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>
<textarea v-model="modelRef.steps" rows="6" />
</div>
......
......@@ -91,6 +91,13 @@
class="space-left rounded pure text-red"
: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>
</ListItem>
<div class="unit-result-info row gap-xl padding-bottom small">
......
......@@ -3,8 +3,9 @@
:showModal="showModalRef"
@onCancel="cancel"
@onOk="submit"
:okTitle="okTitle"
:title="t('sync-from-zentao')"
:contentStyle="{ width: '600px' }"
:contentStyle="{ width: '600px', overflow: 'hidden' }"
>
<Form>
<FormItem labelWidth="140px" :label="t('module')">
......@@ -58,8 +59,8 @@
:sortable="{}"
:hasCheckbox="true"
:isCheckAll="true"
ref="tableRef"
@return-checked-rows="onCheckedRows"
class="table-sync-from-zentao"
>
<template #Type="record">
{{ t('case_type_' + record.value.Type) }}
......@@ -69,7 +70,7 @@
</template>
</Table>
<p v-else class="empty-tip">
{{ t("empty_data") }}
{{ tableNotice }}
</p>
</Form>
</ZModal>
......@@ -110,6 +111,9 @@ const disabled = ref(false);
const props = withDefaults(defineProps<FormWorkspaceProps>(), {
show: false,
});
const okTitle = ref(t('confirm'))
const tableNotice = ref(t('loading'))
watch(props, () => {
if(!props.show) disabled.value = false;
modelRef.value.workspaceId = props.workspaceId;
......@@ -156,6 +160,7 @@ const submit = () => {
if(disabled.value) {
return;
}
okTitle.value = t('syncing');
disabled.value = true;
console.log("syncFromZentaoSubmit", console.log(selectedCases.value));
if (validate()) {
......@@ -164,6 +169,7 @@ const submit = () => {
};
const clearFormData = () => {
okTitle.value = t('confirm');
modelRef.value = {};
};
......@@ -178,14 +184,18 @@ const selectedCases = ref([] as number[]);
const cases = ref([]);
const fetchCases = () => {
tableNotice.value = t('loading');
queryCase({
siteId: currSite.value.id,
productId: currProduct.value.id,
...modelRef.value,
}).then((res) => {
tableNotice.value = t('empty_data');
res.data.forEach((item, index) => {
res.data[index].checked = true;
selectedCases.value.push(item.Id);
}, (err) => {
tableNotice.value = t('empty_data');
});
cases.value = res.data;
});
......@@ -271,8 +281,6 @@ const setColumns = () => {
};
setColumns();
const tableRef = ref({} as any);
const onCheckedRows = (rows: any[]) => {
selectedCases.value = rows.map((item) => {
return parseInt(item);
......@@ -282,4 +290,11 @@ const onCheckedRows = (rows: any[]) => {
defineExpose({
clearFormData,
});
</script>
\ No newline at end of file
</script>
<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.
先完成此消息的编辑!
想要评论请 注册