選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

api_repo_edit_test.go 15KB

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