forked from go-gitea/gitea
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement actions badge svgs (go-gitea#28102)
replace go-gitea#27187 close go-gitea#23688 The badge has two parts: label(workflow name) and message(action status). 5 colors are provided with 7 statuses. Color mapping: ```go var statusColorMap = map[actions_model.Status]string{ actions_model.StatusSuccess: "#4c1", // Green actions_model.StatusSkipped: "#dfb317", // Yellow actions_model.StatusUnknown: "#97ca00", // Light Green actions_model.StatusFailure: "#e05d44", // Red actions_model.StatusCancelled: "#fe7d37", // Orange actions_model.StatusWaiting: "#dfb317", // Yellow actions_model.StatusRunning: "#dfb317", // Yellow actions_model.StatusBlocked: "#dfb317", // Yellow } ``` preview: ![1](https://github.com/go-gitea/gitea/assets/70063547/5465cbaf-23cd-4437-9848-2738c3cb8985) ![2](https://github.com/go-gitea/gitea/assets/70063547/ec393d26-c6e6-4d38-b72c-51f2494c5e71) ![3](https://github.com/go-gitea/gitea/assets/70063547/3edb4fdf-1b08-4a02-ab2a-6bdd7f532fb2) ![4](https://github.com/go-gitea/gitea/assets/70063547/8c189de2-2169-4251-b115-0e39a52f3df8) ![5](https://github.com/go-gitea/gitea/assets/70063547/3fe22c73-c2d7-4fec-9ea4-c501a1e4e3bd) --------- Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Co-authored-by: Giteabot <teabot@gitea.io> Co-authored-by: delvh <dev.lh@web.de>
- Loading branch information
1 parent
e9f4c2d
commit db545b2
Showing
6 changed files
with
242 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
--- | ||
date: "2023-02-25T00:00:00+00:00" | ||
title: "Badge" | ||
slug: "badge" | ||
sidebar_position: 11 | ||
toc: false | ||
draft: false | ||
aliases: | ||
- /en-us/badge | ||
menu: | ||
sidebar: | ||
parent: "usage" | ||
name: "Badge" | ||
sidebar_position: 11 | ||
identifier: "Badge" | ||
--- | ||
|
||
# Badge | ||
|
||
Gitea has its builtin Badge system which allows you to display the status of your repository in other places. You can use the following badges: | ||
|
||
## Workflow Badge | ||
|
||
The Gitea Actions workflow badge is a badge that shows the status of the latest workflow run. | ||
It is designed to be compatible with [GitHub Actions workflow badge](https://docs.github.com/en/actions/monitoring-and-troubleshooting-workflows/adding-a-workflow-status-badge). | ||
|
||
You can use the following URL to get the badge: | ||
|
||
``` | ||
https://your-gitea-instance.com/{owner}/{repo}/actions/workflows/{workflow_file}?branch={branch}&event={event} | ||
``` | ||
|
||
- `{owner}`: The owner of the repository. | ||
- `{repo}`: The name of the repository. | ||
- `{workflow_file}`: The name of the workflow file. | ||
- `{branch}`: Optional. The branch of the workflow. Default to your repository's default branch. | ||
- `{event}`: Optional. The event of the workflow. Default to none. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
// Copyright 2024 The Gitea Authors. All rights reserved. | ||
// SPDX-License-Identifier: MIT | ||
|
||
package badge | ||
|
||
import ( | ||
actions_model "code.gitea.io/gitea/models/actions" | ||
) | ||
|
||
// The Badge layout: |offset|label|message| | ||
// We use 10x scale to calculate more precisely | ||
// Then scale down to normal size in tmpl file | ||
|
||
type Label struct { | ||
text string | ||
width int | ||
} | ||
|
||
func (l Label) Text() string { | ||
return l.text | ||
} | ||
|
||
func (l Label) Width() int { | ||
return l.width | ||
} | ||
|
||
func (l Label) TextLength() int { | ||
return int(float64(l.width-defaultOffset) * 9.5) | ||
} | ||
|
||
func (l Label) X() int { | ||
return l.width*5 + 10 | ||
} | ||
|
||
type Message struct { | ||
text string | ||
width int | ||
x int | ||
} | ||
|
||
func (m Message) Text() string { | ||
return m.text | ||
} | ||
|
||
func (m Message) Width() int { | ||
return m.width | ||
} | ||
|
||
func (m Message) X() int { | ||
return m.x | ||
} | ||
|
||
func (m Message) TextLength() int { | ||
return int(float64(m.width-defaultOffset) * 9.5) | ||
} | ||
|
||
type Badge struct { | ||
Color string | ||
FontSize int | ||
Label Label | ||
Message Message | ||
} | ||
|
||
func (b Badge) Width() int { | ||
return b.Label.width + b.Message.width | ||
} | ||
|
||
const ( | ||
defaultOffset = 9 | ||
defaultFontSize = 11 | ||
DefaultColor = "#9f9f9f" // Grey | ||
defaultFontWidth = 7 // approximate speculation | ||
) | ||
|
||
var StatusColorMap = map[actions_model.Status]string{ | ||
actions_model.StatusSuccess: "#4c1", // Green | ||
actions_model.StatusSkipped: "#dfb317", // Yellow | ||
actions_model.StatusUnknown: "#97ca00", // Light Green | ||
actions_model.StatusFailure: "#e05d44", // Red | ||
actions_model.StatusCancelled: "#fe7d37", // Orange | ||
actions_model.StatusWaiting: "#dfb317", // Yellow | ||
actions_model.StatusRunning: "#dfb317", // Yellow | ||
actions_model.StatusBlocked: "#dfb317", // Yellow | ||
} | ||
|
||
// GenerateBadge generates badge with given template | ||
func GenerateBadge(label, message, color string) Badge { | ||
lw := defaultFontWidth*len(label) + defaultOffset | ||
mw := defaultFontWidth*len(message) + defaultOffset | ||
x := lw*10 + mw*5 - 10 | ||
return Badge{ | ||
Label: Label{ | ||
text: label, | ||
width: lw, | ||
}, | ||
Message: Message{ | ||
text: message, | ||
width: mw, | ||
x: x, | ||
}, | ||
FontSize: defaultFontSize * 10, | ||
Color: color, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
// Copyright 2024 The Gitea Authors. All rights reserved. | ||
// SPDX-License-Identifier: MIT | ||
|
||
package actions | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"net/http" | ||
"path/filepath" | ||
"strings" | ||
|
||
actions_model "code.gitea.io/gitea/models/actions" | ||
"code.gitea.io/gitea/modules/badge" | ||
"code.gitea.io/gitea/modules/util" | ||
"code.gitea.io/gitea/services/context" | ||
) | ||
|
||
func GetWorkflowBadge(ctx *context.Context) { | ||
workflowFile := ctx.Params("workflow_name") | ||
branch := ctx.Req.URL.Query().Get("branch") | ||
if branch == "" { | ||
branch = ctx.Repo.Repository.DefaultBranch | ||
} | ||
branchRef := fmt.Sprintf("refs/heads/%s", branch) | ||
event := ctx.Req.URL.Query().Get("event") | ||
|
||
badge, err := getWorkflowBadge(ctx, workflowFile, branchRef, event) | ||
if err != nil { | ||
ctx.ServerError("GetWorkflowBadge", err) | ||
return | ||
} | ||
|
||
ctx.Data["Badge"] = badge | ||
ctx.RespHeader().Set("Content-Type", "image/svg+xml") | ||
ctx.HTML(http.StatusOK, "shared/actions/runner_badge") | ||
} | ||
|
||
func getWorkflowBadge(ctx *context.Context, workflowFile, branchName, event string) (badge.Badge, error) { | ||
extension := filepath.Ext(workflowFile) | ||
workflowName := strings.TrimSuffix(workflowFile, extension) | ||
|
||
run, err := actions_model.GetWorkflowLatestRun(ctx, ctx.Repo.Repository.ID, workflowFile, branchName, event) | ||
if err != nil { | ||
if errors.Is(err, util.ErrNotExist) { | ||
return badge.GenerateBadge(workflowName, "no status", badge.DefaultColor), nil | ||
} | ||
return badge.Badge{}, err | ||
} | ||
|
||
color, ok := badge.StatusColorMap[run.Status] | ||
if !ok { | ||
return badge.GenerateBadge(workflowName, "unknown status", badge.DefaultColor), nil | ||
} | ||
return badge.GenerateBadge(workflowName, run.Status.String(), color), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{{.Badge.Width}}" height="18" | ||
role="img" aria-label="{{.Badge.Label.Text}}: {{.Badge.Message.Text}}"> | ||
<title>{{.Badge.Label.Text}}: {{.Badge.Message.Text}}</title> | ||
<linearGradient id="s" x2="0" y2="100%"> | ||
<stop offset="0" stop-color="#fff" stop-opacity=".7" /> | ||
<stop offset=".1" stop-color="#aaa" stop-opacity=".1" /> | ||
<stop offset=".9" stop-color="#000" stop-opacity=".3" /> | ||
<stop offset="1" stop-color="#000" stop-opacity=".5" /> | ||
</linearGradient> | ||
<clipPath id="r"> | ||
<rect width="{{.Badge.Width}}" height="18" rx="4" fill="#fff" /> | ||
</clipPath> | ||
<g clip-path="url(#r)"> | ||
<rect width="{{.Badge.Label.Width}}" height="18" fill="#555" /> | ||
<rect x="{{.Badge.Label.Width}}" width="{{.Badge.Message.Width}}" height="18" fill="{{.Badge.Color}}" /> | ||
<rect width="{{.Badge.Width}}" height="18" fill="url(#s)" /> | ||
</g> | ||
<g fill="#fff" text-anchor="middle" font-family="Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" | ||
font-size="{{.Badge.FontSize}}"><text aria-hidden="true" x="{{.Badge.Label.X}}" y="140" fill="#010101" fill-opacity=".3" | ||
transform="scale(.1)" textLength="{{.Badge.Label.TextLength}}">{{.Badge.Label.Text}}</text><text x="{{.Badge.Label.X}}" y="130" | ||
transform="scale(.1)" fill="#fff" textLength="{{.Badge.Label.TextLength}}">{{.Badge.Label.Text}}</text><text aria-hidden="true" | ||
x="{{.Badge.Message.X}}" y="140" fill="#010101" fill-opacity=".3" transform="scale(.1)" | ||
textLength="{{.Badge.Message.TextLength}}">{{.Badge.Message.Text}}</text><text x="{{.Badge.Message.X}}" y="130" transform="scale(.1)" | ||
fill="#fff" textLength="{{.Badge.Message.TextLength}}">{{.Badge.Message.Text}}</text></g> | ||
</svg> |