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

背景与动机

在项目开发流程中,代码质量和团队协作是影响项目发版成功的关键因素之一,随着项目规模的扩大、版本的迭代、团队成员的增加,代码库的维护会变得愈发复杂。为此,开发团队常常通过各种工具来进行自动化代码检查、自动化代码格式化等质量控制措施。Git的pre-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 install,make install任务中包含了simple-pre-commit的执行,会往本地项目的.git/hooks中注入pre-commit

  2. 此后,开发者每次在本地进行提交之前都会触发pre-commit钩子,执行make pre-commit,make 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代码语法。

相关推荐
IOT那些事儿4 小时前
Git报错:Could not get HEAD hash
git·hash·head
杜哥无敌7 小时前
Git Bash + acme.sh 实现 SSL 证书自动续签(完整指南)
git·bash·ssl
nunumaymax10 小时前
Git教程
git
阿萨德528号11 小时前
IDEA 项目 SVN 配置消失、版本控制变成 Git 且无 VCS 菜单的解决办法
git·svn·intellij-idea
vipxieliang12 小时前
Go 泛型结构体与约束进阶:从自定义约束到标准库泛型 API 实战
后端·go
R²AIN SUITE14 小时前
项目管理平台怎么和OA、钉钉、飞书、Git仓库打通?从消息通知到双向同步的5种实现路径
git·钉钉·飞书
Demons_kirit1 天前
CTFHub 信息泄露通关笔记:Git泄露 Log - 教程
笔记·git·网络安全
GlobalTradercrb1 天前
独立站SEO先写博客还是先优化产品页?看站点阶段
数据库·人工智能·google·pdf·go·seo
用户125758524361 天前
GoFrame Vue3开源后台管理系统推荐:数据库与Worker要求怎么验
数据库·后端·go
王中阳Go1 天前
面到 harness 架构就卡住的人,多半是做过但没这么叫过
架构·go·agent