Add single release page and latest redirect (#11102)
* 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>
This commit is contained in:
		
							parent
							
								
									1b86f174ce
								
							
						
					
					
						commit
						4f597b1866
					
				
					 6 changed files with 96 additions and 2 deletions
				
			
		|  | @ -80,6 +80,11 @@ func (r *Release) TarURL() string { | ||||||
| 	return fmt.Sprintf("%s/archive/%s.tar.gz", r.Repo.HTMLURL(), r.TagName) | 	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
 | // APIFormat convert a Release to api.Release
 | ||||||
| func (r *Release) APIFormat() *api.Release { | func (r *Release) APIFormat() *api.Release { | ||||||
| 	assets := make([]*api.Attachment, 0) | 	assets := make([]*api.Attachment, 0) | ||||||
|  | @ -93,6 +98,7 @@ func (r *Release) APIFormat() *api.Release { | ||||||
| 		Title:        r.Title, | 		Title:        r.Title, | ||||||
| 		Note:         r.Note, | 		Note:         r.Note, | ||||||
| 		URL:          r.APIURL(), | 		URL:          r.APIURL(), | ||||||
|  | 		HTMLURL:      r.HTMLURL(), | ||||||
| 		TarURL:       r.TarURL(), | 		TarURL:       r.TarURL(), | ||||||
| 		ZipURL:       r.ZipURL(), | 		ZipURL:       r.ZipURL(), | ||||||
| 		IsDraft:      r.IsDraft, | 		IsDraft:      r.IsDraft, | ||||||
|  | @ -217,6 +223,28 @@ func GetReleasesByRepoID(repoID int64, opts FindReleasesOptions) ([]*Release, er | ||||||
| 	return rels, sess.Find(&rels) | 	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.
 | // GetReleasesByRepoIDAndNames returns a list of releases of repository according repoID and tagNames.
 | ||||||
| func GetReleasesByRepoIDAndNames(ctx DBContext, repoID int64, tagNames []string) (rels []*Release, err error) { | func GetReleasesByRepoIDAndNames(ctx DBContext, repoID int64, tagNames []string) (rels []*Release, err error) { | ||||||
| 	err = ctx.e. | 	err = ctx.e. | ||||||
|  |  | ||||||
|  | @ -16,6 +16,7 @@ type Release struct { | ||||||
| 	Title        string `json:"name"` | 	Title        string `json:"name"` | ||||||
| 	Note         string `json:"body"` | 	Note         string `json:"body"` | ||||||
| 	URL          string `json:"url"` | 	URL          string `json:"url"` | ||||||
|  | 	HTMLURL      string `json:"html_url"` | ||||||
| 	TarURL       string `json:"tarball_url"` | 	TarURL       string `json:"tarball_url"` | ||||||
| 	ZipURL       string `json:"zipball_url"` | 	ZipURL       string `json:"zipball_url"` | ||||||
| 	IsDraft      bool   `json:"draft"` | 	IsDraft      bool   `json:"draft"` | ||||||
|  |  | ||||||
|  | @ -131,6 +131,65 @@ func Releases(ctx *context.Context) { | ||||||
| 	ctx.HTML(200, tplReleases) | 	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
 | // NewRelease render creating release page
 | ||||||
| func NewRelease(ctx *context.Context) { | func NewRelease(ctx *context.Context) { | ||||||
| 	ctx.Data["Title"] = ctx.Tr("repo.release.new_release") | 	ctx.Data["Title"] = ctx.Tr("repo.release.new_release") | ||||||
|  |  | ||||||
|  | @ -805,7 +805,9 @@ func RegisterRoutes(m *macaron.Macaron) { | ||||||
| 	// Releases
 | 	// Releases
 | ||||||
| 	m.Group("/:username/:reponame", func() { | 	m.Group("/:username/:reponame", func() { | ||||||
| 		m.Group("/releases", 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()) | 		}, repo.MustBeNotEmpty, context.RepoRef()) | ||||||
| 		m.Group("/releases", func() { | 		m.Group("/releases", func() { | ||||||
| 			m.Get("/new", repo.NewRelease) | 			m.Get("/new", repo.NewRelease) | ||||||
|  |  | ||||||
|  | @ -49,7 +49,7 @@ | ||||||
| 							</div> | 							</div> | ||||||
| 						{{else}} | 						{{else}} | ||||||
| 							<h3> | 							<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}} | 								{{if $.CanCreateRelease}}<small>(<a href="{{$.RepoLink}}/releases/edit/{{.TagName | EscapePound}}" rel="nofollow">{{$.i18n.Tr "repo.release.edit"}}</a>)</small>{{end}} | ||||||
| 							</h3> | 							</h3> | ||||||
| 							<p class="text grey"> | 							<p class="text grey"> | ||||||
|  |  | ||||||
|  | @ -13107,6 +13107,10 @@ | ||||||
|           "type": "boolean", |           "type": "boolean", | ||||||
|           "x-go-name": "IsDraft" |           "x-go-name": "IsDraft" | ||||||
|         }, |         }, | ||||||
|  |         "html_url": { | ||||||
|  |           "type": "string", | ||||||
|  |           "x-go-name": "HTMLURL" | ||||||
|  |         }, | ||||||
|         "id": { |         "id": { | ||||||
|           "type": "integer", |           "type": "integer", | ||||||
|           "format": "int64", |           "format": "int64", | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue