1
0
mirror of https://github.com/go-gitea/gitea.git synced 2025-02-02 15:09:33 -05:00

Merge branch 'master' into make-targets

This commit is contained in:
techknowlogick 2019-05-15 11:25:43 -04:00 committed by GitHub
commit 0679ef07de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 231 additions and 295 deletions

View File

@ -69,40 +69,41 @@ func TestAPISearchRepo(t *testing.T) {
name, requestURL string name, requestURL string
expectedResults expectedResults
}{ }{
{name: "RepositoriesMax50", requestURL: "/api/v1/repos/search?limit=50", expectedResults: expectedResults{ {name: "RepositoriesMax50", requestURL: "/api/v1/repos/search?limit=50&private=false", expectedResults: expectedResults{
nil: {count: 21}, nil: {count: 21},
user: {count: 21}, user: {count: 21},
user2: {count: 21}}, user2: {count: 21}},
}, },
{name: "RepositoriesMax10", requestURL: "/api/v1/repos/search?limit=10", expectedResults: expectedResults{ {name: "RepositoriesMax10", requestURL: "/api/v1/repos/search?limit=10&private=false", expectedResults: expectedResults{
nil: {count: 10}, nil: {count: 10},
user: {count: 10}, user: {count: 10},
user2: {count: 10}}, user2: {count: 10}},
}, },
{name: "RepositoriesDefaultMax10", requestURL: "/api/v1/repos/search?default", expectedResults: expectedResults{ {name: "RepositoriesDefaultMax10", requestURL: "/api/v1/repos/search?default&private=false", expectedResults: expectedResults{
nil: {count: 10}, nil: {count: 10},
user: {count: 10}, user: {count: 10},
user2: {count: 10}}, user2: {count: 10}},
}, },
{name: "RepositoriesByName", requestURL: fmt.Sprintf("/api/v1/repos/search?q=%s", "big_test_"), expectedResults: expectedResults{ {name: "RepositoriesByName", requestURL: fmt.Sprintf("/api/v1/repos/search?q=%s&private=false", "big_test_"), expectedResults: expectedResults{
nil: {count: 7, repoName: "big_test_"}, nil: {count: 7, repoName: "big_test_"},
user: {count: 7, repoName: "big_test_"}, user: {count: 7, repoName: "big_test_"},
user2: {count: 7, repoName: "big_test_"}}, user2: {count: 7, repoName: "big_test_"}},
}, },
{name: "RepositoriesAccessibleAndRelatedToUser", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user.ID), expectedResults: expectedResults{ {name: "RepositoriesAccessibleAndRelatedToUser", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user.ID), expectedResults: expectedResults{
nil: {count: 4}, nil: {count: 5},
user: {count: 8, includesPrivate: true}, user: {count: 9, includesPrivate: true},
user2: {count: 4}}, user2: {count: 5, includesPrivate: true}},
}, },
{name: "RepositoriesAccessibleAndRelatedToUser2", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user2.ID), expectedResults: expectedResults{ {name: "RepositoriesAccessibleAndRelatedToUser2", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user2.ID), expectedResults: expectedResults{
nil: {count: 1}, nil: {count: 1},
user: {count: 1}, user: {count: 2, includesPrivate: true},
user2: {count: 2, includesPrivate: true}}, user2: {count: 2, includesPrivate: true},
user4: {count: 1}},
}, },
{name: "RepositoriesAccessibleAndRelatedToUser3", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user3.ID), expectedResults: expectedResults{ {name: "RepositoriesAccessibleAndRelatedToUser3", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user3.ID), expectedResults: expectedResults{
nil: {count: 1}, nil: {count: 1},
user: {count: 1}, user: {count: 4, includesPrivate: true},
user2: {count: 1}, user2: {count: 2, includesPrivate: true},
user3: {count: 4, includesPrivate: true}}, user3: {count: 4, includesPrivate: true}},
}, },
{name: "RepositoriesOwnedByOrganization", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", orgUser.ID), expectedResults: expectedResults{ {name: "RepositoriesOwnedByOrganization", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", orgUser.ID), expectedResults: expectedResults{
@ -112,12 +113,12 @@ func TestAPISearchRepo(t *testing.T) {
}, },
{name: "RepositoriesAccessibleAndRelatedToUser4", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user4.ID), expectedResults: expectedResults{ {name: "RepositoriesAccessibleAndRelatedToUser4", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user4.ID), expectedResults: expectedResults{
nil: {count: 3}, nil: {count: 3},
user: {count: 3}, user: {count: 4, includesPrivate: true},
user4: {count: 6, includesPrivate: true}}}, user4: {count: 7, includesPrivate: true}}},
{name: "RepositoriesAccessibleAndRelatedToUser4/SearchModeSource", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d&mode=%s", user4.ID, "source"), expectedResults: expectedResults{ {name: "RepositoriesAccessibleAndRelatedToUser4/SearchModeSource", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d&mode=%s", user4.ID, "source"), expectedResults: expectedResults{
nil: {count: 0}, nil: {count: 0},
user: {count: 0}, user: {count: 1, includesPrivate: true},
user4: {count: 0, includesPrivate: true}}}, user4: {count: 1, includesPrivate: true}}},
{name: "RepositoriesAccessibleAndRelatedToUser4/SearchModeFork", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d&mode=%s", user4.ID, "fork"), expectedResults: expectedResults{ {name: "RepositoriesAccessibleAndRelatedToUser4/SearchModeFork", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d&mode=%s", user4.ID, "fork"), expectedResults: expectedResults{
nil: {count: 1}, nil: {count: 1},
user: {count: 1}, user: {count: 1},
@ -136,8 +137,8 @@ func TestAPISearchRepo(t *testing.T) {
user4: {count: 2, includesPrivate: true}}}, user4: {count: 2, includesPrivate: true}}},
{name: "RepositoriesAccessibleAndRelatedToUser4/SearchModeCollaborative", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d&mode=%s", user4.ID, "collaborative"), expectedResults: expectedResults{ {name: "RepositoriesAccessibleAndRelatedToUser4/SearchModeCollaborative", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d&mode=%s", user4.ID, "collaborative"), expectedResults: expectedResults{
nil: {count: 0}, nil: {count: 0},
user: {count: 0}, user: {count: 1, includesPrivate: true},
user4: {count: 0, includesPrivate: true}}}, user4: {count: 1, includesPrivate: true}}},
} }
for _, testCase := range testCases { for _, testCase := range testCases {
@ -164,14 +165,19 @@ func TestAPISearchRepo(t *testing.T) {
var body api.SearchResults var body api.SearchResults
DecodeJSON(t, response, &body) DecodeJSON(t, response, &body)
assert.Len(t, body.Data, expected.count) repoNames := make([]string, 0, len(body.Data))
for _, repo := range body.Data {
repoNames = append(repoNames, fmt.Sprintf("%d:%s:%t", repo.ID, repo.FullName, repo.Private))
}
assert.Len(t, repoNames, expected.count)
for _, repo := range body.Data { for _, repo := range body.Data {
r := getRepo(t, repo.ID) r := getRepo(t, repo.ID)
hasAccess, err := models.HasAccess(userID, r) hasAccess, err := models.HasAccess(userID, r)
assert.NoError(t, err) assert.NoError(t, err, "Error when checking if User: %d has access to %s: %v", userID, repo.FullName, err)
assert.True(t, hasAccess) assert.True(t, hasAccess, "User: %d does not have access to %s", userID, repo.FullName)
assert.NotEmpty(t, repo.Name) assert.NotEmpty(t, repo.Name)
assert.Equal(t, repo.Name, r.Name)
if len(expected.repoName) > 0 { if len(expected.repoName) > 0 {
assert.Contains(t, repo.Name, expected.repoName) assert.Contains(t, repo.Name, expected.repoName)
@ -182,7 +188,7 @@ func TestAPISearchRepo(t *testing.T) {
} }
if !expected.includesPrivate { if !expected.includesPrivate {
assert.False(t, repo.Private) assert.False(t, repo.Private, "User: %d not expecting private repository: %s", userID, repo.FullName)
} }
} }
}) })

