Fixes #19091 Add Feed for Releases and Tags, can be accessed through `reponame/releases.rss`, `reponame/releases.atom`, `reponame/tags.rss`, and `reponame/tags.atom` Signed-off-by: Reo <reo_999@proton.me>tags/v1.19.0-rc0
@@ -2279,6 +2279,8 @@ release.downloads = Downloads | |||
release.download_count = Downloads: %s | |||
release.add_tag_msg = Use the title and content of release as tag message. | |||
release.add_tag = Create Tag Only | |||
release.releases_for = Releases for %s | |||
release.tags_for = Tags for %s | |||
branch.name = Branch Name | |||
branch.search = Search branches |
@@ -12,6 +12,7 @@ import ( | |||
"strings" | |||
activities_model "code.gitea.io/gitea/models/activities" | |||
repo_model "code.gitea.io/gitea/models/repo" | |||
"code.gitea.io/gitea/modules/context" | |||
"code.gitea.io/gitea/modules/markup" | |||
"code.gitea.io/gitea/modules/markup/markdown" | |||
@@ -268,3 +269,46 @@ func GetFeedType(name string, req *http.Request) (bool, string, string) { | |||
return false, name, "" | |||
} | |||
// feedActionsToFeedItems convert gitea's Repo's Releases to feeds Item | |||
func releasesToFeedItems(ctx *context.Context, releases []*repo_model.Release, isReleasesOnly bool) (items []*feeds.Item, err error) { | |||
for _, rel := range releases { | |||
err := rel.LoadAttributes(ctx) | |||
if err != nil { | |||
return nil, err | |||
} | |||
var title, content string | |||
if rel.IsTag { | |||
title = rel.TagName | |||
} else { | |||
title = rel.Title | |||
} | |||
link := &feeds.Link{Href: rel.HTMLURL()} | |||
content, err = markdown.RenderString(&markup.RenderContext{ | |||
Ctx: ctx, | |||
URLPrefix: rel.Repo.Link(), | |||
Metas: rel.Repo.ComposeMetas(), | |||
}, rel.Note) | |||
if err != nil { | |||
return nil, err | |||
} | |||
items = append(items, &feeds.Item{ | |||
Title: title, | |||
Link: link, | |||
Created: rel.CreatedUnix.AsTime(), | |||
Author: &feeds.Author{ | |||
Name: rel.Publisher.DisplayName(), | |||
Email: rel.Publisher.GetEmail(), | |||
}, | |||
Id: fmt.Sprintf("%v: %v", strconv.FormatInt(rel.ID, 10), link.Href), | |||
Content: content, | |||
}) | |||
} | |||
return items, err | |||
} |
@@ -0,0 +1,50 @@ | |||
// Copyright 2022 The Gitea Authors. All rights reserved. | |||
// SPDX-License-Identifier: MIT | |||
package feed | |||
import ( | |||
"time" | |||
repo_model "code.gitea.io/gitea/models/repo" | |||
"code.gitea.io/gitea/modules/context" | |||
"github.com/gorilla/feeds" | |||
) | |||
// shows tags and/or releases on the repo as RSS / Atom feed | |||
func ShowReleaseFeed(ctx *context.Context, repo *repo_model.Repository, isReleasesOnly bool, formatType string) { | |||
releases, err := repo_model.GetReleasesByRepoID(ctx, ctx.Repo.Repository.ID, repo_model.FindReleasesOptions{ | |||
IncludeTags: !isReleasesOnly, | |||
}) | |||
if err != nil { | |||
ctx.ServerError("GetReleasesByRepoID", err) | |||
return | |||
} | |||
var title string | |||
var link *feeds.Link | |||
if isReleasesOnly { | |||
title = ctx.Tr("repo.release.releases_for", repo.FullName()) | |||
link = &feeds.Link{Href: repo.HTMLURL() + "/release"} | |||
} else { | |||
title = ctx.Tr("repo.release.tags_for", repo.FullName()) | |||
link = &feeds.Link{Href: repo.HTMLURL() + "/tags"} | |||
} | |||
feed := &feeds.Feed{ | |||
Title: title, | |||
Link: link, | |||
Description: repo.Description, | |||
Created: time.Now(), | |||
} | |||
feed.Items, err = releasesToFeedItems(ctx, releases, isReleasesOnly) | |||
if err != nil { | |||
ctx.ServerError("releasesToFeedItems", err) | |||
return | |||
} | |||
writeFeed(ctx, feed, formatType) | |||
} |
@@ -23,6 +23,7 @@ import ( | |||
"code.gitea.io/gitea/modules/upload" | |||
"code.gitea.io/gitea/modules/util" | |||
"code.gitea.io/gitea/modules/web" | |||
"code.gitea.io/gitea/routers/web/feed" | |||
"code.gitea.io/gitea/services/forms" | |||
releaseservice "code.gitea.io/gitea/services/release" | |||
) | |||
@@ -199,6 +200,30 @@ func releasesOrTags(ctx *context.Context, isTagList bool) { | |||
ctx.HTML(http.StatusOK, tplReleases) | |||
} | |||
// ReleasesFeedRSS get feeds for releases in RSS format | |||
func ReleasesFeedRSS(ctx *context.Context) { | |||
releasesOrTagsFeed(ctx, true, "rss") | |||
} | |||
// TagsListFeedRSS get feeds for tags in RSS format | |||
func TagsListFeedRSS(ctx *context.Context) { | |||
releasesOrTagsFeed(ctx, false, "rss") | |||
} | |||
// ReleasesFeedAtom get feeds for releases in Atom format | |||
func ReleasesFeedAtom(ctx *context.Context) { | |||
releasesOrTagsFeed(ctx, true, "atom") | |||
} | |||
// TagsListFeedAtom get feeds for tags in RSS format | |||
func TagsListFeedAtom(ctx *context.Context) { | |||
releasesOrTagsFeed(ctx, false, "atom") | |||
} | |||
func releasesOrTagsFeed(ctx *context.Context, isReleasesOnly bool, formatType string) { | |||
feed.ShowReleaseFeed(ctx, ctx.Repo.Repository, isReleasesOnly, formatType) | |||
} | |||
// SingleRelease renders a single release's page | |||
func SingleRelease(ctx *context.Context) { | |||
ctx.Data["Title"] = ctx.Tr("repo.release.releases") |
@@ -1087,12 +1087,21 @@ func RegisterRoutes(m *web.Route) { | |||
// Releases | |||
m.Group("/{username}/{reponame}", func() { | |||
m.Get("/tags", repo.TagsList, repo.MustBeNotEmpty, | |||
reqRepoCodeReader, context.RepoRefByType(context.RepoRefTag)) | |||
m.Group("/tags", func() { | |||
m.Get("", repo.TagsList) | |||
m.Get(".rss", feedEnabled, repo.TagsListFeedRSS) | |||
m.Get(".atom", feedEnabled, repo.TagsListFeedAtom) | |||
}, func(ctx *context.Context) { | |||
ctx.Data["EnableFeed"] = setting.EnableFeed | |||
}, repo.MustBeNotEmpty, reqRepoCodeReader, context.RepoRefByType(context.RepoRefTag, true)) | |||
m.Group("/releases", func() { | |||
m.Get("/", repo.Releases) | |||
m.Get("/tag/*", repo.SingleRelease) | |||
m.Get("/latest", repo.LatestRelease) | |||
m.Get(".rss", feedEnabled, repo.ReleasesFeedRSS) | |||
m.Get(".atom", feedEnabled, repo.ReleasesFeedAtom) | |||
}, func(ctx *context.Context) { | |||
ctx.Data["EnableFeed"] = setting.EnableFeed | |||
}, repo.MustBeNotEmpty, reqRepoReleaseReader, context.RepoRefByType(context.RepoRefTag, true)) | |||
m.Get("/releases/attachments/{uuid}", repo.GetAttachment, repo.MustBeNotEmpty, reqRepoReleaseReader) | |||
m.Group("/releases", func() { |
@@ -11,6 +11,9 @@ | |||
<a class="{{if .PageIsTagList}}active {{end}}item" href="{{.RepoLink}}/tags">{{.locale.Tr "repo.release.tags"}}</a> | |||
{{end}} | |||
</h2> | |||
{{if .EnableFeed}} | |||
<a href="{{.RepoLink}}/{{if .PageIsTagList}}tags{{else}}releases{{end}}.rss"><i class="ui grey icon tooltip ml-3" data-content="{{.locale.Tr "rss_feed"}}" data-position="top center">{{svg "octicon-rss" 18}}</i></a> | |||
{{end}} | |||
{{if (and .CanCreateRelease (not .PageIsTagList))}} | |||
<a class="ui right small green button" href="{{$.RepoLink}}/releases/new"> | |||
{{.locale.Tr "repo.release.new_release"}} |