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

相关推荐
小慧10248 分钟前
1.2 git使用
git
m0_635647485 小时前
git管理github上的repository(二)
git·github
qqxhb8 小时前
零基础设计模式——行为型模式 - 命令模式
java·设计模式·go·命令模式
今夕节度使11 小时前
通过 VS Code 连接 GitLab 并上传项目
git·elasticsearch·gitlab
陈 洪 伟11 小时前
复习Git命令、Git命令使用流程、VSCode+Git插件管理工程源码
git
用户289881806664212 小时前
Sarama消费组初始化阻塞问题排查
后端·go
qqxhb13 小时前
零基础设计模式——行为型模式 - 迭代器模式
java·设计模式·go·迭代器模式
Brian Xia13 小时前
Jaeger开源分布式追踪平台深度剖析(三)Jaeger默认存储Badger原理剖析
分布式·go·lsm-tree
百锦再13 小时前
Git 使用大全:从入门到精通
git·version·版本·代码·分支·code·clone