1
0
Fork 0
mirror of https://codeberg.org/forgejo/forgejo.git synced 2025-06-27 16:35:57 +00:00

bug: unify RepoActionRun and ActionRun structs (#8250)

Two pull requests were merged at the same time

- https://codeberg.org/forgejo/forgejo/pulls/7699
- https://codeberg.org/forgejo/forgejo/pulls/7508

And added conflicting structs ActionRun modules/structs.  That broke
the forgejo development branch and a quick fix was made to resolve
the name conflict.

- https://codeberg.org/forgejo/forgejo/pulls/8066

However that creates an undesirable duplication of two structures that
serve the same purpose but are different.

- Remove RepoActionRun and replace it with ActionRun
- convert.ToActionRun has one more argument, the doer, because it
  is determined differently in the context of webhooks or API

### Tests

- No need because the two pull requests involved already have good coverage.

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/8250
Reviewed-by: Michael Kriese <michael.kriese@gmx.de>
Reviewed-by: klausfyhn <klausfyhn@noreply.codeberg.org>
Reviewed-by: Christopher Besch <mail@chris-besch.com>
Co-authored-by: Earl Warren <contact@earl-warren.org>
Co-committed-by: Earl Warren <contact@earl-warren.org>
This commit is contained in:
Earl Warren 2025-06-23 07:54:32 +02:00 committed by Earl Warren
parent b58cebc2d9
commit cf4d0e6c34
9 changed files with 187 additions and 140 deletions

View file

@ -78,3 +78,9 @@ type ActionRun struct {
// the url of this action run
HTMLURL string `json:"html_url"`
}
// ListActionRunResponse return a list of ActionRun
type ListActionRunResponse struct {
Entries []*ActionRun `json:"workflow_runs"`
TotalCount int64 `json:"total_count"`
}

View file

@ -32,23 +32,3 @@ type ActionTaskResponse struct {
Entries []*ActionTask `json:"workflow_runs"`
TotalCount int64 `json:"total_count"`
}
// ActionRun represents an ActionRun
type RepoActionRun struct {
ID int64 `json:"id"`
Name string `json:"name"`
RunNumber int64 `json:"run_number"`
Event string `json:"event"`
Status string `json:"status"`
HeadBranch string `json:"head_branch"`
HeadSHA string `json:"head_sha"`
WorkflowID string `json:"workflow_id"`
URL string `json:"url"`
TriggeringActor *User `json:"triggering_actor"`
}
// ListActionRunResponse return a list of ActionRun
type ListRepoActionRunResponse struct {
Entries []*RepoActionRun `json:"workflow_runs"`
TotalCount int64 `json:"total_count"`
}

View file

@ -748,7 +748,7 @@ func ListActionRuns(ctx *context.APIContext) {
// type: string
// responses:
// "200":
// "$ref": "#/responses/RepoActionRunList"
// "$ref": "#/responses/ActionRunList"
// "400":
// "$ref": "#/responses/error"
// "403":
@ -779,16 +779,16 @@ func ListActionRuns(ctx *context.APIContext) {
return
}
res := new(api.ListRepoActionRunResponse)
res := new(api.ListActionRunResponse)
res.TotalCount = total
res.Entries = make([]*api.RepoActionRun, len(runs))
res.Entries = make([]*api.ActionRun, len(runs))
for i, r := range runs {
cr, err := convert.ToRepoActionRun(ctx, r)
if err != nil {
ctx.Error(http.StatusInternalServerError, "ToActionRun", err)
if err := r.LoadAttributes(ctx); err != nil {
ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
return
}
cr := convert.ToActionRun(ctx, r, ctx.Doer)
res.Entries[i] = cr
}
@ -821,7 +821,7 @@ func GetActionRun(ctx *context.APIContext) {
// required: true
// responses:
// "200":
// "$ref": "#/responses/RepoActionRun"
// "$ref": "#/responses/ActionRun"
// "400":
// "$ref": "#/responses/error"
// "403":
@ -839,16 +839,17 @@ func GetActionRun(ctx *context.APIContext) {
return
}
// Action runs lives in its own table, therefore we check that the
// run with the requested ID is owned by the repository
if ctx.Repo.Repository.ID != run.RepoID {
ctx.Error(http.StatusNotFound, "GetRunById", util.ErrNotExist)
return
}
res, err := convert.ToRepoActionRun(ctx, run)
if err != nil {
ctx.Error(http.StatusInternalServerError, "ToRepoActionRun", err)
if err := run.LoadAttributes(ctx); err != nil {
ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
return
}
ctx.JSON(http.StatusOK, res)
ctx.JSON(http.StatusOK, convert.ToActionRun(ctx, run, ctx.Doer))
}

View file

@ -463,16 +463,16 @@ type swaggerSyncForkInfo struct {
Body []api.SyncForkInfo `json:"body"`
}
// RepoActionRunList
// swagger:response RepoActionRunList
type swaggerRepoActionRunList struct {
// ActionRunList
// swagger:response ActionRunList
type swaggerActionRunList struct {
// in:body
Body api.ListRepoActionRunResponse `json:"body"`
Body api.ListActionRunResponse `json:"body"`
}
// RepoActionRun
// swagger:response RepoActionRun
type swaggerRepoActionRun struct {
// ActionRun
// swagger:response ActionRun
type swaggerActionRun struct {
// in:body
Body api.RepoActionRun `json:"body"`
Body api.ActionRun `json:"body"`
}

View file

@ -8,22 +8,17 @@ import (
actions_model "forgejo.org/models/actions"
access_model "forgejo.org/models/perm/access"
user_model "forgejo.org/models/user"
api "forgejo.org/modules/structs"
)
// ToActionRun convert actions_model.User to api.ActionRun
// the run needs all attributes loaded
func ToActionRun(ctx context.Context, run *actions_model.ActionRun) *api.ActionRun {
func ToActionRun(ctx context.Context, run *actions_model.ActionRun, doer *user_model.User) *api.ActionRun {
if run == nil {
return nil
}
// The doer is the one whose perspective is used to view this ActionRun.
// In the best case we use the user that created the webhook.
// Unfortunately we don't know who that was.
// So instead we use the repo owner, who is able to create webhooks and allow others to do so by making them repo admins.
// This is pretty close to perfect.
doer := run.Repo.Owner
permissionInRepo, _ := access_model.GetUserRepoPermission(ctx, run.Repo, doer)
return &api.ActionRun{

View file

@ -222,29 +222,6 @@ func ToActionTask(ctx context.Context, t *actions_model.ActionTask) (*api.Action
}, nil
}
// ToRepoActionRun convert a actions_model.ActionRun to an api.RepoActionRun
func ToRepoActionRun(ctx context.Context, r *actions_model.ActionRun) (*api.RepoActionRun, error) {
if err := r.LoadAttributes(ctx); err != nil {
return nil, err
}
url := strings.TrimSuffix(setting.AppURL, "/") + r.Link()
actor := ToUser(ctx, r.TriggerUser, nil)
return &api.RepoActionRun{
ID: r.ID,
Name: r.Title,
HeadBranch: r.PrettyRef(),
HeadSHA: r.CommitSHA,
RunNumber: r.Index,
Event: r.TriggerEvent,
Status: r.Status.String(),
WorkflowID: r.WorkflowID,
URL: url,
TriggeringActor: actor,
}, nil
}
// ToVerification convert a git.Commit.Signature to an api.PayloadCommitVerification
func ToVerification(ctx context.Context, c *git.Commit) *api.PayloadCommitVerification {
verif := asymkey_model.ParseCommitWithSignature(ctx, c)

View file

@ -894,9 +894,16 @@ func (m *webhookNotifier) ActionRunNowDone(ctx context.Context, run *actions_mod
Owner: run.TriggerUser,
}
// The doer is the one whose perspective is used to view this ActionRun.
// In the best case we use the user that created the webhook.
// Unfortunately we don't know who that was.
// So instead we use the repo owner, who is able to create webhooks and allow others to do so by making them repo admins.
// This is pretty close to perfect.
doer := run.Repo.Owner
payload := &api.ActionPayload{
Run: convert.ToActionRun(ctx, run),
LastRun: convert.ToActionRun(ctx, lastRun),
Run: convert.ToActionRun(ctx, run, doer),
LastRun: convert.ToActionRun(ctx, lastRun, doer),
PriorStatus: priorStatus.String(),
}

View file

@ -4985,7 +4985,7 @@
],
"responses": {
"200": {
"$ref": "#/responses/RepoActionRunList"
"$ref": "#/responses/ActionRunList"
},
"400": {
"$ref": "#/responses/error"
@ -5032,7 +5032,7 @@
],
"responses": {
"200": {
"$ref": "#/responses/RepoActionRun"
"$ref": "#/responses/ActionRun"
},
"400": {
"$ref": "#/responses/error"
@ -21120,6 +21120,129 @@
},
"x-go-package": "forgejo.org/modules/structs"
},
"ActionRun": {
"description": "ActionRun represents an action run",
"type": "object",
"properties": {
"ScheduleID": {
"description": "the cron id for the schedule trigger",
"type": "integer",
"format": "int64"
},
"approved_by": {
"description": "who approved this action run",
"type": "integer",
"format": "int64",
"x-go-name": "ApprovedBy"
},
"commit_sha": {
"description": "the commit sha the action run ran on",
"type": "string",
"x-go-name": "CommitSHA"
},
"created": {
"description": "when the action run was created",
"type": "string",
"format": "date-time",
"x-go-name": "Created"
},
"duration": {
"$ref": "#/definitions/Duration"
},
"event": {
"description": "the webhook event that causes the workflow to run",
"type": "string",
"x-go-name": "Event"
},
"event_payload": {
"description": "the payload of the webhook event that causes the workflow to run",
"type": "string",
"x-go-name": "EventPayload"
},
"html_url": {
"description": "the url of this action run",
"type": "string",
"x-go-name": "HTMLURL"
},
"id": {
"description": "the action run id",
"type": "integer",
"format": "int64",
"x-go-name": "ID"
},
"index_in_repo": {
"description": "a unique number for each run of a repository",
"type": "integer",
"format": "int64",
"x-go-name": "Index"
},
"is_fork_pull_request": {
"description": "If this is triggered by a PR from a forked repository or an untrusted user, we need to check if it is approved and limit permissions when running the workflow.",
"type": "boolean",
"x-go-name": "IsForkPullRequest"
},
"is_ref_deleted": {
"description": "has the commit/tag/… the action run ran on been deleted",
"type": "boolean",
"x-go-name": "IsRefDeleted"
},
"need_approval": {
"description": "may need approval if it's a fork pull request",
"type": "boolean",
"x-go-name": "NeedApproval"
},
"prettyref": {
"description": "the commit/tag/… the action run ran on",
"type": "string",
"x-go-name": "PrettyRef"
},
"repository": {
"$ref": "#/definitions/Repository"
},
"started": {
"description": "when the action run was started",
"type": "string",
"format": "date-time",
"x-go-name": "Started"
},
"status": {
"description": "the current status of this run",
"type": "string",
"x-go-name": "Status"
},
"stopped": {
"description": "when the action run was stopped",
"type": "string",
"format": "date-time",
"x-go-name": "Stopped"
},
"title": {
"description": "the action run's title",
"type": "string",
"x-go-name": "Title"
},
"trigger_event": {
"description": "the trigger event defined in the `on` configuration of the triggered workflow",
"type": "string",
"x-go-name": "TriggerEvent"
},
"trigger_user": {
"$ref": "#/definitions/User"
},
"updated": {
"description": "when the action run was last updated",
"type": "string",
"format": "date-time",
"x-go-name": "Updated"
},
"workflow_id": {
"description": "the name of workflow file",
"type": "string",
"x-go-name": "WorkflowID"
}
},
"x-go-package": "forgejo.org/modules/structs"
},
"ActionRunJob": {
"description": "ActionRunJob represents a job of a run",
"type": "object",
@ -23610,6 +23733,12 @@
},
"x-go-package": "forgejo.org/modules/structs"
},
"Duration": {
"description": "A Duration represents the elapsed time between two instants\nas an int64 nanosecond count. The representation limits the\nlargest representable duration to approximately 290 years.",
"type": "integer",
"format": "int64",
"x-go-package": "time"
},
"EditAttachmentOptions": {
"description": "EditAttachmentOptions options for editing attachments",
"type": "object",
@ -25576,7 +25705,7 @@
},
"x-go-package": "forgejo.org/modules/structs"
},
"ListRepoActionRunResponse": {
"ListActionRunResponse": {
"description": "ListActionRunResponse return a list of ActionRun",
"type": "object",
"properties": {
@ -25588,7 +25717,7 @@
"workflow_runs": {
"type": "array",
"items": {
"$ref": "#/definitions/RepoActionRun"
"$ref": "#/definitions/ActionRun"
},
"x-go-name": "Entries"
}
@ -27353,54 +27482,6 @@
},
"x-go-package": "forgejo.org/modules/structs"
},
"RepoActionRun": {
"description": "ActionRun represents an ActionRun",
"type": "object",
"properties": {
"event": {
"type": "string",
"x-go-name": "Event"
},
"head_branch": {
"type": "string",
"x-go-name": "HeadBranch"
},
"head_sha": {
"type": "string",
"x-go-name": "HeadSHA"
},
"id": {
"type": "integer",
"format": "int64",
"x-go-name": "ID"
},
"name": {
"type": "string",
"x-go-name": "Name"
},
"run_number": {
"type": "integer",
"format": "int64",
"x-go-name": "RunNumber"
},
"status": {
"type": "string",
"x-go-name": "Status"
},
"triggering_actor": {
"$ref": "#/definitions/User"
},
"url": {
"type": "string",
"x-go-name": "URL"
},
"workflow_id": {
"type": "string",
"x-go-name": "WorkflowID"
}
},
"x-go-package": "forgejo.org/modules/structs"
},
"RepoCollaboratorPermission": {
"description": "RepoCollaboratorPermission to get repository permission for a collaborator",
"type": "object",
@ -28847,6 +28928,18 @@
}
}
},
"ActionRun": {
"description": "ActionRun",
"schema": {
"$ref": "#/definitions/ActionRun"
}
},
"ActionRunList": {
"description": "ActionRunList",
"schema": {
"$ref": "#/definitions/ListActionRunResponse"
}
},
"ActionVariable": {
"description": "ActionVariable",
"schema": {
@ -29616,18 +29709,6 @@
}
}
},
"RepoActionRun": {
"description": "RepoActionRun",
"schema": {
"$ref": "#/definitions/RepoActionRun"
}
},
"RepoActionRunList": {
"description": "RepoActionRunList",
"schema": {
"$ref": "#/definitions/ListRepoActionRunResponse"
}
},
"RepoCollaboratorPermission": {
"description": "RepoCollaboratorPermission",
"schema": {

View file

@ -169,7 +169,7 @@ func TestAPIGetListActionRun(t *testing.T) {
req.AddTokenAuth(token)
res := MakeRequest(t, req, http.StatusOK)
apiRuns := new(api.ListRepoActionRunResponse)
apiRuns := new(api.ListActionRunResponse)
DecodeJSON(t, res, apiRuns)
assert.Equal(t, int64(len(tt.expectedIDs)), apiRuns.TotalCount)
@ -231,13 +231,13 @@ func TestAPIGetActionRun(t *testing.T) {
}
dbRun := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ID: tt.runID})
apiRun := new(api.RepoActionRun)
apiRun := new(api.ActionRun)
DecodeJSON(t, res, apiRun)
assert.Equal(t, dbRun.Index, apiRun.RunNumber)
assert.Equal(t, dbRun.Index, apiRun.Index)
assert.Equal(t, dbRun.Status.String(), apiRun.Status)
assert.Equal(t, dbRun.CommitSHA, apiRun.HeadSHA)
assert.Equal(t, dbRun.TriggerUserID, apiRun.TriggeringActor.ID)
assert.Equal(t, dbRun.CommitSHA, apiRun.CommitSHA)
assert.Equal(t, dbRun.TriggerUserID, apiRun.TriggerUser.ID)
})
}
}