cli-z-develop 0.8.5 → 0.8.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{program as e}from"commander";import t from"node:child_process";import n from"node:fs";import i from"node:path";import a,{AxiosError as r}from"axios";import s from"chalk";import o from"dayjs";import c from"shelljs";import l from"node:os";import u from"child_process";import{confirm as p,select as m,input as d,password as f,checkbox as g}from"@inquirer/prompts";import h from"ora";import y from"fs-extra";import{select as w}from"inquirer-select-pro";import v from"lint-staged";import $ from"semver";import{run as b}from"npm-check-updates";import S from"fs/promises";import j from"path";import E from"minimist";var k,A,T;!function(e){e.DEV="dev",e.TEST="test",e.RELEASE="release",e.PROD="production"}(k||(k={})),function(e){e.DEV="dev",e.TEST="test",e.RELEASE="release",e.MASTER="master"}(A||(A={})),function(e){e.H5="h5",e.NPM="npm",e.SERVER="server"}(T||(T={}));const x=[{name:`开发环境 - ${k.DEV}`,value:k.DEV},{name:`测试环境 - ${k.TEST}`,value:k.TEST},{name:`预发环境 - ${k.RELEASE}`,value:k.RELEASE},{name:`正式环境 - ${k.PROD}`,value:k.PROD}],N=[{name:`网页 - ${T.H5}`,value:T.H5},{name:`依赖包 - ${T.NPM}`,value:T.NPM},{name:`服务端 - ${T.SERVER}`,value:T.SERVER}];var C,D,R;!function(e){e.FEAT="feat",e.FIX="fix",e.REFACTOR="refactor"}(C||(C={})),function(e){e.FRONT_END="fe",e.BACK_END="be",e.QUALITY_ASSURANCE="qa"}(D||(D={})),function(e){e.JAVA="Java",e.JAVASCRIPT="JavaScript",e.PYTHON="Python"}(R||(R={}));const O={1:"研发",2:"测试",3:"产品",4:"设计",5:"运营",6:"销售",7:"行政",8:"财务",9:"其他"},F="http://git.cxlqd.com",M=["fe-biz","fe-base","fe-tpl","fe-component","fe-demo"];var z;!function(e){e.FEAT="feat",e.FIX="fix",e.REFACTOR="refactor",e.CHORE="chore",e.CI="ci",e.Break="BREAKING CHANGE"}(z||(z={}));const P="fe-biz7tvsd",I="https://hxhtbr8t8uy.feishu.cn/wiki/LWW5wAQFPiXkmRkKcjOcyDDknLg";var B;!function(e){e.MODULE="module",e.CASE="case"}(B||(B={}));const _=[{name:"拉取远程模块(包含产品)",value:B.MODULE},{name:"拉取远程用例",value:B.CASE}],L=[{name:"创建模块",value:B.MODULE},{name:"创建用例",value:B.CASE}],U=".z",W="develop-config.json",J=".z",V=".commit-msg-tpl",q="project.json";function H(e=""){return i.join(J,e)}function G(){return H(q)}function K(){return H(V)}function Q(){u.spawnSync("git",["config","core.hooksPath",H()]),u.spawnSync("git",["config","commit.template",K()])}function Y(e=""){return i.resolve(l.homedir(),U,e)}function X(){return Y(W)}function Z(){return n.existsSync(Y())&&n.existsSync(X())}function ee(e){return encodeURIComponent(e.replace(`${F}/`,"").replace(/\.git$/,""))}const{red:te,green:ne,blue:ie,magenta:ae}=s;function re(...e){console.log(ne(...e))}function se(e){e instanceof Error&&("ExitPromptError"===e.name||e.message.includes("User force closed the prompt with"))&&(console.log(),console.log(s.cyan(" 👋 下次见~")),console.log(),process.exit(1))}function oe(e,t=!1){se(e);let n=e;e instanceof Error?(n=e.message,a.isAxiosError(e)&&(n=`请求失败:${e.message}`),console.log(te(n)),console.log(ae(e.stack))):console.log(te(e)),t||process.exit(1)}function ce(e){return!!n.existsSync(e)&&n.lstatSync(e).isDirectory()}function le(e=process.cwd()){if(ce(e)){return n.readdirSync(e).filter((t=>ce(i.resolve(e,t))))}return[]}async function ue(e,t={removeTailLinkBreak:!0,silent:!0}){let n=await new Promise(((n,i)=>{try{n(c.exec(e,{silent:t.silent}))}catch(e){i(e)}}));return n=n.toString(),t.removeTailLinkBreak&&(n=n.replace(/\n$/,"")),n}function pe(e){t.execSync(e,{stdio:"inherit"})}function me(){return o(Date.now()).format("YYMMDD")}function de(){n.existsSync(H())||oe("当前不在项目根目录。请切换到项目根目录")}function fe(){n.existsSync(i.resolve(".git"))||oe("当前不是git项目根目录,请先执行git init,或切换到根目录")}async function ge(){""!==await ue("git status -s")&&oe("请先提交代码变动,再进行操作")}async function he(e,...t){try{await e(...t)}catch(e){throw se(e),e}}const ye='{\n "printWidth": 120,\n "tabWidth": 2,\n "useTabs": false,\n "semi": true,\n "singleQuote": false,\n "quoteProps": "as-needed",\n "jsxSingleQuote": false,\n "trailingComma": "all",\n "bracketSpacing": true,\n "bracketSameLine": false,\n "arrowParens": "always",\n "requirePragma": false,\n "insertPragma": false,\n "proseWrap": "preserve",\n "htmlWhitespaceSensitivity": "css",\n "vueIndentScriptAndStyle": false,\n "endOfLine": "lf",\n "embeddedLanguageFormatting": "auto",\n "singleAttributePerLine": false\n}\n',we="# 系统 信息文件\n.DS_Store/\nThumbs.db\n\n# 编辑器配置文件\n.idea/\n.vscode/\n\n# 输出目录\ndist/\n\n# Log files\n*.log\n\n# 本地配置文件\n*.local\n\n# 缓存文件\n*.cache\n\n# 垃圾文件\n.Trashes\n",ve={[R.JAVA]:{"**/*.{java}":"echo 'todo'"},[R.JAVASCRIPT]:{"**/*.{vue,js,jsx,cjs,mjs,ts,tsx,cts,mts}":"eslint --fix","*":"prettier -wu"},[R.PYTHON]:{"**/*.{py}":"echo 'todo'"}},$e='\n[\n {\n "Precondition": "前置条件",\n "Title": "用例名称",\n "URL": "接口地址",\n "Data": "接口入参",\n "Method": "接口类型",\n "Expected": "期望结果"\n }\n]\n',be="# from assets";var Se={name:"cli-z-develop",version:"0.8.5",description:"前端本地开发命令行工具",main:"dist/index.js",bin:{z:"bin/z.js","z-develop":"bin/z.js"},scripts:{prepare:"[ -n '$z' ] && z init prepare || echo 'Warning: z not exist at global'",dev:"rollup -c -w --environment DEBUG:true",build:"rollup -c",eslint:"eslint '**/*.{ts,js}' --fix",prettier:"prettier -wu .",upload:"npm run build && npm publish --access public --registry https://registry.npmjs.org/","upload:patch":"npm version patch && npm run upload","upload:minor":"npm version minor && npm run upload","upload:major":"npm version major && npm run upload"},type:"module",author:"z",devDependencies:{"@lonely9/eslint-config-team":"^1.3.5","@rollup/plugin-json":"^6.1.0","@rollup/plugin-node-resolve":"^16.0.3","@rollup/plugin-replace":"v6.0.3","@rollup/plugin-terser":"^0.4.4","@tsconfig/node22":"^22.0.5","@types/fs-extra":"^11.0.4","@types/inquirer":"^9.0.9","@types/minimist":"^1.2.5","@types/node":"^22.15.29","@types/semver":"^7.7.1","@types/shelljs":"^0.10.0","@typescript-eslint/eslint-plugin":"^8.53.0","@typescript-eslint/parser":"^8.53.0",eslint:"^9.39.2",jiti:"^2.6.1",prettier:"^3.7.4",rollup:"^4.55.1","rollup-plugin-typescript2":"^0.36.0",typescript:"^5.9.3","vue-tsc":"^3.2.2"},dependencies:{"@inquirer/prompts":"^8.2.0",axios:"^1.13.2",chalk:"^5.6.2",commander:"^14.0.2",dayjs:"^1.11.19","fs-extra":"^11.3.3","inquirer-select-pro":"^1.0.0-alpha.9","lint-staged":"^16.2.7",minimist:"^1.2.8","npm-check-updates":"^19.3.1",ora:"^9.0.0",semver:"^7.7.3",shelljs:"^0.10.0"}};const je={profile:{ldapAccount:"",ldapPassword:"",gitToken:"",gitUserId:0,gitName:"",gitEnglishName:"",gitEmail:"",weWorkName:"",weWorkUserId:"",jobType:D.FRONT_END,zenTaoToken:"",k8sToken:""},main:{version:Se.version,latestCheckVersionTimestamp:0,versionCheckDuring:3,weWorkListCache:[]},constants:{ZenTaoDomain:"",K8sDomain:"",FEServerDomain:"",K8SWebDomain:""}};function Ee(e){return e?je.profile[e]:je.profile}function ke(e){return e?je.main[e]:je.main}function Ae(e){return e?je.constants[e]:je.constants}let Te=null,xe=null;function Ne(){if(Te)return Te;const e=i.join("package.json");return n.existsSync(e)||oe(`当前目录(${c.pwd()})不存在${e}文件,请在项目根目录执行该命令。`),Te=y.readJsonSync(e),Te}function Ce(){if(xe)return xe;const e=G();return n.existsSync(e)||oe(`当前目录(${c.pwd()})不存在${e}文件,请在项目根目录执行该命令,或者初始化项目(z init .)。`),xe=y.readJsonSync(e),xe}const De={id:0,path:"",group:"",sourceBranch:"",mergeRequestUrl:""};async function Re(){if(!De.id)try{const e=ee(Ce().repository.url),t=await He(e);De.id=t.id,De.path=e,De.group=t.namespace.full_path,De.mergeRequestUrl=`${t.web_url}/merge_requests`}catch(e){oe(e)}return De.sourceBranch||(De.sourceBranch=await ue("git branch --show-current")),De}function Oe(){y.writeJSONSync(X(),{main:ke(),profile:Ee(),constants:Ae()},{spaces:2})}function Fe(e,t){void 0!==t?je.profile[e]=t:je.profile={...je.profile,...e}}function Me(e,t){je.constants={...je.constants,...e}}function ze(e,t){void 0!==t?je.main[e]=t:je.main={...je.main,...e}}async function Pe(e){const t=e.method||"get",n=e.headers||{},i=e.data||{},o=e.dataKey||["GET","get"].includes(t)?"params":"data";try{const r={url:e.url,method:t,[o]:i,headers:n};s.magenta(r.method.toUpperCase()),s.yellow(r.url),JSON.stringify(r.headers),s.gray(JSON.stringify(r[o],null,2));const c=await a(r);return s.green("Response"),s.grey(JSON.stringify(c.data,null,2)),Promise.resolve(c.data)}catch(e){return e instanceof r&&(s.red("Error"),s.grey(JSON.stringify(e?.response?.data))),Promise.reject(e)}}async function Ie(){const e=Ee("gitToken");if(e)return e;{const{access_token:e}=await Pe({url:`${F}/oauth/token`,method:"post",data:{grant_type:"password",username:Ee("ldapAccount"),password:Ee("ldapPassword")}}),t=`Bearer ${e}`;return Fe("gitToken",t),Oe(),t}}async function Be(e){return Pe({...e,headers:{Authorization:await Ie()}})}async function _e(){const e=Ee("zenTaoToken");if(e)return e;{const{token:e}=await Pe({url:`${Ae("ZenTaoDomain")}/api.php/v1/tokens`,method:"post",data:{account:Ee("ldapAccount"),password:Ee("ldapPassword")}});return Fe("zenTaoToken",e),Oe(),e}}async function Le(e){const t=await Pe({...e,headers:{Token:await _e()}});if(!e.url.includes("local")){const{status:n,data:i}=t;if("success"===n){const t=JSON.parse(i);return"用户登录"===t.title?(Fe("zenTaoToken",""),Le({...e})):t}return{}}if("string"==typeof t){const e=JSON.parse(t.slice(0,t.indexOf("<script>")));return JSON.parse(e.data)}if("object"==typeof t)return"Unauthorized"===t.error||t.data.indexOf("<script>")<0?(Fe("zenTaoToken",""),Le({...e})):t}async function Ue(){const e=Ee("k8sToken");if(e)return e;{const{access_token:e}=await Pe({url:`${Ae("K8sDomain")}/oauth/login/LDAP`,method:"post",headers:{"Content-Type":"application/x-www-form-urlencoded"},data:{username:Ee("ldapAccount"),password:Ee("ldapPassword")}}),t=`Bearer ${e}`;return Fe("k8sToken",t),Oe(),t}}async function We(e){const t=await Pe({...e,headers:{Authorization:await Ue()}});return 401===t.code?(Fe("k8sToken",""),We({...e})):t}const Je=()=>`${F}/api/v4`,Ve=e=>`${Je()}/projects/100/repository/files/${encodeURIComponent(e)}/raw?ref=master`;function qe(){return Be({url:Ve("src/data/z-develop-config.json")})}function He(e){return Be({url:`${Je()}/projects/${e}`})}async function Ge(){const e=await Be({url:`${Je()}/groups`}),t=M.map((t=>{const n=e.find((e=>e.name===t));return!!n&&{name:n.name,id:n.id,description:n.description}})).filter((e=>Boolean(e)));y.writeJSONSync(Y("fe-groups.json"),{groups:t},{spaces:2})}async function Ke(e){const t=`${Ae("FEServerDomain")}/api`,{data:n}=await Pe({url:`${t}/auth/z-develop/login`,method:"post"}),i=await Pe({url:t+e.url,headers:{Authorization:`Bearer ${n}`},data:e.data,method:e.method||"post"});return 0!==i.code&&oe(`${i.code}: ${i.message}`),i.data}function Qe(e){return Ke({url:"/zen/testcase/product/auto-case/module/list",data:{product:e}})}async function Ye(){const e=(await Ke({url:"/user/list2"})).filter((e=>[1,2,3,4,5].includes(e.title))).map((e=>({name:`${e.nick} - ${O[e.title]}`,value:e.weWorkUserId}))),t=ke("weWorkListCache"),n=t.map((e=>e.value)),i=[];return e.forEach((e=>{const a=n.indexOf(e.value);i.push({...e,usageCount:a>-1?t[a].usageCount:0})})),i.sort(((e,t)=>t.usageCount-e.usageCount))}async function Xe(e,t,n){const i=await Ye();let a=await w({message:e,loop:!0,pageSize:i.length||5,clearInputWhenSelected:!0,multiple:n,options:e=>e?i.filter((t=>t.name.includes(e))):i,validate:t});return a=Array.isArray(a)?a:[a],function(e,t){const n=[];t.forEach((t=>{e.includes(t.value)&&n.push(t)}));const i=ke("weWorkListCache"),a=i.map((e=>e.value));n.forEach((e=>{const t=a.indexOf(e.value);t>-1?i[t].usageCount+=1:i.push({...e,usageCount:1})})),ze({weWorkListCache:i.sort(((e,t)=>t.usageCount-e.usageCount))}),Oe()}(a,i),a}async function Ze(e,t,n){const{groups:i}=await Be({url:Ve("src/data/project-group-chats.json")}),a=i.map((e=>({name:e.name,value:e.url})));let r=await w({message:e,loop:!0,pageSize:a.length||5,clearInputWhenSelected:!0,multiple:n,options:e=>e?a.filter((t=>t.name.includes(e))):a,validate:t});return r=Array.isArray(r)?r:[r],r}async function et(){try{if(Z()){await p({message:"系统中已存在z的配置文件,确认重新配置?"})?c.rm("-rf",X()):process.exit(0)}n.mkdirSync(Y(),{recursive:!0});const e=await m({message:"请选择岗位类型",choices:[{name:"前端",value:D.FRONT_END},{name:"后端",value:D.BACK_END},{name:"测试",value:D.QUALITY_ASSURANCE}]}),t=await d({message:"请输入LDAP账号:"}),i=await f({message:"请输入LDAP密码:",mask:!0});Fe("jobType",e),Fe("ldapAccount",t),Fe("ldapPassword",i);Me(await qe());const a=await Ye(),r=await Xe("请选择你自己(用于企微通知):",(e=>e.length>1?"只能选一个":!(e.length<1)||"请选一个")),{name:s,value:o}=a.find((e=>e.value===r[0]));Fe({weWorkName:s,weWorkUserId:o})}catch(e){oe(e)}const e=h("配置信息初始化中").start();try{const t=await Be({url:`${Je()}/user`});Fe({gitUserId:t.id,gitName:t.name,gitEnglishName:t.username,gitEmail:t.email}),ze("latestCheckVersionTimestamp",Date.now()),Oe(),Ee("jobType")===D.FRONT_END&&await Ge(),e.succeed("配置信息初始化完成"),process.exit(0)}catch(t){e.fail("配置信息初始化失败"),a.isAxiosError(t)&&oe("请检查你的域名及令牌配置"),oe(t)}}const tt='{\n "$schema": "https://json.schemastore.org/tsconfig",\n "_version": "0.0.1",\n "compilerOptions": {\n "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.browser.tsbuildinfo",\n "lib": ["ESNext", "DOM", "DOM.Iterable", "WebWorker"],\n // 编译时无需导出类型文件\n "noEmit": true,\n\n // 编译时用模块最新规范,至于打包代码时的兼容问题,交给vite/webpack们解决\n "module": "ESNext",\n // 模块解析策略。同上\n "moduleResolution": "bundler",\n // 可以使用import...from导入json文件\n "resolveJsonModule": true,\n // 带上文件后缀,避免歧义。至于兼容性,交给vite/webpack们解决\n "allowImportingTsExtensions": true,\n // 识别一个文件是模块还是脚本,由于使用了打包工具,所以所有文件都是模块\n "moduleDetection": "force",\n\n // tsc编译时不转化jsx,留给打包工具处理\n "jsx": "preserve",\n // 指定处理jsx的库\n "jsxImportSource": "vue",\n\n // 必须显式声明this的类型,否则报错\n "noImplicitThis": true,\n // 严格模式。将默认开启以下规则:\n // noImplicitAny noImplicitThis alwaysStrict strictBindCallApply strictNullChecks strictFunctionTypes strictPropertyInitialization\n "strict": true,\n\n // 引入类型需要type关键字\n "verbatimModuleSyntax": true,\n\n // 编译目标用最新规范,至于打包代码时的兼容问题,交给vite/webpack们解决\n "target": "ESNext",\n // 合理编译class\n "useDefineForClassFields": true,\n\n // commonjs 和 es module之间可以互操作\n "esModuleInterop": true,\n // 引用路径中文件名大小写敏感\n "forceConsistentCasingInFileNames": true,\n // 会检查自建的和依赖库的所有.d.ts。调试自建d.ts文件时可以考虑打开\n "skipLibCheck": true\n }\n}\n',nt='{\n "$schema": "https://json.schemastore.org/tsconfig",\n "_version": "0.0.1",\n "compilerOptions": {\n "lib": ["ESNext"],\n // 编译时无需导出类型文件\n "noEmit": true,\n\n // 编译时用模块最新规范,至于打包代码时的兼容问题,交给vite/webpack们解决\n "module": "ESNext",\n // 模块解析策略。同上\n "moduleResolution": "bundler",\n // 可以使用import...from导入json文件\n "resolveJsonModule": true,\n // 识别一个文件是模块还是脚本,由于使用了打包工具,所以所有文件都是模块\n "moduleDetection": "force",\n\n // 必须显式声明this的类型,否则报错\n "noImplicitThis": true,\n // 严格模式。将默认开启以下规则:\n // noImplicitAny noImplicitThis alwaysStrict strictBindCallApply strictNullChecks strictFunctionTypes strictPropertyInitialization\n "strict": true,\n\n // 引入类型需要type关键字\n "verbatimModuleSyntax": true,\n\n // 编译目标用最新规范,至于打包代码时的兼容问题,交给vite/webpack们解决\n "target": "ESNext",\n // 合理编译class\n "useDefineForClassFields": true,\n\n // commonjs 和 es module之间可以互操作\n "esModuleInterop": true,\n // 引用路径中文件名大小写敏感\n "forceConsistentCasingInFileNames": true,\n // 会检查自建的和依赖库的所有.d.ts。调试自建d.ts文件时可以考虑打开\n "skipLibCheck": true\n }\n}\n';async function it(e,t){const n=await ue("git remote get-url --push origin");n||oe("获取项目远程git地址失败,请配置后重试");let i=e;i||(i=await m({message:"请选择项目语言",choices:[{name:R.JAVASCRIPT,value:R.JAVASCRIPT},{name:R.JAVA,value:R.JAVA},{name:R.PYTHON,value:R.PYTHON}]}));let a=t;if(!a){const e=ee(n),t=await He(e);if(!t)return oe(`未找到项目,请确认项目${n}是否存在,或者当前账号权限`);a=t.namespace.full_path}var r;r={language:i,"lint-staged":ve[i],repository:{url:n,group:a}},xe=xe?{...xe,...r}:r,y.writeJSONSync(G(),xe,{spaces:2})}async function at(e,t){if(e)c.rm("-rf",J);else if(n.existsSync(H())){await p({message:`当前项目中已存在配置文件夹${J},确认重新配置?`})?c.rm("-rf",J):process.exit(0)}n.mkdirSync(H(),{recursive:!0}),await it(e,t),function(){n.writeFileSync(K(),"",{mode:493}),n.writeFileSync(H(".gitignore"),".commit-msg-tpl\n",{mode:493}),n.writeFileSync(H("commit-msg"),"#!/usr/bin/env sh\nz run commit-msg",{mode:493}),n.writeFileSync(H("pre-commit"),"#!/usr/bin/env sh\nz run commit-files",{mode:493});const{language:e}=Ce();e===R.JAVASCRIPT&&(n.writeFileSync(H(".prettierrc.json"),ye,{mode:493}),n.writeFileSync(H(".prettierignore"),we,{mode:493}),n.writeFileSync(H("tsconfig.node.json"),nt,{mode:493}),n.writeFileSync(H("tsconfig.browser.json"),tt,{mode:493})),Q()}(),re("项目初始化完成")}async function rt(e,t){t.projectLanguage&&!Object.values(R).includes(t.projectLanguage)&&oe("项目语言不支持"),e?(fe(),"."===e?(await at(t.projectLanguage,void 0),process.exit(0)):"prepare"===e?await async function(){n.existsSync(H())&&n.existsSync(K())?Q():await at(),process.exit(0)}():oe("参数错误。执行 z init -h 查看帮助。")):await et()}async function st(e,t){if(!e)return"不能为空";if(!/^[a-z0-9-]+$/.test(e))return"格式为小写字母、中横线(可选)、数字(不推荐)。如apple, apple-tree";if(le().includes(e))return"当前目录下已存在同名文件夹,请先处理。";var n;const i=(await(n=e,Be({url:`${Je()}/projects`,data:{search:n,search_namespaces:!0}}))).find((n=>n.path_with_namespace===`${t}/${e}`));return!i||`远程仓库中已存在同名项目(${i.http_url_to_repo}),请更名后重试`}function ot(e){return!!e||"不能为空"}function ct(e){return e?!!/^[a-zA-Z0-9.]+$/.test(e)||"格式为大小写字母、数字、小数点,小驼峰命名。如userInfo、systemRouter3":"不能为空"}e.command("init").alias("i").argument("[type]","非必填。不传为初始化全局配置;传 . 为初始化当前项目;传 prepare 为初始化GIT HOOKS").option("--project-language",`项目语言。可选值:${Object.values(R).join("/")} `).description("初始化工具配置、项目配置").action(((...e)=>he(rt,...e)));const lt=e=>`${Ae("ZenTaoDomain")}${e}`;function ut(e,t){let i="";if([z.FEAT,z.FIX,z.REFACTOR].includes(e)){i=`${e}(${t.map((e=>e.value)).join(",")}): ${t.map((e=>e.name)).join(";")}`}e===z.CHORE&&(i=`${e}: ${t}`),n.writeFileSync(K(),i,"utf-8"),console.log(s.yellow(i)),re("commit msg模板写入成功,可以进行提交了")}async function pt(){const e=await m({message:"请选择你要创建的模板类型",choices:[{name:"feat - 业务需求/功能开发/BUG修复",value:z.FEAT},{name:"fix - bug修复",value:z.FIX},{name:"refactor - 技术重构/性能优化/代码规范",value:z.REFACTOR},{name:"chore - 其他",value:z.CHORE}]});if([z.FEAT,z.REFACTOR].includes(e)){const e=await async function(){const e=await Le({url:lt("/my-work-task.json?tid=mrrferp8"),method:"get"});return e?.tasks?e.tasks.filter((e=>"done"!==e.status)).map((({id:e,name:t})=>({value:{name:t,value:e},name:t}))):[]}();if(!e.length)return re("🤷 暂无开发任务");const t=await g({message:"请关联开发任务(可多选):",validate:e=>0!==e.length||"请选择项",choices:e.map((e=>({...e,name:`[${e.value.value}]: ${e.name}`}))),pageSize:e.length});ut(z.FEAT,t)}if(e===z.FIX){const e=await async function(){const e=await Le({url:lt("/my-work-bug.json?tid=mrrferp8"),method:"get"});return e?.bugs?Object.values(e.bugs).map((({id:e,title:t})=>({name:t,value:{name:t,value:e}}))):[]}();if(!e.length)return re("🤷 暂无BUG");const t=await g({message:"请关联Bug(可多选):",validate:e=>0!==e.length||"请选择项",choices:e.map((e=>({...e,name:`[${e.value.value}]: ${e.name}`}))),pageSize:e.length});ut(z.FIX,t)}if(e===z.CHORE){const e=await d({message:"请输入commit msg:",validate:e=>0!==e.length||"请输入commit msg"});ut(z.CHORE,e)}process.exit(0)}async function mt(){try{const a={},r=async()=>{const e=le(),{projects:t}=await Be({url:Ve("src/data/template-projects.json")}),n=t.map((t=>{const n={name:`${t.name} [${t.desc}]`,value:t.name,disabled:!1};return e.includes(t.name)&&(n.disabled="目录下已存在同名文件夹"),n})),i=await m({message:"请选择一个项目模板",choices:n}),r=t.find((e=>e.name===i));a.tplName=r.name,a.tplUrl=r.url,a.tplLanguage=r.language},o=async()=>{const{groups:e}=function(){const e=Y("fe-groups.json");return n.existsSync(e)?y.readJSONSync(e):{groups:[]}}(),t=await m({message:"请选择一个分组",choices:e.map((e=>({name:`${e.name} [${e.description}]`,value:e.id,short:e.name})))});a.group={id:t,name:e.find((e=>e.id===t))?.name}},l=async()=>{a.projectName=await d({message:"请输入项目名称",validate:e=>st(e,a.group?.name||"")}),a.projectDesc=await d({message:"请输入项目描述",validate:ot})};await r(),await o(),await l();const u=`${F}/${a.group?.name}/${a.projectName}.git`,p=h("模版初始化中").start();await ue(`git clone --depth=1 ${a.tplUrl}`),n.renameSync(a.tplName,a.projectName),c.cd(a.projectName),c.rm("-rf",".git"),await ue(`git init --initial-branch=${A.MASTER}`),await ue(`git remote add origin ${u}`),await ue(`git config user.name ${Ee("gitName")}`),await ue(`git config user.email ${Ee("gitEmail")}`);const f=Ne();t={...f,name:a.projectName,description:a.projectDesc,scripts:{...f.scripts,prepare:"[ -n '$z' ] && z init prepare || echo 'Warning: z not exist at global'"}},Te=Te?{...Te,...t}:t,y.writeJSONSync(i.join("package.json"),Te,{spaces:2}),await y.writeFile(i.resolve("README.md"),function(e="项目中文名",t="项目描述"){return`\n# ${e}\n${t}\n\n## 快速开始\n### 安装依赖\n\`\`\`bash\n npm i\n\`\`\`\n\n### 本地开发\n\`\`\`bash\n npm run dev:<environment>:[platform]\n\`\`\`\n\n### 打包代码\n\`\`\`bash\n npm run build:<environment>:[platform]\n\`\`\`\n\n\n### 查找、修复代码问题\n\`\`\`bash\n z run eslint\n # 或者\n z r e\n\`\`\`\n\n### 格式化代码\n\`\`\`bash\n z run prettier\n # 或者\n z r p\n\`\`\`\n\n### 检测类型问题\n\`\`\`bash\n z run type-check\n # 或者\n z r tc\n\`\`\`\n\n### 检测依赖更新\n\`\`\`bash\n z run dependency-check\n # 或者\n z r dc\n\`\`\`\n\n## 常见问题\n列出开发中常见的问题和解决方案\n\n## 了解更多\n在此处放入飞书文档链接。请在[前端团队-项目手册](https://hxhtbr8t8uy.feishu.cn/drive/folder/QfQ7favVWljQk7d63Prc8mUGnJf)中按照分类新建文档。\n`}(a.projectName,a.projectDesc)),p.succeed("模版初始化完成"),await at(a.tplLanguage,a.group?.name);const g=h("依赖安装中").start();await ue("npm install --registry https://registry.npmmirror.com/"),g.succeed("依赖安装完成");const w=h("项目推送中").start();await ue('git add . && git commit -m "chore: 项目初始化"'),await ue("git tag v0.0.1");const v=await(e={name:a.projectName,description:a.projectDesc,path:a.projectName,visibility:"private",namespace_id:a.group?.id},Be({url:`${Je()}/projects`,method:"post",data:e}));await ue(`git push -u origin ${A.MASTER}`),await ue(`git push origin HEAD:${A.MASTER} --tags`),w.succeed(`项目已推送到远程,地址: ${s.blue(u)}`);const $=h("初始化分支中").start(),b=`feat_init_${me()}`,S=[A.DEV,A.TEST,A.RELEASE,b],j=await Promise.allSettled(S.map((e=>function(e){return Be({url:`${Je()}/projects/${e.id}/repository/branches`,method:"post",data:e})}({id:v.id,branch:e,ref:A.MASTER})))),E=[];j.forEach((({status:e},t)=>{"fulfilled"===e&&E.push(S[t])})),await ue("git pull"),E.includes(b)?(await ue(`git checkout -b ${b} origin/${b}`),$.succeed(`项目已切换到初始分支: ${s.blue(b)}`)):$.warn("开发分支检出失败!项目当前在主分支,请自行检出开发分支。");const k=`cd ${a.projectName} && z start`;console.log(`输入 ${s.green(k)} 开始开发吧~`),process.exit(0)}catch(e){oe(e)}var e,t}var dt,ft;async function gt(e,t){let n;e?[dt.Project,dt.ProjectAbbr].includes(e)?n=dt.Project:[dt.Branch,dt.BranchAbbr].includes(e)?n=dt.Branch:[dt.CommitMsg,dt.CommitMsgAbbr].includes(e)?n=dt.CommitMsg:oe("参数输入错误"):n=await m({message:"请选择你要创建的类型",choices:[{name:"提交信息(commit message)",value:dt.CommitMsg},{name:"分支(branch)",value:dt.Branch},{name:"项目(project)",value:dt.Project}]}),n===dt.Project?await mt():(de(),fe(),n===dt.Branch?(await ge(),await async function(e){let t,n;de(),fe(),await ge(),t=e.branchType?e.branchType:await m({message:"请选择创建分支的类型",choices:[{name:"开发新功能(feat)",value:C.FEAT},{name:"修复BUG(fix)",value:C.FIX},{name:"重构/优化代码(refactor)",value:C.REFACTOR}]}),n=e.branchPurpose?e.branchPurpose:await d({message:"请输入创建分支的目的(大小写字母、数字,小驼峰式命名。如userInfo)",validate:ct});const i=`${t}_${n}_${me()}`;await ue(`git fetch origin ${A.MASTER}`),await ue(`git checkout -b ${i} origin/${A.MASTER}`),await ue(`git push -u origin ${i}`),process.exit(0)}(t)):n===dt.CommitMsg&&await pt())}function ht(e){return We({url:`${Ae("K8sDomain")}/kapis/clusters/youshou-local/devops.kubesphere.io/v1alpha3/namespaces/${P}/pipelines/${e.projectName}/pipelineruns?branch=${e.branchName}`,method:"post",data:e.params})}async function yt(e,t){de(),fe(),await ge();let n=e,i=t.platform;if(n&&!Object.values(A).includes(n)&&oe("仅支持发布指定环境分支"),i&&!Object.values(T).includes(i)&&oe("发布平台错误"),i||(i=await m({message:"请选择平台",choices:N})),i===T.NPM&&(n=A.MASTER),!n){const e=await m({message:"请选择部署环境",choices:x});n=(a=e)===k.PROD?A.MASTER:a}var a;let r=[];t.skipSelectionNotification||(r=await Xe("请选择部署成功要通知的人员:",(()=>!0),!0));let o=[];t.skipGroupNotification||(o=await Ze("请选择部署成功要通知的群组:",(()=>!0),!0));var c;!function(e,t){const n=Ne(),i=Ce();if(i?.repository?.url||oe(".z/project.json中缺少repository.url"),t===T.H5){const t=`build:${e}`;n?.scripts[t]||oe(`项目package.json文件scripts不存在命令${t}。`)}t===T.NPM&&(n?.scripts.build||oe("项目package.json文件scripts不存在命令build。")),t===T.SERVER&&(n?.scripts.build||oe("项目package.json文件scripts不存在命令build。"))}((c=n)===A.MASTER?k.PROD:c,i);const l=Ne();await async function(e){const t=h("部署任务创建中").start(),{targetBranch:n,notify:i,projectName:a}=e,r=i?[...new Set([Ee("weWorkUserId"),...i])]:[Ee("weWorkUserId")];try{const{metadata:i,spec:o}=await ht({projectName:a,branchName:n,params:{parameters:[{name:"QW_NOTIFY_USER",value:r.join(",")},{name:"QW_NOTIFY_GROUP",value:e.notifyGroup.join(",")}]}}),c=`${Ae("K8SWebDomain")}/youshou-local/clusters/youshou-local/devops/${i.namespace}/pipelines/${o.pipelineRef.name}/branch/${o.scm.refName}/run/${i.name}/task-status`;t.succeed("部署任务创建完成"),console.log(`如有需要,可在k8s中查看 ${s.blue(c)}`),process.exit(0)}catch(e){t.fail("部署任务创建失败"),oe(e)}}({projectName:l.name,targetBranch:n,notify:r,notifyGroup:o})}async function wt(e,t,n,i){const r=h(`分支合并中,${e} -> ${t}`).start();let s=0;try{const{iid:a}=await(o={title:`${e} -> ${t} by z-develop`,id:n.id,source_branch:e,target_branch:t,remove_source_branch:!i&&A.MASTER===t},Be({url:`${Je()}/projects/${o.id}/merge_requests`,method:"post",data:o}));s=a}catch(e){if(a.isAxiosError(e)){const t=e?.response?.status;409===t&&oe(`存在重复的合并请求,前往查看${n.mergeRequestUrl}`)}oe(e)}var o;const c=async()=>{try{await new Promise((e=>{setTimeout(e,5e3)})),await function(e){return Be({url:`${Je()}/projects/${e.id}/merge_requests/${e.iid}/merge`,method:"put"})}({id:n.id,iid:s}),r.succeed(`分支${e}已合并到分支${t}`)}catch(e){a.isAxiosError(e)||oe(e);const t=e?.response?.status;if(406===t)return await c();if(await function(e){return Be({url:`${Je()}/projects/${e.id}/merge_requests/${e.iid}`,method:"put",data:e})}({id:n.id,iid:s,state_event:"close"}),405===t){const e=await function(e){return Be({url:`${Je()}/projects/${e.id}/merge_requests/${e.iid}`,method:"get"})}({id:n.id,iid:s});if("cannot_be_merged"===e.merge_status&&e.diff_refs.base_sha===e.diff_refs.head_sha)return void r.warn("MR已关闭。判定为空的合并请求(没有新内容),可继续进行部署")}r.fail("合并过程中出现冲突,MR已关闭。建议在本地完成合并。"),process.exit(1)}};await c()}async function vt(e,t){de(),fe(),await ge();const n=await Re();Object.values(A).includes(n.sourceBranch)&&oe(`当前分支${n.sourceBranch}不可作为源分支合并到目标分支。`);var i;const a=(await(i=n.id,Be({url:`${Je()}/projects/${i}/repository/branches`}))).filter((e=>![n.sourceBranch].includes(e.name))).map((e=>{let t=e.name;return Object.values(A).includes(t)&&(t=s.bold.blue(t)),{name:t,value:e.name}}));let r;e&&!a.filter((t=>t.value===e)).length&&oe(`未找到目标分支${e}`),r=e||await m({message:"请选择要合并到的目标分支:",choices:a});const o=h(`本地分支${n.sourceBranch}检测中`).start();if(await ue(`git ls-remote --heads origin ${n.sourceBranch}`)){o.text=`存在远程分支origin/${n.sourceBranch}`,await ue("git fetch");const e=await ue(`git rev-parse ${n.sourceBranch}`),t=await ue(`git rev-parse origin/${n.sourceBranch}`);if(await ue(`git merge-base ${t} HEAD`)===t)await ue(`git push -u origin ${n.sourceBranch}`),o.succeed(`本地分支${n.sourceBranch}已推送到远程分支origin/${n.sourceBranch}`);else{await ue(`git merge-base ${e} ${t}`)===e?(await ue("git pull"),o.succeed(`本地分支${n.sourceBranch}已更新`)):(o.fail(`远程分支origin/${n.sourceBranch}和本地分支${n.sourceBranch}都有新的提交,请手动合并后再试。`),process.exit(1))}}else await ue(`git push -u origin ${n.sourceBranch}`),o.succeed(`本地分支${n.sourceBranch}已推送到远程分支origin/${n.sourceBranch}`);await async function(e,t){const n=`origin/${e.sourceBranch}`,i=await ue(`git log -b origin/${A.MASTER} -1 --format=%H`),a=await ue(`git log -b origin/${e.sourceBranch} -1 --format=%H`),r=await ue(`git log ${i}...${a} -b ${n}`);if(r||oe(`分支${e.sourceBranch}上不存在新的commit,不需要合并。`),await ue(`git branch --contains ${i} -r ${n}`)||(console.log(s.yellow("注意:当前分支上不存在远程主分支最新代码,将在自动合入后继续。")),await wt(A.MASTER,e.sourceBranch,e)),t===A.MASTER){const e=r.split("\n").filter((e=>e)),t=await ue(`git log -b origin/${k.TEST} -1 --format=%H`);(function(e,t){for(const n of t)if(!e.includes(n))return!1;return!0})((await ue(`git log ${i}...${t} -b origin/${k.TEST}`)).split("\n").filter((e=>e)),e)||oe("请先在测试环境发布要部署的代码")}}(n,r),await wt(n.sourceBranch,r,n,t.keepBranchAfterMergeMaster),A.MASTER!==r||t.keepBranchAfterMergeMaster||(await ue(`git checkout ${A.MASTER}`),await ue(`git pull origin ${A.MASTER}`),await ue(`git branch -d ${n.sourceBranch}`),re(`${n.sourceBranch}分支已移除,当前已切换到最新的${A.MASTER}。如需继续开发,请检出新分支(z c b)。`)),Object.values(A).includes(r)&&await yt(r,{platform:t.deployPlatform,skipSelectionNotification:t.deploySkipSelectionNotification,skipGroupNotification:t.skipGroupNotification})}function $t(){const e=G();if(n.existsSync(e)){const t=y.readJsonSync(e);if(t["lint-staged"])return t["lint-staged"];throw new Error("未找到lint配置")}throw new Error("请先初始化项目(z i .)。")}function bt(){const e=function(e){if(e.includes("Merge")&&e.includes("# Conflicts:"))return!0;if($.valid(e))return!0;const t=e.split(": ");if(1===t.length)return"body前缺少「: 」";const n=t[0];return/^(feat|fix|refactor)/.test(n)?!!/\(\d+(?:,\d+)*\)/.test(n)||"ID缺少或者格式不正确。":/^(chore|ci)/.test(n)?!![z.CHORE,z.CI].includes(n)||"chore/ci类型无需填写ID。":z.Break===n||"不存在的提交类型。"}(n.readFileSync(i.resolve(".git","COMMIT_EDITMSG"),"utf-8"));!0===e?(re("提交信息格式校验通过 ✅ "),process.exit(0)):oe(`提交信息格式校验失败。${e}`)}async function St(e,t){let a;de(),fe(),e?[ft.CommitMsg,ft.CommitMsgAbbr].includes(e)?a=ft.CommitMsg:[ft.CommitFiles,ft.CommitFilesAbbr].includes(e)?a=ft.CommitFiles:[ft.Prettier,ft.PrettierAbbr].includes(e)?a=ft.Prettier:[ft.Eslint,ft.EslintAbbr].includes(e)?a=ft.Eslint:[ft.TypeCheck,ft.TypeCheckAbbr].includes(e)?a=ft.TypeCheck:[ft.DependencyCheck,ft.DependencyCheckAbbr].includes(e)?a=ft.DependencyCheck:oe("参数输入错误"):a=await m({message:"请选择你要执行的操作",choices:[{name:"执行 prettier",value:ft.Prettier},{name:"执行 eslint",value:ft.Eslint},{name:"执行 type-check",value:ft.TypeCheck},{name:"执行 dependency-check",value:ft.DependencyCheck}]}),a===ft.CommitMsg?bt():a===ft.CommitFiles?await async function(){await v({concurrent:4,debug:!1,config:$t(),quiet:!0,relative:!0})?(re("代码风格检测通过!"),process.exit(0)):oe("代码风格检测未通过!")}():a===ft.Prettier?await async function(){n.existsSync(i.resolve("node_modules",".bin","prettier"))||oe("该项目未安装prettier,请安装后重试");try{await ue("npx prettier --write . --config .z/.prettierrc.json --ignore-path .z/.prettierignore --ignore-unknown --no-error-on-unmatched-pattern",{silent:!1}),re("prettier执行成功"),process.exit(0)}catch(e){oe("prettier校验出错")}}():a===ft.Eslint?await async function(e){n.existsSync(i.resolve("node_modules",".bin","eslint"))||oe("该项目未安装eslint,请安装后重试");try{let t="npx eslint '**/*.{vue,js,jsx,cjs,mjs,ts,tsx,cts,mts}' --fix";"win32"===process.platform&&(t='npx eslint "**/*.{vue,js,jsx,cjs,mjs,ts,tsx,cts,mts}" --fix'),e.quiet&&(t+=" --quiet"),e.maxWarnings&&!isNaN(Number(e.maxWarnings))?t+=` --max-warnings ${Number(e.maxWarnings)}`:t+=" --max-warnings 100",await ue(t,{silent:!1}),re("eslint执行成功"),process.exit(0)}catch(e){oe("eslint校验出错")}}(t):a===ft.TypeCheck?(n.existsSync(i.resolve("./node_modules/.bin/vue-tsc"))||oe("请先安装vue-tsc。推荐命令: npm i -D vue-tsc"),pe("npx vue-tsc --build"),process.exit(0)):a===ft.DependencyCheck&&await async function(){await ge();const e=await b({format:["group","repo"],interactive:!0,upgrade:!0,install:"always"});if(e&&Object.keys(e).length){re("升级完成 🎉");const t=Object.entries(e).map((([e,t])=>`${e}@${t}`)).join("; ");await ue(`git add . && git commit -m "chore: 依赖升级。${t}"`)}process.exit(0)}()}async function jt(e="latest"){await ue(`npm i -g ${Se.name}@${e} --registry https://registry.npmmirror.com/`),ze("latestCheckVersionTimestamp",Date.now()),ze("version",e),Oe(),re(`升级完成,当前版本${e}`),process.exit(0)}async function Et(e){let t=e;t?[k.DEV,k.TEST,k.RELEASE,k.PROD,"d","t","r","p"].includes(e)?"d"===t?t=k.DEV:"t"===t?t=k.TEST:"r"===t?t=k.RELEASE:"p"===t&&(t=k.PROD):oe("参数输入有误"):t=await m({message:"请选择环境",choices:x});const n=`dev:${t}`;Ne().scripts[n]?pe(`npm run ${n}`):oe(`项目中(package.json > scripts)不存在命令${n},请先添加!`)}!function(e){e.Project="project",e.ProjectAbbr="pr",e.Branch="branch",e.BranchAbbr="b",e.CommitMsg="commit-msg",e.CommitMsgAbbr="cm"}(dt||(dt={})),e.command("create").alias("c").argument("[type]","可选值为project|pr, branch|b, commit-msg|cm").option("--branch-type <type>",`分支类型。可选值:${Object.values(C).join(", ")}`).option("--branch-purpose <purpose>","创建分支的目的").description("创建项目/分支/提交信息").action(((...e)=>he(gt,...e))),e.command("merge").alias("m").argument("[branch]","目标分支名称").option("--deploy-platform <platform>",`合并成功后要部署的平台。可选值:${Object.values(T).join("/")}`).option("--deploy-skip-selection-notification","部署时,是否跳过选择部署通知人环节").option("--skip-group-notification","是否跳过选择部署通知群聊环节").option("--keep-branch-after-merge-master","在合并到主分支之后,是否保留分支。默认否").description("合并当前分支到指定远程分支,并部署。").action(((...e)=>he(vt,...e))),e.command("deploy").alias("d").description("部署到指定环境").argument("[branchName]",`部署环境。可选值:${Object.values(A).join("/")}`).option("--platform <platform>",`部署平台。可选值:${Object.values(T).join("/")}`).option("--skip-selection-notification","是否跳过选择部署通知人环节").option("--skip-group-notification","是否跳过选择部署通知群聊环节").action(((...e)=>he(yt,...e))),function(e){e.CommitMsg="commit-msg",e.CommitMsgAbbr="cm",e.CommitFiles="commit-files",e.CommitFilesAbbr="cf",e.Prettier="prettier",e.PrettierAbbr="p",e.Eslint="eslint",e.EslintAbbr="e",e.TypeCheck="type-check",e.TypeCheckAbbr="tc",e.DependencyCheck="dependency-check",e.DependencyCheckAbbr="dc"}(ft||(ft={})),e.command("run").aliases(["r","l","lint"]).argument("[type]","非必填。可选值为commit-msg|cm, commit-files|cf, prettier|p, eslint|e, type-check|tc, dependency-check|dc。").option("--quiet","eslint只打印error").option("--max-warnings [VALUE]","eslint结果warn超过多少个会异常退出,默认为100",parseInt).description("执行 eslint / prettier / type-check / dependency-check 脚本。").action(((...e)=>he(St,...e))),e.command("update").alias("u").argument("[version]","版本号","latest").description("升级").action(((...e)=>he(jt,...e))),e.command("start").alias("s").description("启动本地开发环境").argument("[env]","业务环境。可选值 dev|d, test|t, release|r, prod|p").action(((...e)=>he(Et,...e)));const kt=/Thumbs\.db|\.git|DS_Store|idea/,At="testcase";function Tt(e){const t=e.match(/^(.*[^[])?\[(\d+)]$/);if(t&&!e.startsWith("["))return{type:"module",id:t[2],displayName:t[1]?.trim()||""};const n=e.match(/^\[(\d+)](.+)$/);return n?{type:"case",id:n[1],displayName:n[2]?.trim()||""}:{type:"directory",id:void 0,displayName:e}}async function xt(e,t={}){const{exclude:n=kt}=t,i=[];return await async function a(r){const s=j.basename(r);if((await S.stat(r)).isFile())return null;const o=await S.readdir(r,{withFileTypes:!0}),c=(await Promise.all(o.filter((e=>e.isDirectory()&&!n.test(e.name))).map((e=>a(j.join(r,e.name)))))).filter(Boolean),{type:l,id:u,displayName:p}=Tt(s),m={name:s,id:u,displayName:p,path:r,type:l,children:c};return(t.hasRoot||j.resolve(e)!==r)&&i.push(m),m}(j.resolve(e)),i}async function Nt(e,t={}){const{exclude:n=kt}=t;try{const t=await S.readdir(j.resolve(e),{withFileTypes:!0});return await Promise.all(t.filter((e=>e.isDirectory()&&!n.test(e.name))).map((t=>{const n=j.join(e,t.name),{type:i,id:a,displayName:r}=Tt(t.name);return{name:t.name,id:a,displayName:r,path:n,type:i}})))}catch(t){return oe(`读取目录失败: ${e} : ${t}`),[]}}function Ct(e,t,n){switch(e){case"module":return n?`${t}[${n}]`:t;case"case":return n?`[${n}]${t}`:t;default:return t}}async function Dt(e,t,n,i){try{const a=j.basename(e),r=j.dirname(e),s=Ct(n,t,i),o=j.join(r,s);return a===s||(await ue(`git mv "${e}" "${o}"`),await ue("git add .")),!0}catch(n){return oe(`Git重命名文件夹失败: ${e} -> ${t}。${n}`),!1}}async function Rt(e){const t={id:0,name:"",path:""};if(e)Number.isNaN(Number(e))&&oe("请输入正确的产品ID"),t.id=Number(e);else{const e=await Ke({url:"/zen/testcase/product/list"});t.id=await m({message:"请选择产品",choices:e.map((e=>({name:`${e.label}[${e.value}]`,value:e.value})))})}return t.name=await function(e){return Ke({url:"/zen/testcase/product/name",data:{product:e}})}(t.id),t.path=j.join(At,Ct("module",t.name,String(t.id))),t}async function Ot(e){return(await Nt(At)).find((t=>Number(t.id)===e.id))}async function Ft(e,t){const n={precondition:e.precondition,priority:e.pri,steps:[]};var i;n.steps=await(i=e.id,Ke({url:"/zen/testcase/step/list",data:{id:i}})),y.writeJSONSync(t,n,{spaces:2})}async function Mt(e,t){if(await Ot(e)||oe(`本地未找到产品【${e.name}[${e.id}]】`),t);else{let t=await xt(e.path);console.log("flatList",t);const a=await function(e){return Ke({url:"/zen/testcase/product/auto-case/list",data:{product:e}})}(e.id);for(const r of a){let a;if(a=0===r.module?i.resolve(e.path):t.find((e=>Number(e.id)===r.module))?.path||"",!a)return oe(`用例${r.title}[${r.id}]未找到所属模块(${r.module}),请先拉取模块`);const s=t.find((({id:e})=>r.id===Number(e)));if(s){if(s.displayName!==r.title){await Dt(s.path,r.title,s.type,s.id)&&re(`重命名成功: ${s.displayName} -> ${r.title}`)}t=await xt(e.path),await Ft(r,i.join(t.find((e=>Number(e.id)===r.module))?.path||"",Ct("case",r.title,String(r.id)),"config.json"))}else{const e=i.join(a,Ct("case",r.title,String(r.id)));n.mkdirSync(e,{recursive:!0}),await Ft(r,i.join(e,"config.json")),y.ensureFileSync(i.join(e,"data.json")),n.writeFileSync(i.join(e,"data.json"),n.existsSync(i.resolve(J,"data.json"))?n.readFileSync(i.resolve(J,"data.json")):$e),y.ensureFileSync(i.join(e,"main.py")),n.writeFileSync(i.join(e,"main.py"),n.existsSync(i.resolve(J,"main.py"))?n.readFileSync(i.resolve(J,"main.py")):be)}}}}async function zt(e){const t=await Ot(e);if(t){if(t.displayName!==e.name){await Dt(t.path,e.name,t.type,t.id)&&re(`重命名成功: ${t.displayName} -> ${e.name}`)}}else await S.mkdir(e.path,{recursive:!0}),await ue("git add .");const{children:n}=await Qe(e.id);await async function(e,t,n={}){const{exclude:i=kt}=n;await async function e(t,n){if(!t||0===t.length)return;const a=await Nt(n,{exclude:i});for(const i of t){const t=String(i.id),r=Ct("module",i.title,t),s=a.find((e=>e.id===t));let o=s?.path||j.join(n,r);s?s.displayName!==i.title&&await Dt(s.path,i.title,"module",t)&&(o=j.join(n,r)):(await S.mkdir(o,{recursive:!0}),await ue(`git add "${o}"`)),i.children&&i.children.length>0&&await e(i.children,o)}}(e,j.resolve(t))}(n||[],e.path)}async function Pt(e,t){let n;de(),fe(),await ge(),e?([B.MODULE,B.CASE].includes(e)||oe(`不支持的参数${e}。同步类型参数为 ${B.MODULE} 或者 ${B.CASE}。`),n=e):n=await m({message:"请选择拉取数据类型",choices:_});const i=await Rt(t.productId),a=n===B.MODULE?"模块":B.CASE===n?"用例":"",r=h(`${a}同步中`).start();B.MODULE===n&&await zt(i),B.CASE===n&&await Mt(i,t.caseId),r.succeed(`${a}同步完成 🎉`),!t.disableAutoCommit&&await ue("git status -s")&&(await ue('git add . && git commit -m "chore: 同步禅道数据"'),re("代码已提交"))}async function It(e,t,a){const r=await d({message:"请输入你要创建的用例的前置条件(可不填)"}),s=h(`用例【${a}】创建中`).start(),o=await(c={product:Number(e.id),module:i.resolve(e?.path)===t?.path?0:Number(t?.id||0),title:a,type:"interface",openedBy:Ee("ldapAccount"),precondition:r||""},Ke({url:"/zen/testcase/create",data:c}));var c;await function(e){return Ke({url:"/zen/testcase/step/create",data:e})}({case:o,type:"step",desc:"按照预期执行",expect:"正常执行,符合预期"});const l=i.join(t.path,Ct("case",a,String(o)));if(n.existsSync(l))return re(`${l}已存在,请检查是否对应,本地不再创建。`);n.mkdirSync(l,{recursive:!0}),await Ft({id:o,pri:3,precondition:r},i.join(l,"config.json")),y.ensureFileSync(i.join(l,"data.json")),n.writeFileSync(i.join(l,"data.json"),n.existsSync(i.resolve(J,"data.json"))?n.readFileSync(i.resolve(J,"data.json")):$e),y.ensureFileSync(i.join(l,"main.py")),n.writeFileSync(i.join(l,"main.py"),n.existsSync(i.resolve(J,"main.py"))?n.readFileSync(i.resolve(J,"main.py")):be),s.succeed(`用例【[${o}]${a}】创建完成 🎉`)}async function Bt(e,t,a){const r=h(`模块【${a}】创建中`).start(),s=await(o={root:Number(e.id),name:a,parent:i.resolve(e?.path)===t?.path?0:Number(t?.id||0)},Ke({url:"/zen/testcase/module/create",data:o}));var o;const c=i.join(t.path,Ct("module",a,String(s)));if(n.existsSync(c))return re(`${c}已存在,请检查是否对应,本地不再创建。`);n.mkdirSync(c,{recursive:!0}),r.succeed(`模块【${a}[${s}]】创建完成 🎉`)}async function _t(e,t){let i;de(),fe(),await ge(),e?([B.MODULE,B.CASE].includes(e)||oe(`不支持的参数${e}。同步类型参数为 ${B.MODULE} 或者 ${B.CASE}。`),i=e):i=await m({message:"请选择拉创建的数据类型",choices:L});const a=i===B.MODULE?"模块":B.CASE===i?"用例":"",r=await Rt(t.productId),s=await Ot(r);if(!s)return oe(`本地未找到产品【${r.name}[${r.id}]】`);const o=await Qe(r.id),c=await(l=[o],async function e(t,n=[]){const i=n.length?`请选择层级(当前:${n.join(" / ")})`:"请选择层级",a=await m({message:i,choices:t.map((e=>({name:`${e.tempTitle?e.tempTitle:e.title} ${e.children?.length?"(有子级)":""}`,value:e})))});return a?.children?.length?(function(e){if(!e.children||0===e.children.length)return;const t=e.children[0];t&&t.title===e.title&&t.value===e.value&&(!t.children||0===t.children.length)||e.children.unshift({id:e.id,title:e.title,type:e.type,children:void 0,tempTitle:"当前层级"})}(a),e(a.children,[...n,a.title])):a}(l));var l;const u=(await xt(r.path,{hasRoot:!0})).find((e=>e.name===Ct("module",c.title,String(c.id))));if(!u?.path||!n.existsSync(u.path))return oe(`本地不存在${u?.path}模块`);const p=await d({message:`请输入你要创建的${a}名称`,required:!0,validate:e=>e.length>0&&e.length<255});B.MODULE===i&&await Bt(s,u,p),B.CASE===i&&await It(s,u,p),t.disableAutoCommit||B.CASE!==i||(await ue('git add . && git commit -m "chore: 同步创建的用例"'),re("代码已提交"))}async function Lt(){const e=E(process.argv.slice(2));if(!(e.h||e.help||e.v||e.version)&&(!["init","i"].includes(e._[0])||[".","prepare"].includes(e._[1])))if(Z()){const e=y.readJSONSync(X());Fe(e.profile),ze(e.main),Me(e.constants),await async function(){const e=ke("latestCheckVersionTimestamp"),t=ke("versionCheckDuring");if(Date.now()-Number(e)>24*Number(t)*3600*1e3){let e;Me(await qe());try{const t="TIME_OUT",n=new Promise((e=>{setTimeout((()=>e(t)),3e3)}));e=await Promise.race([n,ue(`npm view ${Se.name} version --registry https://registry.npmmirror.com/`)]),e!==t&&e!==Se.version&&(console.log(`${s.blue(Se.name)}本地版本为${Se.version},低于线上版本${e},开始升级`),await jt(e)),ze("latestCheckVersionTimestamp",Date.now()),Oe()}catch(e){console.log("升级出错!请重试,或者手动升级"),oe(e)}}}()}else oe(`请先初始化z-develop(执行 z i)。更多见${I}`)}e.command("qa-pull").alias("qp").argument("[type]","可选值为module/case").option("--product-id <product>","指定产品ID").option("--case-id <case>","type=case时,可传指定用例(单用例),不传则为产品下全部用例").option("--disable-auto-commit","是否跳过自动将修改结果提交。").description("将禅道中的模块或者用例同步到本地").action(((...e)=>he(Pt,...e))),e.command("qa-create").alias("qc").argument("[type]","可选值为module/case").option("--product-id <product>","指定产品ID").option("--disable-auto-commit","是否跳过自动将修改结果提交。").description("创建模块或者用例").action(((...e)=>he(_t,...e))),e.name("z-develop").alias("z").description(`z-develop, 开发流程管理工具。了解更多: ${s.blue(I)}`).usage("<command> [options]").hook("preAction",(async function(){process.on("unhandledRejection",(e=>{})),process.on("uncaughtException",(e=>{})),c.config.fatal=!0,c.config.silent=!0,c.config.verbose=Boolean(void 0)||!1,await Lt()})).version(Se.version,"-v, --version","当前版本号").helpOption("-h, --help","帮助").showHelpAfterError("可以使用z -h查看帮助。"),e.parse();
|
|
1
|
+
import{program as e}from"commander";import t from"node:child_process";import n from"node:fs";import i from"node:path";import a,{AxiosError as r}from"axios";import s from"chalk";import o from"dayjs";import c from"shelljs";import l from"node:os";import u from"child_process";import{confirm as p,select as m,input as d,password as f,checkbox as g}from"@inquirer/prompts";import h from"ora";import y from"fs-extra";import{select as w}from"inquirer-select-pro";import v from"lint-staged";import $ from"semver";import{run as b}from"npm-check-updates";import S from"fs/promises";import j from"path";import E from"minimist";var k,A,T;!function(e){e.DEV="dev",e.TEST="test",e.RELEASE="release",e.PROD="production"}(k||(k={})),function(e){e.DEV="dev",e.TEST="test",e.RELEASE="release",e.MASTER="master"}(A||(A={})),function(e){e.H5="h5",e.NPM="npm",e.SERVER="server"}(T||(T={}));const x=[{name:`开发环境 - ${k.DEV}`,value:k.DEV},{name:`测试环境 - ${k.TEST}`,value:k.TEST},{name:`预发环境 - ${k.RELEASE}`,value:k.RELEASE},{name:`正式环境 - ${k.PROD}`,value:k.PROD}],N=[{name:`网页 - ${T.H5}`,value:T.H5},{name:`依赖包 - ${T.NPM}`,value:T.NPM},{name:`服务端 - ${T.SERVER}`,value:T.SERVER}];var C,D,R;!function(e){e.FEAT="feat",e.FIX="fix",e.REFACTOR="refactor"}(C||(C={})),function(e){e.FRONT_END="fe",e.BACK_END="be",e.QUALITY_ASSURANCE="qa"}(D||(D={})),function(e){e.JAVA="Java",e.JAVASCRIPT="JavaScript",e.PYTHON="Python"}(R||(R={}));const O={1:"研发",2:"测试",3:"产品",4:"设计",5:"运营",6:"销售",7:"行政",8:"财务",9:"其他"},F="http://git.cxlqd.com",M=["fe-biz","fe-base","fe-tpl","fe-component","fe-demo"];var z;!function(e){e.FEAT="feat",e.FIX="fix",e.REFACTOR="refactor",e.CHORE="chore",e.CI="ci",e.Break="BREAKING CHANGE"}(z||(z={}));const P="fe-biz7tvsd",I="https://hxhtbr8t8uy.feishu.cn/wiki/LWW5wAQFPiXkmRkKcjOcyDDknLg";var B;!function(e){e.MODULE="module",e.CASE="case"}(B||(B={}));const _=[{name:"拉取远程模块(包含产品)",value:B.MODULE},{name:"拉取远程用例",value:B.CASE}],L=[{name:"创建模块",value:B.MODULE},{name:"创建用例",value:B.CASE}],U=".z",W="develop-config.json",J=".z",V=".commit-msg-tpl",q="project.json";function H(e=""){return i.join(J,e)}function G(){return H(q)}function K(){return H(V)}function Q(){u.spawnSync("git",["config","core.hooksPath",H()]),u.spawnSync("git",["config","commit.template",K()])}function Y(e=""){return i.resolve(l.homedir(),U,e)}function X(){return Y(W)}function Z(){return n.existsSync(Y())&&n.existsSync(X())}function ee(e){return encodeURIComponent(e.replace(`${F}/`,"").replace(/\.git$/,""))}const{red:te,green:ne,blue:ie,magenta:ae}=s;function re(...e){console.log(ne(...e))}function se(e){e instanceof Error&&("ExitPromptError"===e.name||e.message.includes("User force closed the prompt with"))&&(console.log(),console.log(s.cyan(" 👋 下次见~")),console.log(),process.exit(1))}function oe(e,t=!1){se(e);let n=e;e instanceof Error?(n=e.message,a.isAxiosError(e)&&(n=`请求失败:${e.message}`),console.log(te(n)),console.log(ae(e.stack))):console.log(te(e)),t||process.exit(1)}function ce(e){return!!n.existsSync(e)&&n.lstatSync(e).isDirectory()}function le(e=process.cwd()){if(ce(e)){return n.readdirSync(e).filter((t=>ce(i.resolve(e,t))))}return[]}async function ue(e,t={removeTailLinkBreak:!0,silent:!0}){let n=await new Promise(((n,i)=>{try{n(c.exec(e,{silent:t.silent}))}catch(e){i(e)}}));return n=n.toString(),t.removeTailLinkBreak&&(n=n.replace(/\n$/,"")),n}function pe(e){t.execSync(e,{stdio:"inherit"})}function me(){return o(Date.now()).format("YYMMDD")}function de(){n.existsSync(H())||oe("当前不在项目根目录。请切换到项目根目录")}function fe(){n.existsSync(i.resolve(".git"))||oe("当前不是git项目根目录,请先执行git init,或切换到根目录")}async function ge(){""!==await ue("git status -s")&&oe("请先提交代码变动,再进行操作")}async function he(e,...t){try{await e(...t)}catch(e){throw se(e),e}}const ye='{\n "printWidth": 120,\n "tabWidth": 2,\n "useTabs": false,\n "semi": true,\n "singleQuote": false,\n "quoteProps": "as-needed",\n "jsxSingleQuote": false,\n "trailingComma": "all",\n "bracketSpacing": true,\n "bracketSameLine": false,\n "arrowParens": "always",\n "requirePragma": false,\n "insertPragma": false,\n "proseWrap": "preserve",\n "htmlWhitespaceSensitivity": "css",\n "vueIndentScriptAndStyle": false,\n "endOfLine": "lf",\n "embeddedLanguageFormatting": "auto",\n "singleAttributePerLine": false\n}\n',we="# 系统 信息文件\n.DS_Store/\nThumbs.db\n\n# 编辑器配置文件\n.idea/\n.vscode/\n\n# 输出目录\ndist/\n\n# Log files\n*.log\n\n# 本地配置文件\n*.local\n\n# 缓存文件\n*.cache\n\n# 垃圾文件\n.Trashes\n",ve={[R.JAVA]:{"**/*.{java}":"echo 'todo'"},[R.JAVASCRIPT]:{"**/*.{vue,js,jsx,cjs,mjs,ts,tsx,cts,mts}":"eslint --fix","*":"prettier -wu"},[R.PYTHON]:{"**/*.{py}":"echo 'todo'"}},$e='[\n {\n "Precondition": "前置条件",\n "Title": "用例名称",\n "URL": "接口地址",\n "Data": "接口入参",\n "Method": "接口类型",\n "Expected": "期望结果"\n }\n]',be="# from assets";var Se={name:"cli-z-develop",version:"0.8.6",description:"前端本地开发命令行工具",main:"dist/index.js",bin:{z:"bin/z.js","z-develop":"bin/z.js"},scripts:{prepare:"[ -n '$z' ] && z init prepare || echo 'Warning: z not exist at global'",dev:"rollup -c -w --environment DEBUG:true",build:"rollup -c",eslint:"eslint '**/*.{ts,js}' --fix",prettier:"prettier -wu .",upload:"npm run build && npm publish --access public --registry https://registry.npmjs.org/","upload:patch":"npm version patch && npm run upload","upload:minor":"npm version minor && npm run upload","upload:major":"npm version major && npm run upload"},type:"module",author:"z",devDependencies:{"@lonely9/eslint-config-team":"^1.3.5","@rollup/plugin-json":"^6.1.0","@rollup/plugin-node-resolve":"^16.0.3","@rollup/plugin-replace":"v6.0.3","@rollup/plugin-terser":"^0.4.4","@tsconfig/node22":"^22.0.5","@types/fs-extra":"^11.0.4","@types/inquirer":"^9.0.9","@types/minimist":"^1.2.5","@types/node":"^22.15.29","@types/semver":"^7.7.1","@types/shelljs":"^0.10.0","@typescript-eslint/eslint-plugin":"^8.53.0","@typescript-eslint/parser":"^8.53.0",eslint:"^9.39.2",jiti:"^2.6.1",prettier:"^3.7.4",rollup:"^4.55.1","rollup-plugin-typescript2":"^0.36.0",typescript:"^5.9.3","vue-tsc":"^3.2.2"},dependencies:{"@inquirer/prompts":"^8.2.0",axios:"^1.13.2",chalk:"^5.6.2",commander:"^14.0.2",dayjs:"^1.11.19","fs-extra":"^11.3.3","inquirer-select-pro":"^1.0.0-alpha.9","lint-staged":"^16.2.7",minimist:"^1.2.8","npm-check-updates":"^19.3.1",ora:"^9.0.0",semver:"^7.7.3",shelljs:"^0.10.0"}};const je={profile:{ldapAccount:"",ldapPassword:"",gitToken:"",gitUserId:0,gitName:"",gitEnglishName:"",gitEmail:"",weWorkName:"",weWorkUserId:"",jobType:D.FRONT_END,zenTaoToken:"",k8sToken:""},main:{version:Se.version,latestCheckVersionTimestamp:0,versionCheckDuring:3,weWorkListCache:[]},constants:{ZenTaoDomain:"",K8sDomain:"",FEServerDomain:"",K8SWebDomain:""}};function Ee(e){return e?je.profile[e]:je.profile}function ke(e){return e?je.main[e]:je.main}function Ae(e){return e?je.constants[e]:je.constants}let Te=null,xe=null;function Ne(){if(Te)return Te;const e=i.join("package.json");return n.existsSync(e)||oe(`当前目录(${c.pwd()})不存在${e}文件,请在项目根目录执行该命令。`),Te=y.readJsonSync(e),Te}function Ce(){if(xe)return xe;const e=G();return n.existsSync(e)||oe(`当前目录(${c.pwd()})不存在${e}文件,请在项目根目录执行该命令,或者初始化项目(z init .)。`),xe=y.readJsonSync(e),xe}const De={id:0,path:"",group:"",sourceBranch:"",mergeRequestUrl:""};async function Re(){if(!De.id)try{const e=ee(Ce().repository.url),t=await He(e);De.id=t.id,De.path=e,De.group=t.namespace.full_path,De.mergeRequestUrl=`${t.web_url}/merge_requests`}catch(e){oe(e)}return De.sourceBranch||(De.sourceBranch=await ue("git branch --show-current")),De}function Oe(){y.writeJSONSync(X(),{main:ke(),profile:Ee(),constants:Ae()},{spaces:2})}function Fe(e,t){void 0!==t?je.profile[e]=t:je.profile={...je.profile,...e}}function Me(e,t){je.constants={...je.constants,...e}}function ze(e,t){void 0!==t?je.main[e]=t:je.main={...je.main,...e}}async function Pe(e){const t=e.method||"get",n=e.headers||{},i=e.data||{},o=e.dataKey||["GET","get"].includes(t)?"params":"data";try{const r={url:e.url,method:t,[o]:i,headers:n};s.magenta(r.method.toUpperCase()),s.yellow(r.url),JSON.stringify(r.headers),s.gray(JSON.stringify(r[o],null,2));const c=await a(r);return s.green("Response"),s.grey(JSON.stringify(c.data,null,2)),Promise.resolve(c.data)}catch(e){return e instanceof r&&(s.red("Error"),s.grey(JSON.stringify(e?.response?.data))),Promise.reject(e)}}async function Ie(){const e=Ee("gitToken");if(e)return e;{const{access_token:e}=await Pe({url:`${F}/oauth/token`,method:"post",data:{grant_type:"password",username:Ee("ldapAccount"),password:Ee("ldapPassword")}}),t=`Bearer ${e}`;return Fe("gitToken",t),Oe(),t}}async function Be(e){return Pe({...e,headers:{Authorization:await Ie()}})}async function _e(){const e=Ee("zenTaoToken");if(e)return e;{const{token:e}=await Pe({url:`${Ae("ZenTaoDomain")}/api.php/v1/tokens`,method:"post",data:{account:Ee("ldapAccount"),password:Ee("ldapPassword")}});return Fe("zenTaoToken",e),Oe(),e}}async function Le(e){const t=await Pe({...e,headers:{Token:await _e()}});if(!e.url.includes("local")){const{status:n,data:i}=t;if("success"===n){const t=JSON.parse(i);return"用户登录"===t.title?(Fe("zenTaoToken",""),Le({...e})):t}return{}}if("string"==typeof t){const e=JSON.parse(t.slice(0,t.indexOf("<script>")));return JSON.parse(e.data)}if("object"==typeof t)return"Unauthorized"===t.error||t.data.indexOf("<script>")<0?(Fe("zenTaoToken",""),Le({...e})):t}async function Ue(){const e=Ee("k8sToken");if(e)return e;{const{access_token:e}=await Pe({url:`${Ae("K8sDomain")}/oauth/login/LDAP`,method:"post",headers:{"Content-Type":"application/x-www-form-urlencoded"},data:{username:Ee("ldapAccount"),password:Ee("ldapPassword")}}),t=`Bearer ${e}`;return Fe("k8sToken",t),Oe(),t}}async function We(e){const t=await Pe({...e,headers:{Authorization:await Ue()}});return 401===t.code?(Fe("k8sToken",""),We({...e})):t}const Je=()=>`${F}/api/v4`,Ve=e=>`${Je()}/projects/100/repository/files/${encodeURIComponent(e)}/raw?ref=master`;function qe(){return Be({url:Ve("src/data/z-develop-config.json")})}function He(e){return Be({url:`${Je()}/projects/${e}`})}async function Ge(){const e=await Be({url:`${Je()}/groups`}),t=M.map((t=>{const n=e.find((e=>e.name===t));return!!n&&{name:n.name,id:n.id,description:n.description}})).filter((e=>Boolean(e)));y.writeJSONSync(Y("fe-groups.json"),{groups:t},{spaces:2})}async function Ke(e){const t=`${Ae("FEServerDomain")}/api`,{data:n}=await Pe({url:`${t}/auth/z-develop/login`,method:"post"}),i=await Pe({url:t+e.url,headers:{Authorization:`Bearer ${n}`},data:e.data,method:e.method||"post"});return 0!==i.code&&oe(`${i.code}: ${i.message}`),i.data}function Qe(e){return Ke({url:"/zen/testcase/product/auto-case/module/list",data:{product:e}})}async function Ye(){const e=(await Ke({url:"/user/list2"})).filter((e=>[1,2,3,4,5].includes(e.title))).map((e=>({name:`${e.nick} - ${O[e.title]}`,value:e.weWorkUserId}))),t=ke("weWorkListCache"),n=t.map((e=>e.value)),i=[];return e.forEach((e=>{const a=n.indexOf(e.value);i.push({...e,usageCount:a>-1?t[a].usageCount:0})})),i.sort(((e,t)=>t.usageCount-e.usageCount))}async function Xe(e,t,n){const i=await Ye();let a=await w({message:e,loop:!0,pageSize:i.length||5,clearInputWhenSelected:!0,multiple:n,options:e=>e?i.filter((t=>t.name.includes(e))):i,validate:t});return a=Array.isArray(a)?a:[a],function(e,t){const n=[];t.forEach((t=>{e.includes(t.value)&&n.push(t)}));const i=ke("weWorkListCache"),a=i.map((e=>e.value));n.forEach((e=>{const t=a.indexOf(e.value);t>-1?i[t].usageCount+=1:i.push({...e,usageCount:1})})),ze({weWorkListCache:i.sort(((e,t)=>t.usageCount-e.usageCount))}),Oe()}(a,i),a}async function Ze(e,t,n){const{groups:i}=await Be({url:Ve("src/data/project-group-chats.json")}),a=i.map((e=>({name:e.name,value:e.url})));let r=await w({message:e,loop:!0,pageSize:a.length||5,clearInputWhenSelected:!0,multiple:n,options:e=>e?a.filter((t=>t.name.includes(e))):a,validate:t});return r=Array.isArray(r)?r:[r],r}async function et(){try{if(Z()){await p({message:"系统中已存在z的配置文件,确认重新配置?"})?c.rm("-rf",X()):process.exit(0)}n.mkdirSync(Y(),{recursive:!0});const e=await m({message:"请选择岗位类型",choices:[{name:"前端",value:D.FRONT_END},{name:"后端",value:D.BACK_END},{name:"测试",value:D.QUALITY_ASSURANCE}]}),t=await d({message:"请输入LDAP账号:"}),i=await f({message:"请输入LDAP密码:",mask:!0});Fe("jobType",e),Fe("ldapAccount",t),Fe("ldapPassword",i);Me(await qe());const a=await Ye(),r=await Xe("请选择你自己(用于企微通知):",(e=>e.length>1?"只能选一个":!(e.length<1)||"请选一个")),{name:s,value:o}=a.find((e=>e.value===r[0]));Fe({weWorkName:s,weWorkUserId:o})}catch(e){oe(e)}const e=h("配置信息初始化中").start();try{const t=await Be({url:`${Je()}/user`});Fe({gitUserId:t.id,gitName:t.name,gitEnglishName:t.username,gitEmail:t.email}),ze("latestCheckVersionTimestamp",Date.now()),Oe(),Ee("jobType")===D.FRONT_END&&await Ge(),e.succeed("配置信息初始化完成"),process.exit(0)}catch(t){e.fail("配置信息初始化失败"),a.isAxiosError(t)&&oe("请检查你的域名及令牌配置"),oe(t)}}const tt='{\n "$schema": "https://json.schemastore.org/tsconfig",\n "_version": "0.0.1",\n "compilerOptions": {\n "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.browser.tsbuildinfo",\n "lib": ["ESNext", "DOM", "DOM.Iterable", "WebWorker"],\n // 编译时无需导出类型文件\n "noEmit": true,\n\n // 编译时用模块最新规范,至于打包代码时的兼容问题,交给vite/webpack们解决\n "module": "ESNext",\n // 模块解析策略。同上\n "moduleResolution": "bundler",\n // 可以使用import...from导入json文件\n "resolveJsonModule": true,\n // 带上文件后缀,避免歧义。至于兼容性,交给vite/webpack们解决\n "allowImportingTsExtensions": true,\n // 识别一个文件是模块还是脚本,由于使用了打包工具,所以所有文件都是模块\n "moduleDetection": "force",\n\n // tsc编译时不转化jsx,留给打包工具处理\n "jsx": "preserve",\n // 指定处理jsx的库\n "jsxImportSource": "vue",\n\n // 必须显式声明this的类型,否则报错\n "noImplicitThis": true,\n // 严格模式。将默认开启以下规则:\n // noImplicitAny noImplicitThis alwaysStrict strictBindCallApply strictNullChecks strictFunctionTypes strictPropertyInitialization\n "strict": true,\n\n // 引入类型需要type关键字\n "verbatimModuleSyntax": true,\n\n // 编译目标用最新规范,至于打包代码时的兼容问题,交给vite/webpack们解决\n "target": "ESNext",\n // 合理编译class\n "useDefineForClassFields": true,\n\n // commonjs 和 es module之间可以互操作\n "esModuleInterop": true,\n // 引用路径中文件名大小写敏感\n "forceConsistentCasingInFileNames": true,\n // 会检查自建的和依赖库的所有.d.ts。调试自建d.ts文件时可以考虑打开\n "skipLibCheck": true\n }\n}\n',nt='{\n "$schema": "https://json.schemastore.org/tsconfig",\n "_version": "0.0.1",\n "compilerOptions": {\n "lib": ["ESNext"],\n // 编译时无需导出类型文件\n "noEmit": true,\n\n // 编译时用模块最新规范,至于打包代码时的兼容问题,交给vite/webpack们解决\n "module": "ESNext",\n // 模块解析策略。同上\n "moduleResolution": "bundler",\n // 可以使用import...from导入json文件\n "resolveJsonModule": true,\n // 识别一个文件是模块还是脚本,由于使用了打包工具,所以所有文件都是模块\n "moduleDetection": "force",\n\n // 必须显式声明this的类型,否则报错\n "noImplicitThis": true,\n // 严格模式。将默认开启以下规则:\n // noImplicitAny noImplicitThis alwaysStrict strictBindCallApply strictNullChecks strictFunctionTypes strictPropertyInitialization\n "strict": true,\n\n // 引入类型需要type关键字\n "verbatimModuleSyntax": true,\n\n // 编译目标用最新规范,至于打包代码时的兼容问题,交给vite/webpack们解决\n "target": "ESNext",\n // 合理编译class\n "useDefineForClassFields": true,\n\n // commonjs 和 es module之间可以互操作\n "esModuleInterop": true,\n // 引用路径中文件名大小写敏感\n "forceConsistentCasingInFileNames": true,\n // 会检查自建的和依赖库的所有.d.ts。调试自建d.ts文件时可以考虑打开\n "skipLibCheck": true\n }\n}\n';async function it(e,t){const n=await ue("git remote get-url --push origin");n||oe("获取项目远程git地址失败,请配置后重试");let i=e;i||(i=await m({message:"请选择项目语言",choices:[{name:R.JAVASCRIPT,value:R.JAVASCRIPT},{name:R.JAVA,value:R.JAVA},{name:R.PYTHON,value:R.PYTHON}]}));let a=t;if(!a){const e=ee(n),t=await He(e);if(!t)return oe(`未找到项目,请确认项目${n}是否存在,或者当前账号权限`);a=t.namespace.full_path}var r;r={language:i,"lint-staged":ve[i],repository:{url:n,group:a}},xe=xe?{...xe,...r}:r,y.writeJSONSync(G(),xe,{spaces:2})}async function at(e,t){if(e)c.rm("-rf",J);else if(n.existsSync(H())){await p({message:`当前项目中已存在配置文件夹${J},确认重新配置?`})?c.rm("-rf",J):process.exit(0)}n.mkdirSync(H(),{recursive:!0}),await it(e,t),function(){n.writeFileSync(K(),"",{mode:493}),n.writeFileSync(H(".gitignore"),".commit-msg-tpl\n",{mode:493}),n.writeFileSync(H("commit-msg"),"#!/usr/bin/env sh\nz run commit-msg",{mode:493}),n.writeFileSync(H("pre-commit"),"#!/usr/bin/env sh\nz run commit-files",{mode:493});const{language:e}=Ce();e===R.JAVASCRIPT&&(n.writeFileSync(H(".prettierrc.json"),ye,{mode:493}),n.writeFileSync(H(".prettierignore"),we,{mode:493}),n.writeFileSync(H("tsconfig.node.json"),nt,{mode:493}),n.writeFileSync(H("tsconfig.browser.json"),tt,{mode:493})),Q()}(),re("项目初始化完成")}async function rt(e,t){t.projectLanguage&&!Object.values(R).includes(t.projectLanguage)&&oe("项目语言不支持"),e?(fe(),"."===e?(await at(t.projectLanguage,void 0),process.exit(0)):"prepare"===e?await async function(){n.existsSync(H())&&n.existsSync(K())?Q():await at(),process.exit(0)}():oe("参数错误。执行 z init -h 查看帮助。")):await et()}async function st(e,t){if(!e)return"不能为空";if(!/^[a-z0-9-]+$/.test(e))return"格式为小写字母、中横线(可选)、数字(不推荐)。如apple, apple-tree";if(le().includes(e))return"当前目录下已存在同名文件夹,请先处理。";var n;const i=(await(n=e,Be({url:`${Je()}/projects`,data:{search:n,search_namespaces:!0}}))).find((n=>n.path_with_namespace===`${t}/${e}`));return!i||`远程仓库中已存在同名项目(${i.http_url_to_repo}),请更名后重试`}function ot(e){return!!e||"不能为空"}function ct(e){return e?!!/^[a-zA-Z0-9.]+$/.test(e)||"格式为大小写字母、数字、小数点,小驼峰命名。如userInfo、systemRouter3":"不能为空"}e.command("init").alias("i").argument("[type]","非必填。不传为初始化全局配置;传 . 为初始化当前项目;传 prepare 为初始化GIT HOOKS").option("--project-language",`项目语言。可选值:${Object.values(R).join("/")} `).description("初始化工具配置、项目配置").action(((...e)=>he(rt,...e)));const lt=e=>`${Ae("ZenTaoDomain")}${e}`;function ut(e,t){let i="";if([z.FEAT,z.FIX,z.REFACTOR].includes(e)){i=`${e}(${t.map((e=>e.value)).join(",")}): ${t.map((e=>e.name)).join(";")}`}e===z.CHORE&&(i=`${e}: ${t}`),n.writeFileSync(K(),i,"utf-8"),console.log(s.yellow(i)),re("commit msg模板写入成功,可以进行提交了")}async function pt(){const e=await m({message:"请选择你要创建的模板类型",choices:[{name:"feat - 业务需求/功能开发/BUG修复",value:z.FEAT},{name:"fix - bug修复",value:z.FIX},{name:"refactor - 技术重构/性能优化/代码规范",value:z.REFACTOR},{name:"chore - 其他",value:z.CHORE}]});if([z.FEAT,z.REFACTOR].includes(e)){const e=await async function(){const e=await Le({url:lt("/my-work-task.json?tid=mrrferp8"),method:"get"});return e?.tasks?e.tasks.filter((e=>"done"!==e.status)).map((({id:e,name:t})=>({value:{name:t,value:e},name:t}))):[]}();if(!e.length)return re("🤷 暂无开发任务");const t=await g({message:"请关联开发任务(可多选):",validate:e=>0!==e.length||"请选择项",choices:e.map((e=>({...e,name:`[${e.value.value}]: ${e.name}`}))),pageSize:e.length});ut(z.FEAT,t)}if(e===z.FIX){const e=await async function(){const e=await Le({url:lt("/my-work-bug.json?tid=mrrferp8"),method:"get"});return e?.bugs?Object.values(e.bugs).map((({id:e,title:t})=>({name:t,value:{name:t,value:e}}))):[]}();if(!e.length)return re("🤷 暂无BUG");const t=await g({message:"请关联Bug(可多选):",validate:e=>0!==e.length||"请选择项",choices:e.map((e=>({...e,name:`[${e.value.value}]: ${e.name}`}))),pageSize:e.length});ut(z.FIX,t)}if(e===z.CHORE){const e=await d({message:"请输入commit msg:",validate:e=>0!==e.length||"请输入commit msg"});ut(z.CHORE,e)}process.exit(0)}async function mt(){try{const a={},r=async()=>{const e=le(),{projects:t}=await Be({url:Ve("src/data/template-projects.json")}),n=t.map((t=>{const n={name:`${t.name} [${t.desc}]`,value:t.name,disabled:!1};return e.includes(t.name)&&(n.disabled="目录下已存在同名文件夹"),n})),i=await m({message:"请选择一个项目模板",choices:n}),r=t.find((e=>e.name===i));a.tplName=r.name,a.tplUrl=r.url,a.tplLanguage=r.language},o=async()=>{const{groups:e}=function(){const e=Y("fe-groups.json");return n.existsSync(e)?y.readJSONSync(e):{groups:[]}}(),t=await m({message:"请选择一个分组",choices:e.map((e=>({name:`${e.name} [${e.description}]`,value:e.id,short:e.name})))});a.group={id:t,name:e.find((e=>e.id===t))?.name}},l=async()=>{a.projectName=await d({message:"请输入项目名称",validate:e=>st(e,a.group?.name||"")}),a.projectDesc=await d({message:"请输入项目描述",validate:ot})};await r(),await o(),await l();const u=`${F}/${a.group?.name}/${a.projectName}.git`,p=h("模版初始化中").start();await ue(`git clone --depth=1 ${a.tplUrl}`),n.renameSync(a.tplName,a.projectName),c.cd(a.projectName),c.rm("-rf",".git"),await ue(`git init --initial-branch=${A.MASTER}`),await ue(`git remote add origin ${u}`),await ue(`git config user.name ${Ee("gitName")}`),await ue(`git config user.email ${Ee("gitEmail")}`);const f=Ne();t={...f,name:a.projectName,description:a.projectDesc,scripts:{...f.scripts,prepare:"[ -n '$z' ] && z init prepare || echo 'Warning: z not exist at global'"}},Te=Te?{...Te,...t}:t,y.writeJSONSync(i.join("package.json"),Te,{spaces:2}),await y.writeFile(i.resolve("README.md"),function(e="项目中文名",t="项目描述"){return`\n# ${e}\n${t}\n\n## 快速开始\n### 安装依赖\n\`\`\`bash\n npm i\n\`\`\`\n\n### 本地开发\n\`\`\`bash\n npm run dev:<environment>:[platform]\n\`\`\`\n\n### 打包代码\n\`\`\`bash\n npm run build:<environment>:[platform]\n\`\`\`\n\n\n### 查找、修复代码问题\n\`\`\`bash\n z run eslint\n # 或者\n z r e\n\`\`\`\n\n### 格式化代码\n\`\`\`bash\n z run prettier\n # 或者\n z r p\n\`\`\`\n\n### 检测类型问题\n\`\`\`bash\n z run type-check\n # 或者\n z r tc\n\`\`\`\n\n### 检测依赖更新\n\`\`\`bash\n z run dependency-check\n # 或者\n z r dc\n\`\`\`\n\n## 常见问题\n列出开发中常见的问题和解决方案\n\n## 了解更多\n在此处放入飞书文档链接。请在[前端团队-项目手册](https://hxhtbr8t8uy.feishu.cn/drive/folder/QfQ7favVWljQk7d63Prc8mUGnJf)中按照分类新建文档。\n`}(a.projectName,a.projectDesc)),p.succeed("模版初始化完成"),await at(a.tplLanguage,a.group?.name);const g=h("依赖安装中").start();await ue("npm install --registry https://registry.npmmirror.com/"),g.succeed("依赖安装完成");const w=h("项目推送中").start();await ue('git add . && git commit -m "chore: 项目初始化"'),await ue("git tag v0.0.1");const v=await(e={name:a.projectName,description:a.projectDesc,path:a.projectName,visibility:"private",namespace_id:a.group?.id},Be({url:`${Je()}/projects`,method:"post",data:e}));await ue(`git push -u origin ${A.MASTER}`),await ue(`git push origin HEAD:${A.MASTER} --tags`),w.succeed(`项目已推送到远程,地址: ${s.blue(u)}`);const $=h("初始化分支中").start(),b=`feat_init_${me()}`,S=[A.DEV,A.TEST,A.RELEASE,b],j=await Promise.allSettled(S.map((e=>function(e){return Be({url:`${Je()}/projects/${e.id}/repository/branches`,method:"post",data:e})}({id:v.id,branch:e,ref:A.MASTER})))),E=[];j.forEach((({status:e},t)=>{"fulfilled"===e&&E.push(S[t])})),await ue("git pull"),E.includes(b)?(await ue(`git checkout -b ${b} origin/${b}`),$.succeed(`项目已切换到初始分支: ${s.blue(b)}`)):$.warn("开发分支检出失败!项目当前在主分支,请自行检出开发分支。");const k=`cd ${a.projectName} && z start`;console.log(`输入 ${s.green(k)} 开始开发吧~`),process.exit(0)}catch(e){oe(e)}var e,t}var dt,ft;async function gt(e,t){let n;e?[dt.Project,dt.ProjectAbbr].includes(e)?n=dt.Project:[dt.Branch,dt.BranchAbbr].includes(e)?n=dt.Branch:[dt.CommitMsg,dt.CommitMsgAbbr].includes(e)?n=dt.CommitMsg:oe("参数输入错误"):n=await m({message:"请选择你要创建的类型",choices:[{name:"提交信息(commit message)",value:dt.CommitMsg},{name:"分支(branch)",value:dt.Branch},{name:"项目(project)",value:dt.Project}]}),n===dt.Project?await mt():(de(),fe(),n===dt.Branch?(await ge(),await async function(e){let t,n;de(),fe(),await ge(),t=e.branchType?e.branchType:await m({message:"请选择创建分支的类型",choices:[{name:"开发新功能(feat)",value:C.FEAT},{name:"修复BUG(fix)",value:C.FIX},{name:"重构/优化代码(refactor)",value:C.REFACTOR}]}),n=e.branchPurpose?e.branchPurpose:await d({message:"请输入创建分支的目的(大小写字母、数字,小驼峰式命名。如userInfo)",validate:ct});const i=`${t}_${n}_${me()}`;await ue(`git fetch origin ${A.MASTER}`),await ue(`git checkout -b ${i} origin/${A.MASTER}`),await ue(`git push -u origin ${i}`),process.exit(0)}(t)):n===dt.CommitMsg&&await pt())}function ht(e){return We({url:`${Ae("K8sDomain")}/kapis/clusters/youshou-local/devops.kubesphere.io/v1alpha3/namespaces/${P}/pipelines/${e.projectName}/pipelineruns?branch=${e.branchName}`,method:"post",data:e.params})}async function yt(e,t){de(),fe(),await ge();let n=e,i=t.platform;if(n&&!Object.values(A).includes(n)&&oe("仅支持发布指定环境分支"),i&&!Object.values(T).includes(i)&&oe("发布平台错误"),i||(i=await m({message:"请选择平台",choices:N})),i===T.NPM&&(n=A.MASTER),!n){const e=await m({message:"请选择部署环境",choices:x});n=(a=e)===k.PROD?A.MASTER:a}var a;let r=[];t.skipSelectionNotification||(r=await Xe("请选择部署成功要通知的人员:",(()=>!0),!0));let o=[];t.skipGroupNotification||(o=await Ze("请选择部署成功要通知的群组:",(()=>!0),!0));var c;!function(e,t){const n=Ne(),i=Ce();if(i?.repository?.url||oe(".z/project.json中缺少repository.url"),t===T.H5){const t=`build:${e}`;n?.scripts[t]||oe(`项目package.json文件scripts不存在命令${t}。`)}t===T.NPM&&(n?.scripts.build||oe("项目package.json文件scripts不存在命令build。")),t===T.SERVER&&(n?.scripts.build||oe("项目package.json文件scripts不存在命令build。"))}((c=n)===A.MASTER?k.PROD:c,i);const l=Ne();await async function(e){const t=h("部署任务创建中").start(),{targetBranch:n,notify:i,projectName:a}=e,r=i?[...new Set([Ee("weWorkUserId"),...i])]:[Ee("weWorkUserId")];try{const{metadata:i,spec:o}=await ht({projectName:a,branchName:n,params:{parameters:[{name:"QW_NOTIFY_USER",value:r.join(",")},{name:"QW_NOTIFY_GROUP",value:e.notifyGroup.join(",")}]}}),c=`${Ae("K8SWebDomain")}/youshou-local/clusters/youshou-local/devops/${i.namespace}/pipelines/${o.pipelineRef.name}/branch/${o.scm.refName}/run/${i.name}/task-status`;t.succeed("部署任务创建完成"),console.log(`如有需要,可在k8s中查看 ${s.blue(c)}`),process.exit(0)}catch(e){t.fail("部署任务创建失败"),oe(e)}}({projectName:l.name,targetBranch:n,notify:r,notifyGroup:o})}async function wt(e,t,n,i){const r=h(`分支合并中,${e} -> ${t}`).start();let s=0;try{const{iid:a}=await(o={title:`${e} -> ${t} by z-develop`,id:n.id,source_branch:e,target_branch:t,remove_source_branch:!i&&A.MASTER===t},Be({url:`${Je()}/projects/${o.id}/merge_requests`,method:"post",data:o}));s=a}catch(e){if(a.isAxiosError(e)){const t=e?.response?.status;409===t&&oe(`存在重复的合并请求,前往查看${n.mergeRequestUrl}`)}oe(e)}var o;const c=async()=>{try{await new Promise((e=>{setTimeout(e,5e3)})),await function(e){return Be({url:`${Je()}/projects/${e.id}/merge_requests/${e.iid}/merge`,method:"put"})}({id:n.id,iid:s}),r.succeed(`分支${e}已合并到分支${t}`)}catch(e){a.isAxiosError(e)||oe(e);const t=e?.response?.status;if(406===t)return await c();if(await function(e){return Be({url:`${Je()}/projects/${e.id}/merge_requests/${e.iid}`,method:"put",data:e})}({id:n.id,iid:s,state_event:"close"}),405===t){const e=await function(e){return Be({url:`${Je()}/projects/${e.id}/merge_requests/${e.iid}`,method:"get"})}({id:n.id,iid:s});if("cannot_be_merged"===e.merge_status&&e.diff_refs.base_sha===e.diff_refs.head_sha)return void r.warn("MR已关闭。判定为空的合并请求(没有新内容),可继续进行部署")}r.fail("合并过程中出现冲突,MR已关闭。建议在本地完成合并。"),process.exit(1)}};await c()}async function vt(e,t){de(),fe(),await ge();const n=await Re();Object.values(A).includes(n.sourceBranch)&&oe(`当前分支${n.sourceBranch}不可作为源分支合并到目标分支。`);var i;const a=(await(i=n.id,Be({url:`${Je()}/projects/${i}/repository/branches`}))).filter((e=>![n.sourceBranch].includes(e.name))).map((e=>{let t=e.name;return Object.values(A).includes(t)&&(t=s.bold.blue(t)),{name:t,value:e.name}}));let r;e&&!a.filter((t=>t.value===e)).length&&oe(`未找到目标分支${e}`),r=e||await m({message:"请选择要合并到的目标分支:",choices:a});const o=h(`本地分支${n.sourceBranch}检测中`).start();if(await ue(`git ls-remote --heads origin ${n.sourceBranch}`)){o.text=`存在远程分支origin/${n.sourceBranch}`,await ue("git fetch");const e=await ue(`git rev-parse ${n.sourceBranch}`),t=await ue(`git rev-parse origin/${n.sourceBranch}`);if(await ue(`git merge-base ${t} HEAD`)===t)await ue(`git push -u origin ${n.sourceBranch}`),o.succeed(`本地分支${n.sourceBranch}已推送到远程分支origin/${n.sourceBranch}`);else{await ue(`git merge-base ${e} ${t}`)===e?(await ue("git pull"),o.succeed(`本地分支${n.sourceBranch}已更新`)):(o.fail(`远程分支origin/${n.sourceBranch}和本地分支${n.sourceBranch}都有新的提交,请手动合并后再试。`),process.exit(1))}}else await ue(`git push -u origin ${n.sourceBranch}`),o.succeed(`本地分支${n.sourceBranch}已推送到远程分支origin/${n.sourceBranch}`);await async function(e,t){const n=`origin/${e.sourceBranch}`,i=await ue(`git log -b origin/${A.MASTER} -1 --format=%H`),a=await ue(`git log -b origin/${e.sourceBranch} -1 --format=%H`),r=await ue(`git log ${i}...${a} -b ${n}`);if(r||oe(`分支${e.sourceBranch}上不存在新的commit,不需要合并。`),await ue(`git branch --contains ${i} -r ${n}`)||(console.log(s.yellow("注意:当前分支上不存在远程主分支最新代码,将在自动合入后继续。")),await wt(A.MASTER,e.sourceBranch,e)),t===A.MASTER){const e=r.split("\n").filter((e=>e)),t=await ue(`git log -b origin/${k.TEST} -1 --format=%H`);(function(e,t){for(const n of t)if(!e.includes(n))return!1;return!0})((await ue(`git log ${i}...${t} -b origin/${k.TEST}`)).split("\n").filter((e=>e)),e)||oe("请先在测试环境发布要部署的代码")}}(n,r),await wt(n.sourceBranch,r,n,t.keepBranchAfterMergeMaster),A.MASTER!==r||t.keepBranchAfterMergeMaster||(await ue(`git checkout ${A.MASTER}`),await ue(`git pull origin ${A.MASTER}`),await ue(`git branch -d ${n.sourceBranch}`),re(`${n.sourceBranch}分支已移除,当前已切换到最新的${A.MASTER}。如需继续开发,请检出新分支(z c b)。`)),Object.values(A).includes(r)&&await yt(r,{platform:t.deployPlatform,skipSelectionNotification:t.deploySkipSelectionNotification,skipGroupNotification:t.skipGroupNotification})}function $t(){const e=G();if(n.existsSync(e)){const t=y.readJsonSync(e);if(t["lint-staged"])return t["lint-staged"];throw new Error("未找到lint配置")}throw new Error("请先初始化项目(z i .)。")}function bt(){const e=function(e){if(e.includes("Merge")&&e.includes("# Conflicts:"))return!0;if($.valid(e))return!0;const t=e.split(": ");if(1===t.length)return"body前缺少「: 」";const n=t[0];return/^(feat|fix|refactor)/.test(n)?!!/\(\d+(?:,\d+)*\)/.test(n)||"ID缺少或者格式不正确。":/^(chore|ci)/.test(n)?!![z.CHORE,z.CI].includes(n)||"chore/ci类型无需填写ID。":z.Break===n||"不存在的提交类型。"}(n.readFileSync(i.resolve(".git","COMMIT_EDITMSG"),"utf-8"));!0===e?(re("提交信息格式校验通过 ✅ "),process.exit(0)):oe(`提交信息格式校验失败。${e}`)}async function St(e,t){let a;de(),fe(),e?[ft.CommitMsg,ft.CommitMsgAbbr].includes(e)?a=ft.CommitMsg:[ft.CommitFiles,ft.CommitFilesAbbr].includes(e)?a=ft.CommitFiles:[ft.Prettier,ft.PrettierAbbr].includes(e)?a=ft.Prettier:[ft.Eslint,ft.EslintAbbr].includes(e)?a=ft.Eslint:[ft.TypeCheck,ft.TypeCheckAbbr].includes(e)?a=ft.TypeCheck:[ft.DependencyCheck,ft.DependencyCheckAbbr].includes(e)?a=ft.DependencyCheck:oe("参数输入错误"):a=await m({message:"请选择你要执行的操作",choices:[{name:"执行 prettier",value:ft.Prettier},{name:"执行 eslint",value:ft.Eslint},{name:"执行 type-check",value:ft.TypeCheck},{name:"执行 dependency-check",value:ft.DependencyCheck}]}),a===ft.CommitMsg?bt():a===ft.CommitFiles?await async function(){await v({concurrent:4,debug:!1,config:$t(),quiet:!0,relative:!0})?(re("代码风格检测通过!"),process.exit(0)):oe("代码风格检测未通过!")}():a===ft.Prettier?await async function(){n.existsSync(i.resolve("node_modules",".bin","prettier"))||oe("该项目未安装prettier,请安装后重试");try{await ue("npx prettier --write . --config .z/.prettierrc.json --ignore-path .z/.prettierignore --ignore-unknown --no-error-on-unmatched-pattern",{silent:!1}),re("prettier执行成功"),process.exit(0)}catch(e){oe("prettier校验出错")}}():a===ft.Eslint?await async function(e){n.existsSync(i.resolve("node_modules",".bin","eslint"))||oe("该项目未安装eslint,请安装后重试");try{let t="npx eslint '**/*.{vue,js,jsx,cjs,mjs,ts,tsx,cts,mts}' --fix";"win32"===process.platform&&(t='npx eslint "**/*.{vue,js,jsx,cjs,mjs,ts,tsx,cts,mts}" --fix'),e.quiet&&(t+=" --quiet"),e.maxWarnings&&!isNaN(Number(e.maxWarnings))?t+=` --max-warnings ${Number(e.maxWarnings)}`:t+=" --max-warnings 100",await ue(t,{silent:!1}),re("eslint执行成功"),process.exit(0)}catch(e){oe("eslint校验出错")}}(t):a===ft.TypeCheck?(n.existsSync(i.resolve("./node_modules/.bin/vue-tsc"))||oe("请先安装vue-tsc。推荐命令: npm i -D vue-tsc"),pe("npx vue-tsc --build"),process.exit(0)):a===ft.DependencyCheck&&await async function(){await ge();const e=await b({format:["group","repo"],interactive:!0,upgrade:!0,install:"always"});if(e&&Object.keys(e).length){re("升级完成 🎉");const t=Object.entries(e).map((([e,t])=>`${e}@${t}`)).join("; ");await ue(`git add . && git commit -m "chore: 依赖升级。${t}"`)}process.exit(0)}()}async function jt(e="latest"){await ue(`npm i -g ${Se.name}@${e} --registry https://registry.npmmirror.com/`),ze("latestCheckVersionTimestamp",Date.now()),ze("version",e),Oe(),re(`升级完成,当前版本${e}`),process.exit(0)}async function Et(e){let t=e;t?[k.DEV,k.TEST,k.RELEASE,k.PROD,"d","t","r","p"].includes(e)?"d"===t?t=k.DEV:"t"===t?t=k.TEST:"r"===t?t=k.RELEASE:"p"===t&&(t=k.PROD):oe("参数输入有误"):t=await m({message:"请选择环境",choices:x});const n=`dev:${t}`;Ne().scripts[n]?pe(`npm run ${n}`):oe(`项目中(package.json > scripts)不存在命令${n},请先添加!`)}!function(e){e.Project="project",e.ProjectAbbr="pr",e.Branch="branch",e.BranchAbbr="b",e.CommitMsg="commit-msg",e.CommitMsgAbbr="cm"}(dt||(dt={})),e.command("create").alias("c").argument("[type]","可选值为project|pr, branch|b, commit-msg|cm").option("--branch-type <type>",`分支类型。可选值:${Object.values(C).join(", ")}`).option("--branch-purpose <purpose>","创建分支的目的").description("创建项目/分支/提交信息").action(((...e)=>he(gt,...e))),e.command("merge").alias("m").argument("[branch]","目标分支名称").option("--deploy-platform <platform>",`合并成功后要部署的平台。可选值:${Object.values(T).join("/")}`).option("--deploy-skip-selection-notification","部署时,是否跳过选择部署通知人环节").option("--skip-group-notification","是否跳过选择部署通知群聊环节").option("--keep-branch-after-merge-master","在合并到主分支之后,是否保留分支。默认否").description("合并当前分支到指定远程分支,并部署。").action(((...e)=>he(vt,...e))),e.command("deploy").alias("d").description("部署到指定环境").argument("[branchName]",`部署环境。可选值:${Object.values(A).join("/")}`).option("--platform <platform>",`部署平台。可选值:${Object.values(T).join("/")}`).option("--skip-selection-notification","是否跳过选择部署通知人环节").option("--skip-group-notification","是否跳过选择部署通知群聊环节").action(((...e)=>he(yt,...e))),function(e){e.CommitMsg="commit-msg",e.CommitMsgAbbr="cm",e.CommitFiles="commit-files",e.CommitFilesAbbr="cf",e.Prettier="prettier",e.PrettierAbbr="p",e.Eslint="eslint",e.EslintAbbr="e",e.TypeCheck="type-check",e.TypeCheckAbbr="tc",e.DependencyCheck="dependency-check",e.DependencyCheckAbbr="dc"}(ft||(ft={})),e.command("run").aliases(["r","l","lint"]).argument("[type]","非必填。可选值为commit-msg|cm, commit-files|cf, prettier|p, eslint|e, type-check|tc, dependency-check|dc。").option("--quiet","eslint只打印error").option("--max-warnings [VALUE]","eslint结果warn超过多少个会异常退出,默认为100",parseInt).description("执行 eslint / prettier / type-check / dependency-check 脚本。").action(((...e)=>he(St,...e))),e.command("update").alias("u").argument("[version]","版本号","latest").description("升级").action(((...e)=>he(jt,...e))),e.command("start").alias("s").description("启动本地开发环境").argument("[env]","业务环境。可选值 dev|d, test|t, release|r, prod|p").action(((...e)=>he(Et,...e)));const kt=/Thumbs\.db|\.git|DS_Store|idea/,At="testcase";function Tt(e){const t=e.match(/^(.*[^[])?\[(\d+)]$/);if(t&&!e.startsWith("["))return{type:"module",id:t[2],displayName:t[1]?.trim()||""};const n=e.match(/^\[(\d+)](.+)$/);return n?{type:"case",id:n[1],displayName:n[2]?.trim()||""}:{type:"directory",id:void 0,displayName:e}}async function xt(e,t={}){const{exclude:n=kt}=t,i=[];return await async function a(r){const s=j.basename(r);if((await S.stat(r)).isFile())return null;const o=await S.readdir(r,{withFileTypes:!0}),c=(await Promise.all(o.filter((e=>e.isDirectory()&&!n.test(e.name))).map((e=>a(j.join(r,e.name)))))).filter(Boolean),{type:l,id:u,displayName:p}=Tt(s),m={name:s,id:u,displayName:p,path:r,type:l,children:c};return(t.hasRoot||j.resolve(e)!==r)&&i.push(m),m}(j.resolve(e)),i}async function Nt(e,t={}){const{exclude:n=kt}=t;try{const t=await S.readdir(j.resolve(e),{withFileTypes:!0});return await Promise.all(t.filter((e=>e.isDirectory()&&!n.test(e.name))).map((t=>{const n=j.join(e,t.name),{type:i,id:a,displayName:r}=Tt(t.name);return{name:t.name,id:a,displayName:r,path:n,type:i}})))}catch(t){return oe(`读取目录失败: ${e} : ${t}`),[]}}function Ct(e,t,n){switch(e){case"module":return n?`${t}[${n}]`:t;case"case":return n?`[${n}]${t}`:t;default:return t}}async function Dt(e,t,n,i){try{const a=j.basename(e),r=j.dirname(e),s=Ct(n,t,i),o=j.join(r,s);return a===s||(await ue(`git mv "${e}" "${o}"`),await ue("git add .")),!0}catch(n){return oe(`Git重命名文件夹失败: ${e} -> ${t}。${n}`),!1}}async function Rt(e){const t={id:0,name:"",path:""};if(e)Number.isNaN(Number(e))&&oe("请输入正确的产品ID"),t.id=Number(e);else{const e=await Ke({url:"/zen/testcase/product/list"});t.id=await m({message:"请选择产品",choices:e.map((e=>({name:`${e.label}[${e.value}]`,value:e.value})))})}return t.name=await function(e){return Ke({url:"/zen/testcase/product/name",data:{product:e}})}(t.id),t.path=j.join(At,Ct("module",t.name,String(t.id))),t}async function Ot(e){return(await Nt(At)).find((t=>Number(t.id)===e.id))}async function Ft(e,t){const n={precondition:e.precondition,priority:e.pri,steps:[]};var i;n.steps=await(i=e.id,Ke({url:"/zen/testcase/step/list",data:{id:i}})),y.writeJSONSync(t,n,{spaces:2})}async function Mt(e,t){if(await Ot(e)||oe(`本地未找到产品【${e.name}[${e.id}]】`),t);else{let t=await xt(e.path);const a=await function(e){return Ke({url:"/zen/testcase/product/auto-case/list",data:{product:e}})}(e.id);for(const r of a){let a;if(a=0===r.module?i.resolve(e.path):t.find((e=>Number(e.id)===r.module))?.path||"",!a)return oe(`用例${r.title}[${r.id}]未找到所属模块(${r.module}),请先拉取模块`);const s=t.find((({id:e})=>r.id===Number(e)));if(s){if(s.displayName!==r.title){await Dt(s.path,r.title,s.type,s.id)&&re(`重命名成功: ${s.displayName} -> ${r.title}`)}t=await xt(e.path),await Ft(r,i.join(t.find((e=>Number(e.id)===r.module))?.path||"",Ct("case",r.title,String(r.id)),"config.json"))}else{const e=i.join(a,Ct("case",r.title,String(r.id)));n.mkdirSync(e,{recursive:!0}),await Ft(r,i.join(e,"config.json")),y.ensureFileSync(i.join(e,"data.json")),n.writeFileSync(i.join(e,"data.json"),n.existsSync(i.resolve(J,"data.json"))?n.readFileSync(i.resolve(J,"data.json")):$e),y.ensureFileSync(i.join(e,"main.py")),n.writeFileSync(i.join(e,"main.py"),n.existsSync(i.resolve(J,"main.py"))?n.readFileSync(i.resolve(J,"main.py")):be)}}}}async function zt(e){const t=await Ot(e);if(t){if(t.displayName!==e.name){await Dt(t.path,e.name,t.type,t.id)&&re(`重命名成功: ${t.displayName} -> ${e.name}`)}}else await S.mkdir(e.path,{recursive:!0}),await ue("git add .");const{children:n}=await Qe(e.id);await async function(e,t,n={}){const{exclude:i=kt}=n;await async function e(t,n){if(!t||0===t.length)return;const a=await Nt(n,{exclude:i});for(const i of t){const t=String(i.id),r=Ct("module",i.title,t),s=a.find((e=>e.id===t));let o=s?.path||j.join(n,r);s?s.displayName!==i.title&&await Dt(s.path,i.title,"module",t)&&(o=j.join(n,r)):(await S.mkdir(o,{recursive:!0}),await ue(`git add "${o}"`)),i.children&&i.children.length>0&&await e(i.children,o)}}(e,j.resolve(t))}(n||[],e.path)}async function Pt(e,t){let n;de(),fe(),await ge(),e?([B.MODULE,B.CASE].includes(e)||oe(`不支持的参数${e}。同步类型参数为 ${B.MODULE} 或者 ${B.CASE}。`),n=e):n=await m({message:"请选择拉取数据类型",choices:_});const i=await Rt(t.productId),a=n===B.MODULE?"模块":B.CASE===n?"用例":"",r=h(`${a}同步中`).start();B.MODULE===n&&await zt(i),B.CASE===n&&await Mt(i,t.caseId),r.succeed(`${a}同步完成 🎉`),!t.disableAutoCommit&&await ue("git status -s")&&(await ue('git add . && git commit -m "chore: 同步禅道数据"'),re("代码已提交"))}async function It(e,t,a){const r=await d({message:"请输入你要创建的用例的前置条件(可不填)"}),s=h(`用例【${a}】创建中`).start(),o=await(c={product:Number(e.id),module:i.resolve(e?.path)===t?.path?0:Number(t?.id||0),title:a,type:"interface",openedBy:Ee("ldapAccount"),precondition:r||""},Ke({url:"/zen/testcase/create",data:c}));var c;await function(e){return Ke({url:"/zen/testcase/step/create",data:e})}({case:o,type:"step",desc:"按照预期执行",expect:"正常执行,符合预期"});const l=i.join(t.path,Ct("case",a,String(o)));if(n.existsSync(l))return re(`${l}已存在,请检查是否对应,本地不再创建。`);n.mkdirSync(l,{recursive:!0}),await Ft({id:o,pri:3,precondition:r},i.join(l,"config.json")),y.ensureFileSync(i.join(l,"data.json")),n.writeFileSync(i.join(l,"data.json"),n.existsSync(i.resolve(J,"data.json"))?n.readFileSync(i.resolve(J,"data.json")):$e),y.ensureFileSync(i.join(l,"main.py")),n.writeFileSync(i.join(l,"main.py"),n.existsSync(i.resolve(J,"main.py"))?n.readFileSync(i.resolve(J,"main.py")):be),s.succeed(`用例【[${o}]${a}】创建完成 🎉`)}async function Bt(e,t,a){const r=h(`模块【${a}】创建中`).start(),s=await(o={root:Number(e.id),name:a,parent:i.resolve(e?.path)===t?.path?0:Number(t?.id||0)},Ke({url:"/zen/testcase/module/create",data:o}));var o;const c=i.join(t.path,Ct("module",a,String(s)));if(n.existsSync(c))return re(`${c}已存在,请检查是否对应,本地不再创建。`);n.mkdirSync(c,{recursive:!0}),r.succeed(`模块【${a}[${s}]】创建完成 🎉`)}async function _t(e,t){let i;de(),fe(),await ge(),e?([B.MODULE,B.CASE].includes(e)||oe(`不支持的参数${e}。同步类型参数为 ${B.MODULE} 或者 ${B.CASE}。`),i=e):i=await m({message:"请选择拉创建的数据类型",choices:L});const a=i===B.MODULE?"模块":B.CASE===i?"用例":"",r=await Rt(t.productId),s=await Ot(r);if(!s)return oe(`本地未找到产品【${r.name}[${r.id}]】`);const o=await Qe(r.id),c=await(l=[o],async function e(t,n=[]){const i=n.length?`请选择层级(当前:${n.join(" / ")})`:"请选择层级",a=await m({message:i,choices:t.map((e=>({name:`${e.tempTitle?e.tempTitle:e.title} ${e.children?.length?"(有子级)":""}`,value:e})))});return a?.children?.length?(function(e){if(!e.children||0===e.children.length)return;const t=e.children[0];t&&t.title===e.title&&t.value===e.value&&(!t.children||0===t.children.length)||e.children.unshift({id:e.id,title:e.title,type:e.type,children:void 0,tempTitle:"当前层级"})}(a),e(a.children,[...n,a.title])):a}(l));var l;const u=(await xt(r.path,{hasRoot:!0})).find((e=>e.name===Ct("module",c.title,String(c.id))));if(!u?.path||!n.existsSync(u.path))return oe(`本地不存在${u?.path}模块`);const p=await d({message:`请输入你要创建的${a}名称`,required:!0,validate:e=>e.length>0&&e.length<255});B.MODULE===i&&await Bt(s,u,p),B.CASE===i&&await It(s,u,p),t.disableAutoCommit||B.CASE!==i||(await ue('git add . && git commit -m "chore: 同步创建的用例"'),re("代码已提交"))}async function Lt(){const e=E(process.argv.slice(2));if(!(e.h||e.help||e.v||e.version)&&(!["init","i"].includes(e._[0])||[".","prepare"].includes(e._[1])))if(Z()){const e=y.readJSONSync(X());Fe(e.profile),ze(e.main),Me(e.constants),await async function(){const e=ke("latestCheckVersionTimestamp"),t=ke("versionCheckDuring");if(Date.now()-Number(e)>24*Number(t)*3600*1e3){let e;Me(await qe());try{const t="TIME_OUT",n=new Promise((e=>{setTimeout((()=>e(t)),3e3)}));e=await Promise.race([n,ue(`npm view ${Se.name} version --registry https://registry.npmmirror.com/`)]),e!==t&&e!==Se.version&&(console.log(`${s.blue(Se.name)}本地版本为${Se.version},低于线上版本${e},开始升级`),await jt(e)),ze("latestCheckVersionTimestamp",Date.now()),Oe()}catch(e){console.log("升级出错!请重试,或者手动升级"),oe(e)}}}()}else oe(`请先初始化z-develop(执行 z i)。更多见${I}`)}e.command("qa-pull").alias("qp").argument("[type]","可选值为module/case").option("--product-id <product>","指定产品ID").option("--case-id <case>","type=case时,可传指定用例(单用例),不传则为产品下全部用例").option("--disable-auto-commit","是否跳过自动将修改结果提交。").description("将禅道中的模块或者用例同步到本地").action(((...e)=>he(Pt,...e))),e.command("qa-create").alias("qc").argument("[type]","可选值为module/case").option("--product-id <product>","指定产品ID").option("--disable-auto-commit","是否跳过自动将修改结果提交。").description("创建模块或者用例").action(((...e)=>he(_t,...e))),e.name("z-develop").alias("z").description(`z-develop, 开发流程管理工具。了解更多: ${s.blue(I)}`).usage("<command> [options]").hook("preAction",(async function(){process.on("unhandledRejection",(e=>{})),process.on("uncaughtException",(e=>{})),c.config.fatal=!0,c.config.silent=!0,c.config.verbose=Boolean(void 0)||!1,await Lt()})).version(Se.version,"-v, --version","当前版本号").helpOption("-h, --help","帮助").showHelpAfterError("可以使用z -h查看帮助。"),e.parse();
|