-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
-
86
-
87
-
88
-
89
-
90
-
91
-
92
-
93
-
94
-
95
-
96
-
97
-
98
-
99
-
100
-
101
-
102
-
103
-
104
-
105
-
106
-
107
-
108
-
109
-
110
-
111
-
112
-
113
-
114
-
115
-
116
-
117
-
118
-
119
-
120
-
121
-
122
-
123
-
124
-
125
-
126
-
127
-
128
-
129
-
130
-
131
-
132
-
133
-
134
-
135
-
136
-
137
-
138
-
139
-
140
-
141
-
142
-
143
-
144
-
145
-
146
-
147
-
148
-
149
-
150
-
151
-
152
-
153
-
154
-
155
-
156
-
157
-
158
-
159
-
160
-
161
-
162
-
163
-
164
-
165
-
166
-
167
-
168
-
169
-
170
-
171
-
172
-
173
-
174
-
175
-
176
-
177
-
178
-
179
-
180
-
181
-
182
-
183
-
184
-
185
-
186
-
187
-
188
-
189
-
190
-
191
-
192
-
193
-
194
-
195
-
196
-
197
-
198
-
199
-
200
-
201
-
202
-
203
-
204
-
205
-
206
-
207
-
208
-
209
-
210
-
211
-
212
-
213
-
214
-
215
-
216
-
217
-
218
-
219
-
220
-
221
-
222
-
223
-
224
-
225
-
226
-
227
-
228
-
229
-
230
-
231
-
232
-
233
-
234
-
235
-
236
-
237
-
238
-
239
-
240
-
241
-
242
-
243
-
244
-
245
-
246
-
247
-
248
-
249
-
250
-
251
-
252
-
253
-
254
-
255
-
256
-
257
-
258
-
259
-
260
-
261
-
262
-
263
-
264
-
265
-
266
-
267
-
268
-
269
-
270
-
271
-
272
-
273
-
274
-
275
-
276
-
277
-
278
-
279
-
280
-
281
-
282
-
283
-
284
-
285
-
286
-
287
-
288
-
289
-
290
-
291
-
292
-
293
-
294
-
295
-
296
-
297
-
298
-
299
-
300
-
301
-
302
-
303
-
304
-
305
-
306
-
307
-
308
-
309
-
310
-
311
-
312
-
313
-
314
-
315
-
316
-
317
-
318
-
319
-
320
-
321
-
322
-
323
-
324
-
325
-
326
-
327
-
328
-
329
-
330
-
331
-
332
-
333
-
334
-
335
-
336
-
337
-
338
-
339
-
340
-
341
-
342
-
343
-
344
-
345
-
346
-
347
-
348
-
349
-
350
-
351
-
352
-
353
-
354
-
355
-
356
-
357
-
358
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package integration
import (
"fmt"
"net/http"
"net/url"
"testing"
repo_model "code.gitea.io/gitea/models/repo"
unit_model "code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
api "code.gitea.io/gitea/modules/structs"
"github.com/stretchr/testify/assert"
)
// getRepoEditOptionFromRepo gets the options for an existing repo exactly as is
func getRepoEditOptionFromRepo(repo *repo_model.Repository) *api.EditRepoOption {
name := repo.Name
description := repo.Description
website := repo.Website
private := repo.IsPrivate
hasIssues := false
var internalTracker *api.InternalTracker
var externalTracker *api.ExternalTracker
if unit, err := repo.GetUnit(unit_model.TypeIssues); err == nil {
config := unit.IssuesConfig()
hasIssues = true
internalTracker = &api.InternalTracker{
EnableTimeTracker: config.EnableTimetracker,
AllowOnlyContributorsToTrackTime: config.AllowOnlyContributorsToTrackTime,
EnableIssueDependencies: config.EnableDependencies,
}
} else if unit, err := repo.GetUnit(unit_model.TypeExternalTracker); err == nil {
config := unit.ExternalTrackerConfig()
hasIssues = true
externalTracker = &api.ExternalTracker{
ExternalTrackerURL: config.ExternalTrackerURL,
ExternalTrackerFormat: config.ExternalTrackerFormat,
ExternalTrackerStyle: config.ExternalTrackerStyle,
ExternalTrackerRegexpPattern: config.ExternalTrackerRegexpPattern,
}
}
hasWiki := false
var externalWiki *api.ExternalWiki
if _, err := repo.GetUnit(unit_model.TypeWiki); err == nil {
hasWiki = true
} else if unit, err := repo.GetUnit(unit_model.TypeExternalWiki); err == nil {
hasWiki = true
config := unit.ExternalWikiConfig()
externalWiki = &api.ExternalWiki{
ExternalWikiURL: config.ExternalWikiURL,
}
}
defaultBranch := repo.DefaultBranch
hasPullRequests := false
ignoreWhitespaceConflicts := false
allowMerge := false
allowRebase := false
allowRebaseMerge := false
allowSquash := false
if unit, err := repo.GetUnit(unit_model.TypePullRequests); err == nil {
config := unit.PullRequestsConfig()
hasPullRequests = true
ignoreWhitespaceConflicts = config.IgnoreWhitespaceConflicts
allowMerge = config.AllowMerge
allowRebase = config.AllowRebase
allowRebaseMerge = config.AllowRebaseMerge
allowSquash = config.AllowSquash
}
archived := repo.IsArchived
return &api.EditRepoOption{
Name: &name,
Description: &description,
Website: &website,
Private: &private,
HasIssues: &hasIssues,
ExternalTracker: externalTracker,
InternalTracker: internalTracker,
HasWiki: &hasWiki,
ExternalWiki: externalWiki,
DefaultBranch: &defaultBranch,
HasPullRequests: &hasPullRequests,
IgnoreWhitespaceConflicts: &ignoreWhitespaceConflicts,
AllowMerge: &allowMerge,
AllowRebase: &allowRebase,
AllowRebaseMerge: &allowRebaseMerge,
AllowSquash: &allowSquash,
Archived: &archived,
}
}
// getNewRepoEditOption Gets the options to change everything about an existing repo by adding to strings or changing
// the boolean
func getNewRepoEditOption(opts *api.EditRepoOption) *api.EditRepoOption {
// Gives a new property to everything
name := *opts.Name + "renamed"
description := "new description"
website := "http://wwww.newwebsite.com"
private := !*opts.Private
hasIssues := !*opts.HasIssues
hasWiki := !*opts.HasWiki
defaultBranch := "master"
hasPullRequests := !*opts.HasPullRequests
ignoreWhitespaceConflicts := !*opts.IgnoreWhitespaceConflicts
allowMerge := !*opts.AllowMerge
allowRebase := !*opts.AllowRebase
allowRebaseMerge := !*opts.AllowRebaseMerge
allowSquash := !*opts.AllowSquash
archived := !*opts.Archived
return &api.EditRepoOption{
Name: &name,
Description: &description,
Website: &website,
Private: &private,
DefaultBranch: &defaultBranch,
HasIssues: &hasIssues,
HasWiki: &hasWiki,
HasPullRequests: &hasPullRequests,
IgnoreWhitespaceConflicts: &ignoreWhitespaceConflicts,
AllowMerge: &allowMerge,
AllowRebase: &allowRebase,
AllowRebaseMerge: &allowRebaseMerge,
AllowSquash: &allowSquash,
Archived: &archived,
}
}
func TestAPIRepoEdit(t *testing.T) {
onGiteaRun(t, func(t *testing.T, u *url.URL) {
bFalse, bTrue := false, true
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo1 & repo16
user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) // owner of the repo3, is an org
user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // owner of neither repos
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) // public repo
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) // public repo
repo15 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 15}) // empty repo
repo16 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}) // private repo
// Get user2's token
session := loginUser(t, user2.Name)
token2 := getTokenForLoggedInUser(t, session)
// Get user4's token
session = loginUser(t, user4.Name)
token4 := getTokenForLoggedInUser(t, session)
session = emptyTestSession(t)
// Test editing a repo1 which user2 owns, changing name and many properties
origRepoEditOption := getRepoEditOptionFromRepo(repo1)
repoEditOption := getNewRepoEditOption(origRepoEditOption)
url := fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, repo1.Name, token2)
req := NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
resp := session.MakeRequest(t, req, http.StatusOK)
var repo api.Repository
DecodeJSON(t, resp, &repo)
assert.NotNil(t, repo)
// check response
assert.Equal(t, *repoEditOption.Name, repo.Name)
assert.Equal(t, *repoEditOption.Description, repo.Description)
assert.Equal(t, *repoEditOption.Website, repo.Website)
assert.Equal(t, *repoEditOption.Archived, repo.Archived)
// check repo1 from database
repo1edited := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
repo1editedOption := getRepoEditOptionFromRepo(repo1edited)
assert.Equal(t, *repoEditOption.Name, *repo1editedOption.Name)
assert.Equal(t, *repoEditOption.Description, *repo1editedOption.Description)
assert.Equal(t, *repoEditOption.Website, *repo1editedOption.Website)
assert.Equal(t, *repoEditOption.Archived, *repo1editedOption.Archived)
assert.Equal(t, *repoEditOption.Private, *repo1editedOption.Private)
assert.Equal(t, *repoEditOption.HasWiki, *repo1editedOption.HasWiki)
// Test editing repo1 to use internal issue and wiki (default)
*repoEditOption.HasIssues = true
repoEditOption.ExternalTracker = nil
repoEditOption.InternalTracker = &api.InternalTracker{
EnableTimeTracker: false,
AllowOnlyContributorsToTrackTime: false,
EnableIssueDependencies: false,
}
*repoEditOption.HasWiki = true
repoEditOption.ExternalWiki = nil
url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, *repoEditOption.Name, token2)
req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &repo)
assert.NotNil(t, repo)
// check repo1 was written to database
repo1edited = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
repo1editedOption = getRepoEditOptionFromRepo(repo1edited)
assert.Equal(t, *repo1editedOption.HasIssues, true)
assert.Nil(t, repo1editedOption.ExternalTracker)
assert.Equal(t, *repo1editedOption.InternalTracker, *repoEditOption.InternalTracker)
assert.Equal(t, *repo1editedOption.HasWiki, true)
assert.Nil(t, repo1editedOption.ExternalWiki)
// Test editing repo1 to use external issue and wiki
repoEditOption.ExternalTracker = &api.ExternalTracker{
ExternalTrackerURL: "http://www.somewebsite.com",
ExternalTrackerFormat: "http://www.somewebsite.com/{user}/{repo}?issue={index}",
ExternalTrackerStyle: "alphanumeric",
}
repoEditOption.ExternalWiki = &api.ExternalWiki{
ExternalWikiURL: "http://www.somewebsite.com",
}
req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &repo)
assert.NotNil(t, repo)
// check repo1 was written to database
repo1edited = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
repo1editedOption = getRepoEditOptionFromRepo(repo1edited)
assert.Equal(t, *repo1editedOption.HasIssues, true)
assert.Equal(t, *repo1editedOption.ExternalTracker, *repoEditOption.ExternalTracker)
assert.Equal(t, *repo1editedOption.HasWiki, true)
assert.Equal(t, *repo1editedOption.ExternalWiki, *repoEditOption.ExternalWiki)
repoEditOption.ExternalTracker.ExternalTrackerStyle = "regexp"
repoEditOption.ExternalTracker.ExternalTrackerRegexpPattern = `(\d+)`
req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &repo)
assert.NotNil(t, repo)
repo1edited = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
repo1editedOption = getRepoEditOptionFromRepo(repo1edited)
assert.Equal(t, *repo1editedOption.HasIssues, true)
assert.Equal(t, *repo1editedOption.ExternalTracker, *repoEditOption.ExternalTracker)
// Do some tests with invalid URL for external tracker and wiki
repoEditOption.ExternalTracker.ExternalTrackerURL = "htp://www.somewebsite.com"
req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
repoEditOption.ExternalTracker.ExternalTrackerURL = "http://www.somewebsite.com"
repoEditOption.ExternalTracker.ExternalTrackerFormat = "http://www.somewebsite.com/{user/{repo}?issue={index}"
req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
repoEditOption.ExternalTracker.ExternalTrackerFormat = "http://www.somewebsite.com/{user}/{repo}?issue={index}"
repoEditOption.ExternalWiki.ExternalWikiURL = "htp://www.somewebsite.com"
req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
// Test small repo change through API with issue and wiki option not set; They shall not be touched.
*repoEditOption.Description = "small change"
repoEditOption.HasIssues = nil
repoEditOption.ExternalTracker = nil
repoEditOption.HasWiki = nil
repoEditOption.ExternalWiki = nil
req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &repo)
assert.NotNil(t, repo)
// check repo1 was written to database
repo1edited = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
repo1editedOption = getRepoEditOptionFromRepo(repo1edited)
assert.Equal(t, *repo1editedOption.Description, *repoEditOption.Description)
assert.Equal(t, *repo1editedOption.HasIssues, true)
assert.NotNil(t, *repo1editedOption.ExternalTracker)
assert.Equal(t, *repo1editedOption.HasWiki, true)
assert.NotNil(t, *repo1editedOption.ExternalWiki)
// reset repo in db
url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, *repoEditOption.Name, token2)
req = NewRequestWithJSON(t, "PATCH", url, &origRepoEditOption)
_ = session.MakeRequest(t, req, http.StatusOK)
// Test editing a non-existing repo
name := "repodoesnotexist"
url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, name, token2)
req = NewRequestWithJSON(t, "PATCH", url, &api.EditRepoOption{Name: &name})
_ = session.MakeRequest(t, req, http.StatusNotFound)
// Test editing repo16 by user4 who does not have write access
origRepoEditOption = getRepoEditOptionFromRepo(repo16)
repoEditOption = getNewRepoEditOption(origRepoEditOption)
url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, repo16.Name, token4)
req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
session.MakeRequest(t, req, http.StatusNotFound)
// Tests a repo with no token given so will fail
origRepoEditOption = getRepoEditOptionFromRepo(repo16)
repoEditOption = getNewRepoEditOption(origRepoEditOption)
url = fmt.Sprintf("/api/v1/repos/%s/%s", user2.Name, repo16.Name)
req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
_ = session.MakeRequest(t, req, http.StatusNotFound)
// Test using access token for a private repo that the user of the token owns
origRepoEditOption = getRepoEditOptionFromRepo(repo16)
repoEditOption = getNewRepoEditOption(origRepoEditOption)
url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, repo16.Name, token2)
req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
_ = session.MakeRequest(t, req, http.StatusOK)
// reset repo in db
url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, *repoEditOption.Name, token2)
req = NewRequestWithJSON(t, "PATCH", url, &origRepoEditOption)
_ = session.MakeRequest(t, req, http.StatusOK)
// Test making a repo public that is private
repo16 = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16})
assert.True(t, repo16.IsPrivate)
repoEditOption = &api.EditRepoOption{
Private: &bFalse,
}
url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, repo16.Name, token2)
req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
_ = session.MakeRequest(t, req, http.StatusOK)
repo16 = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16})
assert.False(t, repo16.IsPrivate)
// Make it private again
repoEditOption.Private = &bTrue
req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
_ = session.MakeRequest(t, req, http.StatusOK)
// Test to change empty repo
assert.False(t, repo15.IsArchived)
url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, repo15.Name, token2)
req = NewRequestWithJSON(t, "PATCH", url, &api.EditRepoOption{
Archived: &bTrue,
})
_ = session.MakeRequest(t, req, http.StatusOK)
repo15 = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 15})
assert.True(t, repo15.IsArchived)
req = NewRequestWithJSON(t, "PATCH", url, &api.EditRepoOption{
Archived: &bFalse,
})
_ = session.MakeRequest(t, req, http.StatusOK)
// Test using org repo "user3/repo3" where user2 is a collaborator
origRepoEditOption = getRepoEditOptionFromRepo(repo3)
repoEditOption = getNewRepoEditOption(origRepoEditOption)
url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user3.Name, repo3.Name, token2)
req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
session.MakeRequest(t, req, http.StatusOK)
// reset repo in db
url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user3.Name, *repoEditOption.Name, token2)
req = NewRequestWithJSON(t, "PATCH", url, &origRepoEditOption)
_ = session.MakeRequest(t, req, http.StatusOK)
// Test using org repo "user3/repo3" with no user token
origRepoEditOption = getRepoEditOptionFromRepo(repo3)
repoEditOption = getNewRepoEditOption(origRepoEditOption)
url = fmt.Sprintf("/api/v1/repos/%s/%s", user3.Name, repo3.Name)
req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
session.MakeRequest(t, req, http.StatusNotFound)
// Test using repo "user2/repo1" where user4 is a NOT collaborator
origRepoEditOption = getRepoEditOptionFromRepo(repo1)
repoEditOption = getNewRepoEditOption(origRepoEditOption)
url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, repo1.Name, token4)
req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
session.MakeRequest(t, req, http.StatusForbidden)
})
}