willis-cli
Version:
常用功能脚手架工具,支持克隆模板项目仓库、git 版本发布、版本预发布、查看分支信息、docker 镜像构建与重启等
2 lines • 8.79 kB
JavaScript
import{program as t}from"commander";import e from"chalk";import a from"ora";import i from"node:fs";import r from"node:path";import n from"node:fs/promises";import o from"inquirer";import s from"node:util";import c from"download-git-repo";import m from"node:child_process";Array.prototype.findLastIndex||(Array.prototype.findLastIndex=function(t,e){for(let a=this.length-1;a>=0;a--)if(t.call(e,this[a],a,this))return a;return-1});var d="willis-cli",g="1.2.0",p="常用功能脚手架工具,支持克隆模板项目仓库、git 版本发布、版本预发布、查看分支信息、docker 镜像构建与重启等";function u(t,a){return o.prompt([{name:"name",type:"input",default:t,message:"请输入你的项目名称",filter:t=>t.trim(),validate:t=>!!t||"项目名称必填"},{name:"repo",type:"input",when:!a,message:`请输入你要克隆的模板仓库 git 地址\n ${e.gray("GitHub - github:owner/name or simply owner/name")}\n ${e.gray("GitLab - gitlab:owner/name")}\n ${e.gray("Bitbucket - bitbucket:owner/name")}\n ${e.gray("私有仓库 - git 仓库链接地址(https://github.com/willis325/willis-cli.git)")}\n ${e.gray("更多输入格式信息请看 https://www.npmjs.com/package/download-git-repo")}\n `,filter:t=>t.trim(),validate:t=>!!t||"git 仓库必填"}])}var w=s.promisify(c);var l=s.promisify(m.exec),f=async(t,e={})=>(await l(t,e)).stdout,y=async(t,e)=>{const a=await(e instanceof Promise?e:Promise.resolve(e));t.info(a)},h=async(t,e,a=[],i)=>{const r=await f(`${e} ${a.join(" ")}`),n=(i??e)+":"+r;return t.info(n),r.trim()??""},v=async()=>{const t=(await f("git status")).includes("nothing to commit, working tree clean");if(!t)throw new Error("当前分支有未提交的代码,请手动解决!");return t},k=async()=>{const t=(await f("git status")).includes("Unmerged paths:");if(t)throw new Error("当前分支有未解决的冲突,请手动解决!");return t};async function $(t){await h(t,"git reset",["--hard"]),t.succeed("代码已回退!!!"),t.succeed("😊😊😊")}t.name(d).usage("<command> [options]").description(e.cyanBright(p)).version(e.cyanBright(g)),t.command("create [project-name]").description(e.green("根据 git 模板仓库快速创建一个新的项目")).option("-t --template <template>",e.green("指定github的模板仓库")).option("-f --force",e.green("强制覆盖,如果当前目录已存在同名目录")).action(async function(t,o){const s=a("模板下载中..."),{name:c,repo:m}=await async function(t,e){if(t&&e)return{name:t.trim(),repo:e.includes("/")?e.trim():`willis325/${e.trim()}`};if(!t&&e){return{name:(await u(t,e)).name,repo:e.includes("/")?e.trim():`willis325/${e.trim()}`}}return await u(t)}(t,null==o?void 0:o.template);try{s.start();const t=r.resolve(process.cwd(),c);await async function(t,e){if(i.existsSync(e)){if(!t)throw new Error("项目已存在,-f 可强制覆盖");await n.rm(e,{recursive:!0,force:!0})}await n.rm(e,{recursive:!0,force:!0})}(!!(null==o?void 0:o.force),t);const e=(m.includes(".zip")||m.includes(".git")?"direct:":"")+m,a=m.includes(".git")?{clone:!0}:{};await w(e,t,a),await async function(t,e){const a=r.resolve(t,"package.json"),i=await n.readFile(a,{encoding:"utf-8"}),o=JSON.parse(i);await n.writeFile(a,i.replaceAll(o.name,e),{encoding:"utf-8"})}(t,c),await async function(t,e){const a=r.resolve(t,"index.html");if(!i.existsSync(a))return;const o=await n.readFile(a,{encoding:"utf-8"});await n.writeFile(a,o.replace(/<title.*?>(.*?)<\/title>/gi,`<title>${e}</title>`),{encoding:"utf-8"})}(t,c),s.succeed("项目创建成功!!!"),s.succeed("😊😊😊")}catch(t){s.fail(e.red(t)),process.exit(1)}}),t.command("deploy [container-name]").description(e.green("重新构建 docker 镜像,并重启镜像服务")).action(async function(t){const i=a("docker命令运行中...");try{i.start(),await y(i,f("docker ps -a")),await y(i,f("docker images"));const{name:e}=await o.prompt([{name:"name",type:"input",default:t,message:"请输入你的容器名称",filter:t=>t.trim(),validate:t=>!!t||"容器名称必填"}]),a=await f("docker ps -a | grep '"+e+"' | awk '{ print $1 }' | xargs docker stop | xargs docker rm -f");i.info(`停止并删除容器${a}`);const r=await f("docker images | grep '"+e+"' | awk '{ print $3 }' | xargs docker rmi -f");i.info(`删除镜像${r}`);const n=await f("docker compose up -d --no-recreate --no-deps --build");i.info(`重新构建并重启${n}`),await y(i,f("docker ps -a")),i.succeed("项目更新成功!!!"),i.succeed("😊😊😊")}catch(t){i.fail(e.red(t)),process.exit(1)}}),t.command("publish").description(e.green("合并预发布 dev 分支到 master 主干,适用于 dev/master 模型分支仓库")).action(async function(){const t=a("git仓库更新中...");try{t.start(),await h(t,"pwd",[],"当前目录");const e=await h(t,"git branch",["--show-current"],"当前分支");await v(),"master"!==e&&await h(t,"git checkout",["master"],"切换到master分支"),await h(t,"git fetch",[]),await h(t,"git pull",["origin","master"]),await h(t,"git merge",["origin/dev"]),await h(t,"git status"),await k(),await h(t,"git show",["--no-patch"]);if(!(await o.prompt([{name:"judge",type:"confirm",message:"请确认是否推送master分支到远程仓库?"}])).judge)throw new Error("您已取消更新");await h(t,"git push",["origin","master"]),await h(t,"git log",["-5",'--pretty=format:"%nAuthor: %an %nDate: %cd %nCommit: %H %nMessage: %s"',"--date=iso"]),t.succeed("更新成功!!!"),t.succeed("😊😊😊")}catch(a){t.fail(e.red(a)),process.exit(1)}}),t.command("release").description(e.green("合并项目开发分支到 dev,进入预发布流程,适用于 dev/master 模型分支仓库")).action(async function(){const t=a("git仓库更新中...");try{t.start(),await h(t,"pwd",[],"当前目录");const e=await h(t,"git branch",["--show-current"],"当前分支");await v();const a="dev"===e?await async function(){const{branch:t}=await o.prompt([{name:"branch",type:"input",message:"请输入你要合并【squash merge】的分支",filter:t=>t.trim(),validate:t=>!!t.trim()||"分支名称必填"}]);return t}():e;"dev"!==e&&await h(t,"git checkout",["dev"]),await h(t,"git fetch"),await h(t,"git pull",["origin","dev"]),await v(),await async function(t,e){try{await h(t,"git merge",["--squash",e])}catch{throw new Error("当前分支有未解决的冲突,请手动解决!")}}(t,a),await h(t,"git status"),await k();const{type:i,judge:r,fallback:n,message:s}=await async function(){return await o.prompt([{name:"type",type:"list",message:"请选择本次操作类型",choices:[{name:"代码白盒",value:0},{name:"版本预发布",value:1}],default:0},{name:"review",type:"input",message:"代码白盒中,请在白盒完成后输入任意字符,将回退本次dev分支的merge操作",when:t=>0===t.type},{name:"judge",type:"confirm",message:"请确认是否推送dev分支到远程仓库?",when:t=>1===t.type},{name:"fallback",type:"confirm",message:"请确认是否回退本次dev分支的merge操作?",when:t=>!t.judge},{name:"message",type:"input",message:"请输入本次提交的描述",filter:t=>t.trim(),validate:t=>!!t.trim()||"提交描述必填",when:t=>t.judge}])}();if(0===i)return await $(t);if(1===i&&!r){if(n)return await $(t);throw new Error("您已取消更新")}await h(t,"git commit",["-m",`"${s}"`]),await h(t,"git push",["origin","dev"]),await h(t,"git log",["-3",'--pretty=format:"%nAuthor: %an %nDate: %cd %nCommit: %H %nMessage: %s"',"--date=iso"]),t.succeed("更新成功!!!"),t.succeed("😊😊😊")}catch(a){t.fail(e.red(a)),process.exit(1)}}),t.command("show [branch-name]").description(e.green("查看本地/远程分支的详细信息")).option("-l --local",e.green("查看本地当前分支的详细信息")).action(async function(t,i){const r=a("分支信息查看中...");try{r.start();const a=await async function(t,a){if(t)return t;if(null==a?void 0:a.local)return"";const{name:i}=await async function(){return o.prompt([{name:"name",type:"input",message:`请输入你要查看的分支名称,不输入则默认查看当前分支\n ${e.gray("本地分支 - feature/fqw/init")} \n ${e.gray("远程分支 - origin/feature/fqw/init")} \n ${e.gray("不输入任何内容 - 默认当前分支")} \n `,filter:t=>t.trim()}])}();return i}(t,i),n=await f("git branch --show-current"),s=await f("git remote get-url origin"),c=a&&a.startsWith("origin/")?a.replace(/^origin\//,""):a||n.trim();await y(r,f(`git log ${a} -1 --pretty=format:"%n提交人: %an %n提交日期: %cd %n分支名: ${c} %n版本号: %H %n仓库地址: ${s} %n提交日志: %s" --date=iso`)),r.succeed("分支信息!!!"),r.succeed("😊😊😊")}catch(t){r.fail(e.red(t)),process.exit(1)}}),t.parse(process.argv);