当前位置: 首页 > Web前端 > JavaScript

使用husky实现前端项目自定义规范验证

时间:2023-03-26 22:39:12 JavaScript

提交bug修复时容易忘记同步调整版本号。如果漏掉了,很容易造成漏更新等问题,所以打算修改版本号,做一个硬性的检测规范。实现效果类似于ESlint的检测。Git在提交后自动执行代码检测。如果不符合规范,则会报错并撤回提交。分析主要需要解决以下几个问题:触发检测的方式既然想到了ESlint,首先想到的就是给ESlint添加一个自定义的插件。但是仔细一想,因为检测的是非JavaScript文件,并不是对代码进行逻辑检测,只是在提交前检查相应的文件是否被修改过,其实不是很合适设想。最合适的是直接使用Githooks。ESlint使用husky调用相关钩子中的检测。之前写过一个husky7+commitlint+lint-staged的记录,所以流程比较熟悉。你只需要在.husky文件夹下添加相关钩子名称的文件,然后直接编写shell脚本即可启动。简单的脚本不利于维护,所以打算像ESlint一样写成命令行,也方便后面添加功能。如何知道文件的变化是Git的一个内置功能。你只需要用gitdiff来比较package.json文件,就会输出比较信息。但是文本不好解析,一下子找不到相关的插件,于是用peggy写了一个相关的解析器,将文本转成便于解析的json数据。提交失败后,终止shell脚本的提交,成功返回0,失败返回非0。Node.js提供了一个相关的方法process.exit(1)。如果有不明白的方法,其实翻遍lint-staged也能找到自己需要的答案,毕竟那里有现成的例子。提供一种主动绕过提交的方法。既然是加在hook上的,一定不要把hook删了,不需要的时候再提交。那只能在提交逻辑中做跳过检测。最合适的是在提交消息的正文中携带指定的关键字,当程序识别到关键字时,可以跳过检测逻辑。关键逻辑提供了一个命令行调用命令,创建一个空项目,添加一个bin字段,在我们的程序中添加一个相关的调用命令“bin”:{"check":"./dist/index.js"}对应check是命令行对应的值是要执行的JavaScript文件:#!/usr/bin/envnodeconsole.log('hello')这样就可以打印出hello了。当然,这还不够。命令行程序还可以携带参数或其他功能,可以配合Commander.js辅助处理命令行命令。由于是和业务代码一起写的,只能举个粗略的例子:import{Command}from"commander";constprogram=newCommand();program.command("change").option("--commitMsgPath","commitmessage包含指定字符串时跳过当前命令检测").description("检查版本号是否发生变化").action(async({commitMsgPath}:{commitMsgPath:string})=>{try{letmsg:string[];if(commitMsgPath)msg??=readGitMessage(commitMsgPath);constflag=awaitcheckVersion(msg);if(!flag)thrownewError("提交前请修改版本号");}catch(e){console.error(`${DATA.NAME}:${e.name}${e.message}`);process.exit(1);}});程序.parse(process.argv);调用gitdiff判断数据,执行git命令。可以使用simple-git库,功能丰富,可惜diff返回的数据是纯文本,不方便处理。使用之前编写的简单diff格式解析器将其处理成可读的json数据。剩下的就很简单了。将返回的diff数据传入解析器,然后判断解析器中是否有对应的关键字版本。如果有,说明修改了版本号。如有需要,可做更详细的版本编号核对。importsimpleGit,{SimpleGit}from"simple-git";constGitDiffParser=require("../lib/gitDiffParser");/***检查版本号是否改变*@parammsg*/exportconstcheckVersion=async(msg?:string[])=>{letflag=false;constgit:SimpleGit=simpleGit({baseDir:process.cwd(),binary:"git",});//检查git消息中是否有指定文本然后跳过版本检测if(msg&&msg.some((item)=>item===DATA.SKIP_MESSAGE_KEY))returntrue;//判断版本号是否发生变化constdiff=awaitgit.diff(["--cached","package.json"]);if(diff){constresult=(GitDiffParser.parse(diff,{REMOVE_INDENT:true}));result.change.forEach((item)=>{item.content.forEach((content)=>{if(content.type==="+"&&content.text.includes(`"version"`))标志=真;});});返回标志;}返回标志;};检测message的方式和提供skippingdetection的方法本来是写在pre-commithook里的,但是查了好几个git命令获取message,都没有办法获取到当前的message。所以只能切换到commit-msghook,通过$1变量获取消息。而且返回的不是消息的正文,而是消息的文件路径,所以需要自己去读取文件内容。/***读取gitmessage消息文件*/exportconstreadGitMessage=(filePath:string)=>{try{constmsg:string=fs.readFileSync(path.join(process.cwd(),filePath),"utf-8");返回msg.split(/\s/).filter((item)=>item);}catch(e){返回未定义;}};这个是在checkVersion过程中调用的,与预定的key进行比较,如果相同则直接返回true,从而跳过了版本检测逻辑。项目中添加commit-msg脚本,可以直接通过npx调用command执行检测逻辑。message地址作为参数传入command(前面.option("--commitMsgPath","commitmessage包含指定字符串时跳过当前命令检测"配置的参数)#!/bin/sh."$(dirname"$0")/_/husky.sh"npxcommitlint--edit"$1"npxcheckchange--commitMsgPath"$1"