simple-pre-commit的设计与golang实现

背景与动机

在项目开发流程中,代码质量和团队协作是影响项目发版成功的关键因素之一,随着项目规模的扩大、版本的迭代、团队成员的增加,代码库的维护会变得愈发复杂。为此,开发团队常常通过各种工具来进行自动化代码检查、自动化代码格式化等质量控制措施。Gitpre-commit hook就是其中一种方案,它要求在本地代码提交之前执行指定的校验任务,确保提交的代码符合团队代码规范、质量标准。本文探讨的是一个简化版的pre-commit钩子设计方案与golang代码实现。

设计

simple-pre-commit的流程为:

  1. 在项目中配置Makefile文件,定义自动化的任务

比如下面这个例子:

sql 复制代码
install:
  go mod tidy
  go install github.com/brenner8023/simple-pre-commit@latest
  simple-pre-commit
test:
  go test --race -v
pre-commit:
  @make test
  1. 要求团队成员在初次将远程仓库拉取到本地后执行make installmake install任务中包含了simple-pre-commit的执行,会往本地项目的.git/hooks中注入pre-commit

  2. 此后,开发者每次在本地进行提交之前都会触发pre-commit钩子,执行make pre-commitmake pre-commit中具体执行哪些任务由团队制定。

实现细节

首先,需要检查项目配置,检查项目是否存在Makefile文件,Makefile文件中是否编写了pre-commit的配置

go 复制代码
func CheckConfig() error {
    // 读取Makefile文件
    file, err := os.Open("Makefile")
    if err != nil {
        return err
    }
    // 用于延迟执行一个函数,直到包含该defer语句的函数返回时才执行。
    // 通常用于确保在函数执行结束时释放资源
    defer file.Close()
    // 编译正则表达式
    preCommitReg := regexp.MustCompile(`^pre-commit\s*:`)
    scanner := bufio.NewScanner(file)
    for scanner.Scan() {
        // 逐行读取内容
        line := scanner.Text()
        // 使用表达式进行匹配
        if preCommitReg.MatchString(line) {
                return nil
        }
    }
    msg := fmt.Sprintf("pre-commit config not found in Makefile")
    return errors.New(msg)
}

找到.git目录

go 复制代码
func GetGitProjectRoot() (string, error) {
    // 从当前工作目录开始查找
    startDir, err := os.Getwd()
    if err != nil {
        return "", err
    }
    parentDir := ""
    for {
        gitDir := filepath.Join(startDir, ".git")
        // 判断是否有.git的信息
        if info, err := os.Stat(gitDir); err == nil && info.IsDir() {
            return startDir, nil
        }
        // 找不到就往上一级找
        parentDir = filepath.Dir(startDir)
        if startDir == parentDir {
            msg := fmt.Sprintf(".git folder not found")
            return "", errors.New(msg)
        }
        startDir = parentDir
    }
}

创建pre-commit文件并往该文件写入内容

go 复制代码
func SetHook(gitRoot string) error {
    hookFile := filepath.Join(gitRoot, ".git", "hooks", "pre-commit")
    command := `make pre-commit`
    // 创建pre-commit文件,若文件已存在,文件内容会被清空
    file, err := os.Create(hookFile)
    if err != nil {
        return err
    }
    defer file.Close()
    // 写入任务指令
    _, err = file.WriteString(command)
    if err != nil {
        return err
    }
    err = os.Chmod(hookFile, 0755)
    if err != nil {
        return err
    }
    msg := fmt.Sprintf("%s: Successfully set git hooks", APP_NAME)
    fmt.Println(msg)
    return nil
}

总结

simple-pre-commit是一个轻量级的Git pre-commit钩子管理工具,旨在通过简单的Makefile配置,帮助开发团队在本地代码提交前进行自动化检查,读者可以通过本文了解基本的Git hook工作原理,学习到基本的golang代码语法。

相关推荐
程序员爱钓鱼10 小时前
Go语言实战案例 — 工具开发篇:实现一个图片批量压缩工具
后端·google·go
雁于飞11 小时前
vscode中使用git、githup的基操
笔记·git·vscode·学习·elasticsearch·gitee·github
郭京京21 小时前
goweb内置的 net/http 包
后端·go
dylan_QAQ21 小时前
Java转Go全过程06-工程管理
java·后端·go
小毛驴85021 小时前
所有微服务部署都使用一个git地址,并且通过docker部署各个服务的情况下,如何编写mvn指令来处理各个服务。
git·docker·微服务
国王不在家21 小时前
git 切换仓库后清理分支缓存
git
lypzcgf1 天前
Coze源码分析-资源库-删除插件-后端源码-错误处理与总结
人工智能·后端·go·coze·coze源码分析·ai应用平台·agent平台
柯南二号1 天前
【Gitlab】Ubuntu 20.04服务器部署Gitlab
git·gitlab
lypzcgf1 天前
Coze源码分析-资源库-删除插件-后端源码-应用和领域服务层
后端·go·coze·coze插件·coze源码分析·智能体平台·ai应用平台
phac1231 天前
git 如何直接拉去远程仓库的内容且忽略本地与远端不一致的commit
大数据·git·elasticsearch