任务详情
收集相关文档
- 搜索了解git钩子相关内容 git钩子-官方文档
- pre-receive钩子配置参考钩子配置
整理与需求相关的钩子配置
- 说明pre-receive: 是服务端保存push内容前,执行的脚本或程序,当程序中返回的推出码非0,服务端将不接受客户端的推送。
- 两种配置钩子方式:
- 通过git config设置init.templateDir
- 使用的是每个仓库.git/hooks目录下的钩子
- 在仓库初始化的时候,从init.templateDir去拷贝hook到当前初始化的仓库(更详细的文档可以查看)
- 通过git config设置core.hooksPath(服务端配置pre-receive推荐使用这个)
- 所有仓库使用的是core.hooksPath全局设定钩子的路径
- 当单独仓库使用本地或其他的hooks可以设置loacl级别的core.hooksPath路径来替代全局的设置
- 通过git config设置init.templateDir
- 配置内容(控制提交的内容不超过100M)
- 在pre-receive.sample中添加
totalSize=$(du -sm|awk '{print $1}')
[ $totalSize -gt 100 ] && echo "can not push exceed 100M file to this depository" && exit 2
- 重命名pre-receive.sample为pre-receive,并确保文件的权限为0755即可
http://t4.uninote.com.cn gogs上实现
- 向gogs app.ini中添加配置内容
[repository.upload] \n FILE_MAX_SIZE = 300
注意换行,修改配置后重启gogs - 在仓库中添加git 钩子内容(totalSize=$(du -sm|awk '{print $1}')[ $totalSize -gt 100 ] && echo "can not push exceed 100M file to this depository" && exit 2) http://t4.uninote.com.cn:3000/5716/5716/settings/hooks/git/pre-receive
- 注册账号lg 123456
- git clone http://t4.uninote.com.cn:3000/5716/5716.git 到本地
- 添加100M以上文件到仓库push
优化实现
上面的方式虽然能实现对仓库总大小的限制,但是显得比较繁琐,因为要对每个仓库的钩子设定相同的pre-receive内容。 分析源码,看看能不能所有仓库实现统一git钩子。
- clone gogs源码分析
// 同步钩子接口部分内容
// /admin组接口
m.Group("/admin", func() {
m.Combo("").Get(admin.Dashboard).Post(admin.Operation)
...
}
// handler函数
func Operation(c *context.Context) {
switch AdminOperation(c.QueryInt("op")){
...
// 同步githooks case
case SyncRepositoryHooks:
success = c.Tr("admin.dashboard.resync_all_hooks_success")
// 同步hooks函数
err = db.SyncRepositoryHooks()
...
}
}
func SyncRepositoryHooks() error {
// 从repository中查询id>0的所有仓库
return x.Where("id > 0").Iterate(new(Repository),
// 对每个仓库的操作
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
// 0. 1~3步骤都是在拼凑hookPath
// 1. 获取仓库的拥有者
// 2. conf.Repository.Root,username+repoName+“.git”组成RepoPath
// 3. 遍历git.ServerSideHooks的三个git服务端钩子,组成hookPath=RepoPath+hookName
// 4. 向hookPath中写入内容,这里的内容是写死的,意思是调用接口钩子的时候手动执行gogs hook --config=/app.ini pre-receive
/*
"pre-receive": "#!/usr/bin/env %s\n\"%s\" hook --config='%s' pre-receive\n",
"update": "#!/usr/bin/env %s\n\"%s\" hook --config='%s' update $1 $2 $3\n",
"post-receive": "#!/usr/bin/env %s\n\"%s\" hook --config='%s' post-receive\n",
*/
// 同步的hook只是执行了用户设定的customPath路径下的hook
if err := createDelegateHooks(repo.RepoPath()); err != nil {
return err
}
...
return nil
})
}
// gogs命令与钩子相关的源码分析
if !com.IsFile(customHooksPath) {
return nil
}
var hookCmd *exec.Cmd
if conf.IsWindowsRuntime() {
hookCmd = exec.Command("bash.exe", "custom_hooks/pre-receive")
} else {
// 最终执行的也是customHooksPath下的钩子。。。。
hookCmd = exec.Command(customHooksPath)
}
hookCmd.Dir = db.RepoPath(os.Getenv(db.ENV_REPO_OWNER_NAME), os.Getenv(db.ENV_REPO_NAME))
hookCmd.Stdout = os.Stdout
hookCmd.Stdin = buf
hookCmd.Stderr = os.Stderr
if err := hookCmd.Run(); err != nil {
fail("Internal error", "Failed to execute custom pre-receive hook: %v", err)
}
-
按源码分析,不能实现统一hook的配置(hookPath下的钩子内容是写死的,如果统一实现得改源码写死的那部分代码,再打包才行)
-
gogs githook源码分析简单总结三点
customPath下的githook是手动指定的
hookPath路径下的hook是管理员账号通过http请求同步的
gogs的githook存放在customPath和hookPath这两个路径下,hookPath通过命令调用了customPath路径下的git hook执行