gitea源码

action.go 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. // Copyright 2024 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package org
  4. import (
  5. "errors"
  6. "net/http"
  7. actions_model "code.gitea.io/gitea/models/actions"
  8. "code.gitea.io/gitea/models/db"
  9. secret_model "code.gitea.io/gitea/models/secret"
  10. api "code.gitea.io/gitea/modules/structs"
  11. "code.gitea.io/gitea/modules/util"
  12. "code.gitea.io/gitea/modules/web"
  13. "code.gitea.io/gitea/routers/api/v1/shared"
  14. "code.gitea.io/gitea/routers/api/v1/utils"
  15. actions_service "code.gitea.io/gitea/services/actions"
  16. "code.gitea.io/gitea/services/context"
  17. secret_service "code.gitea.io/gitea/services/secrets"
  18. )
  19. // ListActionsSecrets list an organization's actions secrets
  20. func (Action) ListActionsSecrets(ctx *context.APIContext) {
  21. // swagger:operation GET /orgs/{org}/actions/secrets organization orgListActionsSecrets
  22. // ---
  23. // summary: List an organization's actions secrets
  24. // produces:
  25. // - application/json
  26. // parameters:
  27. // - name: org
  28. // in: path
  29. // description: name of the organization
  30. // type: string
  31. // required: true
  32. // - name: page
  33. // in: query
  34. // description: page number of results to return (1-based)
  35. // type: integer
  36. // - name: limit
  37. // in: query
  38. // description: page size of results
  39. // type: integer
  40. // responses:
  41. // "200":
  42. // "$ref": "#/responses/SecretList"
  43. // "404":
  44. // "$ref": "#/responses/notFound"
  45. opts := &secret_model.FindSecretsOptions{
  46. OwnerID: ctx.Org.Organization.ID,
  47. ListOptions: utils.GetListOptions(ctx),
  48. }
  49. secrets, count, err := db.FindAndCount[secret_model.Secret](ctx, opts)
  50. if err != nil {
  51. ctx.APIErrorInternal(err)
  52. return
  53. }
  54. apiSecrets := make([]*api.Secret, len(secrets))
  55. for k, v := range secrets {
  56. apiSecrets[k] = &api.Secret{
  57. Name: v.Name,
  58. Description: v.Description,
  59. Created: v.CreatedUnix.AsTime(),
  60. }
  61. }
  62. ctx.SetTotalCountHeader(count)
  63. ctx.JSON(http.StatusOK, apiSecrets)
  64. }
  65. // create or update one secret of the organization
  66. func (Action) CreateOrUpdateSecret(ctx *context.APIContext) {
  67. // swagger:operation PUT /orgs/{org}/actions/secrets/{secretname} organization updateOrgSecret
  68. // ---
  69. // summary: Create or Update a secret value in an organization
  70. // consumes:
  71. // - application/json
  72. // produces:
  73. // - application/json
  74. // parameters:
  75. // - name: org
  76. // in: path
  77. // description: name of organization
  78. // type: string
  79. // required: true
  80. // - name: secretname
  81. // in: path
  82. // description: name of the secret
  83. // type: string
  84. // required: true
  85. // - name: body
  86. // in: body
  87. // schema:
  88. // "$ref": "#/definitions/CreateOrUpdateSecretOption"
  89. // responses:
  90. // "201":
  91. // description: response when creating a secret
  92. // "204":
  93. // description: response when updating a secret
  94. // "400":
  95. // "$ref": "#/responses/error"
  96. // "404":
  97. // "$ref": "#/responses/notFound"
  98. opt := web.GetForm(ctx).(*api.CreateOrUpdateSecretOption)
  99. _, created, err := secret_service.CreateOrUpdateSecret(ctx, ctx.Org.Organization.ID, 0, ctx.PathParam("secretname"), opt.Data, opt.Description)
  100. if err != nil {
  101. if errors.Is(err, util.ErrInvalidArgument) {
  102. ctx.APIError(http.StatusBadRequest, err)
  103. } else if errors.Is(err, util.ErrNotExist) {
  104. ctx.APIError(http.StatusNotFound, err)
  105. } else {
  106. ctx.APIErrorInternal(err)
  107. }
  108. return
  109. }
  110. if created {
  111. ctx.Status(http.StatusCreated)
  112. } else {
  113. ctx.Status(http.StatusNoContent)
  114. }
  115. }
  116. // DeleteSecret delete one secret of the organization
  117. func (Action) DeleteSecret(ctx *context.APIContext) {
  118. // swagger:operation DELETE /orgs/{org}/actions/secrets/{secretname} organization deleteOrgSecret
  119. // ---
  120. // summary: Delete a secret in an organization
  121. // consumes:
  122. // - application/json
  123. // produces:
  124. // - application/json
  125. // parameters:
  126. // - name: org
  127. // in: path
  128. // description: name of organization
  129. // type: string
  130. // required: true
  131. // - name: secretname
  132. // in: path
  133. // description: name of the secret
  134. // type: string
  135. // required: true
  136. // responses:
  137. // "204":
  138. // description: delete one secret of the organization
  139. // "400":
  140. // "$ref": "#/responses/error"
  141. // "404":
  142. // "$ref": "#/responses/notFound"
  143. err := secret_service.DeleteSecretByName(ctx, ctx.Org.Organization.ID, 0, ctx.PathParam("secretname"))
  144. if err != nil {
  145. if errors.Is(err, util.ErrInvalidArgument) {
  146. ctx.APIError(http.StatusBadRequest, err)
  147. } else if errors.Is(err, util.ErrNotExist) {
  148. ctx.APIError(http.StatusNotFound, err)
  149. } else {
  150. ctx.APIErrorInternal(err)
  151. }
  152. return
  153. }
  154. ctx.Status(http.StatusNoContent)
  155. }
  156. // https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-an-organization
  157. // GetRegistrationToken returns the token to register org runners
  158. func (Action) GetRegistrationToken(ctx *context.APIContext) {
  159. // swagger:operation GET /orgs/{org}/actions/runners/registration-token organization orgGetRunnerRegistrationToken
  160. // ---
  161. // summary: Get an organization's actions runner registration token
  162. // produces:
  163. // - application/json
  164. // parameters:
  165. // - name: org
  166. // in: path
  167. // description: name of the organization
  168. // type: string
  169. // required: true
  170. // responses:
  171. // "200":
  172. // "$ref": "#/responses/RegistrationToken"
  173. shared.GetRegistrationToken(ctx, ctx.Org.Organization.ID, 0)
  174. }
  175. // https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-an-organization
  176. // CreateRegistrationToken returns the token to register org runners
  177. func (Action) CreateRegistrationToken(ctx *context.APIContext) {
  178. // swagger:operation POST /orgs/{org}/actions/runners/registration-token organization orgCreateRunnerRegistrationToken
  179. // ---
  180. // summary: Get an organization's actions runner registration token
  181. // produces:
  182. // - application/json
  183. // parameters:
  184. // - name: org
  185. // in: path
  186. // description: name of the organization
  187. // type: string
  188. // required: true
  189. // responses:
  190. // "200":
  191. // "$ref": "#/responses/RegistrationToken"
  192. shared.GetRegistrationToken(ctx, ctx.Org.Organization.ID, 0)
  193. }
  194. // ListVariables list org-level variables
  195. func (Action) ListVariables(ctx *context.APIContext) {
  196. // swagger:operation GET /orgs/{org}/actions/variables organization getOrgVariablesList
  197. // ---
  198. // summary: Get an org-level variables list
  199. // produces:
  200. // - application/json
  201. // parameters:
  202. // - name: org
  203. // in: path
  204. // description: name of the organization
  205. // type: string
  206. // required: true
  207. // - name: page
  208. // in: query
  209. // description: page number of results to return (1-based)
  210. // type: integer
  211. // - name: limit
  212. // in: query
  213. // description: page size of results
  214. // type: integer
  215. // responses:
  216. // "200":
  217. // "$ref": "#/responses/VariableList"
  218. // "400":
  219. // "$ref": "#/responses/error"
  220. // "404":
  221. // "$ref": "#/responses/notFound"
  222. vars, count, err := db.FindAndCount[actions_model.ActionVariable](ctx, &actions_model.FindVariablesOpts{
  223. OwnerID: ctx.Org.Organization.ID,
  224. ListOptions: utils.GetListOptions(ctx),
  225. })
  226. if err != nil {
  227. ctx.APIErrorInternal(err)
  228. return
  229. }
  230. variables := make([]*api.ActionVariable, len(vars))
  231. for i, v := range vars {
  232. variables[i] = &api.ActionVariable{
  233. OwnerID: v.OwnerID,
  234. RepoID: v.RepoID,
  235. Name: v.Name,
  236. Data: v.Data,
  237. Description: v.Description,
  238. }
  239. }
  240. ctx.SetTotalCountHeader(count)
  241. ctx.JSON(http.StatusOK, variables)
  242. }
  243. // GetVariable get an org-level variable
  244. func (Action) GetVariable(ctx *context.APIContext) {
  245. // swagger:operation GET /orgs/{org}/actions/variables/{variablename} organization getOrgVariable
  246. // ---
  247. // summary: Get an org-level variable
  248. // produces:
  249. // - application/json
  250. // parameters:
  251. // - name: org
  252. // in: path
  253. // description: name of the organization
  254. // type: string
  255. // required: true
  256. // - name: variablename
  257. // in: path
  258. // description: name of the variable
  259. // type: string
  260. // required: true
  261. // responses:
  262. // "200":
  263. // "$ref": "#/responses/ActionVariable"
  264. // "400":
  265. // "$ref": "#/responses/error"
  266. // "404":
  267. // "$ref": "#/responses/notFound"
  268. v, err := actions_service.GetVariable(ctx, actions_model.FindVariablesOpts{
  269. OwnerID: ctx.Org.Organization.ID,
  270. Name: ctx.PathParam("variablename"),
  271. })
  272. if err != nil {
  273. if errors.Is(err, util.ErrNotExist) {
  274. ctx.APIError(http.StatusNotFound, err)
  275. } else {
  276. ctx.APIErrorInternal(err)
  277. }
  278. return
  279. }
  280. variable := &api.ActionVariable{
  281. OwnerID: v.OwnerID,
  282. RepoID: v.RepoID,
  283. Name: v.Name,
  284. Data: v.Data,
  285. Description: v.Description,
  286. }
  287. ctx.JSON(http.StatusOK, variable)
  288. }
  289. // DeleteVariable delete an org-level variable
  290. func (Action) DeleteVariable(ctx *context.APIContext) {
  291. // swagger:operation DELETE /orgs/{org}/actions/variables/{variablename} organization deleteOrgVariable
  292. // ---
  293. // summary: Delete an org-level variable
  294. // produces:
  295. // - application/json
  296. // parameters:
  297. // - name: org
  298. // in: path
  299. // description: name of the organization
  300. // type: string
  301. // required: true
  302. // - name: variablename
  303. // in: path
  304. // description: name of the variable
  305. // type: string
  306. // required: true
  307. // responses:
  308. // "200":
  309. // "$ref": "#/responses/ActionVariable"
  310. // "201":
  311. // description: response when deleting a variable
  312. // "204":
  313. // description: response when deleting a variable
  314. // "400":
  315. // "$ref": "#/responses/error"
  316. // "404":
  317. // "$ref": "#/responses/notFound"
  318. if err := actions_service.DeleteVariableByName(ctx, ctx.Org.Organization.ID, 0, ctx.PathParam("variablename")); err != nil {
  319. if errors.Is(err, util.ErrInvalidArgument) {
  320. ctx.APIError(http.StatusBadRequest, err)
  321. } else if errors.Is(err, util.ErrNotExist) {
  322. ctx.APIError(http.StatusNotFound, err)
  323. } else {
  324. ctx.APIErrorInternal(err)
  325. }
  326. return
  327. }
  328. ctx.Status(http.StatusNoContent)
  329. }
  330. // CreateVariable create an org-level variable
  331. func (Action) CreateVariable(ctx *context.APIContext) {
  332. // swagger:operation POST /orgs/{org}/actions/variables/{variablename} organization createOrgVariable
  333. // ---
  334. // summary: Create an org-level variable
  335. // consumes:
  336. // - application/json
  337. // produces:
  338. // - application/json
  339. // parameters:
  340. // - name: org
  341. // in: path
  342. // description: name of the organization
  343. // type: string
  344. // required: true
  345. // - name: variablename
  346. // in: path
  347. // description: name of the variable
  348. // type: string
  349. // required: true
  350. // - name: body
  351. // in: body
  352. // schema:
  353. // "$ref": "#/definitions/CreateVariableOption"
  354. // responses:
  355. // "201":
  356. // description: successfully created the org-level variable
  357. // "400":
  358. // "$ref": "#/responses/error"
  359. // "409":
  360. // description: variable name already exists.
  361. // "500":
  362. // "$ref": "#/responses/error"
  363. opt := web.GetForm(ctx).(*api.CreateVariableOption)
  364. ownerID := ctx.Org.Organization.ID
  365. variableName := ctx.PathParam("variablename")
  366. v, err := actions_service.GetVariable(ctx, actions_model.FindVariablesOpts{
  367. OwnerID: ownerID,
  368. Name: variableName,
  369. })
  370. if err != nil && !errors.Is(err, util.ErrNotExist) {
  371. ctx.APIErrorInternal(err)
  372. return
  373. }
  374. if v != nil && v.ID > 0 {
  375. ctx.APIError(http.StatusConflict, util.NewAlreadyExistErrorf("variable name %s already exists", variableName))
  376. return
  377. }
  378. if _, err := actions_service.CreateVariable(ctx, ownerID, 0, variableName, opt.Value, opt.Description); err != nil {
  379. if errors.Is(err, util.ErrInvalidArgument) {
  380. ctx.APIError(http.StatusBadRequest, err)
  381. } else {
  382. ctx.APIErrorInternal(err)
  383. }
  384. return
  385. }
  386. ctx.Status(http.StatusCreated)
  387. }
  388. // UpdateVariable update an org-level variable
  389. func (Action) UpdateVariable(ctx *context.APIContext) {
  390. // swagger:operation PUT /orgs/{org}/actions/variables/{variablename} organization updateOrgVariable
  391. // ---
  392. // summary: Update an org-level variable
  393. // consumes:
  394. // - application/json
  395. // produces:
  396. // - application/json
  397. // parameters:
  398. // - name: org
  399. // in: path
  400. // description: name of the organization
  401. // type: string
  402. // required: true
  403. // - name: variablename
  404. // in: path
  405. // description: name of the variable
  406. // type: string
  407. // required: true
  408. // - name: body
  409. // in: body
  410. // schema:
  411. // "$ref": "#/definitions/UpdateVariableOption"
  412. // responses:
  413. // "201":
  414. // description: response when updating an org-level variable
  415. // "204":
  416. // description: response when updating an org-level variable
  417. // "400":
  418. // "$ref": "#/responses/error"
  419. // "404":
  420. // "$ref": "#/responses/notFound"
  421. opt := web.GetForm(ctx).(*api.UpdateVariableOption)
  422. v, err := actions_service.GetVariable(ctx, actions_model.FindVariablesOpts{
  423. OwnerID: ctx.Org.Organization.ID,
  424. Name: ctx.PathParam("variablename"),
  425. })
  426. if err != nil {
  427. if errors.Is(err, util.ErrNotExist) {
  428. ctx.APIError(http.StatusNotFound, err)
  429. } else {
  430. ctx.APIErrorInternal(err)
  431. }
  432. return
  433. }
  434. if opt.Name == "" {
  435. opt.Name = ctx.PathParam("variablename")
  436. }
  437. v.Name = opt.Name
  438. v.Data = opt.Value
  439. v.Description = opt.Description
  440. if _, err := actions_service.UpdateVariableNameData(ctx, v); err != nil {
  441. if errors.Is(err, util.ErrInvalidArgument) {
  442. ctx.APIError(http.StatusBadRequest, err)
  443. } else {
  444. ctx.APIErrorInternal(err)
  445. }
  446. return
  447. }
  448. ctx.Status(http.StatusNoContent)
  449. }
  450. // ListRunners get org-level runners
  451. func (Action) ListRunners(ctx *context.APIContext) {
  452. // swagger:operation GET /orgs/{org}/actions/runners organization getOrgRunners
  453. // ---
  454. // summary: Get org-level runners
  455. // produces:
  456. // - application/json
  457. // parameters:
  458. // - name: org
  459. // in: path
  460. // description: name of the organization
  461. // type: string
  462. // required: true
  463. // responses:
  464. // "200":
  465. // "$ref": "#/definitions/ActionRunnersResponse"
  466. // "400":
  467. // "$ref": "#/responses/error"
  468. // "404":
  469. // "$ref": "#/responses/notFound"
  470. shared.ListRunners(ctx, ctx.Org.Organization.ID, 0)
  471. }
  472. // GetRunner get an org-level runner
  473. func (Action) GetRunner(ctx *context.APIContext) {
  474. // swagger:operation GET /orgs/{org}/actions/runners/{runner_id} organization getOrgRunner
  475. // ---
  476. // summary: Get an org-level runner
  477. // produces:
  478. // - application/json
  479. // parameters:
  480. // - name: org
  481. // in: path
  482. // description: name of the organization
  483. // type: string
  484. // required: true
  485. // - name: runner_id
  486. // in: path
  487. // description: id of the runner
  488. // type: string
  489. // required: true
  490. // responses:
  491. // "200":
  492. // "$ref": "#/definitions/ActionRunner"
  493. // "400":
  494. // "$ref": "#/responses/error"
  495. // "404":
  496. // "$ref": "#/responses/notFound"
  497. shared.GetRunner(ctx, ctx.Org.Organization.ID, 0, ctx.PathParamInt64("runner_id"))
  498. }
  499. // DeleteRunner delete an org-level runner
  500. func (Action) DeleteRunner(ctx *context.APIContext) {
  501. // swagger:operation DELETE /orgs/{org}/actions/runners/{runner_id} organization deleteOrgRunner
  502. // ---
  503. // summary: Delete an org-level runner
  504. // produces:
  505. // - application/json
  506. // parameters:
  507. // - name: org
  508. // in: path
  509. // description: name of the organization
  510. // type: string
  511. // required: true
  512. // - name: runner_id
  513. // in: path
  514. // description: id of the runner
  515. // type: string
  516. // required: true
  517. // responses:
  518. // "204":
  519. // description: runner has been deleted
  520. // "400":
  521. // "$ref": "#/responses/error"
  522. // "404":
  523. // "$ref": "#/responses/notFound"
  524. shared.DeleteRunner(ctx, ctx.Org.Organization.ID, 0, ctx.PathParamInt64("runner_id"))
  525. }
  526. func (Action) ListWorkflowJobs(ctx *context.APIContext) {
  527. // swagger:operation GET /orgs/{org}/actions/jobs organization getOrgWorkflowJobs
  528. // ---
  529. // summary: Get org-level workflow jobs
  530. // produces:
  531. // - application/json
  532. // parameters:
  533. // - name: org
  534. // in: path
  535. // description: name of the organization
  536. // type: string
  537. // required: true
  538. // - name: status
  539. // in: query
  540. // description: workflow status (pending, queued, in_progress, failure, success, skipped)
  541. // type: string
  542. // required: false
  543. // - name: page
  544. // in: query
  545. // description: page number of results to return (1-based)
  546. // type: integer
  547. // - name: limit
  548. // in: query
  549. // description: page size of results
  550. // type: integer
  551. // responses:
  552. // "200":
  553. // "$ref": "#/responses/WorkflowJobsList"
  554. // "400":
  555. // "$ref": "#/responses/error"
  556. // "404":
  557. // "$ref": "#/responses/notFound"
  558. shared.ListJobs(ctx, ctx.Org.Organization.ID, 0, 0)
  559. }
  560. func (Action) ListWorkflowRuns(ctx *context.APIContext) {
  561. // swagger:operation GET /orgs/{org}/actions/runs organization getOrgWorkflowRuns
  562. // ---
  563. // summary: Get org-level workflow runs
  564. // produces:
  565. // - application/json
  566. // parameters:
  567. // - name: org
  568. // in: path
  569. // description: name of the organization
  570. // type: string
  571. // required: true
  572. // - name: event
  573. // in: query
  574. // description: workflow event name
  575. // type: string
  576. // required: false
  577. // - name: branch
  578. // in: query
  579. // description: workflow branch
  580. // type: string
  581. // required: false
  582. // - name: status
  583. // in: query
  584. // description: workflow status (pending, queued, in_progress, failure, success, skipped)
  585. // type: string
  586. // required: false
  587. // - name: actor
  588. // in: query
  589. // description: triggered by user
  590. // type: string
  591. // required: false
  592. // - name: head_sha
  593. // in: query
  594. // description: triggering sha of the workflow run
  595. // type: string
  596. // required: false
  597. // - name: page
  598. // in: query
  599. // description: page number of results to return (1-based)
  600. // type: integer
  601. // - name: limit
  602. // in: query
  603. // description: page size of results
  604. // type: integer
  605. // responses:
  606. // "200":
  607. // "$ref": "#/responses/WorkflowRunsList"
  608. // "400":
  609. // "$ref": "#/responses/error"
  610. // "404":
  611. // "$ref": "#/responses/notFound"
  612. shared.ListRuns(ctx, ctx.Org.Organization.ID, 0)
  613. }
  614. var _ actions_service.API = new(Action)
  615. // Action implements actions_service.API
  616. type Action struct{}
  617. // NewAction creates a new Action service
  618. func NewAction() actions_service.API {
  619. return Action{}
  620. }