@ -17,7 +17,6 @@ import (
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markup/markdown"
"code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
@ -330,12 +329,42 @@ func LatestRelease(ctx *context.Context) {
ctx . Redirect ( release . Link ( ) )
}
// NewRelease render creating or edit release page
func NewRelease ( ctx * context . Context ) {
func newReleaseCommon ( ctx * context . Context ) {
ctx . Data [ "Title" ] = ctx . Tr ( "repo.release.new_release" )
ctx . Data [ "PageIsReleaseList" ] = true
tags , err := repo_model . GetTagNamesByRepoID ( ctx , ctx . Repo . Repository . ID )
if err != nil {
ctx . ServerError ( "GetTagNamesByRepoID" , err )
return
}
ctx . Data [ "Tags" ] = tags
ctx . Data [ "IsAttachmentEnabled" ] = setting . Attachment . Enabled
assigneeUsers , err := repo_model . GetRepoAssignees ( ctx , ctx . Repo . Repository )
if err != nil {
ctx . ServerError ( "GetRepoAssignees" , err )
return
}
ctx . Data [ "Assignees" ] = shared_user . MakeSelfOnTop ( ctx . Doer , assigneeUsers )
upload . AddUploadContext ( ctx , "release" )
PrepareBranchList ( ctx ) // for New Release page
}
// NewRelease render creating or edit release page
func NewRelease ( ctx * context . Context ) {
newReleaseCommon ( ctx )
if ctx . Written ( ) {
return
}
ctx . Data [ "ShowCreateTagOnlyButton" ] = true
// pre-fill the form with the tag name, target branch and the existing release (if exists)
ctx . Data [ "tag_target" ] = ctx . Repo . Repository . DefaultBranch
if tagName := ctx . FormString ( "tag" ) ; len ( tagName ) > 0 {
if tagName := ctx . FormString ( "tag" ) ; tagName != "" {
rel , err := repo_model . GetRelease ( ctx , ctx . Repo . Repository . ID , tagName )
if err != nil && ! repo_model . IsErrReleaseNotExist ( err ) {
ctx . ServerError ( "GetRelease" , err )
@ -344,59 +373,51 @@ func NewRelease(ctx *context.Context) {
if rel != nil {
rel . Repo = ctx . Repo . Repository
if err : = rel . LoadAttributes ( ctx ) ; err != nil {
if err = rel . LoadAttributes ( ctx ) ; err != nil {
ctx . ServerError ( "LoadAttributes" , err )
return
}
ctx . Data [ "ShowCreateTagOnlyButton" ] = false
ctx . Data [ "tag_name" ] = rel . TagName
if rel . Target != "" {
ctx . Data [ "tag_target" ] = rel . Target
}
ctx . Data [ "tag_target" ] = rel . Target
ctx . Data [ "title" ] = rel . Title
ctx . Data [ "content" ] = rel . Note
ctx . Data [ "attachments" ] = rel . Attachments
}
}
ctx . Data [ "IsAttachmentEnabled" ] = setting . Attachment . Enabled
assigneeUsers , err := repo_model . GetRepoAssignees ( ctx , ctx . Repo . Repository )
if err != nil {
ctx . ServerError ( "GetRepoAssignees" , err )
return
}
ctx . Data [ "Assignees" ] = shared_user . MakeSelfOnTop ( ctx . Doer , assigneeUsers )
upload . AddUploadContext ( ctx , "release" )
// For New Release page
PrepareBranchList ( ctx )
if ctx . Written ( ) {
return
}
tags , err := repo_model . GetTagNamesByRepoID ( ctx , ctx . Repo . Repository . ID )
if err != nil {
ctx . ServerError ( "GetTagNamesByRepoID" , err )
return
}
ctx . Data [ "Tags" ] = tags
ctx . HTML ( http . StatusOK , tplReleaseNew )
}
// NewReleasePost response for creating a release
func NewReleasePost ( ctx * context . Context ) {
newReleaseCommon ( ctx )
if ctx . Written ( ) {
return
}
form := web . GetForm ( ctx ) . ( * forms . NewReleaseForm )
ctx . Data [ "Title" ] = ctx . Tr ( "repo.release.new_release" )
ctx . Data [ "PageIsReleaseList" ] = true
tags , err := repo_model . GetTagNamesByRepoID ( ctx , ctx . Repo . Repository . ID )
if err != nil {
ctx . ServerError ( "GetTagNamesByRepoID" , err )
// first, check whether the release exists, and prepare "ShowCreateTagOnlyButton"
// the logic should be done before the form error check to make the tmpl has correct variables
rel , err := repo_model . GetRelease ( ctx , ctx . Repo . Repository . ID , form . TagName )
if err != nil && ! repo_model . IsErrReleaseNotExist ( err ) {
ctx . ServerError ( "GetRelease" , err )
return
}
ctx . Data [ "Tags" ] = tags
// We should still show the "tag only" button if the user clicks it, no matter the release exists or not.
// Because if error occurs, end users need to have the chance to edit the name and submit the form with "tag-only" again.
// It is still not completely right, because there could still be cases like this:
// * user visit "new release" page, see the "tag only" button
// * input something, click other buttons but not "tag only"
// * error occurs, the "new release" page is rendered again, but the "tag only" button is gone
// 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.
// Or another choice is "always show the tag-only button" if error occurs.
ctx . Data [ "ShowCreateTagOnlyButton" ] = form . TagOnly || rel == nil
// do some form checks
if ctx . HasError ( ) {
ctx . HTML ( http . StatusOK , tplReleaseNew )
return
@ -407,59 +428,49 @@ func NewReleasePost(ctx *context.Context) {
return
}
// Title of release cannot be empty
if len ( form . TagOnly ) == 0 && len ( form . Title ) == 0 {
if ! form . TagOnly && form . Title == "" {
// if not "tag only", then the title of the release cannot be empty
ctx . RenderWithErr ( ctx . Tr ( "repo.release.title_empty" ) , tplReleaseNew , & form )
return
}
var attachmentUUIDs [ ] string
if setting . Attachment . Enabled {
attachmentUUIDs = form . Files
}
rel , err := repo_model . GetRelease ( ctx , ctx . Repo . Repository . ID , form . TagName )
if err != nil {
if ! repo_model . IsErrReleaseNotExist ( err ) {
ctx . ServerError ( "GetRelease" , err )
return
}
msg := ""
if len ( form . Title ) > 0 && form . AddTagMsg {
msg = form . Title + "\n\n" + form . Content
handleTagReleaseError := func ( err error ) {
ctx . Data [ "Err_TagName" ] = true
switch {
case release_service . IsErrTagAlreadyExists ( err ) :
ctx . RenderWithErr ( ctx . Tr ( "repo.branch.tag_collision" , form . TagName ) , tplReleaseNew , & form )
case repo_model . IsErrReleaseAlreadyExist ( err ) :
ctx . RenderWithErr ( ctx . Tr ( "repo.release.tag_name_already_exist" ) , tplReleaseNew , & form )
case release_service . IsErrInvalidTagName ( err ) :
ctx . RenderWithErr ( ctx . Tr ( "repo.release.tag_name_invalid" ) , tplReleaseNew , & form )
case release_service . IsErrProtectedTagName ( err ) :
ctx . RenderWithErr ( ctx . Tr ( "repo.release.tag_name_protected" ) , tplReleaseNew , & form )
default :
ctx . ServerError ( "handleTagReleaseError" , err )
}
}
if len ( form . TagOnly ) > 0 {
if err = release_service . CreateNewTag ( ctx , ctx . Doer , ctx . Repo . Repository , form . Target , form . TagName , msg ) ; err != nil {
if release_service . IsErrTagAlreadyExists ( err ) {
e := err . ( release_service . ErrTagAlreadyExists )
ctx . Flash . Error ( ctx . Tr ( "repo.branch.tag_collision" , e . TagName ) )
ctx . Redirect ( ctx . Repo . RepoLink + "/src/" + ctx . Repo . RefTypeNameSubURL ( ) )
return
}
if release_service . IsErrInvalidTagName ( err ) {
ctx . Flash . Error ( ctx . Tr ( "repo.release.tag_name_invalid" ) )
ctx . Redirect ( ctx . Repo . RepoLink + "/src/" + ctx . Repo . RefTypeNameSubURL ( ) )
return
}
if release_service . IsErrProtectedTagName ( err ) {
ctx . Flash . Error ( ctx . Tr ( "repo.release.tag_name_protected" ) )
ctx . Redirect ( ctx . Repo . RepoLink + "/src/" + ctx . Repo . RefTypeNameSubURL ( ) )
return
}
ctx . ServerError ( "release_service.CreateNewTag" , err )
return
}
// prepare the git message for creating a new tag
newTagMsg := ""
if form . Title != "" && form . AddTagMsg {
newTagMsg = form . Title + "\n\n" + form . Content
}
ctx . Flash . Success ( ctx . Tr ( "repo.tag.create_success" , form . TagName ) )
ctx . Redirect ( ctx . Repo . RepoLink + "/src/tag/" + util . PathEscapeSegments ( form . TagName ) )
// no release, and tag only
if rel == nil && form . TagOnly {
if err = release_service . CreateNewTag ( ctx , ctx . Doer , ctx . Repo . Repository , form . Target , form . TagName , newTagMsg ) ; err != nil {
handleTagReleaseError ( err )
return
}
ctx . Flash . Success ( ctx . Tr ( "repo.tag.create_success" , form . TagName ) )
ctx . Redirect ( ctx . Repo . RepoLink + "/src/tag/" + util . PathEscapeSegments ( form . TagName ) )
return
}
attachmentUUIDs := util . Iif ( setting . Attachment . Enabled , form . Files , nil )
// no existing release, create a new release
if rel == nil {
rel = & repo_model . Release {
RepoID : ctx . Repo . Repository . ID ,
Repo : ctx . Repo . Repository ,
@ -469,48 +480,39 @@ func NewReleasePost(ctx *context.Context) {
TagName : form . TagName ,
Target : form . Target ,
Note : form . Content ,
IsDraft : len ( form . Draft ) > 0 ,
IsDraft : form . Draft ,
IsPrerelease : form . Prerelease ,
IsTag : false ,
}
if err = release_service . CreateRelease ( ctx . Repo . GitRepo , rel , attachmentUUIDs , msg ) ; err != nil {
ctx . Data [ "Err_TagName" ] = true
switch {
case repo_model . IsErrReleaseAlreadyExist ( err ) :
ctx . RenderWithErr ( ctx . Tr ( "repo.release.tag_name_already_exist" ) , tplReleaseNew , & form )
case release_service . IsErrInvalidTagName ( err ) :
ctx . RenderWithErr ( ctx . Tr ( "repo.release.tag_name_invalid" ) , tplReleaseNew , & form )
case release_service . IsErrProtectedTagName ( err ) :
ctx . RenderWithErr ( ctx . Tr ( "repo.release.tag_name_protected" ) , tplReleaseNew , & form )
default :
ctx . ServerError ( "CreateRelease" , err )
}
return
}
} else {
if ! rel . IsTag {
ctx . Data [ "Err_TagName" ] = true
ctx . RenderWithErr ( ctx . Tr ( "repo.release.tag_name_already_exist" ) , tplReleaseNew , & form )
if err = release_service . CreateRelease ( ctx . Repo . GitRepo , rel , attachmentUUIDs , newTagMsg ) ; err != nil {
handleTagReleaseError ( err )
return
}
ctx . Redirect ( ctx . Repo . RepoLink + "/releases" )
return
}
rel . Title = form . Title
rel . Note = form . Content
rel . Target = form . Target
rel . IsDraft = len ( form . Draft ) > 0
rel . IsPrerelease = form . Prerelease
rel . PublisherID = ctx . Doer . ID
rel . IsTag = false
if err = release_service . UpdateRelease ( ctx , ctx . Doer , ctx . Repo . GitRepo , rel , attachmentUUIDs , nil , nil ) ; err != nil {
ctx . Data [ "Err_TagName" ] = true
ctx . ServerError ( "UpdateRelease" , err )
return
}
// tag exists, try to convert it to a real release
// old logic: if the release is not a tag (it is a real release), do not update it on the "new release" page
// add new logic: if tag-only, do not convert the tag to a release
if form . TagOnly || ! rel . IsTag {
ctx . Data [ "Err_TagName" ] = true
ctx . RenderWithErr ( ctx . Tr ( "repo.release.tag_name_already_exist" ) , tplReleaseNew , & form )
return
}
log . Trace ( "Release created: %s/%s:%s" , ctx . Doer . LowerName , ctx . Repo . Repository . Name , form . TagName )
// convert a tag to a real release (set is_tag=false)
rel . Title = form . Title
rel . Note = form . Content
rel . Target = form . Target
rel . IsDraft = form . Draft
rel . IsPrerelease = form . Prerelease
rel . PublisherID = ctx . Doer . ID
rel . IsTag = false
if err = release_service . UpdateRelease ( ctx , ctx . Doer , ctx . Repo . GitRepo , rel , attachmentUUIDs , nil , nil ) ; err != nil {
handleTagReleaseError ( err )
return
}
ctx . Redirect ( ctx . Repo . RepoLink + "/releases" )
}