Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions cmd/hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"bufio"
"bytes"
"fmt"
"net/url"
"os"
"path/filepath"
"strconv"
Expand Down Expand Up @@ -174,6 +175,7 @@ func runHookPostReceive(c *cli.Context) error {
hookSetup("hooks/post-receive.log")

// the environment setted on serv command
repoID, _ := strconv.ParseInt(os.Getenv(models.ProtectedBranchRepoID), 10, 64)
repoUser := os.Getenv(models.EnvRepoUsername)
isWiki := (os.Getenv(models.EnvRepoIsWiki) == "true")
repoName := os.Getenv(models.EnvRepoName)
Expand Down Expand Up @@ -211,6 +213,47 @@ func runHookPostReceive(c *cli.Context) error {
}); err != nil {
log.GitLogger.Error(2, "Update: %v", err)
}

if strings.HasPrefix(refFullName, git.BranchPrefix) {
branch := strings.TrimPrefix(refFullName, git.BranchPrefix)
repo, pullRequestAllowed, err := private.GetRepository(repoID)
if err != nil {
log.GitLogger.Error(2, "get repo: %v", err)
break
}
if !pullRequestAllowed {
break
}

baseRepo := repo
if repo.IsFork {
baseRepo = repo.BaseRepo
}

if !repo.IsFork && branch == baseRepo.DefaultBranch {
break
}

pr, err := private.ActivePullRequest(baseRepo.ID, repo.ID, baseRepo.DefaultBranch, branch)
if err != nil {
log.GitLogger.Error(2, "get active pr: %v", err)
break
}

fmt.Fprintln(os.Stderr, "")
if pr == nil {
if repo.IsFork {
branch = fmt.Sprintf("%s:%s", repo.OwnerName, branch)
}
fmt.Fprintf(os.Stderr, "Create a new pull request for '%s':\n", branch)
fmt.Fprintf(os.Stderr, " %s/compare/%s...%s\n", baseRepo.HTMLURL(), url.QueryEscape(baseRepo.DefaultBranch), url.QueryEscape(branch))
} else {
fmt.Fprint(os.Stderr, "Visit the existing pull request:\n")
fmt.Fprintf(os.Stderr, " %s/pulls/%d\n", baseRepo.HTMLURL(), pr.Index)
}
fmt.Fprintln(os.Stderr, "")
}

}

return nil
Expand Down
68 changes: 68 additions & 0 deletions modules/private/repository.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright 2018 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 private
Copy link
Member

Choose a reason for hiding this comment

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

comment head

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I changed my PHPStorm template for the project, thanks.


import (
"encoding/json"
"fmt"
"net/url"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
)

// GetRepository return the repository by its ID and a bool about if it's allowed to have PR
func GetRepository(repoID int64) (*models.Repository, bool, error) {
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/repository/%d", repoID)
log.GitLogger.Trace("GetRepository: %s", reqURL)

resp, err := newInternalRequest(reqURL, "GET").Response()
if err != nil {
return nil, false, err
}

var repoInfo struct {
Repository *models.Repository
AllowPullRequest bool
}
if err := json.NewDecoder(resp.Body).Decode(&repoInfo); err != nil {
return nil, false, err
}

defer resp.Body.Close()

// All 2XX status codes are accepted and others will return an error
if resp.StatusCode/100 != 2 {
return nil, false, fmt.Errorf("failed to retrieve repository: %s", decodeJSONError(resp).Err)
}

return repoInfo.Repository, repoInfo.AllowPullRequest, nil
}

// ActivePullRequest returns an active pull request if it exists
func ActivePullRequest(baseRepoID int64, headRepoID int64, baseBranch, headBranch string) (*models.PullRequest, error) {
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/active-pull-request?baseRepoID=%d&headRepoID=%d&baseBranch=%s&headBranch=%s", baseRepoID, headRepoID, url.QueryEscape(baseBranch), url.QueryEscape(headBranch))
log.GitLogger.Trace("ActivePullRequest: %s", reqURL)

resp, err := newInternalRequest(reqURL, "GET").Response()
if err != nil {
return nil, err
}

var pr *models.PullRequest
if err := json.NewDecoder(resp.Body).Decode(&pr); err != nil {
return nil, err
}

defer resp.Body.Close()

// All 2XX status codes are accepted and others will return an error
if resp.StatusCode/100 != 2 {
return nil, fmt.Errorf("failed to retrieve pull request: %s", decodeJSONError(resp).Err)
}

return pr, nil
}
2 changes: 2 additions & 0 deletions routers/private/internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/push/update", PushUpdate)
m.Get("/protectedbranch/:pbid/:userid", CanUserPush)
m.Get("/branch/:id/*", GetProtectedBranchBy)
m.Get("/repository/:rid", GetRepository)
m.Get("/active-pull-request", GetActivePullRequest)
}, CheckInternalToken)
}
84 changes: 84 additions & 0 deletions routers/private/repository.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright 2018 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 private

import (
"net/http"
"net/url"

"code.gitea.io/gitea/models"

macaron "gopkg.in/macaron.v1"
)

// GetRepository return the default branch of a repository
func GetRepository(ctx *macaron.Context) {
repoID := ctx.ParamsInt64(":rid")
repository, err := models.GetRepositoryByID(repoID)
repository.MustOwnerName()
allowPulls := repository.AllowsPulls()
// put it back to nil because json unmarshal can't unmarshal it
repository.Units = nil

if err != nil {
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
"err": err.Error(),
})
return
}

if repository.IsFork {
repository.GetBaseRepo()
if err != nil {
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
"err": err.Error(),
})
return
}
repository.BaseRepo.MustOwnerName()
allowPulls = repository.BaseRepo.AllowsPulls()
// put it back to nil because json unmarshal can't unmarshal it
repository.BaseRepo.Units = nil
}

ctx.JSON(http.StatusOK, struct {
Repository *models.Repository
AllowPullRequest bool
}{
Repository: repository,
AllowPullRequest: allowPulls,
})
}

// GetActivePullRequest return an active pull request when it exists or an empty object
func GetActivePullRequest(ctx *macaron.Context) {
baseRepoID := ctx.QueryInt64("baseRepoID")
headRepoID := ctx.QueryInt64("headRepoID")
baseBranch, err := url.QueryUnescape(ctx.QueryTrim("baseBranch"))
if err != nil {
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
"err": err.Error(),
})
return
}

headBranch, err := url.QueryUnescape(ctx.QueryTrim("headBranch"))
if err != nil {
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
"err": err.Error(),
})
return
}

pr, err := models.GetUnmergedPullRequest(headRepoID, baseRepoID, headBranch, baseBranch)
if err != nil && !models.IsErrPullRequestNotExist(err) {
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
"err": err.Error(),
})
return
}

ctx.JSON(http.StatusOK, pr)
}