Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rewrite pre-commit, post-commit and options hooks (fixes #1250) #1257

Merged
merged 7 commits into from
Mar 23, 2017
2 changes: 2 additions & 0 deletions models/migrations/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ var migrations = []Migration{
NewMigration("change the key_id and primary_key_id type", changeGPGKeysColumns),
// v25 -> v26
NewMigration("add show field in user openid table", addUserOpenIDShow),
// v26 -> v27
NewMigration("generate and migrate repo and wiki Git hooks", generateAndMigrateGitHookChains),
}

// Migrate database to current version
Expand Down
87 changes: 87 additions & 0 deletions models/migrations/v26.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Copyright 2017 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package migrations
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment header


import (
"crypto/md5"
"encoding/hex"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"

"code.gitea.io/gitea/modules/setting"

"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
)

func generateAndMigrateGitHookChains(x *xorm.Engine) (err error) {
type Repository struct {
ID int64
OwnerID int64
Name string
}
type User struct {
ID int64
Name string
}

var (
hookNames = []string{"pre-receive", "update", "post-receive"}
hookTpl = fmt.Sprintf("#!/usr/bin/env %s\ndata=$(cat)\nexitcodes=\"\"\nhookname=$(basename $0)\nGIT_DIR=${GIT_DIR:-$(dirname $0)}\n\nfor hook in ${GIT_DIR}/hooks/${hookname}.d/*; do\ntest -x \"${hook}\" || continue\necho \"${data}\" | \"${hook}\"\nexitcodes=\"${exitcodes} $?\"\ndone\n\nfor i in ${exitcodes}; do\n[ ${i} -eq 0 ] || exit ${i}\ndone\n", setting.ScriptType)
)

return x.Where("id > 0").Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
user := new(User)
has, err := x.Where("id = ?", repo.OwnerID).Get(user)
if err != nil {
return fmt.Errorf("query owner of repository [repo_id: %d, owner_id: %d]: %v", repo.ID, repo.OwnerID, err)
} else if !has {
return nil
}

repoPaths := []string{
filepath.Join(setting.RepoRootPath, strings.ToLower(user.Name), strings.ToLower(repo.Name)) + ".git",
filepath.Join(setting.RepoRootPath, strings.ToLower(user.Name), strings.ToLower(repo.Name)) + ".wiki.git",
}

for _, repoPath := range repoPaths {
if com.IsExist(repoPath) {
hookDir := filepath.Join(repoPath, "hooks")

for _, hookName := range hookNames {
oldHookPath := filepath.Join(hookDir, hookName)

// compare md5sums of hooks
if com.IsExist(oldHookPath) {

f, err := os.Open(oldHookPath)
if err != nil {
return fmt.Errorf("cannot open old hook file '%s': %v", oldHookPath, err)
}
defer f.Close()
h := md5.New()
if _, err := io.Copy(h, f); err != nil {
return fmt.Errorf("cannot read old hook file '%s': %v", oldHookPath, err)
}
if hex.EncodeToString(h.Sum(nil)) == "6718ef67d0834e0a7908259acd566e3f" {
return nil
}
}

if err = ioutil.WriteFile(oldHookPath, []byte(hookTpl), 0777); err != nil {
return fmt.Errorf("write old hook file '%s': %v", oldHookPath, err)
}
}
}
}
return nil
})
}
13 changes: 7 additions & 6 deletions models/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -845,11 +845,7 @@ func cleanUpMigrateGitConfig(configPath string) error {
func createDelegateHooks(repoPath string) (err error) {
var (
hookNames = []string{"pre-receive", "update", "post-receive"}
hookTpls = []string{
fmt.Sprintf("#!/usr/bin/env %s\nORI_DIR=`pwd`\nSHELL_FOLDER=$(cd \"$(dirname \"$0\")\";pwd)\ncd \"$ORI_DIR\"\nfor i in `ls \"$SHELL_FOLDER/pre-receive.d\"`; do\n sh \"$SHELL_FOLDER/pre-receive.d/$i\"\ndone", setting.ScriptType),
fmt.Sprintf("#!/usr/bin/env %s\nORI_DIR=`pwd`\nSHELL_FOLDER=$(cd \"$(dirname \"$0\")\";pwd)\ncd \"$ORI_DIR\"\nfor i in `ls \"$SHELL_FOLDER/update.d\"`; do\n sh \"$SHELL_FOLDER/update.d/$i\" $1 $2 $3\ndone", setting.ScriptType),
fmt.Sprintf("#!/usr/bin/env %s\nORI_DIR=`pwd`\nSHELL_FOLDER=$(cd \"$(dirname \"$0\")\";pwd)\ncd \"$ORI_DIR\"\nfor i in `ls \"$SHELL_FOLDER/post-receive.d\"`; do\n sh \"$SHELL_FOLDER/post-receive.d/$i\"\ndone", setting.ScriptType),
}
hookTpl = fmt.Sprintf("#!/usr/bin/env %s\ndata=$(cat)\nexitcodes=\"\"\nhookname=$(basename $0)\nGIT_DIR=${GIT_DIR:-$(dirname $0)}\n\nfor hook in ${GIT_DIR}/hooks/${hookname}.d/*; do\ntest -x \"${hook}\" || continue\necho \"${data}\" | \"${hook}\"\nexitcodes=\"${exitcodes} $?\"\ndone\n\nfor i in ${exitcodes}; do\n[ ${i} -eq 0 ] || exit ${i}\ndone\n", setting.ScriptType)
giteaHookTpls = []string{
fmt.Sprintf("#!/usr/bin/env %s\n\"%s\" hook --config='%s' pre-receive\n", setting.ScriptType, setting.AppPath, setting.CustomConf),
fmt.Sprintf("#!/usr/bin/env %s\n\"%s\" hook --config='%s' update $1 $2 $3\n", setting.ScriptType, setting.AppPath, setting.CustomConf),
Expand All @@ -868,7 +864,7 @@ func createDelegateHooks(repoPath string) (err error) {
}

// WARNING: This will override all old server-side hooks
if err = ioutil.WriteFile(oldHookPath, []byte(hookTpls[i]), 0777); err != nil {
if err = ioutil.WriteFile(oldHookPath, []byte(hookTpl), 0777); err != nil {
return fmt.Errorf("write old hook file '%s': %v", oldHookPath, err)
}

Expand Down Expand Up @@ -1909,6 +1905,11 @@ func SyncRepositoryHooks() error {
if err := createDelegateHooks(bean.(*Repository).RepoPath()); err != nil {
return fmt.Errorf("SyncRepositoryHook: %v", err)
}
if bean.(*Repository).HasWiki() {
if err := createDelegateHooks(bean.(*Repository).WikiPath()); err != nil {
return fmt.Errorf("SyncRepositoryHook: %v", err)
}
}
return nil
})
}
Expand Down