From 43129a1901149607b65e4c4dd831cd4a13dbfead Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 23 May 2023 06:47:35 +0000 Subject: [PATCH 001/158] add repo license check --- go.mod | 1 + go.sum | 2 + modules/util/path.go | 31 +++++++----- options/locale/locale_en-US.ini | 1 + routers/web/repo/view.go | 85 +++++++++++++++++++++++++-------- templates/repo/sub_menu.tmpl | 11 +++++ 6 files changed, 101 insertions(+), 30 deletions(-) diff --git a/go.mod b/go.mod index 93b8052daf..85b75d4257 100644 --- a/go.mod +++ b/go.mod @@ -203,6 +203,7 @@ require ( github.com/golang/snappy v0.0.4 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-tpm v0.3.3 // indirect + github.com/google/licensecheck v0.3.1 // indirect github.com/gorilla/css v1.0.0 // indirect github.com/gorilla/handlers v1.5.1 // indirect github.com/gorilla/mux v1.8.0 // indirect diff --git a/go.sum b/go.sum index 8e5b728aac..b4911d746f 100644 --- a/go.sum +++ b/go.sum @@ -575,6 +575,8 @@ github.com/google/go-tpm v0.3.3/go.mod h1:9Hyn3rgnzWF9XBWVk6ml6A6hNkbWjNFlDQL51B github.com/google/go-tpm-tools v0.0.0-20190906225433-1614c142f845/go.mod h1:AVfHadzbdzHo54inR2x1v640jdi1YSi3NauM2DUsxk0= github.com/google/go-tpm-tools v0.2.0/go.mod h1:npUd03rQ60lxN7tzeBJreG38RvWwme2N1reF/eeiBk4= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/licensecheck v0.3.1 h1:QoxgoDkaeC4nFrtGN1jV7IPmDCHFNIVh54e5hSt6sPs= +github.com/google/licensecheck v0.3.1/go.mod h1:ORkR35t/JjW+emNKtfJDII0zlciG9JgbT7SmsohlHmY= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= diff --git a/modules/util/path.go b/modules/util/path.go index 1a68bc7488..8164d91c4b 100644 --- a/modules/util/path.go +++ b/modules/util/path.go @@ -282,38 +282,47 @@ func CommonSkip(name string) bool { return false } -// IsReadmeFileName reports whether name looks like a README file +type FileType string + +const ( + FileTypeReadme FileType = "readme" + FileTypeLicense FileType = "license" +) + +// IsFileName reports whether name looks like a fileType file // based on its name. -func IsReadmeFileName(name string) bool { +func IsFileName(name string, fileType FileType) bool { name = strings.ToLower(name) - if len(name) < 6 { + lenFileType := len(fileType) + if len(name) < lenFileType { return false - } else if len(name) == 6 { - return name == "readme" + } else if len(name) == lenFileType { + return name == string(fileType) } - return name[:7] == "readme." + return name[:lenFileType+1] == string(fileType)+"." } -// IsReadmeFileExtension reports whether name looks like a README file +// IsFileExtension reports whether name looks like a fileType file // based on its name. It will look through the provided extensions and check if the file matches // one of the extensions and provide the index in the extension list. // If the filename is `readme.` with an unmatched extension it will match with the index equaling // the length of the provided extension list. // Note that the '.' should be provided in ext, e.g ".md" -func IsReadmeFileExtension(name string, ext ...string) (int, bool) { +func IsFileExtension(name string, fileType FileType, ext ...string) (int, bool) { name = strings.ToLower(name) - if len(name) < 6 || name[:6] != "readme" { + lenFileType := len(fileType) + if len(name) < lenFileType || name[:lenFileType] != string(fileType) { return 0, false } for i, extension := range ext { extension = strings.ToLower(extension) - if name[6:] == extension { + if name[lenFileType:] == extension { return i, true } } - if name[6] == '.' { + if name[lenFileType] == '.' { return len(ext), true } diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 80ccecbce1..72917997c0 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -930,6 +930,7 @@ issue_labels_helper = Select an issue label set. license = License license_helper = Select a license file. license_helper_desc = A license governs what others can and can't do with your code. Not sure which one is right for your project? See Choose a license. +multiple_licenses = Multiple Licenses readme = README readme_helper = Select a README file template. readme_helper_desc = This is the place where you can write a complete description for your project. diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index 2fd893f91c..870df8d997 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -42,6 +42,7 @@ import ( "code.gitea.io/gitea/routers/web/feed" issue_service "code.gitea.io/gitea/services/issue" + "github.com/google/licensecheck" "github.com/nektos/act/pkg/model" ) @@ -54,7 +55,7 @@ const ( tplMigrating base.TplName = "repo/migrate/migrating" ) -// locate a README for a tree in one of the supported paths. +// locate a README/LICENSE for a tree in one of the supported paths. // // entries is passed to reduce calls to ListEntries(), so // this has precondition: @@ -62,14 +63,14 @@ const ( // entries == ctx.Repo.Commit.SubTree(ctx.Repo.TreePath).ListEntries() // // FIXME: There has to be a more efficient way of doing this -func findReadmeFileInEntries(ctx *context.Context, entries []*git.TreeEntry, tryWellKnownDirs bool) (string, *git.TreeEntry, error) { +func findFileInEntries(ctx *context.Context, fileType util.FileType, entries []*git.TreeEntry, tryWellKnownDirs bool) (string, *git.TreeEntry, error) { // Create a list of extensions in priority order // 1. Markdown files - with and without localisation - e.g. README.en-us.md or README.md // 2. Txt files - e.g. README.txt // 3. No extension - e.g. README exts := append(localizedExtensions(".md", ctx.Locale.Language()), ".txt", "") // sorted by priority extCount := len(exts) - readmeFiles := make([]*git.TreeEntry, extCount+1) + targetFiles := make([]*git.TreeEntry, extCount+1) docsEntries := make([]*git.TreeEntry, 3) // (one of docs/, .gitea/ or .github/) for _, entry := range entries { @@ -94,31 +95,31 @@ func findReadmeFileInEntries(ctx *context.Context, entries []*git.TreeEntry, try } continue } - if i, ok := util.IsReadmeFileExtension(entry.Name(), exts...); ok { + if i, ok := util.IsFileExtension(entry.Name(), fileType, exts...); ok { log.Debug("Potential readme file: %s", entry.Name()) - if readmeFiles[i] == nil || base.NaturalSortLess(readmeFiles[i].Name(), entry.Blob().Name()) { + if targetFiles[i] == nil || base.NaturalSortLess(targetFiles[i].Name(), entry.Blob().Name()) { if entry.IsLink() { target, err := entry.FollowLinks() if err != nil && !git.IsErrBadLink(err) { return "", nil, err } else if target != nil && (target.IsExecutable() || target.IsRegular()) { - readmeFiles[i] = entry + targetFiles[i] = entry } } else { - readmeFiles[i] = entry + targetFiles[i] = entry } } } } - var readmeFile *git.TreeEntry - for _, f := range readmeFiles { + var targetFile *git.TreeEntry + for _, f := range targetFiles { if f != nil { - readmeFile = f + targetFile = f break } } - if ctx.Repo.TreePath == "" && readmeFile == nil { + if ctx.Repo.TreePath == "" && targetFile == nil { for _, subTreeEntry := range docsEntries { if subTreeEntry == nil { continue @@ -134,17 +135,17 @@ func findReadmeFileInEntries(ctx *context.Context, entries []*git.TreeEntry, try return "", nil, err } - subfolder, readmeFile, err := findReadmeFileInEntries(ctx, childEntries, false) + subfolder, targetFile, err := findFileInEntries(ctx, fileType, childEntries, false) if err != nil && !git.IsErrNotExist(err) { return "", nil, err } - if readmeFile != nil { - return path.Join(subTreeEntry.Name(), subfolder), readmeFile, nil + if targetFile != nil { + return path.Join(subTreeEntry.Name(), subfolder), targetFile, nil } } } - return "", readmeFile, nil + return "", targetFile, nil } func renderDirectory(ctx *context.Context, treeLink string) { @@ -158,13 +159,19 @@ func renderDirectory(ctx *context.Context, treeLink string) { ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+path.Base(ctx.Repo.TreePath), ctx.Repo.RefName) } - subfolder, readmeFile, err := findReadmeFileInEntries(ctx, entries, true) + subfolder, readmeFile, err := findFileInEntries(ctx, util.FileTypeReadme, entries, true) if err != nil { - ctx.ServerError("findReadmeFileInEntries", err) + ctx.ServerError("findFileInEntries", err) return } - renderReadmeFile(ctx, subfolder, readmeFile, treeLink) + + subfolder, licenseFile, err := findFileInEntries(ctx, util.FileTypeLicense, entries, false) + if err != nil { + ctx.ServerError("findFileInEntries", err) + return + } + renderLicenseFile(ctx, subfolder, licenseFile, treeLink) } // localizedExtensions prepends the provided language code with and without a @@ -323,6 +330,46 @@ func renderReadmeFile(ctx *context.Context, subfolder string, readmeFile *git.Tr } } +func renderLicenseFile(ctx *context.Context, subfolder string, licenseFile *git.TreeEntry, readmeTreelink string) { + target := licenseFile + if licenseFile != nil && licenseFile.IsLink() { + target, _ = licenseFile.FollowLinks() + } + if target == nil { + // if findFile() failed and/or gave us a broken symlink (which it shouldn't) + // simply skip rendering the LICENSE + return + } + + buf, dataRc, fInfo, err := getFileReader(ctx.Repo.Repository.ID, target.Blob()) + if err != nil { + ctx.ServerError("getFileReader", err) + return + } + defer dataRc.Close() + + // TODO: if fInfo.isLFSFile? + if !fInfo.isTextFile { + return + } + if fInfo.fileSize >= setting.UI.MaxDisplayFileSize { + // License file is too large to calculate + return + } + + rd := charset.ToUTF8WithFallbackReader(io.MultiReader(bytes.NewReader(buf), dataRc)) + + contentBuf := &bytes.Buffer{} + ctx.Data["EscapeStatus"], err = charset.EscapeControlStringReader(rd, contentBuf, ctx.Locale) + if err != nil { + log.Error("Read failed: %v", err) + } + cov := licensecheck.Scan(contentBuf.Bytes()) + fmt.Println(cov.Match) + ctx.Data["MatchedLicenses"] = cov.Match + ctx.Data["LicenseFileName"] = licenseFile.Name() +} + func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink string) { ctx.Data["IsViewFile"] = true ctx.Data["HideRepoInfo"] = true @@ -430,7 +477,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st rd := charset.ToUTF8WithFallbackReader(io.MultiReader(bytes.NewReader(buf), dataRc)) shouldRenderSource := ctx.FormString("display") == "source" - readmeExist := util.IsReadmeFileName(blob.Name()) + readmeExist := util.IsFileName(blob.Name(), util.FileTypeReadme) ctx.Data["ReadmeExist"] = readmeExist markupType := markup.Type(blob.Name()) diff --git a/templates/repo/sub_menu.tmpl b/templates/repo/sub_menu.tmpl index bfe5a20b16..dd5891161e 100644 --- a/templates/repo/sub_menu.tmpl +++ b/templates/repo/sub_menu.tmpl @@ -19,6 +19,17 @@ {{$fileSizeFields := StringUtils.Split $fileSizeFormatted " "}} {{svg "octicon-database"}} {{.locale.PrettyNumber (index $fileSizeFields 0)}} {{index $fileSizeFields 1}} + {{if .MatchedLicenses}} +
+ {{svg "octicon-law"}} + {{if eq (len .MatchedLicenses) 1}} + {{(index .MatchedLicenses 0).ID}} + {{else}} + {{.locale.Tr "repo.multiple_licenses"}} + +
+ {{end}} + {{end}} {{end}} From 33ec60016390d7ec05cde5c396c1706233d9834d Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 23 May 2023 06:52:27 +0000 Subject: [PATCH 002/158] fix incorrect location of {{end}} --- templates/repo/sub_menu.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/repo/sub_menu.tmpl b/templates/repo/sub_menu.tmpl index dd5891161e..8ef762bb0c 100644 --- a/templates/repo/sub_menu.tmpl +++ b/templates/repo/sub_menu.tmpl @@ -27,8 +27,8 @@ {{else}} {{.locale.Tr "repo.multiple_licenses"}} + {{end}} - {{end}} {{end}} {{end}} From 7d3f1d5da2e81a7f41c4f28abc786b0aed50ab1d Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 23 May 2023 07:24:04 +0000 Subject: [PATCH 003/158] fix test --- modules/util/path_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/util/path_test.go b/modules/util/path_test.go index 6a38bf4ace..b95093236a 100644 --- a/modules/util/path_test.go +++ b/modules/util/path_test.go @@ -76,10 +76,10 @@ func TestMisc_IsReadmeFileName(t *testing.T) { } for _, testCase := range trueTestCases { - assert.True(t, IsReadmeFileName(testCase)) + assert.True(t, IsFileName(testCase, FileTypeReadme)) } for _, testCase := range falseTestCases { - assert.False(t, IsReadmeFileName(testCase)) + assert.False(t, IsFileName(testCase, FileTypeReadme)) } type extensionTestcase struct { @@ -131,7 +131,7 @@ func TestMisc_IsReadmeFileName(t *testing.T) { } for _, testCase := range testCasesExtensions { - idx, ok := IsReadmeFileExtension(testCase.name, exts...) + idx, ok := IsFileExtension(testCase.name, FileTypeReadme, exts...) assert.Equal(t, testCase.expected, ok) assert.Equal(t, testCase.idx, idx) } From 8acb46e527f6fff36ab01a0bb7f394d95ca966f2 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 23 May 2023 07:47:20 +0000 Subject: [PATCH 004/158] remove debug code --- routers/web/repo/view.go | 1 - 1 file changed, 1 deletion(-) diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index 870df8d997..efc895c0ae 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -365,7 +365,6 @@ func renderLicenseFile(ctx *context.Context, subfolder string, licenseFile *git. log.Error("Read failed: %v", err) } cov := licensecheck.Scan(contentBuf.Bytes()) - fmt.Println(cov.Match) ctx.Data["MatchedLicenses"] = cov.Match ctx.Data["LicenseFileName"] = licenseFile.Name() } From a4e0deb444798285c85a82727471697197e884bb Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 24 May 2023 07:03:08 +0000 Subject: [PATCH 005/158] use make tidy to add licensecheck --- assets/go-licenses.json | 5 +++++ go.mod | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/assets/go-licenses.json b/assets/go-licenses.json index 49f18e7de7..3ca78f0ed9 100644 --- a/assets/go-licenses.json +++ b/assets/go-licenses.json @@ -539,6 +539,11 @@ "path": "github.com/google/go-tpm/LICENSE", "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" }, + { + "name": "github.com/google/licensecheck", + "path": "github.com/google/licensecheck/LICENSE", + "licenseText": "Copyright (c) 2019 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + }, { "name": "github.com/google/pprof/profile", "path": "github.com/google/pprof/profile/LICENSE", diff --git a/go.mod b/go.mod index 85b75d4257..d3bd52460c 100644 --- a/go.mod +++ b/go.mod @@ -56,6 +56,7 @@ require ( github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 github.com/golang-jwt/jwt/v4 v4.5.0 github.com/google/go-github/v51 v51.0.0 + github.com/google/licensecheck v0.3.1 github.com/google/pprof v0.0.0-20230502171905-255e3b9b56de github.com/google/uuid v1.3.0 github.com/gorilla/feeds v1.1.1 @@ -203,7 +204,6 @@ require ( github.com/golang/snappy v0.0.4 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-tpm v0.3.3 // indirect - github.com/google/licensecheck v0.3.1 // indirect github.com/gorilla/css v1.0.0 // indirect github.com/gorilla/handlers v1.5.1 // indirect github.com/gorilla/mux v1.8.0 // indirect From 5a75aab5e0be6ab4f38a15c139e2566377389f8b Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 24 May 2023 07:05:11 +0000 Subject: [PATCH 006/158] use statistics in db --- models/repo/license.go | 38 +++++++++++ models/repo/repo.go | 2 + modules/context/repo.go | 3 + modules/git/repo_license_gogit.go | 68 +++++++++++++++++++ modules/git/repo_license_nogogit.go | 90 ++++++++++++++++++++++++++ modules/git/repo_license_stats_test.go | 35 ++++++++++ modules/indexer/stats/db.go | 16 ++++- routers/web/repo/view.go | 47 -------------- templates/repo/sub_menu.tmpl | 6 +- 9 files changed, 254 insertions(+), 51 deletions(-) create mode 100644 models/repo/license.go create mode 100644 modules/git/repo_license_gogit.go create mode 100644 modules/git/repo_license_nogogit.go create mode 100644 modules/git/repo_license_stats_test.go diff --git a/models/repo/license.go b/models/repo/license.go new file mode 100644 index 0000000000..d8bf4e5583 --- /dev/null +++ b/models/repo/license.go @@ -0,0 +1,38 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package repo + +import ( + "context" + + "code.gitea.io/gitea/models/db" +) + +// UpdateLanguageStats updates the license statistics for repository +func UpdateLicenseStats(repo *Repository, commitID string, licenses []string) error { + ctx, committer, err := db.TxContext(db.DefaultContext) + if err != nil { + return err + } + defer committer.Close() + + if err = UpdateLicense(ctx, repo.ID, licenses); err != nil { + return err + } + + // Update indexer status + if err = UpdateIndexerStatus(ctx, repo, RepoIndexerTypeStats, commitID); err != nil { + return err + } + + return committer.Commit() +} + +// UpdateRepoSize updates the repository size, calculating it using getDirectorySize +func UpdateLicense(ctx context.Context, repoID int64, licenses []string) error { + _, err := db.GetEngine(ctx).ID(repoID).Cols("licenses").NoAutoTime().Update(&Repository{ + Licenses: licenses, + }) + return err +} diff --git a/models/repo/repo.go b/models/repo/repo.go index d3e6daa95b..629c1b177c 100644 --- a/models/repo/repo.go +++ b/models/repo/repo.go @@ -157,6 +157,8 @@ type Repository struct { Units []*RepoUnit `xorm:"-"` PrimaryLanguage *LanguageStat `xorm:"-"` + Licenses []string `xorm:"TEXT JSON"` + IsFork bool `xorm:"INDEX NOT NULL DEFAULT false"` ForkID int64 `xorm:"INDEX"` BaseRepo *Repository `xorm:"-"` diff --git a/modules/context/repo.go b/modules/context/repo.go index fd5f208576..9ee51b2d9e 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -399,6 +399,9 @@ func repoAssignment(ctx *Context, repo *repo_model.Repository) { ctx.Data["PushMirrors"] = pushMirrors ctx.Data["RepoName"] = ctx.Repo.Repository.Name ctx.Data["IsEmptyRepo"] = ctx.Repo.Repository.IsEmpty + ctx.Data["Licenses"] = ctx.Repo.Repository.Licenses + // TODO: support ext + ctx.Data["LicenseFileName"] = "LICENSE" } // RepoIDAssignment returns a handler which assigns the repo to the context. diff --git a/modules/git/repo_license_gogit.go b/modules/git/repo_license_gogit.go new file mode 100644 index 0000000000..a41cb99fef --- /dev/null +++ b/modules/git/repo_license_gogit.go @@ -0,0 +1,68 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +//go:build gogit + +package git + +import ( + "io" + + "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing" + "github.com/go-git/go-git/v5/plumbing/object" + "github.com/google/licensecheck" +) + +// GetLicenseStats calculates license stats for git repository at specified commit +func (repo *Repository) GetLicenseStats(commitID string) ([]string, error) { + r, err := git.PlainOpen(repo.Path) + if err != nil { + return nil, err + } + + rev, err := r.ResolveRevision(plumbing.Revision(commitID)) + if err != nil { + return nil, err + } + + commit, err := r.CommitObject(*rev) + if err != nil { + return nil, err + } + + tree, err := commit.Tree() + if err != nil { + return nil, err + } + + var licenses []string + // TODO: fix unnecessary check + err = tree.Files().ForEach(func(f *object.File) error { + if f.Size == 0 { + return nil + } + + // TODO: support ext + if f.Name == "LICENSE" { + r, err := f.Reader() + if err != nil { + return err + } + defer r.Close() + + content, err := io.ReadAll(r) + if err != nil { + return err + } + + cov := licensecheck.Scan(content) + for _, m := range cov.Match { + licenses = append(licenses, m.ID) + } + } + return nil + }) + + return licenses, nil +} diff --git a/modules/git/repo_license_nogogit.go b/modules/git/repo_license_nogogit.go new file mode 100644 index 0000000000..7bcf5ce18b --- /dev/null +++ b/modules/git/repo_license_nogogit.go @@ -0,0 +1,90 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +//go:build !gogit + +package git + +import ( + "bytes" + "io" + + "code.gitea.io/gitea/modules/log" + "github.com/google/licensecheck" +) + +// GetLicenseStats calculates language stats for git repository at specified commit +func (repo *Repository) GetLicenseStats(commitID string) ([]string, error) { + // We will feed the commit IDs in order into cat-file --batch, followed by blobs as necessary. + // so let's create a batch stdin and stdout + batchStdinWriter, batchReader, cancel := repo.CatFileBatch(repo.Ctx) + defer cancel() + + writeID := func(id string) error { + _, err := batchStdinWriter.Write([]byte(id + "\n")) + return err + } + + if err := writeID(commitID); err != nil { + return nil, err + } + shaBytes, typ, size, err := ReadBatchLine(batchReader) + if typ != "commit" { + log.Debug("Unable to get commit for: %s. Err: %v", commitID, err) + return nil, ErrNotExist{commitID, ""} + } + + sha, err := NewIDFromString(string(shaBytes)) + if err != nil { + log.Debug("Unable to get commit for: %s. Err: %v", commitID, err) + return nil, ErrNotExist{commitID, ""} + } + + commit, err := CommitFromReader(repo, sha, io.LimitReader(batchReader, size)) + if err != nil { + log.Debug("Unable to get commit for: %s. Err: %v", commitID, err) + return nil, err + } + if _, err = batchReader.Discard(1); err != nil { + return nil, err + } + + tree := commit.Tree + + entries, err := tree.ListEntriesRecursiveWithSize() + if err != nil { + return nil, err + } + + var licenses []string + for _, f := range entries { + if f.Size() == 0 { + continue + } + + // TODO: support ext + if f.Name() == "LICENSE" { + // Need to read all of them or can not get the right result from licensecheck.Scan + if err := writeID(f.ID.String()); err != nil { + return nil, err + } + _, _, size, err := ReadBatchLine(batchReader) + if err != nil { + log.Debug("Error reading blob: %s Err: %v", f.ID.String(), err) + return nil, err + } + contentBuf := bytes.Buffer{} + _, err = contentBuf.ReadFrom(io.LimitReader(batchReader, size)) + if err != nil { + return nil, err + } + cov := licensecheck.Scan(contentBuf.Bytes()) + for _, m := range cov.Match { + licenses = append(licenses, m.ID) + } + break + } + } + + return licenses, nil +} diff --git a/modules/git/repo_license_stats_test.go b/modules/git/repo_license_stats_test.go new file mode 100644 index 0000000000..67d83337c0 --- /dev/null +++ b/modules/git/repo_license_stats_test.go @@ -0,0 +1,35 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +//go:build !gogit + +package git + +import ( + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestRepository_GetLicenseStats(t *testing.T) { + // TODO: add the repo + repoPath := filepath.Join(testReposDir, "license_stats_repo") + gitRepo, err := openRepositoryWithDefaultContext(repoPath) + if !assert.NoError(t, err) { + t.Fatal() + } + defer gitRepo.Close() + + // TODO: add the LICENSE file + stats, err := gitRepo.GetLicenseStats("8fee858da5796dfb37704761701bb8e800ad9ef3") + if !assert.NoError(t, err) { + t.Fatal() + } + + // TODO: fix check + assert.EqualValues(t, map[string]int64{ + "Python": 134, + "Java": 112, + }, stats) +} diff --git a/modules/indexer/stats/db.go b/modules/indexer/stats/db.go index 2a0475dea6..05d6dd419a 100644 --- a/modules/indexer/stats/db.go +++ b/modules/indexer/stats/db.go @@ -73,8 +73,22 @@ func (db *DBIndexer) Index(id int64) error { log.Error("Unable to update language stats for ID %s for default branch %s in %s. Error: %v", commitID, repo.DefaultBranch, repo.RepoPath(), err) return err } - log.Debug("DBIndexer completed language stats for ID %s for default branch %s in %s. stats count: %d", commitID, repo.DefaultBranch, repo.RepoPath(), len(stats)) + + licenses, err := gitRepo.GetLicenseStats(commitID) + if err != nil { + if !setting.IsInTesting { + log.Error("Unable to get license stats for ID %s for default branch %s in %s. Error: %v", commitID, repo.DefaultBranch, repo.RepoPath(), err) + } + return err + } + err = repo_model.UpdateLicenseStats(repo, commitID, licenses) + if err != nil { + log.Error("Unable to update license stats for ID %s for default branch %s in %s. Error: %v", commitID, repo.DefaultBranch, repo.RepoPath(), err) + return err + } + log.Debug("DBIndexer completed license stats for ID %s for default branch %s in %s. stats count: %d", commitID, repo.DefaultBranch, repo.RepoPath(), len(stats)) + return nil } diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index efc895c0ae..b9033563a8 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -42,7 +42,6 @@ import ( "code.gitea.io/gitea/routers/web/feed" issue_service "code.gitea.io/gitea/services/issue" - "github.com/google/licensecheck" "github.com/nektos/act/pkg/model" ) @@ -165,13 +164,6 @@ func renderDirectory(ctx *context.Context, treeLink string) { return } renderReadmeFile(ctx, subfolder, readmeFile, treeLink) - - subfolder, licenseFile, err := findFileInEntries(ctx, util.FileTypeLicense, entries, false) - if err != nil { - ctx.ServerError("findFileInEntries", err) - return - } - renderLicenseFile(ctx, subfolder, licenseFile, treeLink) } // localizedExtensions prepends the provided language code with and without a @@ -330,45 +322,6 @@ func renderReadmeFile(ctx *context.Context, subfolder string, readmeFile *git.Tr } } -func renderLicenseFile(ctx *context.Context, subfolder string, licenseFile *git.TreeEntry, readmeTreelink string) { - target := licenseFile - if licenseFile != nil && licenseFile.IsLink() { - target, _ = licenseFile.FollowLinks() - } - if target == nil { - // if findFile() failed and/or gave us a broken symlink (which it shouldn't) - // simply skip rendering the LICENSE - return - } - - buf, dataRc, fInfo, err := getFileReader(ctx.Repo.Repository.ID, target.Blob()) - if err != nil { - ctx.ServerError("getFileReader", err) - return - } - defer dataRc.Close() - - // TODO: if fInfo.isLFSFile? - if !fInfo.isTextFile { - return - } - if fInfo.fileSize >= setting.UI.MaxDisplayFileSize { - // License file is too large to calculate - return - } - - rd := charset.ToUTF8WithFallbackReader(io.MultiReader(bytes.NewReader(buf), dataRc)) - - contentBuf := &bytes.Buffer{} - ctx.Data["EscapeStatus"], err = charset.EscapeControlStringReader(rd, contentBuf, ctx.Locale) - if err != nil { - log.Error("Read failed: %v", err) - } - cov := licensecheck.Scan(contentBuf.Bytes()) - ctx.Data["MatchedLicenses"] = cov.Match - ctx.Data["LicenseFileName"] = licenseFile.Name() -} - func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink string) { ctx.Data["IsViewFile"] = true ctx.Data["HideRepoInfo"] = true diff --git a/templates/repo/sub_menu.tmpl b/templates/repo/sub_menu.tmpl index 8ef762bb0c..3620d20b50 100644 --- a/templates/repo/sub_menu.tmpl +++ b/templates/repo/sub_menu.tmpl @@ -19,11 +19,11 @@ {{$fileSizeFields := StringUtils.Split $fileSizeFormatted " "}} {{svg "octicon-database"}} {{.locale.PrettyNumber (index $fileSizeFields 0)}} {{index $fileSizeFields 1}} - {{if .MatchedLicenses}} + {{if .Licenses}}
{{svg "octicon-law"}} - {{if eq (len .MatchedLicenses) 1}} - {{(index .MatchedLicenses 0).ID}} + {{if eq (len .Licenses) 1}} + {{index .Licenses 0}} {{else}} {{.locale.Tr "repo.multiple_licenses"}} From 973f9950d1f1c11c42fcc229220029864dfba894 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 25 May 2023 00:32:35 +0000 Subject: [PATCH 007/158] check license change in HookPostReceive --- models/repo/license.go | 38 ----------- modules/git/blob.go | 11 ++++ modules/git/repo_license_gogit.go | 68 ------------------- modules/git/repo_license_nogogit.go | 90 -------------------------- modules/git/repo_license_stats_test.go | 35 ---------- modules/indexer/stats/db.go | 16 +---- routers/private/hook_post_receive.go | 63 +++++++++++++++++- 7 files changed, 74 insertions(+), 247 deletions(-) delete mode 100644 models/repo/license.go delete mode 100644 modules/git/repo_license_gogit.go delete mode 100644 modules/git/repo_license_nogogit.go delete mode 100644 modules/git/repo_license_stats_test.go diff --git a/models/repo/license.go b/models/repo/license.go deleted file mode 100644 index d8bf4e5583..0000000000 --- a/models/repo/license.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package repo - -import ( - "context" - - "code.gitea.io/gitea/models/db" -) - -// UpdateLanguageStats updates the license statistics for repository -func UpdateLicenseStats(repo *Repository, commitID string, licenses []string) error { - ctx, committer, err := db.TxContext(db.DefaultContext) - if err != nil { - return err - } - defer committer.Close() - - if err = UpdateLicense(ctx, repo.ID, licenses); err != nil { - return err - } - - // Update indexer status - if err = UpdateIndexerStatus(ctx, repo, RepoIndexerTypeStats, commitID); err != nil { - return err - } - - return committer.Commit() -} - -// UpdateRepoSize updates the repository size, calculating it using getDirectorySize -func UpdateLicense(ctx context.Context, repoID int64, licenses []string) error { - _, err := db.GetEngine(ctx).ID(repoID).Cols("licenses").NoAutoTime().Update(&Repository{ - Licenses: licenses, - }) - return err -} diff --git a/modules/git/blob.go b/modules/git/blob.go index 8864f54d1b..5e126bace1 100644 --- a/modules/git/blob.go +++ b/modules/git/blob.go @@ -33,6 +33,17 @@ func (b *Blob) GetBlobContent() (string, error) { return string(buf), nil } +// GetBlobAll Gets the all content of the blob as bytes +func (b *Blob) GetBlobAll() ([]byte, error) { + dataRc, err := b.DataAsync() + if err != nil { + return nil, err + } + buf, _ := io.ReadAll(dataRc) + _ = dataRc.Close() + return buf, nil +} + // GetBlobLineCount gets line count of the blob func (b *Blob) GetBlobLineCount() (int, error) { reader, err := b.DataAsync() diff --git a/modules/git/repo_license_gogit.go b/modules/git/repo_license_gogit.go deleted file mode 100644 index a41cb99fef..0000000000 --- a/modules/git/repo_license_gogit.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -//go:build gogit - -package git - -import ( - "io" - - "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/plumbing" - "github.com/go-git/go-git/v5/plumbing/object" - "github.com/google/licensecheck" -) - -// GetLicenseStats calculates license stats for git repository at specified commit -func (repo *Repository) GetLicenseStats(commitID string) ([]string, error) { - r, err := git.PlainOpen(repo.Path) - if err != nil { - return nil, err - } - - rev, err := r.ResolveRevision(plumbing.Revision(commitID)) - if err != nil { - return nil, err - } - - commit, err := r.CommitObject(*rev) - if err != nil { - return nil, err - } - - tree, err := commit.Tree() - if err != nil { - return nil, err - } - - var licenses []string - // TODO: fix unnecessary check - err = tree.Files().ForEach(func(f *object.File) error { - if f.Size == 0 { - return nil - } - - // TODO: support ext - if f.Name == "LICENSE" { - r, err := f.Reader() - if err != nil { - return err - } - defer r.Close() - - content, err := io.ReadAll(r) - if err != nil { - return err - } - - cov := licensecheck.Scan(content) - for _, m := range cov.Match { - licenses = append(licenses, m.ID) - } - } - return nil - }) - - return licenses, nil -} diff --git a/modules/git/repo_license_nogogit.go b/modules/git/repo_license_nogogit.go deleted file mode 100644 index 7bcf5ce18b..0000000000 --- a/modules/git/repo_license_nogogit.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -//go:build !gogit - -package git - -import ( - "bytes" - "io" - - "code.gitea.io/gitea/modules/log" - "github.com/google/licensecheck" -) - -// GetLicenseStats calculates language stats for git repository at specified commit -func (repo *Repository) GetLicenseStats(commitID string) ([]string, error) { - // We will feed the commit IDs in order into cat-file --batch, followed by blobs as necessary. - // so let's create a batch stdin and stdout - batchStdinWriter, batchReader, cancel := repo.CatFileBatch(repo.Ctx) - defer cancel() - - writeID := func(id string) error { - _, err := batchStdinWriter.Write([]byte(id + "\n")) - return err - } - - if err := writeID(commitID); err != nil { - return nil, err - } - shaBytes, typ, size, err := ReadBatchLine(batchReader) - if typ != "commit" { - log.Debug("Unable to get commit for: %s. Err: %v", commitID, err) - return nil, ErrNotExist{commitID, ""} - } - - sha, err := NewIDFromString(string(shaBytes)) - if err != nil { - log.Debug("Unable to get commit for: %s. Err: %v", commitID, err) - return nil, ErrNotExist{commitID, ""} - } - - commit, err := CommitFromReader(repo, sha, io.LimitReader(batchReader, size)) - if err != nil { - log.Debug("Unable to get commit for: %s. Err: %v", commitID, err) - return nil, err - } - if _, err = batchReader.Discard(1); err != nil { - return nil, err - } - - tree := commit.Tree - - entries, err := tree.ListEntriesRecursiveWithSize() - if err != nil { - return nil, err - } - - var licenses []string - for _, f := range entries { - if f.Size() == 0 { - continue - } - - // TODO: support ext - if f.Name() == "LICENSE" { - // Need to read all of them or can not get the right result from licensecheck.Scan - if err := writeID(f.ID.String()); err != nil { - return nil, err - } - _, _, size, err := ReadBatchLine(batchReader) - if err != nil { - log.Debug("Error reading blob: %s Err: %v", f.ID.String(), err) - return nil, err - } - contentBuf := bytes.Buffer{} - _, err = contentBuf.ReadFrom(io.LimitReader(batchReader, size)) - if err != nil { - return nil, err - } - cov := licensecheck.Scan(contentBuf.Bytes()) - for _, m := range cov.Match { - licenses = append(licenses, m.ID) - } - break - } - } - - return licenses, nil -} diff --git a/modules/git/repo_license_stats_test.go b/modules/git/repo_license_stats_test.go deleted file mode 100644 index 67d83337c0..0000000000 --- a/modules/git/repo_license_stats_test.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -//go:build !gogit - -package git - -import ( - "path/filepath" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestRepository_GetLicenseStats(t *testing.T) { - // TODO: add the repo - repoPath := filepath.Join(testReposDir, "license_stats_repo") - gitRepo, err := openRepositoryWithDefaultContext(repoPath) - if !assert.NoError(t, err) { - t.Fatal() - } - defer gitRepo.Close() - - // TODO: add the LICENSE file - stats, err := gitRepo.GetLicenseStats("8fee858da5796dfb37704761701bb8e800ad9ef3") - if !assert.NoError(t, err) { - t.Fatal() - } - - // TODO: fix check - assert.EqualValues(t, map[string]int64{ - "Python": 134, - "Java": 112, - }, stats) -} diff --git a/modules/indexer/stats/db.go b/modules/indexer/stats/db.go index 05d6dd419a..2a0475dea6 100644 --- a/modules/indexer/stats/db.go +++ b/modules/indexer/stats/db.go @@ -73,22 +73,8 @@ func (db *DBIndexer) Index(id int64) error { log.Error("Unable to update language stats for ID %s for default branch %s in %s. Error: %v", commitID, repo.DefaultBranch, repo.RepoPath(), err) return err } + log.Debug("DBIndexer completed language stats for ID %s for default branch %s in %s. stats count: %d", commitID, repo.DefaultBranch, repo.RepoPath(), len(stats)) - - licenses, err := gitRepo.GetLicenseStats(commitID) - if err != nil { - if !setting.IsInTesting { - log.Error("Unable to get license stats for ID %s for default branch %s in %s. Error: %v", commitID, repo.DefaultBranch, repo.RepoPath(), err) - } - return err - } - err = repo_model.UpdateLicenseStats(repo, commitID, licenses) - if err != nil { - log.Error("Unable to update license stats for ID %s for default branch %s in %s. Error: %v", commitID, repo.DefaultBranch, repo.RepoPath(), err) - return err - } - log.Debug("DBIndexer completed license stats for ID %s for default branch %s in %s. stats count: %d", commitID, repo.DefaultBranch, repo.RepoPath(), len(stats)) - return nil } diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go index cfe20be106..c4bf8afb96 100644 --- a/routers/private/hook_post_receive.go +++ b/routers/private/hook_post_receive.go @@ -20,12 +20,13 @@ import ( "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" repo_service "code.gitea.io/gitea/services/repository" + "github.com/google/licensecheck" ) // HookPostReceive updates services and users func HookPostReceive(ctx *gitea_context.PrivateContext) { opts := web.GetForm(ctx).(*private.HookOptions) - + fmt.Println(opts) // We don't rely on RepoAssignment here because: // a) we don't need the git repo in this function // b) our update function will likely change the repository in the db so we will need to refresh it @@ -121,6 +122,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { // Now handle the pull request notification trailers for i := range opts.OldCommitIDs { refFullName := opts.RefFullNames[i] + oldCommitID := opts.OldCommitIDs[i] newCommitID := opts.NewCommitIDs[i] // post update for agit pull request @@ -199,6 +201,65 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { // If our branch is the default branch of an unforked repo - there's no PR to create or refer to if !repo.IsFork && branch == baseRepo.DefaultBranch { + // update license + gitRepo, err := git.OpenRepository(ctx, repo.RepoPath()) + if err != nil { + log.Error("Failed to open repository: %s/%s Error: %v", ownerName, repoName, err) + ctx.JSON(http.StatusInternalServerError, private.Response{ + Err: fmt.Sprintf("Failed to open repository: %s/%s Error: %v", ownerName, repoName, err), + }) + return + } + commit, err := gitRepo.GetCommit(newCommitID) + if err != nil { + log.Error("Failed to get new commit by id(%s): %s/%s Error: %v", newCommitID, ownerName, repoName, err) + ctx.JSON(http.StatusInternalServerError, private.Response{ + Err: fmt.Sprintf("Failed to get new commit by id(%s): %s/%s Error: %v", newCommitID, ownerName, repoName, err), + }) + return + } + filesChanged, err := commit.GetFilesChangedSinceCommit(oldCommitID) + if err != nil { + log.Error("Failed to get changed files from %d to %s: %s/%s Error: %v", oldCommitID, newCommitID, ownerName, repoName, err) + ctx.JSON(http.StatusInternalServerError, private.Response{ + Err: fmt.Sprintf("Failed to get changed files from %d to %s: %s/%s Error: %v", oldCommitID, newCommitID, ownerName, repoName, err), + }) + return + } + for _, fn := range filesChanged { + // support ext + if fn == "LICENSE" { + blob, err := commit.GetBlobByPath(fn) + if err != nil { + log.Error("Failed to get license blob %s in commit %s: %s/%s Error: %v", fn, newCommitID, ownerName, repoName, err) + ctx.JSON(http.StatusInternalServerError, private.Response{ + Err: fmt.Sprintf("Failed to get license blob %s in commit %s: %s/%s Error: %v", fn, newCommitID, ownerName, repoName, err), + }) + return + } + contentBuf, err := blob.GetBlobAll() + if err != nil { + log.Error("Failed to get license blob content %s in commit %s: %s/%s Error: %v", fn, newCommitID, ownerName, repoName, err) + ctx.JSON(http.StatusInternalServerError, private.Response{ + Err: fmt.Sprintf("Failed to get license blob content %s in commit %s: %s/%s Error: %v", fn, newCommitID, ownerName, repoName, err), + }) + return + } + var licenses []string + cov := licensecheck.Scan(contentBuf) + for _, m := range cov.Match { + licenses = append(licenses, m.ID) + } + repo.Licenses = licenses + if err := repo_model.UpdateRepositoryCols(ctx, repo, "licenses"); err != nil { + log.Error("Failed to Update Repo Licenses: %s/%s Error: %v", ownerName, repoName, err) + ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{ + Err: fmt.Sprintf("Failed to Update Repo Licenses: %s/%s Error: %v", ownerName, repoName, err), + }) + } + } + } + results = append(results, private.HookPostReceiveBranchResult{}) continue } From a876b2dc0357ebf4acda8e97cedebd06a53b050b Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 25 May 2023 00:33:57 +0000 Subject: [PATCH 008/158] remove debug code --- routers/private/hook_post_receive.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go index c4bf8afb96..f18f0c9fed 100644 --- a/routers/private/hook_post_receive.go +++ b/routers/private/hook_post_receive.go @@ -26,7 +26,7 @@ import ( // HookPostReceive updates services and users func HookPostReceive(ctx *gitea_context.PrivateContext) { opts := web.GetForm(ctx).(*private.HookOptions) - fmt.Println(opts) + // We don't rely on RepoAssignment here because: // a) we don't need the git repo in this function // b) our update function will likely change the repository in the db so we will need to refresh it From a2ef8f68a9343969bb9b0dd869da040c0ad32b03 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 25 May 2023 05:51:10 +0000 Subject: [PATCH 009/158] update license when create a repo --- modules/repository/create.go | 5 +++ modules/repository/license.go | 42 ++++++++++++++++++++ routers/private/hook_post_receive.go | 59 +--------------------------- templates/repo/sub_menu.tmpl | 2 +- 4 files changed, 50 insertions(+), 58 deletions(-) diff --git a/modules/repository/create.go b/modules/repository/create.go index e1f0bdcdf9..7ca2fd41a4 100644 --- a/modules/repository/create.go +++ b/modules/repository/create.go @@ -194,6 +194,10 @@ func CreateRepository(doer, u *user_model.User, opts CreateRepoOptions) (*repo_m } } + var licenses []string + if len(opts.License) > 0 { + licenses = append(licenses, opts.License) + } repo := &repo_model.Repository{ OwnerID: u.ID, Owner: u, @@ -212,6 +216,7 @@ func CreateRepository(doer, u *user_model.User, opts CreateRepoOptions) (*repo_m TrustModel: opts.TrustModel, IsMirror: opts.IsMirror, DefaultBranch: opts.DefaultBranch, + Licenses: licenses, } var rollbackRepo *repo_model.Repository diff --git a/modules/repository/license.go b/modules/repository/license.go index 5b188a041e..7004aeb12f 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -6,11 +6,15 @@ package repository import ( "bufio" "bytes" + "context" "fmt" "regexp" "strings" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/options" + "github.com/google/licensecheck" ) type licenseValues struct { @@ -111,3 +115,41 @@ func getLicensePlaceholder(name string) *licensePlaceholder { } return ret } + +func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository, oldCommitID, newCommitID, ownerName, repoName string) error { + gitRepo, err := git.OpenRepository(ctx, repo.RepoPath()) + if err != nil { + return fmt.Errorf("failed to open repository: %s/%s Error: %v", ownerName, repoName, err) + } + commit, err := gitRepo.GetCommit(newCommitID) + if err != nil { + return fmt.Errorf("failed to get new commit by id(%s): %s/%s Error: %v", newCommitID, ownerName, repoName, err) + } + filesChanged, err := commit.GetFilesChangedSinceCommit(oldCommitID) + if err != nil { + return fmt.Errorf("failed to get changed files from %s to %s: %s/%s Error: %v", oldCommitID, newCommitID, ownerName, repoName, err) + } + for _, fn := range filesChanged { + // support ext + if fn == "LICENSE" { + blob, err := commit.GetBlobByPath(fn) + if err != nil { + return fmt.Errorf("failed to get license blob %s in commit %s: %s/%s Error: %v", fn, newCommitID, ownerName, repoName, err) + } + contentBuf, err := blob.GetBlobAll() + if err != nil { + return fmt.Errorf("failed to get license blob content %s in commit %s: %s/%s Error: %v", fn, newCommitID, ownerName, repoName, err) + } + var licenses []string + cov := licensecheck.Scan(contentBuf) + for _, m := range cov.Match { + licenses = append(licenses, m.ID) + } + repo.Licenses = licenses + if err := repo_model.UpdateRepositoryCols(ctx, repo, "licenses"); err != nil { + return fmt.Errorf("failed to Update Repo Licenses: %s/%s Error: %v", ownerName, repoName, err) + } + } + } + return nil +} diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go index f18f0c9fed..8145e17b65 100644 --- a/routers/private/hook_post_receive.go +++ b/routers/private/hook_post_receive.go @@ -20,7 +20,6 @@ import ( "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" repo_service "code.gitea.io/gitea/services/repository" - "github.com/google/licensecheck" ) // HookPostReceive updates services and users @@ -202,64 +201,10 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { // If our branch is the default branch of an unforked repo - there's no PR to create or refer to if !repo.IsFork && branch == baseRepo.DefaultBranch { // update license - gitRepo, err := git.OpenRepository(ctx, repo.RepoPath()) + err := repo_module.UpdateRepoLicenses(ctx, repo, oldCommitID, newCommitID, ownerName, repoName) if err != nil { - log.Error("Failed to open repository: %s/%s Error: %v", ownerName, repoName, err) - ctx.JSON(http.StatusInternalServerError, private.Response{ - Err: fmt.Sprintf("Failed to open repository: %s/%s Error: %v", ownerName, repoName, err), - }) - return + ctx.JSON(http.StatusInternalServerError, private.Response{Err: err.Error()}) } - commit, err := gitRepo.GetCommit(newCommitID) - if err != nil { - log.Error("Failed to get new commit by id(%s): %s/%s Error: %v", newCommitID, ownerName, repoName, err) - ctx.JSON(http.StatusInternalServerError, private.Response{ - Err: fmt.Sprintf("Failed to get new commit by id(%s): %s/%s Error: %v", newCommitID, ownerName, repoName, err), - }) - return - } - filesChanged, err := commit.GetFilesChangedSinceCommit(oldCommitID) - if err != nil { - log.Error("Failed to get changed files from %d to %s: %s/%s Error: %v", oldCommitID, newCommitID, ownerName, repoName, err) - ctx.JSON(http.StatusInternalServerError, private.Response{ - Err: fmt.Sprintf("Failed to get changed files from %d to %s: %s/%s Error: %v", oldCommitID, newCommitID, ownerName, repoName, err), - }) - return - } - for _, fn := range filesChanged { - // support ext - if fn == "LICENSE" { - blob, err := commit.GetBlobByPath(fn) - if err != nil { - log.Error("Failed to get license blob %s in commit %s: %s/%s Error: %v", fn, newCommitID, ownerName, repoName, err) - ctx.JSON(http.StatusInternalServerError, private.Response{ - Err: fmt.Sprintf("Failed to get license blob %s in commit %s: %s/%s Error: %v", fn, newCommitID, ownerName, repoName, err), - }) - return - } - contentBuf, err := blob.GetBlobAll() - if err != nil { - log.Error("Failed to get license blob content %s in commit %s: %s/%s Error: %v", fn, newCommitID, ownerName, repoName, err) - ctx.JSON(http.StatusInternalServerError, private.Response{ - Err: fmt.Sprintf("Failed to get license blob content %s in commit %s: %s/%s Error: %v", fn, newCommitID, ownerName, repoName, err), - }) - return - } - var licenses []string - cov := licensecheck.Scan(contentBuf) - for _, m := range cov.Match { - licenses = append(licenses, m.ID) - } - repo.Licenses = licenses - if err := repo_model.UpdateRepositoryCols(ctx, repo, "licenses"); err != nil { - log.Error("Failed to Update Repo Licenses: %s/%s Error: %v", ownerName, repoName, err) - ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{ - Err: fmt.Sprintf("Failed to Update Repo Licenses: %s/%s Error: %v", ownerName, repoName, err), - }) - } - } - } - results = append(results, private.HookPostReceiveBranchResult{}) continue } diff --git a/templates/repo/sub_menu.tmpl b/templates/repo/sub_menu.tmpl index 3620d20b50..738984ff98 100644 --- a/templates/repo/sub_menu.tmpl +++ b/templates/repo/sub_menu.tmpl @@ -26,8 +26,8 @@ {{index .Licenses 0}} {{else}} {{.locale.Tr "repo.multiple_licenses"}} - {{end}} +
{{end}} {{end}} From c4c6da53c71e206340648bd7b9a383b0a6c6f080 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 25 May 2023 05:53:41 +0000 Subject: [PATCH 010/158] add todo --- routers/private/hook_post_receive.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go index 8145e17b65..341c4dc745 100644 --- a/routers/private/hook_post_receive.go +++ b/routers/private/hook_post_receive.go @@ -200,7 +200,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { // If our branch is the default branch of an unforked repo - there's no PR to create or refer to if !repo.IsFork && branch == baseRepo.DefaultBranch { - // update license + // TODO: check IsWiki? err := repo_module.UpdateRepoLicenses(ctx, repo, oldCommitID, newCommitID, ownerName, repoName) if err != nil { ctx.JSON(http.StatusInternalServerError, private.Response{Err: err.Error()}) From 02787750511759f649b60710c27ed1bbd297d95c Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 25 May 2023 05:58:20 +0000 Subject: [PATCH 011/158] add license to fork repo --- services/repository/fork.go | 1 + 1 file changed, 1 insertion(+) diff --git a/services/repository/fork.go b/services/repository/fork.go index fb93b10f1c..ba26ef4211 100644 --- a/services/repository/fork.go +++ b/services/repository/fork.go @@ -82,6 +82,7 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork IsEmpty: opts.BaseRepo.IsEmpty, IsFork: true, ForkID: opts.BaseRepo.ID, + Licenses: opts.BaseRepo.Licenses, } oldRepoPath := opts.BaseRepo.RepoPath() From c30bca1f3055e278f8ead99ff29ab8b51af2e33b Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 25 May 2023 06:06:04 +0000 Subject: [PATCH 012/158] fix lint --- modules/repository/license.go | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/repository/license.go b/modules/repository/license.go index 7004aeb12f..ce0ee61dfb 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -14,6 +14,7 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/options" + "github.com/google/licensecheck" ) From aa91765ddca6f8bcfa3d93d46cfe990a42f2499f Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 25 May 2023 06:40:14 +0000 Subject: [PATCH 013/158] add license to mirror repo --- modules/repository/license.go | 51 +++++++++++++--------------- modules/repository/repo.go | 6 ++++ routers/private/hook_post_receive.go | 3 +- 3 files changed, 31 insertions(+), 29 deletions(-) diff --git a/modules/repository/license.go b/modules/repository/license.go index ce0ee61dfb..f20fc0e6f3 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -117,40 +117,37 @@ func getLicensePlaceholder(name string) *licensePlaceholder { return ret } -func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository, oldCommitID, newCommitID, ownerName, repoName string) error { +func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository) error { gitRepo, err := git.OpenRepository(ctx, repo.RepoPath()) if err != nil { - return fmt.Errorf("failed to open repository: %s/%s Error: %v", ownerName, repoName, err) + return fmt.Errorf("OpenRepository: %w", err) } - commit, err := gitRepo.GetCommit(newCommitID) + commitID, err := gitRepo.GetBranchCommitID(repo.DefaultBranch) if err != nil { - return fmt.Errorf("failed to get new commit by id(%s): %s/%s Error: %v", newCommitID, ownerName, repoName, err) + return fmt.Errorf("GetBranchCommitID: %w", err) } - filesChanged, err := commit.GetFilesChangedSinceCommit(oldCommitID) + commit, err := gitRepo.GetCommit(commitID) if err != nil { - return fmt.Errorf("failed to get changed files from %s to %s: %s/%s Error: %v", oldCommitID, newCommitID, ownerName, repoName, err) + return fmt.Errorf("GetCommit: %w", err) } - for _, fn := range filesChanged { - // support ext - if fn == "LICENSE" { - blob, err := commit.GetBlobByPath(fn) - if err != nil { - return fmt.Errorf("failed to get license blob %s in commit %s: %s/%s Error: %v", fn, newCommitID, ownerName, repoName, err) - } - contentBuf, err := blob.GetBlobAll() - if err != nil { - return fmt.Errorf("failed to get license blob content %s in commit %s: %s/%s Error: %v", fn, newCommitID, ownerName, repoName, err) - } - var licenses []string - cov := licensecheck.Scan(contentBuf) - for _, m := range cov.Match { - licenses = append(licenses, m.ID) - } - repo.Licenses = licenses - if err := repo_model.UpdateRepositoryCols(ctx, repo, "licenses"); err != nil { - return fmt.Errorf("failed to Update Repo Licenses: %s/%s Error: %v", ownerName, repoName, err) - } - } + + blob, err := commit.GetBlobByPath("LICENSE") + if err != nil { + return fmt.Errorf("GetBlobByPath: %w", err) } + contentBuf, err := blob.GetBlobAll() + if err != nil { + return fmt.Errorf("GetBlobByPath: %w", err) + } + var licenses []string + cov := licensecheck.Scan(contentBuf) + for _, m := range cov.Match { + licenses = append(licenses, m.ID) + } + repo.Licenses = licenses + if err := repo_model.UpdateRepositoryCols(ctx, repo, "licenses"); err != nil { + return fmt.Errorf("UpdateRepositoryCols: %v", err) + } + return nil } diff --git a/modules/repository/repo.go b/modules/repository/repo.go index a1dba8fc6a..3d5c40a6eb 100644 --- a/modules/repository/repo.go +++ b/modules/repository/repo.go @@ -137,6 +137,12 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User, } defer gitRepo.Close() + // Update repo license + err = UpdateRepoLicenses(ctx, repo) + if err != nil { + return repo, fmt.Errorf("UpdateRepoLicenses: %w", err) + } + repo.IsEmpty, err = gitRepo.IsEmpty() if err != nil { return repo, fmt.Errorf("git.IsEmpty: %w", err) diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go index 341c4dc745..4ff19984cf 100644 --- a/routers/private/hook_post_receive.go +++ b/routers/private/hook_post_receive.go @@ -121,7 +121,6 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { // Now handle the pull request notification trailers for i := range opts.OldCommitIDs { refFullName := opts.RefFullNames[i] - oldCommitID := opts.OldCommitIDs[i] newCommitID := opts.NewCommitIDs[i] // post update for agit pull request @@ -201,7 +200,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { // If our branch is the default branch of an unforked repo - there's no PR to create or refer to if !repo.IsFork && branch == baseRepo.DefaultBranch { // TODO: check IsWiki? - err := repo_module.UpdateRepoLicenses(ctx, repo, oldCommitID, newCommitID, ownerName, repoName) + err := repo_module.UpdateRepoLicenses(ctx, repo) if err != nil { ctx.JSON(http.StatusInternalServerError, private.Response{Err: err.Error()}) } From 84801d5ef184d91f8a32a39e57b32c6f47b6c49a Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 25 May 2023 07:07:27 +0000 Subject: [PATCH 014/158] move findFileInEntries to repo modules --- modules/repository/file.go | 136 +++++++++++++++++++++++++++++ modules/repository/file_test.go | 6 ++ modules/repository/license_test.go | 4 + modules/util/path.go | 33 +++---- routers/web/repo/view.go | 119 +------------------------ 5 files changed, 161 insertions(+), 137 deletions(-) create mode 100644 modules/repository/file.go create mode 100644 modules/repository/file_test.go diff --git a/modules/repository/file.go b/modules/repository/file.go new file mode 100644 index 0000000000..14a68f62a9 --- /dev/null +++ b/modules/repository/file.go @@ -0,0 +1,136 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package repository + +import ( + "path" + "strings" + + "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/util" +) + +type FileType string + +const ( + FileTypeReadme FileType = "readme" + FileTypeLicense FileType = "license" +) + +// locate a README/LICENSE for a tree in one of the supported paths. +// +// entries is passed to reduce calls to ListEntries(), so +// this has precondition: +// +// entries == ctx.Repo.Commit.SubTree(ctx.Repo.TreePath).ListEntries() +// +// FIXME: There has to be a more efficient way of doing this +func FindFileInEntries(fileType FileType, entries []*git.TreeEntry, treePath, language string, tryWellKnownDirs bool) (string, *git.TreeEntry, error) { + // Create a list of extensions in priority order + // 1. Markdown files - with and without localisation - e.g. README.en-us.md or README.md + // 2. Txt files - e.g. README.txt + // 3. No extension - e.g. README + exts := append(localizedExtensions(".md", language), ".txt", "") // sorted by priority + extCount := len(exts) + targetFiles := make([]*git.TreeEntry, extCount+1) + + docsEntries := make([]*git.TreeEntry, 3) // (one of docs/, .gitea/ or .github/) + for _, entry := range entries { + if tryWellKnownDirs && entry.IsDir() { + // as a special case for the top-level repo introduction README, + // fall back to subfolders, looking for e.g. docs/README.md, .gitea/README.zh-CN.txt, .github/README.txt, ... + // (note that docsEntries is ignored unless we are at the root) + lowerName := strings.ToLower(entry.Name()) + switch lowerName { + case "docs": + if entry.Name() == "docs" || docsEntries[0] == nil { + docsEntries[0] = entry + } + case ".gitea": + if entry.Name() == ".gitea" || docsEntries[1] == nil { + docsEntries[1] = entry + } + case ".github": + if entry.Name() == ".github" || docsEntries[2] == nil { + docsEntries[2] = entry + } + } + continue + } + if i, ok := util.IsFileExtension(entry.Name(), string(fileType), exts...); ok { + log.Debug("Potential readme file: %s", entry.Name()) + if targetFiles[i] == nil || base.NaturalSortLess(targetFiles[i].Name(), entry.Blob().Name()) { + if entry.IsLink() { + target, err := entry.FollowLinks() + if err != nil && !git.IsErrBadLink(err) { + return "", nil, err + } else if target != nil && (target.IsExecutable() || target.IsRegular()) { + targetFiles[i] = entry + } + } else { + targetFiles[i] = entry + } + } + } + } + var targetFile *git.TreeEntry + for _, f := range targetFiles { + if f != nil { + targetFile = f + break + } + } + + if treePath == "" && targetFile == nil { + for _, subTreeEntry := range docsEntries { + if subTreeEntry == nil { + continue + } + subTree := subTreeEntry.Tree() + if subTree == nil { + // this should be impossible; if subTreeEntry exists so should this. + continue + } + var err error + childEntries, err := subTree.ListEntries() + if err != nil { + return "", nil, err + } + + subfolder, targetFile, err := FindFileInEntries(fileType, childEntries, subTreeEntry.Name(), language, false) + if err != nil && !git.IsErrNotExist(err) { + return "", nil, err + } + if targetFile != nil { + return path.Join(subTreeEntry.Name(), subfolder), targetFile, nil + } + } + } + + return "", targetFile, nil +} + +// localizedExtensions prepends the provided language code with and without a +// regional identifier to the provided extension. +// Note: the language code will always be lower-cased, if a region is present it must be separated with a `-` +// Note: ext should be prefixed with a `.` +func localizedExtensions(ext, languageCode string) (localizedExts []string) { + if len(languageCode) < 1 { + return []string{ext} + } + + lowerLangCode := "." + strings.ToLower(languageCode) + + if strings.Contains(lowerLangCode, "-") { + underscoreLangCode := strings.ReplaceAll(lowerLangCode, "-", "_") + indexOfDash := strings.Index(lowerLangCode, "-") + // e.g. [.zh-cn.md, .zh_cn.md, .zh.md, _zh.md, .md] + return []string{lowerLangCode + ext, underscoreLangCode + ext, lowerLangCode[:indexOfDash] + ext, "_" + lowerLangCode[1:indexOfDash] + ext, ext} + } + + // e.g. [.en.md, .md] + return []string{lowerLangCode + ext, ext} +} diff --git a/modules/repository/file_test.go b/modules/repository/file_test.go new file mode 100644 index 0000000000..4e34901ad3 --- /dev/null +++ b/modules/repository/file_test.go @@ -0,0 +1,6 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package repository + +// TODO diff --git a/modules/repository/license_test.go b/modules/repository/license_test.go index 13c865693c..e1555a0eed 100644 --- a/modules/repository/license_test.go +++ b/modules/repository/license_test.go @@ -179,3 +179,7 @@ Copyright (C) 2023 by Gitea teabot@gitea.io }) } } + +func Test_UpdateRepoLicenses(t *testing.T) { + // TODO +} diff --git a/modules/util/path.go b/modules/util/path.go index 8164d91c4b..d805fb4ed5 100644 --- a/modules/util/path.go +++ b/modules/util/path.go @@ -282,47 +282,40 @@ func CommonSkip(name string) bool { return false } -type FileType string - -const ( - FileTypeReadme FileType = "readme" - FileTypeLicense FileType = "license" -) - -// IsFileName reports whether name looks like a fileType file +// IsFileName reports whether name looks like a target name file // based on its name. -func IsFileName(name string, fileType FileType) bool { +func IsFileName(name string, targetName string) bool { name = strings.ToLower(name) - lenFileType := len(fileType) - if len(name) < lenFileType { + lenTargetName := len(targetName) + if len(name) < lenTargetName { return false - } else if len(name) == lenFileType { - return name == string(fileType) + } else if len(name) == lenTargetName { + return name == string(targetName) } - return name[:lenFileType+1] == string(fileType)+"." + return name[:lenTargetName+1] == string(targetName)+"." } -// IsFileExtension reports whether name looks like a fileType file +// IsFileExtension reports whether name looks like a target name file // based on its name. It will look through the provided extensions and check if the file matches // one of the extensions and provide the index in the extension list. // If the filename is `readme.` with an unmatched extension it will match with the index equaling // the length of the provided extension list. // Note that the '.' should be provided in ext, e.g ".md" -func IsFileExtension(name string, fileType FileType, ext ...string) (int, bool) { +func IsFileExtension(name, targetName string, ext ...string) (int, bool) { name = strings.ToLower(name) - lenFileType := len(fileType) - if len(name) < lenFileType || name[:lenFileType] != string(fileType) { + lenTargetName := len(targetName) + if len(name) < lenTargetName || name[:lenTargetName] != string(targetName) { return 0, false } for i, extension := range ext { extension = strings.ToLower(extension) - if name[lenFileType:] == extension { + if name[lenTargetName:] == extension { return i, true } } - if name[lenFileType] == '.' { + if name[lenTargetName] == '.' { return len(ext), true } diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index b9033563a8..da78dd87df 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -54,99 +54,6 @@ const ( tplMigrating base.TplName = "repo/migrate/migrating" ) -// locate a README/LICENSE for a tree in one of the supported paths. -// -// entries is passed to reduce calls to ListEntries(), so -// this has precondition: -// -// entries == ctx.Repo.Commit.SubTree(ctx.Repo.TreePath).ListEntries() -// -// FIXME: There has to be a more efficient way of doing this -func findFileInEntries(ctx *context.Context, fileType util.FileType, entries []*git.TreeEntry, tryWellKnownDirs bool) (string, *git.TreeEntry, error) { - // Create a list of extensions in priority order - // 1. Markdown files - with and without localisation - e.g. README.en-us.md or README.md - // 2. Txt files - e.g. README.txt - // 3. No extension - e.g. README - exts := append(localizedExtensions(".md", ctx.Locale.Language()), ".txt", "") // sorted by priority - extCount := len(exts) - targetFiles := make([]*git.TreeEntry, extCount+1) - - docsEntries := make([]*git.TreeEntry, 3) // (one of docs/, .gitea/ or .github/) - for _, entry := range entries { - if tryWellKnownDirs && entry.IsDir() { - // as a special case for the top-level repo introduction README, - // fall back to subfolders, looking for e.g. docs/README.md, .gitea/README.zh-CN.txt, .github/README.txt, ... - // (note that docsEntries is ignored unless we are at the root) - lowerName := strings.ToLower(entry.Name()) - switch lowerName { - case "docs": - if entry.Name() == "docs" || docsEntries[0] == nil { - docsEntries[0] = entry - } - case ".gitea": - if entry.Name() == ".gitea" || docsEntries[1] == nil { - docsEntries[1] = entry - } - case ".github": - if entry.Name() == ".github" || docsEntries[2] == nil { - docsEntries[2] = entry - } - } - continue - } - if i, ok := util.IsFileExtension(entry.Name(), fileType, exts...); ok { - log.Debug("Potential readme file: %s", entry.Name()) - if targetFiles[i] == nil || base.NaturalSortLess(targetFiles[i].Name(), entry.Blob().Name()) { - if entry.IsLink() { - target, err := entry.FollowLinks() - if err != nil && !git.IsErrBadLink(err) { - return "", nil, err - } else if target != nil && (target.IsExecutable() || target.IsRegular()) { - targetFiles[i] = entry - } - } else { - targetFiles[i] = entry - } - } - } - } - var targetFile *git.TreeEntry - for _, f := range targetFiles { - if f != nil { - targetFile = f - break - } - } - - if ctx.Repo.TreePath == "" && targetFile == nil { - for _, subTreeEntry := range docsEntries { - if subTreeEntry == nil { - continue - } - subTree := subTreeEntry.Tree() - if subTree == nil { - // this should be impossible; if subTreeEntry exists so should this. - continue - } - var err error - childEntries, err := subTree.ListEntries() - if err != nil { - return "", nil, err - } - - subfolder, targetFile, err := findFileInEntries(ctx, fileType, childEntries, false) - if err != nil && !git.IsErrNotExist(err) { - return "", nil, err - } - if targetFile != nil { - return path.Join(subTreeEntry.Name(), subfolder), targetFile, nil - } - } - } - - return "", targetFile, nil -} - func renderDirectory(ctx *context.Context, treeLink string) { entries := renderDirectoryFiles(ctx, 1*time.Second) if ctx.Written() { @@ -158,7 +65,7 @@ func renderDirectory(ctx *context.Context, treeLink string) { ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+path.Base(ctx.Repo.TreePath), ctx.Repo.RefName) } - subfolder, readmeFile, err := findFileInEntries(ctx, util.FileTypeReadme, entries, true) + subfolder, readmeFile, err := repo_module.FindFileInEntries(repo_module.FileTypeReadme, entries, ctx.Repo.TreePath, ctx.Locale.Language(), true) if err != nil { ctx.ServerError("findFileInEntries", err) return @@ -166,28 +73,6 @@ func renderDirectory(ctx *context.Context, treeLink string) { renderReadmeFile(ctx, subfolder, readmeFile, treeLink) } -// localizedExtensions prepends the provided language code with and without a -// regional identifier to the provided extension. -// Note: the language code will always be lower-cased, if a region is present it must be separated with a `-` -// Note: ext should be prefixed with a `.` -func localizedExtensions(ext, languageCode string) (localizedExts []string) { - if len(languageCode) < 1 { - return []string{ext} - } - - lowerLangCode := "." + strings.ToLower(languageCode) - - if strings.Contains(lowerLangCode, "-") { - underscoreLangCode := strings.ReplaceAll(lowerLangCode, "-", "_") - indexOfDash := strings.Index(lowerLangCode, "-") - // e.g. [.zh-cn.md, .zh_cn.md, .zh.md, _zh.md, .md] - return []string{lowerLangCode + ext, underscoreLangCode + ext, lowerLangCode[:indexOfDash] + ext, "_" + lowerLangCode[1:indexOfDash] + ext, ext} - } - - // e.g. [.en.md, .md] - return []string{lowerLangCode + ext, ext} -} - type fileInfo struct { isTextFile bool isLFSFile bool @@ -429,7 +314,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st rd := charset.ToUTF8WithFallbackReader(io.MultiReader(bytes.NewReader(buf), dataRc)) shouldRenderSource := ctx.FormString("display") == "source" - readmeExist := util.IsFileName(blob.Name(), util.FileTypeReadme) + readmeExist := util.IsFileName(blob.Name(), string(repo_module.FileTypeReadme)) ctx.Data["ReadmeExist"] = readmeExist markupType := markup.Type(blob.Name()) From 0421e9898272176c41d6b05f36757864f6579e2e Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 25 May 2023 07:16:33 +0000 Subject: [PATCH 015/158] update license when sync mirror repo --- services/mirror/mirror_pull.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go index 60699294c1..39e8d3de10 100644 --- a/services/mirror/mirror_pull.go +++ b/services/mirror/mirror_pull.go @@ -528,6 +528,12 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { return false } + // Update License + if err = repo_module.UpdateRepoLicenses(ctx, m.Repo); err != nil { + log.Error("SyncMirrors [repo: %-v]: unable to update repository 'licenses': %v", m.Repo, err) + return false + } + log.Trace("SyncMirrors [repo: %-v]: Successfully updated", m.Repo) return true From cf028887b8b840e05ca1f23324fddd5a39f66ef5 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 25 May 2023 07:24:57 +0000 Subject: [PATCH 016/158] support search license file --- modules/repository/license.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/modules/repository/license.go b/modules/repository/license.go index f20fc0e6f3..31fd69522e 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -130,15 +130,25 @@ func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository) error if err != nil { return fmt.Errorf("GetCommit: %w", err) } - - blob, err := commit.GetBlobByPath("LICENSE") + entries, err := commit.ListEntries() if err != nil { - return fmt.Errorf("GetBlobByPath: %w", err) + return fmt.Errorf("ListEntries: %w", err) } + + // Find license file + _, licenseFile, err := FindFileInEntries(FileTypeLicense, entries, "", "", false) + if err != nil { + return fmt.Errorf("FindFileInEntries: %w", err) + } + + // Read license file content + blob := licenseFile.Blob() contentBuf, err := blob.GetBlobAll() if err != nil { return fmt.Errorf("GetBlobByPath: %w", err) } + + // check license var licenses []string cov := licensecheck.Scan(contentBuf) for _, m := range cov.Match { From 10b2a902209a930f941f824507df13829384e9f8 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 25 May 2023 07:34:49 +0000 Subject: [PATCH 017/158] imporve debug info --- modules/repository/file.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/repository/file.go b/modules/repository/file.go index 14a68f62a9..6698602bd9 100644 --- a/modules/repository/file.go +++ b/modules/repository/file.go @@ -61,7 +61,7 @@ func FindFileInEntries(fileType FileType, entries []*git.TreeEntry, treePath, la continue } if i, ok := util.IsFileExtension(entry.Name(), string(fileType), exts...); ok { - log.Debug("Potential readme file: %s", entry.Name()) + log.Debug("Potential %s file: %s", fileType, entry.Name()) if targetFiles[i] == nil || base.NaturalSortLess(targetFiles[i].Name(), entry.Blob().Name()) { if entry.IsLink() { target, err := entry.FollowLinks() From f2857204c9c1ad284ac714180b8f5d70812be91f Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 25 May 2023 08:19:24 +0000 Subject: [PATCH 018/158] fix test --- modules/repository/file.go | 11 ++--------- modules/repository/license.go | 3 ++- modules/util/path.go | 29 ++++++++++++++++++----------- routers/web/repo/view.go | 4 ++-- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/modules/repository/file.go b/modules/repository/file.go index 6698602bd9..dc94a2c433 100644 --- a/modules/repository/file.go +++ b/modules/repository/file.go @@ -13,13 +13,6 @@ import ( "code.gitea.io/gitea/modules/util" ) -type FileType string - -const ( - FileTypeReadme FileType = "readme" - FileTypeLicense FileType = "license" -) - // locate a README/LICENSE for a tree in one of the supported paths. // // entries is passed to reduce calls to ListEntries(), so @@ -28,7 +21,7 @@ const ( // entries == ctx.Repo.Commit.SubTree(ctx.Repo.TreePath).ListEntries() // // FIXME: There has to be a more efficient way of doing this -func FindFileInEntries(fileType FileType, entries []*git.TreeEntry, treePath, language string, tryWellKnownDirs bool) (string, *git.TreeEntry, error) { +func FindFileInEntries(fileType util.FileType, entries []*git.TreeEntry, treePath, language string, tryWellKnownDirs bool) (string, *git.TreeEntry, error) { // Create a list of extensions in priority order // 1. Markdown files - with and without localisation - e.g. README.en-us.md or README.md // 2. Txt files - e.g. README.txt @@ -60,7 +53,7 @@ func FindFileInEntries(fileType FileType, entries []*git.TreeEntry, treePath, la } continue } - if i, ok := util.IsFileExtension(entry.Name(), string(fileType), exts...); ok { + if i, ok := util.IsFileExtension(entry.Name(), fileType, exts...); ok { log.Debug("Potential %s file: %s", fileType, entry.Name()) if targetFiles[i] == nil || base.NaturalSortLess(targetFiles[i].Name(), entry.Blob().Name()) { if entry.IsLink() { diff --git a/modules/repository/license.go b/modules/repository/license.go index 31fd69522e..259eb57b11 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -14,6 +14,7 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/options" + "code.gitea.io/gitea/modules/util" "github.com/google/licensecheck" ) @@ -136,7 +137,7 @@ func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository) error } // Find license file - _, licenseFile, err := FindFileInEntries(FileTypeLicense, entries, "", "", false) + _, licenseFile, err := FindFileInEntries(util.FileTypeLicense, entries, "", "", false) if err != nil { return fmt.Errorf("FindFileInEntries: %w", err) } diff --git a/modules/util/path.go b/modules/util/path.go index d805fb4ed5..41e45aa902 100644 --- a/modules/util/path.go +++ b/modules/util/path.go @@ -282,17 +282,24 @@ func CommonSkip(name string) bool { return false } +type FileType string + +const ( + FileTypeReadme FileType = "readme" + FileTypeLicense FileType = "license" +) + // IsFileName reports whether name looks like a target name file // based on its name. -func IsFileName(name string, targetName string) bool { +func IsFileName(name string, fileType FileType) bool { name = strings.ToLower(name) - lenTargetName := len(targetName) - if len(name) < lenTargetName { + lenFileType := len(fileType) + if len(name) < lenFileType { return false - } else if len(name) == lenTargetName { - return name == string(targetName) + } else if len(name) == lenFileType { + return name == string(fileType) } - return name[:lenTargetName+1] == string(targetName)+"." + return name[:lenFileType+1] == string(fileType)+"." } // IsFileExtension reports whether name looks like a target name file @@ -301,21 +308,21 @@ func IsFileName(name string, targetName string) bool { // If the filename is `readme.` with an unmatched extension it will match with the index equaling // the length of the provided extension list. // Note that the '.' should be provided in ext, e.g ".md" -func IsFileExtension(name, targetName string, ext ...string) (int, bool) { +func IsFileExtension(name string, fileType FileType, ext ...string) (int, bool) { name = strings.ToLower(name) - lenTargetName := len(targetName) - if len(name) < lenTargetName || name[:lenTargetName] != string(targetName) { + lenFileType := len(fileType) + if len(name) < lenFileType || name[:lenFileType] != string(fileType) { return 0, false } for i, extension := range ext { extension = strings.ToLower(extension) - if name[lenTargetName:] == extension { + if name[lenFileType:] == extension { return i, true } } - if name[lenTargetName] == '.' { + if name[lenFileType] == '.' { return len(ext), true } diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index da78dd87df..c4f96439d3 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -65,7 +65,7 @@ func renderDirectory(ctx *context.Context, treeLink string) { ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+path.Base(ctx.Repo.TreePath), ctx.Repo.RefName) } - subfolder, readmeFile, err := repo_module.FindFileInEntries(repo_module.FileTypeReadme, entries, ctx.Repo.TreePath, ctx.Locale.Language(), true) + subfolder, readmeFile, err := repo_module.FindFileInEntries(util.FileTypeReadme, entries, ctx.Repo.TreePath, ctx.Locale.Language(), true) if err != nil { ctx.ServerError("findFileInEntries", err) return @@ -314,7 +314,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st rd := charset.ToUTF8WithFallbackReader(io.MultiReader(bytes.NewReader(buf), dataRc)) shouldRenderSource := ctx.FormString("display") == "source" - readmeExist := util.IsFileName(blob.Name(), string(repo_module.FileTypeReadme)) + readmeExist := util.IsFileName(blob.Name(), util.FileTypeReadme) ctx.Data["ReadmeExist"] = readmeExist markupType := markup.Type(blob.Name()) From 7eb45846fa73cae24772ec705d14f42922f27a46 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 25 May 2023 08:29:26 +0000 Subject: [PATCH 019/158] fix test --- modules/repository/file_test.go | 57 +++++++++++++++++++++++++++++- routers/web/repo/view_test.go | 62 --------------------------------- 2 files changed, 56 insertions(+), 63 deletions(-) delete mode 100644 routers/web/repo/view_test.go diff --git a/modules/repository/file_test.go b/modules/repository/file_test.go index 4e34901ad3..171c9d9b74 100644 --- a/modules/repository/file_test.go +++ b/modules/repository/file_test.go @@ -3,4 +3,59 @@ package repository -// TODO +import ( + "reflect" + "testing" +) + +func Test_localizedExtensions(t *testing.T) { + tests := []struct { + name string + ext string + languageCode string + wantLocalizedExts []string + }{ + { + name: "empty language", + ext: ".md", + wantLocalizedExts: []string{".md"}, + }, + { + name: "No region - lowercase", + languageCode: "en", + ext: ".csv", + wantLocalizedExts: []string{".en.csv", ".csv"}, + }, + { + name: "No region - uppercase", + languageCode: "FR", + ext: ".txt", + wantLocalizedExts: []string{".fr.txt", ".txt"}, + }, + { + name: "With region - lowercase", + languageCode: "en-us", + ext: ".md", + wantLocalizedExts: []string{".en-us.md", ".en_us.md", ".en.md", "_en.md", ".md"}, + }, + { + name: "With region - uppercase", + languageCode: "en-CA", + ext: ".MD", + wantLocalizedExts: []string{".en-ca.MD", ".en_ca.MD", ".en.MD", "_en.MD", ".MD"}, + }, + { + name: "With region - all uppercase", + languageCode: "ZH-TW", + ext: ".md", + wantLocalizedExts: []string{".zh-tw.md", ".zh_tw.md", ".zh.md", "_zh.md", ".md"}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if gotLocalizedExts := localizedExtensions(tt.ext, tt.languageCode); !reflect.DeepEqual(gotLocalizedExts, tt.wantLocalizedExts) { + t.Errorf("localizedExtensions() = %v, want %v", gotLocalizedExts, tt.wantLocalizedExts) + } + }) + } +} diff --git a/routers/web/repo/view_test.go b/routers/web/repo/view_test.go deleted file mode 100644 index 73ba118823..0000000000 --- a/routers/web/repo/view_test.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2017 The Gitea Authors. All rights reserved. -// Copyright 2014 The Gogs Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package repo - -import ( - "reflect" - "testing" -) - -func Test_localizedExtensions(t *testing.T) { - tests := []struct { - name string - ext string - languageCode string - wantLocalizedExts []string - }{ - { - name: "empty language", - ext: ".md", - wantLocalizedExts: []string{".md"}, - }, - { - name: "No region - lowercase", - languageCode: "en", - ext: ".csv", - wantLocalizedExts: []string{".en.csv", ".csv"}, - }, - { - name: "No region - uppercase", - languageCode: "FR", - ext: ".txt", - wantLocalizedExts: []string{".fr.txt", ".txt"}, - }, - { - name: "With region - lowercase", - languageCode: "en-us", - ext: ".md", - wantLocalizedExts: []string{".en-us.md", ".en_us.md", ".en.md", "_en.md", ".md"}, - }, - { - name: "With region - uppercase", - languageCode: "en-CA", - ext: ".MD", - wantLocalizedExts: []string{".en-ca.MD", ".en_ca.MD", ".en.MD", "_en.MD", ".MD"}, - }, - { - name: "With region - all uppercase", - languageCode: "ZH-TW", - ext: ".md", - wantLocalizedExts: []string{".zh-tw.md", ".zh_tw.md", ".zh.md", "_zh.md", ".md"}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if gotLocalizedExts := localizedExtensions(tt.ext, tt.languageCode); !reflect.DeepEqual(gotLocalizedExts, tt.wantLocalizedExts) { - t.Errorf("localizedExtensions() = %v, want %v", gotLocalizedExts, tt.wantLocalizedExts) - } - }) - } -} From 8ba16c0c545bcff2be749f09974d2dc44d1b1b43 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 25 May 2023 09:47:41 +0000 Subject: [PATCH 020/158] fix --- modules/repository/license.go | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/modules/repository/license.go b/modules/repository/license.go index 259eb57b11..96bffdce1b 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -142,22 +142,24 @@ func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository) error return fmt.Errorf("FindFileInEntries: %w", err) } - // Read license file content - blob := licenseFile.Blob() - contentBuf, err := blob.GetBlobAll() - if err != nil { - return fmt.Errorf("GetBlobByPath: %w", err) - } + if licenseFile != nil { + // Read license file content + blob := licenseFile.Blob() + contentBuf, err := blob.GetBlobAll() + if err != nil { + return fmt.Errorf("GetBlobByPath: %w", err) + } - // check license - var licenses []string - cov := licensecheck.Scan(contentBuf) - for _, m := range cov.Match { - licenses = append(licenses, m.ID) - } - repo.Licenses = licenses - if err := repo_model.UpdateRepositoryCols(ctx, repo, "licenses"); err != nil { - return fmt.Errorf("UpdateRepositoryCols: %v", err) + // check license + var licenses []string + cov := licensecheck.Scan(contentBuf) + for _, m := range cov.Match { + licenses = append(licenses, m.ID) + } + repo.Licenses = licenses + if err := repo_model.UpdateRepositoryCols(ctx, repo, "licenses"); err != nil { + return fmt.Errorf("UpdateRepositoryCols: %v", err) + } } return nil From 0637b87923a611d3b5ad29d4c1d2286657f13f63 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 25 May 2023 10:19:20 +0000 Subject: [PATCH 021/158] fix --- modules/repository/license.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/repository/license.go b/modules/repository/license.go index 96bffdce1b..e92f9a745c 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -119,6 +119,10 @@ func getLicensePlaceholder(name string) *licensePlaceholder { } func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository) error { + if repo.DefaultBranch == "" { + return nil + } + gitRepo, err := git.OpenRepository(ctx, repo.RepoPath()) if err != nil { return fmt.Errorf("OpenRepository: %w", err) From facd6982e24912bdb3c068297c31e583d8a93aed Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 26 May 2023 00:44:00 +0000 Subject: [PATCH 022/158] improve --- modules/context/repo.go | 2 - modules/repository/license.go | 83 ++++++++++++++++++++-------- modules/repository/repo.go | 2 +- routers/private/hook_post_receive.go | 2 +- routers/web/repo/view.go | 5 ++ services/mirror/mirror_pull.go | 2 +- 6 files changed, 67 insertions(+), 29 deletions(-) diff --git a/modules/context/repo.go b/modules/context/repo.go index 9ee51b2d9e..ff4d2d6803 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -400,8 +400,6 @@ func repoAssignment(ctx *Context, repo *repo_model.Repository) { ctx.Data["RepoName"] = ctx.Repo.Repository.Name ctx.Data["IsEmptyRepo"] = ctx.Repo.Repository.IsEmpty ctx.Data["Licenses"] = ctx.Repo.Repository.Licenses - // TODO: support ext - ctx.Data["LicenseFileName"] = "LICENSE" } // RepoIDAssignment returns a handler which assigns the repo to the context. diff --git a/modules/repository/license.go b/modules/repository/license.go index e92f9a745c..ceb6a600fd 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -118,32 +118,19 @@ func getLicensePlaceholder(name string) *licensePlaceholder { return ret } -func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository) error { - if repo.DefaultBranch == "" { - return nil +// UpdateRepoLicenses will update repository licenses col if license file exists +func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository) error { + if gitRepo == nil { + var err error + gitRepo, err = git.OpenRepository(ctx, repo.RepoPath()) + if err != nil { + return fmt.Errorf("OpenRepository: %w", err) + } } - gitRepo, err := git.OpenRepository(ctx, repo.RepoPath()) + _, licenseFile, err := findLicenseFile(ctx, gitRepo, repo.DefaultBranch) if err != nil { - return fmt.Errorf("OpenRepository: %w", err) - } - commitID, err := gitRepo.GetBranchCommitID(repo.DefaultBranch) - if err != nil { - return fmt.Errorf("GetBranchCommitID: %w", err) - } - commit, err := gitRepo.GetCommit(commitID) - if err != nil { - return fmt.Errorf("GetCommit: %w", err) - } - entries, err := commit.ListEntries() - if err != nil { - return fmt.Errorf("ListEntries: %w", err) - } - - // Find license file - _, licenseFile, err := FindFileInEntries(util.FileTypeLicense, entries, "", "", false) - if err != nil { - return fmt.Errorf("FindFileInEntries: %w", err) + return fmt.Errorf("findLicenseFile: %w", err) } if licenseFile != nil { @@ -151,7 +138,7 @@ func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository) error blob := licenseFile.Blob() contentBuf, err := blob.GetBlobAll() if err != nil { - return fmt.Errorf("GetBlobByPath: %w", err) + return fmt.Errorf("GetBlobAll: %w", err) } // check license @@ -168,3 +155,51 @@ func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository) error return nil } + +// GetLicenseFileName returns license file name in the repository if it exists +func GetLicenseFileName(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository) (string, error) { + if repo.DefaultBranch == "" { + return "", nil + } + if gitRepo == nil { + var err error + gitRepo, err = git.OpenRepository(ctx, repo.RepoPath()) + if err != nil { + return "", fmt.Errorf("OpenRepository: %w", err) + } + } + + _, licenseFile, err := findLicenseFile(ctx, gitRepo, repo.DefaultBranch) + if err != nil { + return "", fmt.Errorf("findLicenseFile: %w", err) + } + + if licenseFile != nil { + return licenseFile.Name(), nil + } + return "", nil +} + +// findLicenseFile returns the entry of license file in the repository if it exists +func findLicenseFile(ctx context.Context, gitRepo *git.Repository, branchName string) (string, *git.TreeEntry, error) { + if branchName == "" { + return "", nil, nil + } + if gitRepo == nil { + return "", nil, nil + } + + commitID, err := gitRepo.GetBranchCommitID(branchName) + if err != nil { + return "", nil, fmt.Errorf("GetBranchCommitID: %w", err) + } + commit, err := gitRepo.GetCommit(commitID) + if err != nil { + return "", nil, fmt.Errorf("GetCommit: %w", err) + } + entries, err := commit.ListEntries() + if err != nil { + return "", nil, fmt.Errorf("ListEntries: %w", err) + } + return FindFileInEntries(util.FileTypeLicense, entries, "", "", false) +} diff --git a/modules/repository/repo.go b/modules/repository/repo.go index 3d5c40a6eb..50fa5788ee 100644 --- a/modules/repository/repo.go +++ b/modules/repository/repo.go @@ -138,7 +138,7 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User, defer gitRepo.Close() // Update repo license - err = UpdateRepoLicenses(ctx, repo) + err = UpdateRepoLicenses(ctx, repo, gitRepo) if err != nil { return repo, fmt.Errorf("UpdateRepoLicenses: %w", err) } diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go index 4ff19984cf..c0a0ca830f 100644 --- a/routers/private/hook_post_receive.go +++ b/routers/private/hook_post_receive.go @@ -200,7 +200,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { // If our branch is the default branch of an unforked repo - there's no PR to create or refer to if !repo.IsFork && branch == baseRepo.DefaultBranch { // TODO: check IsWiki? - err := repo_module.UpdateRepoLicenses(ctx, repo) + err := repo_module.UpdateRepoLicenses(ctx, repo, nil) if err != nil { ctx.JSON(http.StatusInternalServerError, private.Response{Err: err.Error()}) } diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index c4f96439d3..772056bb48 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -870,6 +870,11 @@ func renderCode(ctx *context.Context) { ctx.Data["TreeLink"] = treeLink ctx.Data["TreeNames"] = treeNames ctx.Data["BranchLink"] = branchLink + ctx.Data["LicenseFileName"], err = repo_module.GetLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo) + if err != nil { + ctx.ServerError("GetLicenseFileName", err) + return + } ctx.HTML(http.StatusOK, tplRepoHome) } diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go index 39e8d3de10..d4724de45f 100644 --- a/services/mirror/mirror_pull.go +++ b/services/mirror/mirror_pull.go @@ -529,7 +529,7 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { } // Update License - if err = repo_module.UpdateRepoLicenses(ctx, m.Repo); err != nil { + if err = repo_module.UpdateRepoLicenses(ctx, m.Repo, gitRepo); err != nil { log.Error("SyncMirrors [repo: %-v]: unable to update repository 'licenses': %v", m.Repo, err) return false } From af1b031c0592c651014eb21ed4eea9e235463343 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 26 May 2023 00:53:45 +0000 Subject: [PATCH 023/158] fix fork repo --- routers/private/hook_post_receive.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go index c0a0ca830f..728cac86a1 100644 --- a/routers/private/hook_post_receive.go +++ b/routers/private/hook_post_receive.go @@ -197,15 +197,18 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { } } - // If our branch is the default branch of an unforked repo - there's no PR to create or refer to - if !repo.IsFork && branch == baseRepo.DefaultBranch { + if branch == baseRepo.DefaultBranch { // TODO: check IsWiki? err := repo_module.UpdateRepoLicenses(ctx, repo, nil) if err != nil { ctx.JSON(http.StatusInternalServerError, private.Response{Err: err.Error()}) } - results = append(results, private.HookPostReceiveBranchResult{}) - continue + + // If our branch is the default branch of an unforked repo - there's no PR to create or refer to + if !repo.IsFork { + results = append(results, private.HookPostReceiveBranchResult{}) + continue + } } pr, err := issues_model.GetUnmergedPullRequest(ctx, repo.ID, baseRepo.ID, branch, baseRepo.DefaultBranch, issues_model.PullRequestFlowGithub) From 30c25ba3add3d4715b4e6e6d937441f082dc45d3 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 26 May 2023 01:00:22 +0000 Subject: [PATCH 024/158] remove check iswiki --- routers/private/hook_post_receive.go | 1 - 1 file changed, 1 deletion(-) diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go index 728cac86a1..01b61ab0f0 100644 --- a/routers/private/hook_post_receive.go +++ b/routers/private/hook_post_receive.go @@ -198,7 +198,6 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { } if branch == baseRepo.DefaultBranch { - // TODO: check IsWiki? err := repo_module.UpdateRepoLicenses(ctx, repo, nil) if err != nil { ctx.JSON(http.StatusInternalServerError, private.Response{Err: err.Error()}) From bc005ddc8fd9520dc3d3c7046c717eff11024f15 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 26 May 2023 02:48:05 +0000 Subject: [PATCH 025/158] fix no commitID --- modules/repository/license.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/repository/license.go b/modules/repository/license.go index ceb6a600fd..725c903499 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -191,6 +191,9 @@ func findLicenseFile(ctx context.Context, gitRepo *git.Repository, branchName st commitID, err := gitRepo.GetBranchCommitID(branchName) if err != nil { + if git.IsErrNotExist(err) { + return "", nil, nil + } return "", nil, fmt.Errorf("GetBranchCommitID: %w", err) } commit, err := gitRepo.GetCommit(commitID) From 3518a638992c79add59263fadb349e8ae7fb8c93 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 26 May 2023 02:54:57 +0000 Subject: [PATCH 026/158] fix lint --- routers/private/hook_post_receive.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go index b6034f0343..7d38d07739 100644 --- a/routers/private/hook_post_receive.go +++ b/routers/private/hook_post_receive.go @@ -193,8 +193,8 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { } } - branch := refFullName.BranchName() - + branch := refFullName.BranchName() + if branch == baseRepo.DefaultBranch { err := repo_module.UpdateRepoLicenses(ctx, repo, nil) if err != nil { From 763f104e74befa92e4f6d3c6fa5246dfac6f515e Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 29 May 2023 04:40:05 +0000 Subject: [PATCH 027/158] improve --- modules/repository/license.go | 61 +++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/modules/repository/license.go b/modules/repository/license.go index 725c903499..fe68aa8dcf 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -128,29 +128,15 @@ func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository, gitRep } } - _, licenseFile, err := findLicenseFile(ctx, gitRepo, repo.DefaultBranch) + _, licenseFile, err := findLicenseFile(gitRepo, repo.DefaultBranch) if err != nil { return fmt.Errorf("findLicenseFile: %w", err) } - - if licenseFile != nil { - // Read license file content - blob := licenseFile.Blob() - contentBuf, err := blob.GetBlobAll() - if err != nil { - return fmt.Errorf("GetBlobAll: %w", err) - } - - // check license - var licenses []string - cov := licensecheck.Scan(contentBuf) - for _, m := range cov.Match { - licenses = append(licenses, m.ID) - } - repo.Licenses = licenses - if err := repo_model.UpdateRepositoryCols(ctx, repo, "licenses"); err != nil { - return fmt.Errorf("UpdateRepositoryCols: %v", err) - } + if repo.Licenses, err = detectLicense(licenseFile); err != nil { + return fmt.Errorf("checkLicenseFile: %w", err) + } + if err := repo_model.UpdateRepositoryCols(ctx, repo, "licenses"); err != nil { + return fmt.Errorf("UpdateRepositoryCols: %v", err) } return nil @@ -169,7 +155,7 @@ func GetLicenseFileName(ctx context.Context, repo *repo_model.Repository, gitRep } } - _, licenseFile, err := findLicenseFile(ctx, gitRepo, repo.DefaultBranch) + _, licenseFile, err := findLicenseFile(gitRepo, repo.DefaultBranch) if err != nil { return "", fmt.Errorf("findLicenseFile: %w", err) } @@ -181,7 +167,7 @@ func GetLicenseFileName(ctx context.Context, repo *repo_model.Repository, gitRep } // findLicenseFile returns the entry of license file in the repository if it exists -func findLicenseFile(ctx context.Context, gitRepo *git.Repository, branchName string) (string, *git.TreeEntry, error) { +func findLicenseFile(gitRepo *git.Repository, branchName string) (string, *git.TreeEntry, error) { if branchName == "" { return "", nil, nil } @@ -189,16 +175,12 @@ func findLicenseFile(ctx context.Context, gitRepo *git.Repository, branchName st return "", nil, nil } - commitID, err := gitRepo.GetBranchCommitID(branchName) + commit, err := gitRepo.GetBranchCommit(branchName) if err != nil { if git.IsErrNotExist(err) { return "", nil, nil } - return "", nil, fmt.Errorf("GetBranchCommitID: %w", err) - } - commit, err := gitRepo.GetCommit(commitID) - if err != nil { - return "", nil, fmt.Errorf("GetCommit: %w", err) + return "", nil, fmt.Errorf("GetBranchCommit: %w", err) } entries, err := commit.ListEntries() if err != nil { @@ -206,3 +188,26 @@ func findLicenseFile(ctx context.Context, gitRepo *git.Repository, branchName st } return FindFileInEntries(util.FileTypeLicense, entries, "", "", false) } + +// detectLicense returns the licenses detected in the given file +func detectLicense(file *git.TreeEntry) ([]string, error) { + if file == nil { + return nil, nil + } + + // Read license file content + blob := file.Blob() + contentBuf, err := blob.GetBlobAll() + if err != nil { + return nil, fmt.Errorf("GetBlobAll: %w", err) + } + + // check license + var licenses []string + cov := licensecheck.Scan(contentBuf) + for _, m := range cov.Match { + licenses = append(licenses, m.ID) + } + + return licenses, nil +} From f481624e4c4f50ef418d3d25995e4417ec9253f1 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 29 May 2023 04:40:36 +0000 Subject: [PATCH 028/158] add db migration --- models/migrations/migrations.go | 2 + models/migrations/v1_20/v259.go | 122 ++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+) create mode 100644 models/migrations/v1_20/v259.go diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 231c93cc74..9466e1df03 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -495,6 +495,8 @@ var migrations = []Migration{ NewMigration("Add Actions Artifact table", v1_20.CreateActionArtifactTable), // v258 -> 259 NewMigration("Add PinOrder Column", v1_20.AddPinOrderToIssue), + // v259 -> 260 + NewMigration("Add Repository Licenses", v1_20.AddRepositoryLicenses), } // GetCurrentDBVersion returns the current db version diff --git a/models/migrations/v1_20/v259.go b/models/migrations/v1_20/v259.go new file mode 100644 index 0000000000..d64a938ee6 --- /dev/null +++ b/models/migrations/v1_20/v259.go @@ -0,0 +1,122 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_20 //nolint + +import ( + "fmt" + "path/filepath" + "strings" + + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/log" + repo_module "code.gitea.io/gitea/modules/repository" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" + "github.com/google/licensecheck" + + "xorm.io/builder" + "xorm.io/xorm" +) + +// Copy paste from models/repo.go because we cannot import models package +func repoPath(userName, repoName string) string { + return filepath.Join(userPath(userName), strings.ToLower(repoName)+".git") +} + +func userPath(userName string) string { + return filepath.Join(setting.RepoRootPath, strings.ToLower(userName)) +} + +func findLicenseFile(gitRepo *git.Repository, branchName string) (string, *git.TreeEntry, error) { + if branchName == "" { + return "", nil, nil + } + if gitRepo == nil { + return "", nil, nil + } + + commit, err := gitRepo.GetBranchCommit(branchName) + if err != nil { + if git.IsErrNotExist(err) { + return "", nil, nil + } + return "", nil, fmt.Errorf("GetBranchCommit: %w", err) + } + entries, err := commit.ListEntries() + if err != nil { + return "", nil, fmt.Errorf("ListEntries: %w", err) + } + return repo_module.FindFileInEntries(util.FileTypeLicense, entries, "", "", false) +} + +func detectLicense(file *git.TreeEntry) ([]string, error) { + if file == nil { + return nil, nil + } + + // Read license file content + blob := file.Blob() + contentBuf, err := blob.GetBlobAll() + if err != nil { + return nil, fmt.Errorf("GetBlobAll: %w", err) + } + + // check license + var licenses []string + cov := licensecheck.Scan(contentBuf) + for _, m := range cov.Match { + licenses = append(licenses, m.ID) + } + + return licenses, nil +} + +func AddRepositoryLicenses(x *xorm.Engine) error { + type Repository struct { + ID int64 `xorm:"pk autoincr"` + OwnerName string + Name string `xorm:"INDEX NOT NULL"` + DefaultBranch string + Licenses []string `xorm:"TEXT JSON"` + } + + if err := x.Sync(new(Repository)); err != nil { + return err + } + + sess := x.NewSession() + defer sess.Close() + + if err := sess.Begin(); err != nil { + return err + } + + repos := make([]*Repository, 0) + if err := sess.Where(builder.IsNull{"licenses"}).Find(&repos); err != nil { + return err + } + + for _, repo := range repos { + gitRepo, err := git.OpenRepository(git.DefaultContext, repoPath(repo.OwnerName, repo.Name)) + if err != nil { + log.Error("Error whilst opening git repo for [%d]%s/%s. Error: %v", repo.ID, repo.OwnerName, repo.Name, err) + return err + } + _, licenseFile, err := findLicenseFile(gitRepo, repo.DefaultBranch) + if err != nil { + log.Error("Error whilst finding license file in [%d]%s/%s. Error: %v", repo.ID, repo.OwnerName, repo.Name, err) + return err + } + repo.Licenses, err = detectLicense(licenseFile) + if err != nil { + log.Error("Error whilst detecting license from %s in [%d]%s/%s. Error: %v", licenseFile.Name(), repo.ID, repo.OwnerName, repo.Name, err) + return err + } + if _, err := sess.ID(repo.ID).Cols("licenses").NoAutoTime().Update(repo); err != nil { + log.Error("Error whilst updating [%d]%s/%s licenses column. Error: %v", repo.ID, repo.OwnerName, repo.Name, err) + return err + } + } + return sess.Commit() +} From 07e91bf049b7c689958b777e79b6063392163f71 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 29 May 2023 05:24:09 +0000 Subject: [PATCH 029/158] fix migration --- models/migrations/v1_20/v259.go | 109 +++++++++++++++++++++++++++++++- 1 file changed, 107 insertions(+), 2 deletions(-) diff --git a/models/migrations/v1_20/v259.go b/models/migrations/v1_20/v259.go index d64a938ee6..a20f6dc17d 100644 --- a/models/migrations/v1_20/v259.go +++ b/models/migrations/v1_20/v259.go @@ -5,12 +5,13 @@ package v1_20 //nolint import ( "fmt" + "path" "path/filepath" "strings" + "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" - repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" "github.com/google/licensecheck" @@ -28,6 +29,7 @@ func userPath(userName string) string { return filepath.Join(setting.RepoRootPath, strings.ToLower(userName)) } +// Copy paste from modules/repository/file.go because we cannot import models package func findLicenseFile(gitRepo *git.Repository, branchName string) (string, *git.TreeEntry, error) { if branchName == "" { return "", nil, nil @@ -47,7 +49,110 @@ func findLicenseFile(gitRepo *git.Repository, branchName string) (string, *git.T if err != nil { return "", nil, fmt.Errorf("ListEntries: %w", err) } - return repo_module.FindFileInEntries(util.FileTypeLicense, entries, "", "", false) + return findFileInEntries(util.FileTypeLicense, entries, "", "", false) +} + +func findFileInEntries(fileType util.FileType, entries []*git.TreeEntry, treePath, language string, tryWellKnownDirs bool) (string, *git.TreeEntry, error) { + // Create a list of extensions in priority order + // 1. Markdown files - with and without localisation - e.g. README.en-us.md or README.md + // 2. Txt files - e.g. README.txt + // 3. No extension - e.g. README + exts := append(localizedExtensions(".md", language), ".txt", "") // sorted by priority + extCount := len(exts) + targetFiles := make([]*git.TreeEntry, extCount+1) + + docsEntries := make([]*git.TreeEntry, 3) // (one of docs/, .gitea/ or .github/) + for _, entry := range entries { + if tryWellKnownDirs && entry.IsDir() { + // as a special case for the top-level repo introduction README, + // fall back to subfolders, looking for e.g. docs/README.md, .gitea/README.zh-CN.txt, .github/README.txt, ... + // (note that docsEntries is ignored unless we are at the root) + lowerName := strings.ToLower(entry.Name()) + switch lowerName { + case "docs": + if entry.Name() == "docs" || docsEntries[0] == nil { + docsEntries[0] = entry + } + case ".gitea": + if entry.Name() == ".gitea" || docsEntries[1] == nil { + docsEntries[1] = entry + } + case ".github": + if entry.Name() == ".github" || docsEntries[2] == nil { + docsEntries[2] = entry + } + } + continue + } + if i, ok := util.IsFileExtension(entry.Name(), fileType, exts...); ok { + log.Debug("Potential %s file: %s", fileType, entry.Name()) + if targetFiles[i] == nil || base.NaturalSortLess(targetFiles[i].Name(), entry.Blob().Name()) { + if entry.IsLink() { + target, err := entry.FollowLinks() + if err != nil && !git.IsErrBadLink(err) { + return "", nil, err + } else if target != nil && (target.IsExecutable() || target.IsRegular()) { + targetFiles[i] = entry + } + } else { + targetFiles[i] = entry + } + } + } + } + var targetFile *git.TreeEntry + for _, f := range targetFiles { + if f != nil { + targetFile = f + break + } + } + + if treePath == "" && targetFile == nil { + for _, subTreeEntry := range docsEntries { + if subTreeEntry == nil { + continue + } + subTree := subTreeEntry.Tree() + if subTree == nil { + // this should be impossible; if subTreeEntry exists so should this. + continue + } + var err error + childEntries, err := subTree.ListEntries() + if err != nil { + return "", nil, err + } + + subfolder, targetFile, err := findFileInEntries(fileType, childEntries, subTreeEntry.Name(), language, false) + if err != nil && !git.IsErrNotExist(err) { + return "", nil, err + } + if targetFile != nil { + return path.Join(subTreeEntry.Name(), subfolder), targetFile, nil + } + } + } + + return "", targetFile, nil +} + +func localizedExtensions(ext, languageCode string) (localizedExts []string) { + if len(languageCode) < 1 { + return []string{ext} + } + + lowerLangCode := "." + strings.ToLower(languageCode) + + if strings.Contains(lowerLangCode, "-") { + underscoreLangCode := strings.ReplaceAll(lowerLangCode, "-", "_") + indexOfDash := strings.Index(lowerLangCode, "-") + // e.g. [.zh-cn.md, .zh_cn.md, .zh.md, _zh.md, .md] + return []string{lowerLangCode + ext, underscoreLangCode + ext, lowerLangCode[:indexOfDash] + ext, "_" + lowerLangCode[1:indexOfDash] + ext, ext} + } + + // e.g. [.en.md, .md] + return []string{lowerLangCode + ext, ext} } func detectLicense(file *git.TreeEntry) ([]string, error) { From 744a03226f9bf50b428a6e77f5eeff3fabb78ce9 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 29 May 2023 06:13:49 +0000 Subject: [PATCH 030/158] add licensecheck test --- models/migrations/v1_20/v259.go | 4 +-- modules/repository/license.go | 20 +++++++----- modules/repository/license_test.go | 51 ++++++++++++++++++++++++++++-- 3 files changed, 63 insertions(+), 12 deletions(-) diff --git a/models/migrations/v1_20/v259.go b/models/migrations/v1_20/v259.go index a20f6dc17d..4cb95c980e 100644 --- a/models/migrations/v1_20/v259.go +++ b/models/migrations/v1_20/v259.go @@ -155,7 +155,7 @@ func localizedExtensions(ext, languageCode string) (localizedExts []string) { return []string{lowerLangCode + ext, ext} } -func detectLicense(file *git.TreeEntry) ([]string, error) { +func detectLicenseByEntry(file *git.TreeEntry) ([]string, error) { if file == nil { return nil, nil } @@ -213,7 +213,7 @@ func AddRepositoryLicenses(x *xorm.Engine) error { log.Error("Error whilst finding license file in [%d]%s/%s. Error: %v", repo.ID, repo.OwnerName, repo.Name, err) return err } - repo.Licenses, err = detectLicense(licenseFile) + repo.Licenses, err = detectLicenseByEntry(licenseFile) if err != nil { log.Error("Error whilst detecting license from %s in [%d]%s/%s. Error: %v", licenseFile.Name(), repo.ID, repo.OwnerName, repo.Name, err) return err diff --git a/modules/repository/license.go b/modules/repository/license.go index fe68aa8dcf..09eac2d3ef 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -132,7 +132,7 @@ func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository, gitRep if err != nil { return fmt.Errorf("findLicenseFile: %w", err) } - if repo.Licenses, err = detectLicense(licenseFile); err != nil { + if repo.Licenses, err = detectLicenseByEntry(licenseFile); err != nil { return fmt.Errorf("checkLicenseFile: %w", err) } if err := repo_model.UpdateRepositoryCols(ctx, repo, "licenses"); err != nil { @@ -189,25 +189,29 @@ func findLicenseFile(gitRepo *git.Repository, branchName string) (string, *git.T return FindFileInEntries(util.FileTypeLicense, entries, "", "", false) } -// detectLicense returns the licenses detected in the given file -func detectLicense(file *git.TreeEntry) ([]string, error) { +// detectLicenseByEntry returns the licenses detected by the given tree entry +func detectLicenseByEntry(file *git.TreeEntry) ([]string, error) { if file == nil { return nil, nil } - // Read license file content blob := file.Blob() contentBuf, err := blob.GetBlobAll() if err != nil { return nil, fmt.Errorf("GetBlobAll: %w", err) } + return detectLicense(contentBuf), nil +} + +func detectLicense(buf []byte) []string { + if len(buf) <= 0 { + return nil + } - // check license var licenses []string - cov := licensecheck.Scan(contentBuf) + cov := licensecheck.Scan(buf) for _, m := range cov.Match { licenses = append(licenses, m.ID) } - - return licenses, nil + return licenses } diff --git a/modules/repository/license_test.go b/modules/repository/license_test.go index e1555a0eed..a45537507a 100644 --- a/modules/repository/license_test.go +++ b/modules/repository/license_test.go @@ -6,6 +6,7 @@ package repository import ( "fmt" "testing" + "time" "github.com/stretchr/testify/assert" ) @@ -180,6 +181,52 @@ Copyright (C) 2023 by Gitea teabot@gitea.io } } -func Test_UpdateRepoLicenses(t *testing.T) { - // TODO +func Test_detectLicense(t *testing.T) { + type DetectLicenseTest struct { + name string + arg []byte + want []string + } + + tests := []DetectLicenseTest{ + { + name: "empty", + arg: []byte(""), + want: nil, + }, + { + name: "no detected license", + arg: []byte("Copyright (c) 2023 Gitea"), + want: nil, + }, + } + + LoadRepoConfig() + for _, licenseName := range Licenses { + license, err := getLicense(licenseName, &licenseValues{ + Owner: "Gitea", + Email: "teabot@gitea.io", + Repo: "gitea", + Year: time.Now().Format("2006"), + }) + assert.NoError(t, err) + + tests = append(tests, DetectLicenseTest{ + name: fmt.Sprintf("auto single license test: %s", licenseName), + arg: license, + want: []string{licenseName}, + }) + } + + tests = append(tests, DetectLicenseTest{ + name: fmt.Sprintf("auto multiple license test: %s and %s", tests[2].want[0], tests[3].want[0]), + arg: append(tests[2].arg, tests[3].arg...), + want: []string{tests[2].want[0], tests[3].want[0]}, + }) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equalf(t, tt.want, detectLicense(tt.arg), "%s", tt.arg) + }) + } } From 93d2c7f055e28f95e059c711ccb0de614ffc37c9 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 30 May 2023 05:33:32 +0000 Subject: [PATCH 031/158] fix lint --- modules/repository/license.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/repository/license.go b/modules/repository/license.go index 09eac2d3ef..bd8b1be9b3 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -204,7 +204,7 @@ func detectLicenseByEntry(file *git.TreeEntry) ([]string, error) { } func detectLicense(buf []byte) []string { - if len(buf) <= 0 { + if len(buf) == 0 { return nil } From 92d8df7592b8cdb35ab74c4d29333882f3cfeb7d Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 31 May 2023 01:09:16 +0000 Subject: [PATCH 032/158] move the position of license --- templates/repo/sub_menu.tmpl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/templates/repo/sub_menu.tmpl b/templates/repo/sub_menu.tmpl index 738984ff98..09fb5d1048 100644 --- a/templates/repo/sub_menu.tmpl +++ b/templates/repo/sub_menu.tmpl @@ -14,11 +14,6 @@ {{svg "octicon-tag"}} {{.NumTags}} {{.locale.TrN .NumTags "repo.tag" "repo.tags"}} {{end}} -
- {{$fileSizeFormatted := FileSize .Repository.Size}}{{/* the formatted string is always "{val} {unit}" */}} - {{$fileSizeFields := StringUtils.Split $fileSizeFormatted " "}} - {{svg "octicon-database"}} {{.locale.PrettyNumber (index $fileSizeFields 0)}} {{index $fileSizeFields 1}} -
{{if .Licenses}}
{{svg "octicon-law"}} @@ -30,6 +25,11 @@
{{end}} +
+ {{$fileSizeFormatted := FileSize .Repository.Size}}{{/* the formatted string is always "{val} {unit}" */}} + {{$fileSizeFields := StringUtils.Split $fileSizeFormatted " "}} + {{svg "octicon-database"}} {{.locale.PrettyNumber (index $fileSizeFields 0)}} {{index $fileSizeFields 1}} +
{{end}} From ac8442202c6883d77442704c724b43035714da28 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 31 May 2023 01:26:42 +0000 Subject: [PATCH 033/158] fix --- routers/web/repo/branch.go | 6 ++++++ routers/web/repo/commit.go | 17 ++++++++++++++++- templates/repo/sub_menu.tmpl | 2 +- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go index ea2c01856d..1c54626c0f 100644 --- a/routers/web/repo/branch.go +++ b/routers/web/repo/branch.go @@ -80,6 +80,12 @@ func Branches(ctx *context.Context) { pager.SetDefaultParams(ctx) ctx.Data["Page"] = pager + var err error + ctx.Data["LicenseFileName"], err = repo_module.GetLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo) + if err != nil { + ctx.ServerError("GetLicenseFileName", err) + return + } ctx.HTML(http.StatusOK, tplBranch) } diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index e88f1139f8..1974abd7ab 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -21,6 +21,7 @@ import ( "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitgraph" "code.gitea.io/gitea/modules/log" + repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/services/gitdiff" ) @@ -85,7 +86,11 @@ func Commits(ctx *context.Context) { pager := context.NewPagination(int(commitsCount), pageSize, page, 5) pager.SetDefaultParams(ctx) ctx.Data["Page"] = pager - + ctx.Data["LicenseFileName"], err = repo_module.GetLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo) + if err != nil { + ctx.ServerError("GetLicenseFileName", err) + return + } ctx.HTML(http.StatusOK, tplCommits) } @@ -203,6 +208,11 @@ func SearchCommits(ctx *context.Context) { ctx.Data["Username"] = ctx.Repo.Owner.Name ctx.Data["Reponame"] = ctx.Repo.Repository.Name ctx.Data["RefName"] = ctx.Repo.RefName + ctx.Data["LicenseFileName"], err = repo_module.GetLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo) + if err != nil { + ctx.ServerError("GetLicenseFileName", err) + return + } ctx.HTML(http.StatusOK, tplCommits) } @@ -252,6 +262,11 @@ func FileHistory(ctx *context.Context) { pager.SetDefaultParams(ctx) ctx.Data["Page"] = pager + ctx.Data["LicenseFileName"], err = repo_module.GetLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo) + if err != nil { + ctx.ServerError("GetLicenseFileName", err) + return + } ctx.HTML(http.StatusOK, tplCommits) } diff --git a/templates/repo/sub_menu.tmpl b/templates/repo/sub_menu.tmpl index 09fb5d1048..0d113e621d 100644 --- a/templates/repo/sub_menu.tmpl +++ b/templates/repo/sub_menu.tmpl @@ -16,7 +16,7 @@ {{end}} {{if .Licenses}}
- {{svg "octicon-law"}} + {{svg "octicon-law"}} {{if eq (len .Licenses) 1}} {{index .Licenses 0}} {{else}} From ef340f66289083eaed198ea151b744d107f341bc Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 31 May 2023 02:41:00 +0000 Subject: [PATCH 034/158] only use defaultbranch to display license file --- modules/context/repo.go | 1 + routers/web/repo/branch.go | 1 - routers/web/repo/release.go | 2 -- templates/repo/sub_menu.tmpl | 2 +- 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/modules/context/repo.go b/modules/context/repo.go index ff4d2d6803..bdbd99c42c 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -554,6 +554,7 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) { ctx.Data["Title"] = owner.Name + "/" + repo.Name ctx.Data["Repository"] = repo ctx.Data["Owner"] = ctx.Repo.Repository.Owner + ctx.Data["DefaultBranch"] = ctx.Repo.Repository.DefaultBranch ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner() ctx.Data["IsRepositoryAdmin"] = ctx.Repo.IsAdmin() ctx.Data["RepoOwnerIsOrganization"] = repo.Owner.IsOrganization() diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go index 1c54626c0f..23e0233114 100644 --- a/routers/web/repo/branch.go +++ b/routers/web/repo/branch.go @@ -53,7 +53,6 @@ type Branch struct { func Branches(ctx *context.Context) { ctx.Data["Title"] = "Branches" ctx.Data["IsRepoToolbarBranches"] = true - ctx.Data["DefaultBranch"] = ctx.Repo.Repository.DefaultBranch ctx.Data["AllowsPulls"] = ctx.Repo.Repository.AllowsPulls() ctx.Data["IsWriter"] = ctx.Repo.CanWrite(unit.TypeCode) ctx.Data["IsMirror"] = ctx.Repo.Repository.IsMirror diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go index afba1f18bf..e0df548967 100644 --- a/routers/web/repo/release.go +++ b/routers/web/repo/release.go @@ -82,7 +82,6 @@ func TagsList(ctx *context.Context) { } func releasesOrTags(ctx *context.Context, isTagList bool) { - ctx.Data["DefaultBranch"] = ctx.Repo.Repository.DefaultBranch ctx.Data["IsViewBranch"] = false ctx.Data["IsViewTag"] = true // Disable the showCreateNewBranch form in the dropdown on this page. @@ -236,7 +235,6 @@ func releasesOrTagsFeed(ctx *context.Context, isReleasesOnly bool, formatType st // SingleRelease renders a single release's page func SingleRelease(ctx *context.Context) { ctx.Data["PageIsReleaseList"] = true - ctx.Data["DefaultBranch"] = ctx.Repo.Repository.DefaultBranch writeAccess := ctx.Repo.CanWrite(unit.TypeReleases) ctx.Data["CanCreateRelease"] = writeAccess && !ctx.Repo.Repository.IsArchived diff --git a/templates/repo/sub_menu.tmpl b/templates/repo/sub_menu.tmpl index 0d113e621d..3717970fab 100644 --- a/templates/repo/sub_menu.tmpl +++ b/templates/repo/sub_menu.tmpl @@ -16,7 +16,7 @@ {{end}} {{if .Licenses}}
- {{svg "octicon-law"}} + {{svg "octicon-law"}} {{if eq (len .Licenses) 1}} {{index .Licenses 0}} {{else}} From 63a6da8867ef0a77a2333266610b00be34665cf4 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 31 May 2023 02:54:36 +0000 Subject: [PATCH 035/158] add licenses to api.Repository --- modules/structs/repo.go | 1 + services/convert/repository.go | 1 + 2 files changed, 2 insertions(+) diff --git a/modules/structs/repo.go b/modules/structs/repo.go index fc4ed03de5..8c86cdec84 100644 --- a/modules/structs/repo.go +++ b/modules/structs/repo.go @@ -107,6 +107,7 @@ type Repository struct { // swagger:strfmt date-time MirrorUpdated time.Time `json:"mirror_updated,omitempty"` RepoTransfer *RepoTransfer `json:"repo_transfer"` + Licenses []string `json:"licenses"` } // CreateRepoOption options when creating repository diff --git a/services/convert/repository.go b/services/convert/repository.go index 54a61efe43..4cafd7d525 100644 --- a/services/convert/repository.go +++ b/services/convert/repository.go @@ -208,6 +208,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, mode perm.Acc MirrorInterval: mirrorInterval, MirrorUpdated: mirrorUpdated, RepoTransfer: transfer, + Licenses: repo.Licenses, } } From b9c2329e0e032565dcc059501c73c1f3cee6e06e Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 31 May 2023 06:21:38 +0000 Subject: [PATCH 036/158] update licenses info when update default branch --- routers/private/default_branch.go | 9 +++++++++ routers/web/repo/setting_protected_branch.go | 7 ++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/routers/private/default_branch.go b/routers/private/default_branch.go index b15d6ba33a..b06ef5e1b7 100644 --- a/routers/private/default_branch.go +++ b/routers/private/default_branch.go @@ -11,6 +11,7 @@ import ( gitea_context "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/private" + repo_module "code.gitea.io/gitea/modules/repository" ) // SetDefaultBranch updates the default branch @@ -35,5 +36,13 @@ func SetDefaultBranch(ctx *gitea_context.PrivateContext) { }) return } + + if err := repo_module.UpdateRepoLicenses(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo); err != nil { + ctx.JSON(http.StatusInternalServerError, private.Response{ + Err: fmt.Sprintf("Unable to set default branch on repository: %s/%s Error: %v", ownerName, repoName, err), + }) + return + } + ctx.PlainText(http.StatusOK, "success") } diff --git a/routers/web/repo/setting_protected_branch.go b/routers/web/repo/setting_protected_branch.go index 1a944799c2..86135afbf5 100644 --- a/routers/web/repo/setting_protected_branch.go +++ b/routers/web/repo/setting_protected_branch.go @@ -19,6 +19,7 @@ import ( "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" + repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/forms" @@ -74,7 +75,11 @@ func SetDefaultBranchPost(ctx *context.Context) { } } if err := repo_model.UpdateDefaultBranch(repo); err != nil { - ctx.ServerError("SetDefaultBranch", err) + ctx.ServerError("UpdateDefaultBranch", err) + return + } + if err := repo_module.UpdateRepoLicenses(ctx, repo, ctx.Repo.GitRepo); err != nil { + ctx.ServerError("UpdateRepoLicenses", err) return } } From 48da7a639a9239d9ed7bda951950cc0fc3ec0ca2 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 5 Jun 2023 08:14:34 +0000 Subject: [PATCH 037/158] convert use licenseclassifier --- assets/go-licenses.json | 6 +-- go.mod | 2 +- go.sum | 4 +- models/migrations/v1_20/{v259.go => v260.go} | 41 +++++++++++++++++--- modules/repository/license.go | 41 ++++++++++++++++++-- options/license/GPL-3.0-interface-exception | 7 ++++ 6 files changed, 85 insertions(+), 16 deletions(-) rename models/migrations/v1_20/{v259.go => v260.go} (89%) create mode 100644 options/license/GPL-3.0-interface-exception diff --git a/assets/go-licenses.json b/assets/go-licenses.json index 01328ef046..c767de4e56 100644 --- a/assets/go-licenses.json +++ b/assets/go-licenses.json @@ -540,9 +540,9 @@ "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" }, { - "name": "github.com/google/licensecheck", - "path": "github.com/google/licensecheck/LICENSE", - "licenseText": "Copyright (c) 2019 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + "name": "github.com/google/licenseclassifier/v2", + "path": "github.com/google/licenseclassifier/v2/LICENSE", + "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" }, { "name": "github.com/google/pprof/profile", diff --git a/go.mod b/go.mod index cffa100fc6..732be5ce9b 100644 --- a/go.mod +++ b/go.mod @@ -56,7 +56,7 @@ require ( github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 github.com/golang-jwt/jwt/v4 v4.5.0 github.com/google/go-github/v52 v52.0.0 - github.com/google/licensecheck v0.3.1 + github.com/google/licenseclassifier/v2 v2.0.0 github.com/google/pprof v0.0.0-20230502171905-255e3b9b56de github.com/google/uuid v1.3.0 github.com/gorilla/feeds v1.1.1 diff --git a/go.sum b/go.sum index ddf522b63c..15019d0fe9 100644 --- a/go.sum +++ b/go.sum @@ -576,8 +576,8 @@ github.com/google/go-tpm v0.3.3/go.mod h1:9Hyn3rgnzWF9XBWVk6ml6A6hNkbWjNFlDQL51B github.com/google/go-tpm-tools v0.0.0-20190906225433-1614c142f845/go.mod h1:AVfHadzbdzHo54inR2x1v640jdi1YSi3NauM2DUsxk0= github.com/google/go-tpm-tools v0.2.0/go.mod h1:npUd03rQ60lxN7tzeBJreG38RvWwme2N1reF/eeiBk4= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/licensecheck v0.3.1 h1:QoxgoDkaeC4nFrtGN1jV7IPmDCHFNIVh54e5hSt6sPs= -github.com/google/licensecheck v0.3.1/go.mod h1:ORkR35t/JjW+emNKtfJDII0zlciG9JgbT7SmsohlHmY= +github.com/google/licenseclassifier/v2 v2.0.0 h1:1Y57HHILNf4m0ABuMVb6xk4vAJYEUO0gDxNpog0pyeA= +github.com/google/licenseclassifier/v2 v2.0.0/go.mod h1:cOjbdH0kyC9R22sdQbYsFkto4NGCAc+ZSwbeThazEtM= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= diff --git a/models/migrations/v1_20/v259.go b/models/migrations/v1_20/v260.go similarity index 89% rename from models/migrations/v1_20/v259.go rename to models/migrations/v1_20/v260.go index 4cb95c980e..13fe586ada 100644 --- a/models/migrations/v1_20/v259.go +++ b/models/migrations/v1_20/v260.go @@ -5,6 +5,7 @@ package v1_20 //nolint import ( "fmt" + "os" "path" "path/filepath" "strings" @@ -14,10 +15,11 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" - "github.com/google/licensecheck" "xorm.io/builder" "xorm.io/xorm" + + licenseclassifier "github.com/google/licenseclassifier/v2" ) // Copy paste from models/repo.go because we cannot import models package @@ -168,13 +170,40 @@ func detectLicenseByEntry(file *git.TreeEntry) ([]string, error) { } // check license - var licenses []string - cov := licensecheck.Scan(contentBuf) - for _, m := range cov.Match { - licenses = append(licenses, m.ID) + return detectLicense(contentBuf), nil +} + +func detectLicense(buf []byte) []string { + if len(buf) == 0 { + return nil } - return licenses, nil + var licenses []string + // TODO: load classfier in init + classifier := licenseclassifier.NewClassifier(.8) + licenseEntries, err := os.ReadDir("options/license") + if err != nil { + fmt.Println(err) + return nil + } + + for _, le := range licenseEntries { + path := filepath.Join("options/license/" + le.Name()) + b, err := os.ReadFile(path) + if err != nil { + fmt.Println(err) + return nil + } + classifier.AddContent("License", le.Name(), "license", b) + } + + results := classifier.Match(buf) + for _, r := range results.Matches { + if r.MatchType == "License" { + licenses = append(licenses, r.Name) + } + } + return licenses } func AddRepositoryLicenses(x *xorm.Engine) error { diff --git a/modules/repository/license.go b/modules/repository/license.go index bd8b1be9b3..01c74e805b 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -8,6 +8,9 @@ import ( "bytes" "context" "fmt" + "io" + "os" + "path/filepath" "regexp" "strings" @@ -16,7 +19,7 @@ import ( "code.gitea.io/gitea/modules/options" "code.gitea.io/gitea/modules/util" - "github.com/google/licensecheck" + licenseclassifier "github.com/google/licenseclassifier/v2" ) type licenseValues struct { @@ -203,15 +206,45 @@ func detectLicenseByEntry(file *git.TreeEntry) ([]string, error) { return detectLicense(contentBuf), nil } +func ReadLicenseFile() ([]byte, error) { + fr, err := os.Open("licenses.db") + if err != nil { + return nil, fmt.Errorf("Can't open licenses.db: %w", err) + } + defer fr.Close() + + return io.ReadAll(fr) +} + func detectLicense(buf []byte) []string { if len(buf) == 0 { return nil } var licenses []string - cov := licensecheck.Scan(buf) - for _, m := range cov.Match { - licenses = append(licenses, m.ID) + // TODO: load classfier in init + classifier := licenseclassifier.NewClassifier(.8) + licenseEntries, err := os.ReadDir("options/license") + if err != nil { + fmt.Println(err) + return nil + } + + for _, le := range licenseEntries { + path := filepath.Join("options/license/" + le.Name()) + b, err := os.ReadFile(path) + if err != nil { + fmt.Println(err) + return nil + } + classifier.AddContent("License", le.Name(), "license", b) + } + + results := classifier.Match(buf) + for _, r := range results.Matches { + if r.MatchType == "License" { + licenses = append(licenses, r.Name) + } } return licenses } diff --git a/options/license/GPL-3.0-interface-exception b/options/license/GPL-3.0-interface-exception new file mode 100644 index 0000000000..a86a7fffd7 --- /dev/null +++ b/options/license/GPL-3.0-interface-exception @@ -0,0 +1,7 @@ +Linking [name of library] statically or dynamically with other modules is making a combined work based on [name of library]. Thus, the terms and conditions of the GNU General Public License cover the whole combination. + +As a special exception, the copyright holders of [name of library] give you permission to combine [name of library] program with free software programs or libraries that are released under the GNU LGPL and with independent modules that communicate with [name of library] solely through the [name of library's interface] interface. You may copy and distribute such a system following the terms of the GNU GPL for [name of library] and the licenses of the other code concerned, provided that you include the source code of that other code when and as the GNU GPL requires distribution of source code and provided that you do not modify the [name of library's interface] interface. + +Note that people who make modified versions of [name of library] are not obligated to grant this special exception for their modified versions; it is their choice whether to do so. The GNU General Public License gives permission to release a modified version without this exception; this exception also makes it possible to release a modified version which carries forward this exception. If you modify the [name of library's interface] interface, this exception does not apply to your modified version of [name of library], and you must remove this exception when you distribute your modified version. + +This exception is an additional permission under section 7 of the GNU General Public License, version 3 ("GPLv3") From fa8e34790c13380b774b7cb520fb3641418837d5 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 5 Jun 2023 08:27:56 +0000 Subject: [PATCH 038/158] fix --- models/migrations/migrations.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index a7a33d8447..7690151ef3 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -496,8 +496,8 @@ var migrations = []Migration{ // v258 -> 259 NewMigration("Add PinOrder Column", v1_20.AddPinOrderToIssue), // v259 -> 260 - NewMigration("Convert scoped access tokens", v1_20.ConvertScopedAccessTokens), - // v260 -> 261 + NewMigration("Convert scoped access tokens", v1_20.ConvertScopedAccessTokens), + // v260 -> 261 NewMigration("Add Repository Licenses", v1_20.AddRepositoryLicenses), } From 7a01d3b8897ea151c193cdbac849e28c11d379ce Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 6 Jun 2023 05:54:15 +0000 Subject: [PATCH 039/158] remove unnecessary code --- models/migrations/v1_20/v260.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/models/migrations/v1_20/v260.go b/models/migrations/v1_20/v260.go index 13fe586ada..c079edd4d9 100644 --- a/models/migrations/v1_20/v260.go +++ b/models/migrations/v1_20/v260.go @@ -179,11 +179,9 @@ func detectLicense(buf []byte) []string { } var licenses []string - // TODO: load classfier in init classifier := licenseclassifier.NewClassifier(.8) licenseEntries, err := os.ReadDir("options/license") if err != nil { - fmt.Println(err) return nil } @@ -191,7 +189,6 @@ func detectLicense(buf []byte) []string { path := filepath.Join("options/license/" + le.Name()) b, err := os.ReadFile(path) if err != nil { - fmt.Println(err) return nil } classifier.AddContent("License", le.Name(), "license", b) From 1cb20208f09364d5f90ce26cbbb016bf1d0d4c7c Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 6 Jun 2023 05:59:38 +0000 Subject: [PATCH 040/158] init licenseclassifier when service start --- modules/repository/license.go | 43 ++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/modules/repository/license.go b/modules/repository/license.go index 01c74e805b..d7331234bb 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -10,18 +10,38 @@ import ( "fmt" "io" "os" - "path/filepath" "regexp" "strings" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/options" "code.gitea.io/gitea/modules/util" licenseclassifier "github.com/google/licenseclassifier/v2" ) +var classifier *licenseclassifier.Classifier + +func init() { + // TODO: add threshold to app.ini + classifier = licenseclassifier.NewClassifier(.8) + licenseFiles, err := options.AssetFS().ListFiles("license", true) + if err != nil { + log.Error("init license classifier: %v", err) + return + } + for _, lf := range licenseFiles { + data, err := options.License(lf) + if err != nil { + log.Error("init license classifier: %v", err) + return + } + classifier.AddContent("License", lf, "license", data) + } +} + type licenseValues struct { Owner string Email string @@ -220,31 +240,18 @@ func detectLicense(buf []byte) []string { if len(buf) == 0 { return nil } - - var licenses []string - // TODO: load classfier in init - classifier := licenseclassifier.NewClassifier(.8) - licenseEntries, err := os.ReadDir("options/license") - if err != nil { - fmt.Println(err) + if classifier == nil { + log.Error("detectLicense: license classifier is null.") return nil } - for _, le := range licenseEntries { - path := filepath.Join("options/license/" + le.Name()) - b, err := os.ReadFile(path) - if err != nil { - fmt.Println(err) - return nil - } - classifier.AddContent("License", le.Name(), "license", b) - } - + var licenses []string results := classifier.Match(buf) for _, r := range results.Matches { if r.MatchType == "License" { licenses = append(licenses, r.Name) } } + fmt.Println(licenses) return licenses } From 58b4cc21682e7ba31c4c3a6ee443bd40ff103077 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 6 Jun 2023 06:02:19 +0000 Subject: [PATCH 041/158] remove unnecessary code and add comment --- modules/repository/license.go | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/modules/repository/license.go b/modules/repository/license.go index d7331234bb..4675c54c4f 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -8,8 +8,6 @@ import ( "bytes" "context" "fmt" - "io" - "os" "regexp" "strings" @@ -226,16 +224,7 @@ func detectLicenseByEntry(file *git.TreeEntry) ([]string, error) { return detectLicense(contentBuf), nil } -func ReadLicenseFile() ([]byte, error) { - fr, err := os.Open("licenses.db") - if err != nil { - return nil, fmt.Errorf("Can't open licenses.db: %w", err) - } - defer fr.Close() - - return io.ReadAll(fr) -} - +// detectLicense returns the licenses detected by the given content buff func detectLicense(buf []byte) []string { if len(buf) == 0 { return nil @@ -252,6 +241,5 @@ func detectLicense(buf []byte) []string { licenses = append(licenses, r.Name) } } - fmt.Println(licenses) return licenses } From c58162ecd2d774f6d8f9b948336da5578c457675 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 6 Jun 2023 06:52:24 +0000 Subject: [PATCH 042/158] fix test --- modules/repository/license.go | 16 +++++++++++----- modules/repository/license_test.go | 4 +++- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/modules/repository/license.go b/modules/repository/license.go index 4675c54c4f..d866739456 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -23,21 +23,27 @@ import ( var classifier *licenseclassifier.Classifier func init() { + err := InitClassifier() + if err != nil { + log.Error("initClassifier: %v", err) + } +} + +func InitClassifier() error { // TODO: add threshold to app.ini - classifier = licenseclassifier.NewClassifier(.8) + classifier = licenseclassifier.NewClassifier(.9) licenseFiles, err := options.AssetFS().ListFiles("license", true) if err != nil { - log.Error("init license classifier: %v", err) - return + return err } for _, lf := range licenseFiles { data, err := options.License(lf) if err != nil { - log.Error("init license classifier: %v", err) - return + return err } classifier.AddContent("License", lf, "license", data) } + return nil } type licenseValues struct { diff --git a/modules/repository/license_test.go b/modules/repository/license_test.go index a45537507a..68edcf63b1 100644 --- a/modules/repository/license_test.go +++ b/modules/repository/license_test.go @@ -221,9 +221,11 @@ func Test_detectLicense(t *testing.T) { tests = append(tests, DetectLicenseTest{ name: fmt.Sprintf("auto multiple license test: %s and %s", tests[2].want[0], tests[3].want[0]), arg: append(tests[2].arg, tests[3].arg...), - want: []string{tests[2].want[0], tests[3].want[0]}, + want: []string{"389-exception", "0BSD"}, }) + err := InitClassifier() + assert.NoError(t, err) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { assert.Equalf(t, tt.want, detectLicense(tt.arg), "%s", tt.arg) From f2933cccba9d9086c7733e5db0c6be65b589abaf Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 6 Jun 2023 07:57:21 +0000 Subject: [PATCH 043/158] fix migration --- models/migrations/v1_20/v260.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/models/migrations/v1_20/v260.go b/models/migrations/v1_20/v260.go index c079edd4d9..2565f92cdc 100644 --- a/models/migrations/v1_20/v260.go +++ b/models/migrations/v1_20/v260.go @@ -5,7 +5,6 @@ package v1_20 //nolint import ( "fmt" - "os" "path" "path/filepath" "strings" @@ -13,6 +12,7 @@ import ( "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/options" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" @@ -178,22 +178,22 @@ func detectLicense(buf []byte) []string { return nil } - var licenses []string - classifier := licenseclassifier.NewClassifier(.8) - licenseEntries, err := os.ReadDir("options/license") + classifier := licenseclassifier.NewClassifier(.9) + licenseFiles, err := options.AssetFS().ListFiles("license", true) if err != nil { + log.Error("initClassifier: %v", err) return nil } - - for _, le := range licenseEntries { - path := filepath.Join("options/license/" + le.Name()) - b, err := os.ReadFile(path) + for _, lf := range licenseFiles { + data, err := options.License(lf) if err != nil { + log.Error("initClassifier: %v", err) return nil } - classifier.AddContent("License", le.Name(), "license", b) + classifier.AddContent("License", lf, "license", data) } + var licenses []string results := classifier.Match(buf) for _, r := range results.Matches { if r.MatchType == "License" { From 388bc2600f47800b0fc45f17d717eb353d4d1ce0 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 8 Jun 2023 02:21:08 +0000 Subject: [PATCH 044/158] add tooltips --- templates/repo/sub_menu.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/repo/sub_menu.tmpl b/templates/repo/sub_menu.tmpl index 3717970fab..d69f27a94b 100644 --- a/templates/repo/sub_menu.tmpl +++ b/templates/repo/sub_menu.tmpl @@ -16,7 +16,7 @@ {{end}} {{if .Licenses}}
- {{svg "octicon-law"}} + {{svg "octicon-law"}} {{if eq (len .Licenses) 1}} {{index .Licenses 0}} {{else}} From 7f2b5d0c8e9c694bcf0c4de806f66f08d8562796 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 9 Jun 2023 07:46:27 +0000 Subject: [PATCH 045/158] improve --- modules/repository/license.go | 34 +++++++++++++++++++++--------- modules/repository/license_test.go | 2 +- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/modules/repository/license.go b/modules/repository/license.go index d866739456..1a46cca7f5 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -36,12 +36,15 @@ func InitClassifier() error { if err != nil { return err } - for _, lf := range licenseFiles { - data, err := options.License(lf) - if err != nil { - return err + + if len(licenseFiles) > 0 { + for _, lf := range licenseFiles { + data, err := options.License(lf) + if err != nil { + return err + } + classifier.AddContent("License", lf, "license", data) } - classifier.AddContent("License", lf, "license", data) } return nil } @@ -240,12 +243,23 @@ func detectLicense(buf []byte) []string { return nil } - var licenses []string - results := classifier.Match(buf) - for _, r := range results.Matches { + matches := classifier.Match(buf) + licenseVariants := make(map[string][]string, len(matches.Matches)) + for _, r := range matches.Matches { if r.MatchType == "License" { - licenses = append(licenses, r.Name) + tag := fmt.Sprintf("%d-%d", r.StartLine, r.EndLine) + licenseVariants[tag] = append(licenseVariants[r.Variant], r.Name) } } - return licenses + + var results []string + for _, licenses := range licenseVariants { + if len(licenses) == 1 { + results = append(results, licenses[0]) + } else { + // TODO: reslove license detection conflict + results = append(results, licenses...) + } + } + return results } diff --git a/modules/repository/license_test.go b/modules/repository/license_test.go index 68edcf63b1..753877ec2b 100644 --- a/modules/repository/license_test.go +++ b/modules/repository/license_test.go @@ -228,7 +228,7 @@ func Test_detectLicense(t *testing.T) { assert.NoError(t, err) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - assert.Equalf(t, tt.want, detectLicense(tt.arg), "%s", tt.arg) + assert.Equalf(t, tt.want, detectLicense(tt.arg), "") }) } } From 4cf79bef0293ab4e14e1940dff5f6e3d7049b982 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 9 Jun 2023 07:52:59 +0000 Subject: [PATCH 046/158] fix --- modules/repository/license.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/repository/license.go b/modules/repository/license.go index 1a46cca7f5..160ec28f01 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -248,7 +248,7 @@ func detectLicense(buf []byte) []string { for _, r := range matches.Matches { if r.MatchType == "License" { tag := fmt.Sprintf("%d-%d", r.StartLine, r.EndLine) - licenseVariants[tag] = append(licenseVariants[r.Variant], r.Name) + licenseVariants[tag] = append(licenseVariants[tag], r.Name) } } From 84c7b98aaab970dcb105c09aa38f2a31d7b766d7 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 14 Jun 2023 02:02:08 +0000 Subject: [PATCH 047/158] generate same file list --- build/generate-licenses.go | 166 ++++++++++++++++++++++++++++- modules/repository/license.go | 53 ++++++--- modules/repository/license_test.go | 14 ++- 3 files changed, 210 insertions(+), 23 deletions(-) diff --git a/build/generate-licenses.go b/build/generate-licenses.go index 9a111bc811..7909f1ee39 100644 --- a/build/generate-licenses.go +++ b/build/generate-licenses.go @@ -4,7 +4,9 @@ package main import ( "archive/tar" + "bytes" "compress/gzip" + "crypto/md5" "flag" "fmt" "io" @@ -15,6 +17,7 @@ import ( "path/filepath" "strings" + "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/util" ) @@ -77,7 +80,9 @@ func main() { } tr := tar.NewReader(gz) - + var pf *os.File + var pfn string + sameFiles := make(map[string][]string) for { hdr, err := tr.Next() @@ -97,14 +102,17 @@ func main() { continue } - if strings.HasPrefix(filepath.Base(hdr.Name), "README") { + fbn := filepath.Base(hdr.Name) + ln := strings.TrimSuffix(fbn, ".txt") + + if strings.HasPrefix(fbn, "README") { continue } - if strings.HasPrefix(filepath.Base(hdr.Name), "deprecated_") { + if strings.HasPrefix(fbn, "deprecated_") { continue } - out, err := os.Create(path.Join(destination, strings.TrimSuffix(filepath.Base(hdr.Name), ".txt"))) + out, err := os.Create(path.Join(destination, ln)) if err != nil { log.Fatalf("Failed to create new file. %s", err) } @@ -115,8 +123,158 @@ func main() { log.Fatalf("Failed to write new file. %s", err) } else { fmt.Printf("Written %s\n", out.Name()) + + // some license files have same content, so we need to detect these files and create a convert map into a file + // In InitClassifier, we will use this convert map to avoid adding same license content with different license name + md5, err := getSameFileMD5(pf, out) + if err != nil { + log.Fatalf("Failed to get same file md5. %s", err) + continue + } + if md5 != "" { + _, ok := sameFiles[md5] + if !ok { + sameFiles[md5] = make([]string, 0) + } + if !contains(sameFiles[md5], pfn) { + sameFiles[md5] = append(sameFiles[md5], pfn) + } + sameFiles[md5] = append(sameFiles[md5], ln) + } + pf = out + pfn = ln } } + // generate convert license name map + convertLicenseName := make(map[string]string) + for _, fileNames := range sameFiles { + key := getLicenseKey(fileNames) + for _, fileName := range fileNames { + convertLicenseName[fileName] = key + } + } + // save convert license name map to file + bytes, err := json.Marshal(convertLicenseName) + if err != nil { + log.Fatalf("Failed to create json bytes. %s", err) + return + } + // TODO change the path + path := "options/convertLicenseName" + out, err := os.Create(path) + if err != nil { + log.Fatalf("Failed to create new file. %s", err) + } + defer out.Close() + _, err = out.Write(bytes) + if err != nil { + log.Fatalf("Failed to write %s. %s", path, err) + } + fmt.Println("Done") } + +// getSameFileMD5 returns md5 of the input file, if the content of input files are same +func getSameFileMD5(f1, f2 *os.File) (string, error) { + if f1 == nil || f2 == nil { + return "", nil + } + + // check file size + fs1, err := f1.Stat() + if err != nil { + return "", err + } + fs2, err := f2.Stat() + if err != nil { + return "", err + } + + if fs1.Size() != fs2.Size() { + return "", nil + } + + // check content + var chunkSize = 1024 + _, err = f1.Seek(0, 0) + if err != nil { + return "", err + } + _, err = f2.Seek(0, 0) + if err != nil { + return "", err + } + + var totalBytes []byte + for { + b1 := make([]byte, chunkSize) + _, err1 := f1.Read(b1) + + b2 := make([]byte, chunkSize) + _, err2 := f2.Read(b2) + + totalBytes = append(totalBytes, b1...) + + if err1 != nil || err2 != nil { + if err1 == io.EOF && err2 == io.EOF { + md5 := md5.Sum(totalBytes) + return string(md5[:]), nil + } else if err1 == io.EOF || err2 == io.EOF { + return "", nil + } else if err1 != nil { + return "", err1 + } else if err2 != nil { + return "", err2 + } + } + + if !bytes.Equal(b1, b2) { + return "", nil + } + } +} + +func getLicenseKey(fnl []string) string { + if len(fnl) == 0 { + return "" + } + + shortestItem := func(list []string) string { + s := list[0] + for _, l := range list[1:] { + if len(l) < len(s) { + s = l + } + } + return s + } + allHasPrefix := func(list []string, s string) bool { + for _, l := range list { + if !strings.HasPrefix(l, s) { + return false + } + } + return true + } + + sl := shortestItem(fnl) + slv := strings.Split(sl, "-") + var result string + for i := len(slv); i >= 0; i-- { + result = strings.Join(slv[:i], "-") + if allHasPrefix(fnl, result) { + return result + } + } + return "" +} + +func contains(s []string, e string) bool { + for _, a := range s { + if a == e { + return true + } + } + return false +} diff --git a/modules/repository/license.go b/modules/repository/license.go index 160ec28f01..dc9584f39f 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -7,6 +7,7 @@ import ( "bufio" "bytes" "context" + "encoding/json" "fmt" "regexp" "strings" @@ -23,27 +24,56 @@ import ( var classifier *licenseclassifier.Classifier func init() { - err := InitClassifier() + cln, err := getConvertLicenseName() + if err != nil { + log.Error("getConvertLicenseName: %v", err) + } + err = initClassifier(cln) if err != nil { log.Error("initClassifier: %v", err) } } -func InitClassifier() error { +func getConvertLicenseName() (map[string]string, error) { + data, err := options.AssetFS().ReadFile("", "convertLicenseName") + if err != nil { + return nil, err + } + var convertLicenseName map[string]string + err = json.Unmarshal([]byte(data), &convertLicenseName) + if err != nil { + return nil, err + } + return convertLicenseName, nil +} +func initClassifier(convertLicenseName map[string]string) error { + // threshold should be 0.84~0.86 or the test will be failed // TODO: add threshold to app.ini - classifier = licenseclassifier.NewClassifier(.9) + classifier = licenseclassifier.NewClassifier(.85) licenseFiles, err := options.AssetFS().ListFiles("license", true) if err != nil { return err } + licenseVariantCount := make(map[string]int) if len(licenseFiles) > 0 { for _, lf := range licenseFiles { data, err := options.License(lf) if err != nil { return err } - classifier.AddContent("License", lf, "license", data) + variant := lf + if convertLicenseName != nil { + v, ok := convertLicenseName[lf] + if ok { + variant = v + } + licenseVariantCount[variant]++ + if licenseVariantCount[variant] > 1 { + continue + } + } + classifier.AddContent("License", lf, variant, data) } } return nil @@ -244,21 +274,10 @@ func detectLicense(buf []byte) []string { } matches := classifier.Match(buf) - licenseVariants := make(map[string][]string, len(matches.Matches)) + var results []string for _, r := range matches.Matches { if r.MatchType == "License" { - tag := fmt.Sprintf("%d-%d", r.StartLine, r.EndLine) - licenseVariants[tag] = append(licenseVariants[tag], r.Name) - } - } - - var results []string - for _, licenses := range licenseVariants { - if len(licenses) == 1 { - results = append(results, licenses[0]) - } else { - // TODO: reslove license detection conflict - results = append(results, licenses...) + results = append(results, r.Variant) } } return results diff --git a/modules/repository/license_test.go b/modules/repository/license_test.go index 753877ec2b..7621d8325f 100644 --- a/modules/repository/license_test.go +++ b/modules/repository/license_test.go @@ -202,6 +202,8 @@ func Test_detectLicense(t *testing.T) { } LoadRepoConfig() + convertLicenseName, err := getConvertLicenseName() + assert.NoError(t, err) for _, licenseName := range Licenses { license, err := getLicense(licenseName, &licenseValues{ Owner: "Gitea", @@ -211,20 +213,28 @@ func Test_detectLicense(t *testing.T) { }) assert.NoError(t, err) + variant := licenseName + if convertLicenseName != nil { + v, ok := convertLicenseName[licenseName] + if ok { + variant = v + } + } tests = append(tests, DetectLicenseTest{ name: fmt.Sprintf("auto single license test: %s", licenseName), arg: license, - want: []string{licenseName}, + want: []string{variant}, }) } tests = append(tests, DetectLicenseTest{ name: fmt.Sprintf("auto multiple license test: %s and %s", tests[2].want[0], tests[3].want[0]), arg: append(tests[2].arg, tests[3].arg...), + // TODO doesn't depend on the order want: []string{"389-exception", "0BSD"}, }) - err := InitClassifier() + err = initClassifier(convertLicenseName) assert.NoError(t, err) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From 3da5a80a9c3e753b46f3b5a7e0e2be6979cb8184 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 14 Jun 2023 02:02:38 +0000 Subject: [PATCH 048/158] generate licenses --- options/convertLicenseName | 1 + options/license/Asterisk-exception | 5 + ...-pages-one-para => Linux-man-pages-1-para} | 0 .../license/Linux-man-pages-copyleft-2-para | 8 ++ options/license/Linux-man-pages-copyleft-var | 16 +++ options/license/OPL-UK-3.0 | 114 ++++++++++++++++++ options/license/dtoa | 14 +++ 7 files changed, 158 insertions(+) create mode 100644 options/convertLicenseName create mode 100644 options/license/Asterisk-exception rename options/license/{Linux-man-pages-one-para => Linux-man-pages-1-para} (100%) create mode 100644 options/license/Linux-man-pages-copyleft-2-para create mode 100644 options/license/Linux-man-pages-copyleft-var create mode 100644 options/license/OPL-UK-3.0 create mode 100644 options/license/dtoa diff --git a/options/convertLicenseName b/options/convertLicenseName new file mode 100644 index 0000000000..fe2cf2d58e --- /dev/null +++ b/options/convertLicenseName @@ -0,0 +1 @@ +{"AGPL-1.0-only":"AGPL-1.0","AGPL-1.0-or-later":"AGPL-1.0","AGPL-3.0-only":"AGPL-3.0","AGPL-3.0-or-later":"AGPL-3.0","CAL-1.0":"CAL-1.0","CAL-1.0-Combined-Work-Exception":"CAL-1.0","GFDL-1.1-invariants-only":"GFDL-1.1","GFDL-1.1-invariants-or-later":"GFDL-1.1","GFDL-1.1-no-invariants-only":"GFDL-1.1","GFDL-1.1-no-invariants-or-later":"GFDL-1.1","GFDL-1.1-only":"GFDL-1.1","GFDL-1.1-or-later":"GFDL-1.1","GFDL-1.2-invariants-only":"GFDL-1.2","GFDL-1.2-invariants-or-later":"GFDL-1.2","GFDL-1.2-no-invariants-only":"GFDL-1.2","GFDL-1.2-no-invariants-or-later":"GFDL-1.2","GFDL-1.2-only":"GFDL-1.2","GFDL-1.2-or-later":"GFDL-1.2","GFDL-1.3-invariants-only":"GFDL-1.3","GFDL-1.3-invariants-or-later":"GFDL-1.3","GFDL-1.3-no-invariants-only":"GFDL-1.3","GFDL-1.3-no-invariants-or-later":"GFDL-1.3","GFDL-1.3-only":"GFDL-1.3","GFDL-1.3-or-later":"GFDL-1.3","GPL-1.0-only":"GPL-1.0","GPL-1.0-or-later":"GPL-1.0","GPL-2.0-only":"GPL-2.0","GPL-2.0-or-later":"GPL-2.0","GPL-3.0-only":"GPL-3.0","GPL-3.0-or-later":"GPL-3.0","LGPL-2.0-only":"LGPL-2.0","LGPL-2.0-or-later":"LGPL-2.0","LGPL-2.1-only":"LGPL-2.1","LGPL-2.1-or-later":"LGPL-2.1","LGPL-3.0-only":"LGPL-3.0","LGPL-3.0-or-later":"LGPL-3.0","MPL-2.0":"MPL-2.0","MPL-2.0-no-copyleft-exception":"MPL-2.0","OFL-1.0":"OFL-1.0","OFL-1.0-RFN":"OFL-1.0","OFL-1.0-no-RFN":"OFL-1.0","OFL-1.1":"OFL-1.1","OFL-1.1-RFN":"OFL-1.1","OFL-1.1-no-RFN":"OFL-1.1"} \ No newline at end of file diff --git a/options/license/Asterisk-exception b/options/license/Asterisk-exception new file mode 100644 index 0000000000..88253f12d3 --- /dev/null +++ b/options/license/Asterisk-exception @@ -0,0 +1,5 @@ +In addition, when this program is distributed with Asterisk in any +form that would qualify as a 'combined work' or as a 'derivative work' +(but not mere aggregation), you can redistribute and/or modify the +combination under the terms of the license provided with that copy +of Asterisk, instead of the license terms granted here. diff --git a/options/license/Linux-man-pages-one-para b/options/license/Linux-man-pages-1-para similarity index 100% rename from options/license/Linux-man-pages-one-para rename to options/license/Linux-man-pages-1-para diff --git a/options/license/Linux-man-pages-copyleft-2-para b/options/license/Linux-man-pages-copyleft-2-para new file mode 100644 index 0000000000..b0871675b3 --- /dev/null +++ b/options/license/Linux-man-pages-copyleft-2-para @@ -0,0 +1,8 @@ +Permission is granted to make and distribute verbatim copies of this +manual provided the copyright notice and this permission notice are +preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. diff --git a/options/license/Linux-man-pages-copyleft-var b/options/license/Linux-man-pages-copyleft-var new file mode 100644 index 0000000000..1742303553 --- /dev/null +++ b/options/license/Linux-man-pages-copyleft-var @@ -0,0 +1,16 @@ +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission +notice are preserved on all copies. + +Permission is granted to copy and distribute modified versions of +this manual under the conditions for verbatim copying, provided +that the entire resulting derived work is distributed under the +terms of a permission notice identical to this one. + +Since the Linux kernel and libraries are constantly changing, this +manual page may be incorrect or out-of-date. The author(s) assume +no responsibility for errors or omissions, or for damages resulting +from the use of the information contained herein. + +Formatted or processed versions of this manual, if unaccompanied by +the source, must acknowledge the copyright and authors of this work. diff --git a/options/license/OPL-UK-3.0 b/options/license/OPL-UK-3.0 new file mode 100644 index 0000000000..ee8ca4dd81 --- /dev/null +++ b/options/license/OPL-UK-3.0 @@ -0,0 +1,114 @@ +United Kingdom Open Parliament Licence v3.0 + +Open Parliament Licence + +You are encouraged to use and re-use the information that +is available under this licence freely and flexibly, with +only a few conditions. Using information under this licence + +Use of copyright and database right material made +available under this licence (the ‘information’) indicates +your acceptance of the terms and conditions below. + +The Licensor grants you a worldwide, royalty-free, +perpetual, non-exclusive licence to use the +information subject to the conditions below. + +This licence does not affect your freedom under +fair dealing or fair use or any other copyright +or database right exceptions and limitations. + +You are free to: + * copy, publish, distribute and transmit the information + * adapt the information + * exploit the information commercially and non-commercially, + for example, by combining it with other information, + or by including it in your own product or application + +You must (where you do any of the above): + * acknowledge the source of the information in your + product or application by including the following + attribution statement and, where possible, provide a + link to this licence: Contains Parliamentary information + licensed under the Open Parliament Licence v3.0. + +These are important conditions of this licence and +if you fail to comply with them the rights granted to +you under this licence, or any similar licence granted +by the Licensor, will end automatically. + +Exemptions + +This licence does not cover the use of: + * personal data in the information; + * information that has neither been published nor disclosed + under information access legislation (including the + Freedom of Information Acts for the UK and Scotland) by or + with the consent of the Licensor; + * the Royal Arms and the Crowned Portcullis; + * third party rights the Licensor is not authorised to license; + * information subject to other intellectual property rights, + including patents, trademarks, and design rights + +Non-endorsment + +This licence does not grant you any right to use the +information in a way that suggests any official status or +that the Licensor endorses you or your use of the Information. + +No warranty + +The information is licensed ‘as is’ and the +Licensor excludes all representations, warranties, +obligations and liabilities in relation to the +information to the maximum extent permitted by law. +The Licensor is not liable for any errors or omissions in +the information and shall not be liable for any loss, injury +or damage of any kind caused by its use. The Licensor does +not guarantee the continued supply of the information. + +Governing law + +This licence is governed by the laws of England and Wales. + +Definitions + +In this licence, the terms below have the following meanings: + +‘Information’ means information protected by copyright +or by database right (for example, literary and +artistic works, content, data and source code) +offered for use under the terms of this licence. + +‘Information Provider’ means either House of Parliament. + +‘Licensor’ means— +(a) in relation to copyright, the Speaker of the House of +Commons and the Clerk of the Parliaments representing +the House of Commons and House of Lords respectively, and +(b) in relation to database right, the Corporate +Officer of the House of Commons and the Corporate +Officer of the House of Lords respectively. + +‘Use’ means doing any act which is restricted by copyright +or database right, whether in the original medium or in any +other medium, and includes without limitation distributing, +copying, adapting and modifying as may be technically +necessary to use it in a different mode or format. + +‘You’ means the natural or legal person, or body of persons +corporate or incorporate, acquiring rights under this licence. + +About the Open Parliament Licence + +This is version 3.0 of the Open Parliament Licence. The +Licensor may, from time to time, issue new versions of the +Open Parliament Licence. However, you may continue to use +information licensed under this version should you wish to do so. + +The information licensed under the Open Parliament +Licence includes Parliamentary information in which +Crown copyright subsists. Further context, best practice +and guidance relating to the re-use of public sector +information can be found in the UK Government Licensing +Framework section on The National Archives website. diff --git a/options/license/dtoa b/options/license/dtoa new file mode 100644 index 0000000000..6de2b084fc --- /dev/null +++ b/options/license/dtoa @@ -0,0 +1,14 @@ +The author of this software is David M. Gay. + +Copyright (c) 1991, 2000, 2001 by Lucent Technologies. + +Permission to use, copy, modify, and distribute this software for any +purpose without fee is hereby granted, provided that this entire notice +is included in all copies of any software which is or includes a copy +or modification of this software and in all copies of the supporting +documentation for such software. + +THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED +WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY +REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY +OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. From 1b0783c464d561c449f1a023bb5c1ce58dcc812f Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 14 Jun 2023 02:42:14 +0000 Subject: [PATCH 049/158] fix conflict --- models/migrations/migrations.go | 4 +- .../{v1_20/v260.go => v1_21/v261.go} | 82 ++++++++++++++----- modules/repository/license.go | 1 + 3 files changed, 64 insertions(+), 23 deletions(-) rename models/migrations/{v1_20/v260.go => v1_21/v261.go} (81%) diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 825585d5de..7934fdc805 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -503,8 +503,8 @@ var migrations = []Migration{ // v260 -> v261 NewMigration("Add label column to action_run table, and combine labels", v1_21.DropCustomLabelsColumnToActRunner), - // v261 -> 262 - NewMigration("Add Repository Licenses", v1_20.AddRepositoryLicenses), + // v261 -> 262 + NewMigration("Add Repository Licenses", v1_21.AddRepositoryLicenses), } // GetCurrentDBVersion returns the current db version diff --git a/models/migrations/v1_20/v260.go b/models/migrations/v1_21/v261.go similarity index 81% rename from models/migrations/v1_20/v260.go rename to models/migrations/v1_21/v261.go index 2565f92cdc..e119b24547 100644 --- a/models/migrations/v1_20/v260.go +++ b/models/migrations/v1_21/v261.go @@ -1,9 +1,10 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_20 //nolint +package v1_21 //nolint import ( + "encoding/json" "fmt" "path" "path/filepath" @@ -22,6 +23,8 @@ import ( licenseclassifier "github.com/google/licenseclassifier/v2" ) +var classifier *licenseclassifier.Classifier + // Copy paste from models/repo.go because we cannot import models package func repoPath(userName, repoName string) string { return filepath.Join(userPath(userName), strings.ToLower(repoName)+".git") @@ -157,50 +160,83 @@ func localizedExtensions(ext, languageCode string) (localizedExts []string) { return []string{lowerLangCode + ext, ext} } +// detectLicenseByEntry returns the licenses detected by the given tree entry func detectLicenseByEntry(file *git.TreeEntry) ([]string, error) { if file == nil { return nil, nil } - // Read license file content blob := file.Blob() contentBuf, err := blob.GetBlobAll() if err != nil { return nil, fmt.Errorf("GetBlobAll: %w", err) } - - // check license return detectLicense(contentBuf), nil } +// detectLicense returns the licenses detected by the given content buff func detectLicense(buf []byte) []string { if len(buf) == 0 { return nil } - - classifier := licenseclassifier.NewClassifier(.9) - licenseFiles, err := options.AssetFS().ListFiles("license", true) - if err != nil { - log.Error("initClassifier: %v", err) + if classifier == nil { + log.Error("detectLicense: license classifier is null.") return nil } - for _, lf := range licenseFiles { - data, err := options.License(lf) - if err != nil { - log.Error("initClassifier: %v", err) - return nil + + matches := classifier.Match(buf) + var results []string + for _, r := range matches.Matches { + if r.MatchType == "License" { + results = append(results, r.Variant) } - classifier.AddContent("License", lf, "license", data) + } + return results +} + +func initClassifier() error { + // threshold should be 0.84~0.86 or the test will be failed + // TODO: add threshold to app.ini + data, err := options.AssetFS().ReadFile("", "convertLicenseName") + if err != nil { + return err + } + var convertLicenseName map[string]string + err = json.Unmarshal([]byte(data), &convertLicenseName) + if err != nil { + return err } - var licenses []string - results := classifier.Match(buf) - for _, r := range results.Matches { - if r.MatchType == "License" { - licenses = append(licenses, r.Name) + // threshold should be 0.84~0.86 or the test will be failed + // TODO: add threshold to app.ini + classifier = licenseclassifier.NewClassifier(.85) + licenseFiles, err := options.AssetFS().ListFiles("license", true) + if err != nil { + return err + } + + licenseVariantCount := make(map[string]int) + if len(licenseFiles) > 0 { + for _, lf := range licenseFiles { + data, err := options.License(lf) + if err != nil { + return err + } + variant := lf + if convertLicenseName != nil { + v, ok := convertLicenseName[lf] + if ok { + variant = v + } + licenseVariantCount[variant]++ + if licenseVariantCount[variant] > 1 { + continue + } + } + classifier.AddContent("License", lf, variant, data) } } - return licenses + return nil } func AddRepositoryLicenses(x *xorm.Engine) error { @@ -228,6 +264,10 @@ func AddRepositoryLicenses(x *xorm.Engine) error { return err } + if err := initClassifier(); err != nil { + return err + } + for _, repo := range repos { gitRepo, err := git.OpenRepository(git.DefaultContext, repoPath(repo.OwnerName, repo.Name)) if err != nil { diff --git a/modules/repository/license.go b/modules/repository/license.go index dc9584f39f..4a68d92deb 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -46,6 +46,7 @@ func getConvertLicenseName() (map[string]string, error) { } return convertLicenseName, nil } + func initClassifier(convertLicenseName map[string]string) error { // threshold should be 0.84~0.86 or the test will be failed // TODO: add threshold to app.ini From 25966eb07892c3a9905a8e3450876c2ad541569d Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 14 Jun 2023 02:53:57 +0000 Subject: [PATCH 050/158] fix lint --- models/migrations/v1_21/v261.go | 2 +- modules/repository/license.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/models/migrations/v1_21/v261.go b/models/migrations/v1_21/v261.go index e119b24547..43bb80634b 100644 --- a/models/migrations/v1_21/v261.go +++ b/models/migrations/v1_21/v261.go @@ -202,7 +202,7 @@ func initClassifier() error { return err } var convertLicenseName map[string]string - err = json.Unmarshal([]byte(data), &convertLicenseName) + err = json.Unmarshal(data, &convertLicenseName) if err != nil { return err } diff --git a/modules/repository/license.go b/modules/repository/license.go index 4a68d92deb..411b76a2fc 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -7,13 +7,13 @@ import ( "bufio" "bytes" "context" - "encoding/json" "fmt" "regexp" "strings" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/options" "code.gitea.io/gitea/modules/util" @@ -40,7 +40,7 @@ func getConvertLicenseName() (map[string]string, error) { return nil, err } var convertLicenseName map[string]string - err = json.Unmarshal([]byte(data), &convertLicenseName) + err = json.Unmarshal(data, &convertLicenseName) if err != nil { return nil, err } From 59198d3c310db0848fe62492b5b3aecd5faea79c Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 14 Jun 2023 04:02:55 +0000 Subject: [PATCH 051/158] fix lint --- models/migrations/v1_21/v261.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/migrations/v1_21/v261.go b/models/migrations/v1_21/v261.go index 43bb80634b..2a45bf0985 100644 --- a/models/migrations/v1_21/v261.go +++ b/models/migrations/v1_21/v261.go @@ -4,7 +4,6 @@ package v1_21 //nolint import ( - "encoding/json" "fmt" "path" "path/filepath" @@ -12,6 +11,7 @@ import ( "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/options" "code.gitea.io/gitea/modules/setting" From 4a838adc5e654c3b01746a0f786350ee4e6652c0 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 14 Jun 2023 04:22:17 +0000 Subject: [PATCH 052/158] allow not existed git repo --- models/migrations/v1_21/v261.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/models/migrations/v1_21/v261.go b/models/migrations/v1_21/v261.go index 2a45bf0985..f202da31f6 100644 --- a/models/migrations/v1_21/v261.go +++ b/models/migrations/v1_21/v261.go @@ -272,7 +272,8 @@ func AddRepositoryLicenses(x *xorm.Engine) error { gitRepo, err := git.OpenRepository(git.DefaultContext, repoPath(repo.OwnerName, repo.Name)) if err != nil { log.Error("Error whilst opening git repo for [%d]%s/%s. Error: %v", repo.ID, repo.OwnerName, repo.Name, err) - return err + // Allow git repo not exist + continue } _, licenseFile, err := findLicenseFile(gitRepo, repo.DefaultBranch) if err != nil { From 866de8ddec9148a78d6dc5c3c1a083f392559ce2 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 14 Jun 2023 08:15:42 +0000 Subject: [PATCH 053/158] make generate-swagger --- templates/swagger/v1_json.tmpl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index e78c077fc3..8fd8dd849c 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -20945,6 +20945,13 @@ "type": "string", "x-go-name": "LanguagesURL" }, + "licenses": { + "type": "array", + "items": { + "type": "string" + }, + "x-go-name": "Licenses" + }, "link": { "type": "string", "x-go-name": "Link" From e46fd139c27dabae566afb8cb7d41273d6b4bd93 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 14 Jun 2023 08:20:25 +0000 Subject: [PATCH 054/158] fix --- models/migrations/migrations.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index dda512a273..821b03f73c 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -502,11 +502,9 @@ var migrations = []Migration{ // Gitea 1.20.0 ends at 260 // v260 -> v261 - NewMigration("Add label column to action_run table, and combine labels", v1_21.DropCustomLabelsColumnToActRunner), - // v261 -> 262 NewMigration("Drop custom_labels column of action_runner table", v1_21.DropCustomLabelsColumnOfActionRunner), - // v262 -> 263 - NewMigration("Add Repository Licenses", v1_21.AddRepositoryLicenses), + // v261 -> 262 + NewMigration("Add Repository Licenses", v1_21.AddRepositoryLicenses), } // GetCurrentDBVersion returns the current db version From c831ee31bf96056163a07342dbbe8bba3f107ac7 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 14 Jun 2023 08:40:27 +0000 Subject: [PATCH 055/158] improve --- build/generate-licenses.go | 26 ++++++++--------- models/migrations/v1_21/v261.go | 36 +++++++++++++---------- modules/repository/create.go | 2 +- modules/repository/license.go | 52 ++++++++++++++++++--------------- 4 files changed, 64 insertions(+), 52 deletions(-) diff --git a/build/generate-licenses.go b/build/generate-licenses.go index 7909f1ee39..8bdf06cfba 100644 --- a/build/generate-licenses.go +++ b/build/generate-licenses.go @@ -80,8 +80,8 @@ func main() { } tr := tar.NewReader(gz) - var pf *os.File - var pfn string + var preFile *os.File + var preLicenseName string sameFiles := make(map[string][]string) for { hdr, err := tr.Next() @@ -102,17 +102,17 @@ func main() { continue } - fbn := filepath.Base(hdr.Name) - ln := strings.TrimSuffix(fbn, ".txt") + fileBaseName := filepath.Base(hdr.Name) + licenseName := strings.TrimSuffix(fileBaseName, ".txt") - if strings.HasPrefix(fbn, "README") { + if strings.HasPrefix(fileBaseName, "README") { continue } - if strings.HasPrefix(fbn, "deprecated_") { + if strings.HasPrefix(fileBaseName, "deprecated_") { continue } - out, err := os.Create(path.Join(destination, ln)) + out, err := os.Create(path.Join(destination, licenseName)) if err != nil { log.Fatalf("Failed to create new file. %s", err) } @@ -126,7 +126,7 @@ func main() { // some license files have same content, so we need to detect these files and create a convert map into a file // In InitClassifier, we will use this convert map to avoid adding same license content with different license name - md5, err := getSameFileMD5(pf, out) + md5, err := getSameFileMD5(preFile, out) if err != nil { log.Fatalf("Failed to get same file md5. %s", err) continue @@ -136,13 +136,13 @@ func main() { if !ok { sameFiles[md5] = make([]string, 0) } - if !contains(sameFiles[md5], pfn) { - sameFiles[md5] = append(sameFiles[md5], pfn) + if !contains(sameFiles[md5], preLicenseName) { + sameFiles[md5] = append(sameFiles[md5], preLicenseName) } - sameFiles[md5] = append(sameFiles[md5], ln) + sameFiles[md5] = append(sameFiles[md5], licenseName) } - pf = out - pfn = ln + preFile = out + preLicenseName = licenseName } } diff --git a/models/migrations/v1_21/v261.go b/models/migrations/v1_21/v261.go index f202da31f6..76c010b819 100644 --- a/models/migrations/v1_21/v261.go +++ b/models/migrations/v1_21/v261.go @@ -24,6 +24,7 @@ import ( ) var classifier *licenseclassifier.Classifier +var convertLicenseNames map[string]string // Copy paste from models/repo.go because we cannot import models package func repoPath(userName, repoName string) string { @@ -194,6 +195,18 @@ func detectLicense(buf []byte) []string { return results } +func ConvertLicenseName(name string) string { + if convertLicenseNames == nil { + return name + } + + v, ok := convertLicenseNames[name] + if ok { + return v + } + return name +} + func initClassifier() error { // threshold should be 0.84~0.86 or the test will be failed // TODO: add threshold to app.ini @@ -201,8 +214,7 @@ func initClassifier() error { if err != nil { return err } - var convertLicenseName map[string]string - err = json.Unmarshal(data, &convertLicenseName) + err = json.Unmarshal(data, &convertLicenseNames) if err != nil { return err } @@ -217,23 +229,17 @@ func initClassifier() error { licenseVariantCount := make(map[string]int) if len(licenseFiles) > 0 { - for _, lf := range licenseFiles { - data, err := options.License(lf) + for _, licenseFile := range licenseFiles { + data, err := options.License(licenseFile) if err != nil { return err } - variant := lf - if convertLicenseName != nil { - v, ok := convertLicenseName[lf] - if ok { - variant = v - } - licenseVariantCount[variant]++ - if licenseVariantCount[variant] > 1 { - continue - } + licenseName := ConvertLicenseName(licenseFile) + licenseVariantCount[licenseName]++ + if licenseVariantCount[licenseName] > 1 { + continue } - classifier.AddContent("License", lf, variant, data) + classifier.AddContent("License", licenseFile, licenseName, data) } } return nil diff --git a/modules/repository/create.go b/modules/repository/create.go index c51cda347e..b1e6e202d9 100644 --- a/modules/repository/create.go +++ b/modules/repository/create.go @@ -196,7 +196,7 @@ func CreateRepository(doer, u *user_model.User, opts CreateRepoOptions) (*repo_m var licenses []string if len(opts.License) > 0 { - licenses = append(licenses, opts.License) + licenses = append(licenses, ConvertLicenseName(opts.License)) } repo := &repo_model.Repository{ OwnerID: u.ID, diff --git a/modules/repository/license.go b/modules/repository/license.go index 411b76a2fc..525152fbb5 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -22,32 +22,44 @@ import ( ) var classifier *licenseclassifier.Classifier +var convertLicenseNames map[string]string func init() { - cln, err := getConvertLicenseName() + err := readConvertLicenseNames() if err != nil { - log.Error("getConvertLicenseName: %v", err) + log.Error("getConvertLicenseNames: %v", err) } - err = initClassifier(cln) + err = initClassifier() if err != nil { log.Error("initClassifier: %v", err) } } -func getConvertLicenseName() (map[string]string, error) { +func readConvertLicenseNames() error { data, err := options.AssetFS().ReadFile("", "convertLicenseName") if err != nil { - return nil, err + return err } - var convertLicenseName map[string]string - err = json.Unmarshal(data, &convertLicenseName) + err = json.Unmarshal(data, &convertLicenseNames) if err != nil { - return nil, err + return err } - return convertLicenseName, nil + return nil } -func initClassifier(convertLicenseName map[string]string) error { +func ConvertLicenseName(name string) string { + if convertLicenseNames == nil { + return name + } + + v, ok := convertLicenseNames[name] + if ok { + return v + } + return name +} + +func initClassifier() error { // threshold should be 0.84~0.86 or the test will be failed // TODO: add threshold to app.ini classifier = licenseclassifier.NewClassifier(.85) @@ -58,23 +70,17 @@ func initClassifier(convertLicenseName map[string]string) error { licenseVariantCount := make(map[string]int) if len(licenseFiles) > 0 { - for _, lf := range licenseFiles { - data, err := options.License(lf) + for _, licenseFile := range licenseFiles { + data, err := options.License(licenseFile) if err != nil { return err } - variant := lf - if convertLicenseName != nil { - v, ok := convertLicenseName[lf] - if ok { - variant = v - } - licenseVariantCount[variant]++ - if licenseVariantCount[variant] > 1 { - continue - } + licenseName := ConvertLicenseName(licenseFile) + licenseVariantCount[licenseName]++ + if licenseVariantCount[licenseName] > 1 { + continue } - classifier.AddContent("License", lf, variant, data) + classifier.AddContent("License", licenseFile, licenseName, data) } } return nil From ae27d02aa899a35ec642708a73aaf09fd006049b Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 14 Jun 2023 08:51:41 +0000 Subject: [PATCH 056/158] remove GetBlobAll --- models/migrations/v1_21/v261.go | 14 +++++++++----- modules/git/blob.go | 11 ----------- modules/repository/license.go | 15 ++++++++++----- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/models/migrations/v1_21/v261.go b/models/migrations/v1_21/v261.go index 76c010b819..e00cf27f3f 100644 --- a/models/migrations/v1_21/v261.go +++ b/models/migrations/v1_21/v261.go @@ -168,16 +168,16 @@ func detectLicenseByEntry(file *git.TreeEntry) ([]string, error) { } blob := file.Blob() - contentBuf, err := blob.GetBlobAll() + content, err := blob.GetBlobContent(setting.UI.MaxDisplayFileSize) if err != nil { return nil, fmt.Errorf("GetBlobAll: %w", err) } - return detectLicense(contentBuf), nil + return detectLicense(content), nil } // detectLicense returns the licenses detected by the given content buff -func detectLicense(buf []byte) []string { - if len(buf) == 0 { +func detectLicense(content string) []string { + if len(content) == 0 { return nil } if classifier == nil { @@ -185,7 +185,11 @@ func detectLicense(buf []byte) []string { return nil } - matches := classifier.Match(buf) + matches, err := classifier.MatchFrom(strings.NewReader(content)) + if err != nil { + log.Error("licenseclassifier.MatchFrom: %v", err) + return nil + } var results []string for _, r := range matches.Matches { if r.MatchType == "License" { diff --git a/modules/git/blob.go b/modules/git/blob.go index 4123f6626f..bcecb42e16 100644 --- a/modules/git/blob.go +++ b/modules/git/blob.go @@ -34,17 +34,6 @@ func (b *Blob) GetBlobContent(limit int64) (string, error) { return string(buf), err } -// GetBlobAll Gets the all content of the blob as bytes -func (b *Blob) GetBlobAll() ([]byte, error) { - dataRc, err := b.DataAsync() - if err != nil { - return nil, err - } - buf, _ := io.ReadAll(dataRc) - _ = dataRc.Close() - return buf, nil -} - // GetBlobLineCount gets line count of the blob func (b *Blob) GetBlobLineCount() (int, error) { reader, err := b.DataAsync() diff --git a/modules/repository/license.go b/modules/repository/license.go index 525152fbb5..46bdc806fb 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/options" + "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" licenseclassifier "github.com/google/licenseclassifier/v2" @@ -263,16 +264,16 @@ func detectLicenseByEntry(file *git.TreeEntry) ([]string, error) { } blob := file.Blob() - contentBuf, err := blob.GetBlobAll() + content, err := blob.GetBlobContent(setting.UI.MaxDisplayFileSize) if err != nil { return nil, fmt.Errorf("GetBlobAll: %w", err) } - return detectLicense(contentBuf), nil + return detectLicense(content), nil } // detectLicense returns the licenses detected by the given content buff -func detectLicense(buf []byte) []string { - if len(buf) == 0 { +func detectLicense(content string) []string { + if len(content) == 0 { return nil } if classifier == nil { @@ -280,7 +281,11 @@ func detectLicense(buf []byte) []string { return nil } - matches := classifier.Match(buf) + matches, err := classifier.MatchFrom(strings.NewReader(content)) + if err != nil { + log.Error("licenseclassifier.MatchFrom: %v", err) + return nil + } var results []string for _, r := range matches.Matches { if r.MatchType == "License" { From a79cb78857bc52b91bc54907dd7b906d3e7aa445 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 15 Jun 2023 00:01:16 +0000 Subject: [PATCH 057/158] fix --- modules/repository/license.go | 6 +++--- modules/repository/license_test.go | 23 ++++++++--------------- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/modules/repository/license.go b/modules/repository/license.go index 46bdc806fb..a268e91a7a 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -26,9 +26,9 @@ var classifier *licenseclassifier.Classifier var convertLicenseNames map[string]string func init() { - err := readConvertLicenseNames() + err := loadConvertLicenseNames() if err != nil { - log.Error("getConvertLicenseNames: %v", err) + log.Error("loadConvertLicenseNames: %v", err) } err = initClassifier() if err != nil { @@ -36,7 +36,7 @@ func init() { } } -func readConvertLicenseNames() error { +func loadConvertLicenseNames() error { data, err := options.AssetFS().ReadFile("", "convertLicenseName") if err != nil { return err diff --git a/modules/repository/license_test.go b/modules/repository/license_test.go index 7621d8325f..ed4956f75c 100644 --- a/modules/repository/license_test.go +++ b/modules/repository/license_test.go @@ -184,25 +184,25 @@ Copyright (C) 2023 by Gitea teabot@gitea.io func Test_detectLicense(t *testing.T) { type DetectLicenseTest struct { name string - arg []byte + arg string want []string } tests := []DetectLicenseTest{ { name: "empty", - arg: []byte(""), + arg: "", want: nil, }, { name: "no detected license", - arg: []byte("Copyright (c) 2023 Gitea"), + arg: "Copyright (c) 2023 Gitea", want: nil, }, } LoadRepoConfig() - convertLicenseName, err := getConvertLicenseName() + err := loadConvertLicenseNames() assert.NoError(t, err) for _, licenseName := range Licenses { license, err := getLicense(licenseName, &licenseValues{ @@ -213,28 +213,21 @@ func Test_detectLicense(t *testing.T) { }) assert.NoError(t, err) - variant := licenseName - if convertLicenseName != nil { - v, ok := convertLicenseName[licenseName] - if ok { - variant = v - } - } tests = append(tests, DetectLicenseTest{ name: fmt.Sprintf("auto single license test: %s", licenseName), - arg: license, - want: []string{variant}, + arg: string(license), + want: []string{ConvertLicenseName(licenseName)}, }) } tests = append(tests, DetectLicenseTest{ name: fmt.Sprintf("auto multiple license test: %s and %s", tests[2].want[0], tests[3].want[0]), - arg: append(tests[2].arg, tests[3].arg...), + arg: tests[2].arg + tests[3].arg, // TODO doesn't depend on the order want: []string{"389-exception", "0BSD"}, }) - err = initClassifier(convertLicenseName) + err = initClassifier() assert.NoError(t, err) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From c6cc8b4c8f71aeed7a613f87b9825f54ef2929a2 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 15 Jun 2023 00:52:57 +0000 Subject: [PATCH 058/158] fix lint --- models/migrations/v1_21/v261.go | 6 ++++-- modules/repository/license.go | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/models/migrations/v1_21/v261.go b/models/migrations/v1_21/v261.go index e00cf27f3f..afcc98cf86 100644 --- a/models/migrations/v1_21/v261.go +++ b/models/migrations/v1_21/v261.go @@ -23,8 +23,10 @@ import ( licenseclassifier "github.com/google/licenseclassifier/v2" ) -var classifier *licenseclassifier.Classifier -var convertLicenseNames map[string]string +var ( + classifier *licenseclassifier.Classifier + convertLicenseNames map[string]string +) // Copy paste from models/repo.go because we cannot import models package func repoPath(userName, repoName string) string { diff --git a/modules/repository/license.go b/modules/repository/license.go index a268e91a7a..04f1f738ea 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -22,8 +22,10 @@ import ( licenseclassifier "github.com/google/licenseclassifier/v2" ) -var classifier *licenseclassifier.Classifier -var convertLicenseNames map[string]string +var ( + classifier *licenseclassifier.Classifier + convertLicenseNames map[string]string +) func init() { err := loadConvertLicenseNames() From ea2c0bede20b0399b5cc50ae2c207c3b8aab5ea9 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 15 Jun 2023 01:13:44 +0000 Subject: [PATCH 059/158] convert name remove todo: add threshold to app.ini --- build/generate-licenses.go | 24 +++++++++---------- models/migrations/v1_21/v261.go | 21 +++++++--------- modules/repository/license.go | 25 ++++++++++---------- modules/repository/license_test.go | 2 +- options/{convertLicenseName => sameLicenses} | 0 5 files changed, 34 insertions(+), 38 deletions(-) rename options/{convertLicenseName => sameLicenses} (100%) diff --git a/build/generate-licenses.go b/build/generate-licenses.go index 8bdf06cfba..e336545ab9 100644 --- a/build/generate-licenses.go +++ b/build/generate-licenses.go @@ -23,14 +23,16 @@ import ( func main() { var ( - prefix = "gitea-licenses" - url = "https://api.github.com/repos/spdx/license-list-data/tarball" - githubApiToken = "" - githubUsername = "" - destination = "" + prefix = "gitea-licenses" + url = "https://api.github.com/repos/spdx/license-list-data/tarball" + githubApiToken = "" + githubUsername = "" + destination = "" + sameLicensesDestination = "" ) flag.StringVar(&destination, "dest", "options/license/", "destination for the licenses") + flag.StringVar(&sameLicensesDestination, "samelicensesdest", "options/sameLicenses", "destination for same license json") flag.StringVar(&githubUsername, "username", "", "github username") flag.StringVar(&githubApiToken, "token", "", "github api token") flag.Parse() @@ -147,29 +149,27 @@ func main() { } // generate convert license name map - convertLicenseName := make(map[string]string) + sameLicenses := make(map[string]string) for _, fileNames := range sameFiles { key := getLicenseKey(fileNames) for _, fileName := range fileNames { - convertLicenseName[fileName] = key + sameLicenses[fileName] = key } } // save convert license name map to file - bytes, err := json.Marshal(convertLicenseName) + bytes, err := json.Marshal(sameLicenses) if err != nil { log.Fatalf("Failed to create json bytes. %s", err) return } - // TODO change the path - path := "options/convertLicenseName" - out, err := os.Create(path) + out, err := os.Create(sameLicensesDestination) if err != nil { log.Fatalf("Failed to create new file. %s", err) } defer out.Close() _, err = out.Write(bytes) if err != nil { - log.Fatalf("Failed to write %s. %s", path, err) + log.Fatalf("Failed to write same licenses json file. %s", err) } fmt.Println("Done") diff --git a/models/migrations/v1_21/v261.go b/models/migrations/v1_21/v261.go index afcc98cf86..a2d5c4b886 100644 --- a/models/migrations/v1_21/v261.go +++ b/models/migrations/v1_21/v261.go @@ -24,8 +24,8 @@ import ( ) var ( - classifier *licenseclassifier.Classifier - convertLicenseNames map[string]string + classifier *licenseclassifier.Classifier + sameLicenses map[string]string ) // Copy paste from models/repo.go because we cannot import models package @@ -202,11 +202,11 @@ func detectLicense(content string) []string { } func ConvertLicenseName(name string) string { - if convertLicenseNames == nil { + if sameLicenses == nil { return name } - v, ok := convertLicenseNames[name] + v, ok := sameLicenses[name] if ok { return v } @@ -214,26 +214,23 @@ func ConvertLicenseName(name string) string { } func initClassifier() error { - // threshold should be 0.84~0.86 or the test will be failed - // TODO: add threshold to app.ini - data, err := options.AssetFS().ReadFile("", "convertLicenseName") + data, err := options.AssetFS().ReadFile("", "sameLicenses") if err != nil { return err } - err = json.Unmarshal(data, &convertLicenseNames) + err = json.Unmarshal(data, &sameLicenses) if err != nil { return err } // threshold should be 0.84~0.86 or the test will be failed - // TODO: add threshold to app.ini classifier = licenseclassifier.NewClassifier(.85) licenseFiles, err := options.AssetFS().ListFiles("license", true) if err != nil { return err } - licenseVariantCount := make(map[string]int) + licenseNameCount := make(map[string]int) if len(licenseFiles) > 0 { for _, licenseFile := range licenseFiles { data, err := options.License(licenseFile) @@ -241,8 +238,8 @@ func initClassifier() error { return err } licenseName := ConvertLicenseName(licenseFile) - licenseVariantCount[licenseName]++ - if licenseVariantCount[licenseName] > 1 { + licenseNameCount[licenseName]++ + if licenseNameCount[licenseName] > 1 { continue } classifier.AddContent("License", licenseFile, licenseName, data) diff --git a/modules/repository/license.go b/modules/repository/license.go index 04f1f738ea..eab9f42c81 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -23,14 +23,14 @@ import ( ) var ( - classifier *licenseclassifier.Classifier - convertLicenseNames map[string]string + classifier *licenseclassifier.Classifier + sameLicenses map[string]string ) func init() { - err := loadConvertLicenseNames() + err := loadSameLicenses() if err != nil { - log.Error("loadConvertLicenseNames: %v", err) + log.Error("loadSameLicenses: %v", err) } err = initClassifier() if err != nil { @@ -38,12 +38,12 @@ func init() { } } -func loadConvertLicenseNames() error { - data, err := options.AssetFS().ReadFile("", "convertLicenseName") +func loadSameLicenses() error { + data, err := options.AssetFS().ReadFile("", "sameLicenses") if err != nil { return err } - err = json.Unmarshal(data, &convertLicenseNames) + err = json.Unmarshal(data, &sameLicenses) if err != nil { return err } @@ -51,11 +51,11 @@ func loadConvertLicenseNames() error { } func ConvertLicenseName(name string) string { - if convertLicenseNames == nil { + if sameLicenses == nil { return name } - v, ok := convertLicenseNames[name] + v, ok := sameLicenses[name] if ok { return v } @@ -64,14 +64,13 @@ func ConvertLicenseName(name string) string { func initClassifier() error { // threshold should be 0.84~0.86 or the test will be failed - // TODO: add threshold to app.ini classifier = licenseclassifier.NewClassifier(.85) licenseFiles, err := options.AssetFS().ListFiles("license", true) if err != nil { return err } - licenseVariantCount := make(map[string]int) + licenseNameCount := make(map[string]int) if len(licenseFiles) > 0 { for _, licenseFile := range licenseFiles { data, err := options.License(licenseFile) @@ -79,8 +78,8 @@ func initClassifier() error { return err } licenseName := ConvertLicenseName(licenseFile) - licenseVariantCount[licenseName]++ - if licenseVariantCount[licenseName] > 1 { + licenseNameCount[licenseName]++ + if licenseNameCount[licenseName] > 1 { continue } classifier.AddContent("License", licenseFile, licenseName, data) diff --git a/modules/repository/license_test.go b/modules/repository/license_test.go index ed4956f75c..efa79dd0b5 100644 --- a/modules/repository/license_test.go +++ b/modules/repository/license_test.go @@ -202,7 +202,7 @@ func Test_detectLicense(t *testing.T) { } LoadRepoConfig() - err := loadConvertLicenseNames() + err := loadSameLicenses() assert.NoError(t, err) for _, licenseName := range Licenses { license, err := getLicense(licenseName, &licenseValues{ diff --git a/options/convertLicenseName b/options/sameLicenses similarity index 100% rename from options/convertLicenseName rename to options/sameLicenses From d1932766168603435d3c02dba494adde0472bf24 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 15 Jun 2023 01:15:37 +0000 Subject: [PATCH 060/158] fix lint --- build/generate-licenses.go | 2 +- models/migrations/v1_21/v261.go | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/build/generate-licenses.go b/build/generate-licenses.go index e336545ab9..a4c979a195 100644 --- a/build/generate-licenses.go +++ b/build/generate-licenses.go @@ -196,7 +196,7 @@ func getSameFileMD5(f1, f2 *os.File) (string, error) { } // check content - var chunkSize = 1024 + chunkSize := 1024 _, err = f1.Seek(0, 0) if err != nil { return "", err diff --git a/models/migrations/v1_21/v261.go b/models/migrations/v1_21/v261.go index a2d5c4b886..bab657221a 100644 --- a/models/migrations/v1_21/v261.go +++ b/models/migrations/v1_21/v261.go @@ -17,10 +17,9 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" + licenseclassifier "github.com/google/licenseclassifier/v2" "xorm.io/builder" "xorm.io/xorm" - - licenseclassifier "github.com/google/licenseclassifier/v2" ) var ( From e67a77154ca42b092096dae675e8bd5538da3443 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 19 Jun 2023 02:21:57 +0000 Subject: [PATCH 061/158] improve test --- modules/repository/license_test.go | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/modules/repository/license_test.go b/modules/repository/license_test.go index efa79dd0b5..4106c50268 100644 --- a/modules/repository/license_test.go +++ b/modules/repository/license_test.go @@ -214,24 +214,25 @@ func Test_detectLicense(t *testing.T) { assert.NoError(t, err) tests = append(tests, DetectLicenseTest{ - name: fmt.Sprintf("auto single license test: %s", licenseName), + name: fmt.Sprintf("single license test: %s", licenseName), arg: string(license), want: []string{ConvertLicenseName(licenseName)}, }) } - tests = append(tests, DetectLicenseTest{ - name: fmt.Sprintf("auto multiple license test: %s and %s", tests[2].want[0], tests[3].want[0]), - arg: tests[2].arg + tests[3].arg, - // TODO doesn't depend on the order - want: []string{"389-exception", "0BSD"}, - }) - err = initClassifier() assert.NoError(t, err) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - assert.Equalf(t, tt.want, detectLicense(tt.arg), "") + assert.Equal(t, tt.want, detectLicense(tt.arg)) }) } + + result := detectLicense(tests[2].arg + tests[3].arg + tests[4].arg) + t.Run("multiple licenses test", func(t *testing.T) { + assert.Equal(t, 3, len(result)) + assert.Contains(t, result, tests[2].want[0]) + assert.Contains(t, result, tests[3].want[0]) + assert.Contains(t, result, tests[4].want[0]) + }) } From 6f2529435dad43359a087f4315a1fe6409b949dd Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 19 Jun 2023 06:11:52 +0000 Subject: [PATCH 062/158] convert license col into table --- models/migrations/v1_21/v261.go | 86 ++++++++++---- models/repo/license.go | 117 +++++++++++++++++++ models/repo/repo.go | 2 - modules/context/repo.go | 8 +- modules/repository/create.go | 25 +++- modules/repository/license.go | 51 ++++---- modules/repository/repo.go | 12 +- routers/private/default_branch.go | 2 +- routers/private/hook_post_receive.go | 2 +- routers/web/repo/branch.go | 2 +- routers/web/repo/commit.go | 6 +- routers/web/repo/setting_protected_branch.go | 2 +- routers/web/repo/view.go | 2 +- services/convert/repository.go | 7 +- services/mirror/mirror_pull.go | 2 +- services/repository/fork.go | 4 +- 16 files changed, 255 insertions(+), 75 deletions(-) create mode 100644 models/repo/license.go diff --git a/models/migrations/v1_21/v261.go b/models/migrations/v1_21/v261.go index bab657221a..b081801341 100644 --- a/models/migrations/v1_21/v261.go +++ b/models/migrations/v1_21/v261.go @@ -15,10 +15,10 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/options" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" licenseclassifier "github.com/google/licenseclassifier/v2" - "xorm.io/builder" "xorm.io/xorm" ) @@ -37,21 +37,10 @@ func userPath(userName string) string { } // Copy paste from modules/repository/file.go because we cannot import models package -func findLicenseFile(gitRepo *git.Repository, branchName string) (string, *git.TreeEntry, error) { - if branchName == "" { +func findLicenseFile(commit *git.Commit) (string, *git.TreeEntry, error) { + if commit == nil { return "", nil, nil } - if gitRepo == nil { - return "", nil, nil - } - - commit, err := gitRepo.GetBranchCommit(branchName) - if err != nil { - if git.IsErrNotExist(err) { - return "", nil, nil - } - return "", nil, fmt.Errorf("GetBranchCommit: %w", err) - } entries, err := commit.ListEntries() if err != nil { return "", nil, fmt.Errorf("ListEntries: %w", err) @@ -253,10 +242,18 @@ func AddRepositoryLicenses(x *xorm.Engine) error { OwnerName string Name string `xorm:"INDEX NOT NULL"` DefaultBranch string - Licenses []string `xorm:"TEXT JSON"` } - if err := x.Sync(new(Repository)); err != nil { + type RepoLicense struct { + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"` + CommitID string + License string `xorm:"VARCHAR(50) UNIQUE(s) INDEX NOT NULL"` + CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED"` + UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` + } + + if err := x.Sync(new(RepoLicense)); err != nil { return err } @@ -268,7 +265,7 @@ func AddRepositoryLicenses(x *xorm.Engine) error { } repos := make([]*Repository, 0) - if err := sess.Where(builder.IsNull{"licenses"}).Find(&repos); err != nil { + if err := sess.Find(&repos); err != nil { return err } @@ -283,20 +280,67 @@ func AddRepositoryLicenses(x *xorm.Engine) error { // Allow git repo not exist continue } - _, licenseFile, err := findLicenseFile(gitRepo, repo.DefaultBranch) + commit, err := gitRepo.GetBranchCommit(repo.DefaultBranch) + if err != nil { + if git.IsErrNotExist(err) { + continue + } + log.Error("Error whilst getting default branch commit in [%d]%s/%s. Error: %v", repo.ID, repo.OwnerName, repo.Name, err) + return err + } + _, licenseFile, err := findLicenseFile(commit) if err != nil { log.Error("Error whilst finding license file in [%d]%s/%s. Error: %v", repo.ID, repo.OwnerName, repo.Name, err) return err } - repo.Licenses, err = detectLicenseByEntry(licenseFile) + licenses, err := detectLicenseByEntry(licenseFile) if err != nil { log.Error("Error whilst detecting license from %s in [%d]%s/%s. Error: %v", licenseFile.Name(), repo.ID, repo.OwnerName, repo.Name, err) return err } - if _, err := sess.ID(repo.ID).Cols("licenses").NoAutoTime().Update(repo); err != nil { - log.Error("Error whilst updating [%d]%s/%s licenses column. Error: %v", repo.ID, repo.OwnerName, repo.Name, err) + + oldLicenses := make([]RepoLicense, 0) + if err := sess.Where("`repo_id` = ?", repo.ID).Asc("`license`").Find(&oldLicenses); err != nil { return err } + + for _, license := range licenses { + upd := false + for _, o := range oldLicenses { + // Update already existing license + if o.License == license { + if _, err := sess.ID(o.ID).Cols("`commit_id`").Update(o); err != nil { + log.Error("Error whilst updating [%d]%s/%s license [%s]. Error: %v", repo.ID, repo.OwnerName, repo.Name, license, err) + return err + } + upd = true + break + } + } + // Insert new license + if !upd { + if _, err := sess.Insert(&RepoLicense{ + RepoID: repo.ID, + CommitID: commit.ID.String(), + License: license, + }); err != nil { + log.Error("Error whilst inserting [%d]%s/%s license [%s]. Error: %v", repo.ID, repo.OwnerName, repo.Name, license, err) + return err + } + } + } + // Delete old languages + licenseToDelete := make([]int64, 0, len(oldLicenses)) + for _, o := range oldLicenses { + if o.CommitID != commit.ID.String() { + licenseToDelete = append(licenseToDelete, o.ID) + } + } + if len(licenseToDelete) > 0 { + if _, err := sess.In("`id`", licenseToDelete).Delete(&RepoLicense{}); err != nil { + return err + } + } } return sess.Commit() } diff --git a/models/repo/license.go b/models/repo/license.go new file mode 100644 index 0000000000..5a624bbfa8 --- /dev/null +++ b/models/repo/license.go @@ -0,0 +1,117 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package repo + +import ( + "context" + + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/timeutil" +) + +func init() { + db.RegisterModel(new(RepoLicense)) +} + +type RepoLicense struct { + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"` + CommitID string + License string `xorm:"VARCHAR(50) UNIQUE(s) INDEX NOT NULL"` + CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED"` + UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` +} + +// LanguageStatList defines a list of language statistics +type RepoLicenseList []*RepoLicense + +func (rll RepoLicenseList) StringList() []string { + var licenses []string + for _, rl := range rll { + licenses = append(licenses, rl.License) + } + return licenses +} + +// GetRepoLicenses returns the license statistics for a repository +func GetRepoLicenses(ctx context.Context, repo *Repository) (RepoLicenseList, error) { + licenses := make(RepoLicenseList, 0) + if err := db.GetEngine(ctx).Where("`repo_id` = ?", repo.ID).Asc("`license`").Find(&licenses); err != nil { + return nil, err + } + return licenses, nil +} + +// UpdateRepoLicenses updates the license statistics for repository +func UpdateRepoLicenses(ctx context.Context, repo *Repository, commitID string, licenses []string) error { + oldLicenses, err := GetRepoLicenses(ctx, repo) + if err != nil { + return err + } + for _, license := range licenses { + upd := false + for _, o := range oldLicenses { + // Update already existing license + if o.License == license { + if _, err := db.GetEngine(ctx).ID(o.ID).Cols("`commit_id`").Update(o); err != nil { + return err + } + upd = true + break + } + } + // Insert new license + if !upd { + if err := db.Insert(ctx, &RepoLicense{ + RepoID: repo.ID, + CommitID: commitID, + License: license, + }); err != nil { + return err + } + } + } + // Delete old languages + licenseToDelete := make([]int64, 0, len(oldLicenses)) + for _, o := range oldLicenses { + if o.CommitID != commitID { + licenseToDelete = append(licenseToDelete, o.ID) + } + } + if len(licenseToDelete) > 0 { + if _, err := db.GetEngine(ctx).In("`id`", licenseToDelete).Delete(&RepoLicense{}); err != nil { + return err + } + } + + return nil +} + +// CopyLicense Copy originalRepo license information to destRepo (use for forked repo) +func CopyLicense(originalRepo, destRepo *Repository) error { + ctx, committer, err := db.TxContext(db.DefaultContext) + if err != nil { + return err + } + defer committer.Close() + + repoLicenses, err := GetRepoLicenses(ctx, originalRepo) + if err != nil { + return err + } + if len(repoLicenses) > 0 { + time := timeutil.TimeStampNow() + for i := range repoLicenses { + repoLicenses[i].ID = 0 + repoLicenses[i].RepoID = destRepo.ID + // TODO: convert commitID? + repoLicenses[i].CreatedUnix = time + repoLicenses[i].UpdatedUnix = time + } + if err := db.Insert(ctx, &repoLicenses); err != nil { + return err + } + } + return committer.Commit() +} diff --git a/models/repo/repo.go b/models/repo/repo.go index 629c1b177c..d3e6daa95b 100644 --- a/models/repo/repo.go +++ b/models/repo/repo.go @@ -157,8 +157,6 @@ type Repository struct { Units []*RepoUnit `xorm:"-"` PrimaryLanguage *LanguageStat `xorm:"-"` - Licenses []string `xorm:"TEXT JSON"` - IsFork bool `xorm:"INDEX NOT NULL DEFAULT false"` ForkID int64 `xorm:"INDEX"` BaseRepo *Repository `xorm:"-"` diff --git a/modules/context/repo.go b/modules/context/repo.go index bdbd99c42c..8dce002b8d 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -399,7 +399,13 @@ func repoAssignment(ctx *Context, repo *repo_model.Repository) { ctx.Data["PushMirrors"] = pushMirrors ctx.Data["RepoName"] = ctx.Repo.Repository.Name ctx.Data["IsEmptyRepo"] = ctx.Repo.Repository.IsEmpty - ctx.Data["Licenses"] = ctx.Repo.Repository.Licenses + + repoLicenses, err := repo_model.GetRepoLicenses(ctx, ctx.Repo.Repository) + if err != nil { + ctx.ServerError("GetRepoLicenses", err) + return + } + ctx.Data["Licenses"] = repoLicenses.StringList() } // RepoIDAssignment returns a handler which assigns the repo to the context. diff --git a/modules/repository/create.go b/modules/repository/create.go index b1e6e202d9..95ab1ea2a3 100644 --- a/modules/repository/create.go +++ b/modules/repository/create.go @@ -194,10 +194,6 @@ func CreateRepository(doer, u *user_model.User, opts CreateRepoOptions) (*repo_m } } - var licenses []string - if len(opts.License) > 0 { - licenses = append(licenses, ConvertLicenseName(opts.License)) - } repo := &repo_model.Repository{ OwnerID: u.ID, Owner: u, @@ -216,7 +212,6 @@ func CreateRepository(doer, u *user_model.User, opts CreateRepoOptions) (*repo_m TrustModel: opts.TrustModel, IsMirror: opts.IsMirror, DefaultBranch: opts.DefaultBranch, - Licenses: licenses, } var rollbackRepo *repo_model.Repository @@ -282,6 +277,26 @@ func CreateRepository(doer, u *user_model.User, opts CreateRepoOptions) (*repo_m rollbackRepo.OwnerID = u.ID return fmt.Errorf("CreateRepository(git update-server-info): %w", err) } + + // update licenses + var licenses []string + if len(opts.License) > 0 { + licenses = append(licenses, ConvertLicenseName(opts.License)) + + // TODO git command? + gitRepo, err := git.OpenRepository(ctx, repo.RepoPath()) + if err != nil { + return fmt.Errorf("OpenRepository: %w", err) + } + commitID, err := gitRepo.GetBranchCommitID(repo.DefaultBranch) + if err != nil { + return err + } + if err := repo_model.UpdateRepoLicenses(ctx, repo, commitID, licenses); err != nil { + return err + } + } + return nil }); err != nil { if rollbackRepo != nil { diff --git a/modules/repository/license.go b/modules/repository/license.go index eab9f42c81..5790319d85 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -188,7 +188,7 @@ func getLicensePlaceholder(name string) *licensePlaceholder { } // UpdateRepoLicenses will update repository licenses col if license file exists -func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository) error { +func UpdateRepoLicensesByGitRepo(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository) error { if gitRepo == nil { var err error gitRepo, err = git.OpenRepository(ctx, repo.RepoPath()) @@ -196,15 +196,28 @@ func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository, gitRep return fmt.Errorf("OpenRepository: %w", err) } } + commit, err := gitRepo.GetBranchCommit(repo.DefaultBranch) + if err != nil { + return err + } + return UpdateRepoLicenses(ctx, repo, commit) +} - _, licenseFile, err := findLicenseFile(gitRepo, repo.DefaultBranch) +// UpdateRepoLicenses will update repository licenses col if license file exists +func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository, commit *git.Commit) error { + if commit == nil { + return nil + } + + _, licenseFile, err := findLicenseFile(commit) if err != nil { return fmt.Errorf("findLicenseFile: %w", err) } - if repo.Licenses, err = detectLicenseByEntry(licenseFile); err != nil { + licenses, err := detectLicenseByEntry(licenseFile) + if err != nil { return fmt.Errorf("checkLicenseFile: %w", err) } - if err := repo_model.UpdateRepositoryCols(ctx, repo, "licenses"); err != nil { + if err := repo_model.UpdateRepoLicenses(ctx, repo, commit.ID.String(), licenses); err != nil { return fmt.Errorf("UpdateRepositoryCols: %v", err) } @@ -212,23 +225,14 @@ func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository, gitRep } // GetLicenseFileName returns license file name in the repository if it exists -func GetLicenseFileName(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository) (string, error) { - if repo.DefaultBranch == "" { +func GetLicenseFileName(ctx context.Context, repo *repo_model.Repository, commit *git.Commit) (string, error) { + if commit == nil { return "", nil } - if gitRepo == nil { - var err error - gitRepo, err = git.OpenRepository(ctx, repo.RepoPath()) - if err != nil { - return "", fmt.Errorf("OpenRepository: %w", err) - } - } - - _, licenseFile, err := findLicenseFile(gitRepo, repo.DefaultBranch) + _, licenseFile, err := findLicenseFile(commit) if err != nil { return "", fmt.Errorf("findLicenseFile: %w", err) } - if licenseFile != nil { return licenseFile.Name(), nil } @@ -236,21 +240,10 @@ func GetLicenseFileName(ctx context.Context, repo *repo_model.Repository, gitRep } // findLicenseFile returns the entry of license file in the repository if it exists -func findLicenseFile(gitRepo *git.Repository, branchName string) (string, *git.TreeEntry, error) { - if branchName == "" { +func findLicenseFile(commit *git.Commit) (string, *git.TreeEntry, error) { + if commit == nil { return "", nil, nil } - if gitRepo == nil { - return "", nil, nil - } - - commit, err := gitRepo.GetBranchCommit(branchName) - if err != nil { - if git.IsErrNotExist(err) { - return "", nil, nil - } - return "", nil, fmt.Errorf("GetBranchCommit: %w", err) - } entries, err := commit.ListEntries() if err != nil { return "", nil, fmt.Errorf("ListEntries: %w", err) diff --git a/modules/repository/repo.go b/modules/repository/repo.go index f8dfac0187..9d125845ad 100644 --- a/modules/repository/repo.go +++ b/modules/repository/repo.go @@ -134,12 +134,6 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User, } defer gitRepo.Close() - // Update repo license - err = UpdateRepoLicenses(ctx, repo, gitRepo) - if err != nil { - return repo, fmt.Errorf("UpdateRepoLicenses: %w", err) - } - repo.IsEmpty, err = gitRepo.IsEmpty() if err != nil { return repo, fmt.Errorf("git.IsEmpty: %w", err) @@ -173,6 +167,12 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User, log.Error("Failed to store missing LFS objects for repository: %v", err) } } + + // Update repo license + err = UpdateRepoLicensesByGitRepo(ctx, repo, gitRepo) + if err != nil { + return repo, fmt.Errorf("UpdateRepoLicensesByGitRepo: %w", err) + } } ctx, committer, err := db.TxContext(db.DefaultContext) diff --git a/routers/private/default_branch.go b/routers/private/default_branch.go index b06ef5e1b7..4525673e33 100644 --- a/routers/private/default_branch.go +++ b/routers/private/default_branch.go @@ -37,7 +37,7 @@ func SetDefaultBranch(ctx *gitea_context.PrivateContext) { return } - if err := repo_module.UpdateRepoLicenses(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo); err != nil { + if err := repo_module.UpdateRepoLicenses(ctx, ctx.Repo.Repository, ctx.Repo.Commit); err != nil { ctx.JSON(http.StatusInternalServerError, private.Response{ Err: fmt.Sprintf("Unable to set default branch on repository: %s/%s Error: %v", ownerName, repoName, err), }) diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go index 7d38d07739..88a214a340 100644 --- a/routers/private/hook_post_receive.go +++ b/routers/private/hook_post_receive.go @@ -196,7 +196,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { branch := refFullName.BranchName() if branch == baseRepo.DefaultBranch { - err := repo_module.UpdateRepoLicenses(ctx, repo, nil) + err := repo_module.UpdateRepoLicensesByGitRepo(ctx, repo, nil) if err != nil { ctx.JSON(http.StatusInternalServerError, private.Response{Err: err.Error()}) } diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go index 23e0233114..da7aa84fbb 100644 --- a/routers/web/repo/branch.go +++ b/routers/web/repo/branch.go @@ -80,7 +80,7 @@ func Branches(ctx *context.Context) { ctx.Data["Page"] = pager var err error - ctx.Data["LicenseFileName"], err = repo_module.GetLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo) + ctx.Data["LicenseFileName"], err = repo_module.GetLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.Commit) if err != nil { ctx.ServerError("GetLicenseFileName", err) return diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index 1974abd7ab..f10a4f193a 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -86,7 +86,7 @@ func Commits(ctx *context.Context) { pager := context.NewPagination(int(commitsCount), pageSize, page, 5) pager.SetDefaultParams(ctx) ctx.Data["Page"] = pager - ctx.Data["LicenseFileName"], err = repo_module.GetLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo) + ctx.Data["LicenseFileName"], err = repo_module.GetLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.Commit) if err != nil { ctx.ServerError("GetLicenseFileName", err) return @@ -208,7 +208,7 @@ func SearchCommits(ctx *context.Context) { ctx.Data["Username"] = ctx.Repo.Owner.Name ctx.Data["Reponame"] = ctx.Repo.Repository.Name ctx.Data["RefName"] = ctx.Repo.RefName - ctx.Data["LicenseFileName"], err = repo_module.GetLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo) + ctx.Data["LicenseFileName"], err = repo_module.GetLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.Commit) if err != nil { ctx.ServerError("GetLicenseFileName", err) return @@ -262,7 +262,7 @@ func FileHistory(ctx *context.Context) { pager.SetDefaultParams(ctx) ctx.Data["Page"] = pager - ctx.Data["LicenseFileName"], err = repo_module.GetLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo) + ctx.Data["LicenseFileName"], err = repo_module.GetLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.Commit) if err != nil { ctx.ServerError("GetLicenseFileName", err) return diff --git a/routers/web/repo/setting_protected_branch.go b/routers/web/repo/setting_protected_branch.go index 86135afbf5..2463c887b2 100644 --- a/routers/web/repo/setting_protected_branch.go +++ b/routers/web/repo/setting_protected_branch.go @@ -78,7 +78,7 @@ func SetDefaultBranchPost(ctx *context.Context) { ctx.ServerError("UpdateDefaultBranch", err) return } - if err := repo_module.UpdateRepoLicenses(ctx, repo, ctx.Repo.GitRepo); err != nil { + if err := repo_module.UpdateRepoLicenses(ctx, repo, ctx.Repo.Commit); err != nil { ctx.ServerError("UpdateRepoLicenses", err) return } diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index 4b3c9de7a9..2243e201a4 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -878,7 +878,7 @@ func renderCode(ctx *context.Context) { ctx.Data["TreeLink"] = treeLink ctx.Data["TreeNames"] = treeNames ctx.Data["BranchLink"] = branchLink - ctx.Data["LicenseFileName"], err = repo_module.GetLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo) + ctx.Data["LicenseFileName"], err = repo_module.GetLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.Commit) if err != nil { ctx.ServerError("GetLicenseFileName", err) return diff --git a/services/convert/repository.go b/services/convert/repository.go index 4cafd7d525..45d9bc20ea 100644 --- a/services/convert/repository.go +++ b/services/convert/repository.go @@ -150,6 +150,11 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, mode perm.Acc language = repo.PrimaryLanguage.Language } + repoLicenses, err := repo_model.GetRepoLicenses(ctx, repo) + if err != nil { + return nil + } + repoAPIURL := repo.APIURL() return &api.Repository{ @@ -208,7 +213,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, mode perm.Acc MirrorInterval: mirrorInterval, MirrorUpdated: mirrorUpdated, RepoTransfer: transfer, - Licenses: repo.Licenses, + Licenses: repoLicenses.StringList(), } } diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go index 12a3b461ee..ea0d2d53d9 100644 --- a/services/mirror/mirror_pull.go +++ b/services/mirror/mirror_pull.go @@ -541,7 +541,7 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { } // Update License - if err = repo_module.UpdateRepoLicenses(ctx, m.Repo, gitRepo); err != nil { + if err = repo_module.UpdateRepoLicensesByGitRepo(ctx, m.Repo, gitRepo); err != nil { log.Error("SyncMirrors [repo: %-v]: unable to update repository 'licenses': %v", m.Repo, err) return false } diff --git a/services/repository/fork.go b/services/repository/fork.go index ba26ef4211..9275d70f45 100644 --- a/services/repository/fork.go +++ b/services/repository/fork.go @@ -82,7 +82,6 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork IsEmpty: opts.BaseRepo.IsEmpty, IsFork: true, ForkID: opts.BaseRepo.ID, - Licenses: opts.BaseRepo.Licenses, } oldRepoPath := opts.BaseRepo.RepoPath() @@ -173,6 +172,9 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork if err := repo_model.CopyLanguageStat(opts.BaseRepo, repo); err != nil { log.Error("Copy language stat from oldRepo failed: %v", err) } + if err := repo_model.CopyLicense(opts.BaseRepo, repo); err != nil { + return nil, err + } gitRepo, err := git.OpenRepository(ctx, repo.RepoPath()) if err != nil { From 44a8eceedaa2c73bad5c6e1b3b67d0804de293b9 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 19 Jun 2023 07:22:40 +0000 Subject: [PATCH 063/158] fix lint --- models/repo/license.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/models/repo/license.go b/models/repo/license.go index 5a624bbfa8..add8be1039 100644 --- a/models/repo/license.go +++ b/models/repo/license.go @@ -14,7 +14,7 @@ func init() { db.RegisterModel(new(RepoLicense)) } -type RepoLicense struct { +type RepoLicense struct { //revive:disable-line:exported ID int64 `xorm:"pk autoincr"` RepoID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"` CommitID string @@ -24,7 +24,7 @@ type RepoLicense struct { } // LanguageStatList defines a list of language statistics -type RepoLicenseList []*RepoLicense +type RepoLicenseList []*RepoLicense //revive:disable-line:exported func (rll RepoLicenseList) StringList() []string { var licenses []string From 376b91ac315fb3122a2aca672ee3b2be8d4af428 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 19 Jun 2023 07:23:05 +0000 Subject: [PATCH 064/158] remove todo --- models/repo/license.go | 1 - 1 file changed, 1 deletion(-) diff --git a/models/repo/license.go b/models/repo/license.go index add8be1039..788f02bbfe 100644 --- a/models/repo/license.go +++ b/models/repo/license.go @@ -105,7 +105,6 @@ func CopyLicense(originalRepo, destRepo *Repository) error { for i := range repoLicenses { repoLicenses[i].ID = 0 repoLicenses[i].RepoID = destRepo.ID - // TODO: convert commitID? repoLicenses[i].CreatedUnix = time repoLicenses[i].UpdatedUnix = time } From 4ec4a0ffafdc1cd745b813b28a698398d317af25 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 19 Jun 2023 07:47:02 +0000 Subject: [PATCH 065/158] finish todo --- modules/repository/create.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/repository/create.go b/modules/repository/create.go index 95ab1ea2a3..f887eee793 100644 --- a/modules/repository/create.go +++ b/modules/repository/create.go @@ -283,16 +283,16 @@ func CreateRepository(doer, u *user_model.User, opts CreateRepoOptions) (*repo_m if len(opts.License) > 0 { licenses = append(licenses, ConvertLicenseName(opts.License)) - // TODO git command? - gitRepo, err := git.OpenRepository(ctx, repo.RepoPath()) + stdout, _, err := git.NewCommand(ctx, "rev-parse", "HEAD"). + SetDescription(fmt.Sprintf("CreateRepository(git rev-parse HEAD): %s", repoPath)). + RunStdString(&git.RunOpts{Dir: repoPath}) if err != nil { - return fmt.Errorf("OpenRepository: %w", err) + log.Error("CreateRepository(git rev-parse HEAD) in %v: Stdout: %s\nError: %v", repo, stdout, err) + rollbackRepo = repo + rollbackRepo.OwnerID = u.ID + return fmt.Errorf("CreateRepository(git rev-parse HEAD): %w", err) } - commitID, err := gitRepo.GetBranchCommitID(repo.DefaultBranch) - if err != nil { - return err - } - if err := repo_model.UpdateRepoLicenses(ctx, repo, commitID, licenses); err != nil { + if err := repo_model.UpdateRepoLicenses(ctx, repo, stdout, licenses); err != nil { return err } } From 9cbde7294e75e9ffd2199619dc5ff7a4d4c24c75 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 26 Jun 2023 01:37:58 +0000 Subject: [PATCH 066/158] avoid return same licenses --- models/migrations/v1_21/v261.go | 11 ++++++----- models/repo/license.go | 2 +- modules/repository/license.go | 9 +++++---- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/models/migrations/v1_21/v261.go b/models/migrations/v1_21/v261.go index b081801341..12b405d79d 100644 --- a/models/migrations/v1_21/v261.go +++ b/models/migrations/v1_21/v261.go @@ -10,6 +10,7 @@ import ( "strings" "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" @@ -180,13 +181,13 @@ func detectLicense(content string) []string { log.Error("licenseclassifier.MatchFrom: %v", err) return nil } - var results []string + results := make(container.Set[string], len(matches.Matches)) for _, r := range matches.Matches { - if r.MatchType == "License" { - results = append(results, r.Variant) + if r.MatchType == "License" && !results.Contains(r.Variant) { + results.Add(r.Variant) } } - return results + return results.Values() } func ConvertLicenseName(name string) string { @@ -250,7 +251,7 @@ func AddRepositoryLicenses(x *xorm.Engine) error { CommitID string License string `xorm:"VARCHAR(50) UNIQUE(s) INDEX NOT NULL"` CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED"` - UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` + UpdatedUnix timeutil.TimeStamp `xorm:"INDEX UPDATED"` } if err := x.Sync(new(RepoLicense)); err != nil { diff --git a/models/repo/license.go b/models/repo/license.go index 788f02bbfe..d6d78cdaec 100644 --- a/models/repo/license.go +++ b/models/repo/license.go @@ -72,7 +72,7 @@ func UpdateRepoLicenses(ctx context.Context, repo *Repository, commitID string, } } } - // Delete old languages + // Delete old licenses licenseToDelete := make([]int64, 0, len(oldLicenses)) for _, o := range oldLicenses { if o.CommitID != commitID { diff --git a/modules/repository/license.go b/modules/repository/license.go index 5790319d85..24f03f9e3e 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -12,6 +12,7 @@ import ( "strings" repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" @@ -280,11 +281,11 @@ func detectLicense(content string) []string { log.Error("licenseclassifier.MatchFrom: %v", err) return nil } - var results []string + results := make(container.Set[string], len(matches.Matches)) for _, r := range matches.Matches { - if r.MatchType == "License" { - results = append(results, r.Variant) + if r.MatchType == "License" && !results.Contains(r.Variant) { + results.Add(r.Variant) } } - return results + return results.Values() } From f7da797dbc5e07a197b7d730bfd4c16517710f87 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 26 Jun 2023 01:40:02 +0000 Subject: [PATCH 067/158] fix conflicts --- models/migrations/migrations.go | 4 +++- models/migrations/v1_21/{v261.go => v262.go} | 0 2 files changed, 3 insertions(+), 1 deletion(-) rename models/migrations/v1_21/{v261.go => v262.go} (100%) diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 1b585373cf..16621b3aa9 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -503,7 +503,9 @@ var migrations = []Migration{ // v260 -> v261 NewMigration("Drop custom_labels column of action_runner table", v1_21.DropCustomLabelsColumnOfActionRunner), - // v261 -> 262 + // v261 -> v262 + NewMigration("Add variable table", v1_21.CreateVariableTable), + // v262 -> v263 NewMigration("Add Repository Licenses", v1_21.AddRepositoryLicenses), } diff --git a/models/migrations/v1_21/v261.go b/models/migrations/v1_21/v262.go similarity index 100% rename from models/migrations/v1_21/v261.go rename to models/migrations/v1_21/v262.go From 2904f345e0bc626618b5590de08635e4cf0f5867 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 5 Jul 2023 00:21:37 +0000 Subject: [PATCH 068/158] fix conflicts --- models/migrations/migrations.go | 8 +++++++- models/migrations/v1_21/{v262.go => v265.go} | 0 2 files changed, 7 insertions(+), 1 deletion(-) rename models/migrations/v1_21/{v262.go => v265.go} (100%) diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 16621b3aa9..7f8f7f1463 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -499,13 +499,19 @@ var migrations = []Migration{ // v259 -> v260 NewMigration("Convert scoped access tokens", v1_20.ConvertScopedAccessTokens), - // Gitea 1.20.0 ends at 260 + // Gitea 1.20.0 ends at v260 // v260 -> v261 NewMigration("Drop custom_labels column of action_runner table", v1_21.DropCustomLabelsColumnOfActionRunner), // v261 -> v262 NewMigration("Add variable table", v1_21.CreateVariableTable), // v262 -> v263 + NewMigration("Add TriggerEvent to action_run table", v1_21.AddTriggerEventToActionRun), + // v263 -> v264 + NewMigration("Add git_size and lfs_size columns to repository table", v1_21.AddGitSizeAndLFSSizeToRepositoryTable), + // v264 -> v265 + NewMigration("Add branch table", v1_21.AddBranchTable), + // v265 -> v266 NewMigration("Add Repository Licenses", v1_21.AddRepositoryLicenses), } diff --git a/models/migrations/v1_21/v262.go b/models/migrations/v1_21/v265.go similarity index 100% rename from models/migrations/v1_21/v262.go rename to models/migrations/v1_21/v265.go From e38161b4873cc440f67288e2d90c20c5e5aa209d Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 5 Jul 2023 00:23:57 +0000 Subject: [PATCH 069/158] fix conflicts --- .../{setting_protected_branch.go => setting/protected_branch.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename routers/web/repo/{setting_protected_branch.go => setting/protected_branch.go} (100%) diff --git a/routers/web/repo/setting_protected_branch.go b/routers/web/repo/setting/protected_branch.go similarity index 100% rename from routers/web/repo/setting_protected_branch.go rename to routers/web/repo/setting/protected_branch.go From 2b56a5a3078d2f436379aa5ced519fb9efeba68e Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 5 Jul 2023 00:57:53 +0000 Subject: [PATCH 070/158] fix --- routers/web/repo/branch.go | 1 - 1 file changed, 1 deletion(-) diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go index b7a32db63c..9fb8c8c75d 100644 --- a/routers/web/repo/branch.go +++ b/routers/web/repo/branch.go @@ -81,7 +81,6 @@ func Branches(ctx *context.Context) { pager.SetDefaultParams(ctx) ctx.Data["Page"] = pager - var err error ctx.Data["LicenseFileName"], err = repo_module.GetLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.Commit) if err != nil { ctx.ServerError("GetLicenseFileName", err) From b168d1bc9fcb1a19eedda22692baf6bff9fc6c26 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 5 Jul 2023 01:35:25 +0000 Subject: [PATCH 071/158] improve --- modules/repository/license.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/modules/repository/license.go b/modules/repository/license.go index 24f03f9e3e..6b0043ec58 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -281,11 +281,14 @@ func detectLicense(content string) []string { log.Error("licenseclassifier.MatchFrom: %v", err) return nil } - results := make(container.Set[string], len(matches.Matches)) - for _, r := range matches.Matches { - if r.MatchType == "License" && !results.Contains(r.Variant) { - results.Add(r.Variant) + if len(matches.Matches) > 0 { + results := make(container.Set[string], len(matches.Matches)) + for _, r := range matches.Matches { + if r.MatchType == "License" && !results.Contains(r.Variant) { + results.Add(r.Variant) + } } + return results.Values() } - return results.Values() + return nil } From 7640268926b76b59e114559290108c91dc85f146 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 6 Jul 2023 05:12:03 +0000 Subject: [PATCH 072/158] remove licenses when remove repo --- models/repo.go | 1 + 1 file changed, 1 insertion(+) diff --git a/models/repo.go b/models/repo.go index 9044fc8aed..4b45e4c159 100644 --- a/models/repo.go +++ b/models/repo.go @@ -150,6 +150,7 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error { &git_model.Branch{RepoID: repoID}, &git_model.LFSLock{RepoID: repoID}, &repo_model.LanguageStat{RepoID: repoID}, + &repo_model.RepoLicense{RepoID: repoID}, &issues_model.Milestone{RepoID: repoID}, &repo_model.Mirror{RepoID: repoID}, &activities_model.Notification{RepoID: repoID}, From 7a9d60538acae7d411d68ad1d9f678469a7f5762 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 7 Jul 2023 05:56:14 +0000 Subject: [PATCH 073/158] add fixtures --- models/fixtures/repo_license.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 models/fixtures/repo_license.yml diff --git a/models/fixtures/repo_license.yml b/models/fixtures/repo_license.yml new file mode 100644 index 0000000000..ca780a73aa --- /dev/null +++ b/models/fixtures/repo_license.yml @@ -0,0 +1 @@ +[] # empty From 16822cd864f59b59d35f50040887a96eb21256c7 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 20 Jul 2023 04:13:21 +0000 Subject: [PATCH 074/158] make tidy --- go.mod | 2 +- go.sum | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 63f4cc3588..065fffc7b9 100644 --- a/go.mod +++ b/go.mod @@ -56,7 +56,7 @@ require ( github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 github.com/golang-jwt/jwt/v5 v5.0.0 github.com/google/go-github/v53 v53.2.0 - github.com/google/licenseclassifier/v2 v2.0.0 + github.com/google/licenseclassifier/v2 v2.0.0 github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 github.com/google/uuid v1.3.0 github.com/gorilla/feeds v1.1.1 diff --git a/go.sum b/go.sum index 82ba0e3d82..8fc7ce5445 100644 --- a/go.sum +++ b/go.sum @@ -1071,6 +1071,7 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= From fc93550898225804f62fafa6941a8ee472804736 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 27 Jul 2023 08:59:30 +0000 Subject: [PATCH 075/158] rename to v270 --- models/migrations/v1_21/{v265.go => v270.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename models/migrations/v1_21/{v265.go => v270.go} (100%) diff --git a/models/migrations/v1_21/v265.go b/models/migrations/v1_21/v270.go similarity index 100% rename from models/migrations/v1_21/v265.go rename to models/migrations/v1_21/v270.go From d57592f693808220ecc44f874e70351296907af2 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 27 Jul 2023 09:00:58 +0000 Subject: [PATCH 076/158] fix lint --- models/migrations/migrations.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index b14b3d6932..ab0d09ef45 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -521,8 +521,8 @@ var migrations = []Migration{ NewMigration("Update Action Ref", v1_21.UpdateActionsRefIndex), // v269 -> v270 NewMigration("Drop deleted branch table", v1_21.DropDeletedBranchTable), - // v270 -> v271 - NewMigration("Add Repository Licenses", v1_21.AddRepositoryLicenses), + // v270 -> v271 + NewMigration("Add Repository Licenses", v1_21.AddRepositoryLicenses), } // GetCurrentDBVersion returns the current db version From d6f700636a4e7135eea355c3e8b95cc01ed282f4 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 2 Aug 2023 23:58:55 +0000 Subject: [PATCH 077/158] rename to v271 --- models/migrations/v1_21/{v270.go => v271.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename models/migrations/v1_21/{v270.go => v271.go} (100%) diff --git a/models/migrations/v1_21/v270.go b/models/migrations/v1_21/v271.go similarity index 100% rename from models/migrations/v1_21/v270.go rename to models/migrations/v1_21/v271.go From 3c554a54c7883e0795e246ddc8b70448834dd9aa Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 7 Aug 2023 05:02:51 +0000 Subject: [PATCH 078/158] fix lint --- models/migrations/migrations.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 4ae805ab6a..91cb57f9d7 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -523,8 +523,8 @@ var migrations = []Migration{ NewMigration("Drop deleted branch table", v1_21.DropDeletedBranchTable), // v270 -> v271 NewMigration("Fix PackageProperty typo", v1_21.FixPackagePropertyTypo), - // v271 -> v272 - NewMigration("Add Repository Licenses", v1_21.AddRepositoryLicenses), + // v271 -> v272 + NewMigration("Add Repository Licenses", v1_21.AddRepositoryLicenses), } // GetCurrentDBVersion returns the current db version From f546aaefe37bafbfe081398190b5179c0c03d116 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 22 Aug 2023 04:37:46 +0000 Subject: [PATCH 079/158] rename to v273 --- models/migrations/v1_21/{v271.go => v273.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename models/migrations/v1_21/{v271.go => v273.go} (100%) diff --git a/models/migrations/v1_21/v271.go b/models/migrations/v1_21/v273.go similarity index 100% rename from models/migrations/v1_21/v271.go rename to models/migrations/v1_21/v273.go From 87ae3a626c1125a0818dbcdafa4364875b8c515d Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 29 Aug 2023 07:36:24 +0000 Subject: [PATCH 080/158] rename to v274 --- models/migrations/migrations.go | 2 +- models/migrations/v1_21/{v273.go => v274.go} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename models/migrations/v1_21/{v273.go => v274.go} (100%) diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 97b9f30bd9..2721b7b3d3 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -526,7 +526,7 @@ var migrations = []Migration{ NewMigration("Allow archiving labels", v1_21.AddArchivedUnixColumInLabelTable), // v272 -> v273 NewMigration("Add Version to ActionRun table", v1_21.AddVersionToActionRunTable), - // v273 -> v274 + // v274 -> v275 NewMigration("Add Repository Licenses", v1_21.AddRepositoryLicenses), } diff --git a/models/migrations/v1_21/v273.go b/models/migrations/v1_21/v274.go similarity index 100% rename from models/migrations/v1_21/v273.go rename to models/migrations/v1_21/v274.go From cbe15154b60a290019b204d52f005d6222304f94 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 27 Sep 2023 01:19:05 +0000 Subject: [PATCH 081/158] rename to v278 --- models/migrations/v1_21/{v274.go => v278.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename models/migrations/v1_21/{v274.go => v278.go} (100%) diff --git a/models/migrations/v1_21/v274.go b/models/migrations/v1_21/v278.go similarity index 100% rename from models/migrations/v1_21/v274.go rename to models/migrations/v1_21/v278.go From e70bb25882622db1eb9e4899fd9eef167039f22e Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 27 Sep 2023 01:42:28 +0000 Subject: [PATCH 082/158] recover changes in DeleteRepository --- services/repository/delete.go | 1 + 1 file changed, 1 insertion(+) diff --git a/services/repository/delete.go b/services/repository/delete.go index f3bf91af4f..d4a20cd154 100644 --- a/services/repository/delete.go +++ b/services/repository/delete.go @@ -138,6 +138,7 @@ func DeleteRepositoryDirectly(ctx context.Context, doer *user_model.User, uid, r &git_model.Branch{RepoID: repoID}, &git_model.LFSLock{RepoID: repoID}, &repo_model.LanguageStat{RepoID: repoID}, + &repo_model.RepoLicense{RepoID: repoID}, &issues_model.Milestone{RepoID: repoID}, &repo_model.Mirror{RepoID: repoID}, &activities_model.Notification{RepoID: repoID}, From 498ea785c8e977c8c23b2bb698ac29e0ccb9a6ab Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 27 Sep 2023 01:47:02 +0000 Subject: [PATCH 083/158] recover changes in CreateRepository --- services/repository/create.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/services/repository/create.go b/services/repository/create.go index 09956b74d4..47fe85703f 100644 --- a/services/repository/create.go +++ b/services/repository/create.go @@ -299,6 +299,25 @@ func CreateRepositoryDirectly(ctx context.Context, doer, u *user_model.User, opt rollbackRepo.OwnerID = u.ID return fmt.Errorf("CreateRepository(git update-server-info): %w", err) } + + // update licenses + var licenses []string + if len(opts.License) > 0 { + licenses = append(licenses, repo_module.ConvertLicenseName(opts.License)) + + stdout, _, err := git.NewCommand(ctx, "rev-parse", "HEAD"). + SetDescription(fmt.Sprintf("CreateRepository(git rev-parse HEAD): %s", repoPath)). + RunStdString(&git.RunOpts{Dir: repoPath}) + if err != nil { + log.Error("CreateRepository(git rev-parse HEAD) in %v: Stdout: %s\nError: %v", repo, stdout, err) + rollbackRepo = repo + rollbackRepo.OwnerID = u.ID + return fmt.Errorf("CreateRepository(git rev-parse HEAD): %w", err) + } + if err := repo_model.UpdateRepoLicenses(ctx, repo, stdout, licenses); err != nil { + return err + } + } return nil }); err != nil { if rollbackRepo != nil { From 83945edb044203077688e44c441edea90dcc6b1d Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 27 Sep 2023 01:59:27 +0000 Subject: [PATCH 084/158] recover changes in SetDefaultBranchPost --- routers/web/repo/setting/default_branch.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/routers/web/repo/setting/default_branch.go b/routers/web/repo/setting/default_branch.go index 9bf54e706a..7cd58e3b06 100644 --- a/routers/web/repo/setting/default_branch.go +++ b/routers/web/repo/setting/default_branch.go @@ -10,6 +10,7 @@ import ( "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" + repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/routers/web/repo" notify_service "code.gitea.io/gitea/services/notify" @@ -47,11 +48,15 @@ func SetDefaultBranchPost(ctx *context.Context) { } } if err := repo_model.UpdateDefaultBranch(ctx, repo); err != nil { - ctx.ServerError("SetDefaultBranch", err) + ctx.ServerError("UpdateDefaultBranch", err) return } - notify_service.ChangeDefaultBranch(ctx, repo) + if err := repo_module.UpdateRepoLicenses(ctx, repo, ctx.Repo.Commit); err != nil { + ctx.ServerError("UpdateRepoLicenses", err) + return + } + // TODO: add notify_service.ChangeRepoLicenses } log.Trace("Repository basic settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name) From bae33d5633ba7b8996f765b443139c0faec9da2b Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 27 Sep 2023 01:59:37 +0000 Subject: [PATCH 085/158] recover changes in templates/repo/sub_menu.tmpl --- templates/repo/sub_menu.tmpl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/templates/repo/sub_menu.tmpl b/templates/repo/sub_menu.tmpl index 56c94f1b65..b11f91fb01 100644 --- a/templates/repo/sub_menu.tmpl +++ b/templates/repo/sub_menu.tmpl @@ -13,6 +13,11 @@ {{svg "octicon-tag"}} {{ctx.Locale.PrettyNumber .NumTags}} {{ctx.Locale.TrN .NumTags "repo.tag" "repo.tags"}} {{end}} + {{if .Licenses}} + + {{svg "octicon-law"}} {{if eq (len .Licenses) 1}}{{index .Licenses 0}}{{else}}{{.locale.Tr "repo.multiple_licenses"}}{{end}} + + {{end}} {{$fileSizeFormatted := FileSize .Repository.Size}}{{/* the formatted string is always "{val} {unit}" */}} {{$fileSizeFields := StringUtils.Split $fileSizeFormatted " "}} From ba6019507afac50393b920e9f8a355c9c8161a5a Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 27 Sep 2023 02:08:38 +0000 Subject: [PATCH 086/158] fix --- modules/repository/license_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/repository/license_test.go b/modules/repository/license_test.go index fc0c9dc484..509b9e3038 100644 --- a/modules/repository/license_test.go +++ b/modules/repository/license_test.go @@ -205,7 +205,7 @@ func Test_detectLicense(t *testing.T) { err := loadSameLicenses() assert.NoError(t, err) for _, licenseName := range Licenses { - license, err := getLicense(licenseName, &licenseValues{ + license, err := GetLicense(licenseName, &LicenseValues{ Owner: "Gitea", Email: "teabot@gitea.io", Repo: "gitea", From 91dda747abc8f8e98a1684963994b7def2ec46ca Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 23 Oct 2023 01:27:36 +0000 Subject: [PATCH 087/158] rename to v282 --- models/migrations/{v1_21/v278.go => v1_22/v282.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename models/migrations/{v1_21/v278.go => v1_22/v282.go} (100%) diff --git a/models/migrations/v1_21/v278.go b/models/migrations/v1_22/v282.go similarity index 100% rename from models/migrations/v1_21/v278.go rename to models/migrations/v1_22/v282.go From 462f7f5108ad5d3cbd5be1e97c2720cec29e601c Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 23 Oct 2023 01:35:20 +0000 Subject: [PATCH 088/158] fix package name of migration --- models/migrations/v1_22/v282.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/migrations/v1_22/v282.go b/models/migrations/v1_22/v282.go index 12b405d79d..97f98be300 100644 --- a/models/migrations/v1_22/v282.go +++ b/models/migrations/v1_22/v282.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_21 //nolint +package v1_22 //nolint import ( "fmt" From df3e16872b9c6cef202530c84de55ee7869ca577 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 1 Nov 2023 11:18:58 +0900 Subject: [PATCH 089/158] Update models/migrations/migrations.go Co-authored-by: Denys Konovalov --- models/migrations/migrations.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 1d2268a411..7e854f38e6 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -549,7 +549,7 @@ var migrations = []Migration{ // v281 -> v282 NewMigration("Add auth_token table", v1_22.CreateAuthTokenTable), // v282 -> v283 - NewMigration("Add Repository Licenses", v1_21.AddRepositoryLicenses), + NewMigration("Add Repository Licenses", v1_22.AddRepositoryLicenses), } // GetCurrentDBVersion returns the current db version From 3abe77e6901a83e2c3a49751a1883ca7ee89cd27 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 1 Nov 2023 02:19:40 +0000 Subject: [PATCH 090/158] rename to v283 --- models/migrations/v1_22/{v282.go => v283.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename models/migrations/v1_22/{v282.go => v283.go} (100%) diff --git a/models/migrations/v1_22/v282.go b/models/migrations/v1_22/v283.go similarity index 100% rename from models/migrations/v1_22/v282.go rename to models/migrations/v1_22/v283.go From 640a5e455b74482ca829a44c7e4487bedeff0d3e Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 6 Nov 2023 09:55:30 +0900 Subject: [PATCH 091/158] Update models/migrations/v1_22/v283.go Co-authored-by: Denys Konovalov --- models/migrations/v1_22/v283.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/migrations/v1_22/v283.go b/models/migrations/v1_22/v283.go index 97f98be300..04ec687a7d 100644 --- a/models/migrations/v1_22/v283.go +++ b/models/migrations/v1_22/v283.go @@ -330,7 +330,7 @@ func AddRepositoryLicenses(x *xorm.Engine) error { } } } - // Delete old languages + // Delete old licenses licenseToDelete := make([]int64, 0, len(oldLicenses)) for _, o := range oldLicenses { if o.CommitID != commit.ID.String() { From d6ba4af183a94f2ae3c28e11fa094a34a96b988a Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 6 Nov 2023 00:59:37 +0000 Subject: [PATCH 092/158] use slices.Contains --- build/generate-licenses.go | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/build/generate-licenses.go b/build/generate-licenses.go index a4c979a195..956fb03326 100644 --- a/build/generate-licenses.go +++ b/build/generate-licenses.go @@ -15,6 +15,7 @@ import ( "os" "path" "path/filepath" + "slices" "strings" "code.gitea.io/gitea/modules/json" @@ -138,7 +139,7 @@ func main() { if !ok { sameFiles[md5] = make([]string, 0) } - if !contains(sameFiles[md5], preLicenseName) { + if !slices.Contains(sameFiles[md5], preLicenseName) { sameFiles[md5] = append(sameFiles[md5], preLicenseName) } sameFiles[md5] = append(sameFiles[md5], licenseName) @@ -269,12 +270,3 @@ func getLicenseKey(fnl []string) string { } return "" } - -func contains(s []string, e string) bool { - for _, a := range s { - if a == e { - return true - } - } - return false -} From 8a1c7673bbbfff9a9784e3c39e835a988cbb974e Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 6 Nov 2023 01:02:59 +0000 Subject: [PATCH 093/158] fix --- models/repo/license.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/repo/license.go b/models/repo/license.go index d6d78cdaec..c646f4d700 100644 --- a/models/repo/license.go +++ b/models/repo/license.go @@ -23,7 +23,7 @@ type RepoLicense struct { //revive:disable-line:exported UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` } -// LanguageStatList defines a list of language statistics +// RepoLicenseList defines a list of repo licenses type RepoLicenseList []*RepoLicense //revive:disable-line:exported func (rll RepoLicenseList) StringList() []string { From 7781e7d5364ce3b35b322e8a59a9f9e5b81f24db Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 6 Nov 2023 01:13:57 +0000 Subject: [PATCH 094/158] sync funcs in migration from origin --- models/migrations/v1_22/v283.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/models/migrations/v1_22/v283.go b/models/migrations/v1_22/v283.go index 04ec687a7d..428f188eba 100644 --- a/models/migrations/v1_22/v283.go +++ b/models/migrations/v1_22/v283.go @@ -181,13 +181,16 @@ func detectLicense(content string) []string { log.Error("licenseclassifier.MatchFrom: %v", err) return nil } - results := make(container.Set[string], len(matches.Matches)) - for _, r := range matches.Matches { - if r.MatchType == "License" && !results.Contains(r.Variant) { - results.Add(r.Variant) + if len(matches.Matches) > 0 { + results := make(container.Set[string], len(matches.Matches)) + for _, r := range matches.Matches { + if r.MatchType == "License" && !results.Contains(r.Variant) { + results.Add(r.Variant) + } } + return results.Values() } - return results.Values() + return nil } func ConvertLicenseName(name string) string { From cd0b44c640916ca20612120beefd300f483fa731 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 24 Nov 2023 05:41:22 +0000 Subject: [PATCH 095/158] fix typo --- models/repo/license.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/repo/license.go b/models/repo/license.go index c646f4d700..d178538171 100644 --- a/models/repo/license.go +++ b/models/repo/license.go @@ -20,7 +20,7 @@ type RepoLicense struct { //revive:disable-line:exported CommitID string License string `xorm:"VARCHAR(50) UNIQUE(s) INDEX NOT NULL"` CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED"` - UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` + UpdatedUnix timeutil.TimeStamp `xorm:"INDEX UPDATED"` } // RepoLicenseList defines a list of repo licenses From c57d5422454eb46f5558892a2c20f8ac1f14c872 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 24 Nov 2023 05:52:20 +0000 Subject: [PATCH 096/158] do not init classifier in init() --- modules/repository/license.go | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/modules/repository/license.go b/modules/repository/license.go index ab09065e1e..d049456bf8 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -28,18 +28,11 @@ var ( sameLicenses map[string]string ) -func init() { - err := loadSameLicenses() - if err != nil { - log.Error("loadSameLicenses: %v", err) - } - err = initClassifier() - if err != nil { - log.Error("initClassifier: %v", err) - } -} - func loadSameLicenses() error { + if sameLicenses == nil { + return nil + } + data, err := options.AssetFS().ReadFile("", "sameLicenses") if err != nil { return err @@ -52,7 +45,7 @@ func loadSameLicenses() error { } func ConvertLicenseName(name string) string { - if sameLicenses == nil { + if err := loadSameLicenses(); err != nil { return name } @@ -64,6 +57,10 @@ func ConvertLicenseName(name string) string { } func initClassifier() error { + if classifier != nil { + return nil + } + // threshold should be 0.84~0.86 or the test will be failed classifier = licenseclassifier.NewClassifier(.85) licenseFiles, err := options.AssetFS().ListFiles("license", true) @@ -271,8 +268,7 @@ func detectLicense(content string) []string { if len(content) == 0 { return nil } - if classifier == nil { - log.Error("detectLicense: license classifier is null.") + if err := initClassifier(); err != nil { return nil } From 44cf8e4eee10a7759ffbd8cc40b210d83d934e70 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 24 Nov 2023 05:55:13 +0000 Subject: [PATCH 097/158] add return --- routers/private/hook_post_receive.go | 1 + 1 file changed, 1 insertion(+) diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go index 75814fa82c..f37badaff4 100644 --- a/routers/private/hook_post_receive.go +++ b/routers/private/hook_post_receive.go @@ -199,6 +199,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { err := repo_module.UpdateRepoLicensesByGitRepo(ctx, repo, nil) if err != nil { ctx.JSON(http.StatusInternalServerError, private.Response{Err: err.Error()}) + return } // If our branch is the default branch of an unforked repo - there's no PR to create or refer to From 648d0a0953959730eb0f392c7637e38f28a467fb Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 24 Nov 2023 06:11:41 +0000 Subject: [PATCH 098/158] improve the logic of copy license info --- models/repo/license.go | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/models/repo/license.go b/models/repo/license.go index d178538171..93050a70b9 100644 --- a/models/repo/license.go +++ b/models/repo/license.go @@ -101,14 +101,20 @@ func CopyLicense(originalRepo, destRepo *Repository) error { return err } if len(repoLicenses) > 0 { + newRepoLicenses := make(RepoLicenseList, 0, len(repoLicenses)) + time := timeutil.TimeStampNow() - for i := range repoLicenses { - repoLicenses[i].ID = 0 - repoLicenses[i].RepoID = destRepo.ID - repoLicenses[i].CreatedUnix = time - repoLicenses[i].UpdatedUnix = time + for _, rl := range repoLicenses { + newRepoLicense := &RepoLicense{ + RepoID: destRepo.ID, + CommitID: rl.CommitID, + License: rl.License, + CreatedUnix: time, + UpdatedUnix: time, + } + newRepoLicenses = append(newRepoLicenses, newRepoLicense) } - if err := db.Insert(ctx, &repoLicenses); err != nil { + if err := db.Insert(ctx, &newRepoLicenses); err != nil { return err } } From b45f9073474da559895ea40487c82fd3155f955a Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 24 Nov 2023 06:22:19 +0000 Subject: [PATCH 099/158] improve variable name --- modules/context/repo.go | 2 +- modules/repository/license.go | 4 ++-- routers/web/repo/branch.go | 4 ++-- routers/web/repo/commit.go | 12 ++++++------ routers/web/repo/view.go | 4 ++-- templates/repo/sub_menu.tmpl | 6 +++--- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/modules/context/repo.go b/modules/context/repo.go index 25c9c82007..ee5edb4384 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -405,7 +405,7 @@ func repoAssignment(ctx *Context, repo *repo_model.Repository) { ctx.ServerError("GetRepoLicenses", err) return } - ctx.Data["Licenses"] = repoLicenses.StringList() + ctx.Data["DetectedRepoLicenses"] = repoLicenses.StringList() } // RepoIDAssignment returns a handler which assigns the repo to the context. diff --git a/modules/repository/license.go b/modules/repository/license.go index d049456bf8..a475e96cb6 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -222,8 +222,8 @@ func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository, commit return nil } -// GetLicenseFileName returns license file name in the repository if it exists -func GetLicenseFileName(ctx context.Context, repo *repo_model.Repository, commit *git.Commit) (string, error) { +// GetDetectedLicenseFileName returns license file name in the repository if it exists +func GetDetectedLicenseFileName(ctx context.Context, repo *repo_model.Repository, commit *git.Commit) (string, error) { if commit == nil { return "", nil } diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go index 6aa5b210a1..8b59f6deae 100644 --- a/routers/web/repo/branch.go +++ b/routers/web/repo/branch.go @@ -84,9 +84,9 @@ func Branches(ctx *context.Context) { pager.SetDefaultParams(ctx) ctx.Data["Page"] = pager - ctx.Data["LicenseFileName"], err = repo_module.GetLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.Commit) + ctx.Data["DetectedLicenseFileName"], err = repo_module.GetDetectedLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.Commit) if err != nil { - ctx.ServerError("GetLicenseFileName", err) + ctx.ServerError("GetDetectedLicenseFileName", err) return } ctx.HTML(http.StatusOK, tplBranch) diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index ceda2a4a59..694a4caa95 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -86,9 +86,9 @@ func Commits(ctx *context.Context) { pager := context.NewPagination(int(commitsCount), pageSize, page, 5) pager.SetDefaultParams(ctx) ctx.Data["Page"] = pager - ctx.Data["LicenseFileName"], err = repo_module.GetLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.Commit) + ctx.Data["DetectedLicenseFileName"], err = repo_module.GetDetectedLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.Commit) if err != nil { - ctx.ServerError("GetLicenseFileName", err) + ctx.ServerError("GetDetectedLicenseFileName", err) return } ctx.HTML(http.StatusOK, tplCommits) @@ -208,9 +208,9 @@ func SearchCommits(ctx *context.Context) { ctx.Data["Username"] = ctx.Repo.Owner.Name ctx.Data["Reponame"] = ctx.Repo.Repository.Name ctx.Data["RefName"] = ctx.Repo.RefName - ctx.Data["LicenseFileName"], err = repo_module.GetLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.Commit) + ctx.Data["DetectedLicenseFileName"], err = repo_module.GetDetectedLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.Commit) if err != nil { - ctx.ServerError("GetLicenseFileName", err) + ctx.ServerError("GetDetectedLicenseFileName", err) return } ctx.HTML(http.StatusOK, tplCommits) @@ -261,9 +261,9 @@ func FileHistory(ctx *context.Context) { pager.SetDefaultParams(ctx) ctx.Data["Page"] = pager - ctx.Data["LicenseFileName"], err = repo_module.GetLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.Commit) + ctx.Data["DetectedLicenseFileName"], err = repo_module.GetDetectedLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.Commit) if err != nil { - ctx.ServerError("GetLicenseFileName", err) + ctx.ServerError("GetDetectedLicenseFileName", err) return } ctx.HTML(http.StatusOK, tplCommits) diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index ff23debf7a..8325c06586 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -913,9 +913,9 @@ func renderCode(ctx *context.Context) { ctx.Data["TreeLink"] = treeLink ctx.Data["TreeNames"] = treeNames ctx.Data["BranchLink"] = branchLink - ctx.Data["LicenseFileName"], err = repo_module.GetLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.Commit) + ctx.Data["DetectedLicenseFileName"], err = repo_module.GetDetectedLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.Commit) if err != nil { - ctx.ServerError("GetLicenseFileName", err) + ctx.ServerError("GetDetectedLicenseFileName", err) return } ctx.HTML(http.StatusOK, tplRepoHome) diff --git a/templates/repo/sub_menu.tmpl b/templates/repo/sub_menu.tmpl index b289c5c313..ea689f92ed 100644 --- a/templates/repo/sub_menu.tmpl +++ b/templates/repo/sub_menu.tmpl @@ -13,9 +13,9 @@ {{svg "octicon-tag"}} {{ctx.Locale.PrettyNumber .NumTags}} {{ctx.Locale.TrN .NumTags "repo.tag" "repo.tags"}} {{end}} - {{if .Licenses}} - - {{svg "octicon-law"}} {{if eq (len .Licenses) 1}}{{index .Licenses 0}}{{else}}{{.locale.Tr "repo.multiple_licenses"}}{{end}} + {{if .DetectedRepoLicenses}} + + {{svg "octicon-law"}} {{if eq (len .DetectedRepoLicenses) 1}}{{index .DetectedRepoLicenses 0}}{{else}}{{.locale.Tr "repo.multiple_licenses"}}{{end}} {{end}} From dac32cede886c5a070e06f8ccf39748918b649e5 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 24 Nov 2023 06:57:18 +0000 Subject: [PATCH 100/158] improve detect license --- modules/repository/license.go | 53 ++++++++++++++--------------------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/modules/repository/license.go b/modules/repository/license.go index a475e96cb6..f849115858 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -8,6 +8,7 @@ import ( "bytes" "context" "fmt" + "io" "regexp" "strings" @@ -15,9 +16,7 @@ import ( "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/json" - "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/options" - "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" licenseclassifier "github.com/google/licenseclassifier/v2" @@ -211,14 +210,19 @@ func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository, commit if err != nil { return fmt.Errorf("findLicenseFile: %w", err) } - licenses, err := detectLicenseByEntry(licenseFile) - if err != nil { - return fmt.Errorf("checkLicenseFile: %w", err) + if licenseFile != nil { + r, err := licenseFile.Blob().DataAsync() + if err != nil { + return err + } + licenses, err := detectLicense(r) + if err != nil { + return fmt.Errorf("detectLicense: %w", err) + } + if err := repo_model.UpdateRepoLicenses(ctx, repo, commit.ID.String(), licenses); err != nil { + return fmt.Errorf("UpdateRepositoryCols: %v", err) + } } - if err := repo_model.UpdateRepoLicenses(ctx, repo, commit.ID.String(), licenses); err != nil { - return fmt.Errorf("UpdateRepositoryCols: %v", err) - } - return nil } @@ -249,33 +253,18 @@ func findLicenseFile(commit *git.Commit) (string, *git.TreeEntry, error) { return FindFileInEntries(util.FileTypeLicense, entries, "", "", false) } -// detectLicenseByEntry returns the licenses detected by the given tree entry -func detectLicenseByEntry(file *git.TreeEntry) ([]string, error) { - if file == nil { +// detectLicense returns the licenses detected by the given content buff +func detectLicense(r io.ReadCloser) ([]string, error) { + if r == nil { return nil, nil } - - blob := file.Blob() - content, err := blob.GetBlobContent(setting.UI.MaxDisplayFileSize) - if err != nil { - return nil, fmt.Errorf("GetBlobAll: %w", err) - } - return detectLicense(content), nil -} - -// detectLicense returns the licenses detected by the given content buff -func detectLicense(content string) []string { - if len(content) == 0 { - return nil - } if err := initClassifier(); err != nil { - return nil + return nil, err } - matches, err := classifier.MatchFrom(strings.NewReader(content)) + matches, err := classifier.MatchFrom(r) if err != nil { - log.Error("licenseclassifier.MatchFrom: %v", err) - return nil + return nil, err } if len(matches.Matches) > 0 { results := make(container.Set[string], len(matches.Matches)) @@ -284,7 +273,7 @@ func detectLicense(content string) []string { results.Add(r.Variant) } } - return results.Values() + return results.Values(), nil } - return nil + return nil, nil } From 21b1a7a14c78113ddde05e384a27f4e34505b021 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 24 Nov 2023 07:14:34 +0000 Subject: [PATCH 101/158] fix --- modules/repository/license.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/repository/license.go b/modules/repository/license.go index f849115858..0294bfb986 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -215,6 +215,8 @@ func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository, commit if err != nil { return err } + defer r.Close() + licenses, err := detectLicense(r) if err != nil { return fmt.Errorf("detectLicense: %w", err) From cd06857fd042e577a17047afcc8c5b5f5e37c2a3 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 24 Nov 2023 07:17:35 +0000 Subject: [PATCH 102/158] fix test --- modules/repository/license.go | 2 +- modules/repository/license_test.go | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/modules/repository/license.go b/modules/repository/license.go index 0294bfb986..ffc42f7797 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -256,7 +256,7 @@ func findLicenseFile(commit *git.Commit) (string, *git.TreeEntry, error) { } // detectLicense returns the licenses detected by the given content buff -func detectLicense(r io.ReadCloser) ([]string, error) { +func detectLicense(r io.Reader) ([]string, error) { if r == nil { return nil, nil } diff --git a/modules/repository/license_test.go b/modules/repository/license_test.go index 509b9e3038..a69208a6ad 100644 --- a/modules/repository/license_test.go +++ b/modules/repository/license_test.go @@ -5,6 +5,7 @@ package repository import ( "fmt" + "strings" "testing" "time" @@ -224,11 +225,14 @@ func Test_detectLicense(t *testing.T) { assert.NoError(t, err) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - assert.Equal(t, tt.want, detectLicense(tt.arg)) + license, err := detectLicense(strings.NewReader(tt.arg)) + assert.NoError(t, err) + assert.Equal(t, tt.want, license) }) } - result := detectLicense(tests[2].arg + tests[3].arg + tests[4].arg) + result, err := detectLicense(strings.NewReader(tests[2].arg + tests[3].arg + tests[4].arg)) + assert.NoError(t, err) t.Run("multiple licenses test", func(t *testing.T) { assert.Equal(t, 3, len(result)) assert.Contains(t, result, tests[2].want[0]) From 5ec4b50d75bd77c153f1c69f5f177f8bf3029d92 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 24 Nov 2023 07:43:21 +0000 Subject: [PATCH 103/158] add data-tooltip-placement --- templates/repo/sub_menu.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/repo/sub_menu.tmpl b/templates/repo/sub_menu.tmpl index ea689f92ed..e8622dac2a 100644 --- a/templates/repo/sub_menu.tmpl +++ b/templates/repo/sub_menu.tmpl @@ -14,11 +14,11 @@ {{end}} {{if .DetectedRepoLicenses}} - + {{svg "octicon-law"}} {{if eq (len .DetectedRepoLicenses) 1}}{{index .DetectedRepoLicenses 0}}{{else}}{{.locale.Tr "repo.multiple_licenses"}}{{end}} {{end}} - + {{$fileSizeFormatted := FileSize .Repository.Size}}{{/* the formatted string is always "{val} {unit}" */}} {{$fileSizeFields := StringUtils.Split $fileSizeFormatted " "}} {{svg "octicon-database"}} {{ctx.Locale.PrettyNumber (index $fileSizeFields 0)}} {{index $fileSizeFields 1}} From a5d97637959837a16c41a32c2e8472a28bba53ef Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 30 Nov 2023 07:06:38 +0000 Subject: [PATCH 104/158] fix bug --- modules/repository/license.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/repository/license.go b/modules/repository/license.go index ffc42f7797..7bf6564da2 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -28,7 +28,7 @@ var ( ) func loadSameLicenses() error { - if sameLicenses == nil { + if sameLicenses != nil { return nil } From 9178d90a5fff079c2d7c50ce7c3d8e150c8d0bdc Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 30 Nov 2023 23:51:23 +0000 Subject: [PATCH 105/158] convert sameLicenses to license aliases --- build/generate-licenses.go | 22 +-- models/migrations/v1_22/v283.go | 12 +- modules/repository/license.go | 16 +- modules/repository/license_test.go | 2 +- .../{sameLicenses => license-aliases.json} | 0 options/license/AML-glslang | 41 +++++ options/license/Adobe-Display-PostScript | 30 +++ options/license/DEC-3-Clause | 28 +++ options/license/DRL-1.1 | 17 ++ options/license/GCR-docs | 30 +++ .../license/HPND-sell-MIT-disclaimer-xserver | 12 ++ options/license/Pixar | 174 ++++++++++++++++++ options/license/SAX-PD-2.0 | 10 + options/license/hdparm | 9 + options/license/radvd | 37 ++++ 15 files changed, 414 insertions(+), 26 deletions(-) rename options/{sameLicenses => license-aliases.json} (100%) create mode 100644 options/license/AML-glslang create mode 100644 options/license/Adobe-Display-PostScript create mode 100644 options/license/DEC-3-Clause create mode 100644 options/license/DRL-1.1 create mode 100644 options/license/GCR-docs create mode 100644 options/license/HPND-sell-MIT-disclaimer-xserver create mode 100644 options/license/Pixar create mode 100644 options/license/SAX-PD-2.0 create mode 100644 options/license/hdparm create mode 100644 options/license/radvd diff --git a/build/generate-licenses.go b/build/generate-licenses.go index 956fb03326..d68b8b596e 100644 --- a/build/generate-licenses.go +++ b/build/generate-licenses.go @@ -24,16 +24,16 @@ import ( func main() { var ( - prefix = "gitea-licenses" - url = "https://api.github.com/repos/spdx/license-list-data/tarball" - githubApiToken = "" - githubUsername = "" - destination = "" - sameLicensesDestination = "" + prefix = "gitea-licenses" + url = "https://api.github.com/repos/spdx/license-list-data/tarball" + githubApiToken = "" + githubUsername = "" + destination = "" + licenseAliasesDestination = "" ) flag.StringVar(&destination, "dest", "options/license/", "destination for the licenses") - flag.StringVar(&sameLicensesDestination, "samelicensesdest", "options/sameLicenses", "destination for same license json") + flag.StringVar(&licenseAliasesDestination, "aliasesdest", "options/license-aliases.json", "destination for same license json") flag.StringVar(&githubUsername, "username", "", "github username") flag.StringVar(&githubApiToken, "token", "", "github api token") flag.Parse() @@ -150,20 +150,20 @@ func main() { } // generate convert license name map - sameLicenses := make(map[string]string) + licenseAliases := make(map[string]string) for _, fileNames := range sameFiles { key := getLicenseKey(fileNames) for _, fileName := range fileNames { - sameLicenses[fileName] = key + licenseAliases[fileName] = key } } // save convert license name map to file - bytes, err := json.Marshal(sameLicenses) + bytes, err := json.Marshal(licenseAliases) if err != nil { log.Fatalf("Failed to create json bytes. %s", err) return } - out, err := os.Create(sameLicensesDestination) + out, err := os.Create(licenseAliasesDestination) if err != nil { log.Fatalf("Failed to create new file. %s", err) } diff --git a/models/migrations/v1_22/v283.go b/models/migrations/v1_22/v283.go index 428f188eba..b6bb046411 100644 --- a/models/migrations/v1_22/v283.go +++ b/models/migrations/v1_22/v283.go @@ -24,8 +24,8 @@ import ( ) var ( - classifier *licenseclassifier.Classifier - sameLicenses map[string]string + classifier *licenseclassifier.Classifier + licenseAliases map[string]string ) // Copy paste from models/repo.go because we cannot import models package @@ -194,11 +194,11 @@ func detectLicense(content string) []string { } func ConvertLicenseName(name string) string { - if sameLicenses == nil { + if licenseAliases == nil { return name } - v, ok := sameLicenses[name] + v, ok := licenseAliases[name] if ok { return v } @@ -206,11 +206,11 @@ func ConvertLicenseName(name string) string { } func initClassifier() error { - data, err := options.AssetFS().ReadFile("", "sameLicenses") + data, err := options.AssetFS().ReadFile("", "license-aliases.json") if err != nil { return err } - err = json.Unmarshal(data, &sameLicenses) + err = json.Unmarshal(data, &licenseAliases) if err != nil { return err } diff --git a/modules/repository/license.go b/modules/repository/license.go index 7bf6564da2..5e25aec266 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -23,20 +23,20 @@ import ( ) var ( - classifier *licenseclassifier.Classifier - sameLicenses map[string]string + classifier *licenseclassifier.Classifier + licenseAliases map[string]string ) -func loadSameLicenses() error { - if sameLicenses != nil { +func loadLicenseAliases() error { + if licenseAliases != nil { return nil } - data, err := options.AssetFS().ReadFile("", "sameLicenses") + data, err := options.AssetFS().ReadFile("", "license-aliases.json") if err != nil { return err } - err = json.Unmarshal(data, &sameLicenses) + err = json.Unmarshal(data, &licenseAliases) if err != nil { return err } @@ -44,11 +44,11 @@ func loadSameLicenses() error { } func ConvertLicenseName(name string) string { - if err := loadSameLicenses(); err != nil { + if err := loadLicenseAliases(); err != nil { return name } - v, ok := sameLicenses[name] + v, ok := licenseAliases[name] if ok { return v } diff --git a/modules/repository/license_test.go b/modules/repository/license_test.go index a69208a6ad..88cd3127bb 100644 --- a/modules/repository/license_test.go +++ b/modules/repository/license_test.go @@ -203,7 +203,7 @@ func Test_detectLicense(t *testing.T) { } LoadRepoConfig() - err := loadSameLicenses() + err := loadLicenseAliases() assert.NoError(t, err) for _, licenseName := range Licenses { license, err := GetLicense(licenseName, &LicenseValues{ diff --git a/options/sameLicenses b/options/license-aliases.json similarity index 100% rename from options/sameLicenses rename to options/license-aliases.json diff --git a/options/license/AML-glslang b/options/license/AML-glslang new file mode 100644 index 0000000000..2a24aeac22 --- /dev/null +++ b/options/license/AML-glslang @@ -0,0 +1,41 @@ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/options/license/Adobe-Display-PostScript b/options/license/Adobe-Display-PostScript new file mode 100644 index 0000000000..6df57d3c80 --- /dev/null +++ b/options/license/Adobe-Display-PostScript @@ -0,0 +1,30 @@ +(c)Copyright 1988,1991 Adobe Systems Incorporated. +All rights reserved. + +Permission to use, copy, modify, distribute, and sublicense this software and its +documentation for any purpose and without fee is hereby granted, provided that +the above copyright notices appear in all copies and that both those copyright +notices and this permission notice appear in supporting documentation and that +the name of Adobe Systems Incorporated not be used in advertising or publicity +pertaining to distribution of the software without specific, written prior +permission. No trademark license to use the Adobe trademarks is hereby +granted. If the Adobe trademark "Display PostScript"(tm) is used to describe +this software, its functionality or for any other purpose, such use shall be +limited to a statement that this software works in conjunction with the Display +PostScript system. Proper trademark attribution to reflect Adobe's ownership +of the trademark shall be given whenever any such reference to the Display +PostScript system is made. + +ADOBE MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THE SOFTWARE FOR ANY +PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. ADOBE +DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON- +INFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL ADOBE BE LIABLE TO YOU +OR ANY OTHER PARTY FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +DAMAGES WHATSOEVER WHETHER IN AN ACTION OF CONTRACT,NEGLIGENCE, STRICT +LIABILITY OR ANY OTHER ACTION ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. ADOBE WILL NOT PROVIDE ANY TRAINING OR OTHER +SUPPORT FOR THE SOFTWARE. + +Adobe, PostScript, and Display PostScript are trademarks of Adobe Systems +Incorporated which may be registered in certain jurisdictions. diff --git a/options/license/DEC-3-Clause b/options/license/DEC-3-Clause new file mode 100644 index 0000000000..112edaa70d --- /dev/null +++ b/options/license/DEC-3-Clause @@ -0,0 +1,28 @@ +Copyright 1997 Digital Equipment Corporation. +All rights reserved. + +This software is furnished under license and may be used and copied only in +accordance with the following terms and conditions. Subject to these +conditions, you may download, copy, install, use, modify and distribute +this software in source and/or binary form. No title or ownership is +transferred hereby. + +1) Any source code used, modified or distributed must reproduce and retain + this copyright notice and list of conditions as they appear in the + source file. + +2) No right is granted to use any trade name, trademark, or logo of Digital + Equipment Corporation. Neither the "Digital Equipment Corporation" + name nor any trademark or logo of Digital Equipment Corporation may be + used to endorse or promote products derived from this software without + the prior written permission of Digital Equipment Corporation. + +3) This software is provided "AS-IS" and any express or implied warranties, + including but not limited to, any implied warranties of merchantability, + fitness for a particular purpose, or non-infringement are disclaimed. + In no event shall DIGITAL be liable for any damages whatsoever, and in + particular, DIGITAL shall not be liable for special, indirect, + consequential, or incidental damages or damages for lost profits, loss + of revenue or loss of use, whether such damages arise in contract, + negligence, tort, under statute, in equity, at law or otherwise, even + if advised of the possibility of such damage. diff --git a/options/license/DRL-1.1 b/options/license/DRL-1.1 new file mode 100644 index 0000000000..a6445601ff --- /dev/null +++ b/options/license/DRL-1.1 @@ -0,0 +1,17 @@ +Detection Rule License (DRL) 1.1 + +Permission is hereby granted, free of charge, to any person obtaining a copy of this rule set and associated documentation files (the "Rules"), to deal in the Rules without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Rules, and to permit persons to whom the Rules are furnished to do so, subject to the following conditions: + +If you share the Rules (including in modified form), you must retain the following if it is supplied within the Rules: + +identification of the authors(s) ("author" field) of the Rule and any others designated to receive attribution, in any reasonable manner requested by the Rule author (including by pseudonym if designated). + +a URI or hyperlink to the Rule set or explicit Rule to the extent reasonably practicable + +indicate the Rules are licensed under this Detection Rule License, and include the text of, or the URI or hyperlink to, this Detection Rule License to the extent reasonably practicable + +If you use the Rules (including in modified form) on data, messages based on matches with the Rules must retain the following if it is supplied within the Rules: + +identification of the authors(s) ("author" field) of the Rule and any others designated to receive attribution, in any reasonable manner requested by the Rule author (including by pseudonym if designated). + +THE RULES ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE RULES OR THE USE OR OTHER DEALINGS IN THE RULES. diff --git a/options/license/GCR-docs b/options/license/GCR-docs new file mode 100644 index 0000000000..d5c1293c96 --- /dev/null +++ b/options/license/GCR-docs @@ -0,0 +1,30 @@ +This work may be reproduced and distributed in whole or in part, in +any medium, physical or electronic, so as long as this copyright +notice remains intact and unchanged on all copies. Commercial +redistribution is permitted and encouraged, but you may not +redistribute, in whole or in part, under terms more restrictive than +those under which you received it. If you redistribute a modified or +translated version of this work, you must also make the source code to +the modified or translated version available in electronic form +without charge. However, mere aggregation as part of a larger work +shall not count as a modification for this purpose. + +All code examples in this work are placed into the public domain, +and may be used, modified and redistributed without restriction. + +BECAUSE THIS WORK IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE WORK, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE WORK "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. SHOULD THE WORK PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY REPAIR OR CORRECTION. + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE WORK AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +WORK, EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. diff --git a/options/license/HPND-sell-MIT-disclaimer-xserver b/options/license/HPND-sell-MIT-disclaimer-xserver new file mode 100644 index 0000000000..e7bea21d16 --- /dev/null +++ b/options/license/HPND-sell-MIT-disclaimer-xserver @@ -0,0 +1,12 @@ +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +this permission notice appear in supporting documentation. This permission +notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/options/license/Pixar b/options/license/Pixar new file mode 100644 index 0000000000..c7533090bb --- /dev/null +++ b/options/license/Pixar @@ -0,0 +1,174 @@ + + Modified Apache 2.0 License + + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor + and its affiliates, except as required to comply with Section 4(c) of + the License and to reproduce the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. diff --git a/options/license/SAX-PD-2.0 b/options/license/SAX-PD-2.0 new file mode 100644 index 0000000000..b329db3bb5 --- /dev/null +++ b/options/license/SAX-PD-2.0 @@ -0,0 +1,10 @@ +SAX2 is Free! + +I hereby abandon any property rights to SAX 2.0 (the Simple API for +XML), and release all of the SAX 2.0 source code, compiled code, and +documentation contained in this distribution into the Public Domain. +SAX comes with NO WARRANTY or guarantee of fitness for any +purpose. + +David Megginson, david@megginson.com +2000-05-05 diff --git a/options/license/hdparm b/options/license/hdparm new file mode 100644 index 0000000000..280a1c0797 --- /dev/null +++ b/options/license/hdparm @@ -0,0 +1,9 @@ +BSD-Style Open Source License: + +You may freely use, modify, and redistribute the hdparm program, +as either binary or source, or both. + +The only condition is that my name and copyright notice +remain in the source code as-is. + +Mark Lord (mlord@pobox.com) diff --git a/options/license/radvd b/options/license/radvd new file mode 100644 index 0000000000..4e77909ed7 --- /dev/null +++ b/options/license/radvd @@ -0,0 +1,37 @@ + The author(s) grant permission for redistribution and use in source and +binary forms, with or without modification, of the software and documentation +provided that the following conditions are met: + +0. If you receive a version of the software that is specifically labelled + as not being for redistribution (check the version message and/or README), + you are not permitted to redistribute that version of the software in any + way or form. +1. All terms of all other applicable copyrights and licenses must be + followed. +2. Redistributions of source code must retain the authors' copyright + notice(s), this list of conditions, and the following disclaimer. +3. Redistributions in binary form must reproduce the authors' copyright + notice(s), this list of conditions, and the following disclaimer in the + documentation and/or other materials provided with the distribution. +4. All advertising materials mentioning features or use of this software + must display the following acknowledgement with the name(s) of the + authors as specified in the copyright notice(s) substituted where + indicated: + + This product includes software developed by the authors which are + mentioned at the start of the source files and other contributors. + +5. Neither the name(s) of the author(s) nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. From 093e71d4be5d5f9efa7cd02a9eeb15f98be79578 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 1 Dec 2023 08:54:41 +0900 Subject: [PATCH 106/158] Update modules/repository/license.go Co-authored-by: delvh --- modules/repository/license.go | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/repository/license.go b/modules/repository/license.go index 5e25aec266..8c72e3ebce 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -189,6 +189,7 @@ func UpdateRepoLicensesByGitRepo(ctx context.Context, repo *repo_model.Repositor if gitRepo == nil { var err error gitRepo, err = git.OpenRepository(ctx, repo.RepoPath()) + defer gitRepo.close() if err != nil { return fmt.Errorf("OpenRepository: %w", err) } From 13867800c5c6559730b27d03d91d762fb80a174b Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 1 Dec 2023 01:03:12 +0000 Subject: [PATCH 107/158] remove generate licenses in migrations --- models/migrations/v1_22/v283.go | 329 +------------------------------- 1 file changed, 1 insertion(+), 328 deletions(-) diff --git a/models/migrations/v1_22/v283.go b/models/migrations/v1_22/v283.go index b6bb046411..a5152e195e 100644 --- a/models/migrations/v1_22/v283.go +++ b/models/migrations/v1_22/v283.go @@ -4,250 +4,12 @@ package v1_22 //nolint import ( - "fmt" - "path" - "path/filepath" - "strings" - - "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/container" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/json" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/options" - "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" - "code.gitea.io/gitea/modules/util" - licenseclassifier "github.com/google/licenseclassifier/v2" "xorm.io/xorm" ) -var ( - classifier *licenseclassifier.Classifier - licenseAliases map[string]string -) - -// Copy paste from models/repo.go because we cannot import models package -func repoPath(userName, repoName string) string { - return filepath.Join(userPath(userName), strings.ToLower(repoName)+".git") -} - -func userPath(userName string) string { - return filepath.Join(setting.RepoRootPath, strings.ToLower(userName)) -} - -// Copy paste from modules/repository/file.go because we cannot import models package -func findLicenseFile(commit *git.Commit) (string, *git.TreeEntry, error) { - if commit == nil { - return "", nil, nil - } - entries, err := commit.ListEntries() - if err != nil { - return "", nil, fmt.Errorf("ListEntries: %w", err) - } - return findFileInEntries(util.FileTypeLicense, entries, "", "", false) -} - -func findFileInEntries(fileType util.FileType, entries []*git.TreeEntry, treePath, language string, tryWellKnownDirs bool) (string, *git.TreeEntry, error) { - // Create a list of extensions in priority order - // 1. Markdown files - with and without localisation - e.g. README.en-us.md or README.md - // 2. Txt files - e.g. README.txt - // 3. No extension - e.g. README - exts := append(localizedExtensions(".md", language), ".txt", "") // sorted by priority - extCount := len(exts) - targetFiles := make([]*git.TreeEntry, extCount+1) - - docsEntries := make([]*git.TreeEntry, 3) // (one of docs/, .gitea/ or .github/) - for _, entry := range entries { - if tryWellKnownDirs && entry.IsDir() { - // as a special case for the top-level repo introduction README, - // fall back to subfolders, looking for e.g. docs/README.md, .gitea/README.zh-CN.txt, .github/README.txt, ... - // (note that docsEntries is ignored unless we are at the root) - lowerName := strings.ToLower(entry.Name()) - switch lowerName { - case "docs": - if entry.Name() == "docs" || docsEntries[0] == nil { - docsEntries[0] = entry - } - case ".gitea": - if entry.Name() == ".gitea" || docsEntries[1] == nil { - docsEntries[1] = entry - } - case ".github": - if entry.Name() == ".github" || docsEntries[2] == nil { - docsEntries[2] = entry - } - } - continue - } - if i, ok := util.IsFileExtension(entry.Name(), fileType, exts...); ok { - log.Debug("Potential %s file: %s", fileType, entry.Name()) - if targetFiles[i] == nil || base.NaturalSortLess(targetFiles[i].Name(), entry.Blob().Name()) { - if entry.IsLink() { - target, err := entry.FollowLinks() - if err != nil && !git.IsErrBadLink(err) { - return "", nil, err - } else if target != nil && (target.IsExecutable() || target.IsRegular()) { - targetFiles[i] = entry - } - } else { - targetFiles[i] = entry - } - } - } - } - var targetFile *git.TreeEntry - for _, f := range targetFiles { - if f != nil { - targetFile = f - break - } - } - - if treePath == "" && targetFile == nil { - for _, subTreeEntry := range docsEntries { - if subTreeEntry == nil { - continue - } - subTree := subTreeEntry.Tree() - if subTree == nil { - // this should be impossible; if subTreeEntry exists so should this. - continue - } - var err error - childEntries, err := subTree.ListEntries() - if err != nil { - return "", nil, err - } - - subfolder, targetFile, err := findFileInEntries(fileType, childEntries, subTreeEntry.Name(), language, false) - if err != nil && !git.IsErrNotExist(err) { - return "", nil, err - } - if targetFile != nil { - return path.Join(subTreeEntry.Name(), subfolder), targetFile, nil - } - } - } - - return "", targetFile, nil -} - -func localizedExtensions(ext, languageCode string) (localizedExts []string) { - if len(languageCode) < 1 { - return []string{ext} - } - - lowerLangCode := "." + strings.ToLower(languageCode) - - if strings.Contains(lowerLangCode, "-") { - underscoreLangCode := strings.ReplaceAll(lowerLangCode, "-", "_") - indexOfDash := strings.Index(lowerLangCode, "-") - // e.g. [.zh-cn.md, .zh_cn.md, .zh.md, _zh.md, .md] - return []string{lowerLangCode + ext, underscoreLangCode + ext, lowerLangCode[:indexOfDash] + ext, "_" + lowerLangCode[1:indexOfDash] + ext, ext} - } - - // e.g. [.en.md, .md] - return []string{lowerLangCode + ext, ext} -} - -// detectLicenseByEntry returns the licenses detected by the given tree entry -func detectLicenseByEntry(file *git.TreeEntry) ([]string, error) { - if file == nil { - return nil, nil - } - - blob := file.Blob() - content, err := blob.GetBlobContent(setting.UI.MaxDisplayFileSize) - if err != nil { - return nil, fmt.Errorf("GetBlobAll: %w", err) - } - return detectLicense(content), nil -} - -// detectLicense returns the licenses detected by the given content buff -func detectLicense(content string) []string { - if len(content) == 0 { - return nil - } - if classifier == nil { - log.Error("detectLicense: license classifier is null.") - return nil - } - - matches, err := classifier.MatchFrom(strings.NewReader(content)) - if err != nil { - log.Error("licenseclassifier.MatchFrom: %v", err) - return nil - } - if len(matches.Matches) > 0 { - results := make(container.Set[string], len(matches.Matches)) - for _, r := range matches.Matches { - if r.MatchType == "License" && !results.Contains(r.Variant) { - results.Add(r.Variant) - } - } - return results.Values() - } - return nil -} - -func ConvertLicenseName(name string) string { - if licenseAliases == nil { - return name - } - - v, ok := licenseAliases[name] - if ok { - return v - } - return name -} - -func initClassifier() error { - data, err := options.AssetFS().ReadFile("", "license-aliases.json") - if err != nil { - return err - } - err = json.Unmarshal(data, &licenseAliases) - if err != nil { - return err - } - - // threshold should be 0.84~0.86 or the test will be failed - classifier = licenseclassifier.NewClassifier(.85) - licenseFiles, err := options.AssetFS().ListFiles("license", true) - if err != nil { - return err - } - - licenseNameCount := make(map[string]int) - if len(licenseFiles) > 0 { - for _, licenseFile := range licenseFiles { - data, err := options.License(licenseFile) - if err != nil { - return err - } - licenseName := ConvertLicenseName(licenseFile) - licenseNameCount[licenseName]++ - if licenseNameCount[licenseName] > 1 { - continue - } - classifier.AddContent("License", licenseFile, licenseName, data) - } - } - return nil -} - func AddRepositoryLicenses(x *xorm.Engine) error { - type Repository struct { - ID int64 `xorm:"pk autoincr"` - OwnerName string - Name string `xorm:"INDEX NOT NULL"` - DefaultBranch string - } - type RepoLicense struct { ID int64 `xorm:"pk autoincr"` RepoID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"` @@ -257,94 +19,5 @@ func AddRepositoryLicenses(x *xorm.Engine) error { UpdatedUnix timeutil.TimeStamp `xorm:"INDEX UPDATED"` } - if err := x.Sync(new(RepoLicense)); err != nil { - return err - } - - sess := x.NewSession() - defer sess.Close() - - if err := sess.Begin(); err != nil { - return err - } - - repos := make([]*Repository, 0) - if err := sess.Find(&repos); err != nil { - return err - } - - if err := initClassifier(); err != nil { - return err - } - - for _, repo := range repos { - gitRepo, err := git.OpenRepository(git.DefaultContext, repoPath(repo.OwnerName, repo.Name)) - if err != nil { - log.Error("Error whilst opening git repo for [%d]%s/%s. Error: %v", repo.ID, repo.OwnerName, repo.Name, err) - // Allow git repo not exist - continue - } - commit, err := gitRepo.GetBranchCommit(repo.DefaultBranch) - if err != nil { - if git.IsErrNotExist(err) { - continue - } - log.Error("Error whilst getting default branch commit in [%d]%s/%s. Error: %v", repo.ID, repo.OwnerName, repo.Name, err) - return err - } - _, licenseFile, err := findLicenseFile(commit) - if err != nil { - log.Error("Error whilst finding license file in [%d]%s/%s. Error: %v", repo.ID, repo.OwnerName, repo.Name, err) - return err - } - licenses, err := detectLicenseByEntry(licenseFile) - if err != nil { - log.Error("Error whilst detecting license from %s in [%d]%s/%s. Error: %v", licenseFile.Name(), repo.ID, repo.OwnerName, repo.Name, err) - return err - } - - oldLicenses := make([]RepoLicense, 0) - if err := sess.Where("`repo_id` = ?", repo.ID).Asc("`license`").Find(&oldLicenses); err != nil { - return err - } - - for _, license := range licenses { - upd := false - for _, o := range oldLicenses { - // Update already existing license - if o.License == license { - if _, err := sess.ID(o.ID).Cols("`commit_id`").Update(o); err != nil { - log.Error("Error whilst updating [%d]%s/%s license [%s]. Error: %v", repo.ID, repo.OwnerName, repo.Name, license, err) - return err - } - upd = true - break - } - } - // Insert new license - if !upd { - if _, err := sess.Insert(&RepoLicense{ - RepoID: repo.ID, - CommitID: commit.ID.String(), - License: license, - }); err != nil { - log.Error("Error whilst inserting [%d]%s/%s license [%s]. Error: %v", repo.ID, repo.OwnerName, repo.Name, license, err) - return err - } - } - } - // Delete old licenses - licenseToDelete := make([]int64, 0, len(oldLicenses)) - for _, o := range oldLicenses { - if o.CommitID != commit.ID.String() { - licenseToDelete = append(licenseToDelete, o.ID) - } - } - if len(licenseToDelete) > 0 { - if _, err := sess.In("`id`", licenseToDelete).Delete(&RepoLicense{}); err != nil { - return err - } - } - } - return sess.Commit() + return x.Sync(new(RepoLicense)) } From c5296f449cd7b553f020771fe4dff91dc38f16f7 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 1 Dec 2023 01:03:31 +0000 Subject: [PATCH 108/158] improve initClassifier --- modules/repository/license.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/repository/license.go b/modules/repository/license.go index 8c72e3ebce..1346bb1e59 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -67,18 +67,18 @@ func initClassifier() error { return err } - licenseNameCount := make(map[string]int) + existLicense := make(container.Set[string]) if len(licenseFiles) > 0 { for _, licenseFile := range licenseFiles { + licenseName := ConvertLicenseName(licenseFile) + if existLicense.Contains(licenseName) { + continue + } + existLicense.Add(licenseName) data, err := options.License(licenseFile) if err != nil { return err } - licenseName := ConvertLicenseName(licenseFile) - licenseNameCount[licenseName]++ - if licenseNameCount[licenseName] > 1 { - continue - } classifier.AddContent("License", licenseFile, licenseName, data) } } From 121f2b2c29a088052f994f4571f2e7ad004c253a Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 1 Dec 2023 01:06:08 +0000 Subject: [PATCH 109/158] fix --- modules/repository/license.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/repository/license.go b/modules/repository/license.go index 1346bb1e59..5601c973b7 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -189,10 +189,10 @@ func UpdateRepoLicensesByGitRepo(ctx context.Context, repo *repo_model.Repositor if gitRepo == nil { var err error gitRepo, err = git.OpenRepository(ctx, repo.RepoPath()) - defer gitRepo.close() if err != nil { return fmt.Errorf("OpenRepository: %w", err) } + defer gitRepo.Close() } commit, err := gitRepo.GetBranchCommit(repo.DefaultBranch) if err != nil { From c97caf8b080515821d9e7ae4ea3d6ac6bb92bd41 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 1 Dec 2023 01:46:07 +0000 Subject: [PATCH 110/158] improve --- models/repo/license.go | 10 ++-------- services/repository/fork.go | 2 +- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/models/repo/license.go b/models/repo/license.go index 93050a70b9..08fc00cf81 100644 --- a/models/repo/license.go +++ b/models/repo/license.go @@ -89,13 +89,7 @@ func UpdateRepoLicenses(ctx context.Context, repo *Repository, commitID string, } // CopyLicense Copy originalRepo license information to destRepo (use for forked repo) -func CopyLicense(originalRepo, destRepo *Repository) error { - ctx, committer, err := db.TxContext(db.DefaultContext) - if err != nil { - return err - } - defer committer.Close() - +func CopyLicense(ctx context.Context, originalRepo, destRepo *Repository) error { repoLicenses, err := GetRepoLicenses(ctx, originalRepo) if err != nil { return err @@ -118,5 +112,5 @@ func CopyLicense(originalRepo, destRepo *Repository) error { return err } } - return committer.Commit() + return nil } diff --git a/services/repository/fork.go b/services/repository/fork.go index f62c2692aa..f2a61d4bae 100644 --- a/services/repository/fork.go +++ b/services/repository/fork.go @@ -188,7 +188,7 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork if err := repo_model.CopyLanguageStat(ctx, opts.BaseRepo, repo); err != nil { log.Error("Copy language stat from oldRepo failed: %v", err) } - if err := repo_model.CopyLicense(opts.BaseRepo, repo); err != nil { + if err := repo_model.CopyLicense(ctx, opts.BaseRepo, repo); err != nil { return nil, err } From 727d5ccdc80d8cd0e3a80a2ee511382523061cc8 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 4 Dec 2023 02:52:14 +0000 Subject: [PATCH 111/158] add cron task --- modules/repository/license.go | 4 ++++ options/locale/locale_en-US.ini | 1 + services/cron/tasks_basic.go | 11 ++++++++++ services/repository/licenses.go | 36 +++++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+) create mode 100644 services/repository/licenses.go diff --git a/modules/repository/license.go b/modules/repository/license.go index 5601c973b7..7a25ae1fd5 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -196,6 +196,10 @@ func UpdateRepoLicensesByGitRepo(ctx context.Context, repo *repo_model.Repositor } commit, err := gitRepo.GetBranchCommit(repo.DefaultBranch) if err != nil { + if git.IsErrNotExist(err) { + // allow empty repo + return nil + } return err } return UpdateRepoLicenses(ctx, repo, commit) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 2eb4df1f15..cbc802899a 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -2789,6 +2789,7 @@ dashboard.cancel_abandoned_jobs = Cancel abandoned jobs dashboard.start_schedule_tasks = Start schedule tasks dashboard.sync_branch.started = Branches Sync started dashboard.rebuild_issue_indexer = Rebuild issue indexer +dashboard.sync_repo_licenses = Sync Repo Licenses users.user_manage_panel = User Account Management users.new_account = Create User Account diff --git a/services/cron/tasks_basic.go b/services/cron/tasks_basic.go index 3869382d22..c67f78dbea 100644 --- a/services/cron/tasks_basic.go +++ b/services/cron/tasks_basic.go @@ -171,6 +171,16 @@ func registerActionsCleanup() { }) } +func registerSyncRepoLicenses() { + RegisterTaskFatal("sync_repo_licenses", &BaseConfig{ + Enabled: false, + RunAtStart: false, + Schedule: "@annually", + }, func(ctx context.Context, _ *user_model.User, config Config) error { + return repo_service.SyncRepoLicenses(ctx) + }) +} + func initBasicTasks() { if setting.Mirror.Enabled { registerUpdateMirrorTask() @@ -190,4 +200,5 @@ func initBasicTasks() { if setting.Actions.Enabled { registerActionsCleanup() } + registerSyncRepoLicenses() } diff --git a/services/repository/licenses.go b/services/repository/licenses.go new file mode 100644 index 0000000000..2c0e18d62b --- /dev/null +++ b/services/repository/licenses.go @@ -0,0 +1,36 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package repository + +import ( + "context" + + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/log" + repo_module "code.gitea.io/gitea/modules/repository" +) + +func SyncRepoLicenses(ctx context.Context) error { + log.Trace("Doing: SyncRepoLicenses") + + if err := db.Iterate( + ctx, + nil, + func(ctx context.Context, repo *repo_model.Repository) error { + select { + case <-ctx.Done(): + return db.ErrCancelledf("before sync repo licenses for %s", repo.FullName()) + default: + } + return repo_module.UpdateRepoLicensesByGitRepo(ctx, repo, nil) + }, + ); err != nil { + log.Trace("Error: SyncRepoLicenses: %v", err) + return err + } + + log.Trace("Finished: SyncReposLicenses") + return nil +} From da365540d4f9ac0d4101b77fc27a732c83846ae6 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 4 Dec 2023 02:56:58 +0000 Subject: [PATCH 112/158] use ctx.Locale.Tr --- templates/repo/sub_menu.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/repo/sub_menu.tmpl b/templates/repo/sub_menu.tmpl index e8622dac2a..339360b1dc 100644 --- a/templates/repo/sub_menu.tmpl +++ b/templates/repo/sub_menu.tmpl @@ -15,7 +15,7 @@ {{end}} {{if .DetectedRepoLicenses}} - {{svg "octicon-law"}} {{if eq (len .DetectedRepoLicenses) 1}}{{index .DetectedRepoLicenses 0}}{{else}}{{.locale.Tr "repo.multiple_licenses"}}{{end}} + {{svg "octicon-law"}} {{if eq (len .DetectedRepoLicenses) 1}}{{index .DetectedRepoLicenses 0}}{{else}}{{ctx.Locale.Tr "repo.multiple_licenses"}}{{end}} {{end}} From 3e45a9a3d69051670c4a4a8022702d99c7b457d1 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 4 Dec 2023 13:15:59 +0900 Subject: [PATCH 113/158] Update models/repo/license.go Co-authored-by: delvh --- models/repo/license.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/models/repo/license.go b/models/repo/license.go index 08fc00cf81..adcb1a876f 100644 --- a/models/repo/license.go +++ b/models/repo/license.go @@ -97,14 +97,11 @@ func CopyLicense(ctx context.Context, originalRepo, destRepo *Repository) error if len(repoLicenses) > 0 { newRepoLicenses := make(RepoLicenseList, 0, len(repoLicenses)) - time := timeutil.TimeStampNow() for _, rl := range repoLicenses { newRepoLicense := &RepoLicense{ RepoID: destRepo.ID, CommitID: rl.CommitID, License: rl.License, - CreatedUnix: time, - UpdatedUnix: time, } newRepoLicenses = append(newRepoLicenses, newRepoLicense) } From 7621d98006ba6dab07747913d9e37ae9b375dd89 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 6 Dec 2023 01:21:13 +0000 Subject: [PATCH 114/158] fix lint --- models/repo/license.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/models/repo/license.go b/models/repo/license.go index adcb1a876f..cd35e448fd 100644 --- a/models/repo/license.go +++ b/models/repo/license.go @@ -99,9 +99,9 @@ func CopyLicense(ctx context.Context, originalRepo, destRepo *Repository) error for _, rl := range repoLicenses { newRepoLicense := &RepoLicense{ - RepoID: destRepo.ID, - CommitID: rl.CommitID, - License: rl.License, + RepoID: destRepo.ID, + CommitID: rl.CommitID, + License: rl.License, } newRepoLicenses = append(newRepoLicenses, newRepoLicense) } From d501891dac96b6f3e20acf50f011f8f27749e30d Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 6 Dec 2023 01:55:58 +0000 Subject: [PATCH 115/158] fix test --- tests/integration/api_admin_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/api_admin_test.go b/tests/integration/api_admin_test.go index aae9ec4a24..03a34b2e76 100644 --- a/tests/integration/api_admin_test.go +++ b/tests/integration/api_admin_test.go @@ -298,7 +298,7 @@ func TestAPICron(t *testing.T) { req := NewRequest(t, "GET", urlStr) resp := MakeRequest(t, req, http.StatusOK) - assert.Equal(t, "28", resp.Header().Get("X-Total-Count")) + assert.Equal(t, "29", resp.Header().Get("X-Total-Count")) var crons []api.Cron DecodeJSON(t, resp, &crons) From 8e0929eebd92f40aef06365f10b969628f3ff39a Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 8 Dec 2023 03:00:32 +0000 Subject: [PATCH 116/158] fix test --- tests/integration/api_admin_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/api_admin_test.go b/tests/integration/api_admin_test.go index 03a34b2e76..10f1550433 100644 --- a/tests/integration/api_admin_test.go +++ b/tests/integration/api_admin_test.go @@ -302,7 +302,7 @@ func TestAPICron(t *testing.T) { var crons []api.Cron DecodeJSON(t, resp, &crons) - assert.Len(t, crons, 28) + assert.Len(t, crons, 29) }) t.Run("Execute", func(t *testing.T) { From db2e9ebcef9037ee339751911a604503b43362cf Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 17 Jan 2024 04:22:47 +0000 Subject: [PATCH 117/158] remove add update repo license notify todo --- routers/web/repo/setting/default_branch.go | 1 - 1 file changed, 1 deletion(-) diff --git a/routers/web/repo/setting/default_branch.go b/routers/web/repo/setting/default_branch.go index 7cd58e3b06..bdf95ce2c1 100644 --- a/routers/web/repo/setting/default_branch.go +++ b/routers/web/repo/setting/default_branch.go @@ -56,7 +56,6 @@ func SetDefaultBranchPost(ctx *context.Context) { ctx.ServerError("UpdateRepoLicenses", err) return } - // TODO: add notify_service.ChangeRepoLicenses } log.Trace("Repository basic settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name) From 030c0dda2f829aa8e2cc3970b75d97d25e6c268d Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 17 Jan 2024 04:26:13 +0000 Subject: [PATCH 118/158] rename to v285 --- models/migrations/v1_22/{v283.go => v285.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename models/migrations/v1_22/{v283.go => v285.go} (100%) diff --git a/models/migrations/v1_22/v283.go b/models/migrations/v1_22/v285.go similarity index 100% rename from models/migrations/v1_22/v283.go rename to models/migrations/v1_22/v285.go From 5e72897db8cb62b544e80f29bc2c1272002b9423 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 17 Jan 2024 04:47:56 +0000 Subject: [PATCH 119/158] fix changes from 28691 --- routers/web/repo/setting/default_branch.go | 3 +-- services/repository/branch.go | 5 ++++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/routers/web/repo/setting/default_branch.go b/routers/web/repo/setting/default_branch.go index 9eb8a26c0b..11c43aa69a 100644 --- a/routers/web/repo/setting/default_branch.go +++ b/routers/web/repo/setting/default_branch.go @@ -9,7 +9,6 @@ import ( git_model "code.gitea.io/gitea/models/git" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" - repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/routers/web/repo" repo_service "code.gitea.io/gitea/services/repository" @@ -35,7 +34,7 @@ func SetDefaultBranchPost(ctx *context.Context) { } branch := ctx.FormString("branch") - if err := repo_service.SetRepoDefaultBranch(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, branch); err != nil { + if err := repo_service.SetRepoDefaultBranch(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, ctx.Repo.Commit, branch); err != nil { switch { case git_model.IsErrBranchNotExist(err): ctx.Status(http.StatusNotFound) diff --git a/services/repository/branch.go b/services/repository/branch.go index 6ddc6badfa..0f15506691 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -468,7 +468,7 @@ func AddAllRepoBranchesToSyncQueue(ctx context.Context, doerID int64) error { return nil } -func SetRepoDefaultBranch(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, newBranchName string) error { +func SetRepoDefaultBranch(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, commit *git.Commit, newBranchName string) error { if repo.DefaultBranch == newBranchName { return nil } @@ -505,6 +505,9 @@ func SetRepoDefaultBranch(ctx context.Context, repo *repo_model.Repository, gitR return err } } + if err := repo_module.UpdateRepoLicenses(ctx, repo, commit); err != nil { + log.Error("UpdateRepoLicenses: %v", err) + } return nil }); err != nil { return err From 3ef4aa814d52cb24c24ac7c760465258782731a0 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 18 Jan 2024 00:33:54 +0000 Subject: [PATCH 120/158] improve --- build/generate-licenses.go | 122 ++++++---------------------- options/license/Caldera-no-preamble | 35 ++++++++ options/license/HPND-MIT-disclaimer | 18 ++++ 3 files changed, 79 insertions(+), 96 deletions(-) create mode 100644 options/license/Caldera-no-preamble create mode 100644 options/license/HPND-MIT-disclaimer diff --git a/build/generate-licenses.go b/build/generate-licenses.go index d68b8b596e..9aa3043b5d 100644 --- a/build/generate-licenses.go +++ b/build/generate-licenses.go @@ -4,9 +4,9 @@ package main import ( "archive/tar" - "bytes" "compress/gzip" "crypto/md5" + "encoding/hex" "flag" "fmt" "io" @@ -15,7 +15,6 @@ import ( "os" "path" "path/filepath" - "slices" "strings" "code.gitea.io/gitea/modules/json" @@ -83,9 +82,7 @@ func main() { } tr := tar.NewReader(gz) - var preFile *os.File - var preLicenseName string - sameFiles := make(map[string][]string) + aliasesFiles := make(map[string][]string) for { hdr, err := tr.Next() @@ -122,121 +119,54 @@ func main() { defer out.Close() - if _, err := io.Copy(out, tr); err != nil { + // some license files have same content, so we need to detect these files and create a convert map into a json file + // In functuion initClassifier, we use this convert map to avoid adding same license content with different license name + h := md5.New() + // calculate md5 and write file in the same time + r := io.TeeReader(tr, h) + if _, err := io.Copy(out, r); err != nil { log.Fatalf("Failed to write new file. %s", err) } else { fmt.Printf("Written %s\n", out.Name()) - // some license files have same content, so we need to detect these files and create a convert map into a file - // In InitClassifier, we will use this convert map to avoid adding same license content with different license name - md5, err := getSameFileMD5(preFile, out) - if err != nil { - log.Fatalf("Failed to get same file md5. %s", err) - continue + md5 := hex.EncodeToString(h.Sum(nil)) + if _, ok := aliasesFiles[md5]; ok { + aliasesFiles[md5] = append(aliasesFiles[md5], licenseName) + } else { + aliasesFiles[md5] = []string{licenseName} } - if md5 != "" { - _, ok := sameFiles[md5] - if !ok { - sameFiles[md5] = make([]string, 0) - } - if !slices.Contains(sameFiles[md5], preLicenseName) { - sameFiles[md5] = append(sameFiles[md5], preLicenseName) - } - sameFiles[md5] = append(sameFiles[md5], licenseName) - } - preFile = out - preLicenseName = licenseName } } // generate convert license name map licenseAliases := make(map[string]string) - for _, fileNames := range sameFiles { - key := getLicenseKey(fileNames) - for _, fileName := range fileNames { - licenseAliases[fileName] = key + for _, fileNames := range aliasesFiles { + if len(fileNames) > 1 { + licenseName := getLicenseNameFromAliases(fileNames) + for _, fileName := range fileNames { + licenseAliases[fileName] = licenseName + } } } // save convert license name map to file - bytes, err := json.Marshal(licenseAliases) + b, err := json.Marshal(licenseAliases) if err != nil { log.Fatalf("Failed to create json bytes. %s", err) return } - out, err := os.Create(licenseAliasesDestination) + f, err := os.Create(licenseAliasesDestination) if err != nil { - log.Fatalf("Failed to create new file. %s", err) + log.Fatalf("Failed to create license aliases json file. %s", err) } - defer out.Close() - _, err = out.Write(bytes) - if err != nil { - log.Fatalf("Failed to write same licenses json file. %s", err) + defer f.Close() + if _, err = f.Write(b); err != nil { + log.Fatalf("Failed to write license aliases json file. %s", err) } fmt.Println("Done") } -// getSameFileMD5 returns md5 of the input file, if the content of input files are same -func getSameFileMD5(f1, f2 *os.File) (string, error) { - if f1 == nil || f2 == nil { - return "", nil - } - - // check file size - fs1, err := f1.Stat() - if err != nil { - return "", err - } - fs2, err := f2.Stat() - if err != nil { - return "", err - } - - if fs1.Size() != fs2.Size() { - return "", nil - } - - // check content - chunkSize := 1024 - _, err = f1.Seek(0, 0) - if err != nil { - return "", err - } - _, err = f2.Seek(0, 0) - if err != nil { - return "", err - } - - var totalBytes []byte - for { - b1 := make([]byte, chunkSize) - _, err1 := f1.Read(b1) - - b2 := make([]byte, chunkSize) - _, err2 := f2.Read(b2) - - totalBytes = append(totalBytes, b1...) - - if err1 != nil || err2 != nil { - if err1 == io.EOF && err2 == io.EOF { - md5 := md5.Sum(totalBytes) - return string(md5[:]), nil - } else if err1 == io.EOF || err2 == io.EOF { - return "", nil - } else if err1 != nil { - return "", err1 - } else if err2 != nil { - return "", err2 - } - } - - if !bytes.Equal(b1, b2) { - return "", nil - } - } -} - -func getLicenseKey(fnl []string) string { +func getLicenseNameFromAliases(fnl []string) string { if len(fnl) == 0 { return "" } diff --git a/options/license/Caldera-no-preamble b/options/license/Caldera-no-preamble new file mode 100644 index 0000000000..f70f34b32b --- /dev/null +++ b/options/license/Caldera-no-preamble @@ -0,0 +1,35 @@ +Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +Redistributions of source code and documentation must retain the above +copyright notice, this list of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +All advertising materials mentioning features or use of this software +must display the following acknowledgement: + + This product includes software developed or owned by Caldera + International, Inc. + +Neither the name of Caldera International, Inc. nor the names of other +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA +INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN +NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, +INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/options/license/HPND-MIT-disclaimer b/options/license/HPND-MIT-disclaimer new file mode 100644 index 0000000000..bf035915cf --- /dev/null +++ b/options/license/HPND-MIT-disclaimer @@ -0,0 +1,18 @@ + LICENSE + ======= + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, provided +that the original copyright notices appear in all copies and that both +copyright notice and this permission notice appear in supporting +documentation, and that the name of the author not be used in advertising +or publicity pertaining to distribution of the software without specific +prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. From cc3cf074b90745f0745bf0198aee413bb5ebcf93 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 18 Jan 2024 00:40:39 +0000 Subject: [PATCH 121/158] fix comment --- modules/repository/license.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/repository/license.go b/modules/repository/license.go index 7a25ae1fd5..4259ec4445 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -184,7 +184,7 @@ func getLicensePlaceholder(name string) *licensePlaceholder { return ret } -// UpdateRepoLicenses will update repository licenses col if license file exists +// UpdateRepoLicensesByGitRepo will update repository licenses col if license file exists func UpdateRepoLicensesByGitRepo(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository) error { if gitRepo == nil { var err error From aabb200ea56d7e7df4b26b528439121b866069e7 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 18 Jan 2024 00:42:57 +0000 Subject: [PATCH 122/158] fix --- modules/repository/license.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/repository/license.go b/modules/repository/license.go index 4259ec4445..9501397fe4 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -95,7 +95,7 @@ type LicenseValues struct { func GetLicense(name string, values *LicenseValues) ([]byte, error) { data, err := options.License(name) if err != nil { - return nil, fmt.Errorf("GetRepoInitFile[%s]: %w", name, err) + return nil, fmt.Errorf("GetLicense[%s]: %w", name, err) } return fillLicensePlaceholder(name, values, data), nil } @@ -227,7 +227,7 @@ func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository, commit return fmt.Errorf("detectLicense: %w", err) } if err := repo_model.UpdateRepoLicenses(ctx, repo, commit.ID.String(), licenses); err != nil { - return fmt.Errorf("UpdateRepositoryCols: %v", err) + return fmt.Errorf("UpdateRepoLicenses: %v", err) } } return nil From a0e8a5db7578bf2593bf49694c6cf7881d156f2f Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 22 Feb 2024 15:22:44 +0900 Subject: [PATCH 123/158] Update build/generate-licenses.go Co-authored-by: KN4CK3R --- build/generate-licenses.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/build/generate-licenses.go b/build/generate-licenses.go index 9aa3043b5d..a85a5fa7dd 100644 --- a/build/generate-licenses.go +++ b/build/generate-licenses.go @@ -130,11 +130,7 @@ func main() { fmt.Printf("Written %s\n", out.Name()) md5 := hex.EncodeToString(h.Sum(nil)) - if _, ok := aliasesFiles[md5]; ok { - aliasesFiles[md5] = append(aliasesFiles[md5], licenseName) - } else { - aliasesFiles[md5] = []string{licenseName} - } + aliasesFiles[md5] = append(aliasesFiles[md5], licenseName) } } From 86f8bec0276bf3e1f52ed8e13d6828a7421a6657 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 22 Feb 2024 15:22:49 +0900 Subject: [PATCH 124/158] Update build/generate-licenses.go Co-authored-by: KN4CK3R --- build/generate-licenses.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/generate-licenses.go b/build/generate-licenses.go index a85a5fa7dd..88e66903d9 100644 --- a/build/generate-licenses.go +++ b/build/generate-licenses.go @@ -120,7 +120,7 @@ func main() { defer out.Close() // some license files have same content, so we need to detect these files and create a convert map into a json file - // In functuion initClassifier, we use this convert map to avoid adding same license content with different license name + // Later we use this convert map to avoid adding same license content with different license name h := md5.New() // calculate md5 and write file in the same time r := io.TeeReader(tr, h) From 841453d787aac25b34b9e78892ca0119530452ce Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 22 Feb 2024 06:25:06 +0000 Subject: [PATCH 125/158] convert v285 to v287 --- models/migrations/migrations.go | 2 +- models/migrations/v1_22/{v285.go => v287.go} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename models/migrations/v1_22/{v285.go => v287.go} (100%) diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 9c3c495b84..ca38f9b41f 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -554,7 +554,7 @@ var migrations = []Migration{ NewMigration("Add combined Index to issue_user.uid and issue_id", v1_22.AddCombinedIndexToIssueUser), // v284 -> v285 NewMigration("Add ignore stale approval column on branch table", v1_22.AddIgnoreStaleApprovalsColumnToProtectedBranchTable), - // v285 -> v286 + // v287 -> v288 NewMigration("Add Repository Licenses", v1_22.AddRepositoryLicenses), } diff --git a/models/migrations/v1_22/v285.go b/models/migrations/v1_22/v287.go similarity index 100% rename from models/migrations/v1_22/v285.go rename to models/migrations/v1_22/v287.go From baa29d4df6f8017e13fac56212ef001885782d75 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 22 Feb 2024 06:28:54 +0000 Subject: [PATCH 126/158] update license --- options/license/MIT-Khronos-old | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 options/license/MIT-Khronos-old diff --git a/options/license/MIT-Khronos-old b/options/license/MIT-Khronos-old new file mode 100644 index 0000000000..430863bc98 --- /dev/null +++ b/options/license/MIT-Khronos-old @@ -0,0 +1,23 @@ +Copyright (c) 2014-2020 The Khronos Group Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and/or associated documentation files (the "Materials"), +to deal in the Materials without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Materials, and to permit persons to whom the +Materials are furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Materials. + +MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS +STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND +HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ + +THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS +IN THE MATERIALS. From 7d92e475e1264f0d8b20d0cc250e8d771c097dd3 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 26 Feb 2024 08:11:57 +0000 Subject: [PATCH 127/158] use queue --- modules/repository/license.go | 89 +++++++++++++++++++++------- modules/repository/repo.go | 5 +- routers/init.go | 3 + routers/private/default_branch.go | 5 +- routers/private/hook_post_receive.go | 7 ++- services/mirror/mirror_pull.go | 6 +- services/repository/branch.go | 7 ++- services/repository/licenses.go | 2 +- 8 files changed, 89 insertions(+), 35 deletions(-) diff --git a/modules/repository/license.go b/modules/repository/license.go index 9501397fe4..fc9e9b8543 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -15,8 +15,11 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/options" + "code.gitea.io/gitea/modules/queue" "code.gitea.io/gitea/modules/util" licenseclassifier "github.com/google/licenseclassifier/v2" @@ -25,8 +28,69 @@ import ( var ( classifier *licenseclassifier.Classifier licenseAliases map[string]string + + // licenseUpdaterQueue represents a queue to handle update repo licenses + licenseUpdaterQueue *queue.WorkerPoolQueue[*LicenseUpdaterOptions] ) +func Init() error { + licenseUpdaterQueue = queue.CreateUniqueQueue(graceful.GetManager().ShutdownContext(), "repo_license_updater", repoLicenseUpdater) + if licenseUpdaterQueue == nil { + return fmt.Errorf("unable to create repo_license_updater queue") + } + go graceful.GetManager().RunWithCancel(licenseUpdaterQueue) + return nil +} + +type LicenseUpdaterOptions struct { + RepoID int64 + CommitID string +} + +func repoLicenseUpdater(items ...*LicenseUpdaterOptions) []*LicenseUpdaterOptions { + ctx := graceful.GetManager().ShutdownContext() + + for _, opts := range items { + repo, err := repo_model.GetRepositoryByID(ctx, opts.RepoID) + if err != nil { + log.Error("repoLicenseUpdater [%d] failed: GetRepositoryByID: %v", opts.RepoID, err) + continue + } + if repo.IsEmpty { + continue + } + + gitRepo, err := git.OpenRepository(ctx, repo.RepoPath()) + if err != nil { + log.Error("repoLicenseUpdater [%d] failed: OpenRepository: %v", opts.RepoID, err) + continue + } + defer gitRepo.Close() + + var commit *git.Commit + if opts.CommitID != "" { + commit, err = gitRepo.GetCommit(opts.CommitID) + } else { + commit, err = gitRepo.GetBranchCommit(repo.DefaultBranch) + } + if err != nil { + log.Error("repoLicenseUpdater [%d] failed: OpenRepository: %v", opts.RepoID, err) + continue + } + if err = updateRepoLicenses(ctx, repo, commit); err != nil { + log.Error("repoLicenseUpdater [%d] failed: updateRepoLicenses: %v", opts.RepoID, err) + } + } + return nil +} + +func AddRepoToLicenseUpdaterQueue(opts *LicenseUpdaterOptions) error { + if opts == nil { + return nil + } + return licenseUpdaterQueue.Push(opts) +} + func loadLicenseAliases() error { if licenseAliases != nil { return nil @@ -184,29 +248,8 @@ func getLicensePlaceholder(name string) *licensePlaceholder { return ret } -// UpdateRepoLicensesByGitRepo will update repository licenses col if license file exists -func UpdateRepoLicensesByGitRepo(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository) error { - if gitRepo == nil { - var err error - gitRepo, err = git.OpenRepository(ctx, repo.RepoPath()) - if err != nil { - return fmt.Errorf("OpenRepository: %w", err) - } - defer gitRepo.Close() - } - commit, err := gitRepo.GetBranchCommit(repo.DefaultBranch) - if err != nil { - if git.IsErrNotExist(err) { - // allow empty repo - return nil - } - return err - } - return UpdateRepoLicenses(ctx, repo, commit) -} - -// UpdateRepoLicenses will update repository licenses col if license file exists -func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository, commit *git.Commit) error { +// updateRepoLicenses will update repository licenses col if license file exists +func updateRepoLicenses(ctx context.Context, repo *repo_model.Repository, commit *git.Commit) error { if commit == nil { return nil } diff --git a/modules/repository/repo.go b/modules/repository/repo.go index 38764539f2..57cd700607 100644 --- a/modules/repository/repo.go +++ b/modules/repository/repo.go @@ -174,9 +174,8 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User, } // Update repo license - err = UpdateRepoLicensesByGitRepo(ctx, repo, gitRepo) - if err != nil { - return repo, fmt.Errorf("UpdateRepoLicensesByGitRepo: %w", err) + if err := AddRepoToLicenseUpdaterQueue(&LicenseUpdaterOptions{RepoID: repo.ID}); err != nil { + log.Error("Failed to add repo to license updater queue: %v", err) } } diff --git a/routers/init.go b/routers/init.go index e0a7150ba3..584e0c7e16 100644 --- a/routers/init.go +++ b/routers/init.go @@ -18,6 +18,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/external" + "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/ssh" "code.gitea.io/gitea/modules/storage" @@ -166,6 +167,8 @@ func InitWebInstalled(ctx context.Context) { actions_service.Init() + mustInit(repository.Init) + // Finally start up the cron cron.NewContext(ctx) } diff --git a/routers/private/default_branch.go b/routers/private/default_branch.go index 8963bce641..597a10f7f8 100644 --- a/routers/private/default_branch.go +++ b/routers/private/default_branch.go @@ -37,7 +37,10 @@ func SetDefaultBranch(ctx *gitea_context.PrivateContext) { return } - if err := repo_module.UpdateRepoLicenses(ctx, ctx.Repo.Repository, ctx.Repo.Commit); err != nil { + if err := repo_module.AddRepoToLicenseUpdaterQueue(&repo_module.LicenseUpdaterOptions{ + RepoID: ctx.Repo.Repository.ID, + CommitID: ctx.Repo.Commit.ID.String(), + }); err != nil { ctx.JSON(http.StatusInternalServerError, private.Response{ Err: fmt.Sprintf("Unable to set default branch on repository: %s/%s Error: %v", ownerName, repoName, err), }) diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go index 523a11f76b..e67ba1febd 100644 --- a/routers/private/hook_post_receive.go +++ b/routers/private/hook_post_receive.go @@ -159,7 +159,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { } // If we've pushed a branch (and not deleted it) - if git.IsEmptyCommitID(newCommitID) && refFullName.IsBranch() { + if !git.IsEmptyCommitID(newCommitID) && refFullName.IsBranch() { // First ensure we have the repository loaded, we're allowed pulls requests and we can get the base repo if repo == nil { repo = loadRepository(ctx, ownerName, repoName) @@ -195,8 +195,9 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { branch := refFullName.BranchName() if branch == baseRepo.DefaultBranch { - err := repo_module.UpdateRepoLicensesByGitRepo(ctx, repo, nil) - if err != nil { + if err := repo_module.AddRepoToLicenseUpdaterQueue(&repo_module.LicenseUpdaterOptions{ + RepoID: repo.ID, + }); err != nil { ctx.JSON(http.StatusInternalServerError, private.Response{Err: err.Error()}) return } diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go index aa9e196daf..a26e571f74 100644 --- a/services/mirror/mirror_pull.go +++ b/services/mirror/mirror_pull.go @@ -550,8 +550,10 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { } // Update License - if err = repo_module.UpdateRepoLicensesByGitRepo(ctx, m.Repo, gitRepo); err != nil { - log.Error("SyncMirrors [repo: %-v]: unable to update repository 'licenses': %v", m.Repo, err) + if err = repo_module.AddRepoToLicenseUpdaterQueue(&repo_module.LicenseUpdaterOptions{ + RepoID: m.Repo.ID, + }); err != nil { + log.Error("SyncMirrors [repo: %-v]: unable to add repo to license updater queue: %v", m.Repo, err) return false } diff --git a/services/repository/branch.go b/services/repository/branch.go index 7dc412b26e..c0f302e2eb 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -499,8 +499,11 @@ func SetRepoDefaultBranch(ctx context.Context, repo *repo_model.Repository, gitR return err } } - if err := repo_module.UpdateRepoLicenses(ctx, repo, commit); err != nil { - log.Error("UpdateRepoLicenses: %v", err) + if err := repo_module.AddRepoToLicenseUpdaterQueue(&repo_module.LicenseUpdaterOptions{ + RepoID: repo.ID, + CommitID: commit.ID.String(), + }); err != nil { + log.Error("AddRepoToLicenseUpdaterQueue: %v", err) } return nil }); err != nil { diff --git a/services/repository/licenses.go b/services/repository/licenses.go index 2c0e18d62b..1ea1be68cc 100644 --- a/services/repository/licenses.go +++ b/services/repository/licenses.go @@ -24,7 +24,7 @@ func SyncRepoLicenses(ctx context.Context) error { return db.ErrCancelledf("before sync repo licenses for %s", repo.FullName()) default: } - return repo_module.UpdateRepoLicensesByGitRepo(ctx, repo, nil) + return repo_module.AddRepoToLicenseUpdaterQueue(&repo_module.LicenseUpdaterOptions{RepoID: repo.ID}) }, ); err != nil { log.Trace("Error: SyncRepoLicenses: %v", err) From c79fbaa6e500de7ba2d13e4d3e50065fa20a477e Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 26 Feb 2024 08:28:27 +0000 Subject: [PATCH 128/158] fix not remove old records when license file not detected after branch change --- modules/repository/license.go | 22 ++++++++-------------- routers/private/default_branch.go | 3 +-- services/repository/branch.go | 12 ++++++------ 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/modules/repository/license.go b/modules/repository/license.go index fc9e9b8543..1f447703d8 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -43,8 +43,7 @@ func Init() error { } type LicenseUpdaterOptions struct { - RepoID int64 - CommitID string + RepoID int64 } func repoLicenseUpdater(items ...*LicenseUpdaterOptions) []*LicenseUpdaterOptions { @@ -67,14 +66,9 @@ func repoLicenseUpdater(items ...*LicenseUpdaterOptions) []*LicenseUpdaterOption } defer gitRepo.Close() - var commit *git.Commit - if opts.CommitID != "" { - commit, err = gitRepo.GetCommit(opts.CommitID) - } else { - commit, err = gitRepo.GetBranchCommit(repo.DefaultBranch) - } + commit, err := gitRepo.GetBranchCommit(repo.DefaultBranch) if err != nil { - log.Error("repoLicenseUpdater [%d] failed: OpenRepository: %v", opts.RepoID, err) + log.Error("repoLicenseUpdater [%d] failed: GetBranchCommit: %v", opts.RepoID, err) continue } if err = updateRepoLicenses(ctx, repo, commit); err != nil { @@ -258,6 +252,8 @@ func updateRepoLicenses(ctx context.Context, repo *repo_model.Repository, commit if err != nil { return fmt.Errorf("findLicenseFile: %w", err) } + + licenses := make([]string, 0) if licenseFile != nil { r, err := licenseFile.Blob().DataAsync() if err != nil { @@ -265,15 +261,13 @@ func updateRepoLicenses(ctx context.Context, repo *repo_model.Repository, commit } defer r.Close() - licenses, err := detectLicense(r) + licenses, err = detectLicense(r) if err != nil { return fmt.Errorf("detectLicense: %w", err) } - if err := repo_model.UpdateRepoLicenses(ctx, repo, commit.ID.String(), licenses); err != nil { - return fmt.Errorf("UpdateRepoLicenses: %v", err) - } + } - return nil + return repo_model.UpdateRepoLicenses(ctx, repo, commit.ID.String(), licenses) } // GetDetectedLicenseFileName returns license file name in the repository if it exists diff --git a/routers/private/default_branch.go b/routers/private/default_branch.go index 597a10f7f8..0ed11963c6 100644 --- a/routers/private/default_branch.go +++ b/routers/private/default_branch.go @@ -38,8 +38,7 @@ func SetDefaultBranch(ctx *gitea_context.PrivateContext) { } if err := repo_module.AddRepoToLicenseUpdaterQueue(&repo_module.LicenseUpdaterOptions{ - RepoID: ctx.Repo.Repository.ID, - CommitID: ctx.Repo.Commit.ID.String(), + RepoID: ctx.Repo.Repository.ID, }); err != nil { ctx.JSON(http.StatusInternalServerError, private.Response{ Err: fmt.Sprintf("Unable to set default branch on repository: %s/%s Error: %v", ownerName, repoName, err), diff --git a/services/repository/branch.go b/services/repository/branch.go index c0f302e2eb..f6c5ed4448 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -499,17 +499,17 @@ func SetRepoDefaultBranch(ctx context.Context, repo *repo_model.Repository, gitR return err } } - if err := repo_module.AddRepoToLicenseUpdaterQueue(&repo_module.LicenseUpdaterOptions{ - RepoID: repo.ID, - CommitID: commit.ID.String(), - }); err != nil { - log.Error("AddRepoToLicenseUpdaterQueue: %v", err) - } return nil }); err != nil { return err } + if err := repo_module.AddRepoToLicenseUpdaterQueue(&repo_module.LicenseUpdaterOptions{ + RepoID: repo.ID, + }); err != nil { + log.Error("AddRepoToLicenseUpdaterQueue: %v", err) + } + notify_service.ChangeDefaultBranch(ctx, repo) return nil From fe77ff5429e7bc218a07fdb19bb5b4b4eeca055a Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Mon, 26 Feb 2024 08:29:46 +0000 Subject: [PATCH 129/158] remove unnecessary enter --- modules/repository/license.go | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/repository/license.go b/modules/repository/license.go index 1f447703d8..832afca5e9 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -265,7 +265,6 @@ func updateRepoLicenses(ctx context.Context, repo *repo_model.Repository, commit if err != nil { return fmt.Errorf("detectLicense: %w", err) } - } return repo_model.UpdateRepoLicenses(ctx, repo, commit.ID.String(), licenses) } From 882767c2bae74bf949663131a00f55b93aa37315 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 27 Feb 2024 01:09:52 +0000 Subject: [PATCH 130/158] fix ci error --- services/migrations/gitea_uploader_test.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/services/migrations/gitea_uploader_test.go b/services/migrations/gitea_uploader_test.go index c8102c6b8b..5ad49e3ac1 100644 --- a/services/migrations/gitea_uploader_test.go +++ b/services/migrations/gitea_uploader_test.go @@ -23,6 +23,7 @@ import ( "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" base "code.gitea.io/gitea/modules/migration" + "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/modules/util" @@ -230,13 +231,16 @@ func TestGiteaUploadRemapExternalUser(t *testing.T) { func TestGiteaUploadUpdateGitForPullRequest(t *testing.T) { unittest.PrepareTestEnv(t) + err := repository.Init() + assert.NoError(t, err) + // // fromRepo master // fromRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) baseRef := "master" assert.NoError(t, git.InitRepository(git.DefaultContext, fromRepo.RepoPath(), false, fromRepo.ObjectFormatName)) - err := git.NewCommand(git.DefaultContext, "symbolic-ref").AddDynamicArguments("HEAD", git.BranchPrefix+baseRef).Run(&git.RunOpts{Dir: fromRepo.RepoPath()}) + err = git.NewCommand(git.DefaultContext, "symbolic-ref").AddDynamicArguments("HEAD", git.BranchPrefix+baseRef).Run(&git.RunOpts{Dir: fromRepo.RepoPath()}) assert.NoError(t, err) assert.NoError(t, os.WriteFile(filepath.Join(fromRepo.RepoPath(), "README.md"), []byte(fmt.Sprintf("# Testing Repository\n\nOriginally created in: %s", fromRepo.RepoPath())), 0o644)) assert.NoError(t, git.AddChanges(fromRepo.RepoPath(), true)) From a0a7e9a9b3b0252b750fdb8c6ef05904a5ff9695 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 1 Mar 2024 07:36:08 +0000 Subject: [PATCH 131/158] add api and test --- routers/api/v1/api.go | 1 + routers/api/v1/repo/license.go | 51 +++++++++++ routers/api/v1/repo/repo.go | 11 +++ .../08/51b61d9f8ca0e9e63617e11907988ee88b1ca6 | Bin 0 -> 85 bytes .../12/8105ae73669ac2a4cb42751538f0c65c54e28a | Bin 0 -> 643 bytes .../90/c1019714259b24fb81711d4416ac0f18667dfa | 2 + .../user2/repo1.git/refs/heads/DefaultBranch | 2 +- tests/integration/api_repo_license_test.go | 79 ++++++++++++++++++ 8 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 routers/api/v1/repo/license.go create mode 100644 tests/gitea-repositories-meta/user2/repo1.git/objects/08/51b61d9f8ca0e9e63617e11907988ee88b1ca6 create mode 100644 tests/gitea-repositories-meta/user2/repo1.git/objects/12/8105ae73669ac2a4cb42751538f0c65c54e28a create mode 100644 tests/gitea-repositories-meta/user2/repo1.git/objects/90/c1019714259b24fb81711d4416ac0f18667dfa create mode 100644 tests/integration/api_repo_license_test.go diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index e7bdef1489..7edb0a39fa 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -1274,6 +1274,7 @@ func Routes() *web.Route { m.Get("/issue_config", context.ReferencesGitRepo(), repo.GetIssueConfig) m.Get("/issue_config/validate", context.ReferencesGitRepo(), repo.ValidateIssueConfig) m.Get("/languages", reqRepoReader(unit.TypeCode), repo.GetLanguages) + m.Get("/licenses", reqRepoReader(unit.TypeCode), repo.GetLicenses) m.Get("/activities/feeds", repo.ListRepoActivityFeeds) m.Get("/new_pin_allowed", repo.AreNewIssuePinsAllowed) m.Group("/avatar", func() { diff --git a/routers/api/v1/repo/license.go b/routers/api/v1/repo/license.go new file mode 100644 index 0000000000..a60fc0b37d --- /dev/null +++ b/routers/api/v1/repo/license.go @@ -0,0 +1,51 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package repo + +import ( + "net/http" + + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/log" +) + +// GetLicenses returns licenses +func GetLicenses(ctx *context.APIContext) { + // swagger:operation GET /repos/{owner}/{repo}/licenses repository repoGetLicenses + // --- + // summary: Get repo licenses + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // responses: + // "404": + // "$ref": "#/responses/notFound" + // "200": + // "$ref": "#/responses/LicensesList" + + licenses, err := repo_model.GetRepoLicenses(ctx, ctx.Repo.Repository) + if err != nil { + log.Error("GetRepoLicenses failed: %v", err) + ctx.InternalServerError(err) + return + } + + resp := make([]string, len(licenses)) + for i := range licenses { + resp[i] = licenses[i].License + } + + ctx.JSON(http.StatusOK, resp) +} diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index 40de8853d8..ed3f7c0f59 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -729,6 +729,7 @@ func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) err } // Default branch only updated if changed and exist or the repository is empty + updateRepoLicense := false if opts.DefaultBranch != nil && repo.DefaultBranch != *opts.DefaultBranch && (repo.IsEmpty || ctx.Repo.GitRepo.IsBranchExist(*opts.DefaultBranch)) { if !repo.IsEmpty { if err := ctx.Repo.GitRepo.SetDefaultBranch(*opts.DefaultBranch); err != nil { @@ -737,6 +738,7 @@ func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) err return err } } + updateRepoLicense = true } repo.DefaultBranch = *opts.DefaultBranch } @@ -746,6 +748,15 @@ func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) err return err } + if updateRepoLicense { + if err := repo_module.AddRepoToLicenseUpdaterQueue(&repo_module.LicenseUpdaterOptions{ + RepoID: ctx.Repo.Repository.ID, + }); err != nil { + ctx.Error(http.StatusInternalServerError, "AddRepoToLicenseUpdaterQueue", err) + return err + } + } + log.Trace("Repository basic settings updated: %s/%s", owner.Name, repo.Name) return nil } diff --git a/tests/gitea-repositories-meta/user2/repo1.git/objects/08/51b61d9f8ca0e9e63617e11907988ee88b1ca6 b/tests/gitea-repositories-meta/user2/repo1.git/objects/08/51b61d9f8ca0e9e63617e11907988ee88b1ca6 new file mode 100644 index 0000000000000000000000000000000000000000..69b1e0310be8cdcb0d9b0608094280c7da799277 GIT binary patch literal 85 zcmV-b0IL6Z0V^p=O;s>AVlXr?Ff%bx@bPqZ^$T`o5Nc#ySDZHM(2~UvL r>Vhf>a&>g^b=AvFVes|{TpM^lt9HKX$x4&R%2%(WP38jt9giIUL@DJ zbkf#pGlI6zt4TGlaGdJVsV;`Yq!gF~w0%7tRSeERJ-)(OO%?}C<7z$X@d!1v$l*I( zk1*C8+@+orHg`~4Yg%0+9(1OiPil0v^Lz(AC<}M4SFosV6N~#m(y4j?JtCTdw=1}4 z*PGeFq^z5C>oH<%YKOV=8s4r4ebP4uKOT%*uY9)X!0U|RWIBEDe-&(<=Vs8hkD=2Z zx|tnzT3-wa#@@$gGl5mZ;1M+H4qpGM3q76%vqAn_M1l9xo6|=p7|~&#Mx?}0aHcaD zSz!FFTIVZX`N0f>xp-@>89VL$+HX-L@v3gj9~Hb@_c|JfQbXKf0YSudtG6rL*QmWw zx4@7WHbq!1uq+2jpK zVie~x*iezI5t%Gm&g4FZj7jb>GXy125+PZ#&53|=E6SpxNS`7sXFL z&=)*FwI+EUsK^%8i=Zzl%DrH#wS;w%rxc4zipt0`r&lU8mE?qNVo1q`th_n_1qv3S z?WS(GrlEv<1iwVGf_ocD!KJ`sj4p+IAKkHv#y|wCd?1-95Z=d$6FxKU=QzEh_^5;G d_l;nS4{VF3-?gNaÞƒ¯®ó< ëÐÆ®j!Æ&=Õ *Êž1*¢@””TS*X3›WÞu–©cé.–êKÐ90E¦Äž”$h+µ„fòg<ÖÝ~_@ÞE{=,! €÷m»Ôu¾YŒ Ž„B´g8fz|ú_erkö9U]Þj~2]<¼ \ No newline at end of file diff --git a/tests/gitea-repositories-meta/user2/repo1.git/refs/heads/DefaultBranch b/tests/gitea-repositories-meta/user2/repo1.git/refs/heads/DefaultBranch index f98a263be6..5abf667b61 100644 --- a/tests/gitea-repositories-meta/user2/repo1.git/refs/heads/DefaultBranch +++ b/tests/gitea-repositories-meta/user2/repo1.git/refs/heads/DefaultBranch @@ -1 +1 @@ -65f1bf27bc3bf70f64657658635e66094edbcb4d +90c1019714259b24fb81711d4416ac0f18667dfa diff --git a/tests/integration/api_repo_license_test.go b/tests/integration/api_repo_license_test.go new file mode 100644 index 0000000000..e8eafeee84 --- /dev/null +++ b/tests/integration/api_repo_license_test.go @@ -0,0 +1,79 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package integration + +import ( + "fmt" + "net/http" + "net/url" + "testing" + "time" + + auth_model "code.gitea.io/gitea/models/auth" + api "code.gitea.io/gitea/modules/structs" + "github.com/stretchr/testify/assert" +) + +var testLicenseContent = ` +Copyright (c) 2024 Gitea + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +` + +func TestAPIRepoLicense(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + session := loginUser(t, "user2") + + // Request editor page + req := NewRequest(t, "GET", "/user2/repo1/_new/master/") + resp := session.MakeRequest(t, req, http.StatusOK) + + doc := NewHTMLParser(t, resp.Body) + lastCommit := doc.GetInputValueByName("last_commit") + assert.NotEmpty(t, lastCommit) + + // Save new file to master branch + req = NewRequestWithValues(t, "POST", "/user2/repo1/_new/master/", map[string]string{ + "_csrf": doc.GetCSRF(), + "last_commit": lastCommit, + "tree_path": "LICENSE", + "content": testLicenseContent, + "commit_choice": "direct", + }) + session.MakeRequest(t, req, http.StatusSeeOther) + + // let gitea update repo license + time.Sleep(time.Second) + checkRepoLicense(t, "user2", "repo1", []string{"BSD-2-Clause"}) + + // Change default branch + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) + branchName := "DefaultBranch" + req = NewRequestWithJSON(t, "PATCH", "/api/v1/repos/user2/repo1", api.EditRepoOption{ + DefaultBranch: &branchName, + }).AddTokenAuth(token) + session.MakeRequest(t, req, http.StatusOK) + + // let gitea update repo license + time.Sleep(time.Second) + checkRepoLicense(t, "user2", "repo1", []string{"MIT"}) + }) +} + +func checkRepoLicense(t *testing.T, owner, repo string, excepted []string) { + reqURL := fmt.Sprintf("/api/v1/repos/%s/%s/licenses", owner, repo) + req := NewRequest(t, "GET", reqURL) + resp := MakeRequest(t, req, http.StatusOK) + + var licenses []string + DecodeJSON(t, resp, &licenses) + + assert.ElementsMatch(t, excepted, licenses, 0) +} From 11b5e09e2846920d401128f2d0bb03b15121a38c Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 1 Mar 2024 08:41:30 +0000 Subject: [PATCH 132/158] convert v287 to v288 --- models/migrations/v1_22/{v287.go => v288.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename models/migrations/v1_22/{v287.go => v288.go} (100%) diff --git a/models/migrations/v1_22/v287.go b/models/migrations/v1_22/v288.go similarity index 100% rename from models/migrations/v1_22/v287.go rename to models/migrations/v1_22/v288.go From ce750617f67d7eaf0d204696e5540ed953a8aa94 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 1 Mar 2024 08:54:26 +0000 Subject: [PATCH 133/158] convert code.gitea.io/gitea/modules/context into code.gitea.io/gitea/services/context --- routers/api/v1/repo/license.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/api/v1/repo/license.go b/routers/api/v1/repo/license.go index a60fc0b37d..8a6bdfd42f 100644 --- a/routers/api/v1/repo/license.go +++ b/routers/api/v1/repo/license.go @@ -7,8 +7,8 @@ import ( "net/http" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/services/context" ) // GetLicenses returns licenses From 49ab83b41dfa73b1334c750d426ea4ad81e1e476 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Mon, 4 Mar 2024 02:12:32 +0100 Subject: [PATCH 134/158] Update tests/integration/api_repo_license_test.go Co-authored-by: delvh --- tests/integration/api_repo_license_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/api_repo_license_test.go b/tests/integration/api_repo_license_test.go index e8eafeee84..6014002726 100644 --- a/tests/integration/api_repo_license_test.go +++ b/tests/integration/api_repo_license_test.go @@ -67,7 +67,7 @@ func TestAPIRepoLicense(t *testing.T) { }) } -func checkRepoLicense(t *testing.T, owner, repo string, excepted []string) { +func checkRepoLicense(t *testing.T, owner, repo string, expected []string) { reqURL := fmt.Sprintf("/api/v1/repos/%s/%s/licenses", owner, repo) req := NewRequest(t, "GET", reqURL) resp := MakeRequest(t, req, http.StatusOK) @@ -75,5 +75,5 @@ func checkRepoLicense(t *testing.T, owner, repo string, excepted []string) { var licenses []string DecodeJSON(t, resp, &licenses) - assert.ElementsMatch(t, excepted, licenses, 0) + assert.ElementsMatch(t, expected, licenses, 0) } From 46e1246c004d3ac5902a989316cd9e525e58283f Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Mon, 4 Mar 2024 02:16:41 +0100 Subject: [PATCH 135/158] Apply suggestions from code review Co-authored-by: delvh --- models/migrations/v1_22/v288.go | 2 +- models/repo/license.go | 2 +- options/locale/locale_en-US.ini | 2 +- services/repository/licenses.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/models/migrations/v1_22/v288.go b/models/migrations/v1_22/v288.go index a5152e195e..4acbee6283 100644 --- a/models/migrations/v1_22/v288.go +++ b/models/migrations/v1_22/v288.go @@ -1,4 +1,4 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. +// Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package v1_22 //nolint diff --git a/models/repo/license.go b/models/repo/license.go index cd35e448fd..b99ba71ccf 100644 --- a/models/repo/license.go +++ b/models/repo/license.go @@ -1,4 +1,4 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. +// Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package repo diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index a309411677..dbcbe0f087 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -2846,7 +2846,7 @@ dashboard.start_schedule_tasks = Start schedule tasks dashboard.sync_branch.started = Branches Sync started dashboard.sync_tag.started = Tags Sync started dashboard.rebuild_issue_indexer = Rebuild issue indexer -dashboard.sync_repo_licenses = Sync Repo Licenses +dashboard.sync_repo_licenses = Sync repo licenses users.user_manage_panel = User Account Management users.new_account = Create User Account diff --git a/services/repository/licenses.go b/services/repository/licenses.go index 1ea1be68cc..8b751c2807 100644 --- a/services/repository/licenses.go +++ b/services/repository/licenses.go @@ -1,4 +1,4 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. +// Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package repository From f43425142ebd5944b8f19ebff71320ac226b282b Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 5 Mar 2024 04:41:15 +0000 Subject: [PATCH 136/158] do not use time.Now(9 in test --- modules/repository/license_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/repository/license_test.go b/modules/repository/license_test.go index 88cd3127bb..38cda74454 100644 --- a/modules/repository/license_test.go +++ b/modules/repository/license_test.go @@ -7,7 +7,6 @@ import ( "fmt" "strings" "testing" - "time" "github.com/stretchr/testify/assert" ) @@ -210,7 +209,7 @@ func Test_detectLicense(t *testing.T) { Owner: "Gitea", Email: "teabot@gitea.io", Repo: "gitea", - Year: time.Now().Format("2006"), + Year: "2024", }) assert.NoError(t, err) From c218be05ffccec64a1c2845591d257024f9b1eb7 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 5 Mar 2024 04:45:21 +0000 Subject: [PATCH 137/158] remove commit --- routers/web/repo/setting/default_branch.go | 2 +- services/repository/branch.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/routers/web/repo/setting/default_branch.go b/routers/web/repo/setting/default_branch.go index a6b2e9107c..881d148afc 100644 --- a/routers/web/repo/setting/default_branch.go +++ b/routers/web/repo/setting/default_branch.go @@ -34,7 +34,7 @@ func SetDefaultBranchPost(ctx *context.Context) { } branch := ctx.FormString("branch") - if err := repo_service.SetRepoDefaultBranch(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, ctx.Repo.Commit, branch); err != nil { + if err := repo_service.SetRepoDefaultBranch(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, branch); err != nil { switch { case git_model.IsErrBranchNotExist(err): ctx.Status(http.StatusNotFound) diff --git a/services/repository/branch.go b/services/repository/branch.go index c1dd106cb8..6a7ab5d541 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -461,7 +461,7 @@ func AddAllRepoBranchesToSyncQueue(ctx context.Context, doerID int64) error { return nil } -func SetRepoDefaultBranch(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, commit *git.Commit, newBranchName string) error { +func SetRepoDefaultBranch(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, newBranchName string) error { if repo.DefaultBranch == newBranchName { return nil } From 00b182c17ffffd29ccf510dfc35bce15791a2bc4 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 5 Mar 2024 14:04:10 +0900 Subject: [PATCH 138/158] Update models/repo/license.go Co-authored-by: a1012112796 <1012112796@qq.com> --- models/repo/license.go | 1 + 1 file changed, 1 insertion(+) diff --git a/models/repo/license.go b/models/repo/license.go index b99ba71ccf..a08a9c30bd 100644 --- a/models/repo/license.go +++ b/models/repo/license.go @@ -18,6 +18,7 @@ type RepoLicense struct { //revive:disable-line:exported ID int64 `xorm:"pk autoincr"` RepoID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"` CommitID string + // TODO: `INDEX` will be used to find repositories by license License string `xorm:"VARCHAR(50) UNIQUE(s) INDEX NOT NULL"` CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED"` UpdatedUnix timeutil.TimeStamp `xorm:"INDEX UPDATED"` From ccde2013f7acff37f328b67e9f4d7dfd1d2a1728 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 5 Mar 2024 05:06:11 +0000 Subject: [PATCH 139/158] fix lint --- models/repo/license.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/models/repo/license.go b/models/repo/license.go index a08a9c30bd..07bf3bb6c7 100644 --- a/models/repo/license.go +++ b/models/repo/license.go @@ -15,10 +15,10 @@ func init() { } type RepoLicense struct { //revive:disable-line:exported - ID int64 `xorm:"pk autoincr"` - RepoID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"` - CommitID string - // TODO: `INDEX` will be used to find repositories by license + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"` + CommitID string + // TODO: `INDEX` will be used to find repositories by license License string `xorm:"VARCHAR(50) UNIQUE(s) INDEX NOT NULL"` CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED"` UpdatedUnix timeutil.TimeStamp `xorm:"INDEX UPDATED"` From 5059a0fbfc6a231cbf20df6e67896d7c8c9a4025 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 5 Mar 2024 14:10:51 +0900 Subject: [PATCH 140/158] Update modules/repository/license.go Co-authored-by: Lunny Xiao --- modules/repository/license.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/repository/license.go b/modules/repository/license.go index 832afca5e9..dc74f9a9d4 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -59,7 +59,7 @@ func repoLicenseUpdater(items ...*LicenseUpdaterOptions) []*LicenseUpdaterOption continue } - gitRepo, err := git.OpenRepository(ctx, repo.RepoPath()) + gitRepo, err := gitrepo.OpenRepository(ctx, repo) if err != nil { log.Error("repoLicenseUpdater [%d] failed: OpenRepository: %v", opts.RepoID, err) continue From 75cf5a2b3b37640e41610214152980f45bb68eaf Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 5 Mar 2024 05:12:53 +0000 Subject: [PATCH 141/158] convert v288 into v289 --- models/migrations/v1_22/{v288.go => v289.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename models/migrations/v1_22/{v288.go => v289.go} (100%) diff --git a/models/migrations/v1_22/v288.go b/models/migrations/v1_22/v289.go similarity index 100% rename from models/migrations/v1_22/v288.go rename to models/migrations/v1_22/v289.go From 0e3d5122b31c510d6929a7861a754fa29ef31bf0 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 5 Mar 2024 05:41:56 +0000 Subject: [PATCH 142/158] import gitrepo --- modules/repository/license.go | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/repository/license.go b/modules/repository/license.go index dc74f9a9d4..083566a938 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -15,6 +15,7 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" From 8dc1c3be40a8c274b2a8cceb26c6699420bd5e67 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 5 Mar 2024 06:07:24 +0000 Subject: [PATCH 143/158] fix test --- models/fixtures/repository.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/fixtures/repository.yml b/models/fixtures/repository.yml index e5c6224c96..157ec493d6 100644 --- a/models/fixtures/repository.yml +++ b/models/fixtures/repository.yml @@ -26,7 +26,7 @@ fork_id: 0 is_template: false template_id: 0 - size: 7320 + size: 8201 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false From be5052990f343bfcb0d7c57c898b1e190f56f43b Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 5 Mar 2024 06:16:58 +0000 Subject: [PATCH 144/158] improve --- services/repository/branch.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/services/repository/branch.go b/services/repository/branch.go index 6a7ab5d541..cb2c212989 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -503,10 +503,12 @@ func SetRepoDefaultBranch(ctx context.Context, repo *repo_model.Repository, gitR return err } - if err := repo_module.AddRepoToLicenseUpdaterQueue(&repo_module.LicenseUpdaterOptions{ - RepoID: repo.ID, - }); err != nil { - log.Error("AddRepoToLicenseUpdaterQueue: %v", err) + if !repo.IsEmpty { + if err := repo_module.AddRepoToLicenseUpdaterQueue(&repo_module.LicenseUpdaterOptions{ + RepoID: repo.ID, + }); err != nil { + log.Error("AddRepoToLicenseUpdaterQueue: %v", err) + } } notify_service.ChangeDefaultBranch(ctx, repo) From 2f1af68517deb3d807ad8c4529b6ea3666376bdf Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 5 Mar 2024 07:54:38 +0000 Subject: [PATCH 145/158] fix lint --- services/migrations/gitea_uploader_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/migrations/gitea_uploader_test.go b/services/migrations/gitea_uploader_test.go index afd27068e2..c5ba62c27e 100644 --- a/services/migrations/gitea_uploader_test.go +++ b/services/migrations/gitea_uploader_test.go @@ -23,8 +23,8 @@ import ( "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" base "code.gitea.io/gitea/modules/migration" - "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/optional" + "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/test" From f87f8578cf7e2d6550b32ae628718f02bea5336f Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 5 Mar 2024 08:19:27 +0000 Subject: [PATCH 146/158] move to services --- modules/repository/license.go | 210 ---------------- modules/repository/license_test.go | 60 ----- routers/api/v1/repo/repo.go | 2 +- routers/init.go | 3 - routers/private/default_branch.go | 4 +- routers/private/hook_post_receive.go | 2 +- routers/web/repo/branch.go | 2 +- routers/web/repo/commit.go | 8 +- routers/web/repo/view.go | 5 +- services/migrations/gitea_uploader_test.go | 6 +- services/mirror/mirror_pull.go | 3 +- services/repository/branch.go | 2 +- services/repository/create.go | 2 +- {modules => services}/repository/file.go | 0 {modules => services}/repository/file_test.go | 0 services/repository/license.go | 235 ++++++++++++++++++ services/repository/license_test.go | 72 ++++++ services/repository/licenses.go | 36 --- services/repository/migrate.go | 2 +- services/repository/repository.go | 7 + 20 files changed, 332 insertions(+), 329 deletions(-) rename {modules => services}/repository/file.go (100%) rename {modules => services}/repository/file_test.go (100%) create mode 100644 services/repository/license.go create mode 100644 services/repository/license_test.go delete mode 100644 services/repository/licenses.go diff --git a/modules/repository/license.go b/modules/repository/license.go index 083566a938..9da3af84f8 100644 --- a/modules/repository/license.go +++ b/modules/repository/license.go @@ -6,144 +6,13 @@ package repository import ( "bufio" "bytes" - "context" "fmt" - "io" "regexp" "strings" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/container" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/graceful" - "code.gitea.io/gitea/modules/json" - "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/options" - "code.gitea.io/gitea/modules/queue" - "code.gitea.io/gitea/modules/util" - - licenseclassifier "github.com/google/licenseclassifier/v2" ) -var ( - classifier *licenseclassifier.Classifier - licenseAliases map[string]string - - // licenseUpdaterQueue represents a queue to handle update repo licenses - licenseUpdaterQueue *queue.WorkerPoolQueue[*LicenseUpdaterOptions] -) - -func Init() error { - licenseUpdaterQueue = queue.CreateUniqueQueue(graceful.GetManager().ShutdownContext(), "repo_license_updater", repoLicenseUpdater) - if licenseUpdaterQueue == nil { - return fmt.Errorf("unable to create repo_license_updater queue") - } - go graceful.GetManager().RunWithCancel(licenseUpdaterQueue) - return nil -} - -type LicenseUpdaterOptions struct { - RepoID int64 -} - -func repoLicenseUpdater(items ...*LicenseUpdaterOptions) []*LicenseUpdaterOptions { - ctx := graceful.GetManager().ShutdownContext() - - for _, opts := range items { - repo, err := repo_model.GetRepositoryByID(ctx, opts.RepoID) - if err != nil { - log.Error("repoLicenseUpdater [%d] failed: GetRepositoryByID: %v", opts.RepoID, err) - continue - } - if repo.IsEmpty { - continue - } - - gitRepo, err := gitrepo.OpenRepository(ctx, repo) - if err != nil { - log.Error("repoLicenseUpdater [%d] failed: OpenRepository: %v", opts.RepoID, err) - continue - } - defer gitRepo.Close() - - commit, err := gitRepo.GetBranchCommit(repo.DefaultBranch) - if err != nil { - log.Error("repoLicenseUpdater [%d] failed: GetBranchCommit: %v", opts.RepoID, err) - continue - } - if err = updateRepoLicenses(ctx, repo, commit); err != nil { - log.Error("repoLicenseUpdater [%d] failed: updateRepoLicenses: %v", opts.RepoID, err) - } - } - return nil -} - -func AddRepoToLicenseUpdaterQueue(opts *LicenseUpdaterOptions) error { - if opts == nil { - return nil - } - return licenseUpdaterQueue.Push(opts) -} - -func loadLicenseAliases() error { - if licenseAliases != nil { - return nil - } - - data, err := options.AssetFS().ReadFile("", "license-aliases.json") - if err != nil { - return err - } - err = json.Unmarshal(data, &licenseAliases) - if err != nil { - return err - } - return nil -} - -func ConvertLicenseName(name string) string { - if err := loadLicenseAliases(); err != nil { - return name - } - - v, ok := licenseAliases[name] - if ok { - return v - } - return name -} - -func initClassifier() error { - if classifier != nil { - return nil - } - - // threshold should be 0.84~0.86 or the test will be failed - classifier = licenseclassifier.NewClassifier(.85) - licenseFiles, err := options.AssetFS().ListFiles("license", true) - if err != nil { - return err - } - - existLicense := make(container.Set[string]) - if len(licenseFiles) > 0 { - for _, licenseFile := range licenseFiles { - licenseName := ConvertLicenseName(licenseFile) - if existLicense.Contains(licenseName) { - continue - } - existLicense.Add(licenseName) - data, err := options.License(licenseFile) - if err != nil { - return err - } - classifier.AddContent("License", licenseFile, licenseName, data) - } - } - return nil -} - type LicenseValues struct { Owner string Email string @@ -242,82 +111,3 @@ func getLicensePlaceholder(name string) *licensePlaceholder { } return ret } - -// updateRepoLicenses will update repository licenses col if license file exists -func updateRepoLicenses(ctx context.Context, repo *repo_model.Repository, commit *git.Commit) error { - if commit == nil { - return nil - } - - _, licenseFile, err := findLicenseFile(commit) - if err != nil { - return fmt.Errorf("findLicenseFile: %w", err) - } - - licenses := make([]string, 0) - if licenseFile != nil { - r, err := licenseFile.Blob().DataAsync() - if err != nil { - return err - } - defer r.Close() - - licenses, err = detectLicense(r) - if err != nil { - return fmt.Errorf("detectLicense: %w", err) - } - } - return repo_model.UpdateRepoLicenses(ctx, repo, commit.ID.String(), licenses) -} - -// GetDetectedLicenseFileName returns license file name in the repository if it exists -func GetDetectedLicenseFileName(ctx context.Context, repo *repo_model.Repository, commit *git.Commit) (string, error) { - if commit == nil { - return "", nil - } - _, licenseFile, err := findLicenseFile(commit) - if err != nil { - return "", fmt.Errorf("findLicenseFile: %w", err) - } - if licenseFile != nil { - return licenseFile.Name(), nil - } - return "", nil -} - -// findLicenseFile returns the entry of license file in the repository if it exists -func findLicenseFile(commit *git.Commit) (string, *git.TreeEntry, error) { - if commit == nil { - return "", nil, nil - } - entries, err := commit.ListEntries() - if err != nil { - return "", nil, fmt.Errorf("ListEntries: %w", err) - } - return FindFileInEntries(util.FileTypeLicense, entries, "", "", false) -} - -// detectLicense returns the licenses detected by the given content buff -func detectLicense(r io.Reader) ([]string, error) { - if r == nil { - return nil, nil - } - if err := initClassifier(); err != nil { - return nil, err - } - - matches, err := classifier.MatchFrom(r) - if err != nil { - return nil, err - } - if len(matches.Matches) > 0 { - results := make(container.Set[string], len(matches.Matches)) - for _, r := range matches.Matches { - if r.MatchType == "License" && !results.Contains(r.Variant) { - results.Add(r.Variant) - } - } - return results.Values(), nil - } - return nil, nil -} diff --git a/modules/repository/license_test.go b/modules/repository/license_test.go index 38cda74454..3b0cfa1eed 100644 --- a/modules/repository/license_test.go +++ b/modules/repository/license_test.go @@ -5,7 +5,6 @@ package repository import ( "fmt" - "strings" "testing" "github.com/stretchr/testify/assert" @@ -180,62 +179,3 @@ Copyright (C) 2023 by Gitea teabot@gitea.io }) } } - -func Test_detectLicense(t *testing.T) { - type DetectLicenseTest struct { - name string - arg string - want []string - } - - tests := []DetectLicenseTest{ - { - name: "empty", - arg: "", - want: nil, - }, - { - name: "no detected license", - arg: "Copyright (c) 2023 Gitea", - want: nil, - }, - } - - LoadRepoConfig() - err := loadLicenseAliases() - assert.NoError(t, err) - for _, licenseName := range Licenses { - license, err := GetLicense(licenseName, &LicenseValues{ - Owner: "Gitea", - Email: "teabot@gitea.io", - Repo: "gitea", - Year: "2024", - }) - assert.NoError(t, err) - - tests = append(tests, DetectLicenseTest{ - name: fmt.Sprintf("single license test: %s", licenseName), - arg: string(license), - want: []string{ConvertLicenseName(licenseName)}, - }) - } - - err = initClassifier() - assert.NoError(t, err) - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - license, err := detectLicense(strings.NewReader(tt.arg)) - assert.NoError(t, err) - assert.Equal(t, tt.want, license) - }) - } - - result, err := detectLicense(strings.NewReader(tests[2].arg + tests[3].arg + tests[4].arg)) - assert.NoError(t, err) - t.Run("multiple licenses test", func(t *testing.T) { - assert.Equal(t, 3, len(result)) - assert.Contains(t, result, tests[2].want[0]) - assert.Contains(t, result, tests[3].want[0]) - assert.Contains(t, result, tests[4].want[0]) - }) -} diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index 6e1c29b620..2b8264f1db 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -749,7 +749,7 @@ func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) err } if updateRepoLicense { - if err := repo_module.AddRepoToLicenseUpdaterQueue(&repo_module.LicenseUpdaterOptions{ + if err := repo_service.AddRepoToLicenseUpdaterQueue(&repo_service.LicenseUpdaterOptions{ RepoID: ctx.Repo.Repository.ID, }); err != nil { ctx.Error(http.StatusInternalServerError, "AddRepoToLicenseUpdaterQueue", err) diff --git a/routers/init.go b/routers/init.go index cfc77528e0..aaf95920c2 100644 --- a/routers/init.go +++ b/routers/init.go @@ -17,7 +17,6 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/external" - "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/ssh" "code.gitea.io/gitea/modules/storage" @@ -167,8 +166,6 @@ func InitWebInstalled(ctx context.Context) { actions_service.Init() - mustInit(repository.Init) - // Finally start up the cron cron.NewContext(ctx) } diff --git a/routers/private/default_branch.go b/routers/private/default_branch.go index 0ffa56801c..72e97db344 100644 --- a/routers/private/default_branch.go +++ b/routers/private/default_branch.go @@ -10,8 +10,8 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/private" - repo_module "code.gitea.io/gitea/modules/repository" gitea_context "code.gitea.io/gitea/services/context" + repo_service "code.gitea.io/gitea/services/repository" ) // SetDefaultBranch updates the default branch @@ -37,7 +37,7 @@ func SetDefaultBranch(ctx *gitea_context.PrivateContext) { return } - if err := repo_module.AddRepoToLicenseUpdaterQueue(&repo_module.LicenseUpdaterOptions{ + if err := repo_service.AddRepoToLicenseUpdaterQueue(&repo_service.LicenseUpdaterOptions{ RepoID: ctx.Repo.Repository.ID, }); err != nil { ctx.JSON(http.StatusInternalServerError, private.Response{ diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go index 2e332fbff8..3eba36b2e9 100644 --- a/routers/private/hook_post_receive.go +++ b/routers/private/hook_post_receive.go @@ -195,7 +195,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { branch := refFullName.BranchName() if branch == baseRepo.DefaultBranch { - if err := repo_module.AddRepoToLicenseUpdaterQueue(&repo_module.LicenseUpdaterOptions{ + if err := repo_service.AddRepoToLicenseUpdaterQueue(&repo_service.LicenseUpdaterOptions{ RepoID: repo.ID, }); err != nil { ctx.JSON(http.StatusInternalServerError, private.Response{Err: err.Error()}) diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go index 1995823867..a2f8830105 100644 --- a/routers/web/repo/branch.go +++ b/routers/web/repo/branch.go @@ -85,7 +85,7 @@ func Branches(ctx *context.Context) { pager.SetDefaultParams(ctx) ctx.Data["Page"] = pager - ctx.Data["DetectedLicenseFileName"], err = repo_module.GetDetectedLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.Commit) + ctx.Data["DetectedLicenseFileName"], err = repo_service.GetDetectedLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.Commit) if err != nil { ctx.ServerError("GetDetectedLicenseFileName", err) return diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index 020fa4aea2..f3c9df9d3c 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -24,12 +24,12 @@ import ( "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup" - repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/gitdiff" git_service "code.gitea.io/gitea/services/repository" + repo_service "code.gitea.io/gitea/services/repository" ) const ( @@ -91,7 +91,7 @@ func Commits(ctx *context.Context) { pager := context.NewPagination(int(commitsCount), pageSize, page, 5) pager.SetDefaultParams(ctx) ctx.Data["Page"] = pager - ctx.Data["DetectedLicenseFileName"], err = repo_module.GetDetectedLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.Commit) + ctx.Data["DetectedLicenseFileName"], err = repo_service.GetDetectedLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.Commit) if err != nil { ctx.ServerError("GetDetectedLicenseFileName", err) return @@ -213,7 +213,7 @@ func SearchCommits(ctx *context.Context) { ctx.Data["Username"] = ctx.Repo.Owner.Name ctx.Data["Reponame"] = ctx.Repo.Repository.Name ctx.Data["RefName"] = ctx.Repo.RefName - ctx.Data["DetectedLicenseFileName"], err = repo_module.GetDetectedLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.Commit) + ctx.Data["DetectedLicenseFileName"], err = repo_service.GetDetectedLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.Commit) if err != nil { ctx.ServerError("GetDetectedLicenseFileName", err) return @@ -266,7 +266,7 @@ func FileHistory(ctx *context.Context) { pager.SetDefaultParams(ctx) ctx.Data["Page"] = pager - ctx.Data["DetectedLicenseFileName"], err = repo_module.GetDetectedLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.Commit) + ctx.Data["DetectedLicenseFileName"], err = repo_service.GetDetectedLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.Commit) if err != nil { ctx.ServerError("GetDetectedLicenseFileName", err) return diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index d498a5dd07..fdaf6dee92 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -49,6 +49,7 @@ import ( "code.gitea.io/gitea/routers/web/feed" "code.gitea.io/gitea/services/context" issue_service "code.gitea.io/gitea/services/issue" + repo_service "code.gitea.io/gitea/services/repository" files_service "code.gitea.io/gitea/services/repository/files" "github.com/nektos/act/pkg/model" @@ -77,7 +78,7 @@ func renderDirectory(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+path.Base(ctx.Repo.TreePath), ctx.Repo.RefName) } - subfolder, readmeFile, err := repo_module.FindFileInEntries(util.FileTypeReadme, entries, ctx.Repo.TreePath, ctx.Locale.Language(), true) + subfolder, readmeFile, err := repo_service.FindFileInEntries(util.FileTypeReadme, entries, ctx.Repo.TreePath, ctx.Locale.Language(), true) if err != nil { ctx.ServerError("findFileInEntries", err) return @@ -946,7 +947,7 @@ func renderHomeCode(ctx *context.Context) { ctx.Data["TreeLink"] = treeLink ctx.Data["TreeNames"] = treeNames ctx.Data["BranchLink"] = branchLink - ctx.Data["DetectedLicenseFileName"], err = repo_module.GetDetectedLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.Commit) + ctx.Data["DetectedLicenseFileName"], err = repo_service.GetDetectedLicenseFileName(ctx, ctx.Repo.Repository, ctx.Repo.Commit) if err != nil { ctx.ServerError("GetDetectedLicenseFileName", err) return diff --git a/services/migrations/gitea_uploader_test.go b/services/migrations/gitea_uploader_test.go index c5ba62c27e..c9b9248098 100644 --- a/services/migrations/gitea_uploader_test.go +++ b/services/migrations/gitea_uploader_test.go @@ -24,7 +24,6 @@ import ( "code.gitea.io/gitea/modules/log" base "code.gitea.io/gitea/modules/migration" "code.gitea.io/gitea/modules/optional" - "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/test" @@ -231,16 +230,13 @@ func TestGiteaUploadRemapExternalUser(t *testing.T) { func TestGiteaUploadUpdateGitForPullRequest(t *testing.T) { unittest.PrepareTestEnv(t) - err := repository.Init() - assert.NoError(t, err) - // // fromRepo master // fromRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) baseRef := "master" assert.NoError(t, git.InitRepository(git.DefaultContext, fromRepo.RepoPath(), false, fromRepo.ObjectFormatName)) - err = git.NewCommand(git.DefaultContext, "symbolic-ref").AddDynamicArguments("HEAD", git.BranchPrefix+baseRef).Run(&git.RunOpts{Dir: fromRepo.RepoPath()}) + err := git.NewCommand(git.DefaultContext, "symbolic-ref").AddDynamicArguments("HEAD", git.BranchPrefix+baseRef).Run(&git.RunOpts{Dir: fromRepo.RepoPath()}) assert.NoError(t, err) assert.NoError(t, os.WriteFile(filepath.Join(fromRepo.RepoPath(), "README.md"), []byte(fmt.Sprintf("# Testing Repository\n\nOriginally created in: %s", fromRepo.RepoPath())), 0o644)) assert.NoError(t, git.AddChanges(fromRepo.RepoPath(), true)) diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go index a26e571f74..84e7657980 100644 --- a/services/mirror/mirror_pull.go +++ b/services/mirror/mirror_pull.go @@ -23,6 +23,7 @@ import ( "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" notify_service "code.gitea.io/gitea/services/notify" + repo_service "code.gitea.io/gitea/services/repository" ) // gitShortEmptySha Git short empty SHA @@ -550,7 +551,7 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { } // Update License - if err = repo_module.AddRepoToLicenseUpdaterQueue(&repo_module.LicenseUpdaterOptions{ + if err = repo_service.AddRepoToLicenseUpdaterQueue(&repo_service.LicenseUpdaterOptions{ RepoID: m.Repo.ID, }); err != nil { log.Error("SyncMirrors [repo: %-v]: unable to add repo to license updater queue: %v", m.Repo, err) diff --git a/services/repository/branch.go b/services/repository/branch.go index cb2c212989..8292faa448 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -504,7 +504,7 @@ func SetRepoDefaultBranch(ctx context.Context, repo *repo_model.Repository, gitR } if !repo.IsEmpty { - if err := repo_module.AddRepoToLicenseUpdaterQueue(&repo_module.LicenseUpdaterOptions{ + if err := AddRepoToLicenseUpdaterQueue(&LicenseUpdaterOptions{ RepoID: repo.ID, }); err != nil { log.Error("AddRepoToLicenseUpdaterQueue: %v", err) diff --git a/services/repository/create.go b/services/repository/create.go index bdfaf09404..79e7d01605 100644 --- a/services/repository/create.go +++ b/services/repository/create.go @@ -310,7 +310,7 @@ func CreateRepositoryDirectly(ctx context.Context, doer, u *user_model.User, opt // update licenses var licenses []string if len(opts.License) > 0 { - licenses = append(licenses, repo_module.ConvertLicenseName(opts.License)) + licenses = append(licenses, ConvertLicenseName(opts.License)) stdout, _, err := git.NewCommand(ctx, "rev-parse", "HEAD"). SetDescription(fmt.Sprintf("CreateRepository(git rev-parse HEAD): %s", repoPath)). diff --git a/modules/repository/file.go b/services/repository/file.go similarity index 100% rename from modules/repository/file.go rename to services/repository/file.go diff --git a/modules/repository/file_test.go b/services/repository/file_test.go similarity index 100% rename from modules/repository/file_test.go rename to services/repository/file_test.go diff --git a/services/repository/license.go b/services/repository/license.go new file mode 100644 index 0000000000..b62ef0009b --- /dev/null +++ b/services/repository/license.go @@ -0,0 +1,235 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package repository + +import ( + "context" + "encoding/json" + "fmt" + "io" + + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/container" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/gitrepo" + "code.gitea.io/gitea/modules/graceful" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/options" + "code.gitea.io/gitea/modules/queue" + "code.gitea.io/gitea/modules/util" + + licenseclassifier "github.com/google/licenseclassifier/v2" +) + +var ( + classifier *licenseclassifier.Classifier + licenseAliases map[string]string + + // licenseUpdaterQueue represents a queue to handle update repo licenses + licenseUpdaterQueue *queue.WorkerPoolQueue[*LicenseUpdaterOptions] +) + +func AddRepoToLicenseUpdaterQueue(opts *LicenseUpdaterOptions) error { + if opts == nil { + return nil + } + return licenseUpdaterQueue.Push(opts) +} + +func loadLicenseAliases() error { + if licenseAliases != nil { + return nil + } + + data, err := options.AssetFS().ReadFile("", "license-aliases.json") + if err != nil { + return err + } + err = json.Unmarshal(data, &licenseAliases) + if err != nil { + return err + } + return nil +} + +func ConvertLicenseName(name string) string { + if err := loadLicenseAliases(); err != nil { + return name + } + + v, ok := licenseAliases[name] + if ok { + return v + } + return name +} + +func initClassifier() error { + if classifier != nil { + return nil + } + + // threshold should be 0.84~0.86 or the test will be failed + classifier = licenseclassifier.NewClassifier(.85) + licenseFiles, err := options.AssetFS().ListFiles("license", true) + if err != nil { + return err + } + + existLicense := make(container.Set[string]) + if len(licenseFiles) > 0 { + for _, licenseFile := range licenseFiles { + licenseName := ConvertLicenseName(licenseFile) + if existLicense.Contains(licenseName) { + continue + } + existLicense.Add(licenseName) + data, err := options.License(licenseFile) + if err != nil { + return err + } + classifier.AddContent("License", licenseFile, licenseName, data) + } + } + return nil +} + +type LicenseUpdaterOptions struct { + RepoID int64 +} + +func repoLicenseUpdater(items ...*LicenseUpdaterOptions) []*LicenseUpdaterOptions { + ctx := graceful.GetManager().ShutdownContext() + + for _, opts := range items { + repo, err := repo_model.GetRepositoryByID(ctx, opts.RepoID) + if err != nil { + log.Error("repoLicenseUpdater [%d] failed: GetRepositoryByID: %v", opts.RepoID, err) + continue + } + if repo.IsEmpty { + continue + } + + gitRepo, err := gitrepo.OpenRepository(ctx, repo) + if err != nil { + log.Error("repoLicenseUpdater [%d] failed: OpenRepository: %v", opts.RepoID, err) + continue + } + defer gitRepo.Close() + + commit, err := gitRepo.GetBranchCommit(repo.DefaultBranch) + if err != nil { + log.Error("repoLicenseUpdater [%d] failed: GetBranchCommit: %v", opts.RepoID, err) + continue + } + if err = UpdateRepoLicenses(ctx, repo, commit); err != nil { + log.Error("repoLicenseUpdater [%d] failed: updateRepoLicenses: %v", opts.RepoID, err) + } + } + return nil +} + +func SyncRepoLicenses(ctx context.Context) error { + log.Trace("Doing: SyncRepoLicenses") + + if err := db.Iterate( + ctx, + nil, + func(ctx context.Context, repo *repo_model.Repository) error { + select { + case <-ctx.Done(): + return db.ErrCancelledf("before sync repo licenses for %s", repo.FullName()) + default: + } + return AddRepoToLicenseUpdaterQueue(&LicenseUpdaterOptions{RepoID: repo.ID}) + }, + ); err != nil { + log.Trace("Error: SyncRepoLicenses: %v", err) + return err + } + + log.Trace("Finished: SyncReposLicenses") + return nil +} + +// UpdateRepoLicenses will update repository licenses col if license file exists +func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository, commit *git.Commit) error { + if commit == nil { + return nil + } + + _, licenseFile, err := findLicenseFile(commit) + if err != nil { + return fmt.Errorf("findLicenseFile: %w", err) + } + + licenses := make([]string, 0) + if licenseFile != nil { + r, err := licenseFile.Blob().DataAsync() + if err != nil { + return err + } + defer r.Close() + + licenses, err = detectLicense(r) + if err != nil { + return fmt.Errorf("detectLicense: %w", err) + } + } + return repo_model.UpdateRepoLicenses(ctx, repo, commit.ID.String(), licenses) +} + +// GetDetectedLicenseFileName returns license file name in the repository if it exists +func GetDetectedLicenseFileName(ctx context.Context, repo *repo_model.Repository, commit *git.Commit) (string, error) { + if commit == nil { + return "", nil + } + _, licenseFile, err := findLicenseFile(commit) + if err != nil { + return "", fmt.Errorf("findLicenseFile: %w", err) + } + if licenseFile != nil { + return licenseFile.Name(), nil + } + return "", nil +} + +// findLicenseFile returns the entry of license file in the repository if it exists +func findLicenseFile(commit *git.Commit) (string, *git.TreeEntry, error) { + if commit == nil { + return "", nil, nil + } + entries, err := commit.ListEntries() + if err != nil { + return "", nil, fmt.Errorf("ListEntries: %w", err) + } + return FindFileInEntries(util.FileTypeLicense, entries, "", "", false) +} + +// detectLicense returns the licenses detected by the given content buff +func detectLicense(r io.Reader) ([]string, error) { + if r == nil { + return nil, nil + } + if err := initClassifier(); err != nil { + return nil, err + } + + matches, err := classifier.MatchFrom(r) + if err != nil { + return nil, err + } + if len(matches.Matches) > 0 { + results := make(container.Set[string], len(matches.Matches)) + for _, r := range matches.Matches { + if r.MatchType == "License" && !results.Contains(r.Variant) { + results.Add(r.Variant) + } + } + return results.Values(), nil + } + return nil, nil +} diff --git a/services/repository/license_test.go b/services/repository/license_test.go new file mode 100644 index 0000000000..297cea57ff --- /dev/null +++ b/services/repository/license_test.go @@ -0,0 +1,72 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package repository + +import ( + "fmt" + "strings" + "testing" + + repo_module "code.gitea.io/gitea/modules/repository" + "github.com/stretchr/testify/assert" +) + +func Test_detectLicense(t *testing.T) { + type DetectLicenseTest struct { + name string + arg string + want []string + } + + tests := []DetectLicenseTest{ + { + name: "empty", + arg: "", + want: nil, + }, + { + name: "no detected license", + arg: "Copyright (c) 2023 Gitea", + want: nil, + }, + } + + repo_module.LoadRepoConfig() + err := loadLicenseAliases() + assert.NoError(t, err) + for _, licenseName := range repo_module.Licenses { + license, err := repo_module.GetLicense(licenseName, &repo_module.LicenseValues{ + Owner: "Gitea", + Email: "teabot@gitea.io", + Repo: "gitea", + Year: "2024", + }) + assert.NoError(t, err) + + tests = append(tests, DetectLicenseTest{ + name: fmt.Sprintf("single license test: %s", licenseName), + arg: string(license), + want: []string{ConvertLicenseName(licenseName)}, + }) + } + + err = initClassifier() + assert.NoError(t, err) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + license, err := detectLicense(strings.NewReader(tt.arg)) + assert.NoError(t, err) + assert.Equal(t, tt.want, license) + }) + } + + result, err := detectLicense(strings.NewReader(tests[2].arg + tests[3].arg + tests[4].arg)) + assert.NoError(t, err) + t.Run("multiple licenses test", func(t *testing.T) { + assert.Equal(t, 3, len(result)) + assert.Contains(t, result, tests[2].want[0]) + assert.Contains(t, result, tests[3].want[0]) + assert.Contains(t, result, tests[4].want[0]) + }) +} diff --git a/services/repository/licenses.go b/services/repository/licenses.go deleted file mode 100644 index 8b751c2807..0000000000 --- a/services/repository/licenses.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2024 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package repository - -import ( - "context" - - "code.gitea.io/gitea/models/db" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/log" - repo_module "code.gitea.io/gitea/modules/repository" -) - -func SyncRepoLicenses(ctx context.Context) error { - log.Trace("Doing: SyncRepoLicenses") - - if err := db.Iterate( - ctx, - nil, - func(ctx context.Context, repo *repo_model.Repository) error { - select { - case <-ctx.Done(): - return db.ErrCancelledf("before sync repo licenses for %s", repo.FullName()) - default: - } - return repo_module.AddRepoToLicenseUpdaterQueue(&repo_module.LicenseUpdaterOptions{RepoID: repo.ID}) - }, - ); err != nil { - log.Trace("Error: SyncRepoLicenses: %v", err) - return err - } - - log.Trace("Finished: SyncReposLicenses") - return nil -} diff --git a/services/repository/migrate.go b/services/repository/migrate.go index e934abbe24..38737c93da 100644 --- a/services/repository/migrate.go +++ b/services/repository/migrate.go @@ -152,7 +152,7 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User, } // Update repo license - if err := repo_module.AddRepoToLicenseUpdaterQueue(&repo_module.LicenseUpdaterOptions{RepoID: repo.ID}); err != nil { + if err := AddRepoToLicenseUpdaterQueue(&LicenseUpdaterOptions{RepoID: repo.ID}); err != nil { log.Error("Failed to add repo to license updater queue: %v", err) } } diff --git a/services/repository/repository.go b/services/repository/repository.go index d28200c0ad..ed8b8abdc2 100644 --- a/services/repository/repository.go +++ b/services/repository/repository.go @@ -18,6 +18,7 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/queue" repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" @@ -96,6 +97,12 @@ func PushCreateRepo(ctx context.Context, authUser, owner *user_model.User, repoN // Init start repository service func Init(ctx context.Context) error { + licenseUpdaterQueue = queue.CreateUniqueQueue(graceful.GetManager().ShutdownContext(), "repo_license_updater", repoLicenseUpdater) + if licenseUpdaterQueue == nil { + return fmt.Errorf("unable to create repo_license_updater queue") + } + go graceful.GetManager().RunWithCancel(licenseUpdaterQueue) + if err := repo_module.LoadRepoConfig(); err != nil { return err } From 2910c9c1d95564393bec6c30d9b165e9da1b6db8 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 5 Mar 2024 08:20:45 +0000 Subject: [PATCH 147/158] fix year --- services/repository/license_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/repository/license_test.go b/services/repository/license_test.go index 297cea57ff..41a4efea8c 100644 --- a/services/repository/license_test.go +++ b/services/repository/license_test.go @@ -1,4 +1,4 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. +// Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package repository From 60aba0cae0667468826a2ea9a9fee140972b2900 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 6 Mar 2024 00:08:36 +0000 Subject: [PATCH 148/158] fix typo --- routers/web/repo/commit.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index f3c9df9d3c..6259a92e49 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -28,7 +28,6 @@ import ( "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/gitdiff" - git_service "code.gitea.io/gitea/services/repository" repo_service "code.gitea.io/gitea/services/repository" ) @@ -275,7 +274,7 @@ func FileHistory(ctx *context.Context) { } func LoadBranchesAndTags(ctx *context.Context) { - response, err := git_service.LoadBranchesAndTags(ctx, ctx.Repo, ctx.Params("sha")) + response, err := repo_service.LoadBranchesAndTags(ctx, ctx.Repo, ctx.Params("sha")) if err == nil { ctx.JSON(http.StatusOK, response) return From d5ca326968a76318123596803fc185c746fa3748 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 12 Sep 2024 04:44:31 +0000 Subject: [PATCH 149/158] renqme v289 to v305 --- models/migrations/{v1_22/v289.go => v1_23/v305.go} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename models/migrations/{v1_22/v289.go => v1_23/v305.go} (96%) diff --git a/models/migrations/v1_22/v289.go b/models/migrations/v1_23/v305.go similarity index 96% rename from models/migrations/v1_22/v289.go rename to models/migrations/v1_23/v305.go index 4acbee6283..5c4be51e84 100644 --- a/models/migrations/v1_22/v289.go +++ b/models/migrations/v1_23/v305.go @@ -1,7 +1,7 @@ // Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_22 //nolint +package v1_23 //nolint import ( "code.gitea.io/gitea/modules/timeutil" From 0f008950d41ea3ffcb70c616444987b120ac2af4 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 12 Sep 2024 04:56:40 +0000 Subject: [PATCH 150/158] fix migration --- models/migrations/migrations.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 995f8569b0..f99718ead2 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -601,8 +601,8 @@ var migrations = []Migration{ NewMigration("Add metadata column for comment table", v1_23.AddCommentMetaDataColumn), // v304 -> v305 NewMigration("Add index for release sha1", v1_23.AddIndexForReleaseSha1), - // v305 -> v306 - NewMigration("Add Repository Licenses", v1_22.AddRepositoryLicenses), + // v305 -> v306 + NewMigration("Add Repository Licenses", v1_23.AddRepositoryLicenses), } // GetCurrentDBVersion returns the current db version From fa0119b5520f51df88935a83fd9f90e979abd58e Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 12 Sep 2024 04:56:54 +0000 Subject: [PATCH 151/158] go mod tidy --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index b700962ff9..21c2043aff 100644 --- a/go.mod +++ b/go.mod @@ -62,7 +62,7 @@ require ( github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 github.com/golang-jwt/jwt/v5 v5.2.1 github.com/google/go-github/v61 v61.0.0 - github.com/google/licenseclassifier/v2 v2.0.0 + github.com/google/licenseclassifier/v2 v2.0.0 github.com/google/pprof v0.0.0-20240618054019-d3b898a103f8 github.com/google/uuid v1.6.0 github.com/gorilla/feeds v1.2.0 From cfe8cb51920ab5e201b45d31ac58fe18da02e276 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 12 Sep 2024 05:12:52 +0000 Subject: [PATCH 152/158] fix repository size --- models/fixtures/repository.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/fixtures/repository.yml b/models/fixtures/repository.yml index 20cf524a94..e141593f41 100644 --- a/models/fixtures/repository.yml +++ b/models/fixtures/repository.yml @@ -26,7 +26,7 @@ fork_id: 0 is_template: false template_id: 0 - size: 8201 + size: 8478 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false From 0717cb6faf75c17c5fe9e2b7450233d3ffbcf57c Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 12 Sep 2024 05:13:36 +0000 Subject: [PATCH 153/158] make generate-swagger --- templates/swagger/v1_json.tmpl | 36 ++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index fd906a7151..11033953ec 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -10640,6 +10640,42 @@ } } }, + "/repos/{owner}/{repo}/licenses": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "repository" + ], + "summary": "Get repo licenses", + "operationId": "repoGetLicenses", + "parameters": [ + { + "type": "string", + "description": "owner of the repo", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the repo", + "name": "repo", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/LicensesList" + }, + "404": { + "$ref": "#/responses/notFound" + } + } + } + }, "/repos/{owner}/{repo}/media/{filepath}": { "get": { "produces": [ From 051fdffb50c65faba764850c84f3d1561b718717 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 12 Sep 2024 05:20:42 +0000 Subject: [PATCH 154/158] fix lint --- modules/structs/repo.go | 2 +- services/repository/license_test.go | 1 + tests/integration/api_repo_license_test.go | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/structs/repo.go b/modules/structs/repo.go index 601fb59e2f..832ffa8bcc 100644 --- a/modules/structs/repo.go +++ b/modules/structs/repo.go @@ -114,7 +114,7 @@ type Repository struct { MirrorUpdated time.Time `json:"mirror_updated,omitempty"` RepoTransfer *RepoTransfer `json:"repo_transfer"` Topics []string `json:"topics"` - Licenses []string `json:"licenses"` + Licenses []string `json:"licenses"` } // CreateRepoOption options when creating repository diff --git a/services/repository/license_test.go b/services/repository/license_test.go index 41a4efea8c..580df7c376 100644 --- a/services/repository/license_test.go +++ b/services/repository/license_test.go @@ -9,6 +9,7 @@ import ( "testing" repo_module "code.gitea.io/gitea/modules/repository" + "github.com/stretchr/testify/assert" ) diff --git a/tests/integration/api_repo_license_test.go b/tests/integration/api_repo_license_test.go index 6014002726..52d3085694 100644 --- a/tests/integration/api_repo_license_test.go +++ b/tests/integration/api_repo_license_test.go @@ -12,6 +12,7 @@ import ( auth_model "code.gitea.io/gitea/models/auth" api "code.gitea.io/gitea/modules/structs" + "github.com/stretchr/testify/assert" ) From 1043d39be0251a716c7d779f23bb078cbf47d955 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 17 Sep 2024 00:00:30 +0000 Subject: [PATCH 155/158] fix lint --- services/repository/license.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/repository/license.go b/services/repository/license.go index b62ef0009b..b6d2cd7336 100644 --- a/services/repository/license.go +++ b/services/repository/license.go @@ -5,7 +5,6 @@ package repository import ( "context" - "encoding/json" "fmt" "io" @@ -15,6 +14,7 @@ import ( "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/graceful" + "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/options" "code.gitea.io/gitea/modules/queue" From da313ff9f9e01bd26438fc950b8d623efb9f32e0 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 17 Sep 2024 00:33:01 +0000 Subject: [PATCH 156/158] fix lint --- services/convert/repository.go | 2 +- services/repository/license.go | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/services/convert/repository.go b/services/convert/repository.go index ace15102d0..e026d0f440 100644 --- a/services/convert/repository.go +++ b/services/convert/repository.go @@ -243,7 +243,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR RepoTransfer: transfer, Topics: repo.Topics, ObjectFormatName: repo.ObjectFormatName, - Licenses: repoLicenses.StringList(), + Licenses: repoLicenses.StringList(), } } diff --git a/services/repository/license.go b/services/repository/license.go index b6d2cd7336..b4d3638af2 100644 --- a/services/repository/license.go +++ b/services/repository/license.go @@ -161,7 +161,7 @@ func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository, commit return nil } - _, licenseFile, err := findLicenseFile(commit) + licenseFile, err := findLicenseFile(commit) if err != nil { return fmt.Errorf("findLicenseFile: %w", err) } @@ -187,7 +187,7 @@ func GetDetectedLicenseFileName(ctx context.Context, repo *repo_model.Repository if commit == nil { return "", nil } - _, licenseFile, err := findLicenseFile(commit) + licenseFile, err := findLicenseFile(commit) if err != nil { return "", fmt.Errorf("findLicenseFile: %w", err) } @@ -198,15 +198,16 @@ func GetDetectedLicenseFileName(ctx context.Context, repo *repo_model.Repository } // findLicenseFile returns the entry of license file in the repository if it exists -func findLicenseFile(commit *git.Commit) (string, *git.TreeEntry, error) { +func findLicenseFile(commit *git.Commit) (*git.TreeEntry, error) { if commit == nil { - return "", nil, nil + return nil, nil } entries, err := commit.ListEntries() if err != nil { - return "", nil, fmt.Errorf("ListEntries: %w", err) + return nil, fmt.Errorf("ListEntries: %w", err) } - return FindFileInEntries(util.FileTypeLicense, entries, "", "", false) + _, f, err := FindFileInEntries(util.FileTypeLicense, entries, "", "", false) + return f, err } // detectLicense returns the licenses detected by the given content buff From 875daf82e48247bf79bdd91cadb08e72149ac142 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 17 Sep 2024 00:48:24 +0000 Subject: [PATCH 157/158] fix swagger --- routers/api/v1/swagger/repo.go | 7 +++++++ templates/swagger/v1_json.tmpl | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/routers/api/v1/swagger/repo.go b/routers/api/v1/swagger/repo.go index 345835f9a5..b9d2a0217c 100644 --- a/routers/api/v1/swagger/repo.go +++ b/routers/api/v1/swagger/repo.go @@ -359,6 +359,13 @@ type swaggerLanguageStatistics struct { Body map[string]int64 `json:"body"` } +// LicensesList +// swagger:response LicensesList +type swaggerLicensesList struct { + // in: body + Body []string `json:"body"` +} + // CombinedStatus // swagger:response CombinedStatus type swaggerCombinedStatus struct { diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 11033953ec..019a04afad 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -25760,6 +25760,15 @@ } } }, + "LicensesList": { + "description": "LicensesList", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, "MarkdownRender": { "description": "MarkdownRender is a rendered markdown document", "schema": { From 4e18872f693ee8d842693ac1bb2be3a2bec7c1a1 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 17 Sep 2024 02:41:28 +0000 Subject: [PATCH 158/158] fix test --- services/migrations/gitea_uploader_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/migrations/gitea_uploader_test.go b/services/migrations/gitea_uploader_test.go index c9b9248098..f2379dadf8 100644 --- a/services/migrations/gitea_uploader_test.go +++ b/services/migrations/gitea_uploader_test.go @@ -26,6 +26,7 @@ import ( "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/test" + repo_service "code.gitea.io/gitea/services/repository" "github.com/stretchr/testify/assert" ) @@ -302,6 +303,8 @@ func TestGiteaUploadUpdateGitForPullRequest(t *testing.T) { toRepoName := "migrated" uploader := NewGiteaLocalUploader(context.Background(), fromRepoOwner, fromRepoOwner.Name, toRepoName) uploader.gitServiceType = structs.GiteaService + + assert.NoError(t, repo_service.Init(context.Background())) assert.NoError(t, uploader.CreateRepo(&base.Repository{ Description: "description", OriginalURL: fromRepo.RepoPath(),