gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. // Copyright 2019 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package setting
  4. import (
  5. "os/exec"
  6. "path/filepath"
  7. "strings"
  8. "code.gitea.io/gitea/modules/log"
  9. )
  10. // enumerates all the policy repository creating
  11. const (
  12. RepoCreatingLastUserVisibility = "last"
  13. RepoCreatingPrivate = "private"
  14. RepoCreatingPublic = "public"
  15. )
  16. // ItemsPerPage maximum items per page in forks, watchers and stars of a repo
  17. const ItemsPerPage = 40
  18. // Repository settings
  19. var (
  20. Repository = struct {
  21. DetectedCharsetsOrder []string
  22. DetectedCharsetScore map[string]int `ini:"-"`
  23. AnsiCharset string
  24. ForcePrivate bool
  25. DefaultPrivate string
  26. DefaultPushCreatePrivate bool
  27. MaxCreationLimit int
  28. PreferredLicenses []string
  29. DisableHTTPGit bool
  30. AccessControlAllowOrigin string
  31. UseCompatSSHURI bool
  32. GoGetCloneURLProtocol string
  33. DefaultCloseIssuesViaCommitsInAnyBranch bool
  34. EnablePushCreateUser bool
  35. EnablePushCreateOrg bool
  36. DisabledRepoUnits []string
  37. DefaultRepoUnits []string
  38. DefaultForkRepoUnits []string
  39. DefaultMirrorRepoUnits []string
  40. DefaultTemplateRepoUnits []string
  41. PrefixArchiveFiles bool
  42. DisableMigrations bool
  43. DisableStars bool `ini:"DISABLE_STARS"`
  44. DefaultBranch string
  45. AllowAdoptionOfUnadoptedRepositories bool
  46. AllowDeleteOfUnadoptedRepositories bool
  47. DisableDownloadSourceArchives bool
  48. AllowForkWithoutMaximumLimit bool
  49. AllowForkIntoSameOwner bool
  50. // StreamArchives makes Gitea stream git archive files to the client directly instead of creating an archive first.
  51. // Ideally all users should use this streaming method. However, at the moment we don't know whether there are
  52. // any users who still need the old behavior, so we introduce this option, intentionally not documenting it.
  53. // After one or two releases, if no one complains, we will remove this option and always use streaming.
  54. StreamArchives bool
  55. // Repository editor settings
  56. Editor struct {
  57. LineWrapExtensions []string
  58. } `ini:"-"`
  59. // Repository upload settings
  60. Upload struct {
  61. Enabled bool
  62. AllowedTypes string
  63. FileMaxSize int64
  64. MaxFiles int
  65. } `ini:"-"`
  66. // Pull request settings
  67. PullRequest struct {
  68. WorkInProgressPrefixes []string
  69. CloseKeywords []string
  70. ReopenKeywords []string
  71. DefaultMergeStyle string
  72. DefaultMergeMessageCommitsLimit int
  73. DefaultMergeMessageSize int
  74. DefaultMergeMessageAllAuthors bool
  75. DefaultMergeMessageMaxApprovers int
  76. DefaultMergeMessageOfficialApproversOnly bool
  77. PopulateSquashCommentWithCommitMessages bool
  78. AddCoCommitterTrailers bool
  79. TestConflictingPatchesWithGitApply bool
  80. RetargetChildrenOnMerge bool
  81. DelayCheckForInactiveDays int
  82. } `ini:"repository.pull-request"`
  83. // Issue Setting
  84. Issue struct {
  85. LockReasons []string
  86. MaxPinned int
  87. } `ini:"repository.issue"`
  88. Release struct {
  89. AllowedTypes string
  90. DefaultPagingNum int
  91. } `ini:"repository.release"`
  92. Signing struct {
  93. SigningKey string
  94. SigningName string
  95. SigningEmail string
  96. SigningFormat string
  97. InitialCommit []string
  98. CRUDActions []string `ini:"CRUD_ACTIONS"`
  99. Merges []string
  100. Wiki []string
  101. DefaultTrustModel string
  102. TrustedSSHKeys []string `ini:"TRUSTED_SSH_KEYS"`
  103. } `ini:"repository.signing"`
  104. }{
  105. DetectedCharsetsOrder: []string{
  106. "UTF-8",
  107. "UTF-16BE",
  108. "UTF-16LE",
  109. "UTF-32BE",
  110. "UTF-32LE",
  111. "ISO-8859-1",
  112. "windows-1252",
  113. "ISO-8859-2",
  114. "windows-1250",
  115. "ISO-8859-5",
  116. "ISO-8859-6",
  117. "ISO-8859-7",
  118. "windows-1253",
  119. "ISO-8859-8-I",
  120. "windows-1255",
  121. "ISO-8859-8",
  122. "windows-1251",
  123. "windows-1256",
  124. "KOI8-R",
  125. "ISO-8859-9",
  126. "windows-1254",
  127. "Shift_JIS",
  128. "GB18030",
  129. "EUC-JP",
  130. "EUC-KR",
  131. "Big5",
  132. "ISO-2022-JP",
  133. "ISO-2022-KR",
  134. "ISO-2022-CN",
  135. "IBM424_rtl",
  136. "IBM424_ltr",
  137. "IBM420_rtl",
  138. "IBM420_ltr",
  139. },
  140. DetectedCharsetScore: map[string]int{},
  141. AnsiCharset: "",
  142. ForcePrivate: false,
  143. DefaultPrivate: RepoCreatingLastUserVisibility,
  144. DefaultPushCreatePrivate: true,
  145. MaxCreationLimit: -1,
  146. PreferredLicenses: []string{"Apache License 2.0", "MIT License"},
  147. DisableHTTPGit: false,
  148. AccessControlAllowOrigin: "",
  149. UseCompatSSHURI: false,
  150. DefaultCloseIssuesViaCommitsInAnyBranch: false,
  151. EnablePushCreateUser: false,
  152. EnablePushCreateOrg: false,
  153. DisabledRepoUnits: []string{},
  154. DefaultRepoUnits: []string{},
  155. DefaultForkRepoUnits: []string{},
  156. DefaultMirrorRepoUnits: []string{},
  157. DefaultTemplateRepoUnits: []string{},
  158. PrefixArchiveFiles: true,
  159. DisableMigrations: false,
  160. DisableStars: false,
  161. DefaultBranch: "main",
  162. AllowForkWithoutMaximumLimit: true,
  163. StreamArchives: true,
  164. // Repository editor settings
  165. Editor: struct {
  166. LineWrapExtensions []string
  167. }{
  168. LineWrapExtensions: strings.Split(".txt,.md,.markdown,.mdown,.mkd,.livemd,", ","),
  169. },
  170. // Repository upload settings
  171. Upload: struct {
  172. Enabled bool
  173. AllowedTypes string
  174. FileMaxSize int64
  175. MaxFiles int
  176. }{
  177. Enabled: true,
  178. AllowedTypes: "",
  179. FileMaxSize: 50,
  180. MaxFiles: 5,
  181. },
  182. // Pull request settings
  183. PullRequest: struct {
  184. WorkInProgressPrefixes []string
  185. CloseKeywords []string
  186. ReopenKeywords []string
  187. DefaultMergeStyle string
  188. DefaultMergeMessageCommitsLimit int
  189. DefaultMergeMessageSize int
  190. DefaultMergeMessageAllAuthors bool
  191. DefaultMergeMessageMaxApprovers int
  192. DefaultMergeMessageOfficialApproversOnly bool
  193. PopulateSquashCommentWithCommitMessages bool
  194. AddCoCommitterTrailers bool
  195. TestConflictingPatchesWithGitApply bool
  196. RetargetChildrenOnMerge bool
  197. DelayCheckForInactiveDays int
  198. }{
  199. WorkInProgressPrefixes: []string{"WIP:", "[WIP]"},
  200. // Same as GitHub. See
  201. // https://help.github.com/articles/closing-issues-via-commit-messages
  202. CloseKeywords: strings.Split("close,closes,closed,fix,fixes,fixed,resolve,resolves,resolved", ","),
  203. ReopenKeywords: strings.Split("reopen,reopens,reopened", ","),
  204. DefaultMergeStyle: "merge",
  205. DefaultMergeMessageCommitsLimit: 50,
  206. DefaultMergeMessageSize: 5 * 1024,
  207. DefaultMergeMessageAllAuthors: false,
  208. DefaultMergeMessageMaxApprovers: 10,
  209. DefaultMergeMessageOfficialApproversOnly: true,
  210. PopulateSquashCommentWithCommitMessages: false,
  211. AddCoCommitterTrailers: true,
  212. RetargetChildrenOnMerge: true,
  213. DelayCheckForInactiveDays: 7,
  214. },
  215. // Issue settings
  216. Issue: struct {
  217. LockReasons []string
  218. MaxPinned int
  219. }{
  220. LockReasons: strings.Split("Too heated,Off-topic,Spam,Resolved", ","),
  221. MaxPinned: 3,
  222. },
  223. Release: struct {
  224. AllowedTypes string
  225. DefaultPagingNum int
  226. }{
  227. AllowedTypes: "",
  228. DefaultPagingNum: 10,
  229. },
  230. // Signing settings
  231. Signing: struct {
  232. SigningKey string
  233. SigningName string
  234. SigningEmail string
  235. SigningFormat string
  236. InitialCommit []string
  237. CRUDActions []string `ini:"CRUD_ACTIONS"`
  238. Merges []string
  239. Wiki []string
  240. DefaultTrustModel string
  241. TrustedSSHKeys []string `ini:"TRUSTED_SSH_KEYS"`
  242. }{
  243. SigningKey: "default",
  244. SigningName: "",
  245. SigningEmail: "",
  246. SigningFormat: "openpgp", // git.SigningKeyFormatOpenPGP
  247. InitialCommit: []string{"always"},
  248. CRUDActions: []string{"pubkey", "twofa", "parentsigned"},
  249. Merges: []string{"pubkey", "twofa", "basesigned", "commitssigned"},
  250. Wiki: []string{"never"},
  251. DefaultTrustModel: "collaborator",
  252. TrustedSSHKeys: []string{},
  253. },
  254. }
  255. RepoRootPath string
  256. ScriptType = "bash"
  257. )
  258. func loadRepositoryFrom(rootCfg ConfigProvider) {
  259. var err error
  260. // Determine and create root git repository path.
  261. sec := rootCfg.Section("repository")
  262. Repository.DisableHTTPGit = sec.Key("DISABLE_HTTP_GIT").MustBool()
  263. Repository.UseCompatSSHURI = sec.Key("USE_COMPAT_SSH_URI").MustBool()
  264. Repository.GoGetCloneURLProtocol = sec.Key("GO_GET_CLONE_URL_PROTOCOL").MustString("https")
  265. Repository.MaxCreationLimit = sec.Key("MAX_CREATION_LIMIT").MustInt(-1)
  266. Repository.DefaultBranch = sec.Key("DEFAULT_BRANCH").MustString(Repository.DefaultBranch)
  267. RepoRootPath = sec.Key("ROOT").MustString(filepath.Join(AppDataPath, "gitea-repositories"))
  268. if !filepath.IsAbs(RepoRootPath) {
  269. RepoRootPath = filepath.Join(AppWorkPath, RepoRootPath)
  270. } else {
  271. RepoRootPath = filepath.Clean(RepoRootPath)
  272. }
  273. checkOverlappedPath("[repository].ROOT", RepoRootPath)
  274. defaultDetectedCharsetsOrder := make([]string, 0, len(Repository.DetectedCharsetsOrder))
  275. for _, charset := range Repository.DetectedCharsetsOrder {
  276. defaultDetectedCharsetsOrder = append(defaultDetectedCharsetsOrder, strings.ToLower(strings.TrimSpace(charset)))
  277. }
  278. ScriptType = sec.Key("SCRIPT_TYPE").MustString("bash")
  279. if _, err := exec.LookPath(ScriptType); err != nil {
  280. log.Warn("SCRIPT_TYPE %q is not on the current PATH. Are you sure that this is the correct SCRIPT_TYPE?", ScriptType)
  281. }
  282. if err = sec.MapTo(&Repository); err != nil {
  283. log.Fatal("Failed to map Repository settings: %v", err)
  284. } else if err = rootCfg.Section("repository.editor").MapTo(&Repository.Editor); err != nil {
  285. log.Fatal("Failed to map Repository.Editor settings: %v", err)
  286. } else if err = rootCfg.Section("repository.upload").MapTo(&Repository.Upload); err != nil {
  287. log.Fatal("Failed to map Repository.Upload settings: %v", err)
  288. } else if err = rootCfg.Section("repository.pull-request").MapTo(&Repository.PullRequest); err != nil {
  289. log.Fatal("Failed to map Repository.PullRequest settings: %v", err)
  290. }
  291. if !rootCfg.Section("packages").Key("ENABLED").MustBool(Packages.Enabled) {
  292. Repository.DisabledRepoUnits = append(Repository.DisabledRepoUnits, "repo.packages")
  293. }
  294. if !rootCfg.Section("actions").Key("ENABLED").MustBool(Actions.Enabled) {
  295. Repository.DisabledRepoUnits = append(Repository.DisabledRepoUnits, "repo.actions")
  296. }
  297. // Handle default trustmodel settings
  298. Repository.Signing.DefaultTrustModel = strings.ToLower(strings.TrimSpace(Repository.Signing.DefaultTrustModel))
  299. if Repository.Signing.DefaultTrustModel == "default" {
  300. Repository.Signing.DefaultTrustModel = "collaborator"
  301. }
  302. // Handle preferred charset orders
  303. preferred := make([]string, 0, len(Repository.DetectedCharsetsOrder))
  304. for _, charset := range Repository.DetectedCharsetsOrder {
  305. canonicalCharset := strings.ToLower(strings.TrimSpace(charset))
  306. preferred = append(preferred, canonicalCharset)
  307. // remove it from the defaults
  308. for i, charset := range defaultDetectedCharsetsOrder {
  309. if charset == canonicalCharset {
  310. defaultDetectedCharsetsOrder = append(defaultDetectedCharsetsOrder[:i], defaultDetectedCharsetsOrder[i+1:]...)
  311. break
  312. }
  313. }
  314. }
  315. i := 0
  316. for _, charset := range preferred {
  317. // Add the defaults
  318. if charset == "defaults" {
  319. for _, charset := range defaultDetectedCharsetsOrder {
  320. canonicalCharset := strings.ToLower(strings.TrimSpace(charset))
  321. if _, has := Repository.DetectedCharsetScore[canonicalCharset]; !has {
  322. Repository.DetectedCharsetScore[canonicalCharset] = i
  323. i++
  324. }
  325. }
  326. continue
  327. }
  328. if _, has := Repository.DetectedCharsetScore[charset]; !has {
  329. Repository.DetectedCharsetScore[charset] = i
  330. i++
  331. }
  332. }
  333. if err := loadRepoArchiveFrom(rootCfg); err != nil {
  334. log.Fatal("loadRepoArchiveFrom: %v", err)
  335. }
  336. }