@@ -16,6 +16,7 @@ import (
1616 "code.gitea.io/gitea/modules/charset"
1717 "code.gitea.io/gitea/modules/git"
1818 "code.gitea.io/gitea/modules/httplib"
19+ "code.gitea.io/gitea/modules/log"
1920 "code.gitea.io/gitea/modules/markup"
2021 "code.gitea.io/gitea/modules/setting"
2122 "code.gitea.io/gitea/modules/templates"
@@ -39,26 +40,36 @@ const (
3940 editorCommitChoiceNewBranch string = "commit-to-new-branch"
4041)
4142
42- func prepareEditorCommitFormOptions (ctx * context.Context , editorAction string ) {
43+ func prepareEditorCommitFormOptions (ctx * context.Context , editorAction string ) * context. CommitFormOptions {
4344 cleanedTreePath := files_service .CleanGitTreePath (ctx .Repo .TreePath )
4445 if cleanedTreePath != ctx .Repo .TreePath {
4546 redirectTo := fmt .Sprintf ("%s/%s/%s/%s" , ctx .Repo .RepoLink , editorAction , util .PathEscapeSegments (ctx .Repo .BranchName ), util .PathEscapeSegments (cleanedTreePath ))
4647 if ctx .Req .URL .RawQuery != "" {
4748 redirectTo += "?" + ctx .Req .URL .RawQuery
4849 }
4950 ctx .Redirect (redirectTo )
50- return
51+ return nil
5152 }
5253
53- commitFormBehaviors , err := ctx . Repo .PrepareCommitFormBehaviors ( ctx , ctx .Doer )
54+ commitFormOptions , err := context . PrepareCommitFormOptions ( ctx , ctx . Doer , ctx . Repo .Repository , ctx . Repo . Permission , ctx .Repo . RefFullName )
5455 if err != nil {
55- ctx .ServerError ("PrepareCommitFormBehaviors" , err )
56- return
56+ ctx .ServerError ("PrepareCommitFormOptions" , err )
57+ return nil
58+ }
59+
60+ if commitFormOptions .NeedFork {
61+ ForkToEdit (ctx )
62+ return nil
63+ }
64+
65+ if commitFormOptions .WillSubmitToFork && ! commitFormOptions .TargetRepo .CanEnableEditor () {
66+ ctx .Data ["NotFoundPrompt" ] = ctx .Locale .Tr ("repo.editor.fork_not_editable" )
67+ ctx .NotFound (nil )
5768 }
5869
5970 ctx .Data ["BranchLink" ] = ctx .Repo .RepoLink + "/src/" + ctx .Repo .RefTypeNameSubURL ()
6071 ctx .Data ["TreePath" ] = ctx .Repo .TreePath
61- ctx .Data ["CommitFormBehaviors " ] = commitFormBehaviors
72+ ctx .Data ["CommitFormOptions " ] = commitFormOptions
6273
6374 // for online editor
6475 ctx .Data ["PreviewableExtensions" ] = strings .Join (markup .PreviewableExtensions (), "," )
@@ -69,33 +80,34 @@ func prepareEditorCommitFormOptions(ctx *context.Context, editorAction string) {
6980 // form fields
7081 ctx .Data ["commit_summary" ] = ""
7182 ctx .Data ["commit_message" ] = ""
72- ctx .Data ["commit_choice" ] = util .Iif (commitFormBehaviors .CanCommitToBranch , editorCommitChoiceDirect , editorCommitChoiceNewBranch )
73- ctx .Data ["new_branch_name" ] = getUniquePatchBranchName (ctx , ctx .Doer .LowerName , ctx . Repo . Repository )
83+ ctx .Data ["commit_choice" ] = util .Iif (commitFormOptions .CanCommitToBranch , editorCommitChoiceDirect , editorCommitChoiceNewBranch )
84+ ctx .Data ["new_branch_name" ] = getUniquePatchBranchName (ctx , ctx .Doer .LowerName , commitFormOptions . TargetRepo )
7485 ctx .Data ["last_commit" ] = ctx .Repo .CommitID
86+ return commitFormOptions
7587}
7688
7789func prepareTreePathFieldsAndPaths (ctx * context.Context , treePath string ) {
7890 // show the tree path fields in the "breadcrumb" and help users to edit the target tree path
7991 ctx .Data ["TreeNames" ], ctx .Data ["TreePaths" ] = getParentTreeFields (treePath )
8092}
8193
82- type parsedEditorCommitForm [T any ] struct {
83- form T
84- commonForm * forms.CommitCommonForm
85- CommitFormBehaviors * context.CommitFormBehaviors
86- TargetBranchName string
87- GitCommitter * files_service.IdentityOptions
94+ type preparedEditorCommitForm [T any ] struct {
95+ form T
96+ commonForm * forms.CommitCommonForm
97+ CommitFormOptions * context.CommitFormOptions
98+ TargetBranchName string
99+ GitCommitter * files_service.IdentityOptions
88100}
89101
90- func (f * parsedEditorCommitForm [T ]) GetCommitMessage (defaultCommitMessage string ) string {
102+ func (f * preparedEditorCommitForm [T ]) GetCommitMessage (defaultCommitMessage string ) string {
91103 commitMessage := util .IfZero (strings .TrimSpace (f .commonForm .CommitSummary ), defaultCommitMessage )
92104 if body := strings .TrimSpace (f .commonForm .CommitMessage ); body != "" {
93105 commitMessage += "\n \n " + body
94106 }
95107 return commitMessage
96108}
97109
98- func parseEditorCommitSubmittedForm [T forms.CommitCommonFormInterface ](ctx * context.Context ) * parsedEditorCommitForm [T ] {
110+ func prepareEditorCommitSubmittedForm [T forms.CommitCommonFormInterface ](ctx * context.Context ) * preparedEditorCommitForm [T ] {
99111 form := web .GetForm (ctx ).(T )
100112 if ctx .HasError () {
101113 ctx .JSONError (ctx .GetErrMsg ())
@@ -105,15 +117,20 @@ func parseEditorCommitSubmittedForm[T forms.CommitCommonFormInterface](ctx *cont
105117 commonForm := form .GetCommitCommonForm ()
106118 commonForm .TreePath = files_service .CleanGitTreePath (commonForm .TreePath )
107119
108- commitFormBehaviors , err := ctx . Repo .PrepareCommitFormBehaviors ( ctx , ctx .Doer )
120+ commitFormOptions , err := context . PrepareCommitFormOptions ( ctx , ctx . Doer , ctx . Repo .Repository , ctx . Repo . Permission , ctx .Repo . RefFullName )
109121 if err != nil {
110- ctx .ServerError ("PrepareCommitFormBehaviors" , err )
122+ ctx .ServerError ("PrepareCommitFormOptions" , err )
123+ return nil
124+ }
125+ if commitFormOptions .NeedFork {
126+ // It shouldn't happen, because we should have done the checks in the "GET" request. But just in case.
127+ ctx .JSONError (ctx .Locale .TrString ("error.not_found" ))
111128 return nil
112129 }
113130
114131 // check commit behavior
115132 targetBranchName := util .Iif (commonForm .CommitChoice == editorCommitChoiceNewBranch , commonForm .NewBranchName , ctx .Repo .BranchName )
116- if targetBranchName == ctx .Repo .BranchName && ! commitFormBehaviors .CanCommitToBranch {
133+ if targetBranchName == ctx .Repo .BranchName && ! commitFormOptions .CanCommitToBranch {
117134 ctx .JSONError (ctx .Tr ("repo.editor.cannot_commit_to_protected_branch" , targetBranchName ))
118135 return nil
119136 }
@@ -125,28 +142,38 @@ func parseEditorCommitSubmittedForm[T forms.CommitCommonFormInterface](ctx *cont
125142 return nil
126143 }
127144
128- return & parsedEditorCommitForm [T ]{
129- form : form ,
130- commonForm : commonForm ,
131- CommitFormBehaviors : commitFormBehaviors ,
132- TargetBranchName : targetBranchName ,
133- GitCommitter : gitCommitter ,
145+ fromBaseBranch := ctx .FormString ("from_base_branch" )
146+ if fromBaseBranch != "" {
147+ err = editorPushBranchToForkedRepository (ctx , ctx .Doer , ctx .Repo .Repository .BaseRepo , fromBaseBranch , ctx .Repo .Repository , ctx .Repo .RefFullName .BranchName ())
148+ if err != nil {
149+ log .Error ("Unable to editorPushBranchToForkedRepository: %v" , err )
150+ ctx .JSONError (ctx .Tr ("repo.editor.fork_failed_to_push_branch" , targetBranchName ))
151+ return nil
152+ }
153+ }
154+
155+ return & preparedEditorCommitForm [T ]{
156+ form : form ,
157+ commonForm : commonForm ,
158+ CommitFormOptions : commitFormOptions ,
159+ TargetBranchName : targetBranchName ,
160+ GitCommitter : gitCommitter ,
134161 }
135162}
136163
137164// redirectForCommitChoice redirects after committing the edit to a branch
138- func redirectForCommitChoice [T any ](ctx * context.Context , parsed * parsedEditorCommitForm [T ], treePath string ) {
165+ func redirectForCommitChoice [T any ](ctx * context.Context , parsed * preparedEditorCommitForm [T ], treePath string ) {
139166 if parsed .commonForm .CommitChoice == editorCommitChoiceNewBranch {
140167 // Redirect to a pull request when possible
141168 redirectToPullRequest := false
142169 repo , baseBranch , headBranch := ctx .Repo .Repository , ctx .Repo .BranchName , parsed .TargetBranchName
143- if repo .UnitEnabled (ctx , unit .TypePullRequests ) {
144- redirectToPullRequest = true
145- } else if parsed .CommitFormBehaviors .CanCreateBasePullRequest {
170+ if ctx .Repo .Repository .IsFork && parsed .CommitFormOptions .CanCreateBasePullRequest {
146171 redirectToPullRequest = true
147172 baseBranch = repo .BaseRepo .DefaultBranch
148173 headBranch = repo .Owner .Name + "/" + repo .Name + ":" + headBranch
149174 repo = repo .BaseRepo
175+ } else if repo .UnitEnabled (ctx , unit .TypePullRequests ) {
176+ redirectToPullRequest = true
150177 }
151178 if redirectToPullRequest {
152179 ctx .JSONRedirect (repo .Link () + "/compare/" + util .PathEscapeSegments (baseBranch ) + "..." + util .PathEscapeSegments (headBranch ))
@@ -268,7 +295,7 @@ func EditFile(ctx *context.Context) {
268295func EditFilePost (ctx * context.Context ) {
269296 editorAction := ctx .PathParam ("editor_action" )
270297 isNewFile := editorAction == "_new"
271- parsed := parseEditorCommitSubmittedForm [* forms.EditRepoFileForm ](ctx )
298+ parsed := prepareEditorCommitSubmittedForm [* forms.EditRepoFileForm ](ctx )
272299 if ctx .Written () {
273300 return
274301 }
@@ -327,7 +354,7 @@ func DeleteFile(ctx *context.Context) {
327354
328355// DeleteFilePost response for deleting file
329356func DeleteFilePost (ctx * context.Context ) {
330- parsed := parseEditorCommitSubmittedForm [* forms.DeleteRepoFileForm ](ctx )
357+ parsed := prepareEditorCommitSubmittedForm [* forms.DeleteRepoFileForm ](ctx )
331358 if ctx .Written () {
332359 return
333360 }
@@ -360,18 +387,18 @@ func DeleteFilePost(ctx *context.Context) {
360387
361388func UploadFile (ctx * context.Context ) {
362389 ctx .Data ["PageIsUpload" ] = true
363- upload .AddUploadContext (ctx , "repo" )
364390 prepareTreePathFieldsAndPaths (ctx , ctx .Repo .TreePath )
365-
366- prepareEditorCommitFormOptions (ctx , "_upload" )
391+ opts := prepareEditorCommitFormOptions (ctx , "_upload" )
367392 if ctx .Written () {
368393 return
369394 }
395+ upload .AddUploadContextForRepo (ctx , opts .TargetRepo )
396+
370397 ctx .HTML (http .StatusOK , tplUploadFile )
371398}
372399
373400func UploadFilePost (ctx * context.Context ) {
374- parsed := parseEditorCommitSubmittedForm [* forms.UploadRepoFileForm ](ctx )
401+ parsed := prepareEditorCommitSubmittedForm [* forms.UploadRepoFileForm ](ctx )
375402 if ctx .Written () {
376403 return
377404 }
0 commit comments