@@ -17,7 +17,6 @@ import (
1717 "code.gitea.io/gitea/models/unit"
1818 user_model "code.gitea.io/gitea/models/user"
1919 "code.gitea.io/gitea/modules/git"
20- "code.gitea.io/gitea/modules/log"
2120 "code.gitea.io/gitea/modules/markup/markdown"
2221 "code.gitea.io/gitea/modules/optional"
2322 "code.gitea.io/gitea/modules/setting"
@@ -330,12 +329,42 @@ func LatestRelease(ctx *context.Context) {
330329 ctx .Redirect (release .Link ())
331330}
332331
333- // NewRelease render creating or edit release page
334- func NewRelease (ctx * context.Context ) {
332+ func newReleaseCommon (ctx * context.Context ) {
335333 ctx .Data ["Title" ] = ctx .Tr ("repo.release.new_release" )
336334 ctx .Data ["PageIsReleaseList" ] = true
335+
336+ tags , err := repo_model .GetTagNamesByRepoID (ctx , ctx .Repo .Repository .ID )
337+ if err != nil {
338+ ctx .ServerError ("GetTagNamesByRepoID" , err )
339+ return
340+ }
341+ ctx .Data ["Tags" ] = tags
342+
343+ ctx .Data ["IsAttachmentEnabled" ] = setting .Attachment .Enabled
344+ assigneeUsers , err := repo_model .GetRepoAssignees (ctx , ctx .Repo .Repository )
345+ if err != nil {
346+ ctx .ServerError ("GetRepoAssignees" , err )
347+ return
348+ }
349+ ctx .Data ["Assignees" ] = shared_user .MakeSelfOnTop (ctx .Doer , assigneeUsers )
350+
351+ upload .AddUploadContext (ctx , "release" )
352+
353+ PrepareBranchList (ctx ) // for New Release page
354+ }
355+
356+ // NewRelease render creating or edit release page
357+ func NewRelease (ctx * context.Context ) {
358+ newReleaseCommon (ctx )
359+ if ctx .Written () {
360+ return
361+ }
362+
363+ ctx .Data ["ShowCreateTagOnlyButton" ] = true
364+
365+ // pre-fill the form with the tag name, target branch and the existing release (if exists)
337366 ctx .Data ["tag_target" ] = ctx .Repo .Repository .DefaultBranch
338- if tagName := ctx .FormString ("tag" ); len ( tagName ) > 0 {
367+ if tagName := ctx .FormString ("tag" ); tagName != "" {
339368 rel , err := repo_model .GetRelease (ctx , ctx .Repo .Repository .ID , tagName )
340369 if err != nil && ! repo_model .IsErrReleaseNotExist (err ) {
341370 ctx .ServerError ("GetRelease" , err )
@@ -344,59 +373,51 @@ func NewRelease(ctx *context.Context) {
344373
345374 if rel != nil {
346375 rel .Repo = ctx .Repo .Repository
347- if err : = rel .LoadAttributes (ctx ); err != nil {
376+ if err = rel .LoadAttributes (ctx ); err != nil {
348377 ctx .ServerError ("LoadAttributes" , err )
349378 return
350379 }
351380
381+ ctx .Data ["ShowCreateTagOnlyButton" ] = false
352382 ctx .Data ["tag_name" ] = rel .TagName
353- if rel .Target != "" {
354- ctx .Data ["tag_target" ] = rel .Target
355- }
383+ ctx .Data ["tag_target" ] = rel .Target
356384 ctx .Data ["title" ] = rel .Title
357385 ctx .Data ["content" ] = rel .Note
358386 ctx .Data ["attachments" ] = rel .Attachments
359387 }
360388 }
361- ctx .Data ["IsAttachmentEnabled" ] = setting .Attachment .Enabled
362- assigneeUsers , err := repo_model .GetRepoAssignees (ctx , ctx .Repo .Repository )
363- if err != nil {
364- ctx .ServerError ("GetRepoAssignees" , err )
365- return
366- }
367- ctx .Data ["Assignees" ] = shared_user .MakeSelfOnTop (ctx .Doer , assigneeUsers )
368-
369- upload .AddUploadContext (ctx , "release" )
370-
371- // For New Release page
372- PrepareBranchList (ctx )
373- if ctx .Written () {
374- return
375- }
376-
377- tags , err := repo_model .GetTagNamesByRepoID (ctx , ctx .Repo .Repository .ID )
378- if err != nil {
379- ctx .ServerError ("GetTagNamesByRepoID" , err )
380- return
381- }
382- ctx .Data ["Tags" ] = tags
383389
384390 ctx .HTML (http .StatusOK , tplReleaseNew )
385391}
386392
387393// NewReleasePost response for creating a release
388394func NewReleasePost (ctx * context.Context ) {
395+ newReleaseCommon (ctx )
396+ if ctx .Written () {
397+ return
398+ }
399+
389400 form := web .GetForm (ctx ).(* forms.NewReleaseForm )
390- ctx .Data ["Title" ] = ctx .Tr ("repo.release.new_release" )
391- ctx .Data ["PageIsReleaseList" ] = true
392401
393- tags , err := repo_model .GetTagNamesByRepoID (ctx , ctx .Repo .Repository .ID )
394- if err != nil {
395- ctx .ServerError ("GetTagNamesByRepoID" , err )
402+ // first, check whether the release exists, and prepare "ShowCreateTagOnlyButton"
403+ // the logic should be done before the form error check to make the tmpl has correct variables
404+ rel , err := repo_model .GetRelease (ctx , ctx .Repo .Repository .ID , form .TagName )
405+ if err != nil && ! repo_model .IsErrReleaseNotExist (err ) {
406+ ctx .ServerError ("GetRelease" , err )
396407 return
397408 }
398- ctx .Data ["Tags" ] = tags
399409
410+ // We should still show the "tag only" button if the user clicks it, no matter the release exists or not.
411+ // Because if error occurs, end users need to have the chance to edit the name and submit the form with "tag-only" again.
412+ // It is still not completely right, because there could still be cases like this:
413+ // * user visit "new release" page, see the "tag only" button
414+ // * input something, click other buttons but not "tag only"
415+ // * error occurs, the "new release" page is rendered again, but the "tag only" button is gone
416+ // Such cases are not able to be handled by current code, it needs frontend code to toggle the "tag-only" button if the input changes.
417+ // Or another choice is "always show the tag-only button" if error occurs.
418+ ctx .Data ["ShowCreateTagOnlyButton" ] = form .TagOnly || rel == nil
419+
420+ // do some form checks
400421 if ctx .HasError () {
401422 ctx .HTML (http .StatusOK , tplReleaseNew )
402423 return
@@ -407,59 +428,49 @@ func NewReleasePost(ctx *context.Context) {
407428 return
408429 }
409430
410- // Title of release cannot be empty
411- if len ( form . TagOnly ) == 0 && len ( form . Title ) == 0 {
431+ if ! form . TagOnly && form . Title == "" {
432+ // if not "tag only", then the title of the release cannot be empty
412433 ctx .RenderWithErr (ctx .Tr ("repo.release.title_empty" ), tplReleaseNew , & form )
413434 return
414435 }
415436
416- var attachmentUUIDs []string
417- if setting .Attachment .Enabled {
418- attachmentUUIDs = form .Files
419- }
420-
421- rel , err := repo_model .GetRelease (ctx , ctx .Repo .Repository .ID , form .TagName )
422- if err != nil {
423- if ! repo_model .IsErrReleaseNotExist (err ) {
424- ctx .ServerError ("GetRelease" , err )
425- return
426- }
427-
428- msg := ""
429- if len (form .Title ) > 0 && form .AddTagMsg {
430- msg = form .Title + "\n \n " + form .Content
437+ handleTagReleaseError := func (err error ) {
438+ ctx .Data ["Err_TagName" ] = true
439+ switch {
440+ case release_service .IsErrTagAlreadyExists (err ):
441+ ctx .RenderWithErr (ctx .Tr ("repo.branch.tag_collision" , form .TagName ), tplReleaseNew , & form )
442+ case repo_model .IsErrReleaseAlreadyExist (err ):
443+ ctx .RenderWithErr (ctx .Tr ("repo.release.tag_name_already_exist" ), tplReleaseNew , & form )
444+ case release_service .IsErrInvalidTagName (err ):
445+ ctx .RenderWithErr (ctx .Tr ("repo.release.tag_name_invalid" ), tplReleaseNew , & form )
446+ case release_service .IsErrProtectedTagName (err ):
447+ ctx .RenderWithErr (ctx .Tr ("repo.release.tag_name_protected" ), tplReleaseNew , & form )
448+ default :
449+ ctx .ServerError ("handleTagReleaseError" , err )
431450 }
451+ }
432452
433- if len (form .TagOnly ) > 0 {
434- if err = release_service .CreateNewTag (ctx , ctx .Doer , ctx .Repo .Repository , form .Target , form .TagName , msg ); err != nil {
435- if release_service .IsErrTagAlreadyExists (err ) {
436- e := err .(release_service.ErrTagAlreadyExists )
437- ctx .Flash .Error (ctx .Tr ("repo.branch.tag_collision" , e .TagName ))
438- ctx .Redirect (ctx .Repo .RepoLink + "/src/" + ctx .Repo .RefTypeNameSubURL ())
439- return
440- }
441-
442- if release_service .IsErrInvalidTagName (err ) {
443- ctx .Flash .Error (ctx .Tr ("repo.release.tag_name_invalid" ))
444- ctx .Redirect (ctx .Repo .RepoLink + "/src/" + ctx .Repo .RefTypeNameSubURL ())
445- return
446- }
447-
448- if release_service .IsErrProtectedTagName (err ) {
449- ctx .Flash .Error (ctx .Tr ("repo.release.tag_name_protected" ))
450- ctx .Redirect (ctx .Repo .RepoLink + "/src/" + ctx .Repo .RefTypeNameSubURL ())
451- return
452- }
453-
454- ctx .ServerError ("release_service.CreateNewTag" , err )
455- return
456- }
453+ // prepare the git message for creating a new tag
454+ newTagMsg := ""
455+ if form .Title != "" && form .AddTagMsg {
456+ newTagMsg = form .Title + "\n \n " + form .Content
457+ }
457458
458- ctx .Flash .Success (ctx .Tr ("repo.tag.create_success" , form .TagName ))
459- ctx .Redirect (ctx .Repo .RepoLink + "/src/tag/" + util .PathEscapeSegments (form .TagName ))
459+ // no release, and tag only
460+ if rel == nil && form .TagOnly {
461+ if err = release_service .CreateNewTag (ctx , ctx .Doer , ctx .Repo .Repository , form .Target , form .TagName , newTagMsg ); err != nil {
462+ handleTagReleaseError (err )
460463 return
461464 }
465+ ctx .Flash .Success (ctx .Tr ("repo.tag.create_success" , form .TagName ))
466+ ctx .Redirect (ctx .Repo .RepoLink + "/src/tag/" + util .PathEscapeSegments (form .TagName ))
467+ return
468+ }
469+
470+ attachmentUUIDs := util .Iif (setting .Attachment .Enabled , form .Files , nil )
462471
472+ // no existing release, create a new release
473+ if rel == nil {
463474 rel = & repo_model.Release {
464475 RepoID : ctx .Repo .Repository .ID ,
465476 Repo : ctx .Repo .Repository ,
@@ -469,48 +480,39 @@ func NewReleasePost(ctx *context.Context) {
469480 TagName : form .TagName ,
470481 Target : form .Target ,
471482 Note : form .Content ,
472- IsDraft : len ( form .Draft ) > 0 ,
483+ IsDraft : form .Draft ,
473484 IsPrerelease : form .Prerelease ,
474485 IsTag : false ,
475486 }
476-
477- if err = release_service .CreateRelease (ctx .Repo .GitRepo , rel , attachmentUUIDs , msg ); err != nil {
478- ctx .Data ["Err_TagName" ] = true
479- switch {
480- case repo_model .IsErrReleaseAlreadyExist (err ):
481- ctx .RenderWithErr (ctx .Tr ("repo.release.tag_name_already_exist" ), tplReleaseNew , & form )
482- case release_service .IsErrInvalidTagName (err ):
483- ctx .RenderWithErr (ctx .Tr ("repo.release.tag_name_invalid" ), tplReleaseNew , & form )
484- case release_service .IsErrProtectedTagName (err ):
485- ctx .RenderWithErr (ctx .Tr ("repo.release.tag_name_protected" ), tplReleaseNew , & form )
486- default :
487- ctx .ServerError ("CreateRelease" , err )
488- }
489- return
490- }
491- } else {
492- if ! rel .IsTag {
493- ctx .Data ["Err_TagName" ] = true
494- ctx .RenderWithErr (ctx .Tr ("repo.release.tag_name_already_exist" ), tplReleaseNew , & form )
487+ if err = release_service .CreateRelease (ctx .Repo .GitRepo , rel , attachmentUUIDs , newTagMsg ); err != nil {
488+ handleTagReleaseError (err )
495489 return
496490 }
491+ ctx .Redirect (ctx .Repo .RepoLink + "/releases" )
492+ return
493+ }
497494
498- rel .Title = form .Title
499- rel .Note = form .Content
500- rel .Target = form .Target
501- rel .IsDraft = len (form .Draft ) > 0
502- rel .IsPrerelease = form .Prerelease
503- rel .PublisherID = ctx .Doer .ID
504- rel .IsTag = false
505-
506- if err = release_service .UpdateRelease (ctx , ctx .Doer , ctx .Repo .GitRepo , rel , attachmentUUIDs , nil , nil ); err != nil {
507- ctx .Data ["Err_TagName" ] = true
508- ctx .ServerError ("UpdateRelease" , err )
509- return
510- }
495+ // tag exists, try to convert it to a real release
496+ // old logic: if the release is not a tag (it is a real release), do not update it on the "new release" page
497+ // add new logic: if tag-only, do not convert the tag to a release
498+ if form .TagOnly || ! rel .IsTag {
499+ ctx .Data ["Err_TagName" ] = true
500+ ctx .RenderWithErr (ctx .Tr ("repo.release.tag_name_already_exist" ), tplReleaseNew , & form )
501+ return
511502 }
512- log .Trace ("Release created: %s/%s:%s" , ctx .Doer .LowerName , ctx .Repo .Repository .Name , form .TagName )
513503
504+ // convert a tag to a real release (set is_tag=false)
505+ rel .Title = form .Title
506+ rel .Note = form .Content
507+ rel .Target = form .Target
508+ rel .IsDraft = form .Draft
509+ rel .IsPrerelease = form .Prerelease
510+ rel .PublisherID = ctx .Doer .ID
511+ rel .IsTag = false
512+ if err = release_service .UpdateRelease (ctx , ctx .Doer , ctx .Repo .GitRepo , rel , attachmentUUIDs , nil , nil ); err != nil {
513+ handleTagReleaseError (err )
514+ return
515+ }
514516 ctx .Redirect (ctx .Repo .RepoLink + "/releases" )
515517}
516518
0 commit comments