diff --git a/models/actions/run.go b/models/actions/run.go
index 8078613fb8f5b..cfb36eeb75352 100644
--- a/models/actions/run.go
+++ b/models/actions/run.go
@@ -335,6 +335,21 @@ func GetRunByIndex(ctx context.Context, repoID, index int64) (*ActionRun, error)
return run, nil
}
+func GetRepoBranchLastRun(ctx context.Context, repoID int64, branch, workflowFile string) (*ActionRun, error) {
+ var run ActionRun
+ has, err := db.GetEngine(ctx).Where("repo_id=?", repoID).
+ And("ref = ?", branch).
+ And("workflow_id = ?", workflowFile).
+ Desc("id").
+ Get(&run)
+ if err != nil {
+ return nil, err
+ } else if !has {
+ return nil, util.NewNotExistErrorf("run with repo_id %d, ref %s, workflow_id %s", repoID, branch, workflowFile)
+ }
+ return &run, nil
+}
+
// UpdateRun updates a run.
// It requires the inputted run has Version set.
// It will return error if the version is not matched (it means the run has been changed after loaded).
diff --git a/public/assets/img/svg/gitea_actions_failed.svg b/public/assets/img/svg/gitea_actions_failed.svg
new file mode 100644
index 0000000000000..f862e6935ecf8
--- /dev/null
+++ b/public/assets/img/svg/gitea_actions_failed.svg
@@ -0,0 +1,20 @@
+
\ No newline at end of file
diff --git a/public/assets/img/svg/gitea_actions_pass.svg b/public/assets/img/svg/gitea_actions_pass.svg
new file mode 100644
index 0000000000000..cf9f0154f4deb
--- /dev/null
+++ b/public/assets/img/svg/gitea_actions_pass.svg
@@ -0,0 +1,20 @@
+
\ No newline at end of file
diff --git a/public/assets/img/svg/gitea_actions_pending.svg b/public/assets/img/svg/gitea_actions_pending.svg
new file mode 100644
index 0000000000000..1fdadfedfb3de
--- /dev/null
+++ b/public/assets/img/svg/gitea_actions_pending.svg
@@ -0,0 +1,20 @@
+
\ No newline at end of file
diff --git a/routers/web/repo/actions/badge.go b/routers/web/repo/actions/badge.go
new file mode 100644
index 0000000000000..a9bca5209b0a1
--- /dev/null
+++ b/routers/web/repo/actions/badge.go
@@ -0,0 +1,48 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package actions
+
+import (
+ "errors"
+ "fmt"
+ "strings"
+
+ actions_model "code.gitea.io/gitea/models/actions"
+ "code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/util"
+)
+
+func GetWorkflowBadge(ctx *context.Context) {
+ workflowFile := ctx.PathParamRaw("*")
+ if !strings.HasSuffix(workflowFile, "/badge.svg") {
+ ctx.NotFound("Not found", fmt.Errorf("%s not a badge request", ctx.Req.URL.Path))
+ return
+ }
+
+ workflowFile = strings.TrimSuffix(workflowFile, "/badge.svg")
+ run, err := actions_model.GetRepoBranchLastRun(ctx, ctx.Repo.Repository.ID,
+ git.RefNameFromBranch(ctx.Repo.Repository.DefaultBranch).String(),
+ workflowFile)
+ if err != nil {
+ if errors.Is(err, util.ErrNotExist) {
+ ctx.NotFound("Not found", fmt.Errorf("%s not found", workflowFile))
+ return
+ }
+ ctx.ServerError("GetWorkflowBadge", err)
+ return
+ }
+
+ switch run.Status {
+ case actions_model.StatusSuccess, actions_model.StatusSkipped:
+ ctx.Redirect(setting.AbsoluteAssetURL + "/assets/img/svg/gitea_actions_pass.svg")
+ case actions_model.StatusUnknown, actions_model.StatusFailure, actions_model.StatusCancelled:
+ ctx.Redirect(setting.AbsoluteAssetURL + "/assets/img/svg/gitea_actions_failed.svg")
+ case actions_model.StatusWaiting, actions_model.StatusRunning, actions_model.StatusBlocked:
+ ctx.Redirect(setting.AbsoluteAssetURL + "/assets/img/svg/gitea_actions_pending.svg")
+ default:
+ ctx.NotFound("Not found", fmt.Errorf("unknown status %d", run.Status))
+ }
+}
diff --git a/routers/web/web.go b/routers/web/web.go
index 99862505b48a1..d71716b159991 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -1330,6 +1330,9 @@ func registerRoutes(m *web.Route) {
m.Get("/artifacts/{artifact_name}", actions.ArtifactsDownloadView)
m.Post("/rerun", reqRepoActionsWriter, actions.Rerun)
})
+ m.Group("/workflows", func() {
+ m.Get("/*", actions.GetWorkflowBadge)
+ })
}, reqRepoActionsReader, actions.MustEnableActions)
m.Group("/wiki", func() {