code.gitea.io/gitea@v1.22.3/routers/api/v1/repo/action.go (about) 1 // Copyright 2023 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package repo 5 6 import ( 7 "errors" 8 "net/http" 9 10 actions_model "code.gitea.io/gitea/models/actions" 11 "code.gitea.io/gitea/models/db" 12 secret_model "code.gitea.io/gitea/models/secret" 13 api "code.gitea.io/gitea/modules/structs" 14 "code.gitea.io/gitea/modules/util" 15 "code.gitea.io/gitea/modules/web" 16 "code.gitea.io/gitea/routers/api/v1/shared" 17 "code.gitea.io/gitea/routers/api/v1/utils" 18 actions_service "code.gitea.io/gitea/services/actions" 19 "code.gitea.io/gitea/services/context" 20 secret_service "code.gitea.io/gitea/services/secrets" 21 ) 22 23 // ListActionsSecrets list an repo's actions secrets 24 func (Action) ListActionsSecrets(ctx *context.APIContext) { 25 // swagger:operation GET /repos/{owner}/{repo}/actions/secrets repository repoListActionsSecrets 26 // --- 27 // summary: List an repo's actions secrets 28 // produces: 29 // - application/json 30 // parameters: 31 // - name: owner 32 // in: path 33 // description: owner of the repository 34 // type: string 35 // required: true 36 // - name: repo 37 // in: path 38 // description: name of the repository 39 // type: string 40 // required: true 41 // - name: page 42 // in: query 43 // description: page number of results to return (1-based) 44 // type: integer 45 // - name: limit 46 // in: query 47 // description: page size of results 48 // type: integer 49 // responses: 50 // "200": 51 // "$ref": "#/responses/SecretList" 52 // "404": 53 // "$ref": "#/responses/notFound" 54 55 repo := ctx.Repo.Repository 56 57 opts := &secret_model.FindSecretsOptions{ 58 RepoID: repo.ID, 59 ListOptions: utils.GetListOptions(ctx), 60 } 61 62 secrets, count, err := db.FindAndCount[secret_model.Secret](ctx, opts) 63 if err != nil { 64 ctx.InternalServerError(err) 65 return 66 } 67 68 apiSecrets := make([]*api.Secret, len(secrets)) 69 for k, v := range secrets { 70 apiSecrets[k] = &api.Secret{ 71 Name: v.Name, 72 Created: v.CreatedUnix.AsTime(), 73 } 74 } 75 76 ctx.SetTotalCountHeader(count) 77 ctx.JSON(http.StatusOK, apiSecrets) 78 } 79 80 // create or update one secret of the repository 81 func (Action) CreateOrUpdateSecret(ctx *context.APIContext) { 82 // swagger:operation PUT /repos/{owner}/{repo}/actions/secrets/{secretname} repository updateRepoSecret 83 // --- 84 // summary: Create or Update a secret value in a repository 85 // consumes: 86 // - application/json 87 // produces: 88 // - application/json 89 // parameters: 90 // - name: owner 91 // in: path 92 // description: owner of the repository 93 // type: string 94 // required: true 95 // - name: repo 96 // in: path 97 // description: name of the repository 98 // type: string 99 // required: true 100 // - name: secretname 101 // in: path 102 // description: name of the secret 103 // type: string 104 // required: true 105 // - name: body 106 // in: body 107 // schema: 108 // "$ref": "#/definitions/CreateOrUpdateSecretOption" 109 // responses: 110 // "201": 111 // description: response when creating a secret 112 // "204": 113 // description: response when updating a secret 114 // "400": 115 // "$ref": "#/responses/error" 116 // "404": 117 // "$ref": "#/responses/notFound" 118 119 repo := ctx.Repo.Repository 120 121 opt := web.GetForm(ctx).(*api.CreateOrUpdateSecretOption) 122 123 _, created, err := secret_service.CreateOrUpdateSecret(ctx, 0, repo.ID, ctx.Params("secretname"), opt.Data) 124 if err != nil { 125 if errors.Is(err, util.ErrInvalidArgument) { 126 ctx.Error(http.StatusBadRequest, "CreateOrUpdateSecret", err) 127 } else if errors.Is(err, util.ErrNotExist) { 128 ctx.Error(http.StatusNotFound, "CreateOrUpdateSecret", err) 129 } else { 130 ctx.Error(http.StatusInternalServerError, "CreateOrUpdateSecret", err) 131 } 132 return 133 } 134 135 if created { 136 ctx.Status(http.StatusCreated) 137 } else { 138 ctx.Status(http.StatusNoContent) 139 } 140 } 141 142 // DeleteSecret delete one secret of the repository 143 func (Action) DeleteSecret(ctx *context.APIContext) { 144 // swagger:operation DELETE /repos/{owner}/{repo}/actions/secrets/{secretname} repository deleteRepoSecret 145 // --- 146 // summary: Delete a secret in a repository 147 // consumes: 148 // - application/json 149 // produces: 150 // - application/json 151 // parameters: 152 // - name: owner 153 // in: path 154 // description: owner of the repository 155 // type: string 156 // required: true 157 // - name: repo 158 // in: path 159 // description: name of the repository 160 // type: string 161 // required: true 162 // - name: secretname 163 // in: path 164 // description: name of the secret 165 // type: string 166 // required: true 167 // responses: 168 // "204": 169 // description: delete one secret of the organization 170 // "400": 171 // "$ref": "#/responses/error" 172 // "404": 173 // "$ref": "#/responses/notFound" 174 175 repo := ctx.Repo.Repository 176 177 err := secret_service.DeleteSecretByName(ctx, 0, repo.ID, ctx.Params("secretname")) 178 if err != nil { 179 if errors.Is(err, util.ErrInvalidArgument) { 180 ctx.Error(http.StatusBadRequest, "DeleteSecret", err) 181 } else if errors.Is(err, util.ErrNotExist) { 182 ctx.Error(http.StatusNotFound, "DeleteSecret", err) 183 } else { 184 ctx.Error(http.StatusInternalServerError, "DeleteSecret", err) 185 } 186 return 187 } 188 189 ctx.Status(http.StatusNoContent) 190 } 191 192 // GetVariable get a repo-level variable 193 func (Action) GetVariable(ctx *context.APIContext) { 194 // swagger:operation GET /repos/{owner}/{repo}/actions/variables/{variablename} repository getRepoVariable 195 // --- 196 // summary: Get a repo-level variable 197 // produces: 198 // - application/json 199 // parameters: 200 // - name: owner 201 // in: path 202 // description: name of the owner 203 // type: string 204 // required: true 205 // - name: repo 206 // in: path 207 // description: name of the repository 208 // type: string 209 // required: true 210 // - name: variablename 211 // in: path 212 // description: name of the variable 213 // type: string 214 // required: true 215 // responses: 216 // "200": 217 // "$ref": "#/responses/ActionVariable" 218 // "400": 219 // "$ref": "#/responses/error" 220 // "404": 221 // "$ref": "#/responses/notFound" 222 v, err := actions_service.GetVariable(ctx, actions_model.FindVariablesOpts{ 223 RepoID: ctx.Repo.Repository.ID, 224 Name: ctx.Params("variablename"), 225 }) 226 if err != nil { 227 if errors.Is(err, util.ErrNotExist) { 228 ctx.Error(http.StatusNotFound, "GetVariable", err) 229 } else { 230 ctx.Error(http.StatusInternalServerError, "GetVariable", err) 231 } 232 return 233 } 234 235 variable := &api.ActionVariable{ 236 OwnerID: v.OwnerID, 237 RepoID: v.RepoID, 238 Name: v.Name, 239 Data: v.Data, 240 } 241 242 ctx.JSON(http.StatusOK, variable) 243 } 244 245 // DeleteVariable delete a repo-level variable 246 func (Action) DeleteVariable(ctx *context.APIContext) { 247 // swagger:operation DELETE /repos/{owner}/{repo}/actions/variables/{variablename} repository deleteRepoVariable 248 // --- 249 // summary: Delete a repo-level variable 250 // produces: 251 // - application/json 252 // parameters: 253 // - name: owner 254 // in: path 255 // description: name of the owner 256 // type: string 257 // required: true 258 // - name: repo 259 // in: path 260 // description: name of the repository 261 // type: string 262 // required: true 263 // - name: variablename 264 // in: path 265 // description: name of the variable 266 // type: string 267 // required: true 268 // responses: 269 // "200": 270 // "$ref": "#/responses/ActionVariable" 271 // "201": 272 // description: response when deleting a variable 273 // "204": 274 // description: response when deleting a variable 275 // "400": 276 // "$ref": "#/responses/error" 277 // "404": 278 // "$ref": "#/responses/notFound" 279 280 if err := actions_service.DeleteVariableByName(ctx, 0, ctx.Repo.Repository.ID, ctx.Params("variablename")); err != nil { 281 if errors.Is(err, util.ErrInvalidArgument) { 282 ctx.Error(http.StatusBadRequest, "DeleteVariableByName", err) 283 } else if errors.Is(err, util.ErrNotExist) { 284 ctx.Error(http.StatusNotFound, "DeleteVariableByName", err) 285 } else { 286 ctx.Error(http.StatusInternalServerError, "DeleteVariableByName", err) 287 } 288 return 289 } 290 291 ctx.Status(http.StatusNoContent) 292 } 293 294 // CreateVariable create a repo-level variable 295 func (Action) CreateVariable(ctx *context.APIContext) { 296 // swagger:operation POST /repos/{owner}/{repo}/actions/variables/{variablename} repository createRepoVariable 297 // --- 298 // summary: Create a repo-level variable 299 // produces: 300 // - application/json 301 // parameters: 302 // - name: owner 303 // in: path 304 // description: name of the owner 305 // type: string 306 // required: true 307 // - name: repo 308 // in: path 309 // description: name of the repository 310 // type: string 311 // required: true 312 // - name: variablename 313 // in: path 314 // description: name of the variable 315 // type: string 316 // required: true 317 // - name: body 318 // in: body 319 // schema: 320 // "$ref": "#/definitions/CreateVariableOption" 321 // responses: 322 // "201": 323 // description: response when creating a repo-level variable 324 // "204": 325 // description: response when creating a repo-level variable 326 // "400": 327 // "$ref": "#/responses/error" 328 // "404": 329 // "$ref": "#/responses/notFound" 330 331 opt := web.GetForm(ctx).(*api.CreateVariableOption) 332 333 repoID := ctx.Repo.Repository.ID 334 variableName := ctx.Params("variablename") 335 336 v, err := actions_service.GetVariable(ctx, actions_model.FindVariablesOpts{ 337 RepoID: repoID, 338 Name: variableName, 339 }) 340 if err != nil && !errors.Is(err, util.ErrNotExist) { 341 ctx.Error(http.StatusInternalServerError, "GetVariable", err) 342 return 343 } 344 if v != nil && v.ID > 0 { 345 ctx.Error(http.StatusConflict, "VariableNameAlreadyExists", util.NewAlreadyExistErrorf("variable name %s already exists", variableName)) 346 return 347 } 348 349 if _, err := actions_service.CreateVariable(ctx, 0, repoID, variableName, opt.Value); err != nil { 350 if errors.Is(err, util.ErrInvalidArgument) { 351 ctx.Error(http.StatusBadRequest, "CreateVariable", err) 352 } else { 353 ctx.Error(http.StatusInternalServerError, "CreateVariable", err) 354 } 355 return 356 } 357 358 ctx.Status(http.StatusNoContent) 359 } 360 361 // UpdateVariable update a repo-level variable 362 func (Action) UpdateVariable(ctx *context.APIContext) { 363 // swagger:operation PUT /repos/{owner}/{repo}/actions/variables/{variablename} repository updateRepoVariable 364 // --- 365 // summary: Update a repo-level variable 366 // produces: 367 // - application/json 368 // parameters: 369 // - name: owner 370 // in: path 371 // description: name of the owner 372 // type: string 373 // required: true 374 // - name: repo 375 // in: path 376 // description: name of the repository 377 // type: string 378 // required: true 379 // - name: variablename 380 // in: path 381 // description: name of the variable 382 // type: string 383 // required: true 384 // - name: body 385 // in: body 386 // schema: 387 // "$ref": "#/definitions/UpdateVariableOption" 388 // responses: 389 // "201": 390 // description: response when updating a repo-level variable 391 // "204": 392 // description: response when updating a repo-level variable 393 // "400": 394 // "$ref": "#/responses/error" 395 // "404": 396 // "$ref": "#/responses/notFound" 397 398 opt := web.GetForm(ctx).(*api.UpdateVariableOption) 399 400 v, err := actions_service.GetVariable(ctx, actions_model.FindVariablesOpts{ 401 RepoID: ctx.Repo.Repository.ID, 402 Name: ctx.Params("variablename"), 403 }) 404 if err != nil { 405 if errors.Is(err, util.ErrNotExist) { 406 ctx.Error(http.StatusNotFound, "GetVariable", err) 407 } else { 408 ctx.Error(http.StatusInternalServerError, "GetVariable", err) 409 } 410 return 411 } 412 413 if opt.Name == "" { 414 opt.Name = ctx.Params("variablename") 415 } 416 if _, err := actions_service.UpdateVariable(ctx, v.ID, opt.Name, opt.Value); err != nil { 417 if errors.Is(err, util.ErrInvalidArgument) { 418 ctx.Error(http.StatusBadRequest, "UpdateVariable", err) 419 } else { 420 ctx.Error(http.StatusInternalServerError, "UpdateVariable", err) 421 } 422 return 423 } 424 425 ctx.Status(http.StatusNoContent) 426 } 427 428 // ListVariables list repo-level variables 429 func (Action) ListVariables(ctx *context.APIContext) { 430 // swagger:operation GET /repos/{owner}/{repo}/actions/variables repository getRepoVariablesList 431 // --- 432 // summary: Get repo-level variables list 433 // produces: 434 // - application/json 435 // parameters: 436 // - name: owner 437 // in: path 438 // description: name of the owner 439 // type: string 440 // required: true 441 // - name: repo 442 // in: path 443 // description: name of the repository 444 // type: string 445 // required: true 446 // - name: page 447 // in: query 448 // description: page number of results to return (1-based) 449 // type: integer 450 // - name: limit 451 // in: query 452 // description: page size of results 453 // type: integer 454 // responses: 455 // "200": 456 // "$ref": "#/responses/VariableList" 457 // "400": 458 // "$ref": "#/responses/error" 459 // "404": 460 // "$ref": "#/responses/notFound" 461 462 vars, count, err := db.FindAndCount[actions_model.ActionVariable](ctx, &actions_model.FindVariablesOpts{ 463 RepoID: ctx.Repo.Repository.ID, 464 ListOptions: utils.GetListOptions(ctx), 465 }) 466 if err != nil { 467 ctx.Error(http.StatusInternalServerError, "FindVariables", err) 468 return 469 } 470 471 variables := make([]*api.ActionVariable, len(vars)) 472 for i, v := range vars { 473 variables[i] = &api.ActionVariable{ 474 OwnerID: v.OwnerID, 475 RepoID: v.RepoID, 476 Name: v.Name, 477 } 478 } 479 480 ctx.SetTotalCountHeader(count) 481 ctx.JSON(http.StatusOK, variables) 482 } 483 484 // GetRegistrationToken returns the token to register repo runners 485 func (Action) GetRegistrationToken(ctx *context.APIContext) { 486 // swagger:operation GET /repos/{owner}/{repo}/actions/runners/registration-token repository repoGetRunnerRegistrationToken 487 // --- 488 // summary: Get a repository's actions runner registration token 489 // produces: 490 // - application/json 491 // parameters: 492 // - name: owner 493 // in: path 494 // description: owner of the repo 495 // type: string 496 // required: true 497 // - name: repo 498 // in: path 499 // description: name of the repo 500 // type: string 501 // required: true 502 // responses: 503 // "200": 504 // "$ref": "#/responses/RegistrationToken" 505 506 shared.GetRegistrationToken(ctx, 0, ctx.Repo.Repository.ID) 507 } 508 509 var _ actions_service.API = new(Action) 510 511 // Action implements actions_service.API 512 type Action struct{} 513 514 // NewAction creates a new Action service 515 func NewAction() actions_service.API { 516 return Action{} 517 }