View File

@ -13,7 +13,6 @@ import (
"io/ioutil" "io/ioutil"
"net/url" "net/url"
"os" "os"
"os/exec"
"path" "path"
"path/filepath" "path/filepath"
"regexp" "regexp"
@ -32,11 +31,9 @@ import (
"code.gitea.io/gitea/modules/sync" "code.gitea.io/gitea/modules/sync"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
"github.com/Unknwon/cae/zip"
"github.com/Unknwon/com" "github.com/Unknwon/com"
"github.com/go-xorm/builder" "github.com/go-xorm/builder"
"github.com/go-xorm/xorm" "github.com/go-xorm/xorm"
version "github.com/mcuadros/go-version"
ini "gopkg.in/ini.v1" ini "gopkg.in/ini.v1"
) )
@ -67,8 +64,8 @@ var (
ItemsPerPage = 40 ItemsPerPage = 40
) )
// LoadRepoConfig loads the repository config // loadRepoConfig loads the repository config
func LoadRepoConfig() { func loadRepoConfig() {
// Load .gitignore and license files and readme templates. // Load .gitignore and license files and readme templates.
types := []string{"gitignore", "license", "readme", "label"} types := []string{"gitignore", "license", "readme", "label"}
typeFiles := make([][]string, 4) typeFiles := make([][]string, 4)
@ -119,45 +116,7 @@ func LoadRepoConfig() {
// NewRepoContext creates a new repository context // NewRepoContext creates a new repository context
func NewRepoContext() { func NewRepoContext() {
zip.Verbose = false loadRepoConfig()
// Check Git installation.
if _, err := exec.LookPath("git"); err != nil {
log.Fatal("Failed to test 'git' command: %v (forgotten install?)", err)
}
// Check Git version.
var err error
setting.Git.Version, err = git.BinVersion()
if err != nil {
log.Fatal("Failed to get Git version: %v", err)
}
log.Info("Git Version: %s", setting.Git.Version)
if version.Compare("1.7.1", setting.Git.Version, ">") {
log.Fatal("Gitea requires Git version greater or equal to 1.7.1")
}
// Git requires setting user.name and user.email in order to commit changes.
for configKey, defaultValue := range map[string]string{"user.name": "Gitea", "user.email": "gitea@fake.local"} {
if stdout, stderr, err := process.GetManager().Exec("NewRepoContext(get setting)", "git", "config", "--get", configKey); err != nil || strings.TrimSpace(stdout) == "" {
// ExitError indicates this config is not set
if _, ok := err.(*exec.ExitError); ok || strings.TrimSpace(stdout) == "" {
if _, stderr, gerr := process.GetManager().Exec("NewRepoContext(set "+configKey+")", "git", "config", "--global", configKey, defaultValue); gerr != nil {
log.Fatal("Failed to set git %s(%s): %s", configKey, gerr, stderr)
}
log.Info("Git config %s set to %s", configKey, defaultValue)
} else {
log.Fatal("Failed to get git %s(%s): %s", configKey, err, stderr)
}
}
}
// Set git some configurations.
if _, stderr, err := process.GetManager().Exec("NewRepoContext(git config --global core.quotepath false)",
"git", "config", "--global", "core.quotepath", "false"); err != nil {
log.Fatal("Failed to execute 'git config --global core.quotepath false': %s", stderr)
}
RemoveAllWithNotice("Clean up repository temporary data", filepath.Join(setting.AppDataPath, "tmp")) RemoveAllWithNotice("Clean up repository temporary data", filepath.Join(setting.AppDataPath, "tmp"))
} }

View File

@ -12,7 +12,6 @@ import (
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
"github.com/go-xorm/builder" "github.com/go-xorm/builder"
"github.com/go-xorm/core"
) )
// RepositoryListDefaultPageSize is the default number of repositories // RepositoryListDefaultPageSize is the default number of repositories
@ -112,11 +111,13 @@ func (repos MirrorRepositoryList) LoadAttributes() error {
// SearchRepoOptions holds the search options // SearchRepoOptions holds the search options
type SearchRepoOptions struct { type SearchRepoOptions struct {
UserID int64
UserIsAdmin bool
Keyword string Keyword string
OwnerID int64 OwnerID int64
OrderBy SearchOrderBy OrderBy SearchOrderBy
Private bool // Include private repositories in results Private bool // Include private repositories in results
Starred bool StarredByID int64
Page int Page int
IsProfile bool IsProfile bool
AllPublic bool // Include also all public repositories AllPublic bool // Include also all public repositories
@ -168,21 +169,53 @@ func SearchRepositoryByName(opts *SearchRepoOptions) (RepositoryList, int64, err
if opts.Page <= 0 { if opts.Page <= 0 {
opts.Page = 1 opts.Page = 1
} }
var cond = builder.NewCond() var cond = builder.NewCond()
if !opts.Private { if opts.Private {
if !opts.UserIsAdmin && opts.UserID != 0 && opts.UserID != opts.OwnerID {
// OK we're in the context of a User
// We should be Either
cond = cond.And(builder.Or(
// 1. Be able to see all non-private repositories that either:
cond.And(
builder.Eq{"is_private": false},
builder.Or(
// A. Aren't in organisations __OR__
builder.NotIn("owner_id", builder.Select("id").From("`user`").Where(builder.Eq{"type": UserTypeOrganization})),
// B. Isn't a private organisation. (Limited is OK because we're logged in)
builder.NotIn("owner_id", builder.Select("id").From("`user`").Where(builder.Eq{"visibility": structs.VisibleTypePrivate}))),
),
// 2. Be able to see all repositories that we have access to
builder.In("id", builder.Select("repo_id").
From("`access`").
Where(builder.And(
builder.Eq{"user_id": opts.UserID},
builder.Gt{"mode": int(AccessModeNone)}))),
// 3. Be able to see all repositories that we are in a team
builder.In("id", builder.Select("`team_repo`.repo_id").
From("team_repo").
Where(builder.Eq{"`team_user`.uid": opts.UserID}).
Join("INNER", "team_user", "`team_user`.team_id = `team_repo`.team_id"))))
}
} else {
// Not looking at private organisations
// We should be able to see all non-private repositories that either:
cond = cond.And(builder.Eq{"is_private": false}) cond = cond.And(builder.Eq{"is_private": false})
accessCond := builder.Or( accessCond := builder.Or(
builder.NotIn("owner_id", builder.Select("id").From("`user`").Where(builder.Or(builder.Eq{"visibility": structs.VisibleTypeLimited}, builder.Eq{"visibility": structs.VisibleTypePrivate}))), // A. Aren't in organisations __OR__
builder.NotIn("owner_id", builder.Select("id").From("`user`").Where(builder.Eq{"type": UserTypeOrganization}))) builder.NotIn("owner_id", builder.Select("id").From("`user`").Where(builder.Eq{"type": UserTypeOrganization})),
// B. Isn't a private or limited organisation.
builder.NotIn("owner_id", builder.Select("id").From("`user`").Where(builder.Or(builder.Eq{"visibility": structs.VisibleTypeLimited}, builder.Eq{"visibility": structs.VisibleTypePrivate}))))
cond = cond.And(accessCond) cond = cond.And(accessCond)
} }
// Restrict to starred repositories
if opts.StarredByID > 0 {
cond = cond.And(builder.In("id", builder.Select("repo_id").From("star").Where(builder.Eq{"uid": opts.StarredByID})))
}
// Restrict repositories to those the OwnerID owns or contributes to as per opts.Collaborate
if opts.OwnerID > 0 { if opts.OwnerID > 0 {
if opts.Starred {
cond = cond.And(builder.In("id", builder.Select("repo_id").From("star").Where(builder.Eq{"uid": opts.OwnerID})))
} else {
var accessCond = builder.NewCond() var accessCond = builder.NewCond()
if opts.Collaborate != util.OptionalBoolTrue { if opts.Collaborate != util.OptionalBoolTrue {
accessCond = builder.Eq{"owner_id": opts.OwnerID} accessCond = builder.Eq{"owner_id": opts.OwnerID}
@ -190,7 +223,12 @@ func SearchRepositoryByName(opts *SearchRepoOptions) (RepositoryList, int64, err
if opts.Collaborate != util.OptionalBoolFalse { if opts.Collaborate != util.OptionalBoolFalse {
collaborateCond := builder.And( collaborateCond := builder.And(
builder.Or(
builder.Expr("repository.id IN (SELECT repo_id FROM `access` WHERE access.user_id = ?)", opts.OwnerID), builder.Expr("repository.id IN (SELECT repo_id FROM `access` WHERE access.user_id = ?)", opts.OwnerID),
builder.In("id", builder.Select("`team_repo`.repo_id").
From("team_repo").
Where(builder.Eq{"`team_user`.uid": opts.OwnerID}).
Join("INNER", "team_user", "`team_user`.team_id = `team_repo`.team_id"))),
builder.Neq{"owner_id": opts.OwnerID}) builder.Neq{"owner_id": opts.OwnerID})
if !opts.Private { if !opts.Private {
collaborateCond = collaborateCond.And(builder.Expr("owner_id NOT IN (SELECT org_id FROM org_user WHERE org_user.uid = ? AND org_user.is_public = ?)", opts.OwnerID, false)) collaborateCond = collaborateCond.And(builder.Expr("owner_id NOT IN (SELECT org_id FROM org_user WHERE org_user.uid = ? AND org_user.is_public = ?)", opts.OwnerID, false))
@ -199,42 +237,12 @@ func SearchRepositoryByName(opts *SearchRepoOptions) (RepositoryList, int64, err
accessCond = accessCond.Or(collaborateCond) accessCond = accessCond.Or(collaborateCond)
} }
var exprCond builder.Cond
if DbCfg.Type == core.POSTGRES {
exprCond = builder.Expr("org_user.org_id = \"user\".id")
} else if DbCfg.Type == core.MSSQL {
exprCond = builder.Expr("org_user.org_id = [user].id")
} else {
exprCond = builder.Eq{"org_user.org_id": "user.id"}
}
visibilityCond := builder.Or(
builder.In("owner_id",
builder.Select("org_id").From("org_user").
LeftJoin("`user`", exprCond).
Where(
builder.And(
builder.Eq{"uid": opts.OwnerID},
builder.Eq{"visibility": structs.VisibleTypePrivate})),
),
builder.In("owner_id",
builder.Select("id").From("`user`").
Where(
builder.Or(
builder.Eq{"visibility": structs.VisibleTypePublic},
builder.Eq{"visibility": structs.VisibleTypeLimited})),
),
builder.NotIn("owner_id", builder.Select("id").From("`user`").Where(builder.Eq{"type": UserTypeOrganization})),
)
cond = cond.And(visibilityCond)
if opts.AllPublic { if opts.AllPublic {
accessCond = accessCond.Or(builder.Eq{"is_private": false}) accessCond = accessCond.Or(builder.Eq{"is_private": false})
} }
cond = cond.And(accessCond) cond = cond.And(accessCond)
} }
}
if opts.Keyword != "" { if opts.Keyword != "" {
// separate keyword // separate keyword

View File

@ -117,7 +117,7 @@ func TestSearchRepositoryByName(t *testing.T) {
count: 4}, count: 4},
{name: "PublicRepositoriesOfUserIncludingCollaborative", {name: "PublicRepositoriesOfUserIncludingCollaborative",
opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15}, opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15},
count: 4}, count: 5},
{name: "PublicRepositoriesOfUser2IncludingCollaborative", {name: "PublicRepositoriesOfUser2IncludingCollaborative",
opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 18}, opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 18},
count: 1}, count: 1},
@ -126,13 +126,13 @@ func TestSearchRepositoryByName(t *testing.T) {
count: 3}, count: 3},
{name: "PublicAndPrivateRepositoriesOfUserIncludingCollaborative", {name: "PublicAndPrivateRepositoriesOfUserIncludingCollaborative",
opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15, Private: true}, opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15, Private: true},
count: 8}, count: 9},
{name: "PublicAndPrivateRepositoriesOfUser2IncludingCollaborative", {name: "PublicAndPrivateRepositoriesOfUser2IncludingCollaborative",
opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 18, Private: true}, opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 18, Private: true},
count: 4}, count: 4},
{name: "PublicAndPrivateRepositoriesOfUser3IncludingCollaborative", {name: "PublicAndPrivateRepositoriesOfUser3IncludingCollaborative",
opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 20, Private: true}, opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 20, Private: true},
count: 6}, count: 7},
{name: "PublicRepositoriesOfOrganization", {name: "PublicRepositoriesOfOrganization",
opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 17, Collaborate: util.OptionalBoolFalse}, opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 17, Collaborate: util.OptionalBoolFalse},
count: 1}, count: 1},
@ -150,7 +150,7 @@ func TestSearchRepositoryByName(t *testing.T) {
count: 21}, count: 21},
{name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborative", {name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborative",
opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15, Private: true, AllPublic: true}, opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15, Private: true, AllPublic: true},
count: 26}, count: 27},
{name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborativeByName", {name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborativeByName",
opts: &SearchRepoOptions{Keyword: "test", Page: 1, PageSize: 10, OwnerID: 15, Private: true, AllPublic: true}, opts: &SearchRepoOptions{Keyword: "test", Page: 1, PageSize: 10, OwnerID: 15, Private: true, AllPublic: true},
count: 15}, count: 15},

