* Add single release and latest release routes Signed-off-by: jolheiser <john.olheiser@gmail.com> * Update API and move latest search to models Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix swagger Signed-off-by: jolheiser <john.olheiser@gmail.com> Co-authored-by: guillep2k <18600385+guillep2k@users.noreply.github.com>tags/v1.13.0-dev
@@ -80,6 +80,11 @@ func (r *Release) TarURL() string { | |||
return fmt.Sprintf("%s/archive/%s.tar.gz", r.Repo.HTMLURL(), r.TagName) | |||
} | |||
// HTMLURL the url for a release on the web UI. release must have attributes loaded | |||
func (r *Release) HTMLURL() string { | |||
return fmt.Sprintf("%s/releases/tag/%s", r.Repo.HTMLURL(), r.TagName) | |||
} | |||
// APIFormat convert a Release to api.Release | |||
func (r *Release) APIFormat() *api.Release { | |||
assets := make([]*api.Attachment, 0) | |||
@@ -93,6 +98,7 @@ func (r *Release) APIFormat() *api.Release { | |||
Title: r.Title, | |||
Note: r.Note, | |||
URL: r.APIURL(), | |||
HTMLURL: r.HTMLURL(), | |||
TarURL: r.TarURL(), | |||
ZipURL: r.ZipURL(), | |||
IsDraft: r.IsDraft, | |||
@@ -217,6 +223,28 @@ func GetReleasesByRepoID(repoID int64, opts FindReleasesOptions) ([]*Release, er | |||
return rels, sess.Find(&rels) | |||
} | |||
// GetLatestReleaseByRepoID returns the latest release for a repository | |||
func GetLatestReleaseByRepoID(repoID int64) (*Release, error) { | |||
cond := builder.NewCond(). | |||
And(builder.Eq{"repo_id": repoID}). | |||
And(builder.Eq{"is_draft": false}). | |||
And(builder.Eq{"is_prerelease": false}). | |||
And(builder.Eq{"is_tag": false}) | |||
rel := new(Release) | |||
has, err := x. | |||
Desc("created_unix", "id"). | |||
Where(cond). | |||
Get(rel) | |||
if err != nil { | |||
return nil, err | |||
} else if !has { | |||
return nil, ErrReleaseNotExist{0, "latest"} | |||
} | |||
return rel, nil | |||
} | |||
// GetReleasesByRepoIDAndNames returns a list of releases of repository according repoID and tagNames. | |||
func GetReleasesByRepoIDAndNames(ctx DBContext, repoID int64, tagNames []string) (rels []*Release, err error) { | |||
err = ctx.e. |
@@ -16,6 +16,7 @@ type Release struct { | |||
Title string `json:"name"` | |||
Note string `json:"body"` | |||
URL string `json:"url"` | |||
HTMLURL string `json:"html_url"` | |||
TarURL string `json:"tarball_url"` | |||
ZipURL string `json:"zipball_url"` | |||
IsDraft bool `json:"draft"` |
@@ -131,6 +131,65 @@ func Releases(ctx *context.Context) { | |||
ctx.HTML(200, tplReleases) | |||
} | |||
// SingleRelease renders a single release's page | |||
func SingleRelease(ctx *context.Context) { | |||
ctx.Data["Title"] = ctx.Tr("repo.release.releases") | |||
ctx.Data["PageIsReleaseList"] = true | |||
writeAccess := ctx.Repo.CanWrite(models.UnitTypeReleases) | |||
ctx.Data["CanCreateRelease"] = writeAccess && !ctx.Repo.Repository.IsArchived | |||
release, err := models.GetRelease(ctx.Repo.Repository.ID, ctx.Params("tag")) | |||
if err != nil { | |||
ctx.ServerError("GetReleasesByRepoID", err) | |||
return | |||
} | |||
err = models.GetReleaseAttachments(release) | |||
if err != nil { | |||
ctx.ServerError("GetReleaseAttachments", err) | |||
return | |||
} | |||
release.Publisher, err = models.GetUserByID(release.PublisherID) | |||
if err != nil { | |||
if models.IsErrUserNotExist(err) { | |||
release.Publisher = models.NewGhostUser() | |||
} else { | |||
ctx.ServerError("GetUserByID", err) | |||
return | |||
} | |||
} | |||
if err := calReleaseNumCommitsBehind(ctx.Repo, release, make(map[string]int64)); err != nil { | |||
ctx.ServerError("calReleaseNumCommitsBehind", err) | |||
return | |||
} | |||
release.Note = markdown.RenderString(release.Note, ctx.Repo.RepoLink, ctx.Repo.Repository.ComposeMetas()) | |||
ctx.Data["Releases"] = []*models.Release{release} | |||
ctx.HTML(200, tplReleases) | |||
} | |||
// LatestRelease redirects to the latest release | |||
func LatestRelease(ctx *context.Context) { | |||
release, err := models.GetLatestReleaseByRepoID(ctx.Repo.Repository.ID) | |||
if err != nil { | |||
if models.IsErrReleaseNotExist(err) { | |||
ctx.NotFound("LatestRelease", err) | |||
return | |||
} | |||
ctx.ServerError("GetLatestReleaseByRepoID", err) | |||
return | |||
} | |||
if err := release.LoadAttributes(); err != nil { | |||
ctx.ServerError("LoadAttributes", err) | |||
return | |||
} | |||
ctx.Redirect(release.HTMLURL()) | |||
} | |||
// NewRelease render creating release page | |||
func NewRelease(ctx *context.Context) { | |||
ctx.Data["Title"] = ctx.Tr("repo.release.new_release") |
@@ -805,7 +805,9 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
// Releases | |||
m.Group("/:username/:reponame", func() { | |||
m.Group("/releases", func() { | |||
m.Get("/", repo.MustBeNotEmpty, repo.Releases) | |||
m.Get("/", repo.Releases) | |||
m.Get("/tag/:tag", repo.SingleRelease) | |||
m.Get("/latest", repo.LatestRelease) | |||
}, repo.MustBeNotEmpty, context.RepoRef()) | |||
m.Group("/releases", func() { | |||
m.Get("/new", repo.NewRelease) |
@@ -49,7 +49,7 @@ | |||
</div> | |||
{{else}} | |||
<h3> | |||
<a href="{{$.RepoLink}}/src/tag/{{.TagName | EscapePound}}">{{.Title}}</a> | |||
<a href="{{$.RepoLink}}/releases/tag/{{.TagName | EscapePound}}">{{.Title}}</a> | |||
{{if $.CanCreateRelease}}<small>(<a href="{{$.RepoLink}}/releases/edit/{{.TagName | EscapePound}}" rel="nofollow">{{$.i18n.Tr "repo.release.edit"}}</a>)</small>{{end}} | |||
</h3> | |||
<p class="text grey"> |
@@ -13107,6 +13107,10 @@ | |||
"type": "boolean", | |||
"x-go-name": "IsDraft" | |||
}, | |||
"html_url": { | |||
"type": "string", | |||
"x-go-name": "HTMLURL" | |||
}, | |||
"id": { | |||
"type": "integer", | |||
"format": "int64", |