2017-02-23 06:40:44 +03:00
// 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 cmd
import (
2017-02-25 17:54:40 +03:00
"bufio"
"bytes"
2017-02-23 06:40:44 +03:00
"fmt"
2019-06-01 18:00:21 +03:00
"net/http"
2017-02-23 06:40:44 +03:00
"os"
2017-02-25 17:54:40 +03:00
"strconv"
"strings"
2017-02-23 06:40:44 +03:00
"code.gitea.io/gitea/models"
2019-03-27 12:33:00 +03:00
"code.gitea.io/gitea/modules/git"
2017-05-04 08:42:02 +03:00
"code.gitea.io/gitea/modules/private"
2017-02-23 06:40:44 +03:00
"github.com/urfave/cli"
)
var (
// CmdHook represents the available hooks sub-command.
CmdHook = cli . Command {
Name : "hook" ,
Usage : "Delegate commands to corresponding Git hooks" ,
Description : "This should only be called by Git" ,
Subcommands : [ ] cli . Command {
subcmdHookPreReceive ,
2018-01-13 01:16:49 +03:00
subcmdHookUpdate ,
2017-02-23 06:40:44 +03:00
subcmdHookPostReceive ,
} ,
}
subcmdHookPreReceive = cli . Command {
Name : "pre-receive" ,
Usage : "Delegate pre-receive Git hook" ,
Description : "This command should only be called by Git" ,
Action : runHookPreReceive ,
}
2018-01-13 01:16:49 +03:00
subcmdHookUpdate = cli . Command {
2017-02-23 06:40:44 +03:00
Name : "update" ,
Usage : "Delegate update Git hook" ,
Description : "This command should only be called by Git" ,
Action : runHookUpdate ,
}
subcmdHookPostReceive = cli . Command {
Name : "post-receive" ,
Usage : "Delegate post-receive Git hook" ,
Description : "This command should only be called by Git" ,
Action : runHookPostReceive ,
}
)
func runHookPreReceive ( c * cli . Context ) error {
if len ( os . Getenv ( "SSH_ORIGINAL_COMMAND" ) ) == 0 {
return nil
}
2017-02-25 17:54:40 +03:00
2018-12-19 04:17:43 +03:00
setup ( "hooks/pre-receive.log" )
2017-02-23 06:40:44 +03:00
2017-02-25 17:54:40 +03:00
// the environment setted on serv command
isWiki := ( os . Getenv ( models . EnvRepoIsWiki ) == "true" )
2017-09-14 11:16:22 +03:00
username := os . Getenv ( models . EnvRepoUsername )
reponame := os . Getenv ( models . EnvRepoName )
2019-06-01 18:00:21 +03:00
userID , _ := strconv . ParseInt ( os . Getenv ( models . EnvPusherID ) , 10 , 64 )
2019-07-01 04:18:13 +03:00
prID , _ := strconv . ParseInt ( os . Getenv ( models . ProtectedBranchPRID ) , 10 , 64 )
2017-02-25 17:54:40 +03:00
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
}
2017-09-14 11:16:22 +03:00
oldCommitID := string ( fields [ 0 ] )
2017-02-25 17:54:40 +03:00
newCommitID := string ( fields [ 1 ] )
refFullName := string ( fields [ 2 ] )
2019-05-14 17:40:27 +03:00
// If the ref is a branch, check if it's protected
if strings . HasPrefix ( refFullName , git . BranchPrefix ) {
2019-06-01 18:00:21 +03:00
statusCode , msg := private . HookPreReceive ( username , reponame , private . HookOptions {
OldCommitID : oldCommitID ,
NewCommitID : newCommitID ,
RefFullName : refFullName ,
UserID : userID ,
GitAlternativeObjectDirectories : os . Getenv ( private . GitAlternativeObjectDirectories ) ,
GitObjectDirectory : os . Getenv ( private . GitObjectDirectory ) ,
2019-08-14 12:25:05 +03:00
GitQuarantinePath : os . Getenv ( private . GitQuarantinePath ) ,
2019-07-01 04:18:13 +03:00
ProtectedBranchID : prID ,
2019-06-01 18:00:21 +03:00
} )
switch statusCode {
case http . StatusInternalServerError :
fail ( "Internal Server Error" , msg )
case http . StatusForbidden :
fail ( msg , "" )
2017-03-01 18:01:03 +03:00
}
2017-02-25 17:54:40 +03:00
}
}
2017-02-23 06:40:44 +03:00
return nil
}
func runHookUpdate ( c * cli . Context ) error {
if len ( os . Getenv ( "SSH_ORIGINAL_COMMAND" ) ) == 0 {
return nil
}
2018-12-19 04:17:43 +03:00
setup ( "hooks/update.log" )
2017-02-23 06:40:44 +03:00
return nil
}
func runHookPostReceive ( c * cli . Context ) error {
if len ( os . Getenv ( "SSH_ORIGINAL_COMMAND" ) ) == 0 {
return nil
}
2018-12-19 04:17:43 +03:00
setup ( "hooks/post-receive.log" )
2017-02-23 06:40:44 +03:00
2017-02-25 17:54:40 +03:00
// the environment setted on serv command
repoUser := os . Getenv ( models . EnvRepoUsername )
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 ] )
2019-06-01 18:00:21 +03:00
res , err := private . HookPostReceive ( repoUser , repoName , private . HookOptions {
OldCommitID : oldCommitID ,
NewCommitID : newCommitID ,
RefFullName : refFullName ,
UserID : pusherID ,
UserName : pusherName ,
} )
2018-10-20 09:59:06 +03:00
2019-06-01 18:00:21 +03:00
if res == nil {
fail ( "Internal Server Error" , err )
}
2018-10-20 09:59:06 +03:00
2019-06-01 18:00:21 +03:00
if res [ "message" ] == false {
continue
2018-10-20 09:59:06 +03:00
}
2019-06-01 18:00:21 +03:00
fmt . Fprintln ( os . Stderr , "" )
if res [ "create" ] == true {
fmt . Fprintf ( os . Stderr , "Create a new pull request for '%s':\n" , res [ "branch" ] )
fmt . Fprintf ( os . Stderr , " %s\n" , res [ "url" ] )
} else {
fmt . Fprint ( os . Stderr , "Visit the existing pull request:\n" )
fmt . Fprintf ( os . Stderr , " %s\n" , res [ "url" ] )
}
fmt . Fprintln ( os . Stderr , "" )
2017-02-25 17:54:40 +03:00
}
2017-02-23 06:40:44 +03:00
return nil
}