1
0
Fork 0
mirror of https://codeberg.org/forgejo/forgejo.git synced 2025-08-01 17:38:33 +00:00

feat: make action runs available in api (#7699)

## Summary

Inspired by https://docs.github.com/en/rest/actions/workflow-runs?apiVersion=2022-11-28#list-workflow-runs-for-a-repository and https://docs.github.com/en/rest/actions/workflow-runs?apiVersion=2022-11-28#get-a-workflow-run

## Checklist

The [contributor guide](https://forgejo.org/docs/next/contributor/) contains information that will be helpful to first time contributors. There also are a few [conditions for merging Pull Requests in Forgejo repositories](https://codeberg.org/forgejo/governance/src/branch/main/PullRequestsAgreement.md). You are also welcome to join the [Forgejo development chatroom](https://matrix.to/#/#forgejo-development:matrix.org).

### Tests

- I added test coverage for Go changes...
  - [ ] in their respective `*_test.go` for unit tests.
  - [x] in the `tests/integration` directory if it involves interactions with a live Forgejo server.
- I added test coverage for JavaScript changes...
  - [ ] in `web_src/js/*.test.js` if it can be unit tested.
  - [ ] in `tests/e2e/*.test.e2e.js` if it requires interactions with a live Forgejo server (see also the [developer guide for JavaScript testing](https://codeberg.org/forgejo/forgejo/src/branch/forgejo/tests/e2e/README.md#end-to-end-tests)).

### Documentation

- [ ] I created a pull request [to the documentation](https://codeberg.org/forgejo/docs) to explain to Forgejo users how to use this change.
- [x] I did not document these changes and I do not expect someone else to do it.

### Release notes

- [ ] I do not want this change to show in the release notes.
- [x] I want the title to show in the release notes with a link to this pull request.
- [ ] I want the content of the `release-notes/<pull request number>.md` to be be used for the release notes instead of the title.

<!--start release-notes-assistant-->

## Release notes
<!--URL:https://codeberg.org/forgejo/forgejo-->
- Features
  - [PR](https://codeberg.org/forgejo/forgejo/pulls/7699): <!--number 7699 --><!--line 0 --><!--description bWFrZSBhY3Rpb24gcnVucyBhdmFpbGFibGUgaW4gYXBp-->make action runs available in api<!--description-->
<!--end release-notes-assistant-->

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/7699
Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org>
Co-authored-by: klausfyhn <klausfyhn@gmail.com>
Co-committed-by: klausfyhn <klausfyhn@gmail.com>
This commit is contained in:
klausfyhn 2025-06-02 22:05:12 +02:00 committed by Earl Warren
parent 85c054c412
commit fc35915a28
36 changed files with 730 additions and 1 deletions

View file

@ -1172,6 +1172,10 @@ func Routes() *web.Route {
}, reqToken(), reqAdmin())
m.Group("/actions", func() {
m.Get("/tasks", repo.ListActionTasks)
m.Group("/runs", func() {
m.Get("", repo.ListActionRuns)
m.Get("/{run_id}", repo.GetActionRun)
})
m.Group("/workflows", func() {
m.Group("/{workflowname}", func() {

View file

@ -5,6 +5,7 @@ package repo
import (
"errors"
"fmt"
"net/http"
actions_model "forgejo.org/models/actions"
@ -694,3 +695,160 @@ func DispatchWorkflow(ctx *context.APIContext) {
ctx.JSON(http.StatusNoContent, nil)
}
}
// ListActionRuns return a filtered list of ActionRun
func ListActionRuns(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/actions/runs repository ListActionRuns
// ---
// summary: List a repository's action runs
// produces:
// - application/json
// parameters:
// - name: owner
// in: path
// description: owner of the repo
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo
// type: string
// required: true
// - name: page
// in: query
// description: page number of results to return (1-based)
// type: integer
// - name: limit
// in: query
// description: page size of results, default maximum page size is 50
// type: integer
// - name: event
// in: query
// description: Returns workflow run triggered by the specified events. For example, `push`, `pull_request` or `workflow_dispatch`.
// type: array
// items:
// type: string
// - name: status
// in: query
// description: |
// Returns workflow runs with the check run status or conclusion that is specified. For example, a conclusion can be success or a status can be in_progress. Only Forgejo Actions can set a status of waiting, pending, or requested.
// type: array
// items:
// type: string
// enum: [unknown, waiting, running, success, failure, cancelled, skipped, blocked]
// - name: run_number
// in: query
// description: |
// Returns the workflow run associated with the run number.
// type: integer
// format: int64
// - name: head_sha
// in: query
// description: Only returns workflow runs that are associated with the specified head_sha.
// type: string
// responses:
// "200":
// "$ref": "#/responses/ActionRunList"
// "400":
// "$ref": "#/responses/error"
// "403":
// "$ref": "#/responses/forbidden"
statusStrs := ctx.FormStrings("status")
statuses := make([]actions_model.Status, len(statusStrs))
for i, s := range statusStrs {
if status, exists := actions_model.StatusFromString(s); exists {
statuses[i] = status
} else {
ctx.Error(http.StatusBadRequest, "StatusFromString", fmt.Sprintf("unknown status: %s", s))
return
}
}
runs, total, err := db.FindAndCount[actions_model.ActionRun](ctx, &actions_model.FindRunJobOptions{
ListOptions: utils.GetListOptions(ctx),
OwnerID: ctx.Repo.Owner.ID,
RepoID: ctx.Repo.Repository.ID,
Events: ctx.FormStrings("event"),
Statuses: statuses,
RunNumber: ctx.FormInt64("run_number"),
CommitSHA: ctx.FormString("head_sha"),
})
if err != nil {
ctx.Error(http.StatusInternalServerError, "ListActionRuns", err)
return
}
res := new(api.ListActionRunResponse)
res.TotalCount = total
res.Entries = make([]*api.ActionRun, len(runs))
for i, r := range runs {
cr, err := convert.ToActionRun(ctx, r)
if err != nil {
ctx.Error(http.StatusInternalServerError, "ToActionRun", err)
return
}
res.Entries[i] = cr
}
ctx.JSON(http.StatusOK, &res)
}
// GetActionRun get one action instance
func GetActionRun(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/actions/runs/{run_id} repository ActionRun
// ---
// summary: Get an action run
// produces:
// - application/json
// parameters:
// - name: owner
// in: path
// description: owner of the repo
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo
// type: string
// required: true
// - name: run_id
// in: path
// description: id of the action run
// type: integer
// format: int64
// required: true
// responses:
// "200":
// "$ref": "#/responses/ActionRun"
// "400":
// "$ref": "#/responses/error"
// "403":
// "$ref": "#/responses/forbidden"
// "404":
// "$ref": "#/responses/notFound"
run, err := actions_model.GetRunByID(ctx, ctx.ParamsInt64(":run_id"))
if err != nil {
if errors.Is(err, util.ErrNotExist) {
ctx.Error(http.StatusNotFound, "GetRunById", err)
} else {
ctx.Error(http.StatusInternalServerError, "GetRunByID", err)
}
return
}
if ctx.Repo.Repository.ID != run.RepoID {
ctx.Error(http.StatusNotFound, "GetRunById", util.ErrNotExist)
return
}
res, err := convert.ToActionRun(ctx, run)
if err != nil {
ctx.Error(http.StatusInternalServerError, "ToActionRun", err)
return
}
ctx.JSON(http.StatusOK, res)
}

View file

@ -455,3 +455,17 @@ type swaggerSyncForkInfo struct {
// in:body
Body []api.SyncForkInfo `json:"body"`
}
// ActionRunList
// swagger:response ActionRunList
type swaggerRepoActionRunList struct {
// in:body
Body api.ListActionRunResponse `json:"body"`
}
// ActionRun
// swagger:response ActionRun
type swaggerRepoActionRun struct {
// in:body
Body api.ActionRun `json:"body"`
}