diff --git a/modules/structs/repo_actions.go b/modules/structs/repo_actions.go index eada2db09f..69e616eed9 100644 --- a/modules/structs/repo_actions.go +++ b/modules/structs/repo_actions.go @@ -33,26 +33,51 @@ type ActionTaskResponse struct { TotalCount int64 `json:"total_count"` } -// ActionRunnerLabel represents a Runner Label -type ActionRunnerLabel struct { - ID int64 `json:"id"` - Name string `json:"name"` - Type string `json:"type"` +type RunnerStatus int + +const ( + // RunnerStatusOffline signals that the runner is not connected to Forgejo. + RunnerStatusOffline RunnerStatus = iota + + // RunnerStatusIdle means that the runner is connected to Forgejo and waiting for jobs to run. + RunnerStatusIdle + + // RunnerStatusActive signifies that the runner is connected to Forgejo and running a job. + RunnerStatusActive +) + +var statusName = map[RunnerStatus]string{ + RunnerStatusOffline: "offline", + RunnerStatusIdle: "idle", + RunnerStatusActive: "active", } -// ActionRunner represents a Runner +func (status RunnerStatus) String() string { + return statusName[status] +} + +// ActionRunner represents a runner +// swagger:model type ActionRunner struct { - ID int64 `json:"id"` - Name string `json:"name"` + // ID uniquely identifies this runner. + ID int64 `json:"id"` + // UUID uniquely identifies this runner. + UUID string `json:"uuid"` + // OwnerID is the identifier of the user or organization this runner belongs to. O if the runner is owned by a + // repository. + OwnerID int64 `json:"owner_id"` + // RepoID is the identifier of the repository this runner belongs to. 0 if the runner belongs to a user or + // organization. + RepoID int64 `json:"repo_id"` + // Name of the runner; not unique. + Name string `json:"name"` + // Status indicates whether this runner is offline, or active, for example. + // enum: ["offline", "idle", "active"] Status string `json:"status"` - Busy bool `json:"busy"` - // currently unused as forgejo does not support ephemeral runners, but they are defined in gh api spec - Ephemeral bool `json:"ephemeral"` - Labels []*ActionRunnerLabel `json:"labels"` -} - -// ActionRunnersResponse returns Runners -type ActionRunnersResponse struct { - Entries []*ActionRunner `json:"runners"` - TotalCount int64 `json:"total_count"` + // Version is the self-reported version string of Forgejo Runner. + Version string `json:"version"` + // Labels is a list of labels attached to this runner. + Labels []string `json:"labels"` + // Description provides optional details about this runner. + Description string `json:"description"` } diff --git a/routers/api/v1/admin/runners.go b/routers/api/v1/admin/runners.go index 7c53a717a9..1a7abe2b12 100644 --- a/routers/api/v1/admin/runners.go +++ b/routers/api/v1/admin/runners.go @@ -8,13 +8,11 @@ import ( "forgejo.org/services/context" ) -// https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-an-organization - // GetRegistrationToken returns the token to register global runners func GetRegistrationToken(ctx *context.APIContext) { // swagger:operation GET /admin/runners/registration-token admin adminGetRunnerRegistrationToken // --- - // summary: Get a global actions runner registration token + // summary: Get a runner registration token for registering global runners // produces: // - application/json // parameters: @@ -29,7 +27,7 @@ func GetRegistrationToken(ctx *context.APIContext) { func SearchActionRunJobs(ctx *context.APIContext) { // swagger:operation GET /admin/runners/jobs admin adminSearchRunJobs // --- - // summary: Search action jobs according filter conditions + // summary: Search action jobs according to filter conditions // produces: // - application/json // parameters: @@ -45,31 +43,16 @@ func SearchActionRunJobs(ctx *context.APIContext) { shared.GetActionRunJobs(ctx, 0, 0) } -// CreateRegistrationToken returns the token to register global runners -func CreateRegistrationToken(ctx *context.APIContext) { - // swagger:operation POST /admin/actions/runners/registration-token admin adminCreateRunnerRegistrationToken - // --- - // summary: Get a global actions runner registration token - // produces: - // - application/json - // parameters: - // responses: - // "200": - // "$ref": "#/responses/RegistrationToken" - - shared.GetRegistrationToken(ctx, 0, 0) -} - -// ListRunners get all runners +// ListRunners returns all runners, no matter whether they are global runners or scoped to an organization, user, or repository func ListRunners(ctx *context.APIContext) { // swagger:operation GET /admin/actions/runners admin getAdminRunners // --- - // summary: Get all runners + // summary: Get all runners, no matter whether they are global runners or scoped to an organization, user, or repository // produces: // - application/json // responses: // "200": - // "$ref": "#/definitions/ActionRunnersResponse" + // "$ref": "#/responses/ActionRunnerList" // "400": // "$ref": "#/responses/error" // "404": @@ -77,22 +60,22 @@ func ListRunners(ctx *context.APIContext) { shared.ListRunners(ctx, 0, 0) } -// GetRunner get a global runner +// GetRunner returns a particular runner, no matter whether it is a global runner or scoped to an organization, user, or repository func GetRunner(ctx *context.APIContext) { // swagger:operation GET /admin/actions/runners/{runner_id} admin getAdminRunner // --- - // summary: Get a global runner + // summary: Get a particular runner, no matter whether it is a global runner or scoped to an organization, user, or repository // produces: // - application/json // parameters: // - name: runner_id // in: path - // description: id of the runner + // description: ID of the runner // type: string // required: true // responses: // "200": - // "$ref": "#/definitions/ActionRunner" + // "$ref": "#/responses/ActionRunner" // "400": // "$ref": "#/responses/error" // "404": @@ -100,17 +83,17 @@ func GetRunner(ctx *context.APIContext) { shared.GetRunner(ctx, 0, 0, ctx.ParamsInt64("runner_id")) } -// DeleteRunner delete a global runner +// DeleteRunner removes a particular runner, no matter whether it is a global runner or scoped to an organization, user, or repository func DeleteRunner(ctx *context.APIContext) { // swagger:operation DELETE /admin/actions/runners/{runner_id} admin deleteAdminRunner // --- - // summary: Delete a global runner + // summary: Delete a particular runner, no matter whether it is a global runner or scoped to an organization, user, or repository // produces: // - application/json // parameters: // - name: runner_id // in: path - // description: id of the runner + // description: ID of the runner // type: string // required: true // responses: diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 1206d653c1..f3589094b2 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -858,7 +858,6 @@ func Routes() *web.Route { m.Group("/runners", func() { m.Get("", reqToken(), reqChecker, act.ListRunners) m.Get("/registration-token", reqToken(), reqChecker, act.GetRegistrationToken) - m.Post("/registration-token", reqToken(), reqChecker, act.CreateRegistrationToken) m.Get("/{runner_id}", reqToken(), reqChecker, act.GetRunner) m.Delete("/{runner_id}", reqToken(), reqChecker, act.DeleteRunner) m.Get("/jobs", reqToken(), reqChecker, act.SearchActionRunJobs) @@ -1022,7 +1021,6 @@ func Routes() *web.Route { m.Group("/runners", func() { m.Get("", reqToken(), user.ListRunners) m.Get("/registration-token", reqToken(), user.GetRegistrationToken) - m.Post("/registration-token", reqToken(), user.CreateRegistrationToken) m.Get("/{runner_id}", reqToken(), user.GetRunner) m.Delete("/{runner_id}", reqToken(), user.DeleteRunner) m.Get("/jobs", reqToken(), user.SearchActionRunJobs) @@ -1704,7 +1702,7 @@ func Routes() *web.Route { }) m.Group("/actions/runners", func() { m.Get("", admin.ListRunners) - m.Post("/registration-token", admin.CreateRegistrationToken) + m.Get("/registration-token", admin.GetRegistrationToken) m.Get("/{runner_id}", admin.GetRunner) m.Delete("/{runner_id}", admin.DeleteRunner) }) diff --git a/routers/api/v1/org/action.go b/routers/api/v1/org/action.go index b3fcbca6b1..92921a3328 100644 --- a/routers/api/v1/org/action.go +++ b/routers/api/v1/org/action.go @@ -168,12 +168,11 @@ func (Action) DeleteSecret(ctx *context.APIContext) { ctx.Status(http.StatusNoContent) } -// https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-an-organization -// GetRegistrationToken returns the token to register org runners +// GetRegistrationToken returns the organization's runner registration token func (Action) GetRegistrationToken(ctx *context.APIContext) { // swagger:operation GET /orgs/{org}/actions/runners/registration-token organization orgGetRunnerRegistrationToken // --- - // summary: Get an organization's actions runner registration token + // summary: Get the organization's runner registration token // produces: // - application/json // parameters: @@ -214,27 +213,6 @@ func (Action) SearchActionRunJobs(ctx *context.APIContext) { shared.GetActionRunJobs(ctx, ctx.Org.Organization.ID, 0) } -// https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-an-organization -// CreateRegistrationToken returns the token to register org runners -func (Action) CreateRegistrationToken(ctx *context.APIContext) { - // swagger:operation POST /orgs/{org}/actions/runners/registration-token organization orgCreateRunnerRegistrationToken - // --- - // summary: Get an organization's actions runner registration token - // produces: - // - application/json - // parameters: - // - name: org - // in: path - // description: name of the organization - // type: string - // required: true - // responses: - // "200": - // "$ref": "#/responses/RegistrationToken" - - shared.GetRegistrationToken(ctx, ctx.Org.Organization.ID, 0) -} - // ListVariables list org-level variables func (Action) ListVariables(ctx *context.APIContext) { // swagger:operation GET /orgs/{org}/actions/variables organization getOrgVariablesList @@ -287,11 +265,11 @@ func (Action) ListVariables(ctx *context.APIContext) { ctx.JSON(http.StatusOK, variables) } -// ListRunners get org-level runners +// ListRunners returns the organization's runners func (Action) ListRunners(ctx *context.APIContext) { // swagger:operation GET /orgs/{org}/actions/runners organization getOrgRunners // --- - // summary: Get org-level runners + // summary: Get the organization's runners // produces: // - application/json // parameters: @@ -302,7 +280,7 @@ func (Action) ListRunners(ctx *context.APIContext) { // required: true // responses: // "200": - // "$ref": "#/definitions/ActionRunnersResponse" + // "$ref": "#/responses/ActionRunnerList" // "400": // "$ref": "#/responses/error" // "404": @@ -310,11 +288,11 @@ func (Action) ListRunners(ctx *context.APIContext) { shared.ListRunners(ctx, ctx.Org.Organization.ID, 0) } -// GetRunner get an org-level runner +// GetRunner gets a particular runner that belongs to the organization func (Action) GetRunner(ctx *context.APIContext) { // swagger:operation GET /orgs/{org}/actions/runners/{runner_id} organization getOrgRunner // --- - // summary: Get an org-level runner + // summary: Get a particular runner that belongs to the organization // produces: // - application/json // parameters: @@ -325,12 +303,12 @@ func (Action) GetRunner(ctx *context.APIContext) { // required: true // - name: runner_id // in: path - // description: id of the runner + // description: ID of the runner // type: string // required: true // responses: // "200": - // "$ref": "#/definitions/ActionRunner" + // "$ref": "#/responses/ActionRunner" // "400": // "$ref": "#/responses/error" // "404": @@ -338,11 +316,11 @@ func (Action) GetRunner(ctx *context.APIContext) { shared.GetRunner(ctx, ctx.Org.Organization.ID, 0, ctx.ParamsInt64("runner_id")) } -// DeleteRunner delete an org-level runner +// DeleteRunner removes a particular runner that belongs to the organization func (Action) DeleteRunner(ctx *context.APIContext) { // swagger:operation DELETE /orgs/{org}/actions/runners/{runner_id} organization deleteOrgRunner // --- - // summary: Delete an org-level runner + // summary: Delete a particular runner that belongs to the organization // produces: // - application/json // parameters: @@ -353,7 +331,7 @@ func (Action) DeleteRunner(ctx *context.APIContext) { // required: true // - name: runner_id // in: path - // description: id of the runner + // description: ID of the runner // type: string // required: true // responses: diff --git a/routers/api/v1/repo/action.go b/routers/api/v1/repo/action.go index 9085ee8e70..f413dc4925 100644 --- a/routers/api/v1/repo/action.go +++ b/routers/api/v1/repo/action.go @@ -480,11 +480,11 @@ func (Action) ListVariables(ctx *context.APIContext) { ctx.JSON(http.StatusOK, variables) } -// GetRegistrationToken returns the token to register repo runners +// GetRegistrationToken returns the runner registration token to register runners for the repository func (Action) GetRegistrationToken(ctx *context.APIContext) { // swagger:operation GET /repos/{owner}/{repo}/actions/runners/registration-token repository repoGetRunnerRegistrationToken // --- - // summary: Get a repository's actions runner registration token + // summary: Get a repository's runner registration token // produces: // - application/json // parameters: @@ -505,36 +505,11 @@ func (Action) GetRegistrationToken(ctx *context.APIContext) { shared.GetRegistrationToken(ctx, 0, ctx.Repo.Repository.ID) } -// CreateRegistrationToken returns the token to register repo runners -func (Action) CreateRegistrationToken(ctx *context.APIContext) { - // swagger:operation POST /repos/{owner}/{repo}/actions/runners/registration-token repository repoCreateRunnerRegistrationToken - // --- - // summary: Get a repository's actions runner registration token - // 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 - // responses: - // "200": - // "$ref": "#/responses/RegistrationToken" - - shared.GetRegistrationToken(ctx, 0, ctx.Repo.Repository.ID) -} - -// ListRunners get repo-level runners +// ListRunners returns runners that belong to the repository func (Action) ListRunners(ctx *context.APIContext) { // swagger:operation GET /repos/{owner}/{repo}/actions/runners repository getRepoRunners // --- - // summary: Get repo-level runners + // summary: Get runners belonging to the repository // produces: // - application/json // parameters: @@ -550,7 +525,7 @@ func (Action) ListRunners(ctx *context.APIContext) { // required: true // responses: // "200": - // "$ref": "#/definitions/ActionRunnersResponse" + // "$ref": "#/responses/ActionRunnerList" // "400": // "$ref": "#/responses/error" // "404": @@ -558,11 +533,11 @@ func (Action) ListRunners(ctx *context.APIContext) { shared.ListRunners(ctx, 0, ctx.Repo.Repository.ID) } -// GetRunner get a repo-level runner +// GetRunner returns a particular runner that belongs to the repository func (Action) GetRunner(ctx *context.APIContext) { // swagger:operation GET /repos/{owner}/{repo}/actions/runners/{runner_id} repository getRepoRunner // --- - // summary: Get a repo-level runner + // summary: Get a particular runner that belongs to the repository // produces: // - application/json // parameters: @@ -578,12 +553,12 @@ func (Action) GetRunner(ctx *context.APIContext) { // required: true // - name: runner_id // in: path - // description: id of the runner + // description: ID of the runner // type: string // required: true // responses: // "200": - // "$ref": "#/definitions/ActionRunner" + // "$ref": "#/responses/ActionRunner" // "400": // "$ref": "#/responses/error" // "404": @@ -591,11 +566,11 @@ func (Action) GetRunner(ctx *context.APIContext) { shared.GetRunner(ctx, 0, ctx.Repo.Repository.ID, ctx.ParamsInt64("runner_id")) } -// DeleteRunner delete a repo-level runner +// DeleteRunner removes a particular runner that belongs to a repository func (Action) DeleteRunner(ctx *context.APIContext) { // swagger:operation DELETE /repos/{owner}/{repo}/actions/runners/{runner_id} repository deleteRepoRunner // --- - // summary: Delete a repo-level runner + // summary: Delete a particular runner that belongs to a repository // produces: // - application/json // parameters: @@ -611,7 +586,7 @@ func (Action) DeleteRunner(ctx *context.APIContext) { // required: true // - name: runner_id // in: path - // description: id of the runner + // description: ID of the runner // type: string // required: true // responses: diff --git a/routers/api/v1/shared/runners.go b/routers/api/v1/shared/runners.go index feb47dacaa..4c4f1de00e 100644 --- a/routers/api/v1/shared/runners.go +++ b/routers/api/v1/shared/runners.go @@ -97,15 +97,17 @@ func ListRunners(ctx *context.APIContext, ownerID, repoID int64) { return } - res := new(structs.ActionRunnersResponse) - res.TotalCount = total - - res.Entries = make([]*structs.ActionRunner, len(runners)) + runnerList := make([]structs.ActionRunner, len(runners)) for i, runner := range runners { - res.Entries[i] = convert.ToActionRunner(ctx, runner) + actionRunner, err := convert.ToActionRunner(runner) + if err != nil { + ctx.Error(http.StatusInternalServerError, "ToActionRunner", err) + return + } + runnerList[i] = actionRunner } - - ctx.JSON(http.StatusOK, &res) + ctx.SetTotalCountHeader(total) + ctx.JSON(http.StatusOK, &runnerList) } // GetRunner get the runner for api route validated ownerID and repoID @@ -132,7 +134,12 @@ func GetRunner(ctx *context.APIContext, ownerID, repoID, runnerID int64) { ctx.Error(http.StatusNotFound, "RunnerEdit", "No permission to get this runner") return } - ctx.JSON(http.StatusOK, convert.ToActionRunner(ctx, runner)) + + actionRunner, err := convert.ToActionRunner(runner) + if err != nil { + ctx.Error(http.StatusInternalServerError, "ToActionRunner", err) + } + ctx.JSON(http.StatusOK, actionRunner) } // DeleteRunner deletes the runner for api route validated ownerID and repoID diff --git a/routers/api/v1/swagger/action.go b/routers/api/v1/swagger/action.go index cf853c986f..17181be250 100644 --- a/routers/api/v1/swagger/action.go +++ b/routers/api/v1/swagger/action.go @@ -57,16 +57,16 @@ type swaggerRegistrationToken struct { Body shared.RegistrationToken `json:"body"` } -// ActionRunner represents a Runner +// ActionRunner represents a runner // swagger:response ActionRunner type swaggerActionRunner struct { // in: body Body api.ActionRunner `json:"body"` } -// ActionRunnersResponse returns Runners -// swagger:response ActionRunnersResponse -type swaggerActionRunnerResponse struct { - // in: body - Body api.ActionRunnersResponse `json:"body"` +// ActionRunnerList is a list of Forgejo Action runners +// swagger:response ActionRunnerList +type swaggerActionRunnerListResponse struct { + // in:body + Body []api.ActionRunner `json:"body"` } diff --git a/routers/api/v1/user/runners.go b/routers/api/v1/user/runners.go index 2cfdd8a03a..dfeb49dcb6 100644 --- a/routers/api/v1/user/runners.go +++ b/routers/api/v1/user/runners.go @@ -8,13 +8,11 @@ import ( "forgejo.org/services/context" ) -// https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-an-organization - -// GetRegistrationToken returns the token to register user runners +// GetRegistrationToken returns a token to register user-level runners func GetRegistrationToken(ctx *context.APIContext) { // swagger:operation GET /user/actions/runners/registration-token user userGetRunnerRegistrationToken // --- - // summary: Get an user's actions runner registration token + // summary: Get the user's runner registration token // produces: // - application/json // parameters: @@ -29,7 +27,7 @@ func GetRegistrationToken(ctx *context.APIContext) { shared.GetRegistrationToken(ctx, ctx.Doer.ID, 0) } -// SearchActionRunJobs return a list of actions jobs filtered by the provided parameters +// SearchActionRunJobs returns a list of actions jobs filtered by the provided parameters func SearchActionRunJobs(ctx *context.APIContext) { // swagger:operation GET /user/actions/runners/jobs user userSearchRunJobs // --- @@ -51,33 +49,16 @@ func SearchActionRunJobs(ctx *context.APIContext) { shared.GetActionRunJobs(ctx, ctx.Doer.ID, 0) } -// CreateRegistrationToken returns the token to register user runners -func CreateRegistrationToken(ctx *context.APIContext) { - // swagger:operation POST /user/actions/runners/registration-token user userCreateRunnerRegistrationToken - // --- - // summary: Get an user's actions runner registration token - // produces: - // - application/json - // parameters: - // responses: - // "200": - // "$ref": "#/responses/RegistrationToken" - // "401": - // "$ref": "#/responses/unauthorized" - - shared.GetRegistrationToken(ctx, ctx.Doer.ID, 0) -} - -// ListRunners get user-level runners +// ListRunners returns the user's runners func ListRunners(ctx *context.APIContext) { // swagger:operation GET /user/actions/runners user getUserRunners // --- - // summary: Get user-level runners + // summary: Get the user's runners // produces: // - application/json // responses: // "200": - // "$ref": "#/responses/ActionRunnersResponse" + // "$ref": "#/responses/ActionRunnerList" // "400": // "$ref": "#/responses/error" // "401": @@ -87,17 +68,17 @@ func ListRunners(ctx *context.APIContext) { shared.ListRunners(ctx, ctx.Doer.ID, 0) } -// GetRunner get an user-level runner +// GetRunner gets a particular runner that belongs to the user func GetRunner(ctx *context.APIContext) { // swagger:operation GET /user/actions/runners/{runner_id} user getUserRunner // --- - // summary: Get an user-level runner + // summary: Get a particular runner that belongs to the user // produces: // - application/json // parameters: // - name: runner_id // in: path - // description: id of the runner + // description: ID of the runner // type: string // required: true // responses: @@ -112,17 +93,17 @@ func GetRunner(ctx *context.APIContext) { shared.GetRunner(ctx, ctx.Doer.ID, 0, ctx.ParamsInt64("runner_id")) } -// DeleteRunner delete an user-level runner +// DeleteRunner deletes a particular user-level runner func DeleteRunner(ctx *context.APIContext) { // swagger:operation DELETE /user/actions/runners/{runner_id} user deleteUserRunner // --- - // summary: Delete an user-level runner + // summary: Delete a particular user-level runner // produces: // - application/json // parameters: // - name: runner_id // in: path - // description: id of the runner + // description: ID of the runner // type: string // required: true // responses: diff --git a/services/actions/interface.go b/services/actions/interface.go index a5e0543594..466f8ef857 100644 --- a/services/actions/interface.go +++ b/services/actions/interface.go @@ -27,8 +27,6 @@ type API interface { GetRegistrationToken(*context.APIContext) // SearchActionRunJobs get pending Action run jobs SearchActionRunJobs(*context.APIContext) - // CreateRegistrationToken get registration token - CreateRegistrationToken(*context.APIContext) // ListRunners list runners ListRunners(*context.APIContext) // GetRunner get a runner diff --git a/services/convert/convert.go b/services/convert/convert.go index eaf6459cfd..00e1742178 100644 --- a/services/convert/convert.go +++ b/services/convert/convert.go @@ -522,26 +522,32 @@ func ToChangedFile(f *gitdiff.DiffFile, repo *repo_model.Repository, commit stri return file } -func ToActionRunner(ctx context.Context, runner *actions_model.ActionRunner) *api.ActionRunner { - status := runner.Status() - apiStatus := "offline" - if runner.IsOnline() { - apiStatus = "online" +func ToActionRunner(runner *actions_model.ActionRunner) (api.ActionRunner, error) { + runnerStatus := runner.Status() + + var status api.RunnerStatus + switch runnerStatus { + case runnerv1.RunnerStatus_RUNNER_STATUS_OFFLINE: + status = api.RunnerStatusOffline + case runnerv1.RunnerStatus_RUNNER_STATUS_IDLE: + status = api.RunnerStatusIdle + case runnerv1.RunnerStatus_RUNNER_STATUS_ACTIVE: + status = api.RunnerStatusActive + default: + return api.ActionRunner{}, fmt.Errorf("unexpected runner status: %s", runnerStatus) } - labels := make([]*api.ActionRunnerLabel, len(runner.AgentLabels)) - for i, label := range runner.AgentLabels { - labels[i] = &api.ActionRunnerLabel{ - ID: int64(i), - Name: label, - Type: "custom", - } - } - return &api.ActionRunner{ - ID: runner.ID, - Name: runner.Name, - Status: apiStatus, - Busy: status == runnerv1.RunnerStatus_RUNNER_STATUS_ACTIVE, - // Ephemeral: runner.Ephemeral, - Labels: labels, + + actionRunner := api.ActionRunner{ + ID: runner.ID, + Name: runner.Name, + UUID: runner.UUID, + OwnerID: runner.OwnerID, + RepoID: runner.RepoID, + Description: runner.Description, + Version: runner.Version, + Status: status.String(), + Labels: runner.AgentLabels, } + + return actionRunner, nil } diff --git a/services/convert/convert_test.go b/services/convert/convert_test.go index 04425bf9c3..6b870e0540 100644 --- a/services/convert/convert_test.go +++ b/services/convert/convert_test.go @@ -6,11 +6,13 @@ package convert import ( "testing" + actions_model "forgejo.org/models/actions" "forgejo.org/models/db" "forgejo.org/models/unittest" user_model "forgejo.org/models/user" "forgejo.org/modules/git" api "forgejo.org/modules/structs" + "forgejo.org/modules/timeutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -103,3 +105,77 @@ uf51WIBywxztet6vi+jYJK1jFoY4iA== }, commitVerification) }) } + +func TestToActionRunner(t *testing.T) { + testCases := []struct { + name string + runner actions_model.ActionRunner + expectedStatus api.RunnerStatus + }{ + { + name: "active-runner", + runner: actions_model.ActionRunner{ + ID: 846, + UUID: "0bf6d33b-9be8-4bb3-a210-351ae7f3d48e", + OwnerID: 204958, + RepoID: 0, + Name: "active-example", + Version: "12.1.2", + Description: "A very busy runner", + AgentLabels: []string{"debian", "gpu"}, + LastOnline: timeutil.TimeStampNow(), + LastActive: timeutil.TimeStampNow(), + }, + expectedStatus: api.RunnerStatusActive, + }, + { + name: "offline-runner", + runner: actions_model.ActionRunner{ + ID: 731, + UUID: "29b075f8-cd54-4dc2-b1e2-db303b32b0ce", + OwnerID: 0, + RepoID: 255289, + Name: "offline-example", + Version: "dev", + Description: "", + AgentLabels: []string{}, + LastOnline: 0, + LastActive: 0, + }, + expectedStatus: api.RunnerStatusOffline, + }, + { + name: "idle-runner", + runner: actions_model.ActionRunner{ + ID: 117, + UUID: "865ca613-f258-49bc-a986-1037ace1ca35", + OwnerID: 39115, + RepoID: 0, + Name: "idle-example", + Version: "11.3.1", + Description: "A runner twiddling its thumbs", + AgentLabels: []string{"docker"}, + LastOnline: timeutil.TimeStampNow(), + LastActive: timeutil.TimeStampNow().AddDuration(-actions_model.RunnerIdleTime), + }, + expectedStatus: api.RunnerStatusIdle, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + actionRunner, err := ToActionRunner(&testCase.runner) + + require.NoError(t, err) + assert.Equal(t, testCase.runner.ID, actionRunner.ID) + assert.Equal(t, testCase.runner.Name, actionRunner.Name) + assert.Equal(t, testCase.runner.UUID, actionRunner.UUID) + assert.Equal(t, testCase.runner.OwnerID, actionRunner.OwnerID) + assert.Equal(t, testCase.runner.RepoID, actionRunner.RepoID) + assert.Equal(t, testCase.runner.Version, actionRunner.Version) + assert.Equal(t, testCase.runner.Description, actionRunner.Description) + assert.Equal(t, testCase.expectedStatus.String(), actionRunner.Status) + assert.Equal(t, testCase.runner.AgentLabels, actionRunner.Labels) + }) + } +} diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 3a75d53ba1..1e81d03469 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -319,11 +319,11 @@ "tags": [ "admin" ], - "summary": "Get all runners", + "summary": "Get all runners, no matter whether they are global runners or scoped to an organization, user, or repository", "operationId": "getAdminRunners", "responses": { "200": { - "$ref": "#/definitions/ActionRunnersResponse" + "$ref": "#/responses/ActionRunnerList" }, "400": { "$ref": "#/responses/error" @@ -334,23 +334,6 @@ } } }, - "/admin/actions/runners/registration-token": { - "post": { - "produces": [ - "application/json" - ], - "tags": [ - "admin" - ], - "summary": "Get a global actions runner registration token", - "operationId": "adminCreateRunnerRegistrationToken", - "responses": { - "200": { - "$ref": "#/responses/RegistrationToken" - } - } - } - }, "/admin/actions/runners/{runner_id}": { "get": { "produces": [ @@ -359,12 +342,12 @@ "tags": [ "admin" ], - "summary": "Get a global runner", + "summary": "Get a particular runner, no matter whether it is a global runner or scoped to an organization, user, or repository", "operationId": "getAdminRunner", "parameters": [ { "type": "string", - "description": "id of the runner", + "description": "ID of the runner", "name": "runner_id", "in": "path", "required": true @@ -372,7 +355,7 @@ ], "responses": { "200": { - "$ref": "#/definitions/ActionRunner" + "$ref": "#/responses/ActionRunner" }, "400": { "$ref": "#/responses/error" @@ -389,12 +372,12 @@ "tags": [ "admin" ], - "summary": "Delete a global runner", + "summary": "Delete a particular runner, no matter whether it is a global runner or scoped to an organization, user, or repository", "operationId": "deleteAdminRunner", "parameters": [ { "type": "string", - "description": "id of the runner", + "description": "ID of the runner", "name": "runner_id", "in": "path", "required": true @@ -1245,7 +1228,7 @@ "tags": [ "admin" ], - "summary": "Search action jobs according filter conditions", + "summary": "Search action jobs according to filter conditions", "operationId": "adminSearchRunJobs", "parameters": [ { @@ -1273,7 +1256,7 @@ "tags": [ "admin" ], - "summary": "Get a global actions runner registration token", + "summary": "Get a runner registration token for registering global runners", "operationId": "adminGetRunnerRegistrationToken", "responses": { "200": { @@ -2635,7 +2618,7 @@ "tags": [ "organization" ], - "summary": "Get org-level runners", + "summary": "Get the organization's runners", "operationId": "getOrgRunners", "parameters": [ { @@ -2648,7 +2631,7 @@ ], "responses": { "200": { - "$ref": "#/definitions/ActionRunnersResponse" + "$ref": "#/responses/ActionRunnerList" }, "400": { "$ref": "#/responses/error" @@ -2702,7 +2685,7 @@ "tags": [ "organization" ], - "summary": "Get an organization's actions runner registration token", + "summary": "Get the organization's runner registration token", "operationId": "orgGetRunnerRegistrationToken", "parameters": [ { @@ -2718,30 +2701,6 @@ "$ref": "#/responses/RegistrationToken" } } - }, - "post": { - "produces": [ - "application/json" - ], - "tags": [ - "organization" - ], - "summary": "Get an organization's actions runner registration token", - "operationId": "orgCreateRunnerRegistrationToken", - "parameters": [ - { - "type": "string", - "description": "name of the organization", - "name": "org", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "$ref": "#/responses/RegistrationToken" - } - } } }, "/orgs/{org}/actions/runners/{runner_id}": { @@ -2752,7 +2711,7 @@ "tags": [ "organization" ], - "summary": "Get an org-level runner", + "summary": "Get a particular runner that belongs to the organization", "operationId": "getOrgRunner", "parameters": [ { @@ -2764,7 +2723,7 @@ }, { "type": "string", - "description": "id of the runner", + "description": "ID of the runner", "name": "runner_id", "in": "path", "required": true @@ -2772,7 +2731,7 @@ ], "responses": { "200": { - "$ref": "#/definitions/ActionRunner" + "$ref": "#/responses/ActionRunner" }, "400": { "$ref": "#/responses/error" @@ -2789,7 +2748,7 @@ "tags": [ "organization" ], - "summary": "Delete an org-level runner", + "summary": "Delete a particular runner that belongs to the organization", "operationId": "deleteOrgRunner", "parameters": [ { @@ -2801,7 +2760,7 @@ }, { "type": "string", - "description": "id of the runner", + "description": "ID of the runner", "name": "runner_id", "in": "path", "required": true @@ -5333,7 +5292,7 @@ "tags": [ "repository" ], - "summary": "Get repo-level runners", + "summary": "Get runners belonging to the repository", "operationId": "getRepoRunners", "parameters": [ { @@ -5353,7 +5312,7 @@ ], "responses": { "200": { - "$ref": "#/definitions/ActionRunnersResponse" + "$ref": "#/responses/ActionRunnerList" }, "400": { "$ref": "#/responses/error" @@ -5414,7 +5373,7 @@ "tags": [ "repository" ], - "summary": "Get a repository's actions runner registration token", + "summary": "Get a repository's runner registration token", "operationId": "repoGetRunnerRegistrationToken", "parameters": [ { @@ -5437,37 +5396,6 @@ "$ref": "#/responses/RegistrationToken" } } - }, - "post": { - "produces": [ - "application/json" - ], - "tags": [ - "repository" - ], - "summary": "Get a repository's actions runner registration token", - "operationId": "repoCreateRunnerRegistrationToken", - "parameters": [ - { - "type": "string", - "description": "owner of the repo", - "name": "owner", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "name of the repo", - "name": "repo", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "$ref": "#/responses/RegistrationToken" - } - } } }, "/repos/{owner}/{repo}/actions/runners/{runner_id}": { @@ -5478,7 +5406,7 @@ "tags": [ "repository" ], - "summary": "Get a repo-level runner", + "summary": "Get a particular runner that belongs to the repository", "operationId": "getRepoRunner", "parameters": [ { @@ -5497,7 +5425,7 @@ }, { "type": "string", - "description": "id of the runner", + "description": "ID of the runner", "name": "runner_id", "in": "path", "required": true @@ -5505,7 +5433,7 @@ ], "responses": { "200": { - "$ref": "#/definitions/ActionRunner" + "$ref": "#/responses/ActionRunner" }, "400": { "$ref": "#/responses/error" @@ -5522,7 +5450,7 @@ "tags": [ "repository" ], - "summary": "Delete a repo-level runner", + "summary": "Delete a particular runner that belongs to a repository", "operationId": "deleteRepoRunner", "parameters": [ { @@ -5541,7 +5469,7 @@ }, { "type": "string", - "description": "id of the runner", + "description": "ID of the runner", "name": "runner_id", "in": "path", "required": true @@ -18807,11 +18735,11 @@ "tags": [ "user" ], - "summary": "Get user-level runners", + "summary": "Get the user's runners", "operationId": "getUserRunners", "responses": { "200": { - "$ref": "#/responses/ActionRunnersResponse" + "$ref": "#/responses/ActionRunnerList" }, "400": { "$ref": "#/responses/error" @@ -18864,7 +18792,7 @@ "tags": [ "user" ], - "summary": "Get an user's actions runner registration token", + "summary": "Get the user's runner registration token", "operationId": "userGetRunnerRegistrationToken", "responses": { "200": { @@ -18877,24 +18805,6 @@ "$ref": "#/responses/forbidden" } } - }, - "post": { - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Get an user's actions runner registration token", - "operationId": "userCreateRunnerRegistrationToken", - "responses": { - "200": { - "$ref": "#/responses/RegistrationToken" - }, - "401": { - "$ref": "#/responses/unauthorized" - } - } } }, "/user/actions/runners/{runner_id}": { @@ -18905,12 +18815,12 @@ "tags": [ "user" ], - "summary": "Get an user-level runner", + "summary": "Get a particular runner that belongs to the user", "operationId": "getUserRunner", "parameters": [ { "type": "string", - "description": "id of the runner", + "description": "ID of the runner", "name": "runner_id", "in": "path", "required": true @@ -18938,12 +18848,12 @@ "tags": [ "user" ], - "summary": "Delete an user-level runner", + "summary": "Delete a particular user-level runner", "operationId": "deleteUserRunner", "parameters": [ { "type": "string", - "description": "id of the runner", + "description": "ID of the runner", "name": "runner_id", "in": "path", "required": true @@ -22181,76 +22091,64 @@ "x-go-package": "forgejo.org/modules/structs" }, "ActionRunner": { - "description": "ActionRunner represents a Runner", + "description": "ActionRunner represents a runner", "type": "object", "properties": { - "busy": { - "type": "boolean", - "x-go-name": "Busy" - }, - "ephemeral": { - "description": "currently unused as forgejo does not support ephemeral runners, but they are defined in gh api spec", - "type": "boolean", - "x-go-name": "Ephemeral" + "description": { + "description": "Description provides optional details about this runner.", + "type": "string", + "x-go-name": "Description" }, "id": { + "description": "ID uniquely identifies this runner.", "type": "integer", "format": "int64", "x-go-name": "ID" }, "labels": { + "description": "Labels is a list of labels attached to this runner.", "type": "array", "items": { - "$ref": "#/definitions/ActionRunnerLabel" + "type": "string" }, "x-go-name": "Labels" }, "name": { + "description": "Name of the runner; not unique.", "type": "string", "x-go-name": "Name" }, + "owner_id": { + "description": "OwnerID is the identifier of the user or organization this runner belongs to. O if the runner is owned by a\nrepository.", + "type": "integer", + "format": "int64", + "x-go-name": "OwnerID" + }, + "repo_id": { + "description": "RepoID is the identifier of the repository this runner belongs to. 0 if the runner belongs to a user or\norganization.", + "type": "integer", + "format": "int64", + "x-go-name": "RepoID" + }, "status": { + "description": "Status indicates whether this runner is offline, or active, for example.", "type": "string", + "enum": [ + "offline", + "idle", + "active" + ], "x-go-name": "Status" - } - }, - "x-go-package": "forgejo.org/modules/structs" - }, - "ActionRunnerLabel": { - "description": "ActionRunnerLabel represents a Runner Label", - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64", - "x-go-name": "ID" }, - "name": { + "uuid": { + "description": "UUID uniquely identifies this runner.", "type": "string", - "x-go-name": "Name" + "x-go-name": "UUID" }, - "type": { + "version": { + "description": "Version is the self-reported version string of Forgejo Runner.", "type": "string", - "x-go-name": "Type" - } - }, - "x-go-package": "forgejo.org/modules/structs" - }, - "ActionRunnersResponse": { - "description": "ActionRunnersResponse returns Runners", - "type": "object", - "properties": { - "runners": { - "type": "array", - "items": { - "$ref": "#/definitions/ActionRunner" - }, - "x-go-name": "Entries" - }, - "total_count": { - "type": "integer", - "format": "int64", - "x-go-name": "TotalCount" + "x-go-name": "Version" } }, "x-go-package": "forgejo.org/modules/structs" @@ -29939,15 +29837,18 @@ } }, "ActionRunner": { - "description": "ActionRunner represents a Runner", + "description": "ActionRunner represents a runner", "schema": { "$ref": "#/definitions/ActionRunner" } }, - "ActionRunnersResponse": { - "description": "ActionRunnersResponse returns Runners", + "ActionRunnerList": { + "description": "ActionRunnerList is a list of Forgejo Action runners", "schema": { - "$ref": "#/definitions/ActionRunnersResponse" + "type": "array", + "items": { + "$ref": "#/definitions/ActionRunner" + } } }, "ActionVariable": { diff --git a/tests/integration/actions_job_test.go b/tests/integration/actions_job_test.go index 262358ab9f..baa1420bdd 100644 --- a/tests/integration/actions_job_test.go +++ b/tests/integration/actions_job_test.go @@ -175,36 +175,6 @@ jobs: }) } -func TestRunnerLifecycleGithubEndpoints(t *testing.T) { - if !setting.Database.Type.IsSQLite3() { - // registering a mock runner when using a database other than SQLite leaves leftovers - t.Skip() - } - onApplicationRun(t, func(t *testing.T, u *url.URL) { - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - session := loginUser(t, user2.Name) - token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) - - apiRepo := createActionsTestRepo(t, token, "actions-runner-registration-with-get", false) - runner := newMockRunner() - runner.registerAsRepoRunnerWithPost(t, user2.Name, apiRepo.Name, "mock-runner", []string{"ubuntu-latest"}) - runnersList := runner.listRunners(t, user2.Name, apiRepo.Name) - - assert.NotNil(t, runnersList) - assert.Len(t, runnersList.Entries, 1) - assert.Equal(t, "mock-runner", runnersList.Entries[0].Name) - - runnerDetails := runner.getRunner(t, user2.Name, apiRepo.Name, runnersList.Entries[0].ID) - assert.Equal(t, "mock-runner", runnerDetails.Name) - assert.Equal(t, runnersList.Entries[0].ID, runnerDetails.ID) - - runner.deleteRunner(t, user2.Name, apiRepo.Name, runnersList.Entries[0].ID) - - httpContext := NewAPITestContext(t, user2.Name, apiRepo.Name, auth_model.AccessTokenScopeWriteRepository) - doAPIDeleteRepository(httpContext)(t) - }) -} - func TestActionsJobNeedsMatrix(t *testing.T) { if !setting.Database.Type.IsSQLite3() { t.Skip() diff --git a/tests/integration/actions_runner_test.go b/tests/integration/actions_runner_test.go index 0eb2117325..6cedaf6def 100644 --- a/tests/integration/actions_runner_test.go +++ b/tests/integration/actions_runner_test.go @@ -12,7 +12,6 @@ import ( auth_model "forgejo.org/models/auth" "forgejo.org/modules/setting" - "forgejo.org/modules/structs" pingv1 "code.forgejo.org/forgejo/actions-proto/ping/v1" "code.forgejo.org/forgejo/actions-proto/ping/v1/pingv1connect" @@ -97,61 +96,6 @@ func (r *mockRunner) registerAsRepoRunner(t *testing.T, ownerName, repoName, run r.doRegister(t, runnerName, registrationToken.Token, labels) } -func (r *mockRunner) registerAsRepoRunnerWithPost(t *testing.T, ownerName, repoName, runnerName string, labels []string) { - if !setting.Database.Type.IsSQLite3() { - // registering a mock runner when using a database other than SQLite leaves leftovers - t.FailNow() - } - session := loginUser(t, ownerName) - token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) - req := NewRequest(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/actions/runners/registration-token", ownerName, repoName)).AddTokenAuth(token) - resp := MakeRequest(t, req, http.StatusOK) - var registrationToken struct { - Token string `json:"token"` - } - DecodeJSON(t, resp, ®istrationToken) - r.doRegister(t, runnerName, registrationToken.Token, labels) -} - -func (r *mockRunner) listRunners(t *testing.T, ownerName, repoName string) structs.ActionRunnersResponse { - if !setting.Database.Type.IsSQLite3() { - // registering a mock runner when using a database other than SQLite leaves leftovers - t.FailNow() - } - session := loginUser(t, ownerName) - token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadRepository) - req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/actions/runners", ownerName, repoName)).AddTokenAuth(token) - resp := MakeRequest(t, req, http.StatusOK) - var runnersList structs.ActionRunnersResponse - DecodeJSON(t, resp, &runnersList) - return runnersList -} - -func (r *mockRunner) getRunner(t *testing.T, ownerName, repoName string, runnerID int64) structs.ActionRunner { - if !setting.Database.Type.IsSQLite3() { - // registering a mock runner when using a database other than SQLite leaves leftovers - t.FailNow() - } - session := loginUser(t, ownerName) - token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadRepository) - req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/actions/runners/%d", ownerName, repoName, runnerID)).AddTokenAuth(token) - resp := MakeRequest(t, req, http.StatusOK) - var runner structs.ActionRunner - DecodeJSON(t, resp, &runner) - return runner -} - -func (r *mockRunner) deleteRunner(t *testing.T, ownerName, repoName string, runnerID int64) { - if !setting.Database.Type.IsSQLite3() { - // registering a mock runner when using a database other than SQLite leaves leftovers - t.FailNow() - } - session := loginUser(t, ownerName) - token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) - req := NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/repos/%s/%s/actions/runners/%d", ownerName, repoName, runnerID)).AddTokenAuth(token) - MakeRequest(t, req, http.StatusNoContent) -} - func (r *mockRunner) maybeFetchTask(t *testing.T) *runnerv1.Task { resp, err := r.client.runnerServiceClient.FetchTask(t.Context(), connect.NewRequest(&runnerv1.FetchTaskRequest{ TasksVersion: r.lastTasksVersion, diff --git a/tests/integration/api_admin_actions_test.go b/tests/integration/api_admin_actions_test.go index 52c68098a4..1c03d66b7a 100644 --- a/tests/integration/api_admin_actions_test.go +++ b/tests/integration/api_admin_actions_test.go @@ -11,10 +11,13 @@ import ( actions_model "forgejo.org/models/actions" auth_model "forgejo.org/models/auth" "forgejo.org/models/unittest" + user_model "forgejo.org/models/user" api "forgejo.org/modules/structs" + "forgejo.org/routers/api/v1/shared" "forgejo.org/tests" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestActionsAPISearchActionJobs_GlobalRunner(t *testing.T) { @@ -91,3 +94,164 @@ func TestActionsAPISearchActionJobs_GlobalRunnerAllPendingJobs(t *testing.T) { assert.Equal(t, job198.ID, jobs[5].ID) assert.Equal(t, job196.ID, jobs[6].ID) } + +func TestAPIGlobalActionsRunnerRegistrationTokenOperations(t *testing.T) { + defer unittest.OverrideFixtures("tests/integration/fixtures/TestAPIGlobalActionsRunnerRegistrationTokenOperations")() + require.NoError(t, unittest.PrepareTestDatabase()) + + user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) + session := loginUser(t, user1.Name) + readToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadAdmin) + + t.Run("GetRegistrationToken", func(t *testing.T) { + request := NewRequest(t, "GET", "/api/v1/admin/actions/runners/registration-token") + request.AddTokenAuth(readToken) + response := MakeRequest(t, request, http.StatusOK) + + var registrationToken shared.RegistrationToken + DecodeJSON(t, response, ®istrationToken) + + expected := shared.RegistrationToken{Token: "BzcgyhjWhLeKGA4ihJIigeRDrcxrFESd0yizEpb7xZJ"} + + assert.Equal(t, expected, registrationToken) + }) +} + +func TestAPIGlobalActionsRunnerOperations(t *testing.T) { + defer unittest.OverrideFixtures("tests/integration/fixtures/TestAPIGlobalActionsRunnerOperations")() + require.NoError(t, unittest.PrepareTestDatabase()) + + user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) + session := loginUser(t, user1.Name) + readToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadAdmin) + writeToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin) + + t.Run("GetRunners", func(t *testing.T) { + request := NewRequest(t, "GET", "/api/v1/admin/actions/runners") + request.AddTokenAuth(readToken) + response := MakeRequest(t, request, http.StatusOK) + + assert.NotEmpty(t, response.Header().Get("X-Total-Count")) + + var runners []*api.ActionRunner + DecodeJSON(t, response, &runners) + + runnerOne := &api.ActionRunner{ + ID: 130791, + UUID: "8b0f6b98-fef8-430e-bfdc-dcbeeb58f3c8", + Name: "runner-1-global", + Version: "dev", + OwnerID: 0, + RepoID: 0, + Description: "A superb runner", + Labels: []string{"debian", "gpu"}, + Status: "offline", + } + runnerTwo := &api.ActionRunner{ + ID: 130792, + UUID: "61c48447-6e7d-42da-9dbe-d659ade77a56", + Name: "runner-2-user", + Version: "11.3.1", + OwnerID: 1, + RepoID: 0, + Description: "A splendid runner", + Labels: []string{"docker"}, + Status: "offline", + } + runnerThree := &api.ActionRunner{ + ID: 130793, + UUID: "9b92be13-b002-4fc0-b182-5e7cdbef0b8d", + Name: "runner-3-global", + Version: "11.3.1", + OwnerID: 0, + RepoID: 0, + Description: "Another fine runner", + Labels: []string{"fedora"}, + Status: "offline", + } + + // There are more runners in the result that originate from the global fixtures. The test ignores them to limit + // the impact of unrelated changes. + assert.Contains(t, runners, runnerOne) + assert.Contains(t, runners, runnerTwo) + assert.Contains(t, runners, runnerThree) + }) + + t.Run("GetGlobalRunner", func(t *testing.T) { + request := NewRequest(t, "GET", "/api/v1/admin/actions/runners/130793") + request.AddTokenAuth(readToken) + response := MakeRequest(t, request, http.StatusOK) + + var runner *api.ActionRunner + DecodeJSON(t, response, &runner) + + runnerOne := &api.ActionRunner{ + ID: 130793, + UUID: "9b92be13-b002-4fc0-b182-5e7cdbef0b8d", + Name: "runner-3-global", + Version: "11.3.1", + OwnerID: 0, + RepoID: 0, + Description: "Another fine runner", + Labels: []string{"fedora"}, + Status: "offline", + } + + assert.Equal(t, runnerOne, runner) + }) + + t.Run("GetRepositoryScopedRunner", func(t *testing.T) { + request := NewRequest(t, "GET", "/api/v1/admin/actions/runners/130794") + request.AddTokenAuth(readToken) + response := MakeRequest(t, request, http.StatusOK) + + var runner *api.ActionRunner + DecodeJSON(t, response, &runner) + + runnerFour := &api.ActionRunner{ + ID: 130794, + UUID: "44d595e9-b47d-42ef-b1b9-5869f8b8d501", + Name: "runner-4-repository", + Version: "12.2.0", + OwnerID: 0, + RepoID: 62, + Description: "", + Labels: []string{"nixos"}, + Status: "offline", + } + + assert.Equal(t, runnerFour, runner) + }) + + t.Run("DeleteGlobalRunner", func(t *testing.T) { + url := "/api/v1/admin/actions/runners/130791" + + request := NewRequest(t, "GET", url) + request.AddTokenAuth(readToken) + MakeRequest(t, request, http.StatusOK) + + deleteRequest := NewRequest(t, "DELETE", url) + deleteRequest.AddTokenAuth(writeToken) + MakeRequest(t, deleteRequest, http.StatusNoContent) + + request = NewRequest(t, "GET", url) + request.AddTokenAuth(readToken) + MakeRequest(t, request, http.StatusNotFound) + }) + + t.Run("DeleteRepositoryScopedRunner", func(t *testing.T) { + url := "/api/v1/admin/actions/runners/130794" + + request := NewRequest(t, "GET", url) + request.AddTokenAuth(readToken) + MakeRequest(t, request, http.StatusOK) + + deleteRequest := NewRequest(t, "DELETE", url) + deleteRequest.AddTokenAuth(writeToken) + MakeRequest(t, deleteRequest, http.StatusNoContent) + + request = NewRequest(t, "GET", url) + request.AddTokenAuth(readToken) + MakeRequest(t, request, http.StatusNotFound) + }) +} diff --git a/tests/integration/api_org_actions_test.go b/tests/integration/api_org_actions_test.go index 9a5eabc81a..3d5fb3e50c 100644 --- a/tests/integration/api_org_actions_test.go +++ b/tests/integration/api_org_actions_test.go @@ -11,10 +11,13 @@ import ( actions_model "forgejo.org/models/actions" auth_model "forgejo.org/models/auth" "forgejo.org/models/unittest" + user_model "forgejo.org/models/user" api "forgejo.org/modules/structs" + "forgejo.org/routers/api/v1/shared" "forgejo.org/tests" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestActionsAPISearchActionJobs_OrgRunner(t *testing.T) { @@ -76,3 +79,110 @@ func TestActionsAPISearchActionJobs_OrgRunnerAllPendingJobs(t *testing.T) { assert.Equal(t, job397.ID, jobs[0].ID) assert.Equal(t, job395.ID, jobs[1].ID) } + +func TestAPIOrgActionsRunnerRegistrationTokenOperations(t *testing.T) { + defer unittest.OverrideFixtures("tests/integration/fixtures/TestAPIOrgActionsRunnerRegistrationTokenOperations")() + require.NoError(t, unittest.PrepareTestDatabase()) + + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + session := loginUser(t, user2.Name) + readToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadOrganization) + + t.Run("GetRegistrationToken", func(t *testing.T) { + request := NewRequest(t, "GET", "/api/v1/orgs/org3/actions/runners/registration-token") + request.AddTokenAuth(readToken) + response := MakeRequest(t, request, http.StatusOK) + + var registrationToken shared.RegistrationToken + DecodeJSON(t, response, ®istrationToken) + + expected := shared.RegistrationToken{Token: "Sk9wHjBHelH4n1ckQy-mo3KVYRdoaPZ_aaH1ATfgI05"} + + assert.Equal(t, expected, registrationToken) + }) +} + +func TestAPIOrgActionsRunnerOperations(t *testing.T) { + defer unittest.OverrideFixtures("tests/integration/fixtures/TestAPIOrgActionsRunnerOperations")() + require.NoError(t, unittest.PrepareTestDatabase()) + + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + session := loginUser(t, user2.Name) + readToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadOrganization) + writeToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteOrganization) + + t.Run("GetRunners", func(t *testing.T) { + request := NewRequest(t, "GET", "/api/v1/orgs/org3/actions/runners") + request.AddTokenAuth(readToken) + response := MakeRequest(t, request, http.StatusOK) + + assert.Equal(t, "2", response.Header().Get("X-Total-Count")) + + var runners []*api.ActionRunner + DecodeJSON(t, response, &runners) + + runnerOne := &api.ActionRunner{ + ID: 655691, + UUID: "a3297f3a-ba5c-4a0f-878e-6cc8b8ac79ec", + Name: "runner-1-organization", + Version: "dev", + OwnerID: 3, + RepoID: 0, + Description: "A superb runner", + Labels: []string{"debian", "gpu"}, + Status: "offline", + } + runnerThree := &api.ActionRunner{ + ID: 655693, + UUID: "0a7e5e05-2da4-44d5-a72a-615da120cef6", + Name: "runner-3-organization", + Version: "11.3.1", + OwnerID: 3, + RepoID: 0, + Description: "Another fine runner", + Labels: []string{"fedora"}, + Status: "offline", + } + + assert.ElementsMatch(t, []*api.ActionRunner{runnerOne, runnerThree}, runners) + }) + + t.Run("GetRunner", func(t *testing.T) { + request := NewRequest(t, "GET", "/api/v1/orgs/org3/actions/runners/655691") + request.AddTokenAuth(readToken) + response := MakeRequest(t, request, http.StatusOK) + + var runner *api.ActionRunner + DecodeJSON(t, response, &runner) + + runnerOne := &api.ActionRunner{ + ID: 655691, + UUID: "a3297f3a-ba5c-4a0f-878e-6cc8b8ac79ec", + Name: "runner-1-organization", + Version: "dev", + OwnerID: 3, + RepoID: 0, + Description: "A superb runner", + Labels: []string{"debian", "gpu"}, + Status: "offline", + } + + assert.Equal(t, runnerOne, runner) + }) + + t.Run("DeleteRunner", func(t *testing.T) { + url := "/api/v1/orgs/org3/actions/runners/655691" + + request := NewRequest(t, "GET", url) + request.AddTokenAuth(readToken) + MakeRequest(t, request, http.StatusOK) + + deleteRequest := NewRequest(t, "DELETE", url) + deleteRequest.AddTokenAuth(writeToken) + MakeRequest(t, deleteRequest, http.StatusNoContent) + + request = NewRequest(t, "GET", url) + request.AddTokenAuth(readToken) + MakeRequest(t, request, http.StatusNotFound) + }) +} diff --git a/tests/integration/api_repo_actions_test.go b/tests/integration/api_repo_actions_test.go index ae2591c0a8..9c8be4156a 100644 --- a/tests/integration/api_repo_actions_test.go +++ b/tests/integration/api_repo_actions_test.go @@ -19,6 +19,7 @@ import ( user_model "forgejo.org/models/user" api "forgejo.org/modules/structs" "forgejo.org/modules/webhook" + "forgejo.org/routers/api/v1/shared" files_service "forgejo.org/services/repository/files" "forgejo.org/tests" @@ -351,3 +352,110 @@ func TestActionsAPIGetActionRun(t *testing.T) { }) } } + +func TestAPIRepoActionsRunnerRegistrationTokenOperations(t *testing.T) { + defer unittest.OverrideFixtures("tests/integration/fixtures/TestAPIRepoActionsRunnerRegistrationTokenOperations")() + require.NoError(t, unittest.PrepareTestDatabase()) + + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + session := loginUser(t, user2.Name) + readToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadRepository) + + t.Run("GetRegistrationToken", func(t *testing.T) { + request := NewRequest(t, "GET", "/api/v1/repos/user2/test_workflows/actions/runners/registration-token") + request.AddTokenAuth(readToken) + response := MakeRequest(t, request, http.StatusOK) + + var registrationToken shared.RegistrationToken + DecodeJSON(t, response, ®istrationToken) + + expected := shared.RegistrationToken{Token: "BzcgyhjWhLeKGA4ihJIigeRDrcxrFESd0yizEpb7xZJ"} + + assert.Equal(t, expected, registrationToken) + }) +} + +func TestAPIRepoActionsRunnerOperations(t *testing.T) { + defer unittest.OverrideFixtures("tests/integration/fixtures/TestAPIRepoActionsRunnerOperations")() + require.NoError(t, unittest.PrepareTestDatabase()) + + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + session := loginUser(t, user2.Name) + readToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadRepository) + writeToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) + + t.Run("GetRunners", func(t *testing.T) { + request := NewRequest(t, "GET", "/api/v1/repos/user2/test_workflows/actions/runners") + request.AddTokenAuth(readToken) + response := MakeRequest(t, request, http.StatusOK) + + assert.Equal(t, "2", response.Header().Get("X-Total-Count")) + + var runners []*api.ActionRunner + DecodeJSON(t, response, &runners) + + runnerOne := &api.ActionRunner{ + ID: 899251, + UUID: "a3297f3a-ba5c-4a0f-878e-6cc8b8ac79ec", + Name: "runner-1-repository", + Version: "dev", + OwnerID: 0, + RepoID: 62, + Description: "A superb runner", + Labels: []string{"debian", "gpu"}, + Status: "offline", + } + runnerThree := &api.ActionRunner{ + ID: 899253, + UUID: "0a7e5e05-2da4-44d5-a72a-615da120cef6", + Name: "runner-3-repository", + Version: "11.3.1", + OwnerID: 0, + RepoID: 62, + Description: "Another fine runner", + Labels: []string{"fedora"}, + Status: "offline", + } + + assert.ElementsMatch(t, []*api.ActionRunner{runnerOne, runnerThree}, runners) + }) + + t.Run("GetRunner", func(t *testing.T) { + request := NewRequest(t, "GET", "/api/v1/repos/user2/test_workflows/actions/runners/899251") + request.AddTokenAuth(readToken) + response := MakeRequest(t, request, http.StatusOK) + + var runner *api.ActionRunner + DecodeJSON(t, response, &runner) + + runnerOne := &api.ActionRunner{ + ID: 899251, + UUID: "a3297f3a-ba5c-4a0f-878e-6cc8b8ac79ec", + Name: "runner-1-repository", + Version: "dev", + OwnerID: 0, + RepoID: 62, + Description: "A superb runner", + Labels: []string{"debian", "gpu"}, + Status: "offline", + } + + assert.Equal(t, runnerOne, runner) + }) + + t.Run("DeleteRunner", func(t *testing.T) { + url := "/api/v1/repos/user2/test_workflows/actions/runners/899253" + + request := NewRequest(t, "GET", url) + request.AddTokenAuth(readToken) + MakeRequest(t, request, http.StatusOK) + + deleteRequest := NewRequest(t, "DELETE", url) + deleteRequest.AddTokenAuth(writeToken) + MakeRequest(t, deleteRequest, http.StatusNoContent) + + request = NewRequest(t, "GET", url) + request.AddTokenAuth(readToken) + MakeRequest(t, request, http.StatusNotFound) + }) +} diff --git a/tests/integration/api_user_actions_test.go b/tests/integration/api_user_actions_test.go index 40cf39b2d7..876fd14bbf 100644 --- a/tests/integration/api_user_actions_test.go +++ b/tests/integration/api_user_actions_test.go @@ -11,10 +11,13 @@ import ( actions_model "forgejo.org/models/actions" auth_model "forgejo.org/models/auth" "forgejo.org/models/unittest" + user_model "forgejo.org/models/user" api "forgejo.org/modules/structs" + "forgejo.org/routers/api/v1/shared" "forgejo.org/tests" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestActionsAPISearchActionJobs_UserRunner(t *testing.T) { @@ -74,3 +77,110 @@ func TestActionsAPISearchActionJobs_UserRunnerAllPendingJobs(t *testing.T) { assert.Len(t, jobs, 1) assert.Equal(t, job.ID, jobs[0].ID) } + +func TestAPIUserActionsRunnerRegistrationTokenOperations(t *testing.T) { + defer unittest.OverrideFixtures("tests/integration/fixtures/TestAPIUserActionsRunnerRegistrationTokenOperations")() + require.NoError(t, unittest.PrepareTestDatabase()) + + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + session := loginUser(t, user2.Name) + readToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadUser) + + t.Run("GetRegistrationToken", func(t *testing.T) { + request := NewRequest(t, "GET", "/api/v1/user/actions/runners/registration-token") + request.AddTokenAuth(readToken) + response := MakeRequest(t, request, http.StatusOK) + + var registrationToken shared.RegistrationToken + DecodeJSON(t, response, ®istrationToken) + + expected := shared.RegistrationToken{Token: "Xb3WmQBum2S0-WwFY399A0DhnPkgRdXzpEOJaMmL5UT"} + + assert.Equal(t, expected, registrationToken) + }) +} + +func TestAPIUserActionsRunnerOperations(t *testing.T) { + defer unittest.OverrideFixtures("tests/integration/fixtures/TestAPIUserActionsRunnerOperations")() + require.NoError(t, unittest.PrepareTestDatabase()) + + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + session := loginUser(t, user2.Name) + readToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadUser) + writeToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteUser) + + t.Run("GetRunners", func(t *testing.T) { + request := NewRequest(t, "GET", "/api/v1/user/actions/runners") + request.AddTokenAuth(readToken) + response := MakeRequest(t, request, http.StatusOK) + + assert.Equal(t, "2", response.Header().Get("X-Total-Count")) + + var runners []*api.ActionRunner + DecodeJSON(t, response, &runners) + + runnerOne := &api.ActionRunner{ + ID: 71301, + UUID: "99fc4a58-a25e-4dbe-b6ea-3d55dddcd216", + Name: "runner-1-user", + Version: "dev", + OwnerID: 2, + RepoID: 0, + Description: "A superb runner", + Labels: []string{"debian", "gpu"}, + Status: "offline", + } + runnerThree := &api.ActionRunner{ + ID: 71303, + UUID: "70bc0da3-35b2-4129-bbc9-4679dfdda4d0", + Name: "runner-3-user", + Version: "11.3.1", + OwnerID: 2, + RepoID: 0, + Description: "Another fine runner", + Labels: []string{"fedora"}, + Status: "offline", + } + + assert.ElementsMatch(t, []*api.ActionRunner{runnerOne, runnerThree}, runners) + }) + + t.Run("GetRunner", func(t *testing.T) { + request := NewRequest(t, "GET", "/api/v1/user/actions/runners/71303") + request.AddTokenAuth(readToken) + response := MakeRequest(t, request, http.StatusOK) + + var runner *api.ActionRunner + DecodeJSON(t, response, &runner) + + runnerThree := &api.ActionRunner{ + ID: 71303, + UUID: "70bc0da3-35b2-4129-bbc9-4679dfdda4d0", + Name: "runner-3-user", + Version: "11.3.1", + OwnerID: 2, + RepoID: 0, + Description: "Another fine runner", + Labels: []string{"fedora"}, + Status: "offline", + } + + assert.Equal(t, runnerThree, runner) + }) + + t.Run("DeleteRunner", func(t *testing.T) { + url := "/api/v1/user/actions/runners/71303" + + request := NewRequest(t, "GET", url) + request.AddTokenAuth(readToken) + MakeRequest(t, request, http.StatusOK) + + deleteRequest := NewRequest(t, "DELETE", url) + deleteRequest.AddTokenAuth(writeToken) + MakeRequest(t, deleteRequest, http.StatusNoContent) + + request = NewRequest(t, "GET", url) + request.AddTokenAuth(readToken) + MakeRequest(t, request, http.StatusNotFound) + }) +} diff --git a/tests/integration/fixtures/TestAPIGlobalActionsRunnerOperations/action_runner.yml b/tests/integration/fixtures/TestAPIGlobalActionsRunnerOperations/action_runner.yml new file mode 100644 index 0000000000..ef16984be0 --- /dev/null +++ b/tests/integration/fixtures/TestAPIGlobalActionsRunnerOperations/action_runner.yml @@ -0,0 +1,36 @@ +- id: 130791 + uuid: "8b0f6b98-fef8-430e-bfdc-dcbeeb58f3c8" + name: "runner-1-global" + version: "dev" + owner_id: 0 + repo_id: 0 + description: "A superb runner" + agent_labels: ["debian", "gpu"] + deleted: 0 +- id: 130792 + uuid: "61c48447-6e7d-42da-9dbe-d659ade77a56" + name: "runner-2-user" + version: "11.3.1" + owner_id: 1 + repo_id: 0 + description: "A splendid runner" + agent_labels: ["docker"] + deleted: 0 +- id: 130793 + uuid: "9b92be13-b002-4fc0-b182-5e7cdbef0b8d" + name: "runner-3-global" + version: "11.3.1" + owner_id: 0 + repo_id: 0 + description: "Another fine runner" + agent_labels: ["fedora"] + deleted: 0 +- id: 130794 + uuid: "44d595e9-b47d-42ef-b1b9-5869f8b8d501" + name: "runner-4-repository" + version: "12.2.0" + owner_id: 0 + repo_id: 62 + description: "" + agent_labels: ["nixos"] + deleted: 0 \ No newline at end of file diff --git a/tests/integration/fixtures/TestAPIGlobalActionsRunnerRegistrationTokenOperations/action_runner_token.yml b/tests/integration/fixtures/TestAPIGlobalActionsRunnerRegistrationTokenOperations/action_runner_token.yml new file mode 100644 index 0000000000..c0b5007417 --- /dev/null +++ b/tests/integration/fixtures/TestAPIGlobalActionsRunnerRegistrationTokenOperations/action_runner_token.yml @@ -0,0 +1,12 @@ +- id: 4691 + token: "BzcgyhjWhLeKGA4ihJIigeRDrcxrFESd0yizEpb7xZJ" + owner_id: 0 + repo_id: 0 + is_active: true + deleted: 0 +- id: 4692 + token: "Sk9wHjBHelH4n1ckQy-mo3KVYRdoaPZ_aaH1ATfgI05" + owner_id: 1 + repo_id: 0 + is_active: true + deleted: 0 diff --git a/tests/integration/fixtures/TestAPIOrgActionsRunnerOperations/action_runner.yml b/tests/integration/fixtures/TestAPIOrgActionsRunnerOperations/action_runner.yml new file mode 100644 index 0000000000..f39cac24be --- /dev/null +++ b/tests/integration/fixtures/TestAPIOrgActionsRunnerOperations/action_runner.yml @@ -0,0 +1,36 @@ +- id: 655691 + uuid: "a3297f3a-ba5c-4a0f-878e-6cc8b8ac79ec" + name: "runner-1-organization" + version: "dev" + owner_id: 3 + repo_id: 0 + description: "A superb runner" + agent_labels: ["debian", "gpu"] + deleted: 0 +- id: 655692 + uuid: "6d2d13ef-b19f-47a8-85ad-e82e51f606c5" + name: "runner-2-user" + version: "11.3.1" + owner_id: 1 + repo_id: 0 + description: "A splendid runner" + agent_labels: ["docker"] + deleted: 0 +- id: 655693 + uuid: "0a7e5e05-2da4-44d5-a72a-615da120cef6" + name: "runner-3-organization" + version: "11.3.1" + owner_id: 3 + repo_id: 0 + description: "Another fine runner" + agent_labels: ["fedora"] + deleted: 0 +- id: 655694 + uuid: "166c596c-5016-488d-bd55-b84e5a0460ea" + name: "runner-4-global" + version: "11.3.1" + owner_id: 0 + repo_id: 0 + description: "" + agent_labels: [] + deleted: 0 diff --git a/tests/integration/fixtures/TestAPIOrgActionsRunnerRegistrationTokenOperations/action_runner_token.yml b/tests/integration/fixtures/TestAPIOrgActionsRunnerRegistrationTokenOperations/action_runner_token.yml new file mode 100644 index 0000000000..2bd52feb31 --- /dev/null +++ b/tests/integration/fixtures/TestAPIOrgActionsRunnerRegistrationTokenOperations/action_runner_token.yml @@ -0,0 +1,12 @@ +- id: 3621 + token: "BzcgyhjWhLeKGA4ihJIigeRDrcxrFESd0yizEpb7xZJ" + owner_id: 1 + repo_id: 0 + is_active: true + deleted: 0 +- id: 3622 + token: "Sk9wHjBHelH4n1ckQy-mo3KVYRdoaPZ_aaH1ATfgI05" + owner_id: 3 + repo_id: 0 + is_active: true + deleted: 0 diff --git a/tests/integration/fixtures/TestAPIRepoActionsRunnerOperations/action_runner.yml b/tests/integration/fixtures/TestAPIRepoActionsRunnerOperations/action_runner.yml new file mode 100644 index 0000000000..1f1edb919e --- /dev/null +++ b/tests/integration/fixtures/TestAPIRepoActionsRunnerOperations/action_runner.yml @@ -0,0 +1,36 @@ +- id: 899251 + uuid: "a3297f3a-ba5c-4a0f-878e-6cc8b8ac79ec" + name: "runner-1-repository" + version: "dev" + owner_id: 0 + repo_id: 62 + description: "A superb runner" + agent_labels: ["debian", "gpu"] + deleted: 0 +- id: 899252 + uuid: "6d2d13ef-b19f-47a8-85ad-e82e51f606c5" + name: "runner-2-user" + version: "11.3.1" + owner_id: 1 + repo_id: 0 + description: "A splendid runner" + agent_labels: ["docker"] + deleted: 0 +- id: 899253 + uuid: "0a7e5e05-2da4-44d5-a72a-615da120cef6" + name: "runner-3-repository" + version: "11.3.1" + owner_id: 0 + repo_id: 62 + description: "Another fine runner" + agent_labels: ["fedora"] + deleted: 0 +- id: 899254 + uuid: "6456ac1f-70ec-4e8f-9ab7-bf117ee23d47" + name: "runner-4-global" + version: "11.3.1" + owner_id: 0 + repo_id: 0 + description: "" + agent_labels: [] + deleted: 0 diff --git a/tests/integration/fixtures/TestAPIRepoActionsRunnerRegistrationTokenOperations/action_runner_token.yml b/tests/integration/fixtures/TestAPIRepoActionsRunnerRegistrationTokenOperations/action_runner_token.yml new file mode 100644 index 0000000000..ec32b16bc6 --- /dev/null +++ b/tests/integration/fixtures/TestAPIRepoActionsRunnerRegistrationTokenOperations/action_runner_token.yml @@ -0,0 +1,12 @@ +- id: 3621 + token: "BzcgyhjWhLeKGA4ihJIigeRDrcxrFESd0yizEpb7xZJ" + owner_id: 0 + repo_id: 62 + is_active: true + deleted: 0 +- id: 3622 + token: "Sk9wHjBHelH4n1ckQy-mo3KVYRdoaPZ_aaH1ATfgI05" + owner_id: 0 + repo_id: 1 + is_active: true + deleted: 0 diff --git a/tests/integration/fixtures/TestAPIUserActionsRunnerOperations/action_runner.yml b/tests/integration/fixtures/TestAPIUserActionsRunnerOperations/action_runner.yml new file mode 100644 index 0000000000..be6ace174f --- /dev/null +++ b/tests/integration/fixtures/TestAPIUserActionsRunnerOperations/action_runner.yml @@ -0,0 +1,36 @@ +- id: 71301 + uuid: "99fc4a58-a25e-4dbe-b6ea-3d55dddcd216" + name: "runner-1-user" + version: "dev" + owner_id: 2 + repo_id: 0 + description: "A superb runner" + agent_labels: ["debian", "gpu"] + deleted: 0 +- id: 71302 + uuid: "9d32fe29-be59-4cd6-a97b-b6abb6937d47" + name: "runner-2-user" + version: "11.3.1" + owner_id: 1 + repo_id: 0 + description: "A splendid runner" + agent_labels: ["docker"] + deleted: 0 +- id: 71303 + uuid: "70bc0da3-35b2-4129-bbc9-4679dfdda4d0" + name: "runner-3-user" + version: "11.3.1" + owner_id: 2 + repo_id: 0 + description: "Another fine runner" + agent_labels: ["fedora"] + deleted: 0 +- id: 71304 + uuid: "3873c473-47b8-4559-9fa5-843277419780" + name: "runner-4-global" + version: "11.3.1" + owner_id: 0 + repo_id: 0 + description: "" + agent_labels: [] + deleted: 0 diff --git a/tests/integration/fixtures/TestAPIUserActionsRunnerRegistrationTokenOperations/action_runner_token.yml b/tests/integration/fixtures/TestAPIUserActionsRunnerRegistrationTokenOperations/action_runner_token.yml new file mode 100644 index 0000000000..dc0167cb77 --- /dev/null +++ b/tests/integration/fixtures/TestAPIUserActionsRunnerRegistrationTokenOperations/action_runner_token.yml @@ -0,0 +1,12 @@ +- id: 383951 + token: "xVkXTYaIFUdkTxgqnLaO4X4c-Mg2OKBBcaEo6S1hkZo" + owner_id: 1 + repo_id: 0 + is_active: true + deleted: 0 +- id: 383952 + token: "Xb3WmQBum2S0-WwFY399A0DhnPkgRdXzpEOJaMmL5UT" + owner_id: 2 + repo_id: 0 + is_active: true + deleted: 0