@@ -7,304 +7,13 @@ import (
7
7
"net/http"
8
8
"strings"
9
9
10
- access_model "code.gitea.io/gitea/models/perm/access"
11
- repo_model "code.gitea.io/gitea/models/repo"
12
- "code.gitea.io/gitea/models/unit"
13
10
user_model "code.gitea.io/gitea/models/user"
14
- "code.gitea.io/gitea/modules/git"
15
11
"code.gitea.io/gitea/modules/gitrepo"
16
- "code.gitea.io/gitea/modules/log"
17
12
api "code.gitea.io/gitea/modules/structs"
18
- "code.gitea.io/gitea/modules/util"
19
- "code.gitea.io/gitea/routers/common"
20
13
"code.gitea.io/gitea/services/context"
21
14
"code.gitea.io/gitea/services/convert"
22
15
)
23
16
24
- // ParseCompareInfo parse compare info between two commit for preparing comparing references
25
- func ParseCompareInfo (ctx * context.APIContext ) * common.CompareInfo {
26
- baseRepo := ctx .Repo .Repository
27
- ci := & common.CompareInfo {}
28
-
29
- fileOnly := ctx .FormBool ("file-only" )
30
-
31
- // Get compared branches information
32
- // A full compare url is of the form:
33
- //
34
- // 1. /{:baseOwner}/{:baseRepoName}/compare/{:baseBranch}...{:headBranch}
35
- // 2. /{:baseOwner}/{:baseRepoName}/compare/{:baseBranch}...{:headOwner}:{:headBranch}
36
- // 3. /{:baseOwner}/{:baseRepoName}/compare/{:baseBranch}...{:headOwner}/{:headRepoName}:{:headBranch}
37
- // 4. /{:baseOwner}/{:baseRepoName}/compare/{:headBranch}
38
- // 5. /{:baseOwner}/{:baseRepoName}/compare/{:headOwner}:{:headBranch}
39
- // 6. /{:baseOwner}/{:baseRepoName}/compare/{:headOwner}/{:headRepoName}:{:headBranch}
40
- //
41
- // Here we obtain the infoPath "{:baseBranch}...[{:headOwner}/{:headRepoName}:]{:headBranch}" as ctx.Params("*")
42
- // with the :baseRepo in ctx.Repo.
43
- //
44
- // Note: Generally :headRepoName is not provided here - we are only passed :headOwner.
45
- //
46
- // How do we determine the :headRepo?
47
- //
48
- // 1. If :headOwner is not set then the :headRepo = :baseRepo
49
- // 2. If :headOwner is set - then look for the fork of :baseRepo owned by :headOwner
50
- // 3. But... :baseRepo could be a fork of :headOwner's repo - so check that
51
- // 4. Now, :baseRepo and :headRepos could be forks of the same repo - so check that
52
- //
53
- // format: <base branch>...[<head repo>:]<head branch>
54
- // base<-head: master...head:feature
55
- // same repo: master...feature
56
-
57
- var (
58
- isSameRepo bool
59
- infoPath string
60
- err error
61
- )
62
-
63
- infoPath = ctx .Params ("*" )
64
- var infos []string
65
- if infoPath == "" {
66
- infos = []string {baseRepo .DefaultBranch , baseRepo .DefaultBranch }
67
- } else {
68
- infos = strings .SplitN (infoPath , "..." , 2 )
69
- if len (infos ) != 2 {
70
- if infos = strings .SplitN (infoPath , ".." , 2 ); len (infos ) == 2 {
71
- ci .DirectComparison = true
72
- } else {
73
- infos = []string {baseRepo .DefaultBranch , infoPath }
74
- }
75
- }
76
- }
77
-
78
- ci .BaseBranch = infos [0 ]
79
-
80
- // If there is no head repository, it means compare between same repository.
81
- headInfos := strings .Split (infos [1 ], ":" )
82
- if len (headInfos ) == 1 {
83
- isSameRepo = true
84
- ci .HeadUser = ctx .Repo .Owner
85
- ci .HeadBranch = headInfos [0 ]
86
- } else if len (headInfos ) == 2 {
87
- headInfosSplit := strings .Split (headInfos [0 ], "/" )
88
- if len (headInfosSplit ) == 1 {
89
- ci .HeadUser , err = user_model .GetUserByName (ctx , headInfos [0 ])
90
- if err != nil {
91
- if user_model .IsErrUserNotExist (err ) {
92
- ctx .NotFound ("GetUserByName" , nil )
93
- } else {
94
- ctx .ServerError ("GetUserByName" , err )
95
- }
96
- return nil
97
- }
98
- ci .HeadBranch = headInfos [1 ]
99
- isSameRepo = ci .HeadUser .ID == ctx .Repo .Owner .ID
100
- if isSameRepo {
101
- ci .HeadRepo = baseRepo
102
- }
103
- } else {
104
- ci .HeadRepo , err = repo_model .GetRepositoryByOwnerAndName (ctx , headInfosSplit [0 ], headInfosSplit [1 ])
105
- if err != nil {
106
- if repo_model .IsErrRepoNotExist (err ) {
107
- ctx .NotFound ("GetRepositoryByOwnerAndName" , nil )
108
- } else {
109
- ctx .ServerError ("GetRepositoryByOwnerAndName" , err )
110
- }
111
- return nil
112
- }
113
- if err := ci .HeadRepo .LoadOwner (ctx ); err != nil {
114
- if user_model .IsErrUserNotExist (err ) {
115
- ctx .NotFound ("GetUserByName" , nil )
116
- } else {
117
- ctx .ServerError ("GetUserByName" , err )
118
- }
119
- return nil
120
- }
121
- ci .HeadBranch = headInfos [1 ]
122
- ci .HeadUser = ci .HeadRepo .Owner
123
- isSameRepo = ci .HeadRepo .ID == ctx .Repo .Repository .ID
124
- }
125
- } else {
126
- ctx .NotFound ("CompareAndPullRequest" , nil )
127
- return nil
128
- }
129
- ctx .Repo .PullRequest .SameRepo = isSameRepo
130
-
131
- // Check if base branch is valid.
132
- baseIsCommit := ctx .Repo .GitRepo .IsCommitExist (ci .BaseBranch )
133
- baseIsBranch := ctx .Repo .GitRepo .IsBranchExist (ci .BaseBranch )
134
- baseIsTag := ctx .Repo .GitRepo .IsTagExist (ci .BaseBranch )
135
-
136
- if ! baseIsCommit && ! baseIsBranch && ! baseIsTag {
137
- // Check if baseBranch is short sha commit hash
138
- if baseCommit , _ := ctx .Repo .GitRepo .GetCommit (ci .BaseBranch ); baseCommit != nil {
139
- ci .BaseBranch = baseCommit .ID .String ()
140
- } else if ci .BaseBranch == ctx .Repo .GetObjectFormat ().EmptyObjectID ().String () {
141
- if isSameRepo {
142
- ctx .Redirect (ctx .Repo .RepoLink + "/compare/" + util .PathEscapeSegments (ci .HeadBranch ))
143
- } else {
144
- ctx .Redirect (ctx .Repo .RepoLink + "/compare/" + util .PathEscapeSegments (ci .HeadRepo .FullName ()) + ":" + util .PathEscapeSegments (ci .HeadBranch ))
145
- }
146
- return nil
147
- } else {
148
- ctx .NotFound ("IsRefExist" , nil )
149
- return nil
150
- }
151
- }
152
-
153
- // Now we have the repository that represents the base
154
-
155
- // The current base and head repositories and branches may not
156
- // actually be the intended branches that the user wants to
157
- // create a pull-request from - but also determining the head
158
- // repo is difficult.
159
-
160
- // We will want therefore to offer a few repositories to set as
161
- // our base and head
162
-
163
- // 1. First if the baseRepo is a fork get the "RootRepo" it was
164
- // forked from
165
- var rootRepo * repo_model.Repository
166
- if baseRepo .IsFork {
167
- err = baseRepo .GetBaseRepo (ctx )
168
- if err != nil {
169
- if ! repo_model .IsErrRepoNotExist (err ) {
170
- ctx .ServerError ("Unable to find root repo" , err )
171
- return nil
172
- }
173
- } else {
174
- rootRepo = baseRepo .BaseRepo
175
- }
176
- }
177
-
178
- // 2. Now if the current user is not the owner of the baseRepo,
179
- // check if they have a fork of the base repo and offer that as
180
- // "OwnForkRepo"
181
- var ownForkRepo * repo_model.Repository
182
- if ctx .Doer != nil && baseRepo .OwnerID != ctx .Doer .ID {
183
- repo := repo_model .GetForkedRepo (ctx , ctx .Doer .ID , baseRepo .ID )
184
- if repo != nil {
185
- ownForkRepo = repo
186
- }
187
- }
188
-
189
- has := ci .HeadRepo != nil
190
- // 3. If the base is a forked from "RootRepo" and the owner of
191
- // the "RootRepo" is the :headUser - set headRepo to that
192
- if ! has && rootRepo != nil && rootRepo .OwnerID == ci .HeadUser .ID {
193
- ci .HeadRepo = rootRepo
194
- has = true
195
- }
196
-
197
- // 4. If the ctx.Doer has their own fork of the baseRepo and the headUser is the ctx.Doer
198
- // set the headRepo to the ownFork
199
- if ! has && ownForkRepo != nil && ownForkRepo .OwnerID == ci .HeadUser .ID {
200
- ci .HeadRepo = ownForkRepo
201
- has = true
202
- }
203
-
204
- // 5. If the headOwner has a fork of the baseRepo - use that
205
- if ! has {
206
- ci .HeadRepo = repo_model .GetForkedRepo (ctx , ci .HeadUser .ID , baseRepo .ID )
207
- has = ci .HeadRepo != nil
208
- }
209
-
210
- // 6. If the baseRepo is a fork and the headUser has a fork of that use that
211
- if ! has && baseRepo .IsFork {
212
- ci .HeadRepo = repo_model .GetForkedRepo (ctx , ci .HeadUser .ID , baseRepo .ForkID )
213
- has = ci .HeadRepo != nil
214
- }
215
-
216
- // 7. Finally open the git repo
217
- if isSameRepo {
218
- ci .HeadRepo = ctx .Repo .Repository
219
- ci .HeadGitRepo = ctx .Repo .GitRepo
220
- } else if has {
221
- ci .HeadGitRepo , err = gitrepo .OpenRepository (ctx , ci .HeadRepo )
222
- if err != nil {
223
- ctx .ServerError ("OpenRepository" , err )
224
- return nil
225
- }
226
- defer ci .HeadGitRepo .Close ()
227
- } else {
228
- ctx .NotFound ("ParseCompareInfo" , nil )
229
- return nil
230
- }
231
-
232
- // Now we need to assert that the ctx.Doer has permission to read
233
- // the baseRepo's code and pulls
234
- // (NOT headRepo's)
235
- permBase , err := access_model .GetUserRepoPermission (ctx , baseRepo , ctx .Doer )
236
- if err != nil {
237
- ctx .ServerError ("GetUserRepoPermission" , err )
238
- return nil
239
- }
240
- if ! permBase .CanRead (unit .TypeCode ) {
241
- if log .IsTrace () {
242
- log .Trace ("Permission Denied: User: %-v cannot read code in Repo: %-v\n User in baseRepo has Permissions: %-+v" ,
243
- ctx .Doer ,
244
- baseRepo ,
245
- permBase )
246
- }
247
- ctx .NotFound ("ParseCompareInfo" , nil )
248
- return nil
249
- }
250
-
251
- // If we're not merging from the same repo:
252
- if ! isSameRepo {
253
- // Assert ctx.Doer has permission to read headRepo's codes
254
- permHead , err := access_model .GetUserRepoPermission (ctx , ci .HeadRepo , ctx .Doer )
255
- if err != nil {
256
- ctx .ServerError ("GetUserRepoPermission" , err )
257
- return nil
258
- }
259
- if ! permHead .CanRead (unit .TypeCode ) {
260
- if log .IsTrace () {
261
- log .Trace ("Permission Denied: User: %-v cannot read code in Repo: %-v\n User in headRepo has Permissions: %-+v" ,
262
- ctx .Doer ,
263
- ci .HeadRepo ,
264
- permHead )
265
- }
266
- ctx .NotFound ("ParseCompareInfo" , nil )
267
- return nil
268
- }
269
- }
270
-
271
- // Check if head branch is valid.
272
- headIsCommit := ci .HeadGitRepo .IsCommitExist (ci .HeadBranch )
273
- headIsBranch := ci .HeadGitRepo .IsBranchExist (ci .HeadBranch )
274
- headIsTag := ci .HeadGitRepo .IsTagExist (ci .HeadBranch )
275
- if ! headIsCommit && ! headIsBranch && ! headIsTag {
276
- // Check if headBranch is short sha commit hash
277
- if headCommit , _ := ci .HeadGitRepo .GetCommit (ci .HeadBranch ); headCommit != nil {
278
- ci .HeadBranch = headCommit .ID .String ()
279
- ctx .Data ["HeadBranch" ] = ci .HeadBranch
280
- } else {
281
- ctx .NotFound ("IsRefExist" , nil )
282
- return nil
283
- }
284
- }
285
-
286
- baseBranchRef := ci .BaseBranch
287
- if baseIsBranch {
288
- baseBranchRef = git .BranchPrefix + ci .BaseBranch
289
- } else if baseIsTag {
290
- baseBranchRef = git .TagPrefix + ci .BaseBranch
291
- }
292
- headBranchRef := ci .HeadBranch
293
- if headIsBranch {
294
- headBranchRef = git .BranchPrefix + ci .HeadBranch
295
- } else if headIsTag {
296
- headBranchRef = git .TagPrefix + ci .HeadBranch
297
- }
298
-
299
- ci .CompareInfo , err = ci .HeadGitRepo .GetCompareInfo (baseRepo .RepoPath (), baseBranchRef , headBranchRef , ci .DirectComparison , fileOnly )
300
- if err != nil {
301
- ctx .ServerError ("GetCompareInfo" , err )
302
- return nil
303
- }
304
-
305
- return ci
306
- }
307
-
308
17
// CompareDiff compare two branches or commits
309
18
func CompareDiff (ctx * context.APIContext ) {
310
19
// swagger:operation GET /repos/{owner}/{repo}/compare/{basehead} Get commit comparison information
@@ -344,24 +53,37 @@ func CompareDiff(ctx *context.APIContext) {
344
53
defer gitRepo .Close ()
345
54
}
346
55
347
- ci := ParseCompareInfo (ctx )
348
- defer func () {
349
- if ci != nil && ci .HeadGitRepo != nil {
350
- ci .HeadGitRepo .Close ()
56
+ infoPath := ctx .Params ("*" )
57
+ infos := []string {ctx .Repo .Repository .DefaultBranch , ctx .Repo .Repository .DefaultBranch }
58
+ if infoPath != "" {
59
+ infos = strings .SplitN (infoPath , "..." , 2 )
60
+ if len (infos ) != 2 {
61
+ if infos = strings .SplitN (infoPath , ".." , 2 ); len (infos ) != 2 {
62
+ infos = []string {ctx .Repo .Repository .DefaultBranch , infoPath }
63
+ }
351
64
}
352
- }()
65
+ }
66
+
67
+ _ , _ , headGitRepo , ci , _ , _ := parseCompareInfo (ctx , api.CreatePullRequestOption {
68
+ Base : infos [0 ],
69
+ Head : infos [1 ],
70
+ })
353
71
if ctx .Written () {
354
72
return
355
73
}
74
+ defer headGitRepo .Close ()
75
+
76
+ verification := ctx .FormString ("verification" ) == "" || ctx .FormBool ("verification" )
77
+ files := ctx .FormString ("files" ) == "" || ctx .FormBool ("files" )
356
78
357
- apiCommits := make ([]* api.Commit , 0 , len (ci .CompareInfo . Commits ))
79
+ apiCommits := make ([]* api.Commit , 0 , len (ci .Commits ))
358
80
userCache := make (map [string ]* user_model.User )
359
- for i := 0 ; i < len (ci .CompareInfo . Commits ); i ++ {
360
- apiCommit , err := convert .ToCommit (ctx , ctx .Repo .Repository , ctx .Repo .GitRepo , ci .CompareInfo . Commits [i ], userCache ,
81
+ for i := 0 ; i < len (ci .Commits ); i ++ {
82
+ apiCommit , err := convert .ToCommit (ctx , ctx .Repo .Repository , ctx .Repo .GitRepo , ci .Commits [i ], userCache ,
361
83
convert.ToCommitOptions {
362
84
Stat : true ,
363
- Verification : ctx . FormBool ( " verification" ) ,
364
- Files : ctx . FormBool ( " files" ) ,
85
+ Verification : verification ,
86
+ Files : files ,
365
87
})
366
88
if err != nil {
367
89
ctx .ServerError ("toCommit" , err )
@@ -371,7 +93,7 @@ func CompareDiff(ctx *context.APIContext) {
371
93
}
372
94
373
95
ctx .JSON (http .StatusOK , & api.Compare {
374
- TotalCommits : len (ci .CompareInfo . Commits ),
96
+ TotalCommits : len (ci .Commits ),
375
97
Commits : apiCommits ,
376
98
})
377
99
}
0 commit comments