[GITEA] allow viewing the latest Action Run on the web
Similar to how some other parts of the web UI support a `/latest` path to directly go to the latest of a certain thing, let the Actions web UI do the same: `/{owner}/{repo}/actions/runs/latest` will redirect to the latest run, if there's one available. Fixes gitea#27991. Signed-off-by: Gergely Nagy <forgejo@gergo.csillger.hu> (cherry picked from commit f67ccef1dd3146b0b942a94e2482b37595180e91) Code cleanup in the actions.ViewLatest route handler Based on feedback received after the feature was merged, use `ctx.NotFound` and `ctx.ServerError`, and drop the use of the unnecessary `ctx.Written()`. Signed-off-by: Gergely Nagy <forgejo@gergo.csillger.hu> (cherry picked from commit 74e42da5630f9148faaf6b03bf1ac5724fa86b25) (cherry picked from commit f7535a1cef96ce0589f37907f88b024cd095d0ac) (cherry picked from commit 1a90cd37c31a1b9c770d6d79a4663ed8d67845c0) (cherry picked from commit d86d71340afd372e5b5083d5563c2f5b48d975e6) (cherry picked from commit 9e5cce1afccebcd6146e5e0d364bfdbb840b5276) (cherry picked from commit 2013fb3fab5e23d0088434d835411f26a3fd9905) (cherry picked from commit 88b9d21d1194abd133c3b4cbaa19792da433cb43) (cherry picked from commit 72c020298eebcb0c90e23e7ff35e37be867afc44) (cherry picked from commit 6525f730dfdd7cb412762d9e30348801335d17ee)
This commit is contained in:
parent
533c87da65
commit
fa0759962b
4 changed files with 130 additions and 11 deletions
|
@ -312,6 +312,17 @@ func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWork
|
||||||
return commiter.Commit()
|
return commiter.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetLatestRun(ctx context.Context, repoID int64) (*ActionRun, error) {
|
||||||
|
var run ActionRun
|
||||||
|
has, err := db.GetEngine(ctx).Where("repo_id=?", repoID).OrderBy("id DESC").Limit(1).Get(&run)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if !has {
|
||||||
|
return nil, fmt.Errorf("latest run: %w", util.ErrNotExist)
|
||||||
|
}
|
||||||
|
return &run, nil
|
||||||
|
}
|
||||||
|
|
||||||
func GetRunByID(ctx context.Context, id int64) (*ActionRun, error) {
|
func GetRunByID(ctx context.Context, id int64) (*ActionRun, error) {
|
||||||
var run ActionRun
|
var run ActionRun
|
||||||
has, err := db.GetEngine(ctx).Where("id=?", id).Get(&run)
|
has, err := db.GetEngine(ctx).Where("id=?", id).Get(&run)
|
||||||
|
|
|
@ -46,6 +46,20 @@ func View(ctx *context_module.Context) {
|
||||||
ctx.HTML(http.StatusOK, tplViewActions)
|
ctx.HTML(http.StatusOK, tplViewActions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ViewLatest(ctx *context_module.Context) {
|
||||||
|
run, err := actions_model.GetLatestRun(ctx, ctx.Repo.Repository.ID)
|
||||||
|
if err != nil {
|
||||||
|
ctx.NotFound("GetLatestRun", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = run.LoadAttributes(ctx)
|
||||||
|
if err != nil {
|
||||||
|
ctx.ServerError("LoadAttributes", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Redirect(run.HTMLURL(), http.StatusTemporaryRedirect)
|
||||||
|
}
|
||||||
|
|
||||||
type ViewRequest struct {
|
type ViewRequest struct {
|
||||||
LogCursors []struct {
|
LogCursors []struct {
|
||||||
Step int `json:"step"`
|
Step int `json:"step"`
|
||||||
|
|
|
@ -1347,7 +1347,9 @@ func registerRoutes(m *web.Route) {
|
||||||
m.Post("/disable", reqRepoAdmin, actions.DisableWorkflowFile)
|
m.Post("/disable", reqRepoAdmin, actions.DisableWorkflowFile)
|
||||||
m.Post("/enable", reqRepoAdmin, actions.EnableWorkflowFile)
|
m.Post("/enable", reqRepoAdmin, actions.EnableWorkflowFile)
|
||||||
|
|
||||||
m.Group("/runs/{run}", func() {
|
m.Group("/runs", func() {
|
||||||
|
m.Get("/latest", actions.ViewLatest)
|
||||||
|
m.Group("/{run}", func() {
|
||||||
m.Combo("").
|
m.Combo("").
|
||||||
Get(actions.View).
|
Get(actions.View).
|
||||||
Post(web.Bind(actions.ViewRequest{}), actions.ViewPost)
|
Post(web.Bind(actions.ViewRequest{}), actions.ViewPost)
|
||||||
|
@ -1364,6 +1366,7 @@ func registerRoutes(m *web.Route) {
|
||||||
m.Get("/artifacts/{artifact_name}", actions.ArtifactsDownloadView)
|
m.Get("/artifacts/{artifact_name}", actions.ArtifactsDownloadView)
|
||||||
m.Post("/rerun", reqRepoActionsWriter, actions.Rerun)
|
m.Post("/rerun", reqRepoActionsWriter, actions.Rerun)
|
||||||
})
|
})
|
||||||
|
})
|
||||||
}, reqRepoActionsReader, actions.MustEnableActions)
|
}, reqRepoActionsReader, actions.MustEnableActions)
|
||||||
|
|
||||||
m.Group("/wiki", func() {
|
m.Group("/wiki", func() {
|
||||||
|
|
91
tests/integration/actions_route_test.go
Normal file
91
tests/integration/actions_route_test.go
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
actions_model "code.gitea.io/gitea/models/actions"
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
|
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"
|
||||||
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
repo_service "code.gitea.io/gitea/services/repository"
|
||||||
|
files_service "code.gitea.io/gitea/services/repository/files"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestActionsWebRouteLatestRun(t *testing.T) {
|
||||||
|
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||||
|
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||||
|
|
||||||
|
// create the repo
|
||||||
|
repo, err := repo_service.CreateRepository(db.DefaultContext, user2, user2, repo_service.CreateRepoOptions{
|
||||||
|
Name: "actions-latest",
|
||||||
|
Description: "test /actions/runs/latest",
|
||||||
|
AutoInit: true,
|
||||||
|
Gitignores: "Go",
|
||||||
|
License: "MIT",
|
||||||
|
Readme: "Default",
|
||||||
|
DefaultBranch: "main",
|
||||||
|
IsPrivate: false,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotEmpty(t, repo)
|
||||||
|
|
||||||
|
// enable actions
|
||||||
|
err = repo_service.UpdateRepositoryUnits(db.DefaultContext, repo, []repo_model.RepoUnit{{
|
||||||
|
RepoID: repo.ID,
|
||||||
|
Type: unit_model.TypeActions,
|
||||||
|
}}, nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// add workflow file to the repo
|
||||||
|
addWorkflowToBaseResp, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{
|
||||||
|
Files: []*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"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Message: "add workflow",
|
||||||
|
OldBranch: "main",
|
||||||
|
NewBranch: "main",
|
||||||
|
Author: &files_service.IdentityOptions{
|
||||||
|
Name: user2.Name,
|
||||||
|
Email: user2.Email,
|
||||||
|
},
|
||||||
|
Committer: &files_service.IdentityOptions{
|
||||||
|
Name: user2.Name,
|
||||||
|
Email: user2.Email,
|
||||||
|
},
|
||||||
|
Dates: &files_service.CommitDateOptions{
|
||||||
|
Author: time.Now(),
|
||||||
|
Committer: time.Now(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotEmpty(t, addWorkflowToBaseResp)
|
||||||
|
|
||||||
|
// a run has been created
|
||||||
|
assert.Equal(t, 1, unittest.GetCount(t, &actions_model.ActionRun{RepoID: repo.ID}))
|
||||||
|
|
||||||
|
// Hit the `/actions/runs/latest` route
|
||||||
|
req := NewRequest(t, "GET", fmt.Sprintf("%s/actions/runs/latest", repo.HTMLURL()))
|
||||||
|
resp := MakeRequest(t, req, http.StatusTemporaryRedirect)
|
||||||
|
|
||||||
|
// Verify that it redirects to the run we just created
|
||||||
|
expectedURI := fmt.Sprintf("%s/actions/runs/1", repo.HTMLURL())
|
||||||
|
assert.Equal(t, expectedURI, resp.Header().Get("Location"))
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in a new issue