mirror of
https://github.com/go-gitea/gitea.git
synced 2025-12-24 20:11:32 +00:00
Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83f8414e1e | ||
|
|
0b216f40fd | ||
|
|
dd6e604f8f | ||
|
|
86863ae939 | ||
|
|
f3a90057a5 | ||
|
|
03fdd82d63 | ||
|
|
cd7fa15d1d | ||
|
|
79868d7096 | ||
|
|
19626b93f8 | ||
|
|
91e6a7f7ea | ||
|
|
ff7eaa1eb4 | ||
|
|
5131206aad | ||
|
|
bfc25fcf40 | ||
|
|
4a6765fba2 | ||
|
|
dca8ef9407 | ||
|
|
cebef5c871 | ||
|
|
245d6ebda5 | ||
|
|
d9875ff2e1 | ||
|
|
cc2a6c1d30 | ||
|
|
b5fd55de73 | ||
|
|
e11b3a1076 | ||
|
|
0c4be64345 | ||
|
|
c34ad62eea | ||
|
|
f7d7cf4e2d | ||
|
|
99a364a9dc | ||
|
|
3afbbfe921 | ||
|
|
bfce841b04 | ||
|
|
139fc7cfee | ||
|
|
596eebb2b6 | ||
|
|
1d5d745851 | ||
|
|
3dabfd4933 | ||
|
|
6ee6731290 | ||
|
|
602fe45936 | ||
|
|
e2da9cd21f | ||
|
|
c0b917b7eb | ||
|
|
54ea58ddf0 | ||
|
|
0158725387 |
48
CHANGELOG.md
48
CHANGELOG.md
@@ -4,6 +4,48 @@ This changelog goes through all the changes that have been made in each release
|
||||
without substantial changes to our git log; to see the highlights of what has
|
||||
been added to each release, please refer to the [blog](https://blog.gitea.io).
|
||||
|
||||
## [1.11.5](https://github.com/go-gitea/gitea/releases/tag/v1.11.5) - 2020-05-09
|
||||
|
||||
* BUGFIXES
|
||||
* Prevent timer leaks in Workerpool and others (#11333) (#11340)
|
||||
* Fix tracked time issues (#11349) (#11354)
|
||||
* Add NotifySyncPushCommits to indexer notifier (#11309) (#11338)
|
||||
* Allow X in addition to x in tasks (#10979) (#11335)
|
||||
* When delete tracked time through the API return 404 not 500 (#11319) (#11326)
|
||||
* Prevent duplicate records in organizations list when creating a repository (#11303) (#11325)
|
||||
* Manage port in submodule refurl (#11305) (#11323)
|
||||
* api.Context.NotFound(...) should tolerate nil (#11288) (#11306)
|
||||
* Show pull request selection even when unrelated branches (#11239) (#11283)
|
||||
* Repo: milestone: make /milestone/:id endpoint accessible (#11264) (#11282)
|
||||
* Fix GetContents(): Dont't ignore Executables (#11192) (#11209)
|
||||
* Fix submodule paths when AppSubUrl is not root (#11098) (#11176)
|
||||
* Prevent clones and pushes to disabled wiki (#11131) (#11134)
|
||||
* Remove errant third closing curly-bracket from account.tmpl and send account ID in account.tmpl (#11130)
|
||||
* On Repo Deletion: Delete related TrackedTimes too (#11110) (#11125)
|
||||
* Refresh codemirror on show pull comment tab (#11100) (#11122)
|
||||
* Fix merge dialog on protected branch with missing required statuses (#11074) (#11084)
|
||||
* Load pr Issue Poster on API too (#11033) (#11039)
|
||||
* Fix release counter on API repository info (#10968) (#10996)
|
||||
* Generate Diff and Patch direct from Pull head (#10936) (#10938)
|
||||
* Fix rebase conflict detection in git 2.26 (#10929) (#10930)
|
||||
* ENHANCEMENT
|
||||
* Fix 404 and 500 image size in small size screen (#11043) (#11049)
|
||||
* Multiple Gitea Doctor improvements (#10943) (#10990) (#10064) (#9095) (#10991)
|
||||
|
||||
## [1.11.4](https://github.com/go-gitea/gitea/releases/tag/v1.11.4) - 2020-04-01
|
||||
|
||||
* BUGFIXES
|
||||
* Only update merge_base if not already merged (#10909)
|
||||
* Fix milestones too many SQL variables bug (#10880) (#10904)
|
||||
* Protect against NPEs in notifications list (#10879) (#10883)
|
||||
* Convert plumbing.ErrObjectNotFound to git.ErrNotExist in getCommit (#10862) (#10868)
|
||||
* Convert plumbing.ErrReferenceNotFound to git.ErrNotExist in GetRefCommitID (#10676) (#10797)
|
||||
* Account for empty lines in receive-hook message (#10773) (#10784)
|
||||
* Fix bug on branch API (#10767) (#10775)
|
||||
* Migrate to go-git/go-git v5.0.0 (#10735) (#10753)
|
||||
* Fix hiding of fields in authorization source page (#10734) (#10752)
|
||||
* Prevent default for linkAction (#10742) (#10743)
|
||||
|
||||
## [1.11.3](https://github.com/go-gitea/gitea/releases/tag/v1.11.3) - 2020-03-10
|
||||
|
||||
* BUGFIXES
|
||||
@@ -519,6 +561,12 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
|
||||
* Update CodeMirror to version 5.49.0 (#8381)
|
||||
* Wiki editor: enable side-by-side button (#7242)
|
||||
|
||||
## [1.10.6](https://github.com/go-gitea/gitea/releases/tag/v1.10.6) - 2020-03-10
|
||||
|
||||
This is a re-tag version of v1.10.5 and also explicitly built with Go 1.13.
|
||||
|
||||
WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be used.
|
||||
|
||||
## [1.10.5](https://github.com/go-gitea/gitea/releases/tag/v1.10.5) - 2020-03-06
|
||||
|
||||
* BUGFIXES
|
||||
|
||||
496
cmd/doctor.go
Normal file
496
cmd/doctor.go
Normal file
@@ -0,0 +1,496 @@
|
||||
// Copyright 2019 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 (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
golog "log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/models/migrations"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/options"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"xorm.io/builder"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// CmdDoctor represents the available doctor sub-command.
|
||||
var CmdDoctor = cli.Command{
|
||||
Name: "doctor",
|
||||
Usage: "Diagnose problems",
|
||||
Description: "A command to diagnose problems with the current Gitea instance according to the given configuration.",
|
||||
Action: runDoctor,
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "list",
|
||||
Usage: "List the available checks",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "default",
|
||||
Usage: "Run the default checks (if neither --run or --all is set, this is the default behaviour)",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "run",
|
||||
Usage: "Run the provided checks - (if --default is set, the default checks will also run)",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "all",
|
||||
Usage: "Run all the available checks",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "fix",
|
||||
Usage: "Automatically fix what we can",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "log-file",
|
||||
Usage: `Name of the log file (default: "doctor.log"). Set to "-" to output to stdout, set to "" to disable`,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
type check struct {
|
||||
title string
|
||||
name string
|
||||
isDefault bool
|
||||
f func(ctx *cli.Context) ([]string, error)
|
||||
abortIfFailed bool
|
||||
skipDatabaseInit bool
|
||||
}
|
||||
|
||||
// checklist represents list for all checks
|
||||
var checklist = []check{
|
||||
{
|
||||
// NOTE: this check should be the first in the list
|
||||
title: "Check paths and basic configuration",
|
||||
name: "paths",
|
||||
isDefault: true,
|
||||
f: runDoctorPathInfo,
|
||||
abortIfFailed: true,
|
||||
skipDatabaseInit: true,
|
||||
},
|
||||
{
|
||||
title: "Check Database Version",
|
||||
name: "check-db",
|
||||
isDefault: true,
|
||||
f: runDoctorCheckDBVersion,
|
||||
abortIfFailed: true,
|
||||
},
|
||||
{
|
||||
title: "Check if OpenSSH authorized_keys file is up-to-date",
|
||||
name: "authorized_keys",
|
||||
isDefault: true,
|
||||
f: runDoctorAuthorizedKeys,
|
||||
},
|
||||
{
|
||||
title: "Check if SCRIPT_TYPE is available",
|
||||
name: "script-type",
|
||||
isDefault: false,
|
||||
f: runDoctorScriptType,
|
||||
},
|
||||
{
|
||||
title: "Check if hook files are up-to-date and executable",
|
||||
name: "hooks",
|
||||
isDefault: false,
|
||||
f: runDoctorHooks,
|
||||
},
|
||||
{
|
||||
title: "Recalculate merge bases",
|
||||
name: "recalculate_merge_bases",
|
||||
isDefault: false,
|
||||
f: runDoctorPRMergeBase,
|
||||
},
|
||||
// more checks please append here
|
||||
}
|
||||
|
||||
func runDoctor(ctx *cli.Context) error {
|
||||
|
||||
// Silence the default loggers
|
||||
log.DelNamedLogger("console")
|
||||
log.DelNamedLogger(log.DEFAULT)
|
||||
|
||||
// Now setup our own
|
||||
logFile := ctx.String("log-file")
|
||||
if !ctx.IsSet("log-file") {
|
||||
logFile = "doctor.log"
|
||||
}
|
||||
|
||||
if len(logFile) == 0 {
|
||||
log.NewLogger(1000, "doctor", "console", `{"level":"NONE","stacktracelevel":"NONE","colorize":"%t"}`)
|
||||
} else if logFile == "-" {
|
||||
log.NewLogger(1000, "doctor", "console", `{"level":"trace","stacktracelevel":"NONE"}`)
|
||||
} else {
|
||||
log.NewLogger(1000, "doctor", "file", fmt.Sprintf(`{"filename":%q,"level":"trace","stacktracelevel":"NONE"}`, logFile))
|
||||
}
|
||||
|
||||
// Finally redirect the default golog to here
|
||||
golog.SetFlags(0)
|
||||
golog.SetPrefix("")
|
||||
golog.SetOutput(log.NewLoggerAsWriter("INFO", log.GetLogger(log.DEFAULT)))
|
||||
|
||||
if ctx.IsSet("list") {
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 8, 0, '\t', 0)
|
||||
_, _ = w.Write([]byte("Default\tName\tTitle\n"))
|
||||
for _, check := range checklist {
|
||||
if check.isDefault {
|
||||
_, _ = w.Write([]byte{'*'})
|
||||
}
|
||||
_, _ = w.Write([]byte{'\t'})
|
||||
_, _ = w.Write([]byte(check.name))
|
||||
_, _ = w.Write([]byte{'\t'})
|
||||
_, _ = w.Write([]byte(check.title))
|
||||
_, _ = w.Write([]byte{'\n'})
|
||||
}
|
||||
return w.Flush()
|
||||
}
|
||||
|
||||
var checks []check
|
||||
if ctx.Bool("all") {
|
||||
checks = checklist
|
||||
} else if ctx.IsSet("run") {
|
||||
addDefault := ctx.Bool("default")
|
||||
names := ctx.StringSlice("run")
|
||||
for i, name := range names {
|
||||
names[i] = strings.ToLower(strings.TrimSpace(name))
|
||||
}
|
||||
|
||||
for _, check := range checklist {
|
||||
if addDefault && check.isDefault {
|
||||
checks = append(checks, check)
|
||||
continue
|
||||
}
|
||||
for _, name := range names {
|
||||
if name == check.name {
|
||||
checks = append(checks, check)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, check := range checklist {
|
||||
if check.isDefault {
|
||||
checks = append(checks, check)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dbIsInit := false
|
||||
|
||||
for i, check := range checks {
|
||||
if !dbIsInit && !check.skipDatabaseInit {
|
||||
// Only open database after the most basic configuration check
|
||||
setting.EnableXORMLog = false
|
||||
if err := initDBDisableConsole(true); err != nil {
|
||||
fmt.Println(err)
|
||||
fmt.Println("Check if you are using the right config file. You can use a --config directive to specify one.")
|
||||
return nil
|
||||
}
|
||||
dbIsInit = true
|
||||
}
|
||||
fmt.Println("[", i+1, "]", check.title)
|
||||
messages, err := check.f(ctx)
|
||||
for _, message := range messages {
|
||||
fmt.Println("-", message)
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Println("Error:", err)
|
||||
if check.abortIfFailed {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
fmt.Println("OK.")
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func runDoctorPathInfo(ctx *cli.Context) ([]string, error) {
|
||||
|
||||
res := make([]string, 0, 10)
|
||||
|
||||
if fi, err := os.Stat(setting.CustomConf); err != nil || !fi.Mode().IsRegular() {
|
||||
res = append(res, fmt.Sprintf("Failed to find configuration file at '%s'.", setting.CustomConf))
|
||||
res = append(res, fmt.Sprintf("If you've never ran Gitea yet, this is normal and '%s' will be created for you on first run.", setting.CustomConf))
|
||||
res = append(res, "Otherwise check that you are running this command from the correct path and/or provide a `--config` parameter.")
|
||||
return res, fmt.Errorf("can't proceed without a configuration file")
|
||||
}
|
||||
|
||||
setting.NewContext()
|
||||
|
||||
fail := false
|
||||
|
||||
check := func(name, path string, is_dir, required, is_write bool) {
|
||||
res = append(res, fmt.Sprintf("%-25s '%s'", name+":", path))
|
||||
fi, err := os.Stat(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) && ctx.Bool("fix") && is_dir {
|
||||
if err := os.MkdirAll(path, 0777); err != nil {
|
||||
res = append(res, fmt.Sprintf(" ERROR: %v", err))
|
||||
fail = true
|
||||
return
|
||||
}
|
||||
fi, err = os.Stat(path)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
if required {
|
||||
res = append(res, fmt.Sprintf(" ERROR: %v", err))
|
||||
fail = true
|
||||
return
|
||||
}
|
||||
res = append(res, fmt.Sprintf(" NOTICE: not accessible (%v)", err))
|
||||
return
|
||||
}
|
||||
|
||||
if is_dir && !fi.IsDir() {
|
||||
res = append(res, " ERROR: not a directory")
|
||||
fail = true
|
||||
return
|
||||
} else if !is_dir && !fi.Mode().IsRegular() {
|
||||
res = append(res, " ERROR: not a regular file")
|
||||
fail = true
|
||||
} else if is_write {
|
||||
if err := runDoctorWritableDir(path); err != nil {
|
||||
res = append(res, fmt.Sprintf(" ERROR: not writable: %v", err))
|
||||
fail = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note print paths inside quotes to make any leading/trailing spaces evident
|
||||
check("Configuration File Path", setting.CustomConf, false, true, false)
|
||||
check("Repository Root Path", setting.RepoRootPath, true, true, true)
|
||||
check("Data Root Path", setting.AppDataPath, true, true, true)
|
||||
check("Custom File Root Path", setting.CustomPath, true, false, false)
|
||||
check("Work directory", setting.AppWorkPath, true, true, false)
|
||||
check("Log Root Path", setting.LogRootPath, true, true, true)
|
||||
|
||||
if options.IsDynamic() {
|
||||
// Do not check/report on StaticRootPath if data is embedded in Gitea (-tags bindata)
|
||||
check("Static File Root Path", setting.StaticRootPath, true, true, false)
|
||||
}
|
||||
|
||||
if fail {
|
||||
return res, fmt.Errorf("please check your configuration file and try again")
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func runDoctorWritableDir(path string) error {
|
||||
// There's no platform-independent way of checking if a directory is writable
|
||||
// https://stackoverflow.com/questions/20026320/how-to-tell-if-folder-exists-and-is-writable
|
||||
|
||||
tmpFile, err := ioutil.TempFile(path, "doctors-order")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.Remove(tmpFile.Name()); err != nil {
|
||||
fmt.Printf("Warning: can't remove temporary file: '%s'\n", tmpFile.Name())
|
||||
}
|
||||
tmpFile.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
const tplCommentPrefix = `# gitea public key`
|
||||
|
||||
func runDoctorAuthorizedKeys(ctx *cli.Context) ([]string, error) {
|
||||
if setting.SSH.StartBuiltinServer || !setting.SSH.CreateAuthorizedKeysFile {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
fPath := filepath.Join(setting.SSH.RootPath, "authorized_keys")
|
||||
f, err := os.Open(fPath)
|
||||
if err != nil {
|
||||
if ctx.Bool("fix") {
|
||||
return []string{fmt.Sprintf("Error whilst opening authorized_keys: %v. Attempting regeneration", err)}, models.RewriteAllPublicKeys()
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
linesInAuthorizedKeys := map[string]bool{}
|
||||
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if strings.HasPrefix(line, tplCommentPrefix) {
|
||||
continue
|
||||
}
|
||||
linesInAuthorizedKeys[line] = true
|
||||
}
|
||||
f.Close()
|
||||
|
||||
// now we regenerate and check if there are any lines missing
|
||||
regenerated := &bytes.Buffer{}
|
||||
if err := models.RegeneratePublicKeys(regenerated); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
scanner = bufio.NewScanner(regenerated)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if strings.HasPrefix(line, tplCommentPrefix) {
|
||||
continue
|
||||
}
|
||||
if ok := linesInAuthorizedKeys[line]; ok {
|
||||
continue
|
||||
}
|
||||
if ctx.Bool("fix") {
|
||||
return []string{"authorized_keys is out of date, attempting regeneration"}, models.RewriteAllPublicKeys()
|
||||
}
|
||||
return nil, fmt.Errorf("authorized_keys is out of date and should be regenerated with gitea admin regenerate keys")
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func runDoctorCheckDBVersion(ctx *cli.Context) ([]string, error) {
|
||||
if err := models.NewEngine(context.Background(), migrations.EnsureUpToDate); err != nil {
|
||||
if ctx.Bool("fix") {
|
||||
return []string{fmt.Sprintf("WARN: Got Error %v during ensure up to date", err), "Attempting to migrate to the latest DB version to fix this."}, models.NewEngine(context.Background(), migrations.Migrate)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func iterateRepositories(each func(*models.Repository) ([]string, error)) ([]string, error) {
|
||||
results := []string{}
|
||||
err := models.Iterate(
|
||||
models.DefaultDBContext(),
|
||||
new(models.Repository),
|
||||
builder.Gt{"id": 0},
|
||||
func(idx int, bean interface{}) error {
|
||||
res, err := each(bean.(*models.Repository))
|
||||
results = append(results, res...)
|
||||
return err
|
||||
},
|
||||
)
|
||||
return results, err
|
||||
}
|
||||
|
||||
func iteratePRs(repo *models.Repository, each func(*models.Repository, *models.PullRequest) ([]string, error)) ([]string, error) {
|
||||
results := []string{}
|
||||
err := models.Iterate(
|
||||
models.DefaultDBContext(),
|
||||
new(models.PullRequest),
|
||||
builder.Eq{"base_repo_id": repo.ID},
|
||||
func(idx int, bean interface{}) error {
|
||||
res, err := each(repo, bean.(*models.PullRequest))
|
||||
results = append(results, res...)
|
||||
return err
|
||||
},
|
||||
)
|
||||
return results, err
|
||||
}
|
||||
|
||||
func runDoctorHooks(ctx *cli.Context) ([]string, error) {
|
||||
// Need to iterate across all of the repositories
|
||||
return iterateRepositories(func(repo *models.Repository) ([]string, error) {
|
||||
results, err := models.CheckDelegateHooks(repo.RepoPath())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(results) > 0 && ctx.Bool("fix") {
|
||||
return []string{fmt.Sprintf("regenerated hooks for %s", repo.FullName())}, models.CreateDelegateHooks(repo.RepoPath())
|
||||
}
|
||||
|
||||
return results, nil
|
||||
})
|
||||
}
|
||||
|
||||
func runDoctorPRMergeBase(ctx *cli.Context) ([]string, error) {
|
||||
numRepos := 0
|
||||
numPRs := 0
|
||||
numPRsUpdated := 0
|
||||
results, err := iterateRepositories(func(repo *models.Repository) ([]string, error) {
|
||||
numRepos++
|
||||
return iteratePRs(repo, func(repo *models.Repository, pr *models.PullRequest) ([]string, error) {
|
||||
numPRs++
|
||||
results := []string{}
|
||||
pr.BaseRepo = repo
|
||||
repoPath := repo.RepoPath()
|
||||
|
||||
oldMergeBase := pr.MergeBase
|
||||
|
||||
if !pr.HasMerged {
|
||||
var err error
|
||||
pr.MergeBase, err = git.NewCommand("merge-base", "--", pr.BaseBranch, pr.GetGitRefName()).RunInDir(repoPath)
|
||||
if err != nil {
|
||||
var err2 error
|
||||
pr.MergeBase, err2 = git.NewCommand("rev-parse", git.BranchPrefix+pr.BaseBranch).RunInDir(repoPath)
|
||||
if err2 != nil {
|
||||
results = append(results, fmt.Sprintf("WARN: Unable to get merge base for PR ID %d, #%d onto %s in %s/%s", pr.ID, pr.Index, pr.BaseBranch, pr.BaseRepo.OwnerName, pr.BaseRepo.Name))
|
||||
log.Error("Unable to get merge base for PR ID %d, Index %d in %s/%s. Error: %v & %v", pr.ID, pr.Index, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, err, err2)
|
||||
return results, nil
|
||||
}
|
||||
}
|
||||
} else {
|
||||
parentsString, err := git.NewCommand("rev-list", "--parents", "-n", "1", pr.MergedCommitID).RunInDir(repoPath)
|
||||
if err != nil {
|
||||
results = append(results, fmt.Sprintf("WARN: Unable to get parents for merged PR ID %d, #%d onto %s in %s/%s", pr.ID, pr.Index, pr.BaseBranch, pr.BaseRepo.OwnerName, pr.BaseRepo.Name))
|
||||
log.Error("Unable to get parents for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, err)
|
||||
return results, nil
|
||||
}
|
||||
parents := strings.Split(strings.TrimSpace(parentsString), " ")
|
||||
if len(parents) < 2 {
|
||||
return results, nil
|
||||
}
|
||||
|
||||
args := append([]string{"merge-base", "--"}, parents[1:]...)
|
||||
args = append(args, pr.GetGitRefName())
|
||||
|
||||
pr.MergeBase, err = git.NewCommand(args...).RunInDir(repoPath)
|
||||
if err != nil {
|
||||
results = append(results, fmt.Sprintf("WARN: Unable to get merge base for merged PR ID %d, #%d onto %s in %s/%s", pr.ID, pr.Index, pr.BaseBranch, pr.BaseRepo.OwnerName, pr.BaseRepo.Name))
|
||||
log.Error("Unable to get merge base for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, err)
|
||||
return results, nil
|
||||
}
|
||||
}
|
||||
pr.MergeBase = strings.TrimSpace(pr.MergeBase)
|
||||
if pr.MergeBase != oldMergeBase {
|
||||
if ctx.Bool("fix") {
|
||||
if err := pr.UpdateCols("merge_base"); err != nil {
|
||||
return results, err
|
||||
}
|
||||
} else {
|
||||
results = append(results, fmt.Sprintf("#%d onto %s in %s/%s: MergeBase should be %s but is %s", pr.Index, pr.BaseBranch, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, oldMergeBase, pr.MergeBase))
|
||||
}
|
||||
numPRsUpdated++
|
||||
}
|
||||
return results, nil
|
||||
})
|
||||
})
|
||||
|
||||
if ctx.Bool("fix") {
|
||||
results = append(results, fmt.Sprintf("%d PR mergebases updated of %d PRs total in %d repos", numPRsUpdated, numPRs, numRepos))
|
||||
} else {
|
||||
if numPRsUpdated > 0 && err == nil {
|
||||
return results, fmt.Errorf("%d PRs with incorrect mergebases of %d PRs total in %d repos", numPRsUpdated, numPRs, numRepos)
|
||||
}
|
||||
results = append(results, fmt.Sprintf("%d PRs with incorrect mergebases of %d PRs total in %d repos", numPRsUpdated, numPRs, numRepos))
|
||||
}
|
||||
|
||||
return results, err
|
||||
}
|
||||
|
||||
func runDoctorScriptType(ctx *cli.Context) ([]string, error) {
|
||||
path, err := exec.LookPath(setting.ScriptType)
|
||||
if err != nil {
|
||||
return []string{fmt.Sprintf("ScriptType %s is not on the current PATH", setting.ScriptType)}, err
|
||||
}
|
||||
return []string{fmt.Sprintf("ScriptType %s is on the current PATH at %s", setting.ScriptType, path)}, nil
|
||||
}
|
||||
12
cmd/hook.go
12
cmd/hook.go
@@ -19,6 +19,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/private"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
@@ -113,15 +114,8 @@ func (d *delayWriter) Close() error {
|
||||
if d == nil {
|
||||
return nil
|
||||
}
|
||||
stopped := d.timer.Stop()
|
||||
if stopped {
|
||||
return nil
|
||||
}
|
||||
select {
|
||||
case <-d.timer.C:
|
||||
default:
|
||||
}
|
||||
if d.buf == nil {
|
||||
stopped := util.StopTimer(d.timer)
|
||||
if stopped || d.buf == nil {
|
||||
return nil
|
||||
}
|
||||
_, err := d.internal.Write(d.buf.Bytes())
|
||||
|
||||
@@ -28,11 +28,11 @@ import (
|
||||
"code.gitea.io/gitea/routers"
|
||||
"code.gitea.io/gitea/routers/routes"
|
||||
|
||||
"github.com/go-git/go-git/v5"
|
||||
"github.com/go-git/go-git/v5/config"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
context2 "github.com/gorilla/context"
|
||||
"github.com/unknwon/com"
|
||||
"gopkg.in/src-d/go-git.v4"
|
||||
"gopkg.in/src-d/go-git.v4/config"
|
||||
"gopkg.in/src-d/go-git.v4/plumbing"
|
||||
"gopkg.in/testfixtures.v2"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
@@ -18,7 +18,7 @@ params:
|
||||
description: Git with a cup of tea
|
||||
author: The Gitea Authors
|
||||
website: https://docs.gitea.io
|
||||
version: 1.11.2
|
||||
version: 1.11.5
|
||||
|
||||
outputs:
|
||||
home:
|
||||
|
||||
12
go.mod
12
go.mod
@@ -41,6 +41,8 @@ require (
|
||||
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 // indirect
|
||||
github.com/gliderlabs/ssh v0.2.2
|
||||
github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a // indirect
|
||||
github.com/go-git/go-billy/v5 v5.0.0
|
||||
github.com/go-git/go-git/v5 v5.0.0
|
||||
github.com/go-openapi/jsonreference v0.19.3 // indirect
|
||||
github.com/go-redis/redis v6.15.2+incompatible
|
||||
github.com/go-sql-driver/mysql v1.4.1
|
||||
@@ -80,7 +82,7 @@ require (
|
||||
github.com/quasoft/websspi v1.0.0
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001 // indirect
|
||||
github.com/satori/go.uuid v1.2.0
|
||||
github.com/sergi/go-diff v1.0.0
|
||||
github.com/sergi/go-diff v1.1.0
|
||||
github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b // indirect
|
||||
github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd
|
||||
github.com/steveyen/gtreap v0.0.0-20150807155958-0abe01ef9be2 // indirect
|
||||
@@ -95,10 +97,10 @@ require (
|
||||
github.com/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53
|
||||
github.com/yuin/goldmark v1.1.19
|
||||
go.etcd.io/bbolt v1.3.3 // indirect
|
||||
golang.org/x/crypto v0.0.0-20200219234226-1ad67e1f0ef4
|
||||
golang.org/x/net v0.0.0-20191101175033-0deb6923b6d9
|
||||
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
||||
golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527
|
||||
golang.org/x/text v0.3.2
|
||||
golang.org/x/tools v0.0.0-20191213221258-04c2e8eff935 // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
@@ -106,8 +108,6 @@ require (
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||
gopkg.in/ini.v1 v1.51.1
|
||||
gopkg.in/ldap.v3 v3.0.2
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.2
|
||||
gopkg.in/src-d/go-git.v4 v4.13.1
|
||||
gopkg.in/testfixtures.v2 v2.5.0
|
||||
mvdan.cc/xurls/v2 v2.1.0
|
||||
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251
|
||||
|
||||
54
go.sum
54
go.sum
@@ -110,7 +110,7 @@ github.com/couchbase/vellum v0.0.0-20190829182332-ef2e028c01fd/go.mod h1:xbc8Ff/
|
||||
github.com/couchbaselabs/go-couchbase v0.0.0-20190708161019-23e7ca2ce2b7 h1:1XjEY/gnjQ+AfXef2U6dxCquhiRzkEpxZuWqs+QxTL8=
|
||||
github.com/couchbaselabs/go-couchbase v0.0.0-20190708161019-23e7ca2ce2b7/go.mod h1:mby/05p8HE5yHEAKiIH/555NoblMs7PtW6NrYshDruc=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
|
||||
github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d h1:SwD98825d6bdB+pEuTxWOXiSjBrHdOl/UVp75eI7JT8=
|
||||
github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8=
|
||||
@@ -164,6 +164,14 @@ github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a h1:FQqo
|
||||
github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
||||
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31 h1:gclg6gY70GLy3PbkQ1AERPfmLMMagS60DKF78eWwLn8=
|
||||
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
|
||||
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
|
||||
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
|
||||
github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM=
|
||||
github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.0.1 h1:q+IFMfLx200Q3scvt2hN79JsEzy4AmBTp/pqnefH+Bc=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
|
||||
github.com/go-git/go-git/v5 v5.0.0 h1:k5RWPm4iJwYtfWoxIJy4wJX9ON7ihPeZZYC1fLYDnpg=
|
||||
github.com/go-git/go-git/v5 v5.0.0/go.mod h1:oYD8y9kWsGINPFJoLdaScGCN6dlKg23blmClfZwtUVA=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
@@ -346,9 +354,10 @@ github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
|
||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/lafriks/xormstore v1.3.2 h1:hqi3F8s/B4rz8GuEZZDuHuOxRjeuOpEI/cC7vcnWwH4=
|
||||
github.com/lafriks/xormstore v1.3.2/go.mod h1:mVNIwIa25QIr8rfR7YlVjrqN/apswHkVdtLCyVYBzXw=
|
||||
github.com/lestrrat-go/jwx v0.9.0/go.mod h1:iEoxlYfZjvoGpuWwxUz+eR5e6KTJGsaRcy/YNA/UnBk=
|
||||
@@ -403,6 +412,8 @@ github.com/msteinert/pam v0.0.0-20151204160544-02ccfbfaf0cc/go.mod h1:np1wUFZ6ty
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5 h1:BvoENQQU+fZ9uukda/RzCAL/191HHwJA5b13R6diVlY=
|
||||
github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/niklasfasching/go-org v0.1.8 h1:Kjvs6lP+LIILHhc9zIJ4Gu90a/pVY483if2Qmu8v4Fg=
|
||||
github.com/niklasfasching/go-org v0.1.8/go.mod h1:AsLD6X7djzRIz4/RFZu8vwRL0VGjUvGZCCH1Nz0VdrU=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
@@ -417,7 +428,6 @@ github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo=
|
||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||
github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pelletier/go-toml v1.4.0 h1:u3Z1r+oOXJIkxqw34zVhyPgjBsm6X2wn21NWs/HfSeg=
|
||||
github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=
|
||||
@@ -463,12 +473,11 @@ github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqn
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001 h1:YDeskXpkNDhPdWN3REluVa46HQOVuVkjkd2sWnrABNQ=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b h1:4kg1wyftSKxLtnPAvcRWakIPpokB9w780/KwrNLnfPA=
|
||||
github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
||||
github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd h1:ug7PpSOB5RBPK1Kg6qskGBoP3Vnj/aNYFTznWvlkGo0=
|
||||
@@ -503,13 +512,10 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn
|
||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
|
||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||
github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4=
|
||||
github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
|
||||
github.com/steveyen/gtreap v0.0.0-20150807155958-0abe01ef9be2 h1:JNEGSiWg6D3lcBCMCBqN3ELniXujt+0QNHLhNnO0w3s=
|
||||
github.com/steveyen/gtreap v0.0.0-20150807155958-0abe01ef9be2/go.mod h1:mjqs7N0Q6m5HpR7QfXVBZXZWSqTjQLeTujjA/xUp2uw=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
@@ -533,7 +539,6 @@ github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGr
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/unknwon/cae v0.0.0-20190822084630-55a0b64484a1 h1:SpoCl3+Pta5/ubQyF+Fmx65obtpfkyzeaOIneCE3MTw=
|
||||
github.com/unknwon/cae v0.0.0-20190822084630-55a0b64484a1/go.mod h1:QaSeRctcea9fK6piJpAMCCPKxzJ01+xFcr2k1m3WRPU=
|
||||
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e h1:GSGeB9EAKY2spCABz6xOX5DbxZEXolK+nBSvmsQwRjM=
|
||||
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM=
|
||||
github.com/unknwon/com v1.0.1 h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs=
|
||||
github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM=
|
||||
@@ -579,11 +584,10 @@ golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190907121410-71b5226ff739/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad h1:5E5raQxcv+6CZ11RrBYQe5WRbUIWpScjh0kvHZkZIrQ=
|
||||
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200219234226-1ad67e1f0ef4 h1:4icQlpeqbz3WxfgP6Eq3szTj95KTrlH/CwzBzoxuFd0=
|
||||
golang.org/x/crypto v0.0.0-20200219234226-1ad67e1f0ef4/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM=
|
||||
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
@@ -615,8 +619,8 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191101175033-0deb6923b6d9 h1:DPz9iiH3YoKiKhX/ijjoZvT0VFwK2c6CWYWQ7Zyr8TU=
|
||||
golang.org/x/net v0.0.0-20191101175033-0deb6923b6d9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -646,15 +650,13 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190730183949-1393eb018365/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190907184412-d223b2b6db03/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY=
|
||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c h1:jceGD5YNJGgGMkJz79agzOln1K9TaZUjv5ird16qniQ=
|
||||
golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
@@ -676,7 +678,6 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw
|
||||
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
||||
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191213221258-04c2e8eff935 h1:kJQZhwFzSwJS2BxboKjdZzWczQOZx8VuH7Y8hhuGUtM=
|
||||
golang.org/x/tools v0.0.0-20191213221258-04c2e8eff935/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
@@ -716,8 +717,9 @@ gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 h1:nn6Zav2sOQHCFJHEspya8
|
||||
gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
|
||||
@@ -732,12 +734,6 @@ gopkg.in/ldap.v3 v3.0.2 h1:R6RBtabK6e1GO0eQKtkyOFbAHO73QesLzI2w2DZ6b9w=
|
||||
gopkg.in/ldap.v3 v3.0.2/go.mod h1:oxD7NyBuxchC+SgJDE1Q5Od05eGt29SDQVBmV+HYbzw=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg=
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98=
|
||||
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg=
|
||||
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
|
||||
gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE=
|
||||
gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8=
|
||||
gopkg.in/testfixtures.v2 v2.5.0 h1:N08B7l2GzFQenyYbzqthDnKAA+cmb17iAZhhFxr7JHw=
|
||||
gopkg.in/testfixtures.v2 v2.5.0/go.mod h1:vyAq+MYCgNpR29qitQdLZhdbLFf4mR/2MFJRFoQZZ2M=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
@@ -746,8 +742,9 @@ gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
@@ -761,7 +758,6 @@ xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8=
|
||||
xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU=
|
||||
xorm.io/core v0.7.2 h1:mEO22A2Z7a3fPaZMk6gKL/jMD80iiyNwRrX5HOv3XLw=
|
||||
xorm.io/core v0.7.2/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM=
|
||||
xorm.io/xorm v0.8.0 h1:iALxgJrX8O00f8Jk22GbZwPmxJNgssV5Mv4uc2HL9PM=
|
||||
xorm.io/xorm v0.8.0/go.mod h1:ZkJLEYLoVyg7amJK/5r779bHyzs2AU8f8VMiP6BM7uY=
|
||||
xorm.io/xorm v0.8.1 h1:4f2KXuQxVdaX3RdI3Fw81NzMiSpZeyCZt8m3sEVeIkQ=
|
||||
xorm.io/xorm v0.8.1/go.mod h1:ZkJLEYLoVyg7amJK/5r779bHyzs2AU8f8VMiP6BM7uY=
|
||||
|
||||
@@ -28,6 +28,8 @@ func testAPIGetBranch(t *testing.T, branchName string, exists bool) {
|
||||
var branch api.Branch
|
||||
DecodeJSON(t, resp, &branch)
|
||||
assert.EqualValues(t, branchName, branch.Name)
|
||||
assert.True(t, branch.UserCanPush)
|
||||
assert.True(t, branch.UserCanMerge)
|
||||
}
|
||||
|
||||
func TestAPIGetBranch(t *testing.T) {
|
||||
|
||||
@@ -60,17 +60,17 @@ func TestAPIDeleteTrackedTime(t *testing.T) {
|
||||
//Deletion not allowed
|
||||
req := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/%d/times/%d?token=%s", user2.Name, issue2.Repo.Name, issue2.Index, time6.ID, token)
|
||||
session.MakeRequest(t, req, http.StatusForbidden)
|
||||
/* Delete own time <-- ToDo: timout without reason
|
||||
|
||||
time3 := models.AssertExistsAndLoadBean(t, &models.TrackedTime{ID: 3}).(*models.TrackedTime)
|
||||
req = NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/%d/times/%d?token=%s", user2.Name, issue2.Repo.Name, issue2.Index, time3.ID, token)
|
||||
session.MakeRequest(t, req, http.StatusNoContent)
|
||||
//Delete non existing time
|
||||
session.MakeRequest(t, req, http.StatusInternalServerError) */
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
//Reset time of user 2 on issue 2
|
||||
trackedSeconds, err := models.GetTrackedSeconds(models.FindTrackedTimesOptions{IssueID: 2, UserID: 2})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(3662), trackedSeconds)
|
||||
assert.Equal(t, int64(3661), trackedSeconds)
|
||||
|
||||
req = NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/%d/times?token=%s", user2.Name, issue2.Repo.Name, issue2.Index, token)
|
||||
session.MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
@@ -209,13 +209,31 @@ func getRepo(t *testing.T, repoID int64) *models.Repository {
|
||||
func TestAPIViewRepo(t *testing.T) {
|
||||
defer prepareTestEnv(t)()
|
||||
|
||||
var repo api.Repository
|
||||
|
||||
req := NewRequest(t, "GET", "/api/v1/repos/user2/repo1")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var repo api.Repository
|
||||
DecodeJSON(t, resp, &repo)
|
||||
assert.EqualValues(t, 1, repo.ID)
|
||||
assert.EqualValues(t, "repo1", repo.Name)
|
||||
assert.EqualValues(t, 1, repo.Releases)
|
||||
assert.EqualValues(t, 1, repo.OpenIssues)
|
||||
assert.EqualValues(t, 2, repo.OpenPulls)
|
||||
|
||||
req = NewRequest(t, "GET", "/api/v1/repos/user12/repo10")
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &repo)
|
||||
assert.EqualValues(t, 10, repo.ID)
|
||||
assert.EqualValues(t, "repo10", repo.Name)
|
||||
assert.EqualValues(t, 1, repo.OpenPulls)
|
||||
assert.EqualValues(t, 1, repo.Forks)
|
||||
|
||||
req = NewRequest(t, "GET", "/api/v1/repos/user5/repo4")
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &repo)
|
||||
assert.EqualValues(t, 4, repo.ID)
|
||||
assert.EqualValues(t, "repo4", repo.Name)
|
||||
assert.EqualValues(t, 1, repo.Stars)
|
||||
}
|
||||
|
||||
func TestAPIOrgRepos(t *testing.T) {
|
||||
|
||||
@@ -71,7 +71,6 @@ func testGit(t *testing.T, u *url.URL) {
|
||||
t.Run("BranchProtectMerge", doBranchProtectPRMerge(&httpContext, dstPath))
|
||||
t.Run("MergeFork", func(t *testing.T) {
|
||||
t.Run("CreatePRAndMerge", doMergeFork(httpContext, forkedUserCtx, "master", httpContext.Username+":master"))
|
||||
t.Run("DeleteRepository", doAPIDeleteRepository(httpContext))
|
||||
rawTest(t, &forkedUserCtx, little, big, littleLFS, bigLFS)
|
||||
mediaTest(t, &forkedUserCtx, little, big, littleLFS, bigLFS)
|
||||
})
|
||||
@@ -111,7 +110,6 @@ func testGit(t *testing.T, u *url.URL) {
|
||||
t.Run("BranchProtectMerge", doBranchProtectPRMerge(&sshContext, dstPath))
|
||||
t.Run("MergeFork", func(t *testing.T) {
|
||||
t.Run("CreatePRAndMerge", doMergeFork(sshContext, forkedUserCtx, "master", sshContext.Username+":master"))
|
||||
t.Run("DeleteRepository", doAPIDeleteRepository(sshContext))
|
||||
rawTest(t, &forkedUserCtx, little, big, littleLFS, bigLFS)
|
||||
mediaTest(t, &forkedUserCtx, little, big, littleLFS, bigLFS)
|
||||
})
|
||||
@@ -419,8 +417,62 @@ func doMergeFork(ctx, baseCtx APITestContext, baseBranch, headBranch string) fun
|
||||
pr, err = doAPICreatePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, baseBranch, headBranch)(t)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("EnsureCanSeePull", func(t *testing.T) {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d", url.PathEscape(baseCtx.Username), url.PathEscape(baseCtx.Reponame), pr.Index))
|
||||
ctx.Session.MakeRequest(t, req, http.StatusOK)
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d/files", url.PathEscape(baseCtx.Username), url.PathEscape(baseCtx.Reponame), pr.Index))
|
||||
ctx.Session.MakeRequest(t, req, http.StatusOK)
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d/commits", url.PathEscape(baseCtx.Username), url.PathEscape(baseCtx.Reponame), pr.Index))
|
||||
ctx.Session.MakeRequest(t, req, http.StatusOK)
|
||||
})
|
||||
var diffStr string
|
||||
t.Run("GetDiff", func(t *testing.T) {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d.diff", url.PathEscape(baseCtx.Username), url.PathEscape(baseCtx.Reponame), pr.Index))
|
||||
resp := ctx.Session.MakeRequest(t, req, http.StatusOK)
|
||||
diffStr = resp.Body.String()
|
||||
})
|
||||
t.Run("MergePR", doAPIMergePullRequest(baseCtx, baseCtx.Username, baseCtx.Reponame, pr.Index))
|
||||
|
||||
t.Run("EnsureCanSeePull", func(t *testing.T) {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d", url.PathEscape(baseCtx.Username), url.PathEscape(baseCtx.Reponame), pr.Index))
|
||||
ctx.Session.MakeRequest(t, req, http.StatusOK)
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d/files", url.PathEscape(baseCtx.Username), url.PathEscape(baseCtx.Reponame), pr.Index))
|
||||
ctx.Session.MakeRequest(t, req, http.StatusOK)
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d/commits", url.PathEscape(baseCtx.Username), url.PathEscape(baseCtx.Reponame), pr.Index))
|
||||
ctx.Session.MakeRequest(t, req, http.StatusOK)
|
||||
})
|
||||
t.Run("EnsureDiffNoChange", func(t *testing.T) {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d.diff", url.PathEscape(baseCtx.Username), url.PathEscape(baseCtx.Reponame), pr.Index))
|
||||
resp := ctx.Session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.Equal(t, diffStr, resp.Body.String())
|
||||
})
|
||||
t.Run("DeleteHeadBranch", doBranchDelete(baseCtx, baseCtx.Username, baseCtx.Reponame, headBranch))
|
||||
t.Run("EnsureCanSeePull", func(t *testing.T) {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d", url.PathEscape(baseCtx.Username), url.PathEscape(baseCtx.Reponame), pr.Index))
|
||||
ctx.Session.MakeRequest(t, req, http.StatusOK)
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d/files", url.PathEscape(baseCtx.Username), url.PathEscape(baseCtx.Reponame), pr.Index))
|
||||
ctx.Session.MakeRequest(t, req, http.StatusOK)
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d/commits", url.PathEscape(baseCtx.Username), url.PathEscape(baseCtx.Reponame), pr.Index))
|
||||
ctx.Session.MakeRequest(t, req, http.StatusOK)
|
||||
})
|
||||
t.Run("EnsureDiffNoChange", func(t *testing.T) {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d.diff", url.PathEscape(baseCtx.Username), url.PathEscape(baseCtx.Reponame), pr.Index))
|
||||
resp := ctx.Session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.Equal(t, diffStr, resp.Body.String())
|
||||
})
|
||||
t.Run("DeleteRepository", doAPIDeleteRepository(ctx))
|
||||
t.Run("EnsureCanSeePull", func(t *testing.T) {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d", url.PathEscape(baseCtx.Username), url.PathEscape(baseCtx.Reponame), pr.Index))
|
||||
ctx.Session.MakeRequest(t, req, http.StatusOK)
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d/files", url.PathEscape(baseCtx.Username), url.PathEscape(baseCtx.Reponame), pr.Index))
|
||||
ctx.Session.MakeRequest(t, req, http.StatusOK)
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d/commits", url.PathEscape(baseCtx.Username), url.PathEscape(baseCtx.Reponame), pr.Index))
|
||||
ctx.Session.MakeRequest(t, req, http.StatusOK)
|
||||
})
|
||||
t.Run("EnsureDiffNoChange", func(t *testing.T) {
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d.diff", url.PathEscape(baseCtx.Username), url.PathEscape(baseCtx.Reponame), pr.Index))
|
||||
resp := ctx.Session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.Equal(t, diffStr, resp.Body.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -493,3 +545,14 @@ func doPushCreate(ctx APITestContext, u *url.URL) func(t *testing.T) {
|
||||
assert.True(t, repo.IsPrivate)
|
||||
}
|
||||
}
|
||||
|
||||
func doBranchDelete(ctx APITestContext, owner, repo, branch string) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
csrf := GetCSRF(t, ctx.Session, fmt.Sprintf("/%s/%s/branches", url.PathEscape(owner), url.PathEscape(repo)))
|
||||
|
||||
req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/branches/delete?name=%s", url.PathEscape(owner), url.PathEscape(repo), url.QueryEscape(branch)), map[string]string{
|
||||
"_csrf": csrf,
|
||||
})
|
||||
ctx.Session.MakeRequest(t, req, http.StatusOK)
|
||||
}
|
||||
}
|
||||
|
||||
1
main.go
1
main.go
@@ -68,6 +68,7 @@ arguments - which can alternatively be run by running the subcommand web.`
|
||||
cmd.CmdMigrate,
|
||||
cmd.CmdKeys,
|
||||
cmd.CmdConvert,
|
||||
cmd.CmdDoctor,
|
||||
}
|
||||
// Now adjust these commands to add our global configuration options
|
||||
|
||||
|
||||
@@ -113,6 +113,28 @@ func (protectBranch *ProtectedBranch) CanUserMerge(userID int64) bool {
|
||||
return in
|
||||
}
|
||||
|
||||
// IsUserMergeWhitelisted checks if some user is whitelisted to merge to this branch
|
||||
func (protectBranch *ProtectedBranch) IsUserMergeWhitelisted(userID int64) bool {
|
||||
if !protectBranch.EnableMergeWhitelist {
|
||||
return true
|
||||
}
|
||||
|
||||
if base.Int64sContains(protectBranch.MergeWhitelistUserIDs, userID) {
|
||||
return true
|
||||
}
|
||||
|
||||
if len(protectBranch.MergeWhitelistTeamIDs) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
in, err := IsUserInTeams(userID, protectBranch.MergeWhitelistTeamIDs)
|
||||
if err != nil {
|
||||
log.Error("IsUserInTeams: %v", err)
|
||||
return false
|
||||
}
|
||||
return in
|
||||
}
|
||||
|
||||
// IsUserOfficialReviewer check if user is official reviewer for the branch (counts towards required approvals)
|
||||
func (protectBranch *ProtectedBranch) IsUserOfficialReviewer(user *User) (bool, error) {
|
||||
return protectBranch.isUserOfficialReviewer(x, user)
|
||||
|
||||
@@ -4,6 +4,11 @@
|
||||
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
// DBContext represents a db context
|
||||
type DBContext struct {
|
||||
e Engine
|
||||
@@ -53,3 +58,10 @@ func WithTx(f func(ctx DBContext) error) error {
|
||||
sess.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
// Iterate iterates the databases and doing something
|
||||
func Iterate(ctx DBContext, tableBean interface{}, cond builder.Cond, fun func(idx int, bean interface{}) error) error {
|
||||
return ctx.e.Where(cond).
|
||||
BufferSize(setting.Database.IterateBufferSize).
|
||||
Iterate(tableBean, fun)
|
||||
}
|
||||
|
||||
@@ -1407,7 +1407,7 @@ func (err *ErrPushRejected) GenerateMessage() {
|
||||
}
|
||||
i += 8
|
||||
nl := strings.IndexByte(err.StdErr[i:], '\n')
|
||||
if nl > 0 {
|
||||
if nl >= 0 {
|
||||
messageBuilder.WriteString(err.StdErr[i : i+nl+1])
|
||||
i = i + nl + 1
|
||||
} else {
|
||||
|
||||
@@ -74,8 +74,8 @@ var (
|
||||
issueTasksDonePat *regexp.Regexp
|
||||
)
|
||||
|
||||
const issueTasksRegexpStr = `(^\s*[-*]\s\[[\sx]\]\s.)|(\n\s*[-*]\s\[[\sx]\]\s.)`
|
||||
const issueTasksDoneRegexpStr = `(^\s*[-*]\s\[[x]\]\s.)|(\n\s*[-*]\s\[[x]\]\s.)`
|
||||
const issueTasksRegexpStr = `(^\s*[-*]\s\[[\sxX]\]\s.)|(\n\s*[-*]\s\[[\sxX]\]\s.)`
|
||||
const issueTasksDoneRegexpStr = `(^\s*[-*]\s\[[xX]\]\s.)|(\n\s*[-*]\s\[[xX]\]\s.)`
|
||||
const issueMaxDupIndexAttempts = 3
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -521,10 +521,12 @@ func DeleteMilestoneByRepoID(repoID, id int64) error {
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
// CountMilestonesByRepoIDs map from repoIDs to number of milestones matching the options`
|
||||
func CountMilestonesByRepoIDs(repoIDs []int64, isClosed bool) (map[int64]int64, error) {
|
||||
// CountMilestones map from repo conditions to number of milestones matching the options`
|
||||
func CountMilestones(repoCond builder.Cond, isClosed bool) (map[int64]int64, error) {
|
||||
sess := x.Where("is_closed = ?", isClosed)
|
||||
sess.In("repo_id", repoIDs)
|
||||
if repoCond.IsValid() {
|
||||
sess.In("repo_id", builder.Select("id").From("repository").Where(repoCond))
|
||||
}
|
||||
|
||||
countsSlice := make([]*struct {
|
||||
RepoID int64
|
||||
@@ -544,11 +546,21 @@ func CountMilestonesByRepoIDs(repoIDs []int64, isClosed bool) (map[int64]int64,
|
||||
return countMap, nil
|
||||
}
|
||||
|
||||
// GetMilestonesByRepoIDs returns a list of milestones of given repositories and status.
|
||||
func GetMilestonesByRepoIDs(repoIDs []int64, page int, isClosed bool, sortType string) (MilestoneList, error) {
|
||||
// CountMilestonesByRepoIDs map from repoIDs to number of milestones matching the options`
|
||||
func CountMilestonesByRepoIDs(repoIDs []int64, isClosed bool) (map[int64]int64, error) {
|
||||
return CountMilestones(
|
||||
builder.In("repo_id", repoIDs),
|
||||
isClosed,
|
||||
)
|
||||
}
|
||||
|
||||
// SearchMilestones search milestones
|
||||
func SearchMilestones(repoCond builder.Cond, page int, isClosed bool, sortType string) (MilestoneList, error) {
|
||||
miles := make([]*Milestone, 0, setting.UI.IssuePagingNum)
|
||||
sess := x.Where("is_closed = ?", isClosed)
|
||||
sess.In("repo_id", repoIDs)
|
||||
if repoCond.IsValid() {
|
||||
sess.In("repo_id", builder.Select("id").From("repository").Where(repoCond))
|
||||
}
|
||||
if page > 0 {
|
||||
sess = sess.Limit(setting.UI.IssuePagingNum, (page-1)*setting.UI.IssuePagingNum)
|
||||
}
|
||||
@@ -570,25 +582,45 @@ func GetMilestonesByRepoIDs(repoIDs []int64, page int, isClosed bool, sortType s
|
||||
return miles, sess.Find(&miles)
|
||||
}
|
||||
|
||||
// GetMilestonesByRepoIDs returns a list of milestones of given repositories and status.
|
||||
func GetMilestonesByRepoIDs(repoIDs []int64, page int, isClosed bool, sortType string) (MilestoneList, error) {
|
||||
return SearchMilestones(
|
||||
builder.In("repo_id", repoIDs),
|
||||
page,
|
||||
isClosed,
|
||||
sortType,
|
||||
)
|
||||
}
|
||||
|
||||
// MilestonesStats represents milestone statistic information.
|
||||
type MilestonesStats struct {
|
||||
OpenCount, ClosedCount int64
|
||||
}
|
||||
|
||||
// Total returns the total counts of milestones
|
||||
func (m MilestonesStats) Total() int64 {
|
||||
return m.OpenCount + m.ClosedCount
|
||||
}
|
||||
|
||||
// GetMilestonesStats returns milestone statistic information for dashboard by given conditions.
|
||||
func GetMilestonesStats(userRepoIDs []int64) (*MilestonesStats, error) {
|
||||
func GetMilestonesStats(repoCond builder.Cond) (*MilestonesStats, error) {
|
||||
var err error
|
||||
stats := &MilestonesStats{}
|
||||
|
||||
stats.OpenCount, err = x.Where("is_closed = ?", false).
|
||||
And(builder.In("repo_id", userRepoIDs)).
|
||||
Count(new(Milestone))
|
||||
sess := x.Where("is_closed = ?", false)
|
||||
if repoCond.IsValid() {
|
||||
sess.And(builder.In("repo_id", builder.Select("id").From("repository").Where(repoCond)))
|
||||
}
|
||||
stats.OpenCount, err = sess.Count(new(Milestone))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stats.ClosedCount, err = x.Where("is_closed = ?", true).
|
||||
And(builder.In("repo_id", userRepoIDs)).
|
||||
Count(new(Milestone))
|
||||
|
||||
sess = x.Where("is_closed = ?", true)
|
||||
if repoCond.IsValid() {
|
||||
sess.And(builder.In("repo_id", builder.Select("id").From("repository").Where(repoCond)))
|
||||
}
|
||||
stats.ClosedCount, err = sess.Count(new(Milestone))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"xorm.io/builder"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -370,7 +371,7 @@ func TestGetMilestonesStats(t *testing.T) {
|
||||
repo1 := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
|
||||
repo2 := AssertExistsAndLoadBean(t, &Repository{ID: 2}).(*Repository)
|
||||
|
||||
milestoneStats, err := GetMilestonesStats([]int64{repo1.ID, repo2.ID})
|
||||
milestoneStats, err := GetMilestonesStats(builder.In("repo_id", []int64{repo1.ID, repo2.ID}))
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, repo1.NumOpenMilestones+repo2.NumOpenMilestones, milestoneStats.OpenCount)
|
||||
assert.EqualValues(t, repo1.NumClosedMilestones+repo2.NumClosedMilestones, milestoneStats.ClosedCount)
|
||||
|
||||
@@ -273,6 +273,10 @@ func DeleteTime(t *TrackedTime) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := t.loadAttributes(sess); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := deleteTime(sess, t); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -312,10 +316,8 @@ func deleteTime(e Engine, t *TrackedTime) error {
|
||||
|
||||
// GetTrackedTimeByID returns raw TrackedTime without loading attributes by id
|
||||
func GetTrackedTimeByID(id int64) (*TrackedTime, error) {
|
||||
time := &TrackedTime{
|
||||
ID: id,
|
||||
}
|
||||
has, err := x.Get(time)
|
||||
time := new(TrackedTime)
|
||||
has, err := x.ID(id).Get(time)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !has {
|
||||
|
||||
@@ -292,6 +292,52 @@ var migrations = []Migration{
|
||||
NewMigration("Add block on rejected reviews branch protection", addBlockOnRejectedReviews),
|
||||
}
|
||||
|
||||
// GetCurrentDBVersion returns the current db version
|
||||
func GetCurrentDBVersion(x *xorm.Engine) (int64, error) {
|
||||
if err := x.Sync(new(Version)); err != nil {
|
||||
return -1, fmt.Errorf("sync: %v", err)
|
||||
}
|
||||
|
||||
currentVersion := &Version{ID: 1}
|
||||
has, err := x.Get(currentVersion)
|
||||
if err != nil {
|
||||
return -1, fmt.Errorf("get: %v", err)
|
||||
}
|
||||
if !has {
|
||||
return -1, nil
|
||||
}
|
||||
return currentVersion.Version, nil
|
||||
}
|
||||
|
||||
// ExpectedVersion returns the expected db version
|
||||
func ExpectedVersion() int64 {
|
||||
return int64(minDBVersion + len(migrations))
|
||||
}
|
||||
|
||||
// EnsureUpToDate will check if the db is at the correct version
|
||||
func EnsureUpToDate(x *xorm.Engine) error {
|
||||
currentDB, err := GetCurrentDBVersion(x)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if currentDB < 0 {
|
||||
return fmt.Errorf("Database has not been initialised")
|
||||
}
|
||||
|
||||
if minDBVersion > currentDB {
|
||||
return fmt.Errorf("DB version %d (<= %d) is too old for auto-migration. Upgrade to Gitea 1.6.4 first then upgrade to this version", currentDB, minDBVersion)
|
||||
}
|
||||
|
||||
expected := ExpectedVersion()
|
||||
|
||||
if currentDB != expected {
|
||||
return fmt.Errorf(`Current database version %d is not equal to the expected version %d. Please run "gitea [--config /path/to/app.ini] migrate" to update the database version`, currentDB, expected)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Migrate database to current version
|
||||
func Migrate(x *xorm.Engine) error {
|
||||
if err := x.Sync(new(Version)); err != nil {
|
||||
|
||||
@@ -7,6 +7,7 @@ package models
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
)
|
||||
|
||||
@@ -281,9 +282,9 @@ func (nl NotificationList) getPendingRepoIDs() []int64 {
|
||||
}
|
||||
|
||||
// LoadRepos loads repositories from database
|
||||
func (nl NotificationList) LoadRepos() (RepositoryList, error) {
|
||||
func (nl NotificationList) LoadRepos() (RepositoryList, []int, error) {
|
||||
if len(nl) == 0 {
|
||||
return RepositoryList{}, nil
|
||||
return RepositoryList{}, []int{}, nil
|
||||
}
|
||||
|
||||
var repoIDs = nl.getPendingRepoIDs()
|
||||
@@ -298,7 +299,7 @@ func (nl NotificationList) LoadRepos() (RepositoryList, error) {
|
||||
In("id", repoIDs[:limit]).
|
||||
Rows(new(Repository))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
for rows.Next() {
|
||||
@@ -306,7 +307,7 @@ func (nl NotificationList) LoadRepos() (RepositoryList, error) {
|
||||
err = rows.Scan(&repo)
|
||||
if err != nil {
|
||||
rows.Close()
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
repos[repo.ID] = &repo
|
||||
@@ -317,14 +318,21 @@ func (nl NotificationList) LoadRepos() (RepositoryList, error) {
|
||||
repoIDs = repoIDs[limit:]
|
||||
}
|
||||
|
||||
failed := []int{}
|
||||
|
||||
var reposList = make(RepositoryList, 0, len(repoIDs))
|
||||
for _, notification := range nl {
|
||||
for i, notification := range nl {
|
||||
if notification.Repository == nil {
|
||||
notification.Repository = repos[notification.RepoID]
|
||||
}
|
||||
if notification.Repository == nil {
|
||||
log.Error("Notification[%d]: RepoID: %d not found", notification.ID, notification.RepoID)
|
||||
failed = append(failed, i)
|
||||
continue
|
||||
}
|
||||
var found bool
|
||||
for _, r := range reposList {
|
||||
if r.ID == notification.Repository.ID {
|
||||
if r.ID == notification.RepoID {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
@@ -333,7 +341,7 @@ func (nl NotificationList) LoadRepos() (RepositoryList, error) {
|
||||
reposList = append(reposList, notification.Repository)
|
||||
}
|
||||
}
|
||||
return reposList, nil
|
||||
return reposList, failed, nil
|
||||
}
|
||||
|
||||
func (nl NotificationList) getPendingIssueIDs() []int64 {
|
||||
@@ -350,9 +358,9 @@ func (nl NotificationList) getPendingIssueIDs() []int64 {
|
||||
}
|
||||
|
||||
// LoadIssues loads issues from database
|
||||
func (nl NotificationList) LoadIssues() error {
|
||||
func (nl NotificationList) LoadIssues() ([]int, error) {
|
||||
if len(nl) == 0 {
|
||||
return nil
|
||||
return []int{}, nil
|
||||
}
|
||||
|
||||
var issueIDs = nl.getPendingIssueIDs()
|
||||
@@ -367,7 +375,7 @@ func (nl NotificationList) LoadIssues() error {
|
||||
In("id", issueIDs[:limit]).
|
||||
Rows(new(Issue))
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for rows.Next() {
|
||||
@@ -375,7 +383,7 @@ func (nl NotificationList) LoadIssues() error {
|
||||
err = rows.Scan(&issue)
|
||||
if err != nil {
|
||||
rows.Close()
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
issues[issue.ID] = &issue
|
||||
@@ -386,13 +394,38 @@ func (nl NotificationList) LoadIssues() error {
|
||||
issueIDs = issueIDs[limit:]
|
||||
}
|
||||
|
||||
for _, notification := range nl {
|
||||
failures := []int{}
|
||||
|
||||
for i, notification := range nl {
|
||||
if notification.Issue == nil {
|
||||
notification.Issue = issues[notification.IssueID]
|
||||
if notification.Issue == nil {
|
||||
log.Error("Notification[%d]: IssueID: %d Not Found", notification.ID, notification.IssueID)
|
||||
failures = append(failures, i)
|
||||
continue
|
||||
}
|
||||
notification.Issue.Repo = notification.Repository
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return failures, nil
|
||||
}
|
||||
|
||||
// Without returns the notification list without the failures
|
||||
func (nl NotificationList) Without(failures []int) NotificationList {
|
||||
if len(failures) == 0 {
|
||||
return nl
|
||||
}
|
||||
remaining := make([]*Notification, 0, len(nl))
|
||||
last := -1
|
||||
var i int
|
||||
for _, i = range failures {
|
||||
remaining = append(remaining, nl[last+1:i]...)
|
||||
last = i
|
||||
}
|
||||
if len(nl) > i {
|
||||
remaining = append(remaining, nl[i+1:]...)
|
||||
}
|
||||
return remaining
|
||||
}
|
||||
|
||||
func (nl NotificationList) getPendingCommentIDs() []int64 {
|
||||
@@ -409,9 +442,9 @@ func (nl NotificationList) getPendingCommentIDs() []int64 {
|
||||
}
|
||||
|
||||
// LoadComments loads comments from database
|
||||
func (nl NotificationList) LoadComments() error {
|
||||
func (nl NotificationList) LoadComments() ([]int, error) {
|
||||
if len(nl) == 0 {
|
||||
return nil
|
||||
return []int{}, nil
|
||||
}
|
||||
|
||||
var commentIDs = nl.getPendingCommentIDs()
|
||||
@@ -426,7 +459,7 @@ func (nl NotificationList) LoadComments() error {
|
||||
In("id", commentIDs[:limit]).
|
||||
Rows(new(Comment))
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for rows.Next() {
|
||||
@@ -434,7 +467,7 @@ func (nl NotificationList) LoadComments() error {
|
||||
err = rows.Scan(&comment)
|
||||
if err != nil {
|
||||
rows.Close()
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
comments[comment.ID] = &comment
|
||||
@@ -445,13 +478,19 @@ func (nl NotificationList) LoadComments() error {
|
||||
commentIDs = commentIDs[limit:]
|
||||
}
|
||||
|
||||
for _, notification := range nl {
|
||||
failures := []int{}
|
||||
for i, notification := range nl {
|
||||
if notification.CommentID > 0 && notification.Comment == nil && comments[notification.CommentID] != nil {
|
||||
notification.Comment = comments[notification.CommentID]
|
||||
if notification.Comment == nil {
|
||||
log.Error("Notification[%d]: CommentID[%d] failed to load", notification.ID, notification.CommentID)
|
||||
failures = append(failures, i)
|
||||
continue
|
||||
}
|
||||
notification.Comment.Issue = notification.Issue
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return failures, nil
|
||||
}
|
||||
|
||||
// GetNotificationCount returns the notification count for user
|
||||
|
||||
@@ -470,12 +470,12 @@ func GetOwnedOrgsByUserIDDesc(userID int64, desc string) ([]*User, error) {
|
||||
func GetOrgsCanCreateRepoByUserID(userID int64) ([]*User, error) {
|
||||
orgs := make([]*User, 0, 10)
|
||||
|
||||
return orgs, x.Join("INNER", "`team_user`", "`team_user`.org_id=`user`.id").
|
||||
Join("INNER", "`team`", "`team`.id=`team_user`.team_id").
|
||||
Where("`team_user`.uid=?", userID).
|
||||
And(builder.Eq{"`team`.authorize": AccessModeOwner}.Or(builder.Eq{"`team`.can_create_org_repo": true})).
|
||||
Desc("`user`.updated_unix").
|
||||
Find(&orgs)
|
||||
return orgs, x.Where(builder.In("id", builder.Select("`user`.id").From("`user`").
|
||||
Join("INNER", "`team_user`", "`team_user`.org_id = `user`.id").
|
||||
Join("INNER", "`team`", "`team`.id = `team_user`.team_id").
|
||||
Where(builder.Eq{"`team_user`.uid": userID}).
|
||||
And(builder.Eq{"`team`.authorize": AccessModeOwner}.Or(builder.Eq{"`team`.can_create_org_repo": true})))).
|
||||
Desc("`user`.updated_unix").Find(&orgs)
|
||||
}
|
||||
|
||||
// GetOrgUsersByUserID returns all organization-user relations by user ID.
|
||||
|
||||
119
models/repo.go
119
models/repo.go
@@ -173,7 +173,6 @@ type Repository struct {
|
||||
NumMilestones int `xorm:"NOT NULL DEFAULT 0"`
|
||||
NumClosedMilestones int `xorm:"NOT NULL DEFAULT 0"`
|
||||
NumOpenMilestones int `xorm:"-"`
|
||||
NumReleases int `xorm:"-"`
|
||||
|
||||
IsPrivate bool `xorm:"INDEX"`
|
||||
IsEmpty bool `xorm:"INDEX"`
|
||||
@@ -364,6 +363,8 @@ func (repo *Repository) innerAPIFormat(e Engine, mode AccessMode, isParent bool)
|
||||
allowSquash = config.AllowSquash
|
||||
}
|
||||
|
||||
numReleases, _ := GetReleaseCountByRepoID(repo.ID, FindReleasesOptions{IncludeDrafts: false, IncludeTags: true})
|
||||
|
||||
return &api.Repository{
|
||||
ID: repo.ID,
|
||||
Owner: repo.Owner.APIFormat(),
|
||||
@@ -387,7 +388,7 @@ func (repo *Repository) innerAPIFormat(e Engine, mode AccessMode, isParent bool)
|
||||
Watchers: repo.NumWatches,
|
||||
OpenIssues: repo.NumOpenIssues,
|
||||
OpenPulls: repo.NumOpenPulls,
|
||||
Releases: repo.NumReleases,
|
||||
Releases: int(numReleases),
|
||||
DefaultBranch: repo.DefaultBranch,
|
||||
Created: repo.CreatedUnix.AsTime(),
|
||||
Updated: repo.UpdatedUnix.AsTime(),
|
||||
@@ -968,6 +969,21 @@ func CheckCreateRepository(doer, u *User, name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func getHookTemplates() (hookNames, hookTpls, giteaHookTpls []string) {
|
||||
hookNames = []string{"pre-receive", "update", "post-receive"}
|
||||
hookTpls = []string{
|
||||
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}\" && test -f \"${hook}\" || continue\necho \"${data}\" | \"${hook}\"\nexitcodes=\"${exitcodes} $?\"\ndone\n\nfor i in ${exitcodes}; do\n[ ${i} -eq 0 ] || exit ${i}\ndone\n", setting.ScriptType),
|
||||
fmt.Sprintf("#!/usr/bin/env %s\nexitcodes=\"\"\nhookname=$(basename $0)\nGIT_DIR=${GIT_DIR:-$(dirname $0)}\n\nfor hook in ${GIT_DIR}/hooks/${hookname}.d/*; do\ntest -x \"${hook}\" && test -f \"${hook}\" || continue\n\"${hook}\" $1 $2 $3\nexitcodes=\"${exitcodes} $?\"\ndone\n\nfor i in ${exitcodes}; do\n[ ${i} -eq 0 ] || exit ${i}\ndone\n", setting.ScriptType),
|
||||
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}\" && test -f \"${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),
|
||||
fmt.Sprintf("#!/usr/bin/env %s\n\"%s\" hook --config='%s' post-receive\n", setting.ScriptType, setting.AppPath, setting.CustomConf),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// CreateDelegateHooks creates all the hooks scripts for the repo
|
||||
func CreateDelegateHooks(repoPath string) error {
|
||||
return createDelegateHooks(repoPath)
|
||||
@@ -975,21 +991,7 @@ func CreateDelegateHooks(repoPath string) error {
|
||||
|
||||
// createDelegateHooks creates all the hooks scripts for the repo
|
||||
func createDelegateHooks(repoPath string) (err error) {
|
||||
|
||||
var (
|
||||
hookNames = []string{"pre-receive", "update", "post-receive"}
|
||||
hookTpls = []string{
|
||||
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),
|
||||
fmt.Sprintf("#!/usr/bin/env %s\nexitcodes=\"\"\nhookname=$(basename $0)\nGIT_DIR=${GIT_DIR:-$(dirname $0)}\n\nfor hook in ${GIT_DIR}/hooks/${hookname}.d/*; do\ntest -x \"${hook}\" || continue\n\"${hook}\" $1 $2 $3\nexitcodes=\"${exitcodes} $?\"\ndone\n\nfor i in ${exitcodes}; do\n[ ${i} -eq 0 ] || exit ${i}\ndone\n", setting.ScriptType),
|
||||
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),
|
||||
fmt.Sprintf("#!/usr/bin/env %s\n\"%s\" hook --config='%s' post-receive\n", setting.ScriptType, setting.AppPath, setting.CustomConf),
|
||||
}
|
||||
)
|
||||
|
||||
hookNames, hookTpls, giteaHookTpls := getHookTemplates()
|
||||
hookDir := filepath.Join(repoPath, "hooks")
|
||||
|
||||
for i, hookName := range hookNames {
|
||||
@@ -1008,16 +1010,94 @@ func createDelegateHooks(repoPath string) (err error) {
|
||||
return fmt.Errorf("write old hook file '%s': %v", oldHookPath, err)
|
||||
}
|
||||
|
||||
if err = ensureExecutable(oldHookPath); err != nil {
|
||||
return fmt.Errorf("Unable to set %s executable. Error %v", oldHookPath, err)
|
||||
}
|
||||
|
||||
if err = os.Remove(newHookPath); err != nil && !os.IsNotExist(err) {
|
||||
return fmt.Errorf("unable to pre-remove new hook file '%s' prior to rewriting: %v", newHookPath, err)
|
||||
}
|
||||
if err = ioutil.WriteFile(newHookPath, []byte(giteaHookTpls[i]), 0777); err != nil {
|
||||
return fmt.Errorf("write new hook file '%s': %v", newHookPath, err)
|
||||
}
|
||||
|
||||
if err = ensureExecutable(newHookPath); err != nil {
|
||||
return fmt.Errorf("Unable to set %s executable. Error %v", oldHookPath, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func checkExecutable(filename string) bool {
|
||||
fileInfo, err := os.Stat(filename)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return (fileInfo.Mode() & 0100) > 0
|
||||
}
|
||||
|
||||
func ensureExecutable(filename string) error {
|
||||
fileInfo, err := os.Stat(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (fileInfo.Mode() & 0100) > 0 {
|
||||
return nil
|
||||
}
|
||||
mode := fileInfo.Mode() | 0100
|
||||
return os.Chmod(filename, mode)
|
||||
}
|
||||
|
||||
// CheckDelegateHooks checks the hooks scripts for the repo
|
||||
func CheckDelegateHooks(repoPath string) ([]string, error) {
|
||||
hookNames, hookTpls, giteaHookTpls := getHookTemplates()
|
||||
|
||||
hookDir := filepath.Join(repoPath, "hooks")
|
||||
results := make([]string, 0, 10)
|
||||
|
||||
for i, hookName := range hookNames {
|
||||
oldHookPath := filepath.Join(hookDir, hookName)
|
||||
newHookPath := filepath.Join(hookDir, hookName+".d", "gitea")
|
||||
|
||||
cont := false
|
||||
if !com.IsExist(oldHookPath) {
|
||||
results = append(results, fmt.Sprintf("old hook file %s does not exist", oldHookPath))
|
||||
cont = true
|
||||
}
|
||||
if !com.IsExist(oldHookPath + ".d") {
|
||||
results = append(results, fmt.Sprintf("hooks directory %s does not exist", oldHookPath+".d"))
|
||||
cont = true
|
||||
}
|
||||
if !com.IsExist(newHookPath) {
|
||||
results = append(results, fmt.Sprintf("new hook file %s does not exist", newHookPath))
|
||||
cont = true
|
||||
}
|
||||
if cont {
|
||||
continue
|
||||
}
|
||||
contents, err := ioutil.ReadFile(oldHookPath)
|
||||
if err != nil {
|
||||
return results, err
|
||||
}
|
||||
if string(contents) != hookTpls[i] {
|
||||
results = append(results, fmt.Sprintf("old hook file %s is out of date", oldHookPath))
|
||||
}
|
||||
if !checkExecutable(oldHookPath) {
|
||||
results = append(results, fmt.Sprintf("old hook file %s is not executable", oldHookPath))
|
||||
}
|
||||
contents, err = ioutil.ReadFile(newHookPath)
|
||||
if err != nil {
|
||||
return results, err
|
||||
}
|
||||
if string(contents) != giteaHookTpls[i] {
|
||||
results = append(results, fmt.Sprintf("new hook file %s is out of date", newHookPath))
|
||||
}
|
||||
if !checkExecutable(newHookPath) {
|
||||
results = append(results, fmt.Sprintf("new hook file %s is not executable", newHookPath))
|
||||
}
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// initRepoCommit temporarily changes with work directory.
|
||||
func initRepoCommit(tmpPath string, repo *Repository, u *User) (err error) {
|
||||
@@ -1888,6 +1968,11 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = sess.In("issue_id", deleteCond).
|
||||
Delete(&TrackedTime{}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
attachments = attachments[:0]
|
||||
if err = sess.Join("INNER", "issue", "issue.id = attachment.issue_id").
|
||||
Where("issue.repo_id = ?", repoID).
|
||||
|
||||
@@ -144,6 +144,10 @@ type SearchRepoOptions struct {
|
||||
TopicOnly bool
|
||||
// include description in keyword search
|
||||
IncludeDescription bool
|
||||
// None -> include has milestones AND has no milestone
|
||||
// True -> include just has milestones
|
||||
// False -> include just has no milestone
|
||||
HasMilestones util.OptionalBool
|
||||
}
|
||||
|
||||
//SearchOrderBy is used to sort the result
|
||||
@@ -171,12 +175,9 @@ const (
|
||||
SearchOrderByForksReverse SearchOrderBy = "num_forks DESC"
|
||||
)
|
||||
|
||||
// SearchRepository returns repositories based on search options,
|
||||
// SearchRepositoryCondition returns repositories based on search options,
|
||||
// it returns results in given range and number of total results.
|
||||
func SearchRepository(opts *SearchRepoOptions) (RepositoryList, int64, error) {
|
||||
if opts.Page <= 0 {
|
||||
opts.Page = 1
|
||||
}
|
||||
func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
|
||||
var cond = builder.NewCond()
|
||||
|
||||
if opts.Private {
|
||||
@@ -276,6 +277,29 @@ func SearchRepository(opts *SearchRepoOptions) (RepositoryList, int64, error) {
|
||||
cond = cond.And(builder.Eq{"is_mirror": opts.Mirror == util.OptionalBoolTrue})
|
||||
}
|
||||
|
||||
switch opts.HasMilestones {
|
||||
case util.OptionalBoolTrue:
|
||||
cond = cond.And(builder.Gt{"num_milestones": 0})
|
||||
case util.OptionalBoolFalse:
|
||||
cond = cond.And(builder.Eq{"num_milestones": 0}.Or(builder.IsNull{"num_milestones"}))
|
||||
}
|
||||
|
||||
return cond
|
||||
}
|
||||
|
||||
// SearchRepository returns repositories based on search options,
|
||||
// it returns results in given range and number of total results.
|
||||
func SearchRepository(opts *SearchRepoOptions) (RepositoryList, int64, error) {
|
||||
cond := SearchRepositoryCondition(opts)
|
||||
return SearchRepositoryByCondition(opts, cond)
|
||||
}
|
||||
|
||||
// SearchRepositoryByCondition search repositories by condition
|
||||
func SearchRepositoryByCondition(opts *SearchRepoOptions, cond builder.Cond) (RepositoryList, int64, error) {
|
||||
if opts.Page <= 0 {
|
||||
opts.Page = 1
|
||||
}
|
||||
|
||||
if len(opts.OrderBy) == 0 {
|
||||
opts.OrderBy = SearchOrderByAlphabetically
|
||||
}
|
||||
@@ -296,11 +320,11 @@ func SearchRepository(opts *SearchRepoOptions) (RepositoryList, int64, error) {
|
||||
}
|
||||
|
||||
repos := make(RepositoryList, 0, opts.PageSize)
|
||||
if err = sess.
|
||||
Where(cond).
|
||||
OrderBy(opts.OrderBy.String()).
|
||||
Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).
|
||||
Find(&repos); err != nil {
|
||||
sess.Where(cond).OrderBy(opts.OrderBy.String())
|
||||
if opts.PageSize > 0 {
|
||||
sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
|
||||
}
|
||||
if err = sess.Find(&repos); err != nil {
|
||||
return nil, 0, fmt.Errorf("Repo: %v", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
@@ -687,14 +688,29 @@ func rewriteAllPublicKeys(e Engine) error {
|
||||
}
|
||||
}
|
||||
|
||||
err = e.Iterate(new(PublicKey), func(idx int, bean interface{}) (err error) {
|
||||
_, err = t.WriteString((bean.(*PublicKey)).AuthorizedString())
|
||||
if err := regeneratePublicKeys(e, t); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.Close()
|
||||
return os.Rename(tmpPath, fPath)
|
||||
}
|
||||
|
||||
// RegeneratePublicKeys regenerates the authorized_keys file
|
||||
func RegeneratePublicKeys(t io.Writer) error {
|
||||
return regeneratePublicKeys(x, t)
|
||||
}
|
||||
|
||||
func regeneratePublicKeys(e Engine, t io.Writer) error {
|
||||
err := e.Iterate(new(PublicKey), func(idx int, bean interface{}) (err error) {
|
||||
_, err = t.Write([]byte((bean.(*PublicKey)).AuthorizedString()))
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fPath := filepath.Join(setting.SSH.RootPath, "authorized_keys")
|
||||
if com.IsExist(fPath) {
|
||||
f, err := os.Open(fPath)
|
||||
if err != nil {
|
||||
@@ -707,7 +723,7 @@ func rewriteAllPublicKeys(e Engine) error {
|
||||
scanner.Scan()
|
||||
continue
|
||||
}
|
||||
_, err = t.WriteString(line + "\n")
|
||||
_, err = t.Write([]byte(line + "\n"))
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return err
|
||||
@@ -715,9 +731,7 @@ func rewriteAllPublicKeys(e Engine) error {
|
||||
}
|
||||
f.Close()
|
||||
}
|
||||
|
||||
t.Close()
|
||||
return os.Rename(tmpPath, fPath)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ________ .__ ____ __.
|
||||
|
||||
@@ -212,6 +212,11 @@ func (ctx *APIContext) NotFound(objs ...interface{}) {
|
||||
var message = "Not Found"
|
||||
var errors []string
|
||||
for _, obj := range objs {
|
||||
// Ignore nil
|
||||
if obj == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if err, ok := obj.(error); ok {
|
||||
errors = append(errors, err.Error())
|
||||
} else {
|
||||
|
||||
@@ -396,7 +396,7 @@ func RepoAssignment() macaron.Handler {
|
||||
ctx.Data["RepoExternalIssuesLink"] = unit.ExternalTrackerConfig().ExternalTrackerURL
|
||||
}
|
||||
|
||||
count, err := models.GetReleaseCountByRepoID(ctx.Repo.Repository.ID, models.FindReleasesOptions{
|
||||
ctx.Data["NumReleases"], err = models.GetReleaseCountByRepoID(ctx.Repo.Repository.ID, models.FindReleasesOptions{
|
||||
IncludeDrafts: false,
|
||||
IncludeTags: true,
|
||||
})
|
||||
@@ -404,7 +404,6 @@ func RepoAssignment() macaron.Handler {
|
||||
ctx.ServerError("GetReleaseCountByRepoID", err)
|
||||
return
|
||||
}
|
||||
ctx.Repo.Repository.NumReleases = int(count)
|
||||
|
||||
ctx.Data["Title"] = owner.Name + "/" + repo.Name
|
||||
ctx.Data["Repository"] = repo
|
||||
|
||||
@@ -30,8 +30,17 @@ func ToEmail(email *models.EmailAddress) *api.Email {
|
||||
}
|
||||
|
||||
// ToBranch convert a git.Commit and git.Branch to an api.Branch
|
||||
func ToBranch(repo *models.Repository, b *git.Branch, c *git.Commit, bp *models.ProtectedBranch, user *models.User) *api.Branch {
|
||||
func ToBranch(repo *models.Repository, b *git.Branch, c *git.Commit, bp *models.ProtectedBranch, user *models.User) (*api.Branch, error) {
|
||||
if bp == nil {
|
||||
var hasPerm bool
|
||||
var err error
|
||||
if user != nil {
|
||||
hasPerm, err = models.HasAccessUnit(user, repo, models.UnitTypeCode, models.AccessModeWrite)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &api.Branch{
|
||||
Name: b.Name,
|
||||
Commit: ToCommit(repo, c),
|
||||
@@ -39,20 +48,25 @@ func ToBranch(repo *models.Repository, b *git.Branch, c *git.Commit, bp *models.
|
||||
RequiredApprovals: 0,
|
||||
EnableStatusCheck: false,
|
||||
StatusCheckContexts: []string{},
|
||||
UserCanPush: true,
|
||||
UserCanMerge: true,
|
||||
}
|
||||
UserCanPush: hasPerm,
|
||||
UserCanMerge: hasPerm,
|
||||
}, nil
|
||||
}
|
||||
return &api.Branch{
|
||||
|
||||
branch := &api.Branch{
|
||||
Name: b.Name,
|
||||
Commit: ToCommit(repo, c),
|
||||
Protected: true,
|
||||
RequiredApprovals: bp.RequiredApprovals,
|
||||
EnableStatusCheck: bp.EnableStatusCheck,
|
||||
StatusCheckContexts: bp.StatusCheckContexts,
|
||||
UserCanPush: bp.CanUserPush(user.ID),
|
||||
UserCanMerge: bp.CanUserMerge(user.ID),
|
||||
}
|
||||
|
||||
if user != nil {
|
||||
branch.UserCanPush = bp.CanUserPush(user.ID)
|
||||
branch.UserCanMerge = bp.IsUserMergeWhitelisted(user.ID)
|
||||
}
|
||||
return branch, nil
|
||||
}
|
||||
|
||||
// ToTag convert a git.Tag to an api.Tag
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
"gopkg.in/src-d/go-git.v4/plumbing"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
)
|
||||
|
||||
// Blob represents a Git object.
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/src-d/go-git.v4/plumbing/object"
|
||||
"github.com/go-git/go-git/v5/plumbing/object"
|
||||
)
|
||||
|
||||
// Commit represents a git commit.
|
||||
|
||||
@@ -6,9 +6,9 @@ package git
|
||||
|
||||
import (
|
||||
"github.com/emirpasic/gods/trees/binaryheap"
|
||||
"gopkg.in/src-d/go-git.v4/plumbing"
|
||||
"gopkg.in/src-d/go-git.v4/plumbing/object"
|
||||
cgobject "gopkg.in/src-d/go-git.v4/plumbing/object/commitgraph"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
"github.com/go-git/go-git/v5/plumbing/object"
|
||||
cgobject "github.com/go-git/go-git/v5/plumbing/object/commitgraph"
|
||||
)
|
||||
|
||||
// GetCommitsInfo gets information of all commits that are corresponding to these entries
|
||||
|
||||
@@ -7,7 +7,7 @@ package git
|
||||
import (
|
||||
"io/ioutil"
|
||||
|
||||
"gopkg.in/src-d/go-git.v4/plumbing/object"
|
||||
"github.com/go-git/go-git/v5/plumbing/object"
|
||||
)
|
||||
|
||||
// NotesRef is the git ref where Gitea will look for git-notes data.
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"gopkg.in/src-d/go-git.v4/plumbing/filemode"
|
||||
"gopkg.in/src-d/go-git.v4/plumbing/object"
|
||||
"github.com/go-git/go-git/v5/plumbing/filemode"
|
||||
"github.com/go-git/go-git/v5/plumbing/object"
|
||||
)
|
||||
|
||||
// ParseTreeEntries parses the output of a `git ls-tree` command.
|
||||
|
||||
@@ -7,9 +7,9 @@ package git
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/go-git/go-git/v5/plumbing/filemode"
|
||||
"github.com/go-git/go-git/v5/plumbing/object"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/src-d/go-git.v4/plumbing/filemode"
|
||||
"gopkg.in/src-d/go-git.v4/plumbing/object"
|
||||
)
|
||||
|
||||
func TestParseTreeEntries(t *testing.T) {
|
||||
|
||||
@@ -18,11 +18,11 @@ import (
|
||||
"time"
|
||||
|
||||
gitealog "code.gitea.io/gitea/modules/log"
|
||||
"github.com/go-git/go-billy/v5/osfs"
|
||||
gogit "github.com/go-git/go-git/v5"
|
||||
"github.com/go-git/go-git/v5/plumbing/cache"
|
||||
"github.com/go-git/go-git/v5/storage/filesystem"
|
||||
"github.com/unknwon/com"
|
||||
"gopkg.in/src-d/go-billy.v4/osfs"
|
||||
gogit "gopkg.in/src-d/go-git.v4"
|
||||
"gopkg.in/src-d/go-git.v4/plumbing/cache"
|
||||
"gopkg.in/src-d/go-git.v4/storage/filesystem"
|
||||
)
|
||||
|
||||
// Repository represents a Git repository.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"gopkg.in/src-d/go-git.v4/plumbing"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
)
|
||||
|
||||
func (repo *Repository) getBlob(id SHA1) (*Blob, error) {
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/src-d/go-git.v4/plumbing"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
)
|
||||
|
||||
// BranchPrefix base dir of the branch information file store on git
|
||||
|
||||
@@ -12,15 +12,20 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
"github.com/go-git/go-git/v5/plumbing/object"
|
||||
"github.com/mcuadros/go-version"
|
||||
"gopkg.in/src-d/go-git.v4/plumbing"
|
||||
"gopkg.in/src-d/go-git.v4/plumbing/object"
|
||||
)
|
||||
|
||||
// GetRefCommitID returns the last commit ID string of given reference (branch or tag).
|
||||
func (repo *Repository) GetRefCommitID(name string) (string, error) {
|
||||
ref, err := repo.gogitRepo.Reference(plumbing.ReferenceName(name), true)
|
||||
if err != nil {
|
||||
if err == plumbing.ErrReferenceNotFound {
|
||||
return "", ErrNotExist{
|
||||
ID: name,
|
||||
}
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -89,9 +94,15 @@ func (repo *Repository) getCommit(id SHA1) (*Commit, error) {
|
||||
gogitCommit, err := repo.gogitRepo.CommitObject(id)
|
||||
if err == plumbing.ErrObjectNotFound {
|
||||
tagObject, err = repo.gogitRepo.TagObject(id)
|
||||
if err == plumbing.ErrObjectNotFound {
|
||||
return nil, ErrNotExist{
|
||||
ID: id.String(),
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
gogitCommit, err = repo.gogitRepo.CommitObject(tagObject.Target)
|
||||
}
|
||||
// if we get a plumbing.ErrObjectNotFound here then the repository is broken and it should be 500
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -11,8 +11,8 @@ import (
|
||||
|
||||
gitealog "code.gitea.io/gitea/modules/log"
|
||||
|
||||
"gopkg.in/src-d/go-git.v4/plumbing/format/commitgraph"
|
||||
cgobject "gopkg.in/src-d/go-git.v4/plumbing/object/commitgraph"
|
||||
"github.com/go-git/go-git/v5/plumbing/format/commitgraph"
|
||||
cgobject "github.com/go-git/go-git/v5/plumbing/object/commitgraph"
|
||||
)
|
||||
|
||||
// CommitNodeIndex returns the index for walking commit graph
|
||||
|
||||
@@ -7,8 +7,8 @@ package git
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"gopkg.in/src-d/go-git.v4"
|
||||
"gopkg.in/src-d/go-git.v4/plumbing"
|
||||
"github.com/go-git/go-git/v5"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
)
|
||||
|
||||
// GetRefs returns all references of the repository.
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
"github.com/mcuadros/go-version"
|
||||
"gopkg.in/src-d/go-git.v4/plumbing"
|
||||
)
|
||||
|
||||
// TagPrefix tags prefix path on the repository
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/src-d/go-git.v4/plumbing"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
)
|
||||
|
||||
// EmptySHA defines empty git SHA
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"gopkg.in/src-d/go-git.v4/plumbing/object"
|
||||
"github.com/go-git/go-git/v5/plumbing/object"
|
||||
)
|
||||
|
||||
// Signature represents the Author or Committer information.
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
@@ -38,7 +39,7 @@ func NewSubModuleFile(c *Commit, refURL, refID string) *SubModuleFile {
|
||||
}
|
||||
}
|
||||
|
||||
func getRefURL(refURL, urlPrefix, parentPath string) string {
|
||||
func getRefURL(refURL, urlPrefix, repoFullName string) string {
|
||||
if refURL == "" {
|
||||
return ""
|
||||
}
|
||||
@@ -51,14 +52,14 @@ func getRefURL(refURL, urlPrefix, parentPath string) string {
|
||||
urlPrefixHostname = prefixURL.Host
|
||||
}
|
||||
|
||||
if strings.HasSuffix(urlPrefix, "/") {
|
||||
urlPrefix = urlPrefix[:len(urlPrefix)-1]
|
||||
}
|
||||
|
||||
// FIXME: Need to consider branch - which will require changes in modules/git/commit.go:GetSubModules
|
||||
// Relative url prefix check (according to git submodule documentation)
|
||||
if strings.HasPrefix(refURI, "./") || strings.HasPrefix(refURI, "../") {
|
||||
// ...construct and return correct submodule url here...
|
||||
idx := strings.Index(parentPath, "/src/")
|
||||
if idx == -1 {
|
||||
return refURI
|
||||
}
|
||||
return strings.TrimSuffix(urlPrefix, "/") + parentPath[:idx] + "/" + refURI
|
||||
return urlPrefix + path.Clean(path.Join("/", repoFullName, refURI))
|
||||
}
|
||||
|
||||
if !strings.Contains(refURI, "://") {
|
||||
@@ -69,16 +70,16 @@ func getRefURL(refURL, urlPrefix, parentPath string) string {
|
||||
|
||||
m := match[0]
|
||||
refHostname := m[2]
|
||||
path := m[3]
|
||||
pth := m[3]
|
||||
|
||||
if !strings.HasPrefix(path, "/") {
|
||||
path = "/" + path
|
||||
if !strings.HasPrefix(pth, "/") {
|
||||
pth = "/" + pth
|
||||
}
|
||||
|
||||
if urlPrefixHostname == refHostname {
|
||||
return prefixURL.Scheme + "://" + urlPrefixHostname + path
|
||||
return urlPrefix + path.Clean(path.Join("/", pth))
|
||||
}
|
||||
return "http://" + refHostname + path
|
||||
return "http://" + refHostname + pth
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +98,7 @@ func getRefURL(refURL, urlPrefix, parentPath string) string {
|
||||
for _, scheme := range supportedSchemes {
|
||||
if ref.Scheme == scheme {
|
||||
if urlPrefixHostname == refHostname {
|
||||
return prefixURL.Scheme + "://" + prefixURL.Host + ref.Path
|
||||
return urlPrefix + path.Clean(path.Join("/", ref.Path))
|
||||
} else if ref.Scheme == "http" || ref.Scheme == "https" {
|
||||
if len(ref.User.Username()) > 0 {
|
||||
return ref.Scheme + "://" + fmt.Sprintf("%v", ref.User) + "@" + ref.Host + ref.Path
|
||||
@@ -113,8 +114,8 @@ func getRefURL(refURL, urlPrefix, parentPath string) string {
|
||||
}
|
||||
|
||||
// RefURL guesses and returns reference URL.
|
||||
func (sf *SubModuleFile) RefURL(urlPrefix string, parentPath string) string {
|
||||
return getRefURL(sf.refURL, urlPrefix, parentPath)
|
||||
func (sf *SubModuleFile) RefURL(urlPrefix string, repoFullName string) string {
|
||||
return getRefURL(sf.refURL, urlPrefix, repoFullName)
|
||||
}
|
||||
|
||||
// RefID returns reference ID.
|
||||
|
||||
@@ -17,21 +17,21 @@ func TestGetRefURL(t *testing.T) {
|
||||
parentPath string
|
||||
expect string
|
||||
}{
|
||||
{"git://github.com/user1/repo1", "/", "/", "http://github.com/user1/repo1"},
|
||||
{"https://localhost/user1/repo1.git", "/", "/", "https://localhost/user1/repo1"},
|
||||
{"http://localhost/user1/repo1.git", "/", "/", "http://localhost/user1/repo1"},
|
||||
{"git@github.com:user1/repo1.git", "/", "/", "http://github.com/user1/repo1"},
|
||||
{"ssh://git@git.zefie.net:2222/zefie/lge_g6_kernel_scripts.git", "/", "/", "http://git.zefie.net/zefie/lge_g6_kernel_scripts"},
|
||||
{"git@git.zefie.net:2222/zefie/lge_g6_kernel_scripts.git", "/", "/", "http://git.zefie.net/2222/zefie/lge_g6_kernel_scripts"},
|
||||
{"git@try.gitea.io:go-gitea/gitea", "https://try.gitea.io/go-gitea/gitea", "/", "https://try.gitea.io/go-gitea/gitea"},
|
||||
{"ssh://git@try.gitea.io:9999/go-gitea/gitea", "https://try.gitea.io/go-gitea/gitea", "/", "https://try.gitea.io/go-gitea/gitea"},
|
||||
{"git://git@try.gitea.io:9999/go-gitea/gitea", "https://try.gitea.io/go-gitea/log", "/", "https://try.gitea.io/go-gitea/gitea"},
|
||||
{"ssh://git@127.0.0.1:9999/go-gitea/gitea", "https://127.0.0.1:3000/go-gitea/log", "/", "https://127.0.0.1:3000/go-gitea/gitea"},
|
||||
{"https://gitea.com:3000/user1/repo1.git", "https://127.0.0.1:3000/go-gitea/gitea", "/", "https://gitea.com:3000/user1/repo1"},
|
||||
{"https://username:password@github.com/username/repository.git", "/", "/", "https://username:password@github.com/username/repository"},
|
||||
{"git://github.com/user1/repo1", "/", "user1/repo2", "http://github.com/user1/repo1"},
|
||||
{"https://localhost/user1/repo1.git", "/", "user1/repo2", "https://localhost/user1/repo1"},
|
||||
{"http://localhost/user1/repo1.git", "/", "owner/reponame", "http://localhost/user1/repo1"},
|
||||
{"git@github.com:user1/repo1.git", "/", "owner/reponame", "http://github.com/user1/repo1"},
|
||||
{"ssh://git@git.zefie.net:2222/zefie/lge_g6_kernel_scripts.git", "/", "zefie/lge_g6_kernel", "http://git.zefie.net/zefie/lge_g6_kernel_scripts"},
|
||||
{"git@git.zefie.net:2222/zefie/lge_g6_kernel_scripts.git", "/", "zefie/lge_g6_kernel", "http://git.zefie.net/2222/zefie/lge_g6_kernel_scripts"},
|
||||
{"git@try.gitea.io:go-gitea/gitea", "https://try.gitea.io/", "go-gitea/sdk", "https://try.gitea.io/go-gitea/gitea"},
|
||||
{"ssh://git@try.gitea.io:9999/go-gitea/gitea", "https://try.gitea.io/", "go-gitea/sdk", "https://try.gitea.io/go-gitea/gitea"},
|
||||
{"git://git@try.gitea.io:9999/go-gitea/gitea", "https://try.gitea.io/", "go-gitea/sdk", "https://try.gitea.io/go-gitea/gitea"},
|
||||
{"ssh://git@127.0.0.1:9999/go-gitea/gitea", "https://127.0.0.1:3000/", "go-gitea/sdk", "https://127.0.0.1:3000/go-gitea/gitea"},
|
||||
{"https://gitea.com:3000/user1/repo1.git", "https://127.0.0.1:3000/", "user/repo2", "https://gitea.com:3000/user1/repo1"},
|
||||
{"https://username:password@github.com/username/repository.git", "/", "username/repository2", "https://username:password@github.com/username/repository"},
|
||||
{"somethingbad", "https://127.0.0.1:3000/go-gitea/gitea", "/", ""},
|
||||
{"git@localhost:user/repo", "https://localhost/user/repo2", "/", "https://localhost/user/repo"},
|
||||
{"../path/to/repo.git/", "https://localhost/user/repo2/src/branch/master/test", "/", "../path/to/repo.git/"},
|
||||
{"git@localhost:user/repo", "https://localhost/", "user2/repo1", "https://localhost/user/repo"},
|
||||
{"../path/to/repo.git/", "https://localhost/", "user/repo2", "https://localhost/user/path/to/repo.git"},
|
||||
}
|
||||
|
||||
for _, kase := range kases {
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/src-d/go-git.v4/plumbing"
|
||||
"gopkg.in/src-d/go-git.v4/plumbing/object"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
"github.com/go-git/go-git/v5/plumbing/object"
|
||||
)
|
||||
|
||||
// Tree represents a flat directory listing.
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/src-d/go-git.v4/plumbing/filemode"
|
||||
"gopkg.in/src-d/go-git.v4/plumbing/object"
|
||||
"github.com/go-git/go-git/v5/plumbing/filemode"
|
||||
"github.com/go-git/go-git/v5/plumbing/object"
|
||||
)
|
||||
|
||||
// GetTreeEntryByPath get the tree entries according the sub dir
|
||||
|
||||
@@ -10,9 +10,9 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/src-d/go-git.v4/plumbing"
|
||||
"gopkg.in/src-d/go-git.v4/plumbing/filemode"
|
||||
"gopkg.in/src-d/go-git.v4/plumbing/object"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
"github.com/go-git/go-git/v5/plumbing/filemode"
|
||||
"github.com/go-git/go-git/v5/plumbing/object"
|
||||
)
|
||||
|
||||
// EntryMode the type of the object in the git tree
|
||||
|
||||
@@ -7,9 +7,9 @@ package git
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/go-git/go-git/v5/plumbing/filemode"
|
||||
"github.com/go-git/go-git/v5/plumbing/object"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/src-d/go-git.v4/plumbing/filemode"
|
||||
"gopkg.in/src-d/go-git.v4/plumbing/object"
|
||||
)
|
||||
|
||||
func getTestEntries() Entries {
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/migrations/base"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"github.com/google/go-github/v24/github"
|
||||
"golang.org/x/oauth2"
|
||||
@@ -121,7 +122,7 @@ func (g *GithubDownloaderV3) sleep() {
|
||||
timer := time.NewTimer(time.Until(g.rate.Reset.Time))
|
||||
select {
|
||||
case <-g.ctx.Done():
|
||||
timer.Stop()
|
||||
util.StopTimer(timer)
|
||||
return
|
||||
case <-timer.C:
|
||||
}
|
||||
|
||||
@@ -124,6 +124,12 @@ func (r *indexerNotifier) NotifyPushCommits(pusher *models.User, repo *models.Re
|
||||
}
|
||||
}
|
||||
|
||||
func (r *indexerNotifier) NotifySyncPushCommits(pusher *models.User, repo *models.Repository, refName, oldCommitID, newCommitID string, commits *models.PushCommits) {
|
||||
if setting.Indexer.RepoIndexerEnabled && refName == git.BranchPrefix+repo.DefaultBranch {
|
||||
code_indexer.UpdateRepoIndexer(repo)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *indexerNotifier) NotifyIssueChangeContent(doer *models.User, issue *models.Issue, oldContent string) {
|
||||
issue_indexer.UpdateIssueIndexer(issue)
|
||||
}
|
||||
|
||||
@@ -98,3 +98,8 @@ func fileFromDir(name string) ([]byte, error) {
|
||||
|
||||
return []byte{}, fmt.Errorf("Asset file does not exist: %s", name)
|
||||
}
|
||||
|
||||
// IsDynamic will return false when using embedded data (-tags bindata)
|
||||
func IsDynamic() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -112,3 +112,8 @@ func fileFromDir(name string) ([]byte, error) {
|
||||
|
||||
return ioutil.ReadAll(f)
|
||||
}
|
||||
|
||||
// IsDynamic will return false when using embedded data (-tags bindata)
|
||||
func IsDynamic() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
// WrappedQueueType is the type for a wrapped delayed starting queue
|
||||
@@ -77,7 +78,7 @@ func (q *delayedStarter) setInternal(atShutdown func(context.Context, func()), h
|
||||
t := time.NewTimer(sleepTime)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
t.Stop()
|
||||
util.StopTimer(t)
|
||||
case <-t.C:
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
// WorkerPool takes
|
||||
@@ -56,12 +57,7 @@ func (p *WorkerPool) pushBoost(data Data) {
|
||||
p.lock.Unlock()
|
||||
select {
|
||||
case p.dataChan <- data:
|
||||
if timer.Stop() {
|
||||
select {
|
||||
case <-timer.C:
|
||||
default:
|
||||
}
|
||||
}
|
||||
util.StopTimer(timer)
|
||||
case <-timer.C:
|
||||
p.lock.Lock()
|
||||
if p.blockTimeout > ourTimeout || (p.numberOfWorkers > p.maxNumberOfWorkers && p.maxNumberOfWorkers >= 0) {
|
||||
@@ -277,12 +273,7 @@ func (p *WorkerPool) doWork(ctx context.Context) {
|
||||
timer := time.NewTimer(delay)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if timer.Stop() {
|
||||
select {
|
||||
case <-timer.C:
|
||||
default:
|
||||
}
|
||||
}
|
||||
util.StopTimer(timer)
|
||||
if len(data) > 0 {
|
||||
log.Trace("Handling: %d data, %v", len(data), data)
|
||||
p.handle(data...)
|
||||
@@ -290,12 +281,7 @@ func (p *WorkerPool) doWork(ctx context.Context) {
|
||||
log.Trace("Worker shutting down")
|
||||
return
|
||||
case datum, ok := <-p.dataChan:
|
||||
if timer.Stop() {
|
||||
select {
|
||||
case <-timer.C:
|
||||
default:
|
||||
}
|
||||
}
|
||||
util.StopTimer(timer)
|
||||
if !ok {
|
||||
// the dataChan has been closed - we should finish up:
|
||||
if len(data) > 0 {
|
||||
|
||||
@@ -159,7 +159,7 @@ func GetContents(repo *models.Repository, treePath, ref string, forList bool) (*
|
||||
}
|
||||
|
||||
// Now populate the rest of the ContentsResponse based on entry type
|
||||
if entry.IsRegular() {
|
||||
if entry.IsRegular() || entry.IsExecutable() {
|
||||
contentsResponse.Type = string(ContentTypeRegular)
|
||||
if blobResponse, err := GetBlobBySHA(repo, entry.ID.String()); err != nil {
|
||||
return nil, err
|
||||
|
||||
21
modules/util/timer.go
Normal file
21
modules/util/timer.go
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright 2020 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 util
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// StopTimer is a utility function to safely stop a time.Timer and clean its channel
|
||||
func StopTimer(t *time.Timer) bool {
|
||||
stopped := t.Stop()
|
||||
if !stopped {
|
||||
select {
|
||||
case <-t.C:
|
||||
default:
|
||||
}
|
||||
}
|
||||
return stopped
|
||||
}
|
||||
@@ -1062,6 +1062,7 @@ pulls.data_broken = This pull request is broken due to missing fork information.
|
||||
pulls.files_conflicted = This pull request has changes conflicting with the target branch.
|
||||
pulls.is_checking = "Merge conflict checking is in progress. Try again in few moments."
|
||||
pulls.required_status_check_failed = Some required checks were not successful.
|
||||
pulls.required_status_check_missing = Some required checks are missing.
|
||||
pulls.required_status_check_administrator = As an administrator, you may still merge this pull request.
|
||||
pulls.blocked_by_approvals = "This Pull Request doesn't have enough approvals yet. %d of %d approvals granted."
|
||||
pulls.blocked_by_rejection = "This Pull Request has changes requested by an official reviewer."
|
||||
|
||||
@@ -70,7 +70,13 @@ func GetBranch(ctx *context.APIContext) {
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, convert.ToBranch(ctx.Repo.Repository, branch, c, branchProtection, ctx.User))
|
||||
br, err := convert.ToBranch(ctx.Repo.Repository, branch, c, branchProtection, ctx.User)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "convert.ToBranch", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, br)
|
||||
}
|
||||
|
||||
// ListBranches list all the branches of a repository
|
||||
@@ -113,7 +119,14 @@ func ListBranches(ctx *context.APIContext) {
|
||||
ctx.Error(http.StatusInternalServerError, "GetBranchProtection", err)
|
||||
return
|
||||
}
|
||||
apiBranches[i] = convert.ToBranch(ctx.Repo.Repository, branches[i], c, branchProtection, ctx.User)
|
||||
|
||||
br, err := convert.ToBranch(ctx.Repo.Repository, branches[i], c, branchProtection, ctx.User)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "convert.ToBranch", err)
|
||||
return
|
||||
}
|
||||
|
||||
apiBranches[i] = br
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, &apiBranches)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
@@ -289,7 +290,15 @@ func DeleteTime(ctx *context.APIContext) {
|
||||
|
||||
time, err := models.GetTrackedTimeByID(ctx.ParamsInt64(":id"))
|
||||
if err != nil {
|
||||
ctx.Error(500, "GetTrackedTimeByID", err)
|
||||
if models.IsErrNotExist(err) {
|
||||
ctx.NotFound(err)
|
||||
return
|
||||
}
|
||||
ctx.Error(http.StatusInternalServerError, "GetTrackedTimeByID", err)
|
||||
return
|
||||
}
|
||||
if time.Deleted {
|
||||
ctx.NotFound(fmt.Errorf("tracked time [%d] already deleted", time.ID))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -329,8 +329,27 @@ func ServCommand(ctx *macaron.Context) {
|
||||
results.RepoID = repo.ID
|
||||
}
|
||||
|
||||
// Finally if we're trying to touch the wiki we should init it
|
||||
if results.IsWiki {
|
||||
// Ensure the wiki is enabled before we allow access to it
|
||||
if _, err := repo.GetUnit(models.UnitTypeWiki); err != nil {
|
||||
if models.IsErrUnitTypeNotExist(err) {
|
||||
ctx.JSON(http.StatusForbidden, map[string]interface{}{
|
||||
"results": results,
|
||||
"type": "ErrForbidden",
|
||||
"err": "repository wiki is disabled",
|
||||
})
|
||||
return
|
||||
}
|
||||
log.Error("Failed to get the wiki unit in %-v Error: %v", repo, err)
|
||||
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
|
||||
"results": results,
|
||||
"type": "InternalServerError",
|
||||
"err": fmt.Sprintf("Failed to get the wiki unit in %s/%s Error: %v", ownerName, repoName, err),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Finally if we're trying to touch the wiki we should init it
|
||||
if err = wiki_service.InitWiki(repo); err != nil {
|
||||
log.Error("Failed to initialize the wiki in %-v Error: %v", repo, err)
|
||||
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
|
||||
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/repofiles"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"gopkg.in/src-d/go-git.v4/plumbing"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -252,7 +251,7 @@ func loadBranches(ctx *context.Context) []*Branch {
|
||||
repoIDToGitRepo[pr.BaseRepoID] = baseGitRepo
|
||||
}
|
||||
pullCommit, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName())
|
||||
if err != nil && err != plumbing.ErrReferenceNotFound {
|
||||
if err != nil && !git.IsErrNotExist(err) {
|
||||
ctx.ServerError("GetBranchCommitID", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -320,9 +320,6 @@ func PrepareCompareDiff(
|
||||
compareInfo.Commits = models.ParseCommitsWithStatus(compareInfo.Commits, headRepo)
|
||||
ctx.Data["Commits"] = compareInfo.Commits
|
||||
ctx.Data["CommitCount"] = compareInfo.Commits.Len()
|
||||
if ctx.Data["CommitCount"] == 0 {
|
||||
ctx.Data["PageIsComparePull"] = false
|
||||
}
|
||||
|
||||
if compareInfo.Commits.Len() == 1 {
|
||||
c := compareInfo.Commits.Front().Value.(models.SignCommitWithStatuses)
|
||||
|
||||
@@ -313,6 +313,19 @@ func HTTP(ctx *context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
if isWiki {
|
||||
// Ensure the wiki is enabled before we allow access to it
|
||||
if _, err := repo.GetUnit(models.UnitTypeWiki); err != nil {
|
||||
if models.IsErrUnitTypeNotExist(err) {
|
||||
ctx.HandleText(http.StatusForbidden, "repository wiki is disabled")
|
||||
return
|
||||
}
|
||||
log.Error("Failed to get the wiki unit in %-v Error: %v", repo, err)
|
||||
ctx.ServerError("GetUnit(UnitTypeWiki) for "+repo.FullName(), err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
environ = append(environ, models.ProtectedBranchRepoID+fmt.Sprintf("=%d", repo.ID))
|
||||
|
||||
w := ctx.Resp
|
||||
|
||||
@@ -30,11 +30,11 @@ import (
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
gogit "github.com/go-git/go-git/v5"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
"github.com/go-git/go-git/v5/plumbing/object"
|
||||
"github.com/mcuadros/go-version"
|
||||
"github.com/unknwon/com"
|
||||
gogit "gopkg.in/src-d/go-git.v4"
|
||||
"gopkg.in/src-d/go-git.v4/plumbing"
|
||||
"gopkg.in/src-d/go-git.v4/plumbing/object"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -413,9 +413,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare
|
||||
}
|
||||
return false
|
||||
}
|
||||
state := pull_service.MergeRequiredContextsCommitStatus(commitStatuses, pull.ProtectedBranch.StatusCheckContexts)
|
||||
ctx.Data["RequiredStatusCheckState"] = state
|
||||
ctx.Data["IsRequiredStatusCheckSuccess"] = state.IsSuccess()
|
||||
ctx.Data["RequiredStatusCheckState"] = pull_service.MergeRequiredContextsCommitStatus(commitStatuses, pull.ProtectedBranch.StatusCheckContexts)
|
||||
}
|
||||
|
||||
ctx.Data["HeadBranchMovedOn"] = headBranchSha != sha
|
||||
|
||||
@@ -668,6 +668,14 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||
|
||||
m.Post("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), context.UnitTypes(), repo.Action)
|
||||
|
||||
// Grouping for those endpoints not requiring authentication
|
||||
m.Group("/:username/:reponame", func() {
|
||||
m.Group("/milestone", func() {
|
||||
m.Get("/:id", repo.MilestoneIssuesAndPulls)
|
||||
}, reqRepoIssuesOrPullsReader, context.RepoRef())
|
||||
}, context.RepoAssignment(), context.UnitTypes())
|
||||
|
||||
// Grouping for those endpoints that do require authentication
|
||||
m.Group("/:username/:reponame", func() {
|
||||
m.Group("/issues", func() {
|
||||
m.Combo("/new").Get(context.RepoRef(), repo.NewIssue).
|
||||
@@ -723,9 +731,6 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||
m.Post("/:id/:action", repo.ChangeMilestonStatus)
|
||||
m.Post("/delete", repo.DeleteMilestone)
|
||||
}, context.RepoMustNotBeArchived(), reqRepoIssuesOrPullsWriter, context.RepoRef())
|
||||
m.Group("/milestone", func() {
|
||||
m.Get("/:id", repo.MilestoneIssuesAndPulls)
|
||||
}, reqRepoIssuesOrPullsReader, context.RepoRef())
|
||||
m.Combo("/compare/*", repo.MustBeNotEmpty, reqRepoCodeReader, repo.SetEditorconfigIfExists).
|
||||
Get(repo.SetDiffViewStyle, repo.CompareDiff).
|
||||
Post(context.RepoMustNotBeArchived(), reqRepoPullsReader, repo.MustAllowPulls, bindIgnErr(auth.CreateIssueForm{}), repo.CompareAndPullRequestPost)
|
||||
|
||||
@@ -24,7 +24,7 @@ import (
|
||||
|
||||
"github.com/keybase/go-crypto/openpgp"
|
||||
"github.com/keybase/go-crypto/openpgp/armor"
|
||||
"github.com/unknwon/com"
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -171,135 +171,114 @@ func Milestones(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
sortType := ctx.Query("sort")
|
||||
page := ctx.QueryInt("page")
|
||||
var (
|
||||
repoOpts = models.SearchRepoOptions{
|
||||
OwnerID: ctxUser.ID,
|
||||
Private: true,
|
||||
AllPublic: false, // Include also all public repositories of users and public organisations
|
||||
AllLimited: false, // Include also all public repositories of limited organisations
|
||||
HasMilestones: util.OptionalBoolTrue, // Just needs display repos has milestones
|
||||
IsProfile: false,
|
||||
}
|
||||
|
||||
userRepoCond = models.SearchRepositoryCondition(&repoOpts) // all repo condition user could visit
|
||||
repoCond = userRepoCond
|
||||
repoIDs []int64
|
||||
|
||||
reposQuery = ctx.Query("repos")
|
||||
isShowClosed = ctx.Query("state") == "closed"
|
||||
sortType = ctx.Query("sort")
|
||||
page = ctx.QueryInt("page")
|
||||
)
|
||||
|
||||
if page <= 1 {
|
||||
page = 1
|
||||
}
|
||||
|
||||
reposQuery := ctx.Query("repos")
|
||||
isShowClosed := ctx.Query("state") == "closed"
|
||||
|
||||
// Get repositories.
|
||||
var err error
|
||||
var userRepoIDs []int64
|
||||
if ctxUser.IsOrganization() {
|
||||
env, err := ctxUser.AccessibleReposEnv(ctx.User.ID)
|
||||
if err != nil {
|
||||
ctx.ServerError("AccessibleReposEnv", err)
|
||||
return
|
||||
}
|
||||
userRepoIDs, err = env.RepoIDs(1, ctxUser.NumRepos)
|
||||
if err != nil {
|
||||
ctx.ServerError("env.RepoIDs", err)
|
||||
return
|
||||
}
|
||||
userRepoIDs, err = models.FilterOutRepoIdsWithoutUnitAccess(ctx.User, userRepoIDs, models.UnitTypeIssues, models.UnitTypePullRequests)
|
||||
if err != nil {
|
||||
ctx.ServerError("FilterOutRepoIdsWithoutUnitAccess", err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
userRepoIDs, err = ctxUser.GetAccessRepoIDs(models.UnitTypeIssues, models.UnitTypePullRequests)
|
||||
if err != nil {
|
||||
ctx.ServerError("ctxUser.GetAccessRepoIDs", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if len(userRepoIDs) == 0 {
|
||||
userRepoIDs = []int64{-1}
|
||||
}
|
||||
|
||||
var repoIDs []int64
|
||||
if len(reposQuery) != 0 {
|
||||
if issueReposQueryPattern.MatchString(reposQuery) {
|
||||
// remove "[" and "]" from string
|
||||
reposQuery = reposQuery[1 : len(reposQuery)-1]
|
||||
//for each ID (delimiter ",") add to int to repoIDs
|
||||
reposSet := false
|
||||
|
||||
for _, rID := range strings.Split(reposQuery, ",") {
|
||||
// Ensure nonempty string entries
|
||||
if rID != "" && rID != "0" {
|
||||
reposSet = true
|
||||
rIDint64, err := strconv.ParseInt(rID, 10, 64)
|
||||
// If the repo id specified by query is not parseable or not accessible by user, just ignore it.
|
||||
if err == nil && com.IsSliceContainsInt64(userRepoIDs, rIDint64) {
|
||||
if err == nil {
|
||||
repoIDs = append(repoIDs, rIDint64)
|
||||
}
|
||||
}
|
||||
}
|
||||
if reposSet && len(repoIDs) == 0 {
|
||||
// force an empty result
|
||||
repoIDs = []int64{-1}
|
||||
if len(repoIDs) > 0 {
|
||||
// Don't just let repoCond = builder.In("id", repoIDs) because user may has no permission on repoIDs
|
||||
// But the original repoCond has a limitation
|
||||
repoCond = repoCond.And(builder.In("id", repoIDs))
|
||||
}
|
||||
} else {
|
||||
log.Warn("issueReposQueryPattern not match with query")
|
||||
}
|
||||
}
|
||||
|
||||
if len(repoIDs) == 0 {
|
||||
repoIDs = userRepoIDs
|
||||
}
|
||||
|
||||
counts, err := models.CountMilestonesByRepoIDs(userRepoIDs, isShowClosed)
|
||||
counts, err := models.CountMilestones(userRepoCond, isShowClosed)
|
||||
if err != nil {
|
||||
ctx.ServerError("CountMilestonesByRepoIDs", err)
|
||||
return
|
||||
}
|
||||
|
||||
milestones, err := models.GetMilestonesByRepoIDs(repoIDs, page, isShowClosed, sortType)
|
||||
milestones, err := models.SearchMilestones(repoCond, page, isShowClosed, sortType)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetMilestonesByRepoIDs", err)
|
||||
return
|
||||
}
|
||||
|
||||
showReposMap := make(map[int64]*models.Repository, len(counts))
|
||||
for rID := range counts {
|
||||
if rID == -1 {
|
||||
break
|
||||
}
|
||||
repo, err := models.GetRepositoryByID(rID)
|
||||
if err != nil {
|
||||
if models.IsErrRepoNotExist(err) {
|
||||
ctx.NotFound("GetRepositoryByID", err)
|
||||
return
|
||||
} else if err != nil {
|
||||
ctx.ServerError("GetRepositoryByID", fmt.Errorf("[%d]%v", rID, err))
|
||||
return
|
||||
}
|
||||
}
|
||||
showReposMap[rID] = repo
|
||||
}
|
||||
|
||||
showRepos := models.RepositoryListOfMap(showReposMap)
|
||||
sort.Sort(showRepos)
|
||||
if err = showRepos.LoadAttributes(); err != nil {
|
||||
ctx.ServerError("LoadAttributes", err)
|
||||
showRepos, _, err := models.SearchRepositoryByCondition(&repoOpts, userRepoCond)
|
||||
if err != nil {
|
||||
ctx.ServerError("SearchRepositoryByCondition", err)
|
||||
return
|
||||
}
|
||||
sort.Sort(showRepos)
|
||||
|
||||
for _, m := range milestones {
|
||||
m.Repo = showReposMap[m.RepoID]
|
||||
m.RenderedContent = string(markdown.Render([]byte(m.Content), m.Repo.Link(), m.Repo.ComposeMetas()))
|
||||
if m.Repo.IsTimetrackerEnabled() {
|
||||
err := m.LoadTotalTrackedTime()
|
||||
for i := 0; i < len(milestones); {
|
||||
for _, repo := range showRepos {
|
||||
if milestones[i].RepoID == repo.ID {
|
||||
milestones[i].Repo = repo
|
||||
break
|
||||
}
|
||||
}
|
||||
if milestones[i].Repo == nil {
|
||||
log.Warn("Cannot find milestone %d 's repository %d", milestones[i].ID, milestones[i].RepoID)
|
||||
milestones = append(milestones[:i], milestones[i+1:]...)
|
||||
continue
|
||||
}
|
||||
|
||||
milestones[i].RenderedContent = string(markdown.Render([]byte(milestones[i].Content), milestones[i].Repo.Link(), milestones[i].Repo.ComposeMetas()))
|
||||
if milestones[i].Repo.IsTimetrackerEnabled() {
|
||||
err := milestones[i].LoadTotalTrackedTime()
|
||||
if err != nil {
|
||||
ctx.ServerError("LoadTotalTrackedTime", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
milestoneStats, err := models.GetMilestonesStats(repoIDs)
|
||||
milestoneStats, err := models.GetMilestonesStats(repoCond)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetMilestoneStats", err)
|
||||
return
|
||||
}
|
||||
|
||||
totalMilestoneStats, err := models.GetMilestonesStats(userRepoIDs)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetMilestoneStats", err)
|
||||
return
|
||||
var totalMilestoneStats *models.MilestonesStats
|
||||
if len(repoIDs) == 0 {
|
||||
totalMilestoneStats = milestoneStats
|
||||
} else {
|
||||
totalMilestoneStats, err = models.GetMilestonesStats(userRepoCond)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetMilestoneStats", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var pagerCount int
|
||||
@@ -318,7 +297,7 @@ func Milestones(ctx *context.Context) {
|
||||
ctx.Data["Counts"] = counts
|
||||
ctx.Data["MilestoneStats"] = milestoneStats
|
||||
ctx.Data["SortType"] = sortType
|
||||
if len(repoIDs) != len(userRepoIDs) {
|
||||
if milestoneStats.Total() != totalMilestoneStats.Total() {
|
||||
ctx.Data["RepoIDs"] = repoIDs
|
||||
}
|
||||
ctx.Data["IsShowClosed"] = isShowClosed
|
||||
|
||||
@@ -48,7 +48,7 @@ func TestMilestones(t *testing.T) {
|
||||
assert.EqualValues(t, "furthestduedate", ctx.Data["SortType"])
|
||||
assert.EqualValues(t, 1, ctx.Data["Total"])
|
||||
assert.Len(t, ctx.Data["Milestones"], 1)
|
||||
assert.Len(t, ctx.Data["Repos"], 1)
|
||||
assert.Len(t, ctx.Data["Repos"], 2) // both repo 42 and 1 have milestones and both are owned by user 2
|
||||
}
|
||||
|
||||
func TestMilestonesForSpecificRepo(t *testing.T) {
|
||||
@@ -68,5 +68,5 @@ func TestMilestonesForSpecificRepo(t *testing.T) {
|
||||
assert.EqualValues(t, "furthestduedate", ctx.Data["SortType"])
|
||||
assert.EqualValues(t, 1, ctx.Data["Total"])
|
||||
assert.Len(t, ctx.Data["Milestones"], 1)
|
||||
assert.Len(t, ctx.Data["Repos"], 1)
|
||||
assert.Len(t, ctx.Data["Repos"], 2) // both repo 42 and 1 have milestones and both are owned by user 2
|
||||
}
|
||||
|
||||
@@ -68,24 +68,39 @@ func Notifications(c *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
repos, err := notifications.LoadRepos()
|
||||
failCount := 0
|
||||
|
||||
repos, failures, err := notifications.LoadRepos()
|
||||
if err != nil {
|
||||
c.ServerError("LoadRepos", err)
|
||||
return
|
||||
}
|
||||
notifications = notifications.Without(failures)
|
||||
if err := repos.LoadAttributes(); err != nil {
|
||||
c.ServerError("LoadAttributes", err)
|
||||
return
|
||||
}
|
||||
failCount += len(failures)
|
||||
|
||||
if err := notifications.LoadIssues(); err != nil {
|
||||
failures, err = notifications.LoadIssues()
|
||||
if err != nil {
|
||||
c.ServerError("LoadIssues", err)
|
||||
return
|
||||
}
|
||||
if err := notifications.LoadComments(); err != nil {
|
||||
notifications = notifications.Without(failures)
|
||||
failCount += len(failures)
|
||||
|
||||
failures, err = notifications.LoadComments()
|
||||
if err != nil {
|
||||
c.ServerError("LoadComments", err)
|
||||
return
|
||||
}
|
||||
notifications = notifications.Without(failures)
|
||||
failCount += len(failures)
|
||||
|
||||
if failCount > 0 {
|
||||
c.Flash.Error(fmt.Sprintf("ERROR: %d notifications were removed due to missing parts - check the logs", failCount))
|
||||
}
|
||||
|
||||
total, err := models.GetNotificationCount(c.User, status)
|
||||
if err != nil {
|
||||
|
||||
@@ -47,7 +47,7 @@ func checkAndUpdateStatus(pr *models.PullRequest) {
|
||||
|
||||
// Make sure there is no waiting test to process before leaving the checking status.
|
||||
if !pullRequestQueue.Exist(pr.ID) {
|
||||
if err := pr.UpdateCols("merge_base", "status", "conflicted_files"); err != nil {
|
||||
if err := pr.UpdateColsIfNotMerged("merge_base", "status", "conflicted_files"); err != nil {
|
||||
log.Error("Update[%d]: %v", pr.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,17 +211,34 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
|
||||
if err := git.NewCommand("rebase", baseBranch).RunInDirPipeline(tmpBasePath, &outbuf, &errbuf); err != nil {
|
||||
// Rebase will leave a REBASE_HEAD file in .git if there is a conflict
|
||||
if _, statErr := os.Stat(filepath.Join(tmpBasePath, ".git", "REBASE_HEAD")); statErr == nil {
|
||||
// The original commit SHA1 that is failing will be in .git/rebase-apply/original-commit
|
||||
commitShaBytes, readErr := ioutil.ReadFile(filepath.Join(tmpBasePath, ".git", "rebase-apply", "original-commit"))
|
||||
if readErr != nil {
|
||||
// Abandon this attempt to handle the error
|
||||
var commitSha string
|
||||
ok := false
|
||||
failingCommitPaths := []string{
|
||||
filepath.Join(tmpBasePath, ".git", "rebase-apply", "original-commit"), // Git < 2.26
|
||||
filepath.Join(tmpBasePath, ".git", "rebase-merge", "stopped-sha"), // Git >= 2.26
|
||||
}
|
||||
for _, failingCommitPath := range failingCommitPaths {
|
||||
if _, statErr := os.Stat(filepath.Join(failingCommitPath)); statErr == nil {
|
||||
commitShaBytes, readErr := ioutil.ReadFile(filepath.Join(failingCommitPath))
|
||||
if readErr != nil {
|
||||
// Abandon this attempt to handle the error
|
||||
log.Error("git rebase staging on to base [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
|
||||
return fmt.Errorf("git rebase staging on to base [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
|
||||
}
|
||||
commitSha = strings.TrimSpace(string(commitShaBytes))
|
||||
ok = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
log.Error("Unable to determine failing commit sha for this rebase message. Cannot cast as models.ErrRebaseConflicts.")
|
||||
log.Error("git rebase staging on to base [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
|
||||
return fmt.Errorf("git rebase staging on to base [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
|
||||
}
|
||||
log.Debug("RebaseConflict at %s [%s:%s -> %s:%s]: %v\n%s\n%s", strings.TrimSpace(string(commitShaBytes)), pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
|
||||
log.Debug("RebaseConflict at %s [%s:%s -> %s:%s]: %v\n%s\n%s", commitSha, pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
|
||||
return models.ErrRebaseConflicts{
|
||||
Style: mergeStyle,
|
||||
CommitSHA: strings.TrimSpace(string(commitShaBytes)),
|
||||
CommitSHA: commitSha,
|
||||
StdOut: outbuf.String(),
|
||||
StdErr: errbuf.String(),
|
||||
Err: err,
|
||||
@@ -268,6 +285,10 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
|
||||
return err
|
||||
}
|
||||
|
||||
if err = pr.Issue.LoadPoster(); err != nil {
|
||||
log.Error("LoadPoster: %v", err)
|
||||
return fmt.Errorf("LoadPoster: %v", err)
|
||||
}
|
||||
sig := pr.Issue.Poster.NewGitSig()
|
||||
if signArg == "" {
|
||||
if err := git.NewCommand("commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), "-m", message).RunInDirTimeoutEnvPipeline(env, -1, tmpBasePath, &outbuf, &errbuf); err != nil {
|
||||
|
||||
@@ -31,32 +31,19 @@ func DownloadPatch(pr *models.PullRequest, w io.Writer, patch bool) error {
|
||||
|
||||
// DownloadDiffOrPatch will write the patch for the pr to the writer
|
||||
func DownloadDiffOrPatch(pr *models.PullRequest, w io.Writer, patch bool) error {
|
||||
// Clone base repo.
|
||||
tmpBasePath, err := createTemporaryRepo(pr)
|
||||
if err != nil {
|
||||
log.Error("CreateTemporaryPath: %v", err)
|
||||
if err := pr.LoadBaseRepo(); err != nil {
|
||||
log.Error("Unable to load base repository ID %d for pr #%d [%d]", pr.BaseRepoID, pr.Index, pr.ID)
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err := models.RemoveTemporaryPath(tmpBasePath); err != nil {
|
||||
log.Error("DownloadDiff: RemoveTemporaryPath: %s", err)
|
||||
}
|
||||
}()
|
||||
|
||||
gitRepo, err := git.OpenRepository(tmpBasePath)
|
||||
gitRepo, err := git.OpenRepository(pr.BaseRepo.RepoPath())
|
||||
if err != nil {
|
||||
return fmt.Errorf("OpenRepository: %v", err)
|
||||
}
|
||||
defer gitRepo.Close()
|
||||
|
||||
pr.MergeBase, err = git.NewCommand("merge-base", "--", "base", "tracking").RunInDir(tmpBasePath)
|
||||
if err != nil {
|
||||
pr.MergeBase = "base"
|
||||
}
|
||||
pr.MergeBase = strings.TrimSpace(pr.MergeBase)
|
||||
if err := gitRepo.GetDiffOrPatch(pr.MergeBase, "tracking", w, patch); err != nil {
|
||||
log.Error("Unable to get patch file from %s to %s in %s/%s Error: %v", pr.MergeBase, pr.HeadBranch, pr.BaseRepo.MustOwner().Name, pr.BaseRepo.Name, err)
|
||||
return fmt.Errorf("Unable to get patch file from %s to %s in %s/%s Error: %v", pr.MergeBase, pr.HeadBranch, pr.BaseRepo.MustOwner().Name, pr.BaseRepo.Name, err)
|
||||
if err := gitRepo.GetDiffOrPatch(pr.MergeBase, pr.GetGitRefName(), w, patch); err != nil {
|
||||
log.Error("Unable to get patch file from %s to %s in %s Error: %v", pr.MergeBase, pr.HeadBranch, pr.BaseRepo.FullName(), err)
|
||||
return fmt.Errorf("Unable to get patch file from %s to %s in %s Error: %v", pr.MergeBase, pr.HeadBranch, pr.BaseRepo.FullName(), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ func ChangeTargetBranch(pr *models.PullRequest, doer *models.User, targetBranch
|
||||
if pr.Status == models.PullRequestStatusChecking {
|
||||
pr.Status = models.PullRequestStatusMergeable
|
||||
}
|
||||
if err := pr.UpdateCols("status, conflicted_files, base_branch"); err != nil {
|
||||
if err := pr.UpdateColsIfNotMerged("merge_base", "status", "conflicted_files", "base_branch"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
|
||||
{{if .IsNothingToCompare}}
|
||||
<div class="ui segment">{{.i18n.Tr "repo.pulls.nothing_to_compare"}}</div>
|
||||
{{else if .PageIsComparePull}}
|
||||
{{else if and .PageIsComparePull (gt .CommitCount 0)}}
|
||||
{{if .HasPullRequest}}
|
||||
<div class="ui segment">
|
||||
{{.i18n.Tr "repo.pulls.has_pull_request" $.RepoLink $.RepoRelPath .PullRequest.Index | Safe}}
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
|
||||
{{if and (.Permission.CanRead $.UnitTypeReleases) (not .IsEmptyRepo) }}
|
||||
<a class="{{if .PageIsReleaseList}}active{{end}} item" href="{{.RepoLink}}/releases">
|
||||
<i class="octicon octicon-tag"></i> {{.i18n.Tr "repo.releases"}} <span class="ui {{if not .Repository.NumReleases}}gray{{else}}blue{{end}} small label">{{.Repository.NumReleases}}</span>
|
||||
<i class="octicon octicon-tag"></i> {{.i18n.Tr "repo.releases"}} <span class="ui {{if not .NumReleases}}gray{{else}}blue{{end}} small label">{{.NumReleases}}</span>
|
||||
</a>
|
||||
{{end}}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
{{else if .IsBlockedByApprovals}}red
|
||||
{{else if .IsBlockedByRejection}}red
|
||||
{{else if and .EnableStatusCheck (or .RequiredStatusCheckState.IsFailure .RequiredStatusCheckState.IsError)}}red
|
||||
{{else if and .EnableStatusCheck (or .RequiredStatusCheckState.IsPending .RequiredStatusCheckState.IsWarning)}}yellow
|
||||
{{else if and .EnableStatusCheck (or (not $.LatestCommitStatus) .RequiredStatusCheckState.IsPending .RequiredStatusCheckState.IsWarning)}}yellow
|
||||
{{else if .Issue.PullRequest.IsChecking}}yellow
|
||||
{{else if .Issue.PullRequest.CanAutoMerge}}green
|
||||
{{else}}red{{end}}"><span class="mega-octicon octicon-git-merge"></span></a>
|
||||
@@ -112,7 +112,7 @@
|
||||
<span class="octicon octicon-sync"></span>
|
||||
{{$.i18n.Tr "repo.pulls.is_checking"}}
|
||||
</div>
|
||||
{{else if and (not .Issue.PullRequest.CanAutoMerge) .EnableStatusCheck (not .IsRequiredStatusCheckSuccess)}}
|
||||
{{else if and (not .Issue.PullRequest.CanAutoMerge) .EnableStatusCheck (not .RequiredStatusCheckState.IsSuccess)}}
|
||||
<div class="item text red">
|
||||
<span class="octicon octicon-x"></span>
|
||||
{{$.i18n.Tr "repo.pulls.required_status_check_failed"}}
|
||||
@@ -123,9 +123,14 @@
|
||||
<span class="octicon octicon-x"></span>
|
||||
{{$.i18n.Tr "repo.pulls.required_status_check_failed"}}
|
||||
</div>
|
||||
{{else if and .EnableStatusCheck (not .RequiredStatusCheckState.IsSuccess)}}
|
||||
<div class="item text red">
|
||||
<span class="octicon octicon-x"></span>
|
||||
{{$.i18n.Tr "repo.pulls.required_status_check_missing"}}
|
||||
</div>
|
||||
{{end}}
|
||||
{{if or $.IsRepoAdmin (not .EnableStatusCheck) .IsRequiredStatusCheckSuccess}}
|
||||
{{if and $.IsRepoAdmin .EnableStatusCheck (not .IsRequiredStatusCheckSuccess)}}
|
||||
{{if or $.IsRepoAdmin (not .EnableStatusCheck) .RequiredStatusCheckState.IsSuccess}}
|
||||
{{if and $.IsRepoAdmin .EnableStatusCheck (not .RequiredStatusCheckState.IsSuccess)}}
|
||||
<div class="item text yellow">
|
||||
<span class="octicon octicon-primitive-dot"></span>
|
||||
{{$.i18n.Tr "repo.pulls.required_status_check_administrator"}}
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
<td>
|
||||
<span class="truncate">
|
||||
<span class="octicon octicon-file-submodule"></span>
|
||||
{{$refURL := $commit.RefURL AppUrl $.BranchLink}}
|
||||
{{$refURL := $commit.RefURL AppUrl $.Repository.FullName}}
|
||||
{{if $refURL}}
|
||||
<a href="{{$refURL}}">{{$entry.Name}}</a> @ <a href="{{$refURL}}/commit/{{$commit.RefID}}">{{ShortSha $commit.RefID}}</a>
|
||||
{{else}}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{{template "base/head" .}}
|
||||
{{if .IsRepo}}<div class="repository">{{template "repo/header" .}}</div>{{end}}
|
||||
<div class="ui container center">
|
||||
<p style="margin-top: 100px"><img src="{{StaticUrlPrefix}}/img/404.png" alt="404"/></p>
|
||||
<p style="margin-top: 100px"><img class="ui centered image" src="{{StaticUrlPrefix}}/img/404.png" alt="404"/></p>
|
||||
<div class="ui divider"></div>
|
||||
<br>
|
||||
{{if .ShowFooterVersion}}<p>Application Version: {{AppVer}}</p>{{end}}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{{template "base/head" .}}
|
||||
<div class="ui container center">
|
||||
<p style="margin-top: 100px"><img src="{{StaticUrlPrefix}}/img/500.png" alt="500"/></p>
|
||||
<p style="margin-top: 100px"><img class="ui centered image" src="{{StaticUrlPrefix}}/img/500.png" alt="500"/></p>
|
||||
<div class="ui divider"></div>
|
||||
<br>
|
||||
{{if .ErrorMsg}}<p>An error has occurred :</p>
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
<form action="{{AppSubUrl}}/user/settings/account/email" method="post">
|
||||
{{$.CsrfTokenHtml}}
|
||||
<input name="_method" type="hidden" value="SENDACTIVATION">
|
||||
<input name="id" type="hidden" value="{{if .IsPrimary}}PRIMARY{{else}}}.ID{{end}}">
|
||||
<input name="id" type="hidden" value="{{if .IsPrimary}}PRIMARY{{else}}{{.ID}}{{end}}">
|
||||
{{if $.ActivationsPending}}
|
||||
<button disabled class="ui blue tiny button">{{$.i18n.Tr "settings.activations_pending"}}</button>
|
||||
{{else}}
|
||||
|
||||
0
vendor/github.com/src-d/gcfg/LICENSE → vendor/github.com/go-git/gcfg/LICENSE
generated
vendored
0
vendor/github.com/src-d/gcfg/LICENSE → vendor/github.com/go-git/gcfg/LICENSE
generated
vendored
0
vendor/github.com/src-d/gcfg/README → vendor/github.com/go-git/gcfg/README
generated
vendored
0
vendor/github.com/src-d/gcfg/README → vendor/github.com/go-git/gcfg/README
generated
vendored
2
vendor/github.com/src-d/gcfg/doc.go → vendor/github.com/go-git/gcfg/doc.go
generated
vendored
2
vendor/github.com/src-d/gcfg/doc.go → vendor/github.com/go-git/gcfg/doc.go
generated
vendored
@@ -142,4 +142,4 @@
|
||||
// - make error context accessible programmatically?
|
||||
// - limit input size?
|
||||
//
|
||||
package gcfg // import "github.com/src-d/gcfg"
|
||||
package gcfg // import "github.com/go-git/gcfg"
|
||||
0
vendor/github.com/src-d/gcfg/errors.go → vendor/github.com/go-git/gcfg/errors.go
generated
vendored
0
vendor/github.com/src-d/gcfg/errors.go → vendor/github.com/go-git/gcfg/errors.go
generated
vendored
0
vendor/github.com/src-d/gcfg/go1_0.go → vendor/github.com/go-git/gcfg/go1_0.go
generated
vendored
0
vendor/github.com/src-d/gcfg/go1_0.go → vendor/github.com/go-git/gcfg/go1_0.go
generated
vendored
0
vendor/github.com/src-d/gcfg/go1_2.go → vendor/github.com/go-git/gcfg/go1_2.go
generated
vendored
0
vendor/github.com/src-d/gcfg/go1_2.go → vendor/github.com/go-git/gcfg/go1_2.go
generated
vendored
4
vendor/github.com/src-d/gcfg/read.go → vendor/github.com/go-git/gcfg/read.go
generated
vendored
4
vendor/github.com/src-d/gcfg/read.go → vendor/github.com/go-git/gcfg/read.go
generated
vendored
@@ -7,8 +7,8 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/src-d/gcfg/scanner"
|
||||
"github.com/src-d/gcfg/token"
|
||||
"github.com/go-git/gcfg/scanner"
|
||||
"github.com/go-git/gcfg/token"
|
||||
"gopkg.in/warnings.v0"
|
||||
)
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
import (
|
||||
"github.com/src-d/gcfg/token"
|
||||
"github.com/go-git/gcfg/token"
|
||||
)
|
||||
|
||||
// In an ErrorList, an error is represented by an *Error.
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
)
|
||||
|
||||
import (
|
||||
"github.com/src-d/gcfg/token"
|
||||
"github.com/go-git/gcfg/token"
|
||||
)
|
||||
|
||||
// An ErrorHandler may be provided to Scanner.Init. If a syntax error is
|
||||
2
vendor/github.com/src-d/gcfg/set.go → vendor/github.com/go-git/gcfg/set.go
generated
vendored
2
vendor/github.com/src-d/gcfg/set.go → vendor/github.com/go-git/gcfg/set.go
generated
vendored
@@ -10,7 +10,7 @@ import (
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/src-d/gcfg/types"
|
||||
"github.com/go-git/gcfg/types"
|
||||
"gopkg.in/warnings.v0"
|
||||
)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user