gogs/routers/repo/release.go
Unknwon ebc0943713
templates/repo: only show Git stats in repository home page (#3518)
Move 'Commits' and 'Releases' tabs down to body.

This patch also reduces page load time for pages that do not need
to use commits count anywhere. Get commits count can hurt
performance badly for huge repositories that has tens of thousands
commits like Linux Kernel.
2017-03-10 15:13:48 -05:00

298 lines
8.0 KiB
Go

// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package repo
import (
"fmt"
log "gopkg.in/clog.v1"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/context"
"github.com/gogits/gogs/modules/form"
"github.com/gogits/gogs/modules/markdown"
)
const (
RELEASES base.TplName = "repo/release/list"
RELEASE_NEW base.TplName = "repo/release/new"
)
// calReleaseNumCommitsBehind calculates given release has how many commits behind release target.
func calReleaseNumCommitsBehind(repoCtx *context.Repository, release *models.Release, countCache map[string]int64) error {
// Get count if not exists
if _, ok := countCache[release.Target]; !ok {
if repoCtx.GitRepo.IsBranchExist(release.Target) {
commit, err := repoCtx.GitRepo.GetBranchCommit(release.Target)
if err != nil {
return fmt.Errorf("GetBranchCommit: %v", err)
}
countCache[release.Target], err = commit.CommitsCount()
if err != nil {
return fmt.Errorf("CommitsCount: %v", err)
}
} else {
// Use NumCommits of the newest release on that target
countCache[release.Target] = release.NumCommits
}
}
release.NumCommitsBehind = countCache[release.Target] - release.NumCommits
return nil
}
func Releases(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.release.releases")
ctx.Data["PageIsReleaseList"] = true
tagsResult, err := ctx.Repo.GitRepo.GetTagsAfter(ctx.Query("after"), 10)
if err != nil {
ctx.Handle(500, fmt.Sprintf("GetTags '%s'", ctx.Repo.Repository.RepoPath()), err)
return
}
releases, err := models.GetPublishedReleasesByRepoID(ctx.Repo.Repository.ID, tagsResult.Tags...)
if err != nil {
ctx.Handle(500, "GetPublishedReleasesByRepoID", err)
return
}
// Temproray cache commits count of used branches to speed up.
countCache := make(map[string]int64)
results := make([]*models.Release, len(tagsResult.Tags))
for i, rawTag := range tagsResult.Tags {
for j, r := range releases {
if r == nil || r.TagName != rawTag {
continue
}
releases[j] = nil // Mark as used.
if err = r.LoadAttributes(); err != nil {
ctx.Handle(500, "LoadAttributes", err)
return
}
if err := calReleaseNumCommitsBehind(ctx.Repo, r, countCache); err != nil {
ctx.Handle(500, "calReleaseNumCommitsBehind", err)
return
}
r.Note = markdown.RenderString(r.Note, ctx.Repo.RepoLink, ctx.Repo.Repository.ComposeMetas())
results[i] = r
break
}
// No published release matches this tag
if results[i] == nil {
commit, err := ctx.Repo.GitRepo.GetTagCommit(rawTag)
if err != nil {
ctx.Handle(500, "GetTagCommit", err)
return
}
results[i] = &models.Release{
Title: rawTag,
TagName: rawTag,
Sha1: commit.ID.String(),
}
results[i].NumCommits, err = commit.CommitsCount()
if err != nil {
ctx.Handle(500, "CommitsCount", err)
return
}
results[i].NumCommitsBehind = ctx.Repo.CommitsCount - results[i].NumCommits
}
}
models.SortReleases(results)
// Only show drafts if user is viewing the latest page
var drafts []*models.Release
if tagsResult.HasLatest {
drafts, err = models.GetDraftReleasesByRepoID(ctx.Repo.Repository.ID)
if err != nil {
ctx.Handle(500, "GetDraftReleasesByRepoID", err)
return
}
for _, r := range drafts {
if err = r.LoadAttributes(); err != nil {
ctx.Handle(500, "LoadAttributes", err)
return
}
if err := calReleaseNumCommitsBehind(ctx.Repo, r, countCache); err != nil {
ctx.Handle(500, "calReleaseNumCommitsBehind", err)
return
}
r.Note = markdown.RenderString(r.Note, ctx.Repo.RepoLink, ctx.Repo.Repository.ComposeMetas())
}
if len(drafts) > 0 {
results = append(drafts, results...)
}
}
ctx.Data["Releases"] = results
ctx.Data["HasPrevious"] = !tagsResult.HasLatest
ctx.Data["ReachEnd"] = tagsResult.ReachEnd
ctx.Data["PreviousAfter"] = tagsResult.PreviousAfter
if len(results) > 0 {
ctx.Data["NextAfter"] = results[len(results)-1].TagName
}
ctx.HTML(200, RELEASES)
}
func NewRelease(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.release.new_release")
ctx.Data["PageIsReleaseList"] = true
ctx.Data["tag_target"] = ctx.Repo.Repository.DefaultBranch
ctx.HTML(200, RELEASE_NEW)
}
func NewReleasePost(ctx *context.Context, f form.NewRelease) {
ctx.Data["Title"] = ctx.Tr("repo.release.new_release")
ctx.Data["PageIsReleaseList"] = true
if ctx.HasError() {
ctx.HTML(200, RELEASE_NEW)
return
}
if !ctx.Repo.GitRepo.IsBranchExist(f.Target) {
ctx.RenderWithErr(ctx.Tr("form.target_branch_not_exist"), RELEASE_NEW, &f)
return
}
var tagCreatedUnix int64
tag, err := ctx.Repo.GitRepo.GetTag(f.TagName)
if err == nil {
commit, err := tag.Commit()
if err == nil {
tagCreatedUnix = commit.Author.When.Unix()
}
}
commit, err := ctx.Repo.GitRepo.GetBranchCommit(f.Target)
if err != nil {
ctx.Handle(500, "GetBranchCommit", err)
return
}
commitsCount, err := commit.CommitsCount()
if err != nil {
ctx.Handle(500, "CommitsCount", err)
return
}
rel := &models.Release{
RepoID: ctx.Repo.Repository.ID,
PublisherID: ctx.User.ID,
Title: f.Title,
TagName: f.TagName,
Target: f.Target,
Sha1: commit.ID.String(),
NumCommits: commitsCount,
Note: f.Content,
IsDraft: len(f.Draft) > 0,
IsPrerelease: f.Prerelease,
CreatedUnix: tagCreatedUnix,
}
if err = models.CreateRelease(ctx.Repo.GitRepo, rel); err != nil {
ctx.Data["Err_TagName"] = true
switch {
case models.IsErrReleaseAlreadyExist(err):
ctx.RenderWithErr(ctx.Tr("repo.release.tag_name_already_exist"), RELEASE_NEW, &f)
case models.IsErrInvalidTagName(err):
ctx.RenderWithErr(ctx.Tr("repo.release.tag_name_invalid"), RELEASE_NEW, &f)
default:
ctx.Handle(500, "CreateRelease", err)
}
return
}
log.Trace("Release created: %s/%s:%s", ctx.User.LowerName, ctx.Repo.Repository.Name, f.TagName)
ctx.Redirect(ctx.Repo.RepoLink + "/releases")
}
func EditRelease(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.release.edit_release")
ctx.Data["PageIsReleaseList"] = true
ctx.Data["PageIsEditRelease"] = true
tagName := ctx.Params("*")
rel, err := models.GetRelease(ctx.Repo.Repository.ID, tagName)
if err != nil {
if models.IsErrReleaseNotExist(err) {
ctx.Handle(404, "GetRelease", err)
} else {
ctx.Handle(500, "GetRelease", err)
}
return
}
ctx.Data["ID"] = rel.ID
ctx.Data["tag_name"] = rel.TagName
ctx.Data["tag_target"] = rel.Target
ctx.Data["title"] = rel.Title
ctx.Data["content"] = rel.Note
ctx.Data["prerelease"] = rel.IsPrerelease
ctx.Data["IsDraft"] = rel.IsDraft
ctx.HTML(200, RELEASE_NEW)
}
func EditReleasePost(ctx *context.Context, f form.EditRelease) {
ctx.Data["Title"] = ctx.Tr("repo.release.edit_release")
ctx.Data["PageIsReleaseList"] = true
ctx.Data["PageIsEditRelease"] = true
tagName := ctx.Params("*")
rel, err := models.GetRelease(ctx.Repo.Repository.ID, tagName)
if err != nil {
if models.IsErrReleaseNotExist(err) {
ctx.Handle(404, "GetRelease", err)
} else {
ctx.Handle(500, "GetRelease", err)
}
return
}
ctx.Data["tag_name"] = rel.TagName
ctx.Data["tag_target"] = rel.Target
ctx.Data["title"] = rel.Title
ctx.Data["content"] = rel.Note
ctx.Data["prerelease"] = rel.IsPrerelease
ctx.Data["IsDraft"] = rel.IsDraft
if ctx.HasError() {
ctx.HTML(200, RELEASE_NEW)
return
}
rel.Title = f.Title
rel.Note = f.Content
rel.IsDraft = len(f.Draft) > 0
rel.IsPrerelease = f.Prerelease
if err = models.UpdateRelease(ctx.Repo.GitRepo, rel); err != nil {
ctx.Handle(500, "UpdateRelease", err)
return
}
ctx.Redirect(ctx.Repo.RepoLink + "/releases")
}
func DeleteRelease(ctx *context.Context) {
if err := models.DeleteReleaseOfRepoByID(ctx.Repo.Repository.ID, ctx.QueryInt64("id")); err != nil {
ctx.Flash.Error("DeleteReleaseByID: " + err.Error())
} else {
ctx.Flash.Success(ctx.Tr("repo.release.deletion_success"))
}
ctx.JSON(200, map[string]interface{}{
"redirect": ctx.Repo.RepoLink + "/releases",
})
}