code.gitea.io/gitea@v1.21.7/routers/web/repo/release.go (about) 1 // Copyright 2014 The Gogs Authors. All rights reserved. 2 // Copyright 2018 The Gitea Authors. All rights reserved. 3 // SPDX-License-Identifier: MIT 4 5 package repo 6 7 import ( 8 "errors" 9 "fmt" 10 "net/http" 11 "strings" 12 13 "code.gitea.io/gitea/models" 14 "code.gitea.io/gitea/models/db" 15 repo_model "code.gitea.io/gitea/models/repo" 16 "code.gitea.io/gitea/models/unit" 17 user_model "code.gitea.io/gitea/models/user" 18 "code.gitea.io/gitea/modules/base" 19 "code.gitea.io/gitea/modules/context" 20 "code.gitea.io/gitea/modules/git" 21 "code.gitea.io/gitea/modules/log" 22 "code.gitea.io/gitea/modules/markup" 23 "code.gitea.io/gitea/modules/markup/markdown" 24 "code.gitea.io/gitea/modules/setting" 25 "code.gitea.io/gitea/modules/upload" 26 "code.gitea.io/gitea/modules/util" 27 "code.gitea.io/gitea/modules/web" 28 "code.gitea.io/gitea/routers/web/feed" 29 "code.gitea.io/gitea/services/forms" 30 releaseservice "code.gitea.io/gitea/services/release" 31 ) 32 33 const ( 34 tplReleasesList base.TplName = "repo/release/list" 35 tplReleaseNew base.TplName = "repo/release/new" 36 tplTagsList base.TplName = "repo/tag/list" 37 ) 38 39 // calReleaseNumCommitsBehind calculates given release has how many commits behind release target. 40 func calReleaseNumCommitsBehind(repoCtx *context.Repository, release *repo_model.Release, countCache map[string]int64) error { 41 target := release.Target 42 if target == "" { 43 target = repoCtx.Repository.DefaultBranch 44 } 45 // Get count if not cached 46 if _, ok := countCache[target]; !ok { 47 commit, err := repoCtx.GitRepo.GetBranchCommit(target) 48 if err != nil { 49 var errNotExist git.ErrNotExist 50 if target == repoCtx.Repository.DefaultBranch || !errors.As(err, &errNotExist) { 51 return fmt.Errorf("GetBranchCommit: %w", err) 52 } 53 // fallback to default branch 54 target = repoCtx.Repository.DefaultBranch 55 commit, err = repoCtx.GitRepo.GetBranchCommit(target) 56 if err != nil { 57 return fmt.Errorf("GetBranchCommit(DefaultBranch): %w", err) 58 } 59 } 60 countCache[target], err = commit.CommitsCount() 61 if err != nil { 62 return fmt.Errorf("CommitsCount: %w", err) 63 } 64 } 65 release.NumCommitsBehind = countCache[target] - release.NumCommits 66 release.TargetBehind = target 67 return nil 68 } 69 70 // Releases render releases list page 71 func Releases(ctx *context.Context) { 72 ctx.Data["PageIsReleaseList"] = true 73 ctx.Data["Title"] = ctx.Tr("repo.release.releases") 74 releasesOrTags(ctx, false) 75 } 76 77 // TagsList render tags list page 78 func TagsList(ctx *context.Context) { 79 ctx.Data["PageIsTagList"] = true 80 ctx.Data["Title"] = ctx.Tr("repo.release.tags") 81 releasesOrTags(ctx, true) 82 } 83 84 func releasesOrTags(ctx *context.Context, isTagList bool) { 85 ctx.Data["DefaultBranch"] = ctx.Repo.Repository.DefaultBranch 86 ctx.Data["IsViewBranch"] = false 87 ctx.Data["IsViewTag"] = true 88 // Disable the showCreateNewBranch form in the dropdown on this page. 89 ctx.Data["CanCreateBranch"] = false 90 ctx.Data["HideBranchesInDropdown"] = true 91 92 listOptions := db.ListOptions{ 93 Page: ctx.FormInt("page"), 94 PageSize: ctx.FormInt("limit"), 95 } 96 if listOptions.PageSize == 0 { 97 listOptions.PageSize = setting.Repository.Release.DefaultPagingNum 98 } 99 if listOptions.PageSize > setting.API.MaxResponseItems { 100 listOptions.PageSize = setting.API.MaxResponseItems 101 } 102 103 // TODO(20073) tags are used for compare feature which needs all tags 104 // filtering is done on the client-side atm 105 tagListStart, tagListEnd := 0, 0 106 if isTagList { 107 tagListStart, tagListEnd = listOptions.GetStartEnd() 108 } 109 110 tags, err := ctx.Repo.GitRepo.GetTags(tagListStart, tagListEnd) 111 if err != nil { 112 ctx.ServerError("GetTags", err) 113 return 114 } 115 ctx.Data["Tags"] = tags 116 117 writeAccess := ctx.Repo.CanWrite(unit.TypeReleases) 118 ctx.Data["CanCreateRelease"] = writeAccess && !ctx.Repo.Repository.IsArchived 119 120 opts := repo_model.FindReleasesOptions{ 121 ListOptions: listOptions, 122 } 123 if isTagList { 124 // for the tags list page, show all releases with real tags (having real commit-id), 125 // the drafts should also be included because a real tag might be used as a draft. 126 opts.IncludeDrafts = true 127 opts.IncludeTags = true 128 opts.HasSha1 = util.OptionalBoolTrue 129 } else { 130 // only show draft releases for users who can write, read-only users shouldn't see draft releases. 131 opts.IncludeDrafts = writeAccess 132 } 133 134 releases, err := repo_model.GetReleasesByRepoID(ctx, ctx.Repo.Repository.ID, opts) 135 if err != nil { 136 ctx.ServerError("GetReleasesByRepoID", err) 137 return 138 } 139 140 count, err := repo_model.GetReleaseCountByRepoID(ctx, ctx.Repo.Repository.ID, opts) 141 if err != nil { 142 ctx.ServerError("GetReleaseCountByRepoID", err) 143 return 144 } 145 146 for _, release := range releases { 147 release.Repo = ctx.Repo.Repository 148 } 149 150 if err = repo_model.GetReleaseAttachments(ctx, releases...); err != nil { 151 ctx.ServerError("GetReleaseAttachments", err) 152 return 153 } 154 155 // Temporary cache commits count of used branches to speed up. 156 countCache := make(map[string]int64) 157 cacheUsers := make(map[int64]*user_model.User) 158 if ctx.Doer != nil { 159 cacheUsers[ctx.Doer.ID] = ctx.Doer 160 } 161 var ok bool 162 163 for _, r := range releases { 164 if r.Publisher, ok = cacheUsers[r.PublisherID]; !ok { 165 r.Publisher, err = user_model.GetUserByID(ctx, r.PublisherID) 166 if err != nil { 167 if user_model.IsErrUserNotExist(err) { 168 r.Publisher = user_model.NewGhostUser() 169 } else { 170 ctx.ServerError("GetUserByID", err) 171 return 172 } 173 } 174 cacheUsers[r.PublisherID] = r.Publisher 175 } 176 177 r.Note, err = markdown.RenderString(&markup.RenderContext{ 178 Links: markup.Links{ 179 Base: ctx.Repo.RepoLink, 180 }, 181 Metas: ctx.Repo.Repository.ComposeMetas(), 182 GitRepo: ctx.Repo.GitRepo, 183 Ctx: ctx, 184 }, r.Note) 185 if err != nil { 186 ctx.ServerError("RenderString", err) 187 return 188 } 189 190 if r.IsDraft { 191 continue 192 } 193 194 if err := calReleaseNumCommitsBehind(ctx.Repo, r, countCache); err != nil { 195 ctx.ServerError("calReleaseNumCommitsBehind", err) 196 return 197 } 198 } 199 200 ctx.Data["Releases"] = releases 201 202 pager := context.NewPagination(int(count), opts.PageSize, opts.Page, 5) 203 pager.SetDefaultParams(ctx) 204 ctx.Data["Page"] = pager 205 206 if isTagList { 207 ctx.Data["PageIsViewCode"] = !ctx.Repo.Repository.UnitEnabled(ctx, unit.TypeReleases) 208 ctx.HTML(http.StatusOK, tplTagsList) 209 } else { 210 ctx.HTML(http.StatusOK, tplReleasesList) 211 } 212 } 213 214 // ReleasesFeedRSS get feeds for releases in RSS format 215 func ReleasesFeedRSS(ctx *context.Context) { 216 releasesOrTagsFeed(ctx, true, "rss") 217 } 218 219 // TagsListFeedRSS get feeds for tags in RSS format 220 func TagsListFeedRSS(ctx *context.Context) { 221 releasesOrTagsFeed(ctx, false, "rss") 222 } 223 224 // ReleasesFeedAtom get feeds for releases in Atom format 225 func ReleasesFeedAtom(ctx *context.Context) { 226 releasesOrTagsFeed(ctx, true, "atom") 227 } 228 229 // TagsListFeedAtom get feeds for tags in RSS format 230 func TagsListFeedAtom(ctx *context.Context) { 231 releasesOrTagsFeed(ctx, false, "atom") 232 } 233 234 func releasesOrTagsFeed(ctx *context.Context, isReleasesOnly bool, formatType string) { 235 feed.ShowReleaseFeed(ctx, ctx.Repo.Repository, isReleasesOnly, formatType) 236 } 237 238 // SingleRelease renders a single release's page 239 func SingleRelease(ctx *context.Context) { 240 ctx.Data["PageIsReleaseList"] = true 241 ctx.Data["DefaultBranch"] = ctx.Repo.Repository.DefaultBranch 242 243 writeAccess := ctx.Repo.CanWrite(unit.TypeReleases) 244 ctx.Data["CanCreateRelease"] = writeAccess && !ctx.Repo.Repository.IsArchived 245 246 release, err := repo_model.GetRelease(ctx, ctx.Repo.Repository.ID, ctx.Params("*")) 247 if err != nil { 248 if repo_model.IsErrReleaseNotExist(err) { 249 ctx.NotFound("GetRelease", err) 250 return 251 } 252 ctx.ServerError("GetReleasesByRepoID", err) 253 return 254 } 255 ctx.Data["PageIsSingleTag"] = release.IsTag 256 if release.IsTag { 257 ctx.Data["Title"] = release.TagName 258 } else { 259 ctx.Data["Title"] = release.Title 260 } 261 262 release.Repo = ctx.Repo.Repository 263 264 err = repo_model.GetReleaseAttachments(ctx, release) 265 if err != nil { 266 ctx.ServerError("GetReleaseAttachments", err) 267 return 268 } 269 270 release.Publisher, err = user_model.GetUserByID(ctx, release.PublisherID) 271 if err != nil { 272 if user_model.IsErrUserNotExist(err) { 273 release.Publisher = user_model.NewGhostUser() 274 } else { 275 ctx.ServerError("GetUserByID", err) 276 return 277 } 278 } 279 if !release.IsDraft { 280 if err := calReleaseNumCommitsBehind(ctx.Repo, release, make(map[string]int64)); err != nil { 281 ctx.ServerError("calReleaseNumCommitsBehind", err) 282 return 283 } 284 } 285 release.Note, err = markdown.RenderString(&markup.RenderContext{ 286 Links: markup.Links{ 287 Base: ctx.Repo.RepoLink, 288 }, 289 Metas: ctx.Repo.Repository.ComposeMetas(), 290 GitRepo: ctx.Repo.GitRepo, 291 Ctx: ctx, 292 }, release.Note) 293 if err != nil { 294 ctx.ServerError("RenderString", err) 295 return 296 } 297 298 ctx.Data["Releases"] = []*repo_model.Release{release} 299 ctx.HTML(http.StatusOK, tplReleasesList) 300 } 301 302 // LatestRelease redirects to the latest release 303 func LatestRelease(ctx *context.Context) { 304 release, err := repo_model.GetLatestReleaseByRepoID(ctx, ctx.Repo.Repository.ID) 305 if err != nil { 306 if repo_model.IsErrReleaseNotExist(err) { 307 ctx.NotFound("LatestRelease", err) 308 return 309 } 310 ctx.ServerError("GetLatestReleaseByRepoID", err) 311 return 312 } 313 314 if err := release.LoadAttributes(ctx); err != nil { 315 ctx.ServerError("LoadAttributes", err) 316 return 317 } 318 319 ctx.Redirect(release.Link()) 320 } 321 322 // NewRelease render creating or edit release page 323 func NewRelease(ctx *context.Context) { 324 ctx.Data["Title"] = ctx.Tr("repo.release.new_release") 325 ctx.Data["PageIsReleaseList"] = true 326 ctx.Data["tag_target"] = ctx.Repo.Repository.DefaultBranch 327 if tagName := ctx.FormString("tag"); len(tagName) > 0 { 328 rel, err := repo_model.GetRelease(ctx, ctx.Repo.Repository.ID, tagName) 329 if err != nil && !repo_model.IsErrReleaseNotExist(err) { 330 ctx.ServerError("GetRelease", err) 331 return 332 } 333 334 if rel != nil { 335 rel.Repo = ctx.Repo.Repository 336 if err := rel.LoadAttributes(ctx); err != nil { 337 ctx.ServerError("LoadAttributes", err) 338 return 339 } 340 341 ctx.Data["tag_name"] = rel.TagName 342 if rel.Target != "" { 343 ctx.Data["tag_target"] = rel.Target 344 } 345 ctx.Data["title"] = rel.Title 346 ctx.Data["content"] = rel.Note 347 ctx.Data["attachments"] = rel.Attachments 348 } 349 } 350 ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled 351 assigneeUsers, err := repo_model.GetRepoAssignees(ctx, ctx.Repo.Repository) 352 if err != nil { 353 ctx.ServerError("GetRepoAssignees", err) 354 return 355 } 356 ctx.Data["Assignees"] = MakeSelfOnTop(ctx.Doer, assigneeUsers) 357 358 upload.AddUploadContext(ctx, "release") 359 360 // For New Release page 361 PrepareBranchList(ctx) 362 if ctx.Written() { 363 return 364 } 365 366 tags, err := repo_model.GetTagNamesByRepoID(ctx, ctx.Repo.Repository.ID) 367 if err != nil { 368 ctx.ServerError("GetTagNamesByRepoID", err) 369 return 370 } 371 ctx.Data["Tags"] = tags 372 373 ctx.HTML(http.StatusOK, tplReleaseNew) 374 } 375 376 // NewReleasePost response for creating a release 377 func NewReleasePost(ctx *context.Context) { 378 form := web.GetForm(ctx).(*forms.NewReleaseForm) 379 ctx.Data["Title"] = ctx.Tr("repo.release.new_release") 380 ctx.Data["PageIsReleaseList"] = true 381 382 tags, err := repo_model.GetTagNamesByRepoID(ctx, ctx.Repo.Repository.ID) 383 if err != nil { 384 ctx.ServerError("GetTagNamesByRepoID", err) 385 return 386 } 387 ctx.Data["Tags"] = tags 388 389 if ctx.HasError() { 390 ctx.HTML(http.StatusOK, tplReleaseNew) 391 return 392 } 393 394 if !ctx.Repo.GitRepo.IsBranchExist(form.Target) { 395 ctx.RenderWithErr(ctx.Tr("form.target_branch_not_exist"), tplReleaseNew, &form) 396 return 397 } 398 399 // Title of release cannot be empty 400 if len(form.TagOnly) == 0 && len(form.Title) == 0 { 401 ctx.RenderWithErr(ctx.Tr("repo.release.title_empty"), tplReleaseNew, &form) 402 return 403 } 404 405 var attachmentUUIDs []string 406 if setting.Attachment.Enabled { 407 attachmentUUIDs = form.Files 408 } 409 410 rel, err := repo_model.GetRelease(ctx, ctx.Repo.Repository.ID, form.TagName) 411 if err != nil { 412 if !repo_model.IsErrReleaseNotExist(err) { 413 ctx.ServerError("GetRelease", err) 414 return 415 } 416 417 msg := "" 418 if len(form.Title) > 0 && form.AddTagMsg { 419 msg = form.Title + "\n\n" + form.Content 420 } 421 422 if len(form.TagOnly) > 0 { 423 if err = releaseservice.CreateNewTag(ctx, ctx.Doer, ctx.Repo.Repository, form.Target, form.TagName, msg); err != nil { 424 if models.IsErrTagAlreadyExists(err) { 425 e := err.(models.ErrTagAlreadyExists) 426 ctx.Flash.Error(ctx.Tr("repo.branch.tag_collision", e.TagName)) 427 ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()) 428 return 429 } 430 431 if models.IsErrInvalidTagName(err) { 432 ctx.Flash.Error(ctx.Tr("repo.release.tag_name_invalid")) 433 ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()) 434 return 435 } 436 437 if models.IsErrProtectedTagName(err) { 438 ctx.Flash.Error(ctx.Tr("repo.release.tag_name_protected")) 439 ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()) 440 return 441 } 442 443 ctx.ServerError("releaseservice.CreateNewTag", err) 444 return 445 } 446 447 ctx.Flash.Success(ctx.Tr("repo.tag.create_success", form.TagName)) 448 ctx.Redirect(ctx.Repo.RepoLink + "/src/tag/" + util.PathEscapeSegments(form.TagName)) 449 return 450 } 451 452 rel = &repo_model.Release{ 453 RepoID: ctx.Repo.Repository.ID, 454 Repo: ctx.Repo.Repository, 455 PublisherID: ctx.Doer.ID, 456 Publisher: ctx.Doer, 457 Title: form.Title, 458 TagName: form.TagName, 459 Target: form.Target, 460 Note: form.Content, 461 IsDraft: len(form.Draft) > 0, 462 IsPrerelease: form.Prerelease, 463 IsTag: false, 464 } 465 466 if err = releaseservice.CreateRelease(ctx.Repo.GitRepo, rel, attachmentUUIDs, msg); err != nil { 467 ctx.Data["Err_TagName"] = true 468 switch { 469 case repo_model.IsErrReleaseAlreadyExist(err): 470 ctx.RenderWithErr(ctx.Tr("repo.release.tag_name_already_exist"), tplReleaseNew, &form) 471 case models.IsErrInvalidTagName(err): 472 ctx.RenderWithErr(ctx.Tr("repo.release.tag_name_invalid"), tplReleaseNew, &form) 473 case models.IsErrProtectedTagName(err): 474 ctx.RenderWithErr(ctx.Tr("repo.release.tag_name_protected"), tplReleaseNew, &form) 475 default: 476 ctx.ServerError("CreateRelease", err) 477 } 478 return 479 } 480 } else { 481 if !rel.IsTag { 482 ctx.Data["Err_TagName"] = true 483 ctx.RenderWithErr(ctx.Tr("repo.release.tag_name_already_exist"), tplReleaseNew, &form) 484 return 485 } 486 487 rel.Title = form.Title 488 rel.Note = form.Content 489 rel.Target = form.Target 490 rel.IsDraft = len(form.Draft) > 0 491 rel.IsPrerelease = form.Prerelease 492 rel.PublisherID = ctx.Doer.ID 493 rel.IsTag = false 494 495 if err = releaseservice.UpdateRelease(ctx, ctx.Doer, ctx.Repo.GitRepo, rel, attachmentUUIDs, nil, nil); err != nil { 496 ctx.Data["Err_TagName"] = true 497 ctx.ServerError("UpdateRelease", err) 498 return 499 } 500 } 501 log.Trace("Release created: %s/%s:%s", ctx.Doer.LowerName, ctx.Repo.Repository.Name, form.TagName) 502 503 ctx.Redirect(ctx.Repo.RepoLink + "/releases") 504 } 505 506 // EditRelease render release edit page 507 func EditRelease(ctx *context.Context) { 508 ctx.Data["Title"] = ctx.Tr("repo.release.edit_release") 509 ctx.Data["PageIsReleaseList"] = true 510 ctx.Data["PageIsEditRelease"] = true 511 ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled 512 upload.AddUploadContext(ctx, "release") 513 514 tagName := ctx.Params("*") 515 rel, err := repo_model.GetRelease(ctx, ctx.Repo.Repository.ID, tagName) 516 if err != nil { 517 if repo_model.IsErrReleaseNotExist(err) { 518 ctx.NotFound("GetRelease", err) 519 } else { 520 ctx.ServerError("GetRelease", err) 521 } 522 return 523 } 524 ctx.Data["ID"] = rel.ID 525 ctx.Data["tag_name"] = rel.TagName 526 ctx.Data["tag_target"] = rel.Target 527 ctx.Data["title"] = rel.Title 528 ctx.Data["content"] = rel.Note 529 ctx.Data["prerelease"] = rel.IsPrerelease 530 ctx.Data["IsDraft"] = rel.IsDraft 531 532 rel.Repo = ctx.Repo.Repository 533 if err := rel.LoadAttributes(ctx); err != nil { 534 ctx.ServerError("LoadAttributes", err) 535 return 536 } 537 ctx.Data["attachments"] = rel.Attachments 538 539 // Get assignees. 540 assigneeUsers, err := repo_model.GetRepoAssignees(ctx, rel.Repo) 541 if err != nil { 542 ctx.ServerError("GetRepoAssignees", err) 543 return 544 } 545 ctx.Data["Assignees"] = MakeSelfOnTop(ctx.Doer, assigneeUsers) 546 547 ctx.HTML(http.StatusOK, tplReleaseNew) 548 } 549 550 // EditReleasePost response for edit release 551 func EditReleasePost(ctx *context.Context) { 552 form := web.GetForm(ctx).(*forms.EditReleaseForm) 553 ctx.Data["Title"] = ctx.Tr("repo.release.edit_release") 554 ctx.Data["PageIsReleaseList"] = true 555 ctx.Data["PageIsEditRelease"] = true 556 557 tagName := ctx.Params("*") 558 rel, err := repo_model.GetRelease(ctx, ctx.Repo.Repository.ID, tagName) 559 if err != nil { 560 if repo_model.IsErrReleaseNotExist(err) { 561 ctx.NotFound("GetRelease", err) 562 } else { 563 ctx.ServerError("GetRelease", err) 564 } 565 return 566 } 567 if rel.IsTag { 568 ctx.NotFound("GetRelease", err) 569 return 570 } 571 ctx.Data["tag_name"] = rel.TagName 572 ctx.Data["tag_target"] = rel.Target 573 ctx.Data["title"] = rel.Title 574 ctx.Data["content"] = rel.Note 575 ctx.Data["prerelease"] = rel.IsPrerelease 576 577 if ctx.HasError() { 578 ctx.HTML(http.StatusOK, tplReleaseNew) 579 return 580 } 581 582 const delPrefix = "attachment-del-" 583 const editPrefix = "attachment-edit-" 584 var addAttachmentUUIDs, delAttachmentUUIDs []string 585 editAttachments := make(map[string]string) // uuid -> new name 586 if setting.Attachment.Enabled { 587 addAttachmentUUIDs = form.Files 588 for k, v := range ctx.Req.Form { 589 if strings.HasPrefix(k, delPrefix) && v[0] == "true" { 590 delAttachmentUUIDs = append(delAttachmentUUIDs, k[len(delPrefix):]) 591 } else if strings.HasPrefix(k, editPrefix) { 592 editAttachments[k[len(editPrefix):]] = v[0] 593 } 594 } 595 } 596 597 rel.Title = form.Title 598 rel.Note = form.Content 599 rel.IsDraft = len(form.Draft) > 0 600 rel.IsPrerelease = form.Prerelease 601 if err = releaseservice.UpdateRelease(ctx, ctx.Doer, ctx.Repo.GitRepo, 602 rel, addAttachmentUUIDs, delAttachmentUUIDs, editAttachments); err != nil { 603 ctx.ServerError("UpdateRelease", err) 604 return 605 } 606 ctx.Redirect(ctx.Repo.RepoLink + "/releases") 607 } 608 609 // DeleteRelease deletes a release 610 func DeleteRelease(ctx *context.Context) { 611 deleteReleaseOrTag(ctx, false) 612 } 613 614 // DeleteTag deletes a tag 615 func DeleteTag(ctx *context.Context) { 616 deleteReleaseOrTag(ctx, true) 617 } 618 619 func deleteReleaseOrTag(ctx *context.Context, isDelTag bool) { 620 redirect := func() { 621 if isDelTag { 622 ctx.JSONRedirect(ctx.Repo.RepoLink + "/tags") 623 return 624 } 625 626 ctx.JSONRedirect(ctx.Repo.RepoLink + "/releases") 627 } 628 629 rel, err := repo_model.GetReleaseForRepoByID(ctx, ctx.Repo.Repository.ID, ctx.FormInt64("id")) 630 if err != nil { 631 if repo_model.IsErrReleaseNotExist(err) { 632 ctx.NotFound("GetReleaseForRepoByID", err) 633 } else { 634 ctx.Flash.Error("DeleteReleaseByID: " + err.Error()) 635 redirect() 636 } 637 return 638 } 639 640 if err := releaseservice.DeleteReleaseByID(ctx, ctx.Repo.Repository, rel, ctx.Doer, isDelTag); err != nil { 641 if models.IsErrProtectedTagName(err) { 642 ctx.Flash.Error(ctx.Tr("repo.release.tag_name_protected")) 643 } else { 644 ctx.Flash.Error("DeleteReleaseByID: " + err.Error()) 645 } 646 } else { 647 if isDelTag { 648 ctx.Flash.Success(ctx.Tr("repo.release.deletion_tag_success")) 649 } else { 650 ctx.Flash.Success(ctx.Tr("repo.release.deletion_success")) 651 } 652 } 653 654 redirect() 655 }