0
0
mirror of https://github.com/go-gitea/gitea.git synced 2025-07-21 12:24:38 +02:00

add more test and more level of runs / jobs access

This commit is contained in:
Christopher Homberger 2025-05-03 13:26:14 +02:00
parent 3f479a2686
commit f82178edb3
13 changed files with 578 additions and 158 deletions

View File

@ -85,9 +85,6 @@ func (opts FindRunJobOptions) ToConds() builder.Cond {
if opts.RepoID > 0 {
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
}
if opts.OwnerID > 0 {
cond = cond.And(builder.Eq{"owner_id": opts.OwnerID})
}
if opts.CommitSHA != "" {
cond = cond.And(builder.Eq{"commit_sha": opts.CommitSHA})
}
@ -99,3 +96,15 @@ func (opts FindRunJobOptions) ToConds() builder.Cond {
}
return cond
}
func (opts FindRunJobOptions) ToJoins() []db.JoinFunc {
if opts.OwnerID > 0 {
return []db.JoinFunc{
func(sess db.Engine) error {
sess.Join("INNER", "repository", "repository.id = repo_id AND repository.owner_id = ?", opts.OwnerID)
return nil
},
}
}
return nil
}

View File

@ -79,9 +79,6 @@ func (opts FindRunOptions) ToConds() builder.Cond {
if opts.RepoID > 0 {
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
}
if opts.OwnerID > 0 {
cond = cond.And(builder.Eq{"owner_id": opts.OwnerID})
}
if opts.WorkflowID != "" {
cond = cond.And(builder.Eq{"workflow_id": opts.WorkflowID})
}
@ -103,6 +100,16 @@ func (opts FindRunOptions) ToConds() builder.Cond {
return cond
}
func (opts FindRunOptions) ToJoins() []db.JoinFunc {
if opts.OwnerID > 0 {
return []db.JoinFunc{func(sess db.Engine) error {
sess.Join("INNER", "repository", "repository.id = repo_id AND repository.owner_id = ?", opts.OwnerID)
return nil
}}
}
return nil
}
func (opts FindRunOptions) ToOrders() string {
return "`id` DESC"
}

View File

@ -93,3 +93,22 @@
updated: 1683636626
need_approval: 0
approved_by: 0
-
id: 803
title: "workflow run list for user"
repo_id: 2
owner_id: 0
workflow_id: "test.yaml"
index: 191
trigger_user_id: 1
ref: "refs/heads/test"
commit_sha: "c2d72f548424103f01ee1dc02889c1e2bff816b0"
event: "push"
is_fork_pull_request: 0
status: 1
started: 1683636528
stopped: 1683636626
created: 1683636108
updated: 1683636626
need_approval: 0
approved_by: 0

View File

@ -73,7 +73,22 @@
id: 203
run_id: 802
repo_id: 5
owner_id: 3
owner_id: 0
commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0
is_fork_pull_request: 0
name: job2
attempt: 1
job_id: job2
needs: '["job1"]'
task_id: 51
status: 5
started: 1683636528
stopped: 1683636626
-
id: 204
run_id: 803
repo_id: 2
owner_id: 0
commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0
is_fork_pull_request: 0
name: job2

View File

@ -102,3 +102,39 @@ func DeleteRunner(ctx *context.APIContext) {
// "$ref": "#/responses/notFound"
shared.DeleteRunner(ctx, 0, 0, ctx.PathParamInt64("runner_id"))
}
// ListWorkflowJobs Lists all jobs
func ListWorkflowJobs(ctx *context.APIContext) {
// swagger:operation GET /admin/actions/jobs admin listAdminWorkflowJobs
// ---
// summary: Lists all jobs
// produces:
// - application/json
// responses:
// "200":
// "$ref": "#/responses/JobList"
// "400":
// "$ref": "#/responses/error"
// "404":
// "$ref": "#/responses/notFound"
shared.ListJobs(ctx, 0, 0, 0)
}
// ListWorkflowRuns Lists all runs
func ListWorkflowRuns(ctx *context.APIContext) {
// swagger:operation GET /admin/actions/runs admin listAdminWorkflowRuns
// ---
// summary: Lists all runs
// produces:
// - application/json
// responses:
// "200":
// "$ref": "#/responses/RunList"
// "400":
// "$ref": "#/responses/error"
// "404":
// "$ref": "#/responses/notFound"
shared.ListRuns(ctx, 0, 0)
}

View File

@ -942,6 +942,8 @@ func Routes() *web.Router {
m.Get("/{runner_id}", reqToken(), reqChecker, act.GetRunner)
m.Delete("/{runner_id}", reqToken(), reqChecker, act.DeleteRunner)
})
m.Get("/runs", reqToken(), reqChecker, act.ListWorkflowRuns)
m.Get("/jobs", reqToken(), reqChecker, act.ListWorkflowJobs)
})
}
@ -1077,6 +1079,9 @@ func Routes() *web.Router {
m.Get("/{runner_id}", reqToken(), user.GetRunner)
m.Delete("/{runner_id}", reqToken(), user.DeleteRunner)
})
m.Get("/runs", reqToken(), user.ListWorkflowRuns)
m.Get("/jobs", reqToken(), user.ListWorkflowJobs)
})
m.Get("/followers", user.ListMyFollowers)
@ -1281,10 +1286,9 @@ func Routes() *web.Router {
m.Group("/actions", func() {
m.Get("/tasks", repo.ListActionTasks)
m.Group("/runs", func() {
m.Get("", repo.GetWorkflowRuns)
m.Group("/{run}", func() {
m.Get("", repo.GetWorkflowRun)
m.Get("/jobs", repo.GetWorkflowJobs)
m.Get("/jobs", repo.ListWorkflowRunJobs)
m.Get("/artifacts", repo.GetArtifactsOfRun)
})
})
@ -1737,11 +1741,15 @@ func Routes() *web.Router {
Patch(bind(api.EditHookOption{}), admin.EditHook).
Delete(admin.DeleteHook)
})
m.Group("/actions/runners", func() {
m.Get("", admin.ListRunners)
m.Post("/registration-token", admin.CreateRegistrationToken)
m.Get("/{runner_id}", admin.GetRunner)
m.Delete("/{runner_id}", admin.DeleteRunner)
m.Group("/actions", func() {
m.Group("/runners", func() {
m.Get("", admin.ListRunners)
m.Post("/registration-token", admin.CreateRegistrationToken)
m.Get("/{runner_id}", admin.GetRunner)
m.Delete("/{runner_id}", admin.DeleteRunner)
})
m.Get("/runs", admin.ListWorkflowRuns)
m.Get("/jobs", admin.ListWorkflowJobs)
})
m.Group("/runners", func() {
m.Get("/registration-token", admin.GetRegistrationToken)

View File

@ -570,6 +570,36 @@ func (Action) DeleteRunner(ctx *context.APIContext) {
shared.DeleteRunner(ctx, ctx.Org.Organization.ID, 0, ctx.PathParamInt64("runner_id"))
}
func (Action) ListWorkflowJobs(ctx *context.APIContext) {
// swagger:operation GET /orgs/{org}/actions/jobs organization getOrgWorkflowJobs
// ---
// summary: Get org-level workflow jobs
// produces:
// - application/json
// parameters:
// - name: org
// in: path
// description: name of the organization
// type: string
// required: true
shared.ListJobs(ctx, ctx.Org.Organization.ID, 0, 0)
}
func (Action) ListWorkflowRuns(ctx *context.APIContext) {
// swagger:operation GET /orgs/{org}/actions/runs organization getOrgWorkflowRuns
// ---
// summary: Get org-level workflow runs
// produces:
// - application/json
// parameters:
// - name: org
// in: path
// description: name of the organization
// type: string
// required: true
shared.ListRuns(ctx, ctx.Org.Organization.ID, 0)
}
var _ actions_service.API = new(Action)
// Action implements actions_service.API

View File

@ -21,13 +21,11 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
secret_model "code.gitea.io/gitea/models/secret"
"code.gitea.io/gitea/modules/actions"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/httplib"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/modules/webhook"
"code.gitea.io/gitea/routers/api/v1/shared"
"code.gitea.io/gitea/routers/api/v1/utils"
actions_service "code.gitea.io/gitea/services/actions"
@ -652,6 +650,83 @@ func (Action) DeleteRunner(ctx *context.APIContext) {
shared.DeleteRunner(ctx, 0, ctx.Repo.Repository.ID, ctx.PathParamInt64("runner_id"))
}
// GetWorkflowRunJobs Lists all jobs for a workflow run.
func (Action) ListWorkflowJobs(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/actions/jobs repository listWorkflowJobs
// ---
// summary: Lists all jobs for a repository
// produces:
// - application/json
// parameters:
// - name: owner
// in: path
// description: name of the owner
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repository
// type: string
// required: true
// responses:
// "200":
// "$ref": "#/responses/JobList"
// "400":
// "$ref": "#/responses/error"
// "404":
// "$ref": "#/responses/notFound"
repoID := ctx.Repo.Repository.ID
shared.ListJobs(ctx, 0, repoID, 0)
}
// ListWorkflowRuns Lists all runs for a repository run.
func (Action) ListWorkflowRuns(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/actions/runs repository getWorkflowRuns
// ---
// summary: Lists all runs for a repository run
// produces:
// - application/json
// parameters:
// - name: owner
// in: path
// description: name of the owner
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repository
// type: string
// required: true
// - name: event
// in: query
// description: workflow event name
// type: string
// required: false
// - name: branch
// in: query
// description: workflow branch
// type: string
// required: false
// - name: status
// in: query
// description: workflow status (pending, queued, in_progress, failure, success, skipped)
// type: string
// required: false
// responses:
// "200":
// "$ref": "#/responses/ArtifactsList"
// "400":
// "$ref": "#/responses/error"
// "404":
// "$ref": "#/responses/notFound"
repoID := ctx.Repo.Repository.ID
shared.ListRuns(ctx, 0, repoID)
}
var _ actions_service.API = new(Action)
// Action implements actions_service.API
@ -994,109 +1069,6 @@ func ActionsEnableWorkflow(ctx *context.APIContext) {
ctx.Status(http.StatusNoContent)
}
func convertToInternal(s string) actions_model.Status {
switch s {
case "pending":
return actions_model.StatusBlocked
case "queued":
return actions_model.StatusWaiting
case "in_progress":
return actions_model.StatusRunning
case "failure":
return actions_model.StatusFailure
case "success":
return actions_model.StatusSuccess
case "skipped":
return actions_model.StatusSkipped
default:
return actions_model.StatusUnknown
}
}
// GetWorkflowRuns Lists all runs for a repository run.
func GetWorkflowRuns(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/actions/runs repository getWorkflowRuns
// ---
// summary: Lists all runs for a repository run
// produces:
// - application/json
// parameters:
// - name: owner
// in: path
// description: name of the owner
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repository
// type: string
// required: true
// - name: event
// in: query
// description: workflow event name
// type: string
// required: false
// - name: branch
// in: query
// description: workflow branch
// type: string
// required: false
// - name: status
// in: query
// description: workflow status (pending, queued, in_progress, failure, success, skipped)
// type: string
// required: false
// responses:
// "200":
// "$ref": "#/responses/ArtifactsList"
// "400":
// "$ref": "#/responses/error"
// "404":
// "$ref": "#/responses/notFound"
repoID := ctx.Repo.Repository.ID
opts := actions_model.FindRunOptions{
RepoID: repoID,
ListOptions: utils.GetListOptions(ctx),
}
if event := ctx.Req.URL.Query().Get("event"); event != "" {
opts.TriggerEvent = webhook.HookEventType(event)
}
if branch := ctx.Req.URL.Query().Get("branch"); branch != "" {
opts.Ref = string(git.RefNameFromBranch(branch))
}
if status := ctx.Req.URL.Query().Get("status"); status != "" {
opts.Status = []actions_model.Status{convertToInternal(status)}
}
// if actor := ctx.Req.URL.Query().Get("actor"); actor != "" {
// user_model.
// opts.TriggerUserID =
// }
runs, total, err := db.FindAndCount[actions_model.ActionRun](ctx, opts)
if err != nil {
ctx.APIErrorInternal(err)
return
}
res := new(api.ActionWorkflowRunsResponse)
res.TotalCount = total
res.Entries = make([]*api.ActionWorkflowRun, len(runs))
for i := range runs {
convertedRun, err := convert.ToActionWorkflowRun(ctx, ctx.Repo.Repository, runs[i])
if err != nil {
ctx.APIErrorInternal(err)
return
}
res.Entries[i] = convertedRun
}
ctx.JSON(http.StatusOK, &res)
}
// GetWorkflowRun Gets a specific workflow run.
func GetWorkflowRun(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/actions/runs/{run} repository GetWorkflowRun
@ -1143,9 +1115,9 @@ func GetWorkflowRun(ctx *context.APIContext) {
ctx.JSON(http.StatusOK, convertedArtifact)
}
// GetWorkflowJobs Lists all jobs for a workflow run.
func GetWorkflowJobs(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/actions/runs/{run}/jobs repository getWorkflowJobs
// ListWorkflowRunJobs Lists all jobs for a workflow run.
func ListWorkflowRunJobs(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/actions/runs/{run}/jobs repository listWorkflowRunJobs
// ---
// summary: Lists all jobs for a workflow run
// produces:
@ -1168,7 +1140,7 @@ func GetWorkflowJobs(ctx *context.APIContext) {
// required: true
// responses:
// "200":
// "$ref": "#/responses/ArtifactsList"
// "$ref": "#/responses/JobList"
// "400":
// "$ref": "#/responses/error"
// "404":
@ -1178,30 +1150,7 @@ func GetWorkflowJobs(ctx *context.APIContext) {
runID := ctx.PathParamInt64("run")
artifacts, total, err := db.FindAndCount[actions_model.ActionRunJob](ctx, actions_model.FindRunJobOptions{
RepoID: repoID,
RunID: runID,
ListOptions: utils.GetListOptions(ctx),
})
if err != nil {
ctx.APIErrorInternal(err)
return
}
res := new(api.ActionWorkflowJobsResponse)
res.TotalCount = total
res.Entries = make([]*api.ActionWorkflowJob, len(artifacts))
for i := range artifacts {
convertedWorkflowJob, err := convert.ToActionWorkflowJob(ctx, ctx.Repo.Repository, nil, artifacts[i])
if err != nil {
ctx.APIErrorInternal(err)
return
}
res.Entries[i] = convertedWorkflowJob
}
ctx.JSON(http.StatusOK, &res)
shared.ListJobs(ctx, 0, repoID, runID)
}
// GetWorkflowJob Gets a specific workflow job for a workflow run.
@ -1229,7 +1178,7 @@ func GetWorkflowJob(ctx *context.APIContext) {
// required: true
// responses:
// "200":
// "$ref": "#/responses/Artifact"
// "$ref": "#/responses/Job"
// "400":
// "$ref": "#/responses/error"
// "404":

View File

@ -9,9 +9,13 @@ import (
actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/webhook"
"code.gitea.io/gitea/routers/api/v1/utils"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/convert"
@ -116,3 +120,141 @@ func DeleteRunner(ctx *context.APIContext, ownerID, repoID, runnerID int64) {
}
ctx.Status(http.StatusNoContent)
}
// ListJobs lists jobs for api route validated ownerID and repoID
// ownerID == 0 and repoID == 0 means all jobs
// ownerID == 0 and repoID != 0 means all jobs for the given repo
// ownerID != 0 and repoID == 0 means all jobs for the given user/org
// ownerID != 0 and repoID != 0 undefined behavior
// runID == 0 means all jobs
// Access rights are checked at the API route level
func ListJobs(ctx *context.APIContext, ownerID, repoID, runID int64) {
if ownerID != 0 && repoID != 0 {
setting.PanicInDevOrTesting("ownerID and repoID should not be both set")
}
jobs, total, err := db.FindAndCount[actions_model.ActionRunJob](ctx, actions_model.FindRunJobOptions{
OwnerID: ownerID,
RepoID: repoID,
RunID: runID,
ListOptions: utils.GetListOptions(ctx),
})
if err != nil {
ctx.APIErrorInternal(err)
return
}
res := new(api.ActionWorkflowJobsResponse)
res.TotalCount = total
res.Entries = make([]*api.ActionWorkflowJob, len(jobs))
isRepoLevel := repoID != 0 && ctx.Repo != nil && ctx.Repo.Repository != nil && ctx.Repo.Repository.ID == repoID
for i := range jobs {
var repository *repo_model.Repository
if isRepoLevel {
repository = ctx.Repo.Repository
} else {
repository, err = repo_model.GetRepositoryByID(ctx, repoID)
if err != nil {
ctx.APIErrorInternal(err)
return
}
}
convertedWorkflowJob, err := convert.ToActionWorkflowJob(ctx, repository, nil, jobs[i])
if err != nil {
ctx.APIErrorInternal(err)
return
}
res.Entries[i] = convertedWorkflowJob
}
ctx.JSON(http.StatusOK, &res)
}
func convertToInternal(s string) actions_model.Status {
switch s {
case "pending":
return actions_model.StatusBlocked
case "queued":
return actions_model.StatusWaiting
case "in_progress":
return actions_model.StatusRunning
case "failure":
return actions_model.StatusFailure
case "success":
return actions_model.StatusSuccess
case "skipped":
return actions_model.StatusSkipped
default:
return actions_model.StatusUnknown
}
}
// ListRuns lists jobs for api route validated ownerID and repoID
// ownerID == 0 and repoID == 0 means all runs
// ownerID == 0 and repoID != 0 means all runs for the given repo
// ownerID != 0 and repoID == 0 means all runs for the given user/org
// ownerID != 0 and repoID != 0 undefined behavior
// Access rights are checked at the API route level
func ListRuns(ctx *context.APIContext, ownerID, repoID int64) {
if ownerID != 0 && repoID != 0 {
setting.PanicInDevOrTesting("ownerID and repoID should not be both set")
}
opts := actions_model.FindRunOptions{
OwnerID: ownerID,
RepoID: repoID,
ListOptions: utils.GetListOptions(ctx),
}
if event := ctx.Req.URL.Query().Get("event"); event != "" {
opts.TriggerEvent = webhook.HookEventType(event)
}
if branch := ctx.Req.URL.Query().Get("branch"); branch != "" {
opts.Ref = string(git.RefNameFromBranch(branch))
}
if status := ctx.Req.URL.Query().Get("status"); status != "" {
opts.Status = []actions_model.Status{convertToInternal(status)}
}
if actor := ctx.Req.URL.Query().Get("actor"); actor != "" {
user, err := user_model.GetUserByName(ctx, actor)
if err != nil {
ctx.APIErrorInternal(err)
return
}
opts.TriggerUserID = user.ID
}
runs, total, err := db.FindAndCount[actions_model.ActionRun](ctx, opts)
if err != nil {
ctx.APIErrorInternal(err)
return
}
res := new(api.ActionWorkflowRunsResponse)
res.TotalCount = total
res.Entries = make([]*api.ActionWorkflowRun, len(runs))
isRepoLevel := repoID != 0 && ctx.Repo != nil && ctx.Repo.Repository != nil && ctx.Repo.Repository.ID == repoID
for i := range runs {
var repository *repo_model.Repository
if isRepoLevel {
repository = ctx.Repo.Repository
} else {
repository, err = repo_model.GetRepositoryByID(ctx, runs[i].RepoID)
if err != nil {
ctx.APIErrorInternal(err)
return
}
}
convertedRun, err := convert.ToActionWorkflowRun(ctx, repository, runs[i])
if err != nil {
ctx.APIErrorInternal(err)
return
}
res.Entries[i] = convertedRun
}
ctx.JSON(http.StatusOK, &res)
}

View File

@ -102,3 +102,29 @@ func DeleteRunner(ctx *context.APIContext) {
// "$ref": "#/responses/notFound"
shared.DeleteRunner(ctx, ctx.Doer.ID, 0, ctx.PathParamInt64("runner_id"))
}
// ListWorkflowRuns lists workflow runs
func ListWorkflowRuns(ctx *context.APIContext) {
// swagger:operation GET /user/actions/runs user getUserWorkflowRuns
// ---
// summary: Get workflow runs
// produces:
// - application/json
// responses:
// "200":
// "$ref": "#/responses/ActionWorkflowRunsResponse"
shared.ListRuns(ctx, ctx.Doer.ID, 0)
}
// ListWorkflowJobs lists workflow jobs
func ListWorkflowJobs(ctx *context.APIContext) {
// swagger:operation GET /user/actions/jobs user getUserWorkflowJobs
// ---
// summary: Get workflow jobs
// produces:
// - application/json
// responses:
// "200":
// "$ref": "#/responses/ActionWorkflowJobsResponse"
shared.ListJobs(ctx, ctx.Doer.ID, 0, 0)
}

View File

@ -33,4 +33,8 @@ type API interface {
GetRunner(*context.APIContext)
// DeleteRunner delete runner
DeleteRunner(*context.APIContext)
// ListWorkflowJobs list jobs
ListWorkflowJobs(*context.APIContext)
// ListWorkflowRuns list runs
ListWorkflowRuns(*context.APIContext)
}

View File

@ -75,6 +75,29 @@
}
}
},
"/admin/actions/jobs": {
"get": {
"produces": [
"application/json"
],
"tags": [
"admin"
],
"summary": "Lists all jobs",
"operationId": "listAdminWorkflowJobs",
"responses": {
"200": {
"$ref": "#/responses/JobList"
},
"400": {
"$ref": "#/responses/error"
},
"404": {
"$ref": "#/responses/notFound"
}
}
}
},
"/admin/actions/runners": {
"get": {
"produces": [
@ -177,6 +200,29 @@
}
}
},
"/admin/actions/runs": {
"get": {
"produces": [
"application/json"
],
"tags": [
"admin"
],
"summary": "Lists all runs",
"operationId": "listAdminWorkflowRuns",
"responses": {
"200": {
"$ref": "#/responses/RunList"
},
"400": {
"$ref": "#/responses/error"
},
"404": {
"$ref": "#/responses/notFound"
}
}
}
},
"/admin/cron": {
"get": {
"produces": [
@ -1799,6 +1845,27 @@
}
}
},
"/orgs/{org}/actions/jobs": {
"get": {
"produces": [
"application/json"
],
"tags": [
"organization"
],
"summary": "Get org-level workflow jobs",
"operationId": "getOrgWorkflowJobs",
"parameters": [
{
"type": "string",
"description": "name of the organization",
"name": "org",
"in": "path",
"required": true
}
]
}
},
"/orgs/{org}/actions/runners": {
"get": {
"produces": [
@ -1957,6 +2024,27 @@
}
}
},
"/orgs/{org}/actions/runs": {
"get": {
"produces": [
"application/json"
],
"tags": [
"organization"
],
"summary": "Get org-level workflow runs",
"operationId": "getOrgWorkflowRuns",
"parameters": [
{
"type": "string",
"description": "name of the organization",
"name": "org",
"in": "path",
"required": true
}
]
}
},
"/orgs/{org}/actions/secrets": {
"get": {
"produces": [
@ -4519,6 +4607,45 @@
}
}
},
"/repos/{owner}/{repo}/actions/jobs": {
"get": {
"produces": [
"application/json"
],
"tags": [
"repository"
],
"summary": "Lists all jobs for a repository",
"operationId": "listWorkflowJobs",
"parameters": [
{
"type": "string",
"description": "name of the owner",
"name": "owner",
"in": "path",
"required": true
},
{
"type": "string",
"description": "name of the repository",
"name": "repo",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"$ref": "#/responses/JobList"
},
"400": {
"$ref": "#/responses/error"
},
"404": {
"$ref": "#/responses/notFound"
}
}
}
},
"/repos/{owner}/{repo}/actions/jobs/{job_id}": {
"get": {
"produces": [
@ -4554,7 +4681,7 @@
],
"responses": {
"200": {
"$ref": "#/responses/Artifact"
"$ref": "#/responses/Job"
},
"400": {
"$ref": "#/responses/error"
@ -4968,7 +5095,7 @@
"repository"
],
"summary": "Lists all jobs for a workflow run",
"operationId": "getWorkflowJobs",
"operationId": "listWorkflowRunJobs",
"parameters": [
{
"type": "string",
@ -4994,7 +5121,7 @@
],
"responses": {
"200": {
"$ref": "#/responses/ArtifactsList"
"$ref": "#/responses/JobList"
},
"400": {
"$ref": "#/responses/error"
@ -17662,6 +17789,23 @@
}
}
},
"/user/actions/jobs": {
"get": {
"produces": [
"application/json"
],
"tags": [
"user"
],
"summary": "Get workflow jobs",
"operationId": "getUserWorkflowJobs",
"responses": {
"200": {
"$ref": "#/responses/ActionWorkflowJobsResponse"
}
}
}
},
"/user/actions/runners": {
"get": {
"produces": [
@ -17779,6 +17923,23 @@
}
}
},
"/user/actions/runs": {
"get": {
"produces": [
"application/json"
],
"tags": [
"user"
],
"summary": "Get workflow runs",
"operationId": "getUserWorkflowRuns",
"responses": {
"200": {
"$ref": "#/responses/ActionWorkflowRunsResponse"
}
}
}
},
"/user/actions/secrets/{secretname}": {
"put": {
"consumes": [

View File

@ -15,17 +15,31 @@ import (
"github.com/stretchr/testify/assert"
)
func TestAPIWorkflowRunRepoApi(t *testing.T) {
defer tests.PrepareTestEnv(t)()
userUsername := "user2"
token := getUserToken(t, userUsername, auth_model.AccessTokenScopeWriteRepository)
func TestAPIWorkflowRun(t *testing.T) {
t.Run("AdminRunner", func(t *testing.T) {
testAPIWorkflowRunBasic(t, "/api/v1/admin/actions/runs", 6, "User1", 802, auth_model.AccessTokenScopeReadAdmin, auth_model.AccessTokenScopeReadRepository)
})
t.Run("UserRunner", func(t *testing.T) {
testAPIWorkflowRunBasic(t, "/api/v1/user/actions/runs", 1, "User2", 803, auth_model.AccessTokenScopeReadUser, auth_model.AccessTokenScopeReadRepository)
})
t.Run("OrgRuns", func(t *testing.T) {
testAPIWorkflowRunBasic(t, "/api/v1/orgs/org3/actions/runs", 1, "User1", 802, auth_model.AccessTokenScopeReadOrganization, auth_model.AccessTokenScopeReadRepository)
})
t.Run("RepoRuns", func(t *testing.T) {
testAPIWorkflowRunBasic(t, "/api/v1/repos/org3/repo5/actions/runs", 1, "User2", 802, auth_model.AccessTokenScopeReadRepository)
})
}
req := NewRequest(t, "GET", "/api/v1/repos/org3/repo5/actions/runs").AddTokenAuth(token)
func testAPIWorkflowRunBasic(t *testing.T, runAPIURL string, itemCount int, userUsername string, runID int64, scope ...auth_model.AccessTokenScope) {
defer tests.PrepareTestEnv(t)()
token := getUserToken(t, userUsername, scope...)
req := NewRequest(t, "GET", runAPIURL).AddTokenAuth(token)
runnerListResp := MakeRequest(t, req, http.StatusOK)
runnerList := api.ActionWorkflowRunsResponse{}
DecodeJSON(t, runnerListResp, &runnerList)
assert.Len(t, runnerList.Entries, 1)
assert.Len(t, runnerList.Entries, itemCount)
foundRun := false
@ -35,7 +49,7 @@ func TestAPIWorkflowRunRepoApi(t *testing.T) {
jobList := api.ActionWorkflowJobsResponse{}
DecodeJSON(t, jobsResp, &jobList)
if run.ID == 802 {
if run.ID == runID {
foundRun = true
assert.Len(t, jobList.Entries, 1)
for _, job := range jobList.Entries {