[GITEA] Add support for shields.io-based badges
Adds a new `/{username}/{repo}/badges` family of routes, which redirect
to various shields.io badges. The goal is to not reimplement badge
generation, and delegate it to shields.io (or a similar service), which
are already used by many. This way, we get all the goodies that come
with it: different styles, colors, logos, you name it.
So these routes are just thin wrappers around shields.io that make it
easier to display the information we want. The URL is configurable via
`app.ini`, and is templatable, allowing to use alternative badge
generator services with slightly different URL patterns.
Additionally, for compatibility with GitHub, there's an
`/{username}/{repo}/actions/workflows/{workflow_file}/badge.svg` route
that works much the same way as on GitHub. Change the hostname in the
URL, and done.
Fixes gitea#5633, gitea#23688, and also fixes #126.
Work sponsored by Codeberg e.V.
Signed-off-by: Gergely Nagy <forgejo@gergo.csillger.hu>
(cherry picked from commit fcd0f61212d8febd4bdfc27e61a4e13cbdd16d49)
(cherry picked from commit 20d14f784490a880c51ca0f0a6a5988a01887635)
(cherry picked from commit 4359741431bb39de4cf24de8b0cfb513f5233f55)
(cherry picked from commit 35cff45eb86177e750cd22e82a201880a5efe045)
(cherry picked from commit 2fc0d0b8a302d24177a00ab48b42ce083b52e506)
2024-01-01 07:38:49 -05:00
|
|
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
|
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
|
|
|
|
package integration
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net/http"
|
|
|
|
"net/http/httptest"
|
|
|
|
"net/url"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
actions_model "code.gitea.io/gitea/models/actions"
|
2024-03-20 17:41:20 -04:00
|
|
|
auth_model "code.gitea.io/gitea/models/auth"
|
[GITEA] Add support for shields.io-based badges
Adds a new `/{username}/{repo}/badges` family of routes, which redirect
to various shields.io badges. The goal is to not reimplement badge
generation, and delegate it to shields.io (or a similar service), which
are already used by many. This way, we get all the goodies that come
with it: different styles, colors, logos, you name it.
So these routes are just thin wrappers around shields.io that make it
easier to display the information we want. The URL is configurable via
`app.ini`, and is templatable, allowing to use alternative badge
generator services with slightly different URL patterns.
Additionally, for compatibility with GitHub, there's an
`/{username}/{repo}/actions/workflows/{workflow_file}/badge.svg` route
that works much the same way as on GitHub. Change the hostname in the
URL, and done.
Fixes gitea#5633, gitea#23688, and also fixes #126.
Work sponsored by Codeberg e.V.
Signed-off-by: Gergely Nagy <forgejo@gergo.csillger.hu>
(cherry picked from commit fcd0f61212d8febd4bdfc27e61a4e13cbdd16d49)
(cherry picked from commit 20d14f784490a880c51ca0f0a6a5988a01887635)
(cherry picked from commit 4359741431bb39de4cf24de8b0cfb513f5233f55)
(cherry picked from commit 35cff45eb86177e750cd22e82a201880a5efe045)
(cherry picked from commit 2fc0d0b8a302d24177a00ab48b42ce083b52e506)
2024-01-01 07:38:49 -05:00
|
|
|
repo_model "code.gitea.io/gitea/models/repo"
|
|
|
|
unit_model "code.gitea.io/gitea/models/unit"
|
|
|
|
"code.gitea.io/gitea/models/unittest"
|
|
|
|
user_model "code.gitea.io/gitea/models/user"
|
2024-03-20 17:41:20 -04:00
|
|
|
"code.gitea.io/gitea/modules/git"
|
2024-02-26 03:22:51 -05:00
|
|
|
"code.gitea.io/gitea/modules/setting"
|
[GITEA] Add support for shields.io-based badges
Adds a new `/{username}/{repo}/badges` family of routes, which redirect
to various shields.io badges. The goal is to not reimplement badge
generation, and delegate it to shields.io (or a similar service), which
are already used by many. This way, we get all the goodies that come
with it: different styles, colors, logos, you name it.
So these routes are just thin wrappers around shields.io that make it
easier to display the information we want. The URL is configurable via
`app.ini`, and is templatable, allowing to use alternative badge
generator services with slightly different URL patterns.
Additionally, for compatibility with GitHub, there's an
`/{username}/{repo}/actions/workflows/{workflow_file}/badge.svg` route
that works much the same way as on GitHub. Change the hostname in the
URL, and done.
Fixes gitea#5633, gitea#23688, and also fixes #126.
Work sponsored by Codeberg e.V.
Signed-off-by: Gergely Nagy <forgejo@gergo.csillger.hu>
(cherry picked from commit fcd0f61212d8febd4bdfc27e61a4e13cbdd16d49)
(cherry picked from commit 20d14f784490a880c51ca0f0a6a5988a01887635)
(cherry picked from commit 4359741431bb39de4cf24de8b0cfb513f5233f55)
(cherry picked from commit 35cff45eb86177e750cd22e82a201880a5efe045)
(cherry picked from commit 2fc0d0b8a302d24177a00ab48b42ce083b52e506)
2024-01-01 07:38:49 -05:00
|
|
|
"code.gitea.io/gitea/modules/test"
|
2024-02-26 03:22:51 -05:00
|
|
|
"code.gitea.io/gitea/routers"
|
2024-03-20 17:41:20 -04:00
|
|
|
"code.gitea.io/gitea/services/release"
|
[GITEA] Add support for shields.io-based badges
Adds a new `/{username}/{repo}/badges` family of routes, which redirect
to various shields.io badges. The goal is to not reimplement badge
generation, and delegate it to shields.io (or a similar service), which
are already used by many. This way, we get all the goodies that come
with it: different styles, colors, logos, you name it.
So these routes are just thin wrappers around shields.io that make it
easier to display the information we want. The URL is configurable via
`app.ini`, and is templatable, allowing to use alternative badge
generator services with slightly different URL patterns.
Additionally, for compatibility with GitHub, there's an
`/{username}/{repo}/actions/workflows/{workflow_file}/badge.svg` route
that works much the same way as on GitHub. Change the hostname in the
URL, and done.
Fixes gitea#5633, gitea#23688, and also fixes #126.
Work sponsored by Codeberg e.V.
Signed-off-by: Gergely Nagy <forgejo@gergo.csillger.hu>
(cherry picked from commit fcd0f61212d8febd4bdfc27e61a4e13cbdd16d49)
(cherry picked from commit 20d14f784490a880c51ca0f0a6a5988a01887635)
(cherry picked from commit 4359741431bb39de4cf24de8b0cfb513f5233f55)
(cherry picked from commit 35cff45eb86177e750cd22e82a201880a5efe045)
(cherry picked from commit 2fc0d0b8a302d24177a00ab48b42ce083b52e506)
2024-01-01 07:38:49 -05:00
|
|
|
files_service "code.gitea.io/gitea/services/repository/files"
|
|
|
|
"code.gitea.io/gitea/tests"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestBadges(t *testing.T) {
|
2024-01-12 05:50:29 -05:00
|
|
|
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
|
|
|
prep := func(t *testing.T) (*repo_model.Repository, func()) {
|
|
|
|
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
|
|
|
|
|
|
|
repo, _, f := CreateDeclarativeRepo(t, owner, "",
|
|
|
|
[]unit_model.Type{unit_model.TypeActions},
|
|
|
|
[]unit_model.Type{unit_model.TypeIssues, unit_model.TypePullRequests, unit_model.TypeReleases},
|
|
|
|
[]*files_service.ChangeRepoFile{
|
|
|
|
{
|
|
|
|
Operation: "create",
|
|
|
|
TreePath: ".gitea/workflows/pr.yml",
|
|
|
|
ContentReader: strings.NewReader("name: test\non:\n push:\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - run: echo helloworld\n"),
|
|
|
|
},
|
2024-03-20 17:41:20 -04:00
|
|
|
{
|
|
|
|
Operation: "create",
|
|
|
|
TreePath: ".gitea/workflows/self-test.yaml",
|
|
|
|
ContentReader: strings.NewReader("name: test\non:\n push:\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - run: echo helloworld\n"),
|
|
|
|
},
|
2024-01-12 05:50:29 -05:00
|
|
|
},
|
|
|
|
)
|
2024-03-20 17:41:20 -04:00
|
|
|
assert.Equal(t, 2, unittest.GetCount(t, &actions_model.ActionRun{RepoID: repo.ID}))
|
2024-01-12 05:50:29 -05:00
|
|
|
|
|
|
|
return repo, f
|
|
|
|
}
|
|
|
|
|
|
|
|
assertBadge := func(t *testing.T, resp *httptest.ResponseRecorder, badge string) {
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
assert.Equal(t, fmt.Sprintf("https://img.shields.io/badge/%s", badge), test.RedirectURL(resp))
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("Workflows", func(t *testing.T) {
|
|
|
|
defer tests.PrintCurrentTest(t)()
|
|
|
|
repo, f := prep(t)
|
|
|
|
defer f()
|
|
|
|
|
|
|
|
// Actions disabled
|
|
|
|
req := NewRequest(t, "GET", "/user2/repo1/badges/workflows/test.yaml/badge.svg")
|
|
|
|
resp := MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
assertBadge(t, resp, "test.yaml-Not%20found-crimson")
|
|
|
|
|
|
|
|
req = NewRequest(t, "GET", "/user2/repo1/badges/workflows/test.yaml/badge.svg?branch=no-such-branch")
|
|
|
|
resp = MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
assertBadge(t, resp, "test.yaml-Not%20found-crimson")
|
|
|
|
|
|
|
|
// Actions enabled
|
|
|
|
req = NewRequestf(t, "GET", "/user2/%s/badges/workflows/pr.yml/badge.svg", repo.Name)
|
|
|
|
resp = MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
assertBadge(t, resp, "pr.yml-waiting-lightgrey")
|
|
|
|
|
|
|
|
req = NewRequestf(t, "GET", "/user2/%s/badges/workflows/pr.yml/badge.svg?branch=main", repo.Name)
|
|
|
|
resp = MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
assertBadge(t, resp, "pr.yml-waiting-lightgrey")
|
|
|
|
|
|
|
|
req = NewRequestf(t, "GET", "/user2/%s/badges/workflows/pr.yml/badge.svg?branch=no-such-branch", repo.Name)
|
|
|
|
resp = MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
assertBadge(t, resp, "pr.yml-Not%20found-crimson")
|
|
|
|
|
|
|
|
req = NewRequestf(t, "GET", "/user2/%s/badges/workflows/pr.yml/badge.svg?event=cron", repo.Name)
|
|
|
|
resp = MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
assertBadge(t, resp, "pr.yml-Not%20found-crimson")
|
|
|
|
|
2024-03-20 17:41:20 -04:00
|
|
|
// Workflow with a dash in its name
|
|
|
|
req = NewRequestf(t, "GET", "/user2/%s/badges/workflows/self-test.yaml/badge.svg", repo.Name)
|
|
|
|
resp = MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
assertBadge(t, resp, "self--test.yaml-waiting-lightgrey")
|
|
|
|
|
2024-01-12 05:50:29 -05:00
|
|
|
// GitHub compatibility
|
|
|
|
req = NewRequestf(t, "GET", "/user2/%s/actions/workflows/pr.yml/badge.svg", repo.Name)
|
|
|
|
resp = MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
assertBadge(t, resp, "pr.yml-waiting-lightgrey")
|
|
|
|
|
|
|
|
req = NewRequestf(t, "GET", "/user2/%s/actions/workflows/pr.yml/badge.svg?branch=main", repo.Name)
|
|
|
|
resp = MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
assertBadge(t, resp, "pr.yml-waiting-lightgrey")
|
|
|
|
|
|
|
|
req = NewRequestf(t, "GET", "/user2/%s/actions/workflows/pr.yml/badge.svg?branch=no-such-branch", repo.Name)
|
|
|
|
resp = MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
assertBadge(t, resp, "pr.yml-Not%20found-crimson")
|
|
|
|
|
|
|
|
req = NewRequestf(t, "GET", "/user2/%s/actions/workflows/pr.yml/badge.svg?event=cron", repo.Name)
|
|
|
|
resp = MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
assertBadge(t, resp, "pr.yml-Not%20found-crimson")
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("Stars", func(t *testing.T) {
|
|
|
|
defer tests.PrintCurrentTest(t)()
|
|
|
|
|
|
|
|
req := NewRequest(t, "GET", "/user2/repo1/badges/stars.svg")
|
|
|
|
resp := MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
|
|
|
|
assertBadge(t, resp, "stars-0-blue")
|
2024-02-26 03:22:51 -05:00
|
|
|
|
|
|
|
t.Run("disabled stars", func(t *testing.T) {
|
|
|
|
defer tests.PrintCurrentTest(t)()
|
|
|
|
defer test.MockVariableValue(&setting.Repository.DisableStars, true)()
|
|
|
|
defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())()
|
|
|
|
|
|
|
|
MakeRequest(t, req, http.StatusNotFound)
|
|
|
|
})
|
2024-01-12 05:50:29 -05:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("Issues", func(t *testing.T) {
|
|
|
|
defer tests.PrintCurrentTest(t)()
|
|
|
|
repo, f := prep(t)
|
|
|
|
defer f()
|
|
|
|
|
|
|
|
// Issues enabled
|
|
|
|
req := NewRequest(t, "GET", "/user2/repo1/badges/issues.svg")
|
|
|
|
resp := MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
assertBadge(t, resp, "issues-2-blue")
|
|
|
|
|
|
|
|
req = NewRequest(t, "GET", "/user2/repo1/badges/issues/open.svg")
|
|
|
|
resp = MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
assertBadge(t, resp, "issues-1%20open-blue")
|
|
|
|
|
|
|
|
req = NewRequest(t, "GET", "/user2/repo1/badges/issues/closed.svg")
|
|
|
|
resp = MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
assertBadge(t, resp, "issues-1%20closed-blue")
|
|
|
|
|
|
|
|
// Issues disabled
|
|
|
|
req = NewRequestf(t, "GET", "/user2/%s/badges/issues.svg", repo.Name)
|
|
|
|
resp = MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
assertBadge(t, resp, "issues-Not%20found-crimson")
|
|
|
|
|
|
|
|
req = NewRequestf(t, "GET", "/user2/%s/badges/issues/open.svg", repo.Name)
|
|
|
|
resp = MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
assertBadge(t, resp, "issues-Not%20found-crimson")
|
|
|
|
|
|
|
|
req = NewRequestf(t, "GET", "/user2/%s/badges/issues/closed.svg", repo.Name)
|
|
|
|
resp = MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
assertBadge(t, resp, "issues-Not%20found-crimson")
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("Pulls", func(t *testing.T) {
|
|
|
|
defer tests.PrintCurrentTest(t)()
|
|
|
|
repo, f := prep(t)
|
|
|
|
defer f()
|
|
|
|
|
|
|
|
// Pull requests enabled
|
|
|
|
req := NewRequest(t, "GET", "/user2/repo1/badges/pulls.svg")
|
|
|
|
resp := MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
assertBadge(t, resp, "pulls-3-blue")
|
|
|
|
|
|
|
|
req = NewRequest(t, "GET", "/user2/repo1/badges/pulls/open.svg")
|
|
|
|
resp = MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
assertBadge(t, resp, "pulls-3%20open-blue")
|
|
|
|
|
|
|
|
req = NewRequest(t, "GET", "/user2/repo1/badges/pulls/closed.svg")
|
|
|
|
resp = MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
assertBadge(t, resp, "pulls-0%20closed-blue")
|
|
|
|
|
|
|
|
// Pull requests disabled
|
|
|
|
req = NewRequestf(t, "GET", "/user2/%s/badges/pulls.svg", repo.Name)
|
|
|
|
resp = MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
assertBadge(t, resp, "pulls-Not%20found-crimson")
|
|
|
|
|
|
|
|
req = NewRequestf(t, "GET", "/user2/%s/badges/pulls/open.svg", repo.Name)
|
|
|
|
resp = MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
assertBadge(t, resp, "pulls-Not%20found-crimson")
|
|
|
|
|
|
|
|
req = NewRequestf(t, "GET", "/user2/%s/badges/pulls/closed.svg", repo.Name)
|
|
|
|
resp = MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
assertBadge(t, resp, "pulls-Not%20found-crimson")
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("Release", func(t *testing.T) {
|
|
|
|
defer tests.PrintCurrentTest(t)()
|
|
|
|
repo, f := prep(t)
|
|
|
|
defer f()
|
|
|
|
|
|
|
|
req := NewRequest(t, "GET", "/user2/repo1/badges/release.svg")
|
|
|
|
resp := MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
assertBadge(t, resp, "release-v1.1-blue")
|
|
|
|
|
|
|
|
req = NewRequestf(t, "GET", "/user2/%s/badges/release.svg", repo.Name)
|
|
|
|
resp = MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
assertBadge(t, resp, "release-Not%20found-crimson")
|
2024-03-20 17:41:20 -04:00
|
|
|
|
|
|
|
t.Run("Dashes in the name", func(t *testing.T) {
|
|
|
|
defer tests.PrintCurrentTest(t)()
|
|
|
|
|
|
|
|
session := loginUser(t, repo.Owner.Name)
|
|
|
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
|
|
|
|
err := release.CreateNewTag(git.DefaultContext, repo.Owner, repo, "main", "repo-name-2.0", "dash in the tag name")
|
|
|
|
assert.NoError(t, err)
|
2024-04-29 04:47:56 -04:00
|
|
|
createNewReleaseUsingAPI(t, token, repo.Owner, repo, "repo-name-2.0", "main", "dashed release", "dashed release")
|
2024-03-20 17:41:20 -04:00
|
|
|
|
|
|
|
req := NewRequestf(t, "GET", "/user2/%s/badges/release.svg", repo.Name)
|
|
|
|
resp := MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
assertBadge(t, resp, "release-repo--name--2.0-blue")
|
|
|
|
})
|
2024-01-12 05:50:29 -05:00
|
|
|
})
|
[GITEA] Add support for shields.io-based badges
Adds a new `/{username}/{repo}/badges` family of routes, which redirect
to various shields.io badges. The goal is to not reimplement badge
generation, and delegate it to shields.io (or a similar service), which
are already used by many. This way, we get all the goodies that come
with it: different styles, colors, logos, you name it.
So these routes are just thin wrappers around shields.io that make it
easier to display the information we want. The URL is configurable via
`app.ini`, and is templatable, allowing to use alternative badge
generator services with slightly different URL patterns.
Additionally, for compatibility with GitHub, there's an
`/{username}/{repo}/actions/workflows/{workflow_file}/badge.svg` route
that works much the same way as on GitHub. Change the hostname in the
URL, and done.
Fixes gitea#5633, gitea#23688, and also fixes #126.
Work sponsored by Codeberg e.V.
Signed-off-by: Gergely Nagy <forgejo@gergo.csillger.hu>
(cherry picked from commit fcd0f61212d8febd4bdfc27e61a4e13cbdd16d49)
(cherry picked from commit 20d14f784490a880c51ca0f0a6a5988a01887635)
(cherry picked from commit 4359741431bb39de4cf24de8b0cfb513f5233f55)
(cherry picked from commit 35cff45eb86177e750cd22e82a201880a5efe045)
(cherry picked from commit 2fc0d0b8a302d24177a00ab48b42ce083b52e506)
2024-01-01 07:38:49 -05:00
|
|
|
})
|
|
|
|
}
|