提交 5e5bad2c 编写于 作者: aaronchen2k2k's avatar aaronchen2k2k

sync from zentao

上级 4ddfc24c
......@@ -7,6 +7,7 @@ type SyncSettings struct {
ModuleId int `json:"moduleId"`
SuiteId int `json:"suiteId"`
TaskId int `json:"taskId"`
CaseId int `json:"caseId"`
Lang string `json:"lang"`
ByModule bool `json:"byModule"`
......
......@@ -15,7 +15,7 @@ import (
)
func GenerateScripts(cases []commDomain.ZtfCase, langType string, independentFile bool,
byModule bool, targetDir string) (int, error) {
byModule bool, targetDir string) (pths []string, err error) {
caseIds := make([]string, 0)
if commConsts.ExecFrom == commConsts.FromCmd { // from cmd
......@@ -25,16 +25,18 @@ func GenerateScripts(cases []commDomain.ZtfCase, langType string, independentFil
targetDir = fileUtils.AbsolutePath(targetDir)
for _, cs := range cases {
GenerateScript(cs, langType, independentFile, &caseIds, targetDir, byModule)
pth, _ := GenerateScript(cs, langType, independentFile, &caseIds, targetDir, byModule)
pths = append(pths, pth)
}
GenSuite(caseIds, targetDir)
return len(cases), nil
return
}
func GenerateScript(cs commDomain.ZtfCase, langType string, independentFile bool, caseIds *[]string,
targetDir string, byModule bool) {
targetDir string, byModule bool) (scriptPath string, err error) {
caseId := cs.Id
productId := cs.Product
moduleId := cs.Module
......@@ -48,9 +50,9 @@ func GenerateScript(cs commDomain.ZtfCase, langType string, independentFile bool
content := ""
isOldFormat := false
scriptFile := filepath.Join(targetDir, fmt.Sprintf("%d.%s", caseId, commConsts.LangMap[langType]["extName"]))
if fileUtils.FileExist(scriptFile) { // update title and steps
content = fileUtils.ReadFile(scriptFile)
scriptPath = filepath.Join(targetDir, fmt.Sprintf("%d.%s", caseId, commConsts.LangMap[langType]["extName"]))
if fileUtils.FileExist(scriptPath) { // update title and steps
content = fileUtils.ReadFile(scriptPath)
isOldFormat = strings.Index(content, "[esac]") > -1
}
......@@ -78,21 +80,23 @@ func GenerateScript(cs commDomain.ZtfCase, langType string, independentFile bool
info = append(info, strings.Join(steps, "\n"))
if independentFile {
expectFile := ScriptToExpectName(scriptFile)
expectFile := ScriptToExpectName(scriptPath)
fileUtils.WriteFile(expectFile, strings.Join(independentExpects, "\n"))
}
if fileUtils.FileExist(scriptFile) { // update title and steps
if fileUtils.FileExist(scriptPath) { // update title and steps
newContent := strings.Join(info, "\n")
ReplaceCaseDesc(newContent, scriptFile)
ReplaceCaseDesc(newContent, scriptPath)
return
}
path := fmt.Sprintf("res%stemplate%s", consts.FilePthSep, consts.FilePthSep)
template, _ := resUtils.ReadRes(path + langType + ".tpl")
templatePath := fmt.Sprintf("res%stemplate%s", consts.FilePthSep, consts.FilePthSep)
template, _ := resUtils.ReadRes(templatePath + langType + ".tpl")
out := fmt.Sprintf(string(template), strings.Join(info, "\n"), srcCode)
fileUtils.WriteFile(scriptFile, out)
fileUtils.WriteFile(scriptPath, out)
return
}
func generateTestStepAndScriptObsolete(testSteps []commDomain.ZtfStep, steps *[]string, independentExpects *[]string, independentFile bool) {
......
......@@ -67,7 +67,7 @@ func CommitCase(caseId int, title string,
return
}
func GetCaseById(baseUrl string, caseId int) (cs commDomain.ZtfCase) {
func GetCaseById(baseUrl string, caseId int) (cs commDomain.ZtfCase, err error) {
uri := fmt.Sprintf("/testcases/%d", caseId)
url := GenApiUrl(uri, nil, baseUrl)
......@@ -208,15 +208,26 @@ func LoadTestCaseDetail(productId, moduleId, suiteId, taskId int,
for _, cs := range casesResp.Cases {
caseId := cs.Id
csWithSteps := GetCaseById(config.Url, caseId)
stepArr := genCaseSteps(csWithSteps)
cases = append(cases, commDomain.ZtfCase{Id: caseId, Product: cs.Product, Module: cs.Module,
Title: cs.Title, Steps: stepArr})
cs, err := GetTestCaseDetail(caseId, config)
if err != nil {
continue
}
cases = append(cases, cs)
}
return
}
func GetTestCaseDetail(caseId int, config commDomain.WorkspaceConf) (cs commDomain.ZtfCase, err error) {
csWithSteps, err := GetCaseById(config.Url, caseId)
stepArr := genCaseSteps(csWithSteps)
cs = commDomain.ZtfCase{Id: caseId, Product: cs.Product, Module: cs.Module,
Title: cs.Title, Steps: stepArr}
return
}
func GetCaseIdsInZentaoModule(productId, moduleId uint, config commDomain.WorkspaceConf) (
caseIdMap map[int]string, err error) {
......
......@@ -12,36 +12,52 @@ import (
"path/filepath"
)
func SyncFromZentao(settings commDomain.SyncSettings, config commDomain.WorkspaceConf, workspacePath string) (err error) {
func SyncFromZentao(settings commDomain.SyncSettings, config commDomain.WorkspaceConf, workspacePath string) (
pths []string, err error) {
productId := settings.ProductId
moduleId := settings.ModuleId
suiteId := settings.SuiteId
taskId := settings.TaskId
caseId := settings.CaseId
byModule := settings.ByModule
independentFile := settings.IndependentFile
lang := settings.Lang
lang := "php" // settings.Lang
ok := langHelper.CheckSupportLanguages(lang)
if !ok {
return
}
cases, err := LoadTestCaseDetail(productId, moduleId, suiteId, taskId, config)
cases := make([]commDomain.ZtfCase, 0)
if caseId != 0 {
cs, err := GetTestCaseDetail(caseId, config)
if err == nil {
cases = append(cases, cs)
}
} else {
cases, err = LoadTestCaseDetail(productId, moduleId, suiteId, taskId, config)
}
if err != nil {
return
}
if cases != nil && len(cases) > 0 {
if cases == nil || len(cases) == 0 {
return
}
if productId == 0 {
productId = cases[0].Product
targetDir := fileUtils.AddFilePathSepIfNeeded(filepath.Join(workspacePath, fmt.Sprintf("product%d", productId)))
}
targetDir := fileUtils.AddFilePathSepIfNeeded(filepath.Join(workspacePath, fmt.Sprintf("product%d", productId)))
count, err := scriptHelper.GenerateScripts(cases, lang, independentFile, byModule, targetDir)
if err == nil {
logUtils.Infof(i118Utils.Sprintf("success_to_generate", count, targetDir))
} else {
logUtils.Infof(color.RedString(err.Error()))
}
pths, err = scriptHelper.GenerateScripts(cases, lang, independentFile, byModule, targetDir)
if err == nil {
logUtils.Infof(i118Utils.Sprintf("success_to_generate", len(pths), targetDir))
} else {
logUtils.Infof(color.RedString(err.Error()))
}
return
......
......@@ -82,8 +82,8 @@ func Login(config commDomain.WorkspaceConf) (err error) {
}
func ListLang() (langs []serverDomain.ZentaoLang, err error) {
for key, _ := range commConsts.LangMap {
langs = append(langs, serverDomain.ZentaoLang{Code: key, Name: key})
for key, mp := range commConsts.LangMap {
langs = append(langs, serverDomain.ZentaoLang{Code: key, Name: mp["name"]})
}
return
......
......@@ -128,13 +128,16 @@ func (c *TestScriptCtrl) SyncFromZentao(ctx iris.Context) {
workspace, _ := c.WorkspaceService.Get(uint(syncSettings.WorkspaceId))
syncSettings.ProductId = currProductId
err = zentaoHelper.SyncFromZentao(syncSettings, config, workspace.Path)
if syncSettings.Lang == "" {
syncSettings.Lang = workspace.Lang
}
pths, err := zentaoHelper.SyncFromZentao(syncSettings, config, workspace.Path)
if err != nil {
ctx.JSON(c.ErrResp(commConsts.CommErr, err.Error()))
return
}
ctx.JSON(c.SuccessResp(nil))
ctx.JSON(c.SuccessResp(pths))
}
func (c *TestScriptCtrl) SyncToZentao(ctx iris.Context) {
......
......@@ -9,6 +9,7 @@ type Workspace struct {
Name string `json:"name"`
Desc string `json:"desc" gorm:"column:descr"`
Type commConsts.TestTool `json:"type" gorm:"default:ztf"`
Lang string `json:"lang"`
Cmd string `json:"cmd"`
SiteId uint `json:"siteId"`
......
......@@ -92,6 +92,7 @@ export default defineComponent({
const store = useStore<{ Zentao: ZentaoData }>();
const profile = computed<any[]>(() => store.state.Zentao.profile);
store.dispatch('Zentao/getProfile');
store.dispatch('Zentao/fetchLangs')
const { topNavEnable } = toRefs(props);
......
......@@ -87,6 +87,7 @@ export default {
'suite': 'Suite',
'task': 'Task',
'lang': 'Language',
'default_lang': 'Default Language',
'independent_by_module': 'Save Script By Module',
'independent_expect': 'Save Expect Result in Independent File.',
......@@ -166,6 +167,7 @@ export default {
'checkout_case': 'Checkout Cases',
'checkin_case': 'Checkin Cases',
'exec_selected': 'Exec Selected',
'script_file_not_exist': 'No script file for this case, you may Checkout Zentao TestCase to create.',
'show_result_log': 'Show Result Logs',
'show_exec_log': 'Show Exec Logs',
......
......@@ -86,6 +86,7 @@ export default {
'suite': '套件',
'task': '任务',
'lang': '语言',
'default_lang': '默认语言',
'independent_by_module': '按模块组织用例',
'independent_expect': '期待结果为独立文件',
......@@ -165,6 +166,7 @@ export default {
'checkout_case': '导出禅道用例',
'checkin_case': '更新禅道用例',
'exec_selected': '执行选中',
'script_file_not_exist': '该禅道用例未有对应的脚本文件,可使用导出禅道用例功能创建。',
'show_result_log': '显示结果日志',
'show_exec_log': '显示执行日志',
......
......@@ -5,8 +5,6 @@ import {queryLang, querySiteAndProduct, getProfile, queryProduct, queryModule, q
import {setCurrProductIdBySite, setCurrSiteId} from "@/utils/cache";
import {notification} from "ant-design-vue";
export interface ZentaoData {
langs: any[]
......
export const EventNodeId = 'deeptest-event-node'
export const EventName = 'deeptest-event-from-chrome'
export const ScopeDeeptest = 'scope-com-deeptest'
export const ScriptFileNotExist = 'script_file_not_exist'
export const ScriptLanguages = [
'Python',
......
......@@ -2,10 +2,13 @@
<a-form :label-col="labelCol" :wrapper-col="wrapperCol">
<a-form-item :label="t('workspace')" v-bind="validateInfosFrom.workspaceId">
<a-select v-model:value="model.workspaceId">
<a-select v-model:value="model.workspaceId" @change="selectWorkspace">
<a-select-option key="" value="">&nbsp;</a-select-option>
<a-select-option v-for="item in workspaces" :key="item.id" :value="item.id"><span v-html="item.name"></span>
</a-select-option>
<template v-for="item in workspaces">
<a-select-option v-if="item.type === 'ztf'" :key="item.id" :value="item.id">
<span v-html="item.name"></span>
</a-select-option>
</template>
</a-select>
</a-form-item>
......@@ -65,6 +68,8 @@ import {useRouter} from "vue-router";
import {WorkspaceData} from "../../workspace/store";
import {syncFromZentao} from "@/views/script/service";
import {isWindows} from "@/utils/comm";
import {get as getWorkspace} from "@/views/workspace/service";
import {ScriptData} from "@/views/script/store";
const useForm = Form.useForm;
......@@ -84,6 +89,7 @@ export default defineComponent({
const workspaceStore = useStore<{ Workspace: WorkspaceData }>();
const zentaoStore = useStore<{ Zentao: ZentaoData }>();
const scriptStore = useStore<{ Script: ScriptData }>();
const currSite = computed<any>(() => zentaoStore.state.Zentao.currSite);
const currProduct = computed<any>(() => zentaoStore.state.Zentao.currProduct);
......@@ -124,28 +130,38 @@ export default defineComponent({
const validateFrom = syncFromForm.validate
const validateInfosFrom = syncFromForm.validateInfos
const selectWorkspace = () => {
console.log('selectWorkspace')
getWorkspace(parseInt(model.value.workspaceId)).then((json) => {
if (json.code === 0) {
model.value.lang = json.data.lang
}
})
}
const syncFromZentaoSubmit = () => {
console.log('syncFromZentaoSubmit')
validateFrom()
.then(() => {
syncFromZentao(model).then((json) => {
console.log('json', json)
if (json.code === 0) {
notification.success({
message: t('sync_success'),
});
} else {
notification.error({
message: t('sync_fail'),
description: json.msg,
});
}
})
})
.catch(err => {
console.log('validate fail', err)
});
.then(() => {
scriptStore.dispatch('Script/syncFromZentao', model.value).then((resp => {
if (resp.code === 0) {
notification.success({
message: t('sync_success'),
});
props.onClose()
} else {
notification.error({
message: t('sync_fail'),
description: resp.data.msg,
});
}
}))
})
.catch(err => {
console.log('validate fail', err)
});
};
return {
......@@ -167,6 +183,7 @@ export default defineComponent({
suites,
tasks,
selectWorkspace,
syncFromZentaoSubmit,
simpleImage: Empty.PRESENTED_IMAGE_SIMPLE,
......
......@@ -208,7 +208,7 @@ export default defineComponent({
let filerItems = ref([] as any)
const loadScripts = async () => {
console.log(`---------------- loadScripts should be executed only once`)
console.log(`loadScripts should be executed only once`)
console.log(`filerType: ${filerType.value}, filerValue: ${filerValue.value}`)
const params = {filerType: filerType.value, filerValue: filerValue.value} as any
......@@ -346,7 +346,6 @@ export default defineComponent({
const onSave = async () => {
console.log('onSave')
fromVisible.value = false
loadScripts()
}
const onCancel = async () => {
console.log('onCancel')
......
......@@ -2,14 +2,15 @@
<div class="ztf-script-main">
<div class="toolbar" v-if="scriptCode !== ''">
<a-button :disabled="isRunning === 'true'" @click="execSingle" type="primary" class="t-btn-gap">
<a-button v-if="scriptCode !== ScriptFileNotExist && isRunning !== 'true'" @click="execSingle" type="primary" class="t-btn-gap">
{{ t('exec') }}
</a-button>
<a-button v-if="isRunning === 'true'" @click="execStop" class="t-btn-gap">{{ t('stop') }}</a-button>
<a-button @click="extract" type="primary">{{ t('extract_step') }}</a-button>
<a-button v-if="scriptCode === ScriptFileNotExist" @click="checkout" type="primary">{{ t('checkout_case') }}</a-button>
<a-button v-if="scriptCode !== ScriptFileNotExist" @click="extract" type="primary">{{ t('extract_step') }}</a-button>
<a-button @click="save" type="primary">{{ t('save') }}</a-button>
<a-button v-if="scriptCode !== ScriptFileNotExist" @click="save" :disabled="scriptCode === ScriptFileNotExist" type="primary">{{ t('save') }}</a-button>
</div>
<div id="right-content" class="right-content">
......@@ -19,13 +20,17 @@
<a-tabs :animated="true">
<a-tab-pane key="1" tab="脚本1">
<MonacoEditor
v-if="scriptCode !== ''"
v-if="scriptCode !== '' && scriptCode !== ScriptFileNotExist"
v-model:value="scriptCode"
:language="lang"
:options="editorOptions"
class="editor"
ref="editorRef"
/>
<div v-if="scriptCode === ScriptFileNotExist" :class="ScriptFileNotExist">
{{t(ScriptFileNotExist)}}
</div>
</a-tab-pane>
<a-tab-pane key="2" tab="脚本2" :forceRender="true">
<MonacoEditor
......@@ -79,7 +84,7 @@ import {ScriptData} from "../store";
import {resizeHeight, resizeWidth} from "@/utils/dom";
import {Empty, notification} from "ant-design-vue";
import {MonacoOptions} from "@/utils/const";
import {MonacoOptions, ScriptFileNotExist} from "@/utils/const";
import bus from "@/utils/eventBus"
import MonacoEditor from "@/components/Editor/MonacoEditor.vue";
import {ZentaoData} from "@/store/zentao";
......@@ -87,6 +92,7 @@ import {ZentaoData} from "@/store/zentao";
import ScriptExecLogPage from "./execLog.vue";
import settings from "@/config/settings";
import {ExecStatus} from "@/store/exec";
import {syncFromZentao} from "@/views/script/service";
export default defineComponent({
name: 'ZtfScriptPage',
......@@ -121,6 +127,13 @@ export default defineComponent({
console.log('watch script', script)
if (script.value) {
if (script.value.code === ScriptFileNotExist) {
scriptCode.value = ScriptFileNotExist
lang.value = ''
return
}
scriptCode.value = script.value.code ? script.value.code : t('empty')
lang.value = script.value.lang
......@@ -158,6 +171,24 @@ export default defineComponent({
bus.emit(settings.eventExec, data);
}
const checkout = () => {
console.log('checkout', script.value)
const data = {caseId: script.value.id, workspaceId: script.value.workspaceId}
scriptStore.dispatch('Script/syncFromZentao', data).then((resp => {
if (resp.code === 0) {
notification.success({
message: t('sync_success'),
});
} else {
notification.error({
message: t('sync_fail'),
description: resp.data.msg,
});
}
}))
}
const extract = () => {
console.log('extract', script.value)
......@@ -209,11 +240,13 @@ export default defineComponent({
isRunning,
execSingle,
execStop,
checkout,
extract,
stop,
showLogPanel,
editorRef,
ScriptFileNotExist,
}
}
......@@ -222,6 +255,10 @@ export default defineComponent({
<style lang="less">
#editor-panel {
.script_file_not_exist {
padding: 10px;
}
.ant-tabs {
height: 100%;
overflow: hidden;
......
......@@ -3,14 +3,16 @@ import { StoreModuleType } from "@/utils/store";
import { ResponseData } from '@/utils/request';
import {
list, get, extract, create, update, remove, loadChildren, updateCode
list, get, extract, create, update, remove, loadChildren, updateCode, syncFromZentao
} from './service';
import {ScriptFileNotExist} from "@/utils/const";
export interface ScriptData {
list: [];
detail: any;
currWorkspace: any
queryParams: any;
}
export interface ModuleType extends StoreModuleType<ScriptData> {
......@@ -19,11 +21,13 @@ export interface ModuleType extends StoreModuleType<ScriptData> {
setList: Mutation<ScriptData>;
setItem: Mutation<ScriptData>;
setWorkspace: Mutation<ScriptData>;
setQueryParams: Mutation<ScriptData>;
};
actions: {
listScript: Action<ScriptData, ScriptData>;
getScript: Action<ScriptData, ScriptData>;
loadChildren: Action<ScriptData, ScriptData>;
syncFromZentao: Action<ScriptData, ScriptData>;
extractScript: Action<ScriptData, ScriptData>;
changeWorkspace: Action<ScriptData, ScriptData>;
......@@ -37,7 +41,8 @@ const initState: ScriptData = {
list: [],
detail: null,
currWorkspace: {id: 0, type: 'ztf'}
currWorkspace: {id: 0, type: 'ztf'},
queryParams: {},
};
const StoreModel: ModuleType = {
......@@ -56,12 +61,17 @@ const StoreModel: ModuleType = {
setWorkspace(state, payload) {
state.currWorkspace = payload;
},
setQueryParams(state, payload) {
state.queryParams = payload;
},
},
actions: {
async listScript({ commit }, playload: any ) {
const response: ResponseData = await list(playload);
const { data } = response;
commit('setList', [data]);
commit('setQueryParams', playload);
return true;
},
async loadChildren({ commit }, treeNode: any ) {
......@@ -81,12 +91,32 @@ const StoreModel: ModuleType = {
return true;
}
if (script.path.indexOf('zentao-') === 0) {
commit('setItem', {id: script.caseId, workspaceId: script.workspaceId, code: ScriptFileNotExist});
return true;
}
const response: ResponseData = await get(script.path, script.workspaceId);
const { data } = response;
commit('setItem', data);
commit('setItem', response.data);
return true;
},
async syncFromZentao({ commit }, payload: any ) {
const resp = await syncFromZentao(payload)
if (resp.code === 0) {
this.dispatch('Script/listScript', this.state['Script'].queryParams)
if (resp.code === 0 && resp.data.length === 1) {
const getResp = await get(resp.data[0], payload.workspaceId);
commit('setItem', getResp.data);
} else {
commit('setItem', null);
}
}
return resp
},
async extractScript({ commit }, script: any ) {
if (!script.path) return true
......@@ -124,7 +154,6 @@ const StoreModel: ModuleType = {
}
},
async updateCode({ commit }, payload: any ) {
try {
await updateCode(payload);
......
......@@ -36,6 +36,13 @@
</a-select>
</a-form-item>
<a-form-item v-if="modelRef.type === 'ztf'" :label="t('default_lang')" v-bind="validateInfos.lang">
<a-select v-model:value="modelRef.lang">
<a-select-option key="" value=""></a-select-option>
<a-select-option v-for="item in langs" :key="item.code" :value="item.code">{{ item.name }}</a-select-option>
</a-select>
</a-form-item>
<a-form-item v-if="showCmd" :label="t('test_cmd')" v-bind="validateInfos.cmd">
<a-textarea v-model:value="modelRef.cmd" :auto-size="{ minRows: 3, maxRows: 6 }" />
<div class="t-tips" style="margin-top: 5px;">
......@@ -79,10 +86,12 @@ export default defineComponent({
const testTypes = ref([...ztfTestTypesDef, ...unitTestTypesDef])
const cmdMap = ref(arrToMap(testTypes.value))
const isElectron = ref(!!window.require)
const cmdSample = ref('')
const zentaoStore = useStore<{ Zentao: ZentaoData }>();
const langs = computed<any[]>(() => zentaoStore.state.Zentao.langs);
const store = useStore<{ Workspace: WorkspaceData }>();
const modelRef = computed(() => store.state.Workspace.detailResult);
const showCmd = computed(() => { return modelRef.value.type !== 'ztf' })
......@@ -98,6 +107,7 @@ export default defineComponent({
name: [{ required: true, message: t('pls_name'), trigger: 'blur' }],
path: [{ required: true, message: t('pls_workspace_path'), trigger: 'change' }],
type: [{ required: true, message: t('pls_workspace_type'), trigger: 'blur' }],
lang: [{ required: true, message: t('pls_input_lang'), trigger: 'blur' }],
cmd: [
{
trigger: 'blur',
......@@ -155,6 +165,7 @@ export default defineComponent({
t,
isElectron,
cmdSample,
langs,
testTypes,
cmdMap,
showCmd,
......
......@@ -21,9 +21,9 @@ export async function listByProduct(productId: number): Promise<any> {
});
}
export async function get(seq: number): Promise<any> {
export async function get(id: number): Promise<any> {
return request({
url: `/${apiPath}/${seq}`
url: `/${apiPath}/${id}`
});
}
......
......@@ -89,7 +89,7 @@ const StoreModel: ModuleType = {
}
},
async get({ commit }, id: number ) {
let data = {name:'', path: '', type: 'ztf'}
let data = {name:'', path: '', type: 'ztf', lang: ''}
if (id) {
const response: ResponseData = await get(id);
data = response.data;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册