gitea源码

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