forked from NYANDEV/forgejo
[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)
This commit is contained in:
parent
2b22272dc5
commit
88b9d21d11
4 changed files with 130 additions and 11 deletions
|
@ -309,6 +309,17 @@ func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWork
|
|||
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) {
|
||||
var run ActionRun
|
||||
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)
|
||||
}
|
||||
|
||||
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 {
|
||||
LogCursors []struct {
|
||||
Step int `json:"step"`
|
||||
|
|
|
@ -1347,22 +1347,25 @@ func registerRoutes(m *web.Route) {
|
|||
m.Post("/disable", reqRepoAdmin, actions.DisableWorkflowFile)
|
||||
m.Post("/enable", reqRepoAdmin, actions.EnableWorkflowFile)
|
||||
|
||||
m.Group("/runs/{run}", func() {
|
||||
m.Combo("").
|
||||
Get(actions.View).
|
||||
Post(web.Bind(actions.ViewRequest{}), actions.ViewPost)
|
||||
m.Group("/jobs/{job}", func() {
|
||||
m.Group("/runs", func() {
|
||||
m.Get("/latest", actions.ViewLatest)
|
||||
m.Group("/{run}", func() {
|
||||
m.Combo("").
|
||||
Get(actions.View).
|
||||
Post(web.Bind(actions.ViewRequest{}), actions.ViewPost)
|
||||
m.Group("/jobs/{job}", func() {
|
||||
m.Combo("").
|
||||
Get(actions.View).
|
||||
Post(web.Bind(actions.ViewRequest{}), actions.ViewPost)
|
||||
m.Post("/rerun", reqRepoActionsWriter, actions.Rerun)
|
||||
m.Get("/logs", actions.Logs)
|
||||
})
|
||||
m.Post("/cancel", reqRepoActionsWriter, actions.Cancel)
|
||||
m.Post("/approve", reqRepoActionsWriter, actions.Approve)
|
||||
m.Post("/artifacts", actions.ArtifactsView)
|
||||
m.Get("/artifacts/{artifact_name}", actions.ArtifactsDownloadView)
|
||||
m.Post("/rerun", reqRepoActionsWriter, actions.Rerun)
|
||||
m.Get("/logs", actions.Logs)
|
||||
})
|
||||
m.Post("/cancel", reqRepoActionsWriter, actions.Cancel)
|
||||
m.Post("/approve", reqRepoActionsWriter, actions.Approve)
|
||||
m.Post("/artifacts", actions.ArtifactsView)
|
||||
m.Get("/artifacts/{artifact_name}", actions.ArtifactsDownloadView)
|
||||
m.Post("/rerun", reqRepoActionsWriter, actions.Rerun)
|
||||
})
|
||||
}, reqRepoActionsReader, actions.MustEnableActions)
|
||||
|
||||
|
|
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