View File

@ -755,17 +755,15 @@ func prepareWebhooks(e Engine, repo *Repository, event HookEventType, p api.Payl
func (t *HookTask) deliver() { func (t *HookTask) deliver() {
t.IsDelivered = true t.IsDelivered = true
t.RequestInfo = &HookRequest{
Headers: map[string]string{},
}
t.ResponseInfo = &HookResponse{
Headers: map[string]string{},
}
timeout := time.Duration(setting.Webhook.DeliverTimeout) * time.Second timeout := time.Duration(setting.Webhook.DeliverTimeout) * time.Second
var req *httplib.Request var req *httplib.Request
if t.HTTPMethod == http.MethodPost { switch t.HTTPMethod {
case "":
log.Info("HTTP Method for webhook %d empty, setting to POST as default", t.ID)
fallthrough
case http.MethodPost:
req = httplib.Post(t.URL) req = httplib.Post(t.URL)
switch t.ContentType { switch t.ContentType {
case ContentTypeJSON: case ContentTypeJSON:
@ -773,10 +771,10 @@ func (t *HookTask) deliver() {
case ContentTypeForm: case ContentTypeForm:
req.Param("payload", t.PayloadContent) req.Param("payload", t.PayloadContent)
} }
} else if t.HTTPMethod == http.MethodGet { case http.MethodGet:
req = httplib.Get(t.URL).Param("payload", t.PayloadContent) req = httplib.Get(t.URL).Param("payload", t.PayloadContent)
} else { default:
t.ResponseInfo.Body = fmt.Sprintf("Invalid http method: %v", t.HTTPMethod) log.Error("Invalid http method for webhook: [%d] %v", t.ID, t.HTTPMethod)
return return
} }
@ -792,10 +790,17 @@ func (t *HookTask) deliver() {
SetTLSClientConfig(&tls.Config{InsecureSkipVerify: setting.Webhook.SkipTLSVerify}) SetTLSClientConfig(&tls.Config{InsecureSkipVerify: setting.Webhook.SkipTLSVerify})
// Record delivery information. // Record delivery information.
t.RequestInfo = &HookRequest{
Headers: map[string]string{},
}
for k, vals := range req.Headers() { for k, vals := range req.Headers() {
t.RequestInfo.Headers[k] = strings.Join(vals, ",") t.RequestInfo.Headers[k] = strings.Join(vals, ",")
} }
t.ResponseInfo = &HookResponse{
Headers: map[string]string{},
}
defer func() { defer func() {
t.Delivered = time.Now().UnixNano() t.Delivered = time.Now().UnixNano()
if t.IsSucceed { if t.IsSucceed {

View File

@ -11,6 +11,8 @@ import (
"strings" "strings"
"time" "time"
"code.gitea.io/gitea/modules/process"
"github.com/mcuadros/go-version" "github.com/mcuadros/go-version"
) )
@ -31,6 +33,8 @@ var (
// GitExecutable is the command name of git // GitExecutable is the command name of git
// Could be updated to an absolute path while initialization // Could be updated to an absolute path while initialization
GitExecutable = "git" GitExecutable = "git"
gitVersion string
) )
func log(format string, args ...interface{}) { func log(format string, args ...interface{}) {
@ -46,8 +50,6 @@ func log(format string, args ...interface{}) {
} }
} }
var gitVersion string
// BinVersion returns current Git version from shell. // BinVersion returns current Git version from shell.
func BinVersion() (string, error) { func BinVersion() (string, error) {
if len(gitVersion) > 0 { if len(gitVersion) > 0 {
@ -89,6 +91,26 @@ func init() {
if version.Compare(gitVersion, GitVersionRequired, "<") { if version.Compare(gitVersion, GitVersionRequired, "<") {
panic(fmt.Sprintf("Git version not supported. Requires version > %v", GitVersionRequired)) panic(fmt.Sprintf("Git version not supported. Requires version > %v", GitVersionRequired))
} }
// Git requires setting user.name and user.email in order to commit changes.
for configKey, defaultValue := range map[string]string{"user.name": "Gitea", "user.email": "gitea@fake.local"} {
if stdout, stderr, err := process.GetManager().Exec("git.Init(get setting)", GitExecutable, "config", "--get", configKey); err != nil || strings.TrimSpace(stdout) == "" {
// ExitError indicates this config is not set
if _, ok := err.(*exec.ExitError); ok || strings.TrimSpace(stdout) == "" {
if _, stderr, gerr := process.GetManager().Exec("git.Init(set "+configKey+")", "git", "config", "--global", configKey, defaultValue); gerr != nil {
panic(fmt.Sprintf("Failed to set git %s(%s): %s", configKey, gerr, stderr))
}
} else {
panic(fmt.Sprintf("Failed to get git %s(%s): %s", configKey, err, stderr))
}
}
}
// Set git some configurations.
if _, stderr, err := process.GetManager().Exec("git.Init(git config --global core.quotepath false)",
GitExecutable, "config", "--global", "core.quotepath", "false"); err != nil {
panic(fmt.Sprintf("Failed to execute 'git config --global core.quotepath false': %s", stderr))
}
} }
// Fsck verifies the connectivity and validity of the objects in the database // Fsck verifies the connectivity and validity of the objects in the database

View File

@ -16,7 +16,6 @@ import (
var ( var (
// Git settings // Git settings
Git = struct { Git = struct {
Version string `ini:"-"`
DisableDiffHighlight bool DisableDiffHighlight bool
MaxGitDiffLines int MaxGitDiffLines int
MaxGitDiffLineCharacters int MaxGitDiffLineCharacters int
@ -65,6 +64,8 @@ func newGit() {
log.Fatal("Error retrieving git version: %v", err) log.Fatal("Error retrieving git version: %v", err)
} }
log.Info("Git Version: %s", binVersion)
if version.Compare(binVersion, "2.9", ">=") { if version.Compare(binVersion, "2.9", ">=") {
// Explicitly disable credential helper, otherwise Git credentials might leak // Explicitly disable credential helper, otherwise Git credentials might leak
git.GlobalCommandArgs = append(git.GlobalCommandArgs, "-c", "credential.helper=") git.GlobalCommandArgs = append(git.GlobalCommandArgs, "-c", "credential.helper=")

View File

@ -27,6 +27,7 @@ import (
_ "code.gitea.io/gitea/modules/minwinsvc" // import minwinsvc for windows services _ "code.gitea.io/gitea/modules/minwinsvc" // import minwinsvc for windows services
"code.gitea.io/gitea/modules/user" "code.gitea.io/gitea/modules/user"
"github.com/Unknwon/cae/zip"
"github.com/Unknwon/com" "github.com/Unknwon/com"
_ "github.com/go-macaron/cache/memcache" // memcache plugin for cache _ "github.com/go-macaron/cache/memcache" // memcache plugin for cache
_ "github.com/go-macaron/cache/redis" _ "github.com/go-macaron/cache/redis"
@ -931,6 +932,8 @@ func NewContext() {
sec = Cfg.Section("U2F") sec = Cfg.Section("U2F")
U2F.TrustedFacets, _ = shellquote.Split(sec.Key("TRUSTED_FACETS").MustString(strings.TrimRight(AppURL, "/"))) U2F.TrustedFacets, _ = shellquote.Split(sec.Key("TRUSTED_FACETS").MustString(strings.TrimRight(AppURL, "/")))
U2F.AppID = sec.Key("APP_ID").MustString(strings.TrimRight(AppURL, "/")) U2F.AppID = sec.Key("APP_ID").MustString(strings.TrimRight(AppURL, "/"))
zip.Verbose = false
} }
func loadInternalToken(sec *ini.Section) string { func loadInternalToken(sec *ini.Section) string {

View File

@ -18,6 +18,7 @@ import (
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/cron" "code.gitea.io/gitea/modules/cron"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
) )
@ -210,7 +211,7 @@ func Config(ctx *context.Context) {
ctx.Data["DisableRouterLog"] = setting.DisableRouterLog ctx.Data["DisableRouterLog"] = setting.DisableRouterLog
ctx.Data["RunUser"] = setting.RunUser ctx.Data["RunUser"] = setting.RunUser
ctx.Data["RunMode"] = strings.Title(macaron.Env) ctx.Data["RunMode"] = strings.Title(macaron.Env)
ctx.Data["GitVersion"] = setting.Git.Version ctx.Data["GitVersion"], _ = git.BinVersion()
ctx.Data["RepoRootPath"] = setting.RepoRootPath ctx.Data["RepoRootPath"] = setting.RepoRootPath
ctx.Data["CustomRootPath"] = setting.CustomPath ctx.Data["CustomRootPath"] = setting.CustomPath
ctx.Data["StaticRootPath"] = setting.StaticRootPath ctx.Data["StaticRootPath"] = setting.StaticRootPath

View File

@ -56,6 +56,15 @@ func Search(ctx *context.APIContext) {
// description: search only for repos that the user with the given id owns or contributes to // description: search only for repos that the user with the given id owns or contributes to
// type: integer // type: integer
// format: int64 // format: int64
// - name: starredBy
// in: query
// description: search only for repos that the user with the given id has starred
// type: integer
// format: int64
// - name: private
// in: query
// description: include private repositories this user has access to (defaults to true)
// type: boolean
// - name: page // - name: page
// in: query // in: query
// description: page number of results to return (1-based) // description: page number of results to return (1-based)
@ -96,6 +105,10 @@ func Search(ctx *context.APIContext) {
PageSize: convert.ToCorrectPageSize(ctx.QueryInt("limit")), PageSize: convert.ToCorrectPageSize(ctx.QueryInt("limit")),
TopicOnly: ctx.QueryBool("topic"), TopicOnly: ctx.QueryBool("topic"),
Collaborate: util.OptionalBoolNone, Collaborate: util.OptionalBoolNone,
Private: ctx.IsSigned && (ctx.Query("private") == "" || ctx.QueryBool("private")),
UserIsAdmin: ctx.IsUserSiteAdmin(),
UserID: ctx.Data["SignedUserID"].(int64),
StarredByID: ctx.QueryInt64("starredBy"),
} }
if ctx.QueryBool("exclusive") { if ctx.QueryBool("exclusive") {
@ -140,42 +153,6 @@ func Search(ctx *context.APIContext) {
} }
var err error var err error
if opts.OwnerID > 0 {
var repoOwner *models.User
if ctx.User != nil && ctx.User.ID == opts.OwnerID {
repoOwner = ctx.User
} else {
repoOwner, err = models.GetUserByID(opts.OwnerID)
if err != nil {
ctx.JSON(500, api.SearchError{
OK: false,
Error: err.Error(),
})
return
}
}
if repoOwner.IsOrganization() {
opts.Collaborate = util.OptionalBoolFalse
}
// Check visibility.
if ctx.IsSigned {
if ctx.User.ID == repoOwner.ID {
opts.Private = true
} else if repoOwner.IsOrganization() {
opts.Private, err = repoOwner.IsOwnedBy(ctx.User.ID)
if err != nil {
ctx.JSON(500, api.SearchError{
OK: false,
Error: err.Error(),
})
return
}
}
}
}
repos, count, err := models.SearchRepositoryByName(opts) repos, count, err := models.SearchRepositoryByName(opts)
if err != nil { if err != nil {
ctx.JSON(500, api.SearchError{ ctx.JSON(500, api.SearchError{

View File

@ -98,6 +98,7 @@ func addHook(ctx *context.APIContext, form *api.CreateHookOption, orgID, repoID
URL: form.Config["url"], URL: form.Config["url"],
ContentType: models.ToHookContentType(form.Config["content_type"]), ContentType: models.ToHookContentType(form.Config["content_type"]),
Secret: form.Config["secret"], Secret: form.Config["secret"],
HTTPMethod: "POST",
HookEvent: &models.HookEvent{ HookEvent: &models.HookEvent{
ChooseEvents: true, ChooseEvents: true,
HookEvents: models.HookEvents{ HookEvents: models.HookEvents{

View File

@ -86,7 +86,6 @@ func GlobalInit() {
log.Fatal("Failed to initialize OAuth2 support: %v", err) log.Fatal("Failed to initialize OAuth2 support: %v", err)
} }
models.LoadRepoConfig()
models.NewRepoContext() models.NewRepoContext()
// Booting long running goroutines. // Booting long running goroutines.

View File

@ -564,6 +564,7 @@ func WebHooksEditPost(ctx *context.Context, form auth.NewWebhookForm) {
w.Secret = form.Secret w.Secret = form.Secret
w.HookEvent = ParseHookEvent(form.WebhookForm) w.HookEvent = ParseHookEvent(form.WebhookForm)
w.IsActive = form.Active w.IsActive = form.Active
w.HTTPMethod = form.HTTPMethod
if err := w.UpdateEvent(); err != nil { if err := w.UpdateEvent(); err != nil {
ctx.ServerError("UpdateEvent", err) ctx.ServerError("UpdateEvent", err)
return return

View File

@ -499,41 +499,13 @@ func showOrgProfile(ctx *context.Context) {
count int64 count int64
err error err error
) )
if ctx.IsSigned && !ctx.User.IsAdmin {
env, err := org.AccessibleReposEnv(ctx.User.ID)
if err != nil {
ctx.ServerError("AccessibleReposEnv", err)
return
}
env.SetSort(orderBy)
if len(keyword) != 0 {
env.AddKeyword(keyword)
}
repos, err = env.Repos(page, setting.UI.User.RepoPagingNum)
if err != nil {
ctx.ServerError("env.Repos", err)
return
}
count, err = env.CountRepos()
if err != nil {
ctx.ServerError("env.CountRepos", err)
return
}
} else {
showPrivate := ctx.IsSigned && ctx.User.IsAdmin
if len(keyword) == 0 {
repos, err = models.GetUserRepositories(org.ID, showPrivate, page, setting.UI.User.RepoPagingNum, orderBy.String())
if err != nil {
ctx.ServerError("GetRepositories", err)
return
}
count = models.CountUserRepositories(org.ID, showPrivate)
} else {
repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{ repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{
Keyword: keyword, Keyword: keyword,
OwnerID: org.ID, OwnerID: org.ID,
OrderBy: orderBy, OrderBy: orderBy,
Private: showPrivate, Private: ctx.IsSigned,
UserIsAdmin: ctx.IsUserSiteAdmin(),
UserID: ctx.Data["SignedUserID"].(int64),
Page: page, Page: page,
IsProfile: true, IsProfile: true,
PageSize: setting.UI.User.RepoPagingNum, PageSize: setting.UI.User.RepoPagingNum,
@ -542,8 +514,6 @@ func showOrgProfile(ctx *context.Context) {
ctx.ServerError("SearchRepositoryByName", err) ctx.ServerError("SearchRepositoryByName", err)
return return
} }
}
}
if err := org.GetMembers(); err != nil { if err := org.GetMembers(); err != nil {
ctx.ServerError("GetMembers", err) ctx.ServerError("GetMembers", err)

View File

@ -170,27 +170,15 @@ func Profile(ctx *context.Context) {
} }
case "stars": case "stars":
ctx.Data["PageIsProfileStarList"] = true ctx.Data["PageIsProfileStarList"] = true
if len(keyword) == 0 {
repos, err = ctxUser.GetStarredRepos(showPrivate, page, setting.UI.User.RepoPagingNum, orderBy.String())
if err != nil {
ctx.ServerError("GetStarredRepos", err)
return
}
count, err = ctxUser.GetStarredRepoCount(showPrivate)
if err != nil {
ctx.ServerError("GetStarredRepoCount", err)
return
}
} else {
repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{ repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{
Keyword: keyword, Keyword: keyword,
OwnerID: ctxUser.ID,
OrderBy: orderBy, OrderBy: orderBy,
Private: showPrivate, Private: ctx.IsSigned,
UserIsAdmin: ctx.IsUserSiteAdmin(),
UserID: ctx.Data["SignedUserID"].(int64),
Page: page, Page: page,
PageSize: setting.UI.User.RepoPagingNum, PageSize: setting.UI.User.RepoPagingNum,
Starred: true, StarredByID: ctxUser.ID,
Collaborate: util.OptionalBoolFalse, Collaborate: util.OptionalBoolFalse,
TopicOnly: topicOnly, TopicOnly: topicOnly,
}) })
@ -198,33 +186,16 @@ func Profile(ctx *context.Context) {
ctx.ServerError("SearchRepositoryByName", err) ctx.ServerError("SearchRepositoryByName", err)
return return
} }
}
total = int(count) total = int(count)
default: default:
if len(keyword) == 0 {
repos, err = models.GetUserRepositories(ctxUser.ID, showPrivate, page, setting.UI.User.RepoPagingNum, orderBy.String())
if err != nil {
ctx.ServerError("GetRepositories", err)
return
}
if showPrivate {
total = ctxUser.NumRepos
} else {
count, err := models.GetPublicRepositoryCount(ctxUser)
if err != nil {
ctx.ServerError("GetPublicRepositoryCount", err)
return
}
total = int(count)
}
} else {
repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{ repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{
Keyword: keyword, Keyword: keyword,
OwnerID: ctxUser.ID, OwnerID: ctxUser.ID,
OrderBy: orderBy, OrderBy: orderBy,
Private: showPrivate, Private: ctx.IsSigned,
UserIsAdmin: ctx.IsUserSiteAdmin(),
UserID: ctx.Data["SignedUserID"].(int64),
Page: page, Page: page,
IsProfile: true, IsProfile: true,
PageSize: setting.UI.User.RepoPagingNum, PageSize: setting.UI.User.RepoPagingNum,
@ -238,7 +209,6 @@ func Profile(ctx *context.Context) {
total = int(count) total = int(count)
} }
}
ctx.Data["Repos"] = repos ctx.Data["Repos"] = repos
ctx.Data["Total"] = total ctx.Data["Total"] = total

View File

@ -45,7 +45,7 @@
{{if .RequestInfo}} {{if .RequestInfo}}
<h5>{{$.i18n.Tr "repo.settings.webhook.headers"}}</h5> <h5>{{$.i18n.Tr "repo.settings.webhook.headers"}}</h5>
<pre class="raw"><strong>Request URL:</strong> {{.URL}} <pre class="raw"><strong>Request URL:</strong> {{.URL}}
<strong>Request method:</strong> POST <strong>Request method:</strong> {{if .HTTPMethod}}{{.HTTPMethod}}{{else}}POST{{end}}
{{ range $key, $val := .RequestInfo.Headers }}<strong>{{$key}}:</strong> {{$val}} {{ range $key, $val := .RequestInfo.Headers }}<strong>{{$key}}:</strong> {{$val}}
{{end}}</pre> {{end}}</pre>
<h5>{{$.i18n.Tr "repo.settings.webhook.payload"}}</h5> <h5>{{$.i18n.Tr "repo.settings.webhook.payload"}}</h5>

View File

@ -1085,6 +1085,19 @@
"name": "uid", "name": "uid",
"in": "query" "in": "query"
}, },
{
"type": "integer",
"format": "int64",
"description": "search only for repos that the user with the given id has starred",
"name": "starredBy",
"in": "query"
},
{
"type": "boolean",
"description": "include private repositories this user has access to (defaults to true)",
"name": "private",
"in": "query"
},
{ {
"type": "integer", "type": "integer",
"description": "page number of results to return (1-based)", "description": "page number of results to return (1-based)",