aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLunny Xiao <xiaolunwen@gmail.com>2017-02-25 22:54:40 +0800
committerGitHub <noreply@github.com>2017-02-25 22:54:40 +0800
commitcd1821a7e292b05e04fcc2a969b42d06ab512849 (patch)
tree084f97bfb24a37ec3028d15fdacb51e86cfcc368
parente8e56da9ac321aacb3c06968997a45c2f133cd4e (diff)
downloadgitea-cd1821a7e292b05e04fcc2a969b42d06ab512849.tar.gz
gitea-cd1821a7e292b05e04fcc2a969b42d06ab512849.zip
Move push update to post-receive and protected branch check to pre-receive (#1030)
* move all push update to git hook post-receive and protected branch check to git hook pre-receive * add SSH_ORIGINAL_COMMAND check back * remove all unused codes * fix the import
-rw-r--r--cmd/hook.go135
-rw-r--r--cmd/serv.go76
-rw-r--r--cmd/update.go83
-rw-r--r--main.go1
-rw-r--r--models/fixtures/update_task.yml20
-rw-r--r--models/models.go2
-rw-r--r--models/update.go43
-rw-r--r--models/update_test.go34
-rw-r--r--routers/repo/http.go196
9 files changed, 175 insertions, 415 deletions
diff --git a/cmd/hook.go b/cmd/hook.go
index 15ad74f8e0..a89c3741bf 100644
--- a/cmd/hook.go
+++ b/cmd/hook.go
@@ -5,11 +5,22 @@
package cmd
import (
+ "bufio"
+ "bytes"
+ "crypto/tls"
"fmt"
"os"
+ "strconv"
+ "strings"
+ "code.gitea.io/git"
"code.gitea.io/gitea/models"
+ "code.gitea.io/gitea/modules/base"
+ "code.gitea.io/gitea/modules/httplib"
+ "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/setting"
+ "github.com/Unknwon/com"
"github.com/urfave/cli"
)
@@ -57,10 +68,59 @@ func runHookPreReceive(c *cli.Context) error {
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
return nil
}
+
if err := setup("hooks/pre-receive.log"); err != nil {
fail("Hook pre-receive init failed", fmt.Sprintf("setup: %v", err))
}
+ // the environment setted on serv command
+ repoID, _ := strconv.ParseInt(os.Getenv(models.ProtectedBranchRepoID), 10, 64)
+ isWiki := (os.Getenv(models.EnvRepoIsWiki) == "true")
+
+ buf := bytes.NewBuffer(nil)
+ scanner := bufio.NewScanner(os.Stdin)
+ for scanner.Scan() {
+ buf.Write(scanner.Bytes())
+ buf.WriteByte('\n')
+
+ // TODO: support news feeds for wiki
+ if isWiki {
+ continue
+ }
+
+ fields := bytes.Fields(scanner.Bytes())
+ if len(fields) != 3 {
+ continue
+ }
+
+ oldCommitID := string(fields[0])
+ newCommitID := string(fields[1])
+ refFullName := string(fields[2])
+
+ branchName := strings.TrimPrefix(refFullName, git.BranchPrefix)
+ protectBranch, err := models.GetProtectedBranchBy(repoID, branchName)
+ if err != nil {
+ log.GitLogger.Fatal(2, "retrieve protected branches information failed")
+ }
+
+ if protectBranch != nil {
+ fail(fmt.Sprintf("protected branch %s can not be pushed to", branchName), "")
+ }
+
+ // check and deletion
+ if newCommitID == git.EmptySHA {
+ fail(fmt.Sprintf("Branch '%s' is protected from deletion", branchName), "")
+ }
+
+ // Check force push
+ output, err := git.NewCommand("rev-list", oldCommitID, "^"+newCommitID).Run()
+ if err != nil {
+ fail("Internal error", "Fail to detect force push: %v", err)
+ } else if len(output) > 0 {
+ fail(fmt.Sprintf("Branch '%s' is protected from force push", branchName), "")
+ }
+ }
+
return nil
}
@@ -73,23 +133,6 @@ func runHookUpdate(c *cli.Context) error {
fail("Hook update init failed", fmt.Sprintf("setup: %v", err))
}
- args := c.Args()
- if len(args) != 3 {
- fail("Arguments received are not equal to three", "Arguments received are not equal to three")
- } else if len(args[0]) == 0 {
- fail("First argument 'refName' is empty", "First argument 'refName' is empty")
- }
-
- uuid := os.Getenv(envUpdateTaskUUID)
- if err := models.AddUpdateTask(&models.UpdateTask{
- UUID: uuid,
- RefName: args[0],
- OldCommitID: args[1],
- NewCommitID: args[2],
- }); err != nil {
- fail("Internal error", "Fail to add update task '%s': %v", uuid, err)
- }
-
return nil
}
@@ -102,5 +145,63 @@ func runHookPostReceive(c *cli.Context) error {
fail("Hook post-receive init failed", fmt.Sprintf("setup: %v", err))
}
+ // the environment setted on serv command
+ repoUser := os.Getenv(models.EnvRepoUsername)
+ repoUserSalt := os.Getenv(models.EnvRepoUserSalt)
+ isWiki := (os.Getenv(models.EnvRepoIsWiki) == "true")
+ repoName := os.Getenv(models.EnvRepoName)
+ pusherID, _ := strconv.ParseInt(os.Getenv(models.EnvPusherID), 10, 64)
+ pusherName := os.Getenv(models.EnvPusherName)
+
+ buf := bytes.NewBuffer(nil)
+ scanner := bufio.NewScanner(os.Stdin)
+ for scanner.Scan() {
+ buf.Write(scanner.Bytes())
+ buf.WriteByte('\n')
+
+ // TODO: support news feeds for wiki
+ if isWiki {
+ continue
+ }
+
+ fields := bytes.Fields(scanner.Bytes())
+ if len(fields) != 3 {
+ continue
+ }
+
+ oldCommitID := string(fields[0])
+ newCommitID := string(fields[1])
+ refFullName := string(fields[2])
+
+ if err := models.PushUpdate(models.PushUpdateOptions{
+ RefFullName: refFullName,
+ OldCommitID: oldCommitID,
+ NewCommitID: newCommitID,
+ PusherID: pusherID,
+ PusherName: pusherName,
+ RepoUserName: repoUser,
+ RepoName: repoName,
+ }); err != nil {
+ log.GitLogger.Error(2, "Update: %v", err)
+ }
+
+ // Ask for running deliver hook and test pull request tasks.
+ reqURL := setting.LocalURL + repoUser + "/" + repoName + "/tasks/trigger?branch=" +
+ strings.TrimPrefix(refFullName, git.BranchPrefix) + "&secret=" + base.EncodeMD5(repoUserSalt) + "&pusher=" + com.ToStr(pusherID)
+ log.GitLogger.Trace("Trigger task: %s", reqURL)
+
+ resp, err := httplib.Head(reqURL).SetTLSClientConfig(&tls.Config{
+ InsecureSkipVerify: true,
+ }).Response()
+ if err == nil {
+ resp.Body.Close()
+ if resp.StatusCode/100 != 2 {
+ log.GitLogger.Error(2, "Failed to trigger task: not 2xx response code")
+ }
+ } else {
+ log.GitLogger.Error(2, "Failed to trigger task: %v", err)
+ }
+ }
+
return nil
}
diff --git a/cmd/serv.go b/cmd/serv.go
index 141a58a2ac..5b1caf4d34 100644
--- a/cmd/serv.go
+++ b/cmd/serv.go
@@ -6,7 +6,6 @@
package cmd
import (
- "crypto/tls"
"encoding/json"
"fmt"
"os"
@@ -15,22 +14,17 @@ import (
"strings"
"time"
- "code.gitea.io/git"
"code.gitea.io/gitea/models"
- "code.gitea.io/gitea/modules/base"
- "code.gitea.io/gitea/modules/httplib"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"github.com/Unknwon/com"
"github.com/dgrijalva/jwt-go"
- gouuid "github.com/satori/go.uuid"
"github.com/urfave/cli"
)
const (
accessDenied = "Repository does not exist or you do not have access"
lfsAuthenticateVerb = "git-lfs-authenticate"
- envUpdateTaskUUID = "GITEA_UUID"
)
// CmdServ represents the available serv sub-command.
@@ -96,52 +90,6 @@ func fail(userMessage, logMessage string, args ...interface{}) {
os.Exit(1)
}
-func handleUpdateTask(uuid string, user, repoUser *models.User, reponame string, isWiki bool) {
- task, err := models.GetUpdateTaskByUUID(uuid)
- if err != nil {
- if models.IsErrUpdateTaskNotExist(err) {
- log.GitLogger.Trace("No update task is presented: %s", uuid)
- return
- }
- log.GitLogger.Fatal(2, "GetUpdateTaskByUUID: %v", err)
- } else if err = models.DeleteUpdateTaskByUUID(uuid); err != nil {
- log.GitLogger.Fatal(2, "DeleteUpdateTaskByUUID: %v", err)
- }
-
- if isWiki {
- return
- }
-
- if err = models.PushUpdate(models.PushUpdateOptions{
- RefFullName: task.RefName,
- OldCommitID: task.OldCommitID,
- NewCommitID: task.NewCommitID,
- PusherID: user.ID,
- PusherName: user.Name,
- RepoUserName: repoUser.Name,
- RepoName: reponame,
- }); err != nil {
- log.GitLogger.Error(2, "Update: %v", err)
- }
-
- // Ask for running deliver hook and test pull request tasks.
- reqURL := setting.LocalURL + repoUser.Name + "/" + reponame + "/tasks/trigger?branch=" +
- strings.TrimPrefix(task.RefName, git.BranchPrefix) + "&secret=" + base.EncodeMD5(repoUser.Salt) + "&pusher=" + com.ToStr(user.ID)
- log.GitLogger.Trace("Trigger task: %s", reqURL)
-
- resp, err := httplib.Head(reqURL).SetTLSClientConfig(&tls.Config{
- InsecureSkipVerify: true,
- }).Response()
- if err == nil {
- resp.Body.Close()
- if resp.StatusCode/100 != 2 {
- log.GitLogger.Error(2, "Failed to trigger task: not 2xx response code")
- }
- } else {
- log.GitLogger.Error(2, "Failed to trigger task: %v", err)
- }
-}
-
func runServ(c *cli.Context) error {
if c.IsSet("config") {
setting.CustomConf = c.String("config")
@@ -187,6 +135,7 @@ func runServ(c *cli.Context) error {
if len(rr) != 2 {
fail("Invalid repository path", "Invalid repository path: %v", args)
}
+
username := strings.ToLower(rr[0])
reponame := strings.ToLower(strings.TrimSuffix(rr[1], ".git"))
@@ -196,6 +145,14 @@ func runServ(c *cli.Context) error {
reponame = reponame[:len(reponame)-5]
}
+ os.Setenv(models.EnvRepoUsername, username)
+ if isWiki {
+ os.Setenv(models.EnvRepoIsWiki, "true")
+ } else {
+ os.Setenv(models.EnvRepoIsWiki, "false")
+ }
+ os.Setenv(models.EnvRepoName, reponame)
+
repoUser, err := models.GetUserByName(username)
if err != nil {
if models.IsErrUserNotExist(err) {
@@ -204,6 +161,8 @@ func runServ(c *cli.Context) error {
fail("Internal error", "Failed to get repository owner (%s): %v", username, err)
}
+ os.Setenv(models.EnvRepoUserSalt, repoUser.Salt)
+
repo, err := models.GetRepositoryByName(repoUser.ID, reponame)
if err != nil {
if models.IsErrRepoNotExist(err) {
@@ -286,7 +245,8 @@ func runServ(c *cli.Context) error {
user.Name, requestedMode, repoPath)
}
- os.Setenv("GITEA_PUSHER_NAME", user.Name)
+ os.Setenv(models.EnvPusherName, user.Name)
+ os.Setenv(models.EnvPusherID, fmt.Sprintf("%d", user.ID))
}
}
@@ -323,11 +283,6 @@ func runServ(c *cli.Context) error {
return nil
}
- uuid := gouuid.NewV4().String()
- os.Setenv(envUpdateTaskUUID, uuid)
- // Keep the old env variable name for backward compability
- os.Setenv("uuid", uuid)
-
// Special handle for Windows.
if setting.IsWindows {
verb = strings.Replace(verb, "-", " ", 1)
@@ -341,7 +296,6 @@ func runServ(c *cli.Context) error {
gitcmd = exec.Command(verb, repoPath)
}
- os.Setenv(models.ProtectedBranchAccessMode, requestedMode.String())
os.Setenv(models.ProtectedBranchRepoID, fmt.Sprintf("%d", repo.ID))
gitcmd.Dir = setting.RepoRootPath
@@ -352,10 +306,6 @@ func runServ(c *cli.Context) error {
fail("Internal error", "Failed to execute git command: %v", err)
}
- if requestedMode == models.AccessModeWrite {
- handleUpdateTask(uuid, user, repoUser, reponame, isWiki)
- }
-
// Update user key activity.
if keyID > 0 {
key, err := models.GetPublicKeyByID(keyID)
diff --git a/cmd/update.go b/cmd/update.go
deleted file mode 100644
index 58e60493d0..0000000000
--- a/cmd/update.go
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2014 The Gogs 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 cmd
-
-import (
- "os"
- "strconv"
- "strings"
-
- "github.com/urfave/cli"
-
- "code.gitea.io/git"
- "code.gitea.io/gitea/models"
- "code.gitea.io/gitea/modules/log"
- "code.gitea.io/gitea/modules/setting"
-)
-
-// CmdUpdate represents the available update sub-command.
-var CmdUpdate = cli.Command{
- Name: "update",
- Usage: "This command should only be called by Git hook",
- Description: `Update get pushed info and insert into database`,
- Action: runUpdate,
- Flags: []cli.Flag{
- cli.StringFlag{
- Name: "config, c",
- Value: "custom/conf/app.ini",
- Usage: "Custom configuration file path",
- },
- },
-}
-
-func runUpdate(c *cli.Context) error {
- if c.IsSet("config") {
- setting.CustomConf = c.String("config")
- }
-
- setup("update.log")
-
- if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
- log.GitLogger.Trace("SSH_ORIGINAL_COMMAND is empty")
- return nil
- }
-
- args := c.Args()
- if len(args) != 3 {
- log.GitLogger.Fatal(2, "Arguments received are not equal to three")
- } else if len(args[0]) == 0 {
- log.GitLogger.Fatal(2, "First argument 'refName' is empty, shouldn't use")
- }
-
- // protected branch check
- branchName := strings.TrimPrefix(args[0], git.BranchPrefix)
- repoID, _ := strconv.ParseInt(os.Getenv(models.ProtectedBranchRepoID), 10, 64)
- log.GitLogger.Trace("pushing to %d %v", repoID, branchName)
- accessMode := models.ParseAccessMode(os.Getenv(models.ProtectedBranchAccessMode))
- // skip admin or owner AccessMode
- if accessMode == models.AccessModeWrite {
- protectBranch, err := models.GetProtectedBranchBy(repoID, branchName)
- if err != nil {
- log.GitLogger.Fatal(2, "retrieve protected branches information failed")
- }
-
- if protectBranch != nil {
- log.GitLogger.Fatal(2, "protected branches can not be pushed to")
- }
- }
-
- task := models.UpdateTask{
- UUID: os.Getenv("GITEA_UUID"),
- RefName: args[0],
- OldCommitID: args[1],
- NewCommitID: args[2],
- }
-
- if err := models.AddUpdateTask(&task); err != nil {
- log.GitLogger.Fatal(2, "AddUpdateTask: %v", err)
- }
-
- return nil
-}
diff --git a/main.go b/main.go
index b7e8244b4b..6576bf3e89 100644
--- a/main.go
+++ b/main.go
@@ -40,5 +40,4 @@ func main() {
if err != nil {
log.Fatal(4, "Failed to run app with %s: %v", os.Args, err)
}
-
}
diff --git a/models/fixtures/update_task.yml b/models/fixtures/update_task.yml
deleted file mode 100644
index ffcd5fd6fa..0000000000
--- a/models/fixtures/update_task.yml
+++ /dev/null
@@ -1,20 +0,0 @@
--
- id: 1
- uuid: uuid1
- ref_name: refName1
- old_commit_id: oldCommitId1
- new_commit_id: newCommitId1
-
--
- id: 2
- uuid: uuid2
- ref_name: refName2
- old_commit_id: oldCommitId2
- new_commit_id: newCommitId2
-
--
- id: 3
- uuid: uuid3
- ref_name: refName3
- old_commit_id: oldCommitId3
- new_commit_id: newCommitId3
diff --git a/models/models.go b/models/models.go
index 0840b4600e..29428dba04 100644
--- a/models/models.go
+++ b/models/models.go
@@ -100,7 +100,6 @@ func init() {
new(Release),
new(LoginSource),
new(Webhook),
- new(UpdateTask),
new(HookTask),
new(Team),
new(OrgUser),
@@ -316,7 +315,6 @@ func GetStatistic() (stats Statistic) {
stats.Counter.Label, _ = x.Count(new(Label))
stats.Counter.HookTask, _ = x.Count(new(HookTask))
stats.Counter.Team, _ = x.Count(new(Team))
- stats.Counter.UpdateTask, _ = x.Count(new(UpdateTask))
stats.Counter.Attachment, _ = x.Count(new(Attachment))
return
}
diff --git a/models/update.go b/models/update.go
index 677a9bda31..3cb0608594 100644
--- a/models/update.go
+++ b/models/update.go
@@ -15,40 +15,15 @@ import (
"code.gitea.io/gitea/modules/log"
)
-// UpdateTask defines an UpdateTask
-type UpdateTask struct {
- ID int64 `xorm:"pk autoincr"`
- UUID string `xorm:"index"`
- RefName string
- OldCommitID string
- NewCommitID string
-}
-
-// AddUpdateTask adds an UpdateTask
-func AddUpdateTask(task *UpdateTask) error {
- _, err := x.Insert(task)
- return err
-}
-
-// GetUpdateTaskByUUID returns update task by given UUID.
-func GetUpdateTaskByUUID(uuid string) (*UpdateTask, error) {
- task := &UpdateTask{
- UUID: uuid,
- }
- has, err := x.Get(task)
- if err != nil {
- return nil, err
- } else if !has {
- return nil, ErrUpdateTaskNotExist{uuid}
- }
- return task, nil
-}
-
-// DeleteUpdateTaskByUUID deletes an UpdateTask from the database
-func DeleteUpdateTaskByUUID(uuid string) error {
- _, err := x.Delete(&UpdateTask{UUID: uuid})
- return err
-}
+// env keys for git hooks need
+const (
+ EnvRepoName = "GITEA_REPO_NAME"
+ EnvRepoUsername = "GITEA_REPO_USER_NAME"
+ EnvRepoUserSalt = "GITEA_REPO_USER_SALT"
+ EnvRepoIsWiki = "GITEA_REPO_IS_WIKI"
+ EnvPusherName = "GITEA_PUSHER_NAME"
+ EnvPusherID = "GITEA_PUSHER_ID"
+)
// CommitToPushCommit transforms a git.Commit to PushCommit type.
func CommitToPushCommit(commit *git.Commit) *PushCommit {
diff --git a/models/update_test.go b/models/update_test.go
index db9d7b94b9..ae95a9641b 100644
--- a/models/update_test.go
+++ b/models/update_test.go
@@ -14,40 +14,6 @@ import (
"github.com/stretchr/testify/assert"
)
-func TestAddUpdateTask(t *testing.T) {
- assert.NoError(t, PrepareTestDatabase())
- task := &UpdateTask{
- UUID: "uuid4",
- RefName: "refName4",
- OldCommitID: "oldCommitId4",
- NewCommitID: "newCommitId4",
- }
- assert.NoError(t, AddUpdateTask(task))
- AssertExistsAndLoadBean(t, task)
-}
-
-func TestGetUpdateTaskByUUID(t *testing.T) {
- assert.NoError(t, PrepareTestDatabase())
- task, err := GetUpdateTaskByUUID("uuid1")
- assert.NoError(t, err)
- assert.Equal(t, "uuid1", task.UUID)
- assert.Equal(t, "refName1", task.RefName)
- assert.Equal(t, "oldCommitId1", task.OldCommitID)
- assert.Equal(t, "newCommitId1", task.NewCommitID)
-
- _, err = GetUpdateTaskByUUID("invalid")
- assert.Error(t, err)
- assert.True(t, IsErrUpdateTaskNotExist(err))
-}
-
-func TestDeleteUpdateTaskByUUID(t *testing.T) {
- assert.NoError(t, PrepareTestDatabase())
- assert.NoError(t, DeleteUpdateTaskByUUID("uuid1"))
- AssertNotExistsBean(t, &UpdateTask{UUID: "uuid1"})
-
- assert.NoError(t, DeleteUpdateTaskByUUID("invalid"))
-}
-
func TestCommitToPushCommit(t *testing.T) {
now := time.Now()
sig := &git.Signature{
diff --git a/routers/repo/http.go b/routers/repo/http.go
index 4c143f66d0..dc29651847 100644
--- a/routers/repo/http.go
+++ b/routers/repo/http.go
@@ -8,20 +8,15 @@ import (
"bytes"
"compress/gzip"
"fmt"
- "io"
- "io/ioutil"
"net/http"
"os"
"os/exec"
"path"
"regexp"
- "runtime"
"strconv"
"strings"
"time"
- "code.gitea.io/git"
-
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
@@ -59,7 +54,7 @@ func HTTP(ctx *context.Context) {
isWiki := false
if strings.HasSuffix(reponame, ".wiki") {
isWiki = true
- reponame = reponame[:len(reponame) - 5]
+ reponame = reponame[:len(reponame)-5]
}
repoUser, err := models.GetUserByName(username)
@@ -89,6 +84,7 @@ func HTTP(ctx *context.Context) {
authUser *models.User
authUsername string
authPasswd string
+ environ []string
)
// check access
@@ -182,94 +178,42 @@ func HTTP(ctx *context.Context) {
}
}
}
- }
- callback := func(rpc string, input []byte) {
- if rpc != "receive-pack" || isWiki {
- return
+ environ = []string{
+ models.EnvRepoUsername + "=" + username,
+ models.EnvRepoName + "=" + reponame,
+ models.EnvRepoUserSalt + "=" + repoUser.Salt,
+ models.EnvPusherName + "=" + authUser.Name,
+ models.EnvPusherID + fmt.Sprintf("=%d", authUser.ID),
+ models.ProtectedBranchRepoID + fmt.Sprintf("=%d", repo.ID),
}
-
- var lastLine int64
- for {
- head := input[lastLine: lastLine + 2]
- if head[0] == '0' && head[1] == '0' {
- size, err := strconv.ParseInt(string(input[lastLine + 2:lastLine + 4]), 16, 32)
- if err != nil {
- log.Error(4, "%v", err)
- return
- }
-
- if size == 0 {
- //fmt.Println(string(input[lastLine:]))
- break
- }
-
- line := input[lastLine: lastLine + size]
- idx := bytes.IndexRune(line, '\000')
- if idx > -1 {
- line = line[:idx]
- }
-
- fields := strings.Fields(string(line))
- if len(fields) >= 3 {
- oldCommitID := fields[0][4:]
- newCommitID := fields[1]
- refFullName := fields[2]
-
- // FIXME: handle error.
- if err = models.PushUpdate(models.PushUpdateOptions{
- RefFullName: refFullName,
- OldCommitID: oldCommitID,
- NewCommitID: newCommitID,
- PusherID: authUser.ID,
- PusherName: authUser.Name,
- RepoUserName: username,
- RepoName: reponame,
- }); err == nil {
- go models.AddTestPullRequestTask(authUser, repo.ID, strings.TrimPrefix(refFullName, git.BranchPrefix), true)
- }
-
- }
- lastLine = lastLine + size
- } else {
- break
- }
- }
- }
-
- params := make(map[string]string)
-
- if askAuth {
- params[models.ProtectedBranchUserID] = fmt.Sprintf("%d", authUser.ID)
- if err == nil {
- params[models.ProtectedBranchAccessMode] = accessMode.String()
+ if isWiki {
+ environ = append(environ, models.EnvRepoIsWiki+"=true")
+ } else {
+ environ = append(environ, models.EnvRepoIsWiki+"=false")
}
- params[models.ProtectedBranchRepoID] = fmt.Sprintf("%d", repo.ID)
}
HTTPBackend(ctx, &serviceConfig{
UploadPack: true,
ReceivePack: true,
- Params: params,
- OnSucceed: callback,
+ Env: environ,
})(ctx.Resp, ctx.Req.Request)
-
- runtime.GC()
}
type serviceConfig struct {
UploadPack bool
ReceivePack bool
- Params map[string]string
- OnSucceed func(rpc string, input []byte)
+ Env []string
}
type serviceHandler struct {
- cfg *serviceConfig
- w http.ResponseWriter
- r *http.Request
- dir string
- file string
+ cfg *serviceConfig
+ w http.ResponseWriter
+ r *http.Request
+ dir string
+ file string
+ environ []string
}
func (h *serviceHandler) setHeaderNoCache() {
@@ -278,42 +222,6 @@ func (h *serviceHandler) setHeaderNoCache() {
h.w.Header().Set("Cache-Control", "no-cache, max-age=0, must-revalidate")
}
-func (h *serviceHandler) getBranch(input []byte) string {
- var lastLine int64
- var branchName string
- for {
- head := input[lastLine : lastLine+2]
- if head[0] == '0' && head[1] == '0' {
- size, err := strconv.ParseInt(string(input[lastLine+2:lastLine+4]), 16, 32)
- if err != nil {
- log.Error(4, "%v", err)
- return branchName
- }
-
- if size == 0 {
- //fmt.Println(string(input[lastLine:]))
- break
- }
-
- line := input[lastLine : lastLine+size]
- idx := bytes.IndexRune(line, '\000')
- if idx > -1 {
- line = line[:idx]
- }
-
- fields := strings.Fields(string(line))
- if len(fields) >= 3 {
- refFullName := fields[2]
- branchName = strings.TrimPrefix(refFullName, git.BranchPrefix)
- }
- lastLine = lastLine + size
- } else {
- break
- }
- }
- return branchName
-}
-
func (h *serviceHandler) setHeaderCacheForever() {
now := time.Now().Unix()
expires := now + 31536000
@@ -370,7 +278,7 @@ func gitCommand(dir string, args ...string) []byte {
func getGitConfig(option, dir string) string {
out := string(gitCommand(dir, "config", option))
- return out[0: len(out) - 1]
+ return out[0 : len(out)-1]
}
func getConfigSetting(service, dir string) bool {
@@ -414,13 +322,8 @@ func serviceRPC(h serviceHandler, service string) {
h.w.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-result", service))
- var (
- reqBody = h.r.Body
- input []byte
- br io.Reader
- err error
- branchName string
- )
+ var err error
+ var reqBody = h.r.Body
// Handle GZIP.
if h.r.Header.Get("Content-Encoding") == "gzip" {
@@ -432,52 +335,23 @@ func serviceRPC(h serviceHandler, service string) {
}
}
- if h.cfg.OnSucceed != nil {
- input, err = ioutil.ReadAll(reqBody)
- if err != nil {
- log.GitLogger.Error(2, "fail to read request body: %v", err)
- h.w.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- branchName = h.getBranch(input)
- br = bytes.NewReader(input)
- } else {
- br = reqBody
- }
-
- // check protected branch
- repoID, _ := strconv.ParseInt(h.cfg.Params[models.ProtectedBranchRepoID], 10, 64)
- accessMode := models.ParseAccessMode(h.cfg.Params[models.ProtectedBranchAccessMode])
- // skip admin or owner AccessMode
- if accessMode == models.AccessModeWrite {
- protectBranch, err := models.GetProtectedBranchBy(repoID, branchName)
- if err != nil {
- log.GitLogger.Error(2, "fail to get protected branch information: %v", err)
- h.w.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- if protectBranch != nil {
- log.GitLogger.Error(2, "protected branches can not be pushed to")
- h.w.WriteHeader(http.StatusForbidden)
- return
- }
- }
+ // set this for allow pre-receive and post-receive execute
+ h.environ = append(h.environ, "SSH_ORIGINAL_COMMAND="+service)
+ var stderr bytes.Buffer
cmd := exec.Command("git", service, "--stateless-rpc", h.dir)
cmd.Dir = h.dir
+ if service == "receive-pack" {
+ cmd.Env = append(os.Environ(), h.environ...)
+ }
cmd.Stdout = h.w
- cmd.Stdin = br
+ cmd.Stdin = reqBody
+ cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
- log.GitLogger.Error(2, "fail to serve RPC(%s): %v", service, err)
+ log.GitLogger.Error(2, "fail to serve RPC(%s): %v - %v", service, err, stderr)
h.w.WriteHeader(http.StatusInternalServerError)
return
}
-
- if h.cfg.OnSucceed != nil {
- h.cfg.OnSucceed(service, input)
- }
}
func serviceUploadPack(h serviceHandler) {
@@ -501,7 +375,7 @@ func updateServerInfo(dir string) []byte {
}
func packetWrite(str string) []byte {
- s := strconv.FormatInt(int64(len(str) + 4), 16)
+ s := strconv.FormatInt(int64(len(str)+4), 16)
if len(s)%4 != 0 {
s = strings.Repeat("0", 4-len(s)%4) + s
}
@@ -593,7 +467,7 @@ func HTTPBackend(ctx *context.Context, cfg *serviceConfig) http.HandlerFunc {
return
}
- route.handler(serviceHandler{cfg, w, r, dir, file})
+ route.handler(serviceHandler{cfg, w, r, dir, file, cfg.Env})
return
}
}