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代码语法。

相关推荐
一丝晨光1 小时前
数值溢出保护?数值溢出应该是多少?Swift如何让整数计算溢出不抛出异常?类型最大值和最小值?
java·javascript·c++·rust·go·c·swift
sduwcgg1 小时前
git经验
git
麻雀无能为力2 小时前
git的使用
git
算法歌者5 小时前
Visual Studio 项目 .gitignore 文件指南
git·visual studio
江边垂钓者5 小时前
git cherry-pick和git stash命令详解
git
Lw老王要学习5 小时前
Linux架构篇、第五章git2.49.0部署与使用
linux·运维·git·云计算·it
爱学习的张哥5 小时前
专栏项目框架介绍
git·fpga开发·udp·ddr·gt收发器
Aric_Jones8 小时前
lua入门语法,包含安装,注释,变量,循环等
java·开发语言·git·elasticsearch·junit·lua
Sapphire~14 小时前
odoo-049 Pycharm 中 git stash 后有pyc 文件,如何删除pyc文件
ide·git·pycharm
Willis_m18 小时前
Linux 服务器用 SSH 拉取多个 Git 工程
linux·服务器·git·ssh