From fc40a5e24238c46af63a66a8b05bdfba0bd6856d Mon Sep 17 00:00:00 2001 From: Gusted Date: Fri, 23 Aug 2024 03:08:06 +0200 Subject: [PATCH 01/15] [CHORE] Move to new sessioner library - Moves to a fork of gitea.com/go-chi/session that removed support for couchbase (and ledis, but that was never made available in Forgejo) along with other code improvements. https://code.forgejo.org/go-chi/session/compare/f8ce6775954417f3270aafd573d3e4e448a44bad..main - The rationale for removing Couchbase is quite simple. Its not licensed under FOSS license (https://www.couchbase.com/blog/couchbase-adopts-bsl-license/) and therefore cannot be tested by Forgejo and shouldn't be supported. This is a similair vein to the removal of MSSQL support (https://codeberg.org/forgejo/discussions/issues/122) - A additional benefit is that this reduces the Forgejo binary by ~600Kb. --- assets/go-licenses.json | 25 +- cmd/dump.go | 2 +- go.mod | 9 +- go.sum | 18 +- modules/queue/mock/redisuniversalclient.go | 261 ++++++++++++++++++++ modules/session/db.go | 2 +- modules/session/redis.go | 2 +- modules/session/store.go | 2 +- modules/session/virtual.go | 15 +- release-notes/5090.md | 1 + routers/common/middleware.go | 2 +- routers/install/install.go | 2 +- routers/web/admin/config.go | 2 +- services/auth/source/oauth2/store.go | 2 +- services/context/context.go | 2 +- tests/integration/create_no_session_test.go | 2 +- 16 files changed, 294 insertions(+), 55 deletions(-) create mode 100644 release-notes/5090.md diff --git a/assets/go-licenses.json b/assets/go-licenses.json index 090b2b374c..1577cfcebf 100644 --- a/assets/go-licenses.json +++ b/assets/go-licenses.json @@ -14,6 +14,11 @@ "path": "code.forgejo.org/forgejo/reply/LICENSE", "licenseText": "MIT License\n\nCopyright (c) The Forgejo Authors\nCopyright (c) Discourse\nCopyright (c) Claudemiro\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" }, + { + "name": "code.forgejo.org/go-chi/session", + "path": "code.forgejo.org/go-chi/session/LICENSE", + "licenseText": "Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n\"License\" shall mean the terms and conditions for use, reproduction, and\ndistribution as defined by Sections 1 through 9 of this document.\n\n\"Licensor\" shall mean the copyright owner or entity authorized by the copyright\nowner that is granting the License.\n\n\"Legal Entity\" shall mean the union of the acting entity and all other entities\nthat control, are controlled by, or are under common control with that entity.\nFor the purposes of this definition, \"control\" means (i) the power, direct or\nindirect, to cause the direction or management of such entity, whether by\ncontract or otherwise, or (ii) ownership of fifty percent (50%) or more of the\noutstanding shares, or (iii) beneficial ownership of such entity.\n\n\"You\" (or \"Your\") shall mean an individual or Legal Entity exercising\npermissions granted by this License.\n\n\"Source\" form shall mean the preferred form for making modifications, including\nbut not limited to software source code, documentation source, and configuration\nfiles.\n\n\"Object\" form shall mean any form resulting from mechanical transformation or\ntranslation of a Source form, including but not limited to compiled object code,\ngenerated documentation, and conversions to other media types.\n\n\"Work\" shall mean the work of authorship, whether in Source or Object form, made\navailable under the License, as indicated by a copyright notice that is included\nin or attached to the work (an example is provided in the Appendix below).\n\n\"Derivative Works\" shall mean any work, whether in Source or Object form, that\nis based on (or derived from) the Work and for which the editorial revisions,\nannotations, elaborations, or other modifications represent, as a whole, an\noriginal work of authorship. For the purposes of this License, Derivative Works\nshall not include works that remain separable from, or merely link (or bind by\nname) to the interfaces of, the Work and Derivative Works thereof.\n\n\"Contribution\" shall mean any work of authorship, including the original version\nof the Work and any modifications or additions to that Work or Derivative Works\nthereof, that is intentionally submitted to Licensor for inclusion in the Work\nby the copyright owner or by an individual or Legal Entity authorized to submit\non behalf of the copyright owner. For the purposes of this definition,\n\"submitted\" means any form of electronic, verbal, or written communication sent\nto the Licensor or its representatives, including but not limited to\ncommunication on electronic mailing lists, source code control systems, and\nissue tracking systems that are managed by, or on behalf of, the Licensor for\nthe purpose of discussing and improving the Work, but excluding communication\nthat is conspicuously marked or otherwise designated in writing by the copyright\nowner as \"Not a Contribution.\"\n\n\"Contributor\" shall mean Licensor and any individual or Legal Entity on behalf\nof whom a Contribution has been received by Licensor and subsequently\nincorporated within the Work.\n\n2. Grant of Copyright License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable copyright license to reproduce, prepare Derivative Works of,\npublicly display, publicly perform, sublicense, and distribute the Work and such\nDerivative Works in Source or Object form.\n\n3. Grant of Patent License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable (except as stated in this section) patent license to make, have\nmade, use, offer to sell, sell, import, and otherwise transfer the Work, where\nsuch license applies only to those patent claims licensable by such Contributor\nthat are necessarily infringed by their Contribution(s) alone or by combination\nof their Contribution(s) with the Work to which such Contribution(s) was\nsubmitted. If You institute patent litigation against any entity (including a\ncross-claim or counterclaim in a lawsuit) alleging that the Work or a\nContribution incorporated within the Work constitutes direct or contributory\npatent infringement, then any patent licenses granted to You under this License\nfor that Work shall terminate as of the date such litigation is filed.\n\n4. Redistribution.\n\nYou may reproduce and distribute copies of the Work or Derivative Works thereof\nin any medium, with or without modifications, and in Source or Object form,\nprovided that You meet the following conditions:\n\nYou must give any other recipients of the Work or Derivative Works a copy of\nthis License; and\nYou must cause any modified files to carry prominent notices stating that You\nchanged the files; and\nYou must retain, in the Source form of any Derivative Works that You distribute,\nall copyright, patent, trademark, and attribution notices from the Source form\nof the Work, excluding those notices that do not pertain to any part of the\nDerivative Works; and\nIf the Work includes a \"NOTICE\" text file as part of its distribution, then any\nDerivative Works that You distribute must include a readable copy of the\nattribution notices contained within such NOTICE file, excluding those notices\nthat do not pertain to any part of the Derivative Works, in at least one of the\nfollowing places: within a NOTICE text file distributed as part of the\nDerivative Works; within the Source form or documentation, if provided along\nwith the Derivative Works; or, within a display generated by the Derivative\nWorks, if and wherever such third-party notices normally appear. The contents of\nthe NOTICE file are for informational purposes only and do not modify the\nLicense. You may add Your own attribution notices within Derivative Works that\nYou distribute, alongside or as an addendum to the NOTICE text from the Work,\nprovided that such additional attribution notices cannot be construed as\nmodifying the License.\nYou may add Your own copyright statement to Your modifications and may provide\nadditional or different license terms and conditions for use, reproduction, or\ndistribution of Your modifications, or for any such Derivative Works as a whole,\nprovided Your use, reproduction, and distribution of the Work otherwise complies\nwith the conditions stated in this License.\n\n5. Submission of Contributions.\n\nUnless You explicitly state otherwise, any Contribution intentionally submitted\nfor inclusion in the Work by You to the Licensor shall be under the terms and\nconditions of this License, without any additional terms or conditions.\nNotwithstanding the above, nothing herein shall supersede or modify the terms of\nany separate license agreement you may have executed with Licensor regarding\nsuch Contributions.\n\n6. Trademarks.\n\nThis License does not grant permission to use the trade names, trademarks,\nservice marks, or product names of the Licensor, except as required for\nreasonable and customary use in describing the origin of the Work and\nreproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty.\n\nUnless required by applicable law or agreed to in writing, Licensor provides the\nWork (and each Contributor provides its Contributions) on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,\nincluding, without limitation, any warranties or conditions of TITLE,\nNON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are\nsolely responsible for determining the appropriateness of using or\nredistributing the Work and assume any risks associated with Your exercise of\npermissions under this License.\n\n8. Limitation of Liability.\n\nIn no event and under no legal theory, whether in tort (including negligence),\ncontract, or otherwise, unless required by applicable law (such as deliberate\nand grossly negligent acts) or agreed to in writing, shall any Contributor be\nliable to You for damages, including any direct, indirect, special, incidental,\nor consequential damages of any character arising as a result of this License or\nout of the use or inability to use the Work (including but not limited to\ndamages for loss of goodwill, work stoppage, computer failure or malfunction, or\nany and all other commercial damages or losses), even if such Contributor has\nbeen advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability.\n\nWhile redistributing the Work or Derivative Works thereof, You may choose to\noffer, and charge a fee for, acceptance of support, warranty, indemnity, or\nother liability obligations and/or rights consistent with this License. However,\nin accepting such obligations, You may act only on Your own behalf and on Your\nsole responsibility, not on behalf of any other Contributor, and only if You\nagree to indemnify, defend, and hold each Contributor harmless for any liability\nincurred by, or claims asserted against, such Contributor by reason of your\naccepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work\n\nTo apply the Apache License to your work, attach the following boilerplate\nnotice, with the fields enclosed by brackets \"[]\" replaced with your own\nidentifying information. (Don't include the brackets!) The text should be\nenclosed in the appropriate comment syntax for the file format. We also\nrecommend that a file or class name and description of purpose be included on\nthe same \"printed page\" as the copyright notice for easier identification within\nthird-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." + }, { "name": "code.gitea.io/actions-proto-go", "path": "code.gitea.io/actions-proto-go/LICENSE", @@ -69,11 +74,6 @@ "path": "gitea.com/go-chi/captcha/LICENSE", "licenseText": "Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n\"License\" shall mean the terms and conditions for use, reproduction, and\ndistribution as defined by Sections 1 through 9 of this document.\n\n\"Licensor\" shall mean the copyright owner or entity authorized by the copyright\nowner that is granting the License.\n\n\"Legal Entity\" shall mean the union of the acting entity and all other entities\nthat control, are controlled by, or are under common control with that entity.\nFor the purposes of this definition, \"control\" means (i) the power, direct or\nindirect, to cause the direction or management of such entity, whether by\ncontract or otherwise, or (ii) ownership of fifty percent (50%) or more of the\noutstanding shares, or (iii) beneficial ownership of such entity.\n\n\"You\" (or \"Your\") shall mean an individual or Legal Entity exercising\npermissions granted by this License.\n\n\"Source\" form shall mean the preferred form for making modifications, including\nbut not limited to software source code, documentation source, and configuration\nfiles.\n\n\"Object\" form shall mean any form resulting from mechanical transformation or\ntranslation of a Source form, including but not limited to compiled object code,\ngenerated documentation, and conversions to other media types.\n\n\"Work\" shall mean the work of authorship, whether in Source or Object form, made\navailable under the License, as indicated by a copyright notice that is included\nin or attached to the work (an example is provided in the Appendix below).\n\n\"Derivative Works\" shall mean any work, whether in Source or Object form, that\nis based on (or derived from) the Work and for which the editorial revisions,\nannotations, elaborations, or other modifications represent, as a whole, an\noriginal work of authorship. For the purposes of this License, Derivative Works\nshall not include works that remain separable from, or merely link (or bind by\nname) to the interfaces of, the Work and Derivative Works thereof.\n\n\"Contribution\" shall mean any work of authorship, including the original version\nof the Work and any modifications or additions to that Work or Derivative Works\nthereof, that is intentionally submitted to Licensor for inclusion in the Work\nby the copyright owner or by an individual or Legal Entity authorized to submit\non behalf of the copyright owner. For the purposes of this definition,\n\"submitted\" means any form of electronic, verbal, or written communication sent\nto the Licensor or its representatives, including but not limited to\ncommunication on electronic mailing lists, source code control systems, and\nissue tracking systems that are managed by, or on behalf of, the Licensor for\nthe purpose of discussing and improving the Work, but excluding communication\nthat is conspicuously marked or otherwise designated in writing by the copyright\nowner as \"Not a Contribution.\"\n\n\"Contributor\" shall mean Licensor and any individual or Legal Entity on behalf\nof whom a Contribution has been received by Licensor and subsequently\nincorporated within the Work.\n\n2. Grant of Copyright License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable copyright license to reproduce, prepare Derivative Works of,\npublicly display, publicly perform, sublicense, and distribute the Work and such\nDerivative Works in Source or Object form.\n\n3. Grant of Patent License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable (except as stated in this section) patent license to make, have\nmade, use, offer to sell, sell, import, and otherwise transfer the Work, where\nsuch license applies only to those patent claims licensable by such Contributor\nthat are necessarily infringed by their Contribution(s) alone or by combination\nof their Contribution(s) with the Work to which such Contribution(s) was\nsubmitted. If You institute patent litigation against any entity (including a\ncross-claim or counterclaim in a lawsuit) alleging that the Work or a\nContribution incorporated within the Work constitutes direct or contributory\npatent infringement, then any patent licenses granted to You under this License\nfor that Work shall terminate as of the date such litigation is filed.\n\n4. Redistribution.\n\nYou may reproduce and distribute copies of the Work or Derivative Works thereof\nin any medium, with or without modifications, and in Source or Object form,\nprovided that You meet the following conditions:\n\nYou must give any other recipients of the Work or Derivative Works a copy of\nthis License; and\nYou must cause any modified files to carry prominent notices stating that You\nchanged the files; and\nYou must retain, in the Source form of any Derivative Works that You distribute,\nall copyright, patent, trademark, and attribution notices from the Source form\nof the Work, excluding those notices that do not pertain to any part of the\nDerivative Works; and\nIf the Work includes a \"NOTICE\" text file as part of its distribution, then any\nDerivative Works that You distribute must include a readable copy of the\nattribution notices contained within such NOTICE file, excluding those notices\nthat do not pertain to any part of the Derivative Works, in at least one of the\nfollowing places: within a NOTICE text file distributed as part of the\nDerivative Works; within the Source form or documentation, if provided along\nwith the Derivative Works; or, within a display generated by the Derivative\nWorks, if and wherever such third-party notices normally appear. The contents of\nthe NOTICE file are for informational purposes only and do not modify the\nLicense. You may add Your own attribution notices within Derivative Works that\nYou distribute, alongside or as an addendum to the NOTICE text from the Work,\nprovided that such additional attribution notices cannot be construed as\nmodifying the License.\nYou may add Your own copyright statement to Your modifications and may provide\nadditional or different license terms and conditions for use, reproduction, or\ndistribution of Your modifications, or for any such Derivative Works as a whole,\nprovided Your use, reproduction, and distribution of the Work otherwise complies\nwith the conditions stated in this License.\n\n5. Submission of Contributions.\n\nUnless You explicitly state otherwise, any Contribution intentionally submitted\nfor inclusion in the Work by You to the Licensor shall be under the terms and\nconditions of this License, without any additional terms or conditions.\nNotwithstanding the above, nothing herein shall supersede or modify the terms of\nany separate license agreement you may have executed with Licensor regarding\nsuch Contributions.\n\n6. Trademarks.\n\nThis License does not grant permission to use the trade names, trademarks,\nservice marks, or product names of the Licensor, except as required for\nreasonable and customary use in describing the origin of the Work and\nreproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty.\n\nUnless required by applicable law or agreed to in writing, Licensor provides the\nWork (and each Contributor provides its Contributions) on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,\nincluding, without limitation, any warranties or conditions of TITLE,\nNON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are\nsolely responsible for determining the appropriateness of using or\nredistributing the Work and assume any risks associated with Your exercise of\npermissions under this License.\n\n8. Limitation of Liability.\n\nIn no event and under no legal theory, whether in tort (including negligence),\ncontract, or otherwise, unless required by applicable law (such as deliberate\nand grossly negligent acts) or agreed to in writing, shall any Contributor be\nliable to You for damages, including any direct, indirect, special, incidental,\nor consequential damages of any character arising as a result of this License or\nout of the use or inability to use the Work (including but not limited to\ndamages for loss of goodwill, work stoppage, computer failure or malfunction, or\nany and all other commercial damages or losses), even if such Contributor has\nbeen advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability.\n\nWhile redistributing the Work or Derivative Works thereof, You may choose to\noffer, and charge a fee for, acceptance of support, warranty, indemnity, or\nother liability obligations and/or rights consistent with this License. However,\nin accepting such obligations, You may act only on Your own behalf and on Your\nsole responsibility, not on behalf of any other Contributor, and only if You\nagree to indemnify, defend, and hold each Contributor harmless for any liability\nincurred by, or claims asserted against, such Contributor by reason of your\naccepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work\n\nTo apply the Apache License to your work, attach the following boilerplate\nnotice, with the fields enclosed by brackets \"[]\" replaced with your own\nidentifying information. (Don't include the brackets!) The text should be\nenclosed in the appropriate comment syntax for the file format. We also\nrecommend that a file or class name and description of purpose be included on\nthe same \"printed page\" as the copyright notice for easier identification within\nthird-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." }, - { - "name": "gitea.com/go-chi/session", - "path": "gitea.com/go-chi/session/LICENSE", - "licenseText": "Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n\"License\" shall mean the terms and conditions for use, reproduction, and\ndistribution as defined by Sections 1 through 9 of this document.\n\n\"Licensor\" shall mean the copyright owner or entity authorized by the copyright\nowner that is granting the License.\n\n\"Legal Entity\" shall mean the union of the acting entity and all other entities\nthat control, are controlled by, or are under common control with that entity.\nFor the purposes of this definition, \"control\" means (i) the power, direct or\nindirect, to cause the direction or management of such entity, whether by\ncontract or otherwise, or (ii) ownership of fifty percent (50%) or more of the\noutstanding shares, or (iii) beneficial ownership of such entity.\n\n\"You\" (or \"Your\") shall mean an individual or Legal Entity exercising\npermissions granted by this License.\n\n\"Source\" form shall mean the preferred form for making modifications, including\nbut not limited to software source code, documentation source, and configuration\nfiles.\n\n\"Object\" form shall mean any form resulting from mechanical transformation or\ntranslation of a Source form, including but not limited to compiled object code,\ngenerated documentation, and conversions to other media types.\n\n\"Work\" shall mean the work of authorship, whether in Source or Object form, made\navailable under the License, as indicated by a copyright notice that is included\nin or attached to the work (an example is provided in the Appendix below).\n\n\"Derivative Works\" shall mean any work, whether in Source or Object form, that\nis based on (or derived from) the Work and for which the editorial revisions,\nannotations, elaborations, or other modifications represent, as a whole, an\noriginal work of authorship. For the purposes of this License, Derivative Works\nshall not include works that remain separable from, or merely link (or bind by\nname) to the interfaces of, the Work and Derivative Works thereof.\n\n\"Contribution\" shall mean any work of authorship, including the original version\nof the Work and any modifications or additions to that Work or Derivative Works\nthereof, that is intentionally submitted to Licensor for inclusion in the Work\nby the copyright owner or by an individual or Legal Entity authorized to submit\non behalf of the copyright owner. For the purposes of this definition,\n\"submitted\" means any form of electronic, verbal, or written communication sent\nto the Licensor or its representatives, including but not limited to\ncommunication on electronic mailing lists, source code control systems, and\nissue tracking systems that are managed by, or on behalf of, the Licensor for\nthe purpose of discussing and improving the Work, but excluding communication\nthat is conspicuously marked or otherwise designated in writing by the copyright\nowner as \"Not a Contribution.\"\n\n\"Contributor\" shall mean Licensor and any individual or Legal Entity on behalf\nof whom a Contribution has been received by Licensor and subsequently\nincorporated within the Work.\n\n2. Grant of Copyright License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable copyright license to reproduce, prepare Derivative Works of,\npublicly display, publicly perform, sublicense, and distribute the Work and such\nDerivative Works in Source or Object form.\n\n3. Grant of Patent License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable (except as stated in this section) patent license to make, have\nmade, use, offer to sell, sell, import, and otherwise transfer the Work, where\nsuch license applies only to those patent claims licensable by such Contributor\nthat are necessarily infringed by their Contribution(s) alone or by combination\nof their Contribution(s) with the Work to which such Contribution(s) was\nsubmitted. If You institute patent litigation against any entity (including a\ncross-claim or counterclaim in a lawsuit) alleging that the Work or a\nContribution incorporated within the Work constitutes direct or contributory\npatent infringement, then any patent licenses granted to You under this License\nfor that Work shall terminate as of the date such litigation is filed.\n\n4. Redistribution.\n\nYou may reproduce and distribute copies of the Work or Derivative Works thereof\nin any medium, with or without modifications, and in Source or Object form,\nprovided that You meet the following conditions:\n\nYou must give any other recipients of the Work or Derivative Works a copy of\nthis License; and\nYou must cause any modified files to carry prominent notices stating that You\nchanged the files; and\nYou must retain, in the Source form of any Derivative Works that You distribute,\nall copyright, patent, trademark, and attribution notices from the Source form\nof the Work, excluding those notices that do not pertain to any part of the\nDerivative Works; and\nIf the Work includes a \"NOTICE\" text file as part of its distribution, then any\nDerivative Works that You distribute must include a readable copy of the\nattribution notices contained within such NOTICE file, excluding those notices\nthat do not pertain to any part of the Derivative Works, in at least one of the\nfollowing places: within a NOTICE text file distributed as part of the\nDerivative Works; within the Source form or documentation, if provided along\nwith the Derivative Works; or, within a display generated by the Derivative\nWorks, if and wherever such third-party notices normally appear. The contents of\nthe NOTICE file are for informational purposes only and do not modify the\nLicense. You may add Your own attribution notices within Derivative Works that\nYou distribute, alongside or as an addendum to the NOTICE text from the Work,\nprovided that such additional attribution notices cannot be construed as\nmodifying the License.\nYou may add Your own copyright statement to Your modifications and may provide\nadditional or different license terms and conditions for use, reproduction, or\ndistribution of Your modifications, or for any such Derivative Works as a whole,\nprovided Your use, reproduction, and distribution of the Work otherwise complies\nwith the conditions stated in this License.\n\n5. Submission of Contributions.\n\nUnless You explicitly state otherwise, any Contribution intentionally submitted\nfor inclusion in the Work by You to the Licensor shall be under the terms and\nconditions of this License, without any additional terms or conditions.\nNotwithstanding the above, nothing herein shall supersede or modify the terms of\nany separate license agreement you may have executed with Licensor regarding\nsuch Contributions.\n\n6. Trademarks.\n\nThis License does not grant permission to use the trade names, trademarks,\nservice marks, or product names of the Licensor, except as required for\nreasonable and customary use in describing the origin of the Work and\nreproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty.\n\nUnless required by applicable law or agreed to in writing, Licensor provides the\nWork (and each Contributor provides its Contributions) on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,\nincluding, without limitation, any warranties or conditions of TITLE,\nNON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are\nsolely responsible for determining the appropriateness of using or\nredistributing the Work and assume any risks associated with Your exercise of\npermissions under this License.\n\n8. Limitation of Liability.\n\nIn no event and under no legal theory, whether in tort (including negligence),\ncontract, or otherwise, unless required by applicable law (such as deliberate\nand grossly negligent acts) or agreed to in writing, shall any Contributor be\nliable to You for damages, including any direct, indirect, special, incidental,\nor consequential damages of any character arising as a result of this License or\nout of the use or inability to use the Work (including but not limited to\ndamages for loss of goodwill, work stoppage, computer failure or malfunction, or\nany and all other commercial damages or losses), even if such Contributor has\nbeen advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability.\n\nWhile redistributing the Work or Derivative Works thereof, You may choose to\noffer, and charge a fee for, acceptance of support, warranty, indemnity, or\nother liability obligations and/or rights consistent with this License. However,\nin accepting such obligations, You may act only on Your own behalf and on Your\nsole responsibility, not on behalf of any other Contributor, and only if You\nagree to indemnify, defend, and hold each Contributor harmless for any liability\nincurred by, or claims asserted against, such Contributor by reason of your\naccepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work\n\nTo apply the Apache License to your work, attach the following boilerplate\nnotice, with the fields enclosed by brackets \"[]\" replaced with your own\nidentifying information. (Don't include the brackets!) The text should be\nenclosed in the appropriate comment syntax for the file format. We also\nrecommend that a file or class name and description of purpose be included on\nthe same \"printed page\" as the copyright notice for easier identification within\nthird-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." - }, { "name": "gitea.com/lunny/levelqueue", "path": "gitea.com/lunny/levelqueue/LICENSE", @@ -279,21 +279,6 @@ "path": "github.com/cloudflare/circl/LICENSE", "licenseText": "Copyright (c) 2019 Cloudflare. 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 Cloudflare 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\n========================================================================\n\nCopyright (c) 2009 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/couchbase/go-couchbase", - "path": "github.com/couchbase/go-couchbase/LICENSE", - "licenseText": "Copyright (c) 2013 Couchbase, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" - }, - { - "name": "github.com/couchbase/gomemcached", - "path": "github.com/couchbase/gomemcached/LICENSE", - "licenseText": "Copyright (c) 2013 Dustin Sallings\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n" - }, - { - "name": "github.com/couchbase/goutils", - "path": "github.com/couchbase/goutils/LICENSE.md", - "licenseText": "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\n" - }, { "name": "github.com/cpuguy83/go-md2man/v2/md2man", "path": "github.com/cpuguy83/go-md2man/v2/md2man/LICENSE.md", diff --git a/cmd/dump.go b/cmd/dump.go index 0a18adb27d..5c641995a9 100644 --- a/cmd/dump.go +++ b/cmd/dump.go @@ -20,7 +20,7 @@ import ( "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/util" - "gitea.com/go-chi/session" + "code.forgejo.org/go-chi/session" "github.com/mholt/archiver/v3" "github.com/urfave/cli/v2" ) diff --git a/go.mod b/go.mod index 269bc1a040..b29d425803 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.23.0 require ( code.forgejo.org/f3/gof3/v3 v3.7.0 code.forgejo.org/forgejo/reply v1.0.2 + code.forgejo.org/go-chi/session v0.0.0-20240825010209-bd25d509c8bf code.gitea.io/actions-proto-go v0.4.0 code.gitea.io/gitea-vet v0.2.3 code.gitea.io/sdk/gitea v0.17.1 @@ -13,7 +14,6 @@ require ( gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed gitea.com/go-chi/cache v0.2.0 gitea.com/go-chi/captcha v0.0.0-20240315150714-fb487f629098 - gitea.com/go-chi/session v0.0.0-20240316035857-16768d98ec96 gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4 github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121 github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 @@ -37,7 +37,7 @@ require ( github.com/gliderlabs/ssh v0.3.7 github.com/go-ap/activitypub v0.0.0-20231114162308-e219254dc5c9 github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73 - github.com/go-chi/chi/v5 v5.0.14 + github.com/go-chi/chi/v5 v5.1.0 github.com/go-chi/cors v1.2.1 github.com/go-co-op/gocron v1.37.0 github.com/go-enry/go-enry/v2 v2.8.8 @@ -84,7 +84,7 @@ require ( github.com/pquerna/otp v1.4.0 github.com/prometheus/client_golang v1.18.0 github.com/quasoft/websspi v1.1.2 - github.com/redis/go-redis/v9 v9.5.2 + github.com/redis/go-redis/v9 v9.6.1 github.com/robfig/cron/v3 v3.0.1 github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 github.com/sassoftware/go-rpmutils v0.4.0 @@ -161,9 +161,6 @@ require ( github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudflare/circl v1.3.8 // indirect - github.com/couchbase/go-couchbase v0.1.1 // indirect - github.com/couchbase/gomemcached v0.3.0 // indirect - github.com/couchbase/goutils v0.1.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect diff --git a/go.sum b/go.sum index f3c8cdc4e9..6bbe43d9f7 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ code.forgejo.org/forgejo/archiver/v3 v3.5.1 h1:UmmbA7D5550uf71SQjarmrn6yKwOGxtEj code.forgejo.org/forgejo/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4= code.forgejo.org/forgejo/reply v1.0.2 h1:dMhQCHV6/O3L5CLWNTol+dNzDAuyCK88z4J/lCdgFuQ= code.forgejo.org/forgejo/reply v1.0.2/go.mod h1:RyZUfzQLc+fuLIGjTSQWDAJWPiL4WtKXB/FifT5fM7U= +code.forgejo.org/go-chi/session v0.0.0-20240825010209-bd25d509c8bf h1:gJRuqEPd3/U0/1YM+uSgbC/fpR8qrcMdvT6E7eSetyM= +code.forgejo.org/go-chi/session v0.0.0-20240825010209-bd25d509c8bf/go.mod h1:PcnIg89MAhO1yExkw1QXXNDiPssVdCsMmwUo67g7GD4= code.gitea.io/actions-proto-go v0.4.0 h1:OsPBPhodXuQnsspG1sQ4eRE1PeoZyofd7+i73zCwnsU= code.gitea.io/actions-proto-go v0.4.0/go.mod h1:mn7Wkqz6JbnTOHQpot3yDeHx+O5C9EGhMEE+htvHBas= code.gitea.io/gitea-vet v0.2.3 h1:gdFmm6WOTM65rE8FUBTRzeQZYzXePKSSB1+r574hWwI= @@ -30,8 +32,6 @@ gitea.com/go-chi/cache v0.2.0 h1:E0npuTfDW6CT1yD8NMDVc1SK6IeRjfmRL2zlEsCEd7w= gitea.com/go-chi/cache v0.2.0/go.mod h1:iQlVK2aKTZ/rE9UcHyz9pQWGvdP9i1eI2spOpzgCrtE= gitea.com/go-chi/captcha v0.0.0-20240315150714-fb487f629098 h1:p2ki+WK0cIeNQuqjR98IP2KZQKRzJJiV7aTeMAFwaWo= gitea.com/go-chi/captcha v0.0.0-20240315150714-fb487f629098/go.mod h1:LjzIOHlRemuUyO7WR12fmm18VZIlCAaOt9L3yKw40pk= -gitea.com/go-chi/session v0.0.0-20240316035857-16768d98ec96 h1:IFDiMBObsP6CZIRaDLd54SR6zPYAffPXiXck5Xslu0Q= -gitea.com/go-chi/session v0.0.0-20240316035857-16768d98ec96/go.mod h1:0iEpFKnwO5dG0aF98O4eq6FMsAiXkNBaDIlUOlq4BtM= gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4 h1:IFT+hup2xejHqdhS7keYWioqfmxdnfblFDTGoOwcZ+o= gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4/go.mod h1:HBqmLbz56JWpfEGG0prskAV97ATNRoj5LDmPicD22hU= gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s= @@ -166,12 +166,6 @@ github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38 github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cloudflare/circl v1.3.8 h1:j+V8jJt09PoeMFIu2uh5JUyEaIHTXVOHslFoLNAKqwI= github.com/cloudflare/circl v1.3.8/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU= -github.com/couchbase/go-couchbase v0.1.1 h1:ClFXELcKj/ojyoTYbsY34QUrrYCBi/1G749sXSCkdhk= -github.com/couchbase/go-couchbase v0.1.1/go.mod h1:+/bddYDxXsf9qt0xpDUtRR47A2GjaXmGGAqQ/k3GJ8A= -github.com/couchbase/gomemcached v0.3.0 h1:XkMDdP6w7rtvLijDE0/RhcccX+XvAk5cboyBv1YcI0U= -github.com/couchbase/gomemcached v0.3.0/go.mod h1:mxliKQxOv84gQ0bJWbI+w9Wxdpt9HjDvgW9MjCym5Vo= -github.com/couchbase/goutils v0.1.2 h1:gWr8B6XNWPIhfalHNog3qQKfGiYyh4K4VhO3P2o9BCs= -github.com/couchbase/goutils v0.1.2/go.mod h1:h89Ek/tiOxxqjz30nPPlwZdQbdB8BwgnuBxeoUe/ViE= github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -244,8 +238,8 @@ github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73/go.mod h1:jyveZeGw5La github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA= github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-chi/chi/v5 v5.0.1/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= -github.com/go-chi/chi/v5 v5.0.14 h1:PyEwo2Vudraa0x/Wl6eDRRW2NXBvekgfxyydcM0WGE0= -github.com/go-chi/chi/v5 v5.0.14/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= +github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= github.com/go-co-op/gocron v1.37.0 h1:ZYDJGtQ4OMhTLKOKMIch+/CY70Brbb1dGdooLEhh7b0= @@ -610,8 +604,8 @@ github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/quasoft/websspi v1.1.2 h1:/mA4w0LxWlE3novvsoEL6BBA1WnjJATbjkh1kFrTidw= github.com/quasoft/websspi v1.1.2/go.mod h1:HmVdl939dQ0WIXZhyik+ARdI03M6bQzaSEKcgpFmewk= -github.com/redis/go-redis/v9 v9.5.2 h1:L0L3fcSNReTRGyZ6AqAEN0K56wYeYAwapBIhkvh0f3E= -github.com/redis/go-redis/v9 v9.5.2/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= +github.com/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0y4= +github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rhysd/actionlint v1.6.27 h1:xxwe8YmveBcC8lydW6GoHMGmB6H/MTqUU60F2p10wjw= diff --git a/modules/queue/mock/redisuniversalclient.go b/modules/queue/mock/redisuniversalclient.go index 95e6f6d5a8..a5ad7b2823 100644 --- a/modules/queue/mock/redisuniversalclient.go +++ b/modules/queue/mock/redisuniversalclient.go @@ -2540,6 +2540,101 @@ func (mr *MockUniversalClientMockRecorder) HExists(arg0, arg1, arg2 any) *gomock return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HExists", reflect.TypeOf((*MockUniversalClient)(nil).HExists), arg0, arg1, arg2) } +// HExpire mocks base method. +func (m *MockUniversalClient) HExpire(arg0 context.Context, arg1 string, arg2 time.Duration, arg3 ...string) *redis.IntSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2} + for _, a := range arg3 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "HExpire", varargs...) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// HExpire indicates an expected call of HExpire. +func (mr *MockUniversalClientMockRecorder) HExpire(arg0, arg1, arg2 any, arg3 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HExpire", reflect.TypeOf((*MockUniversalClient)(nil).HExpire), varargs...) +} + +// HExpireAt mocks base method. +func (m *MockUniversalClient) HExpireAt(arg0 context.Context, arg1 string, arg2 time.Time, arg3 ...string) *redis.IntSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2} + for _, a := range arg3 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "HExpireAt", varargs...) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// HExpireAt indicates an expected call of HExpireAt. +func (mr *MockUniversalClientMockRecorder) HExpireAt(arg0, arg1, arg2 any, arg3 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HExpireAt", reflect.TypeOf((*MockUniversalClient)(nil).HExpireAt), varargs...) +} + +// HExpireAtWithArgs mocks base method. +func (m *MockUniversalClient) HExpireAtWithArgs(arg0 context.Context, arg1 string, arg2 time.Time, arg3 redis.HExpireArgs, arg4 ...string) *redis.IntSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2, arg3} + for _, a := range arg4 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "HExpireAtWithArgs", varargs...) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// HExpireAtWithArgs indicates an expected call of HExpireAtWithArgs. +func (mr *MockUniversalClientMockRecorder) HExpireAtWithArgs(arg0, arg1, arg2, arg3 any, arg4 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2, arg3}, arg4...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HExpireAtWithArgs", reflect.TypeOf((*MockUniversalClient)(nil).HExpireAtWithArgs), varargs...) +} + +// HExpireTime mocks base method. +func (m *MockUniversalClient) HExpireTime(arg0 context.Context, arg1 string, arg2 ...string) *redis.IntSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "HExpireTime", varargs...) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// HExpireTime indicates an expected call of HExpireTime. +func (mr *MockUniversalClientMockRecorder) HExpireTime(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HExpireTime", reflect.TypeOf((*MockUniversalClient)(nil).HExpireTime), varargs...) +} + +// HExpireWithArgs mocks base method. +func (m *MockUniversalClient) HExpireWithArgs(arg0 context.Context, arg1 string, arg2 time.Duration, arg3 redis.HExpireArgs, arg4 ...string) *redis.IntSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2, arg3} + for _, a := range arg4 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "HExpireWithArgs", varargs...) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// HExpireWithArgs indicates an expected call of HExpireWithArgs. +func (mr *MockUniversalClientMockRecorder) HExpireWithArgs(arg0, arg1, arg2, arg3 any, arg4 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2, arg3}, arg4...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HExpireWithArgs", reflect.TypeOf((*MockUniversalClient)(nil).HExpireWithArgs), varargs...) +} + // HGet mocks base method. func (m *MockUniversalClient) HGet(arg0 context.Context, arg1, arg2 string) *redis.StringCmd { m.ctrl.T.Helper() @@ -2662,6 +2757,139 @@ func (mr *MockUniversalClientMockRecorder) HMSet(arg0, arg1 any, arg2 ...any) *g return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HMSet", reflect.TypeOf((*MockUniversalClient)(nil).HMSet), varargs...) } +// HPExpire mocks base method. +func (m *MockUniversalClient) HPExpire(arg0 context.Context, arg1 string, arg2 time.Duration, arg3 ...string) *redis.IntSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2} + for _, a := range arg3 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "HPExpire", varargs...) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// HPExpire indicates an expected call of HPExpire. +func (mr *MockUniversalClientMockRecorder) HPExpire(arg0, arg1, arg2 any, arg3 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HPExpire", reflect.TypeOf((*MockUniversalClient)(nil).HPExpire), varargs...) +} + +// HPExpireAt mocks base method. +func (m *MockUniversalClient) HPExpireAt(arg0 context.Context, arg1 string, arg2 time.Time, arg3 ...string) *redis.IntSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2} + for _, a := range arg3 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "HPExpireAt", varargs...) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// HPExpireAt indicates an expected call of HPExpireAt. +func (mr *MockUniversalClientMockRecorder) HPExpireAt(arg0, arg1, arg2 any, arg3 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HPExpireAt", reflect.TypeOf((*MockUniversalClient)(nil).HPExpireAt), varargs...) +} + +// HPExpireAtWithArgs mocks base method. +func (m *MockUniversalClient) HPExpireAtWithArgs(arg0 context.Context, arg1 string, arg2 time.Time, arg3 redis.HExpireArgs, arg4 ...string) *redis.IntSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2, arg3} + for _, a := range arg4 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "HPExpireAtWithArgs", varargs...) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// HPExpireAtWithArgs indicates an expected call of HPExpireAtWithArgs. +func (mr *MockUniversalClientMockRecorder) HPExpireAtWithArgs(arg0, arg1, arg2, arg3 any, arg4 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2, arg3}, arg4...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HPExpireAtWithArgs", reflect.TypeOf((*MockUniversalClient)(nil).HPExpireAtWithArgs), varargs...) +} + +// HPExpireTime mocks base method. +func (m *MockUniversalClient) HPExpireTime(arg0 context.Context, arg1 string, arg2 ...string) *redis.IntSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "HPExpireTime", varargs...) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// HPExpireTime indicates an expected call of HPExpireTime. +func (mr *MockUniversalClientMockRecorder) HPExpireTime(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HPExpireTime", reflect.TypeOf((*MockUniversalClient)(nil).HPExpireTime), varargs...) +} + +// HPExpireWithArgs mocks base method. +func (m *MockUniversalClient) HPExpireWithArgs(arg0 context.Context, arg1 string, arg2 time.Duration, arg3 redis.HExpireArgs, arg4 ...string) *redis.IntSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1, arg2, arg3} + for _, a := range arg4 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "HPExpireWithArgs", varargs...) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// HPExpireWithArgs indicates an expected call of HPExpireWithArgs. +func (mr *MockUniversalClientMockRecorder) HPExpireWithArgs(arg0, arg1, arg2, arg3 any, arg4 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1, arg2, arg3}, arg4...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HPExpireWithArgs", reflect.TypeOf((*MockUniversalClient)(nil).HPExpireWithArgs), varargs...) +} + +// HPTTL mocks base method. +func (m *MockUniversalClient) HPTTL(arg0 context.Context, arg1 string, arg2 ...string) *redis.IntSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "HPTTL", varargs...) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// HPTTL indicates an expected call of HPTTL. +func (mr *MockUniversalClientMockRecorder) HPTTL(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HPTTL", reflect.TypeOf((*MockUniversalClient)(nil).HPTTL), varargs...) +} + +// HPersist mocks base method. +func (m *MockUniversalClient) HPersist(arg0 context.Context, arg1 string, arg2 ...string) *redis.IntSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "HPersist", varargs...) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// HPersist indicates an expected call of HPersist. +func (mr *MockUniversalClientMockRecorder) HPersist(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HPersist", reflect.TypeOf((*MockUniversalClient)(nil).HPersist), varargs...) +} + // HRandField mocks base method. func (m *MockUniversalClient) HRandField(arg0 context.Context, arg1 string, arg2 int) *redis.StringSliceCmd { m.ctrl.T.Helper() @@ -2704,6 +2932,20 @@ func (mr *MockUniversalClientMockRecorder) HScan(arg0, arg1, arg2, arg3, arg4 an return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HScan", reflect.TypeOf((*MockUniversalClient)(nil).HScan), arg0, arg1, arg2, arg3, arg4) } +// HScanNoValues mocks base method. +func (m *MockUniversalClient) HScanNoValues(arg0 context.Context, arg1 string, arg2 uint64, arg3 string, arg4 int64) *redis.ScanCmd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HScanNoValues", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(*redis.ScanCmd) + return ret0 +} + +// HScanNoValues indicates an expected call of HScanNoValues. +func (mr *MockUniversalClientMockRecorder) HScanNoValues(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HScanNoValues", reflect.TypeOf((*MockUniversalClient)(nil).HScanNoValues), arg0, arg1, arg2, arg3, arg4) +} + // HSet mocks base method. func (m *MockUniversalClient) HSet(arg0 context.Context, arg1 string, arg2 ...any) *redis.IntCmd { m.ctrl.T.Helper() @@ -2737,6 +2979,25 @@ func (mr *MockUniversalClientMockRecorder) HSetNX(arg0, arg1, arg2, arg3 any) *g return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HSetNX", reflect.TypeOf((*MockUniversalClient)(nil).HSetNX), arg0, arg1, arg2, arg3) } +// HTTL mocks base method. +func (m *MockUniversalClient) HTTL(arg0 context.Context, arg1 string, arg2 ...string) *redis.IntSliceCmd { + m.ctrl.T.Helper() + varargs := []any{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "HTTL", varargs...) + ret0, _ := ret[0].(*redis.IntSliceCmd) + return ret0 +} + +// HTTL indicates an expected call of HTTL. +func (mr *MockUniversalClientMockRecorder) HTTL(arg0, arg1 any, arg2 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HTTL", reflect.TypeOf((*MockUniversalClient)(nil).HTTL), varargs...) +} + // HVals mocks base method. func (m *MockUniversalClient) HVals(arg0 context.Context, arg1 string) *redis.StringSliceCmd { m.ctrl.T.Helper() diff --git a/modules/session/db.go b/modules/session/db.go index 9909f2dc1e..3b12b93521 100644 --- a/modules/session/db.go +++ b/modules/session/db.go @@ -11,7 +11,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/timeutil" - "gitea.com/go-chi/session" + "code.forgejo.org/go-chi/session" ) // DBStore represents a session store implementation based on the DB. diff --git a/modules/session/redis.go b/modules/session/redis.go index d4cca3f43e..69cf6b1a4a 100644 --- a/modules/session/redis.go +++ b/modules/session/redis.go @@ -25,7 +25,7 @@ import ( "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/nosql" - "gitea.com/go-chi/session" + "code.forgejo.org/go-chi/session" "github.com/redis/go-redis/v9" ) diff --git a/modules/session/store.go b/modules/session/store.go index 70988fcdc5..baab26315d 100644 --- a/modules/session/store.go +++ b/modules/session/store.go @@ -6,7 +6,7 @@ package session import ( "net/http" - "gitea.com/go-chi/session" + "code.forgejo.org/go-chi/session" ) // Store represents a session store diff --git a/modules/session/virtual.go b/modules/session/virtual.go index 80352b6e72..9cf3683a71 100644 --- a/modules/session/virtual.go +++ b/modules/session/virtual.go @@ -8,12 +8,12 @@ import ( "sync" "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/log" - "gitea.com/go-chi/session" - couchbase "gitea.com/go-chi/session/couchbase" - memcache "gitea.com/go-chi/session/memcache" - mysql "gitea.com/go-chi/session/mysql" - postgres "gitea.com/go-chi/session/postgres" + "code.forgejo.org/go-chi/session" + memcache "code.forgejo.org/go-chi/session/memcache" + mysql "code.forgejo.org/go-chi/session/mysql" + postgres "code.forgejo.org/go-chi/session/postgres" ) // VirtualSessionProvider represents a shadowed session provider implementation. @@ -35,6 +35,9 @@ func (o *VirtualSessionProvider) Init(gclifetime int64, config string) error { switch opts.Provider { case "memory": o.provider = &session.MemProvider{} + case "couchbase": + log.Warn("Couchbase as session provider is no longer supported, falling back to file as session provider") + fallthrough case "file": o.provider = &session.FileProvider{} case "redis": @@ -45,8 +48,6 @@ func (o *VirtualSessionProvider) Init(gclifetime int64, config string) error { o.provider = &mysql.MysqlProvider{} case "postgres": o.provider = &postgres.PostgresProvider{} - case "couchbase": - o.provider = &couchbase.CouchbaseProvider{} case "memcache": o.provider = &memcache.MemcacheProvider{} default: diff --git a/release-notes/5090.md b/release-notes/5090.md new file mode 100644 index 0000000000..dba7855147 --- /dev/null +++ b/release-notes/5090.md @@ -0,0 +1 @@ +Remove support for Couchbase as a session provider; it instead will now fallback to the file provider. The rationale for removing Couchbase support is that it's not free software, https://www.couchbase.com/blog/couchbase-adopts-bsl-license/, and therefore cannot be tested in Forgejo and neither should be supported. diff --git a/routers/common/middleware.go b/routers/common/middleware.go index c7c75fb099..59e59b8d3f 100644 --- a/routers/common/middleware.go +++ b/routers/common/middleware.go @@ -15,7 +15,7 @@ import ( "code.gitea.io/gitea/modules/web/routing" "code.gitea.io/gitea/services/context" - "gitea.com/go-chi/session" + "code.forgejo.org/go-chi/session" "github.com/chi-middleware/proxy" chi "github.com/go-chi/chi/v5" ) diff --git a/routers/install/install.go b/routers/install/install.go index 140e008d9a..24db25f459 100644 --- a/routers/install/install.go +++ b/routers/install/install.go @@ -36,7 +36,7 @@ import ( "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" - "gitea.com/go-chi/session" + "code.forgejo.org/go-chi/session" ) const ( diff --git a/routers/web/admin/config.go b/routers/web/admin/config.go index 09f332b447..06d0ea60fb 100644 --- a/routers/web/admin/config.go +++ b/routers/web/admin/config.go @@ -22,7 +22,7 @@ import ( "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/mailer" - "gitea.com/go-chi/session" + "code.forgejo.org/go-chi/session" ) const ( diff --git a/services/auth/source/oauth2/store.go b/services/auth/source/oauth2/store.go index 90fa965602..e031653119 100644 --- a/services/auth/source/oauth2/store.go +++ b/services/auth/source/oauth2/store.go @@ -11,7 +11,7 @@ import ( "code.gitea.io/gitea/modules/log" session_module "code.gitea.io/gitea/modules/session" - chiSession "gitea.com/go-chi/session" + chiSession "code.forgejo.org/go-chi/session" "github.com/gorilla/sessions" ) diff --git a/services/context/context.go b/services/context/context.go index 3e113e76ba..6ab3ae761d 100644 --- a/services/context/context.go +++ b/services/context/context.go @@ -27,8 +27,8 @@ import ( "code.gitea.io/gitea/modules/web/middleware" web_types "code.gitea.io/gitea/modules/web/types" + "code.forgejo.org/go-chi/session" "gitea.com/go-chi/cache" - "gitea.com/go-chi/session" ) // Render represents a template render diff --git a/tests/integration/create_no_session_test.go b/tests/integration/create_no_session_test.go index 044b823737..ca2a775459 100644 --- a/tests/integration/create_no_session_test.go +++ b/tests/integration/create_no_session_test.go @@ -15,7 +15,7 @@ import ( "code.gitea.io/gitea/routers" "code.gitea.io/gitea/tests" - "gitea.com/go-chi/session" + "code.forgejo.org/go-chi/session" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) From 3af7e03aeb2ef5ccba96669641949e4bcb67a32f Mon Sep 17 00:00:00 2001 From: Gusted Date: Mon, 26 Aug 2024 03:29:27 +0200 Subject: [PATCH 02/15] [CHORE] Remove unused `exclude` This was introduced in https://github.com/go-gitea/gitea/pull/18311 to exclude a vulnerable dependency. I am not sure when this happened or with which dependency update, but this dependency is no longer being used by another dependency and therefore these `exclude`s are no longer needed. (Verified via `go mod graph`). --- go.mod | 8 -------- 1 file changed, 8 deletions(-) diff --git a/go.mod b/go.mod index ee339da6d6..42c0faacdd 100644 --- a/go.mod +++ b/go.mod @@ -300,12 +300,4 @@ replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142 replace github.com/nektos/act => code.forgejo.org/forgejo/act v1.21.2 -exclude github.com/gofrs/uuid v3.2.0+incompatible - -exclude github.com/gofrs/uuid v4.0.0+incompatible - -exclude github.com/goccy/go-json v0.4.11 - -exclude github.com/satori/go.uuid v1.2.0 - replace github.com/mholt/archiver/v3 => code.forgejo.org/forgejo/archiver/v3 v3.5.1 From 0ca13c5eaef536dade65f4587b9ce1d144111f87 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 21 Aug 2024 01:04:57 +0800 Subject: [PATCH 03/15] [PORT] Refactor the usage of batch catfile (gitea#31754) When opening a repository, it will call `ensureValidRepository` and also `CatFileBatch`. But sometimes these will not be used until repository closed. So it's a waste of CPU to invoke 3 times git command for every open repository. This PR removed all of these from `OpenRepository` but only kept checking whether the folder exists. When a batch is necessary, the necessary functions will be invoked. --- Conflict resolution: Because of the removal of go-git in (#4941) `_nogogit.go` files were either renamed or merged into the 'common' file. Git does handle the renames correctly, but for those that were merged has to be manually copied pasted over. The patch looks the same, 201 additions 90 deletions as the original patch. (cherry picked from commit c03baab678ba5b2e9d974aea147e660417f5d3f7) --- modules/git/batch.go | 46 +++++++++ modules/git/batch_reader.go | 12 +-- modules/git/blob.go | 15 ++- modules/git/commit_info.go | 5 +- modules/git/pipeline/lfs.go | 5 +- modules/git/repo_base.go | 96 ++++++++++--------- modules/git/repo_branch.go | 16 +++- modules/git/repo_commit.go | 21 +++- modules/git/repo_language_stats.go | 5 +- modules/git/repo_tag.go | 12 ++- modules/git/repo_tree.go | 5 +- modules/git/tree.go | 5 +- modules/git/tree_entry.go | 8 +- modules/indexer/code/bleve/bleve.go | 20 ++-- .../code/elasticsearch/elasticsearch.go | 20 ++-- 15 files changed, 201 insertions(+), 90 deletions(-) create mode 100644 modules/git/batch.go diff --git a/modules/git/batch.go b/modules/git/batch.go new file mode 100644 index 0000000000..3ec4f1ddcc --- /dev/null +++ b/modules/git/batch.go @@ -0,0 +1,46 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package git + +import ( + "bufio" + "context" +) + +type Batch struct { + cancel context.CancelFunc + Reader *bufio.Reader + Writer WriteCloserError +} + +func (repo *Repository) NewBatch(ctx context.Context) (*Batch, error) { + // Now because of some insanity with git cat-file not immediately failing if not run in a valid git directory we need to run git rev-parse first! + if err := ensureValidGitRepository(ctx, repo.Path); err != nil { + return nil, err + } + + var batch Batch + batch.Writer, batch.Reader, batch.cancel = catFileBatch(ctx, repo.Path) + return &batch, nil +} + +func (repo *Repository) NewBatchCheck(ctx context.Context) (*Batch, error) { + // Now because of some insanity with git cat-file not immediately failing if not run in a valid git directory we need to run git rev-parse first! + if err := ensureValidGitRepository(ctx, repo.Path); err != nil { + return nil, err + } + + var check Batch + check.Writer, check.Reader, check.cancel = catFileBatchCheck(ctx, repo.Path) + return &check, nil +} + +func (b *Batch) Close() { + if b.cancel != nil { + b.cancel() + b.Reader = nil + b.Writer = nil + b.cancel = nil + } +} diff --git a/modules/git/batch_reader.go b/modules/git/batch_reader.go index c988d6ab86..3b1a466b2e 100644 --- a/modules/git/batch_reader.go +++ b/modules/git/batch_reader.go @@ -26,10 +26,10 @@ type WriteCloserError interface { CloseWithError(err error) error } -// EnsureValidGitRepository runs git rev-parse in the repository path - thus ensuring that the repository is a valid repository. +// ensureValidGitRepository runs git rev-parse in the repository path - thus ensuring that the repository is a valid repository. // Run before opening git cat-file. // This is needed otherwise the git cat-file will hang for invalid repositories. -func EnsureValidGitRepository(ctx context.Context, repoPath string) error { +func ensureValidGitRepository(ctx context.Context, repoPath string) error { stderr := strings.Builder{} err := NewCommand(ctx, "rev-parse"). SetDescription(fmt.Sprintf("%s rev-parse [repo_path: %s]", GitExecutable, repoPath)). @@ -43,8 +43,8 @@ func EnsureValidGitRepository(ctx context.Context, repoPath string) error { return nil } -// CatFileBatchCheck opens git cat-file --batch-check in the provided repo and returns a stdin pipe, a stdout reader and cancel function -func CatFileBatchCheck(ctx context.Context, repoPath string) (WriteCloserError, *bufio.Reader, func()) { +// catFileBatchCheck opens git cat-file --batch-check in the provided repo and returns a stdin pipe, a stdout reader and cancel function +func catFileBatchCheck(ctx context.Context, repoPath string) (WriteCloserError, *bufio.Reader, func()) { batchStdinReader, batchStdinWriter := io.Pipe() batchStdoutReader, batchStdoutWriter := io.Pipe() ctx, ctxCancel := context.WithCancel(ctx) @@ -93,8 +93,8 @@ func CatFileBatchCheck(ctx context.Context, repoPath string) (WriteCloserError, return batchStdinWriter, batchReader, cancel } -// CatFileBatch opens git cat-file --batch in the provided repo and returns a stdin pipe, a stdout reader and cancel function -func CatFileBatch(ctx context.Context, repoPath string) (WriteCloserError, *bufio.Reader, func()) { +// catFileBatch opens git cat-file --batch in the provided repo and returns a stdin pipe, a stdout reader and cancel function +func catFileBatch(ctx context.Context, repoPath string) (WriteCloserError, *bufio.Reader, func()) { // We often want to feed the commits in order into cat-file --batch, followed by their trees and sub trees as necessary. // so let's create a batch stdin and stdout batchStdinReader, batchStdinWriter := io.Pipe() diff --git a/modules/git/blob.go b/modules/git/blob.go index 3de8ce8e90..2f02693428 100644 --- a/modules/git/blob.go +++ b/modules/git/blob.go @@ -28,9 +28,12 @@ type Blob struct { // DataAsync gets a ReadCloser for the contents of a blob without reading it all. // Calling the Close function on the result will discard all unread output. func (b *Blob) DataAsync() (io.ReadCloser, error) { - wr, rd, cancel := b.repo.CatFileBatch(b.repo.Ctx) + wr, rd, cancel, err := b.repo.CatFileBatch(b.repo.Ctx) + if err != nil { + return nil, err + } - _, err := wr.Write([]byte(b.ID.String() + "\n")) + _, err = wr.Write([]byte(b.ID.String() + "\n")) if err != nil { cancel() return nil, err @@ -66,9 +69,13 @@ func (b *Blob) Size() int64 { return b.size } - wr, rd, cancel := b.repo.CatFileBatchCheck(b.repo.Ctx) + wr, rd, cancel, err := b.repo.CatFileBatchCheck(b.repo.Ctx) + if err != nil { + log.Debug("error whilst reading size for %s in %s. Error: %v", b.ID.String(), b.repo.Path, err) + return 0 + } defer cancel() - _, err := wr.Write([]byte(b.ID.String() + "\n")) + _, err = wr.Write([]byte(b.ID.String() + "\n")) if err != nil { log.Debug("error whilst reading size for %s in %s. Error: %v", b.ID.String(), b.repo.Path, err) return 0 diff --git a/modules/git/commit_info.go b/modules/git/commit_info.go index a26d749320..3b34b7933a 100644 --- a/modules/git/commit_info.go +++ b/modules/git/commit_info.go @@ -129,7 +129,10 @@ func GetLastCommitForPaths(ctx context.Context, commit *Commit, treePath string, return nil, err } - batchStdinWriter, batchReader, cancel := commit.repo.CatFileBatch(ctx) + batchStdinWriter, batchReader, cancel, err := commit.repo.CatFileBatch(ctx) + if err != nil { + return nil, err + } defer cancel() commitsMap := map[string]*Commit{} diff --git a/modules/git/pipeline/lfs.go b/modules/git/pipeline/lfs.go index 55c49aaf3d..3407eb9838 100644 --- a/modules/git/pipeline/lfs.go +++ b/modules/git/pipeline/lfs.go @@ -67,7 +67,10 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err // Next feed the commits in order into cat-file --batch, followed by their trees and sub trees as necessary. // so let's create a batch stdin and stdout - batchStdinWriter, batchReader, cancel := repo.CatFileBatch(repo.Ctx) + batchStdinWriter, batchReader, cancel, err := repo.CatFileBatch(repo.Ctx) + if err != nil { + return nil, err + } defer cancel() // We'll use a scanner for the revList because it's simpler than a bufio.Reader diff --git a/modules/git/repo_base.go b/modules/git/repo_base.go index 8c34efc2c7..5f17bc14f6 100644 --- a/modules/git/repo_base.go +++ b/modules/git/repo_base.go @@ -21,15 +21,11 @@ type Repository struct { gpgSettings *GPGSettings - batchInUse bool - batchCancel context.CancelFunc - batchReader *bufio.Reader - batchWriter WriteCloserError + batchInUse bool + batch *Batch - checkInUse bool - checkCancel context.CancelFunc - checkReader *bufio.Reader - checkWriter WriteCloserError + checkInUse bool + check *Batch Ctx context.Context LastCommitCache *LastCommitCache @@ -51,63 +47,75 @@ func OpenRepository(ctx context.Context, repoPath string) (*Repository, error) { return nil, errors.New("no such file or directory") } - // Now because of some insanity with git cat-file not immediately failing if not run in a valid git directory we need to run git rev-parse first! - if err := EnsureValidGitRepository(ctx, repoPath); err != nil { - return nil, err - } - - repo := &Repository{ + return &Repository{ Path: repoPath, tagCache: newObjectCache(), Ctx: ctx, - } - - repo.batchWriter, repo.batchReader, repo.batchCancel = CatFileBatch(ctx, repoPath) - repo.checkWriter, repo.checkReader, repo.checkCancel = CatFileBatchCheck(ctx, repoPath) - - return repo, nil + }, nil } // CatFileBatch obtains a CatFileBatch for this repository -func (repo *Repository) CatFileBatch(ctx context.Context) (WriteCloserError, *bufio.Reader, func()) { - if repo.batchCancel == nil || repo.batchInUse { - log.Debug("Opening temporary cat file batch for: %s", repo.Path) - return CatFileBatch(ctx, repo.Path) +func (repo *Repository) CatFileBatch(ctx context.Context) (WriteCloserError, *bufio.Reader, func(), error) { + if repo.batch == nil { + var err error + repo.batch, err = repo.NewBatch(ctx) + if err != nil { + return nil, nil, nil, err + } } - repo.batchInUse = true - return repo.batchWriter, repo.batchReader, func() { - repo.batchInUse = false + + if !repo.batchInUse { + repo.batchInUse = true + return repo.batch.Writer, repo.batch.Reader, func() { + repo.batchInUse = false + }, nil } + + log.Debug("Opening temporary cat file batch for: %s", repo.Path) + tempBatch, err := repo.NewBatch(ctx) + if err != nil { + return nil, nil, nil, err + } + return tempBatch.Writer, tempBatch.Reader, tempBatch.Close, nil } // CatFileBatchCheck obtains a CatFileBatchCheck for this repository -func (repo *Repository) CatFileBatchCheck(ctx context.Context) (WriteCloserError, *bufio.Reader, func()) { - if repo.checkCancel == nil || repo.checkInUse { - log.Debug("Opening temporary cat file batch-check for: %s", repo.Path) - return CatFileBatchCheck(ctx, repo.Path) +func (repo *Repository) CatFileBatchCheck(ctx context.Context) (WriteCloserError, *bufio.Reader, func(), error) { + if repo.check == nil { + var err error + repo.check, err = repo.NewBatchCheck(ctx) + if err != nil { + return nil, nil, nil, err + } } - repo.checkInUse = true - return repo.checkWriter, repo.checkReader, func() { - repo.checkInUse = false + + if !repo.checkInUse { + repo.checkInUse = true + return repo.check.Writer, repo.check.Reader, func() { + repo.checkInUse = false + }, nil } + + log.Debug("Opening temporary cat file batch-check for: %s", repo.Path) + tempBatchCheck, err := repo.NewBatchCheck(ctx) + if err != nil { + return nil, nil, nil, err + } + return tempBatchCheck.Writer, tempBatchCheck.Reader, tempBatchCheck.Close, nil } func (repo *Repository) Close() error { if repo == nil { return nil } - if repo.batchCancel != nil { - repo.batchCancel() - repo.batchReader = nil - repo.batchWriter = nil - repo.batchCancel = nil + if repo.batch != nil { + repo.batch.Close() + repo.batch = nil repo.batchInUse = false } - if repo.checkCancel != nil { - repo.checkCancel() - repo.checkCancel = nil - repo.checkReader = nil - repo.checkWriter = nil + if repo.check != nil { + repo.check.Close() + repo.check = nil repo.checkInUse = false } repo.LastCommitCache = nil diff --git a/modules/git/repo_branch.go b/modules/git/repo_branch.go index dff3a43fa3..7339c7db0d 100644 --- a/modules/git/repo_branch.go +++ b/modules/git/repo_branch.go @@ -169,9 +169,13 @@ func (repo *Repository) IsObjectExist(name string) bool { return false } - wr, rd, cancel := repo.CatFileBatchCheck(repo.Ctx) + wr, rd, cancel, err := repo.CatFileBatchCheck(repo.Ctx) + if err != nil { + log.Debug("Error writing to CatFileBatchCheck %v", err) + return false + } defer cancel() - _, err := wr.Write([]byte(name + "\n")) + _, err = wr.Write([]byte(name + "\n")) if err != nil { log.Debug("Error writing to CatFileBatchCheck %v", err) return false @@ -186,9 +190,13 @@ func (repo *Repository) IsReferenceExist(name string) bool { return false } - wr, rd, cancel := repo.CatFileBatchCheck(repo.Ctx) + wr, rd, cancel, err := repo.CatFileBatchCheck(repo.Ctx) + if err != nil { + log.Debug("Error writing to CatFileBatchCheck %v", err) + return false + } defer cancel() - _, err := wr.Write([]byte(name + "\n")) + _, err = wr.Write([]byte(name + "\n")) if err != nil { log.Debug("Error writing to CatFileBatchCheck %v", err) return false diff --git a/modules/git/repo_commit.go b/modules/git/repo_commit.go index 2a325d3644..1f3d64fe03 100644 --- a/modules/git/repo_commit.go +++ b/modules/git/repo_commit.go @@ -536,9 +536,12 @@ func (repo *Repository) ResolveReference(name string) (string, error) { // GetRefCommitID returns the last commit ID string of given reference (branch or tag). func (repo *Repository) GetRefCommitID(name string) (string, error) { - wr, rd, cancel := repo.CatFileBatchCheck(repo.Ctx) + wr, rd, cancel, err := repo.CatFileBatchCheck(repo.Ctx) + if err != nil { + return "", err + } defer cancel() - _, err := wr.Write([]byte(name + "\n")) + _, err = wr.Write([]byte(name + "\n")) if err != nil { return "", err } @@ -564,12 +567,19 @@ func (repo *Repository) RemoveReference(name string) error { // IsCommitExist returns true if given commit exists in current repository. func (repo *Repository) IsCommitExist(name string) bool { + if err := ensureValidGitRepository(repo.Ctx, repo.Path); err != nil { + log.Error("IsCommitExist: %v", err) + return false + } _, _, err := NewCommand(repo.Ctx, "cat-file", "-e").AddDynamicArguments(name).RunStdString(&RunOpts{Dir: repo.Path}) return err == nil } func (repo *Repository) getCommit(id ObjectID) (*Commit, error) { - wr, rd, cancel := repo.CatFileBatch(repo.Ctx) + wr, rd, cancel, err := repo.CatFileBatch(repo.Ctx) + if err != nil { + return nil, err + } defer cancel() _, _ = wr.Write([]byte(id.String() + "\n")) @@ -646,7 +656,10 @@ func (repo *Repository) ConvertToGitID(commitID string) (ObjectID, error) { } } - wr, rd, cancel := repo.CatFileBatchCheck(repo.Ctx) + wr, rd, cancel, err := repo.CatFileBatchCheck(repo.Ctx) + if err != nil { + return nil, err + } defer cancel() _, err = wr.Write([]byte(commitID + "\n")) if err != nil { diff --git a/modules/git/repo_language_stats.go b/modules/git/repo_language_stats.go index 84638b3cef..37c23faf68 100644 --- a/modules/git/repo_language_stats.go +++ b/modules/git/repo_language_stats.go @@ -60,7 +60,10 @@ func mergeLanguageStats(stats map[string]int64) map[string]int64 { func (repo *Repository) GetLanguageStats(commitID string) (map[string]int64, 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) + batchStdinWriter, batchReader, cancel, err := repo.CatFileBatch(repo.Ctx) + if err != nil { + return nil, err + } defer cancel() writeID := func(id string) error { diff --git a/modules/git/repo_tag.go b/modules/git/repo_tag.go index d925d4a7d3..12b0c022cb 100644 --- a/modules/git/repo_tag.go +++ b/modules/git/repo_tag.go @@ -257,9 +257,12 @@ func (repo *Repository) GetTags(skip, limit int) (tags []string, err error) { // GetTagType gets the type of the tag, either commit (simple) or tag (annotated) func (repo *Repository) GetTagType(id ObjectID) (string, error) { - wr, rd, cancel := repo.CatFileBatchCheck(repo.Ctx) + wr, rd, cancel, err := repo.CatFileBatchCheck(repo.Ctx) + if err != nil { + return "", err + } defer cancel() - _, err := wr.Write([]byte(id.String() + "\n")) + _, err = wr.Write([]byte(id.String() + "\n")) if err != nil { return "", err } @@ -315,7 +318,10 @@ func (repo *Repository) getTag(tagID ObjectID, name string) (*Tag, error) { } // The tag is an annotated tag with a message. - wr, rd, cancel := repo.CatFileBatch(repo.Ctx) + wr, rd, cancel, err := repo.CatFileBatch(repo.Ctx) + if err != nil { + return nil, err + } defer cancel() if _, err := wr.Write([]byte(tagID.String() + "\n")); err != nil { diff --git a/modules/git/repo_tree.go b/modules/git/repo_tree.go index 79a7e50eb4..53d94d9d7d 100644 --- a/modules/git/repo_tree.go +++ b/modules/git/repo_tree.go @@ -68,7 +68,10 @@ func (repo *Repository) CommitTree(author, committer *Signature, tree *Tree, opt } func (repo *Repository) getTree(id ObjectID) (*Tree, error) { - wr, rd, cancel := repo.CatFileBatch(repo.Ctx) + wr, rd, cancel, err := repo.CatFileBatch(repo.Ctx) + if err != nil { + return nil, err + } defer cancel() _, _ = wr.Write([]byte(id.String() + "\n")) diff --git a/modules/git/tree.go b/modules/git/tree.go index 422fe68caa..5b06cbf359 100644 --- a/modules/git/tree.go +++ b/modules/git/tree.go @@ -41,7 +41,10 @@ func (t *Tree) ListEntries() (Entries, error) { } if t.repo != nil { - wr, rd, cancel := t.repo.CatFileBatch(t.repo.Ctx) + wr, rd, cancel, err := t.repo.CatFileBatch(t.repo.Ctx) + if err != nil { + return nil, err + } defer cancel() _, _ = wr.Write([]byte(t.ID.String() + "\n")) diff --git a/modules/git/tree_entry.go b/modules/git/tree_entry.go index b5dd801309..0d9cfd2258 100644 --- a/modules/git/tree_entry.go +++ b/modules/git/tree_entry.go @@ -47,9 +47,13 @@ func (te *TreeEntry) Size() int64 { return te.size } - wr, rd, cancel := te.ptree.repo.CatFileBatchCheck(te.ptree.repo.Ctx) + wr, rd, cancel, err := te.ptree.repo.CatFileBatchCheck(te.ptree.repo.Ctx) + if err != nil { + log.Debug("error whilst reading size for %s in %s. Error: %v", te.ID.String(), te.ptree.repo.Path, err) + return 0 + } defer cancel() - _, err := wr.Write([]byte(te.ID.String() + "\n")) + _, err = wr.Write([]byte(te.ID.String() + "\n")) if err != nil { log.Debug("error whilst reading size for %s in %s. Error: %v", te.ID.String(), te.ptree.repo.Path, err) return 0 diff --git a/modules/indexer/code/bleve/bleve.go b/modules/indexer/code/bleve/bleve.go index 66724a3445..cf9fcbd8b5 100644 --- a/modules/indexer/code/bleve/bleve.go +++ b/modules/indexer/code/bleve/bleve.go @@ -16,10 +16,10 @@ import ( "code.gitea.io/gitea/modules/analyze" "code.gitea.io/gitea/modules/charset" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/indexer/code/internal" indexer_internal "code.gitea.io/gitea/modules/indexer/internal" inner_bleve "code.gitea.io/gitea/modules/indexer/internal/bleve" - "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/typesniffer" @@ -193,21 +193,23 @@ func (b *Indexer) addDelete(filename string, repo *repo_model.Repository, batch func (b *Indexer) Index(ctx context.Context, repo *repo_model.Repository, sha string, changes *internal.RepoChanges) error { batch := inner_bleve.NewFlushingBatch(b.inner.Indexer, maxBatchSize) if len(changes.Updates) > 0 { - // Now because of some insanity with git cat-file not immediately failing if not run in a valid git directory we need to run git rev-parse first! - if err := git.EnsureValidGitRepository(ctx, repo.RepoPath()); err != nil { - log.Error("Unable to open git repo: %s for %-v: %v", repo.RepoPath(), repo, err) + r, err := gitrepo.OpenRepository(ctx, repo) + if err != nil { return err } - - batchWriter, batchReader, cancel := git.CatFileBatch(ctx, repo.RepoPath()) - defer cancel() + defer r.Close() + gitBatch, err := r.NewBatch(ctx) + if err != nil { + return err + } + defer gitBatch.Close() for _, update := range changes.Updates { - if err := b.addUpdate(ctx, batchWriter, batchReader, sha, update, repo, batch); err != nil { + if err := b.addUpdate(ctx, gitBatch.Writer, gitBatch.Reader, sha, update, repo, batch); err != nil { return err } } - cancel() + gitBatch.Close() } for _, filename := range changes.RemovedFilenames { if err := b.addDelete(filename, repo, batch); err != nil { diff --git a/modules/indexer/code/elasticsearch/elasticsearch.go b/modules/indexer/code/elasticsearch/elasticsearch.go index e4622fd66e..0bda180fac 100644 --- a/modules/indexer/code/elasticsearch/elasticsearch.go +++ b/modules/indexer/code/elasticsearch/elasticsearch.go @@ -15,11 +15,11 @@ import ( "code.gitea.io/gitea/modules/analyze" "code.gitea.io/gitea/modules/charset" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/indexer/code/internal" indexer_internal "code.gitea.io/gitea/modules/indexer/internal" inner_elasticsearch "code.gitea.io/gitea/modules/indexer/internal/elasticsearch" "code.gitea.io/gitea/modules/json" - "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/typesniffer" @@ -154,17 +154,19 @@ func (b *Indexer) addDelete(filename string, repo *repo_model.Repository) elasti func (b *Indexer) Index(ctx context.Context, repo *repo_model.Repository, sha string, changes *internal.RepoChanges) error { reqs := make([]elastic.BulkableRequest, 0) if len(changes.Updates) > 0 { - // Now because of some insanity with git cat-file not immediately failing if not run in a valid git directory we need to run git rev-parse first! - if err := git.EnsureValidGitRepository(ctx, repo.RepoPath()); err != nil { - log.Error("Unable to open git repo: %s for %-v: %v", repo.RepoPath(), repo, err) + r, err := gitrepo.OpenRepository(ctx, repo) + if err != nil { return err } - - batchWriter, batchReader, cancel := git.CatFileBatch(ctx, repo.RepoPath()) - defer cancel() + defer r.Close() + batch, err := r.NewBatch(ctx) + if err != nil { + return err + } + defer batch.Close() for _, update := range changes.Updates { - updateReqs, err := b.addUpdate(ctx, batchWriter, batchReader, sha, update, repo) + updateReqs, err := b.addUpdate(ctx, batch.Writer, batch.Reader, sha, update, repo) if err != nil { return err } @@ -172,7 +174,7 @@ func (b *Indexer) Index(ctx context.Context, repo *repo_model.Repository, sha st reqs = append(reqs, updateReqs...) } } - cancel() + batch.Close() } for _, filename := range changes.RemovedFilenames { From 24bbf051c3d1f1567dd8ea143ac7a4d3cafbd7b5 Mon Sep 17 00:00:00 2001 From: Gusted Date: Mon, 26 Aug 2024 04:46:27 +0200 Subject: [PATCH 04/15] [TESTS] Add test for CatFileBatch(Check) --- modules/git/repo_base_test.go | 163 ++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 modules/git/repo_base_test.go diff --git a/modules/git/repo_base_test.go b/modules/git/repo_base_test.go new file mode 100644 index 0000000000..323b28f476 --- /dev/null +++ b/modules/git/repo_base_test.go @@ -0,0 +1,163 @@ +// Copyright 2024 The Forgejo Authors. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-or-later + +package git + +import ( + "bufio" + "context" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// This unit test relies on the implementation detail of CatFileBatch. +func TestCatFileBatch(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + repo, err := OpenRepository(ctx, "./tests/repos/repo1_bare") + require.NoError(t, err) + defer repo.Close() + + var wr WriteCloserError + var r *bufio.Reader + var cancel1 func() + t.Run("Request cat file batch", func(t *testing.T) { + assert.Nil(t, repo.batch) + wr, r, cancel1, err = repo.CatFileBatch(ctx) + require.NoError(t, err) + assert.NotNil(t, repo.batch) + assert.Equal(t, repo.batch.Writer, wr) + assert.True(t, repo.batchInUse) + }) + + t.Run("Request temporary cat file batch", func(t *testing.T) { + wr, r, cancel, err := repo.CatFileBatch(ctx) + require.NoError(t, err) + assert.NotEqual(t, repo.batch.Writer, wr) + + t.Run("Check temporary cat file batch", func(t *testing.T) { + _, err = wr.Write([]byte("95bb4d39648ee7e325106df01a621c530863a653" + "\n")) + require.NoError(t, err) + + sha, typ, size, err := ReadBatchLine(r) + require.NoError(t, err) + assert.Equal(t, "commit", typ) + assert.EqualValues(t, []byte("95bb4d39648ee7e325106df01a621c530863a653"), sha) + assert.EqualValues(t, 144, size) + }) + + cancel() + assert.True(t, repo.batchInUse) + }) + + t.Run("Check cached cat file batch", func(t *testing.T) { + _, err = wr.Write([]byte("95bb4d39648ee7e325106df01a621c530863a653" + "\n")) + require.NoError(t, err) + + sha, typ, size, err := ReadBatchLine(r) + require.NoError(t, err) + assert.Equal(t, "commit", typ) + assert.EqualValues(t, []byte("95bb4d39648ee7e325106df01a621c530863a653"), sha) + assert.EqualValues(t, 144, size) + }) + + t.Run("Cancel cached cat file batch", func(t *testing.T) { + cancel1() + assert.False(t, repo.batchInUse) + assert.NotNil(t, repo.batch) + }) + + t.Run("Request cached cat file batch", func(t *testing.T) { + wr, _, _, err := repo.CatFileBatch(ctx) + require.NoError(t, err) + assert.NotNil(t, repo.batch) + assert.Equal(t, repo.batch.Writer, wr) + assert.True(t, repo.batchInUse) + + t.Run("Close git repo", func(t *testing.T) { + require.NoError(t, repo.Close()) + assert.Nil(t, repo.batch) + }) + + _, err = wr.Write([]byte("95bb4d39648ee7e325106df01a621c530863a653" + "\n")) + require.Error(t, err) + }) +} + +// This unit test relies on the implementation detail of CatFileBatchCheck. +func TestCatFileBatchCheck(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + repo, err := OpenRepository(ctx, "./tests/repos/repo1_bare") + require.NoError(t, err) + defer repo.Close() + + var wr WriteCloserError + var r *bufio.Reader + var cancel1 func() + t.Run("Request cat file batch check", func(t *testing.T) { + assert.Nil(t, repo.check) + wr, r, cancel1, err = repo.CatFileBatchCheck(ctx) + require.NoError(t, err) + assert.NotNil(t, repo.check) + assert.Equal(t, repo.check.Writer, wr) + assert.True(t, repo.checkInUse) + }) + + t.Run("Request temporary cat file batch check", func(t *testing.T) { + wr, r, cancel, err := repo.CatFileBatchCheck(ctx) + require.NoError(t, err) + assert.NotEqual(t, repo.check.Writer, wr) + + t.Run("Check temporary cat file batch check", func(t *testing.T) { + _, err = wr.Write([]byte("test" + "\n")) + require.NoError(t, err) + + sha, typ, size, err := ReadBatchLine(r) + require.NoError(t, err) + assert.Equal(t, "tag", typ) + assert.EqualValues(t, []byte("3ad28a9149a2864384548f3d17ed7f38014c9e8a"), sha) + assert.EqualValues(t, 807, size) + }) + + cancel() + assert.True(t, repo.checkInUse) + }) + + t.Run("Check cached cat file batch check", func(t *testing.T) { + _, err = wr.Write([]byte("test" + "\n")) + require.NoError(t, err) + + sha, typ, size, err := ReadBatchLine(r) + require.NoError(t, err) + assert.Equal(t, "tag", typ) + assert.EqualValues(t, []byte("3ad28a9149a2864384548f3d17ed7f38014c9e8a"), sha) + assert.EqualValues(t, 807, size) + }) + + t.Run("Cancel cached cat file batch check", func(t *testing.T) { + cancel1() + assert.False(t, repo.checkInUse) + assert.NotNil(t, repo.check) + }) + + t.Run("Request cached cat file batch check", func(t *testing.T) { + wr, _, _, err := repo.CatFileBatchCheck(ctx) + require.NoError(t, err) + assert.NotNil(t, repo.check) + assert.Equal(t, repo.check.Writer, wr) + assert.True(t, repo.checkInUse) + + t.Run("Close git repo", func(t *testing.T) { + require.NoError(t, repo.Close()) + assert.Nil(t, repo.check) + }) + + _, err = wr.Write([]byte("test" + "\n")) + require.Error(t, err) + }) +} From fbe464309bdf133c398c402dd3ecac2661d94279 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 26 Aug 2024 04:05:34 +0000 Subject: [PATCH 05/15] Update renovate to v38.52.3 --- .forgejo/workflows/renovate.yml | 2 +- Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.forgejo/workflows/renovate.yml b/.forgejo/workflows/renovate.yml index 20093b5f21..aebf7b107b 100644 --- a/.forgejo/workflows/renovate.yml +++ b/.forgejo/workflows/renovate.yml @@ -23,7 +23,7 @@ jobs: runs-on: docker container: - image: code.forgejo.org/forgejo-contrib/renovate:38.39.6 + image: code.forgejo.org/forgejo-contrib/renovate:38.52.3 steps: - name: Load renovate repo cache diff --git a/Makefile b/Makefile index 7a0d24c5e0..fc1473bc24 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,7 @@ GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1 # renovate: datasour DEADCODE_PACKAGE ?= golang.org/x/tools/cmd/deadcode@v0.24.0 # renovate: datasource=go GOMOCK_PACKAGE ?= go.uber.org/mock/mockgen@v0.4.0 # renovate: datasource=go GOPLS_PACKAGE ?= golang.org/x/tools/gopls@v0.16.1 # renovate: datasource=go -RENOVATE_NPM_PACKAGE ?= renovate@38.39.6 # renovate: datasource=docker packageName=code.forgejo.org/forgejo-contrib/renovate +RENOVATE_NPM_PACKAGE ?= renovate@38.52.3 # renovate: datasource=docker packageName=code.forgejo.org/forgejo-contrib/renovate ifeq ($(HAS_GO), yes) CGO_EXTRA_CFLAGS := -DSQLITE_MAX_VARIABLE_NUMBER=32766 From b44dcf553cda964028c57cdf60ad8605d9000786 Mon Sep 17 00:00:00 2001 From: Gusted Date: Mon, 26 Aug 2024 08:03:48 +0200 Subject: [PATCH 06/15] [TESTS] Fix usage of `LoadRepoCommit` It loads the Commit with a temporary open GitRepo. This is incorrect, the GitRepo should be open as long as the Commit can be used. This mainly removes the usage of this function as it's not needed. --- routers/api/v1/repo/hook_test.go | 6 +- routers/web/repo/editor_test.go | 12 +-- services/contexttest/context_tests.go | 27 ++++-- services/repository/files/content_test.go | 102 ++++++--------------- services/repository/files/diff_test.go | 19 ++-- services/repository/files/file_test.go | 16 +--- services/repository/files/tree_test.go | 1 - tests/integration/repo_view_test.go | 7 +- tests/integration/repofiles_change_test.go | 84 +++-------------- 9 files changed, 84 insertions(+), 190 deletions(-) diff --git a/routers/api/v1/repo/hook_test.go b/routers/api/v1/repo/hook_test.go index 37cf61c1ed..a8065e4a60 100644 --- a/routers/api/v1/repo/hook_test.go +++ b/routers/api/v1/repo/hook_test.go @@ -19,9 +19,11 @@ func TestTestHook(t *testing.T) { ctx, _ := contexttest.MockAPIContext(t, "user2/repo1/wiki/_pages") ctx.SetParams(":id", "1") - contexttest.LoadRepo(t, ctx, 1) - contexttest.LoadRepoCommit(t, ctx) contexttest.LoadUser(t, ctx, 2) + contexttest.LoadRepo(t, ctx, 1) + contexttest.LoadGitRepo(t, ctx) + defer ctx.Repo.GitRepo.Close() + contexttest.LoadRepoCommit(t, ctx) TestHook(ctx) assert.EqualValues(t, http.StatusNoContent, ctx.Resp.Status()) diff --git a/routers/web/repo/editor_test.go b/routers/web/repo/editor_test.go index 313fcfe33a..4d565b5fd6 100644 --- a/routers/web/repo/editor_test.go +++ b/routers/web/repo/editor_test.go @@ -6,6 +6,7 @@ package repo import ( "testing" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" @@ -45,7 +46,6 @@ func TestGetUniquePatchBranchName(t *testing.T) { ctx, _ := contexttest.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") contexttest.LoadRepo(t, ctx, 1) - contexttest.LoadRepoCommit(t, ctx) contexttest.LoadUser(t, ctx, 2) contexttest.LoadGitRepo(t, ctx) defer ctx.Repo.GitRepo.Close() @@ -57,15 +57,7 @@ func TestGetUniquePatchBranchName(t *testing.T) { func TestGetClosestParentWithFiles(t *testing.T) { unittest.PrepareTestEnv(t) - ctx, _ := contexttest.MockContext(t, "user2/repo1") - ctx.SetParams(":id", "1") - contexttest.LoadRepo(t, ctx, 1) - contexttest.LoadRepoCommit(t, ctx) - contexttest.LoadUser(t, ctx, 2) - contexttest.LoadGitRepo(t, ctx) - defer ctx.Repo.GitRepo.Close() - - repo := ctx.Repo.Repository + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) branch := repo.DefaultBranch gitRepo, _ := gitrepo.OpenRepository(git.DefaultContext, repo) defer gitRepo.Close() diff --git a/services/contexttest/context_tests.go b/services/contexttest/context_tests.go index a4cc967a57..7c829f3598 100644 --- a/services/contexttest/context_tests.go +++ b/services/contexttest/context_tests.go @@ -136,14 +136,15 @@ func LoadRepoCommit(t *testing.T, ctx gocontext.Context) { assert.FailNow(t, "context is not *context.Context or *context.APIContext") } - gitRepo, err := gitrepo.OpenRepository(ctx, repo.Repository) - require.NoError(t, err) - defer gitRepo.Close() - branch, err := gitRepo.GetHEADBranch() + if repo.GitRepo == nil { + assert.FailNow(t, "must call LoadGitRepo") + } + + branch, err := repo.GitRepo.GetHEADBranch() require.NoError(t, err) assert.NotNil(t, branch) if branch != nil { - repo.Commit, err = gitRepo.GetBranchCommit(branch.Name) + repo.Commit, err = repo.GitRepo.GetBranchCommit(branch.Name) require.NoError(t, err) } } @@ -176,10 +177,20 @@ func LoadOrganization(t *testing.T, ctx gocontext.Context, orgID int64) { // LoadGitRepo load a git repo into a test context. Requires that ctx.Repo has // already been populated. -func LoadGitRepo(t *testing.T, ctx *context.Context) { - require.NoError(t, ctx.Repo.Repository.LoadOwner(ctx)) +func LoadGitRepo(t *testing.T, ctx gocontext.Context) { + var repo *context.Repository + switch ctx := ctx.(type) { + case *context.Context: + repo = ctx.Repo + case *context.APIContext: + repo = ctx.Repo + default: + assert.FailNow(t, "context is not *context.Context or *context.APIContext") + } + + require.NoError(t, repo.Repository.LoadOwner(ctx)) var err error - ctx.Repo.GitRepo, err = gitrepo.OpenRepository(ctx, ctx.Repo.Repository) + repo.GitRepo, err = gitrepo.OpenRepository(ctx, repo.Repository) require.NoError(t, err) } diff --git a/services/repository/files/content_test.go b/services/repository/files/content_test.go index 768d6d2f39..c22dcd2e8d 100644 --- a/services/repository/files/content_test.go +++ b/services/repository/files/content_test.go @@ -6,10 +6,11 @@ package files import ( "testing" + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/modules/gitrepo" api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/services/contexttest" _ "code.gitea.io/gitea/models/actions" @@ -53,27 +54,21 @@ func getExpectedReadmeContentsResponse() *api.ContentsResponse { func TestGetContents(t *testing.T) { unittest.PrepareTestEnv(t) - ctx, _ := contexttest.MockContext(t, "user2/repo1") - ctx.SetParams(":id", "1") - contexttest.LoadRepo(t, ctx, 1) - contexttest.LoadRepoCommit(t, ctx) - contexttest.LoadUser(t, ctx, 2) - contexttest.LoadGitRepo(t, ctx) - defer ctx.Repo.GitRepo.Close() + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) treePath := "README.md" - ref := ctx.Repo.Repository.DefaultBranch + ref := repo.DefaultBranch expectedContentsResponse := getExpectedReadmeContentsResponse() t.Run("Get README.md contents with GetContents(ctx, )", func(t *testing.T) { - fileContentResponse, err := GetContents(ctx, ctx.Repo.Repository, treePath, ref, false) + fileContentResponse, err := GetContents(db.DefaultContext, repo, treePath, ref, false) assert.EqualValues(t, expectedContentsResponse, fileContentResponse) require.NoError(t, err) }) t.Run("Get README.md contents with ref as empty string (should then use the repo's default branch) with GetContents(ctx, )", func(t *testing.T) { - fileContentResponse, err := GetContents(ctx, ctx.Repo.Repository, treePath, "", false) + fileContentResponse, err := GetContents(db.DefaultContext, repo, treePath, "", false) assert.EqualValues(t, expectedContentsResponse, fileContentResponse) require.NoError(t, err) }) @@ -81,16 +76,10 @@ func TestGetContents(t *testing.T) { func TestGetContentsOrListForDir(t *testing.T) { unittest.PrepareTestEnv(t) - ctx, _ := contexttest.MockContext(t, "user2/repo1") - ctx.SetParams(":id", "1") - contexttest.LoadRepo(t, ctx, 1) - contexttest.LoadRepoCommit(t, ctx) - contexttest.LoadUser(t, ctx, 2) - contexttest.LoadGitRepo(t, ctx) - defer ctx.Repo.GitRepo.Close() + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) treePath := "" // root dir - ref := ctx.Repo.Repository.DefaultBranch + ref := repo.DefaultBranch readmeContentsResponse := getExpectedReadmeContentsResponse() // because will be in a list, doesn't have encoding and content @@ -102,13 +91,13 @@ func TestGetContentsOrListForDir(t *testing.T) { } t.Run("Get root dir contents with GetContentsOrList(ctx, )", func(t *testing.T) { - fileContentResponse, err := GetContentsOrList(ctx, ctx.Repo.Repository, treePath, ref) + fileContentResponse, err := GetContentsOrList(db.DefaultContext, repo, treePath, ref) assert.EqualValues(t, expectedContentsListResponse, fileContentResponse) require.NoError(t, err) }) t.Run("Get root dir contents with ref as empty string (should then use the repo's default branch) with GetContentsOrList(ctx, )", func(t *testing.T) { - fileContentResponse, err := GetContentsOrList(ctx, ctx.Repo.Repository, treePath, "") + fileContentResponse, err := GetContentsOrList(db.DefaultContext, repo, treePath, "") assert.EqualValues(t, expectedContentsListResponse, fileContentResponse) require.NoError(t, err) }) @@ -116,27 +105,21 @@ func TestGetContentsOrListForDir(t *testing.T) { func TestGetContentsOrListForFile(t *testing.T) { unittest.PrepareTestEnv(t) - ctx, _ := contexttest.MockContext(t, "user2/repo1") - ctx.SetParams(":id", "1") - contexttest.LoadRepo(t, ctx, 1) - contexttest.LoadRepoCommit(t, ctx) - contexttest.LoadUser(t, ctx, 2) - contexttest.LoadGitRepo(t, ctx) - defer ctx.Repo.GitRepo.Close() + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) treePath := "README.md" - ref := ctx.Repo.Repository.DefaultBranch + ref := repo.DefaultBranch expectedContentsResponse := getExpectedReadmeContentsResponse() t.Run("Get README.md contents with GetContentsOrList(ctx, )", func(t *testing.T) { - fileContentResponse, err := GetContentsOrList(ctx, ctx.Repo.Repository, treePath, ref) + fileContentResponse, err := GetContentsOrList(db.DefaultContext, repo, treePath, ref) assert.EqualValues(t, expectedContentsResponse, fileContentResponse) require.NoError(t, err) }) t.Run("Get README.md contents with ref as empty string (should then use the repo's default branch) with GetContentsOrList(ctx, )", func(t *testing.T) { - fileContentResponse, err := GetContentsOrList(ctx, ctx.Repo.Repository, treePath, "") + fileContentResponse, err := GetContentsOrList(db.DefaultContext, repo, treePath, "") assert.EqualValues(t, expectedContentsResponse, fileContentResponse) require.NoError(t, err) }) @@ -144,28 +127,21 @@ func TestGetContentsOrListForFile(t *testing.T) { func TestGetContentsErrors(t *testing.T) { unittest.PrepareTestEnv(t) - ctx, _ := contexttest.MockContext(t, "user2/repo1") - ctx.SetParams(":id", "1") - contexttest.LoadRepo(t, ctx, 1) - contexttest.LoadRepoCommit(t, ctx) - contexttest.LoadUser(t, ctx, 2) - contexttest.LoadGitRepo(t, ctx) - defer ctx.Repo.GitRepo.Close() + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) - repo := ctx.Repo.Repository treePath := "README.md" ref := repo.DefaultBranch t.Run("bad treePath", func(t *testing.T) { badTreePath := "bad/tree.md" - fileContentResponse, err := GetContents(ctx, repo, badTreePath, ref, false) + fileContentResponse, err := GetContents(db.DefaultContext, repo, badTreePath, ref, false) require.EqualError(t, err, "object does not exist [id: , rel_path: bad]") assert.Nil(t, fileContentResponse) }) t.Run("bad ref", func(t *testing.T) { badRef := "bad_ref" - fileContentResponse, err := GetContents(ctx, repo, treePath, badRef, false) + fileContentResponse, err := GetContents(db.DefaultContext, repo, treePath, badRef, false) require.EqualError(t, err, "object does not exist [id: "+badRef+", rel_path: ]") assert.Nil(t, fileContentResponse) }) @@ -173,28 +149,21 @@ func TestGetContentsErrors(t *testing.T) { func TestGetContentsOrListErrors(t *testing.T) { unittest.PrepareTestEnv(t) - ctx, _ := contexttest.MockContext(t, "user2/repo1") - ctx.SetParams(":id", "1") - contexttest.LoadRepo(t, ctx, 1) - contexttest.LoadRepoCommit(t, ctx) - contexttest.LoadUser(t, ctx, 2) - contexttest.LoadGitRepo(t, ctx) - defer ctx.Repo.GitRepo.Close() + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) - repo := ctx.Repo.Repository treePath := "README.md" ref := repo.DefaultBranch t.Run("bad treePath", func(t *testing.T) { badTreePath := "bad/tree.md" - fileContentResponse, err := GetContentsOrList(ctx, repo, badTreePath, ref) + fileContentResponse, err := GetContentsOrList(db.DefaultContext, repo, badTreePath, ref) require.EqualError(t, err, "object does not exist [id: , rel_path: bad]") assert.Nil(t, fileContentResponse) }) t.Run("bad ref", func(t *testing.T) { badRef := "bad_ref" - fileContentResponse, err := GetContentsOrList(ctx, repo, treePath, badRef) + fileContentResponse, err := GetContentsOrList(db.DefaultContext, repo, treePath, badRef) require.EqualError(t, err, "object does not exist [id: "+badRef+", rel_path: ]") assert.Nil(t, fileContentResponse) }) @@ -202,17 +171,10 @@ func TestGetContentsOrListErrors(t *testing.T) { func TestGetContentsOrListOfEmptyRepos(t *testing.T) { unittest.PrepareTestEnv(t) - ctx, _ := contexttest.MockContext(t, "user30/empty") - ctx.SetParams(":id", "52") - contexttest.LoadRepo(t, ctx, 52) - contexttest.LoadUser(t, ctx, 30) - contexttest.LoadGitRepo(t, ctx) - defer ctx.Repo.GitRepo.Close() - - repo := ctx.Repo.Repository + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 52}) t.Run("empty repo", func(t *testing.T) { - contents, err := GetContentsOrList(ctx, repo, "", "") + contents, err := GetContentsOrList(db.DefaultContext, repo, "", "") require.NoError(t, err) assert.Empty(t, contents) }) @@ -220,23 +182,13 @@ func TestGetContentsOrListOfEmptyRepos(t *testing.T) { func TestGetBlobBySHA(t *testing.T) { unittest.PrepareTestEnv(t) - ctx, _ := contexttest.MockContext(t, "user2/repo1") - contexttest.LoadRepo(t, ctx, 1) - contexttest.LoadRepoCommit(t, ctx) - contexttest.LoadUser(t, ctx, 2) - contexttest.LoadGitRepo(t, ctx) - defer ctx.Repo.GitRepo.Close() + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) - sha := "65f1bf27bc3bf70f64657658635e66094edbcb4d" - ctx.SetParams(":id", "1") - ctx.SetParams(":sha", sha) + gitRepo, err := gitrepo.OpenRepository(db.DefaultContext, repo) + require.NoError(t, err) + defer gitRepo.Close() - gitRepo, err := gitrepo.OpenRepository(ctx, ctx.Repo.Repository) - if err != nil { - t.Fail() - } - - gbr, err := GetBlobBySHA(ctx, ctx.Repo.Repository, gitRepo, ctx.Params(":sha")) + gbr, err := GetBlobBySHA(db.DefaultContext, repo, gitRepo, "65f1bf27bc3bf70f64657658635e66094edbcb4d") expectedGBR := &api.GitBlobResponse{ Content: "dHJlZSAyYTJmMWQ0NjcwNzI4YTJlMTAwNDllMzQ1YmQ3YTI3NjQ2OGJlYWI2CmF1dGhvciB1c2VyMSA8YWRkcmVzczFAZXhhbXBsZS5jb20+IDE0ODk5NTY0NzkgLTA0MDAKY29tbWl0dGVyIEV0aGFuIEtvZW5pZyA8ZXRoYW50a29lbmlnQGdtYWlsLmNvbT4gMTQ4OTk1NjQ3OSAtMDQwMAoKSW5pdGlhbCBjb21taXQK", Encoding: "base64", diff --git a/services/repository/files/diff_test.go b/services/repository/files/diff_test.go index 1ea4a170cc..95de10e07e 100644 --- a/services/repository/files/diff_test.go +++ b/services/repository/files/diff_test.go @@ -6,6 +6,7 @@ package files import ( "testing" + "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/modules/json" @@ -21,7 +22,6 @@ func TestGetDiffPreview(t *testing.T) { ctx, _ := contexttest.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") contexttest.LoadRepo(t, ctx, 1) - contexttest.LoadRepoCommit(t, ctx) contexttest.LoadUser(t, ctx, 2) contexttest.LoadGitRepo(t, ctx) defer ctx.Repo.GitRepo.Close() @@ -140,33 +140,26 @@ func TestGetDiffPreview(t *testing.T) { func TestGetDiffPreviewErrors(t *testing.T) { unittest.PrepareTestEnv(t) - ctx, _ := contexttest.MockContext(t, "user2/repo1") - ctx.SetParams(":id", "1") - contexttest.LoadRepo(t, ctx, 1) - contexttest.LoadRepoCommit(t, ctx) - contexttest.LoadUser(t, ctx, 2) - contexttest.LoadGitRepo(t, ctx) - defer ctx.Repo.GitRepo.Close() - - branch := ctx.Repo.Repository.DefaultBranch + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + branch := repo.DefaultBranch treePath := "README.md" content := "# repo1\n\nDescription for repo1\nthis is a new line" t.Run("empty repo", func(t *testing.T) { - diff, err := GetDiffPreview(ctx, &repo_model.Repository{}, branch, treePath, content) + diff, err := GetDiffPreview(db.DefaultContext, &repo_model.Repository{}, branch, treePath, content) assert.Nil(t, diff) assert.EqualError(t, err, "repository does not exist [id: 0, uid: 0, owner_name: , name: ]") }) t.Run("bad branch", func(t *testing.T) { badBranch := "bad_branch" - diff, err := GetDiffPreview(ctx, ctx.Repo.Repository, badBranch, treePath, content) + diff, err := GetDiffPreview(db.DefaultContext, repo, badBranch, treePath, content) assert.Nil(t, diff) assert.EqualError(t, err, "branch does not exist [name: "+badBranch+"]") }) t.Run("empty treePath", func(t *testing.T) { - diff, err := GetDiffPreview(ctx, ctx.Repo.Repository, branch, "", content) + diff, err := GetDiffPreview(db.DefaultContext, repo, branch, "", content) assert.Nil(t, diff) assert.EqualError(t, err, "path is invalid [path: ]") }) diff --git a/services/repository/files/file_test.go b/services/repository/files/file_test.go index 2c6a169da1..7c387e2dd5 100644 --- a/services/repository/files/file_test.go +++ b/services/repository/files/file_test.go @@ -6,11 +6,12 @@ package files import ( "testing" + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/services/contexttest" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -99,23 +100,16 @@ func getExpectedFileResponse() *api.FileResponse { func TestGetFileResponseFromCommit(t *testing.T) { unittest.PrepareTestEnv(t) - ctx, _ := contexttest.MockContext(t, "user2/repo1") - ctx.SetParams(":id", "1") - contexttest.LoadRepo(t, ctx, 1) - contexttest.LoadRepoCommit(t, ctx) - contexttest.LoadUser(t, ctx, 2) - contexttest.LoadGitRepo(t, ctx) - defer ctx.Repo.GitRepo.Close() - repo := ctx.Repo.Repository + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) branch := repo.DefaultBranch treePath := "README.md" - gitRepo, _ := gitrepo.OpenRepository(ctx, repo) + gitRepo, _ := gitrepo.OpenRepository(db.DefaultContext, repo) defer gitRepo.Close() commit, _ := gitRepo.GetBranchCommit(branch) expectedFileResponse := getExpectedFileResponse() - fileResponse, err := GetFileResponseFromCommit(ctx, repo, commit, branch, treePath) + fileResponse, err := GetFileResponseFromCommit(db.DefaultContext, repo, commit, branch, treePath) require.NoError(t, err) assert.EqualValues(t, expectedFileResponse, fileResponse) } diff --git a/services/repository/files/tree_test.go b/services/repository/files/tree_test.go index faa9b8e29e..9e5c5c1701 100644 --- a/services/repository/files/tree_test.go +++ b/services/repository/files/tree_test.go @@ -18,7 +18,6 @@ func TestGetTreeBySHA(t *testing.T) { unittest.PrepareTestEnv(t) ctx, _ := contexttest.MockContext(t, "user2/repo1") contexttest.LoadRepo(t, ctx, 1) - contexttest.LoadRepoCommit(t, ctx) contexttest.LoadUser(t, ctx, 2) contexttest.LoadGitRepo(t, ctx) defer ctx.Repo.GitRepo.Close() diff --git a/tests/integration/repo_view_test.go b/tests/integration/repo_view_test.go index 290686d554..7c280e2491 100644 --- a/tests/integration/repo_view_test.go +++ b/tests/integration/repo_view_test.go @@ -52,8 +52,13 @@ func createRepoAndGetContext(t *testing.T, files []string, deleteMdReadme bool) ctx, _ := contexttest.MockContext(t, "user1/readmetest") ctx.SetParams(":id", fmt.Sprint(repo.ID)) contexttest.LoadRepo(t, ctx, repo.ID) + contexttest.LoadGitRepo(t, ctx) contexttest.LoadRepoCommit(t, ctx) - return ctx, f + + return ctx, func() { + f() + ctx.Repo.GitRepo.Close() + } } func TestRepoView_FindReadme(t *testing.T) { diff --git a/tests/integration/repofiles_change_test.go b/tests/integration/repofiles_change_test.go index 7f5e17c2ce..9790b36183 100644 --- a/tests/integration/repofiles_change_test.go +++ b/tests/integration/repofiles_change_test.go @@ -12,11 +12,11 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/services/contexttest" files_service "code.gitea.io/gitea/services/repository/files" "github.com/stretchr/testify/assert" @@ -247,16 +247,8 @@ func getExpectedFileResponseForRepofilesUpdate(commitID, filename, lastCommitSHA func TestChangeRepoFilesForCreate(t *testing.T) { // setup onGiteaRun(t, func(t *testing.T, u *url.URL) { - ctx, _ := contexttest.MockContext(t, "user2/repo1") - ctx.SetParams(":id", "1") - contexttest.LoadRepo(t, ctx, 1) - contexttest.LoadRepoCommit(t, ctx) - contexttest.LoadUser(t, ctx, 2) - contexttest.LoadGitRepo(t, ctx) - defer ctx.Repo.GitRepo.Close() - - repo := ctx.Repo.Repository - doer := ctx.Doer + doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) opts := getCreateRepoFilesOptions(repo) // test @@ -284,16 +276,8 @@ func TestChangeRepoFilesForCreate(t *testing.T) { func TestChangeRepoFilesForUpdate(t *testing.T) { // setup onGiteaRun(t, func(t *testing.T, u *url.URL) { - ctx, _ := contexttest.MockContext(t, "user2/repo1") - ctx.SetParams(":id", "1") - contexttest.LoadRepo(t, ctx, 1) - contexttest.LoadRepoCommit(t, ctx) - contexttest.LoadUser(t, ctx, 2) - contexttest.LoadGitRepo(t, ctx) - defer ctx.Repo.GitRepo.Close() - - repo := ctx.Repo.Repository - doer := ctx.Doer + doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) opts := getUpdateRepoFilesOptions(repo) // test @@ -318,16 +302,8 @@ func TestChangeRepoFilesForUpdate(t *testing.T) { func TestChangeRepoFilesForUpdateWithFileMove(t *testing.T) { // setup onGiteaRun(t, func(t *testing.T, u *url.URL) { - ctx, _ := contexttest.MockContext(t, "user2/repo1") - ctx.SetParams(":id", "1") - contexttest.LoadRepo(t, ctx, 1) - contexttest.LoadRepoCommit(t, ctx) - contexttest.LoadUser(t, ctx, 2) - contexttest.LoadGitRepo(t, ctx) - defer ctx.Repo.GitRepo.Close() - - repo := ctx.Repo.Repository - doer := ctx.Doer + doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) opts := getUpdateRepoFilesOptions(repo) opts.Files[0].FromTreePath = "README.md" opts.Files[0].TreePath = "README_new.md" // new file name, README_new.md @@ -369,16 +345,8 @@ func TestChangeRepoFilesForUpdateWithFileMove(t *testing.T) { func TestChangeRepoFilesWithoutBranchNames(t *testing.T) { // setup onGiteaRun(t, func(t *testing.T, u *url.URL) { - ctx, _ := contexttest.MockContext(t, "user2/repo1") - ctx.SetParams(":id", "1") - contexttest.LoadRepo(t, ctx, 1) - contexttest.LoadRepoCommit(t, ctx) - contexttest.LoadUser(t, ctx, 2) - contexttest.LoadGitRepo(t, ctx) - defer ctx.Repo.GitRepo.Close() - - repo := ctx.Repo.Repository - doer := ctx.Doer + doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) opts := getUpdateRepoFilesOptions(repo) opts.OldBranch = "" opts.NewBranch = "" @@ -405,15 +373,8 @@ func TestChangeRepoFilesForDelete(t *testing.T) { func testDeleteRepoFiles(t *testing.T, u *url.URL) { // setup unittest.PrepareTestEnv(t) - ctx, _ := contexttest.MockContext(t, "user2/repo1") - ctx.SetParams(":id", "1") - contexttest.LoadRepo(t, ctx, 1) - contexttest.LoadRepoCommit(t, ctx) - contexttest.LoadUser(t, ctx, 2) - contexttest.LoadGitRepo(t, ctx) - defer ctx.Repo.GitRepo.Close() - repo := ctx.Repo.Repository - doer := ctx.Doer + doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) opts := getDeleteRepoFilesOptions(repo) t.Run("Delete README.md file", func(t *testing.T) { @@ -444,16 +405,9 @@ func TestChangeRepoFilesForDeleteWithoutBranchNames(t *testing.T) { func testDeleteRepoFilesWithoutBranchNames(t *testing.T, u *url.URL) { // setup unittest.PrepareTestEnv(t) - ctx, _ := contexttest.MockContext(t, "user2/repo1") - ctx.SetParams(":id", "1") - contexttest.LoadRepo(t, ctx, 1) - contexttest.LoadRepoCommit(t, ctx) - contexttest.LoadUser(t, ctx, 2) - contexttest.LoadGitRepo(t, ctx) - defer ctx.Repo.GitRepo.Close() + doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) - repo := ctx.Repo.Repository - doer := ctx.Doer opts := getDeleteRepoFilesOptions(repo) opts.OldBranch = "" opts.NewBranch = "" @@ -474,16 +428,8 @@ func testDeleteRepoFilesWithoutBranchNames(t *testing.T, u *url.URL) { func TestChangeRepoFilesErrors(t *testing.T) { // setup onGiteaRun(t, func(t *testing.T, u *url.URL) { - ctx, _ := contexttest.MockContext(t, "user2/repo1") - ctx.SetParams(":id", "1") - contexttest.LoadRepo(t, ctx, 1) - contexttest.LoadRepoCommit(t, ctx) - contexttest.LoadUser(t, ctx, 2) - contexttest.LoadGitRepo(t, ctx) - defer ctx.Repo.GitRepo.Close() - - repo := ctx.Repo.Repository - doer := ctx.Doer + doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) t.Run("bad branch", func(t *testing.T) { opts := getUpdateRepoFilesOptions(repo) From 1a68d14cf8ba6930afbb35e8c595d26764f9ea71 Mon Sep 17 00:00:00 2001 From: Gusted Date: Mon, 26 Aug 2024 08:54:16 +0200 Subject: [PATCH 07/15] [FIX] Don't allow SSH authentication without ssh executable - Follow up of #4819 - When no `ssh` executable is present, disable the UI and backend bits that allow the creation of push mirrors that use SSH authentication. As this feature requires the usage of the `ssh` binary. - Integration test added. --- modules/git/git.go | 6 ++++ options/locale/locale_en-US.ini | 1 + routers/api/v1/repo/mirror.go | 6 ++++ routers/web/repo/setting/setting.go | 6 ++++ templates/repo/settings/options.tmpl | 2 ++ tests/integration/api_push_mirror_test.go | 23 +++++++++++++++ tests/integration/mirror_push_test.go | 36 +++++++++++++++++++++++ 7 files changed, 80 insertions(+) diff --git a/modules/git/git.go b/modules/git/git.go index d1e841eeb8..851b563e88 100644 --- a/modules/git/git.go +++ b/modules/git/git.go @@ -38,6 +38,8 @@ var ( InvertedGitFlushEnv bool // 2.43.1 SupportCheckAttrOnBare bool // >= 2.40 + HasSSHExecutable bool + gitVersion *version.Version ) @@ -203,6 +205,10 @@ func InitFull(ctx context.Context) (err error) { globalCommandArgs = append(globalCommandArgs, "-c", "filter.lfs.required=", "-c", "filter.lfs.smudge=", "-c", "filter.lfs.clean=") } + // Detect the presence of the ssh executable in $PATH. + _, err = exec.LookPath("ssh") + HasSSHExecutable = err == nil + return syncGitConfig() } diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 0495dffd88..a74446b7f0 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1105,6 +1105,7 @@ mirror_interval_invalid = The mirror interval is not valid. mirror_public_key = Public SSH key mirror_use_ssh.text = Use SSH authentication mirror_use_ssh.helper = Forgejo will mirror the repository via Git over SSH and create a keypair for you when you select this option. You must ensure that the generated public key is authorized to push to the destination repository. You cannot use password-based authorization when selecting this. +mirror_use_ssh.not_available = SSH authentication isn't available. mirror_denied_combination = Cannot use public key and password based authentication in combination. mirror_sync = synced mirror_sync_on_commit = Sync when commits are pushed diff --git a/routers/api/v1/repo/mirror.go b/routers/api/v1/repo/mirror.go index 9ccf6f05ac..ae727fdbae 100644 --- a/routers/api/v1/repo/mirror.go +++ b/routers/api/v1/repo/mirror.go @@ -13,6 +13,7 @@ import ( "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" @@ -350,6 +351,11 @@ func CreatePushMirror(ctx *context.APIContext, mirrorOption *api.CreatePushMirro return } + if mirrorOption.UseSSH && !git.HasSSHExecutable { + ctx.Error(http.StatusBadRequest, "CreatePushMirror", "SSH authentication not available.") + return + } + if mirrorOption.UseSSH && (mirrorOption.RemoteUsername != "" || mirrorOption.RemotePassword != "") { ctx.Error(http.StatusBadRequest, "CreatePushMirror", "'use_ssh' is mutually exclusive with 'remote_username' and 'remote_passoword'") return diff --git a/routers/web/repo/setting/setting.go b/routers/web/repo/setting/setting.go index 76539b9fa2..32e1d99e24 100644 --- a/routers/web/repo/setting/setting.go +++ b/routers/web/repo/setting/setting.go @@ -92,6 +92,7 @@ func SettingsCtxData(ctx *context.Context) { return } ctx.Data["PushMirrors"] = pushMirrors + ctx.Data["CanUseSSHMirroring"] = git.HasSSHExecutable } // Units show a repositorys unit settings page @@ -643,6 +644,11 @@ func SettingsPost(ctx *context.Context) { return } + if form.PushMirrorUseSSH && !git.HasSSHExecutable { + ctx.RenderWithErr(ctx.Tr("repo.mirror_use_ssh.not_available"), tplSettingsOptions, &form) + return + } + address, err := forms.ParseRemoteAddr(form.PushMirrorAddress, form.PushMirrorUsername, form.PushMirrorPassword) if err == nil { err = migrations.IsMigrateURLAllowed(address, ctx.Doer) diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index a18a584c56..09f80cac84 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -300,6 +300,7 @@ + {{if .CanUseSSHMirroring}}
@@ -307,6 +308,7 @@ {{ctx.Locale.Tr "repo.mirror_use_ssh.helper"}}
+ {{end}}
diff --git a/tests/integration/api_push_mirror_test.go b/tests/integration/api_push_mirror_test.go index fb78e1bfaa..f2135cec62 100644 --- a/tests/integration/api_push_mirror_test.go +++ b/tests/integration/api_push_mirror_test.go @@ -11,6 +11,7 @@ import ( "net/http" "net/url" "os" + "os/exec" "path/filepath" "strconv" "testing" @@ -23,6 +24,7 @@ import ( "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" @@ -141,6 +143,11 @@ func testAPIPushMirror(t *testing.T, u *url.URL) { } func TestAPIPushMirrorSSH(t *testing.T) { + _, err := exec.LookPath("ssh") + if err != nil { + t.Skip("SSH executable not present") + } + onGiteaRun(t, func(t *testing.T, _ *url.URL) { defer test.MockVariableValue(&setting.Migrations.AllowLocalNetworks, true)() defer test.MockVariableValue(&setting.Mirror.Enabled, true)() @@ -178,6 +185,22 @@ func TestAPIPushMirrorSSH(t *testing.T) { assert.EqualValues(t, "'use_ssh' is mutually exclusive with 'remote_username' and 'remote_passoword'", apiError.Message) }) + t.Run("SSH not available", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + defer test.MockVariableValue(&git.HasSSHExecutable, false)() + + req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/push_mirrors", srcRepo.FullName()), &api.CreatePushMirrorOption{ + RemoteAddress: sshURL, + Interval: "8h", + UseSSH: true, + }).AddTokenAuth(token) + resp := MakeRequest(t, req, http.StatusBadRequest) + + var apiError api.APIError + DecodeJSON(t, resp, &apiError) + assert.EqualValues(t, "SSH authentication not available.", apiError.Message) + }) + t.Run("Normal", func(t *testing.T) { var pushMirror *repo_model.PushMirror t.Run("Adding", func(t *testing.T) { diff --git a/tests/integration/mirror_push_test.go b/tests/integration/mirror_push_test.go index c2a0d5a45b..2dda4d6836 100644 --- a/tests/integration/mirror_push_test.go +++ b/tests/integration/mirror_push_test.go @@ -11,6 +11,7 @@ import ( "net/http" "net/url" "os" + "os/exec" "path/filepath" "strconv" "testing" @@ -157,6 +158,11 @@ func doRemovePushMirror(ctx APITestContext, address, username, password string, } func TestSSHPushMirror(t *testing.T) { + _, err := exec.LookPath("ssh") + if err != nil { + t.Skip("SSH executable not present") + } + onGiteaRun(t, func(t *testing.T, _ *url.URL) { defer test.MockVariableValue(&setting.Migrations.AllowLocalNetworks, true)() defer test.MockVariableValue(&setting.Mirror.Enabled, true)() @@ -194,6 +200,36 @@ func TestSSHPushMirror(t *testing.T) { assert.Contains(t, errMsg, "Cannot use public key and password based authentication in combination.") }) + inputSelector := `input[id="push_mirror_use_ssh"]` + + t.Run("SSH not available", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + defer test.MockVariableValue(&git.HasSSHExecutable, false)() + + req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/settings", srcRepo.FullName()), map[string]string{ + "_csrf": GetCSRF(t, sess, fmt.Sprintf("/%s/settings", srcRepo.FullName())), + "action": "push-mirror-add", + "push_mirror_address": sshURL, + "push_mirror_use_ssh": "true", + "push_mirror_interval": "0", + }) + resp := sess.MakeRequest(t, req, http.StatusOK) + htmlDoc := NewHTMLParser(t, resp.Body) + + errMsg := htmlDoc.Find(".ui.negative.message").Text() + assert.Contains(t, errMsg, "SSH authentication isn't available.") + + htmlDoc.AssertElement(t, inputSelector, false) + }) + + t.Run("SSH available", func(t *testing.T) { + req := NewRequest(t, "GET", fmt.Sprintf("/%s/settings", srcRepo.FullName())) + resp := sess.MakeRequest(t, req, http.StatusOK) + + htmlDoc := NewHTMLParser(t, resp.Body) + htmlDoc.AssertElement(t, inputSelector, true) + }) + t.Run("Normal", func(t *testing.T) { var pushMirror *repo_model.PushMirror t.Run("Adding", func(t *testing.T) { From 681b5e5113302ef7cac51ac99251fc01ab253295 Mon Sep 17 00:00:00 2001 From: Earl Warren Date: Mon, 26 Aug 2024 09:54:03 +0200 Subject: [PATCH 08/15] chore(release-notes): Update module github.com/go-enry/go-enry/v2 to v2.8.9 --- release-notes/5120.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 release-notes/5120.md diff --git a/release-notes/5120.md b/release-notes/5120.md new file mode 100644 index 0000000000..d502b21874 --- /dev/null +++ b/release-notes/5120.md @@ -0,0 +1,2 @@ +feat: Language detection in the repository learned about the following languages: [Luau](https://github.com/github-linguist/linguist/pull/6612), [BQN](https://github.com/github-linguist/linguist/pull/6623), [Cron table](https://github.com/github-linguist/linguist/pull/6759), [NMODL](https://github.com/github-linguist/linguist/pull/6776), [Pkl](https://github.com/github-linguist/linguist/pull/6730), [templ](https://github.com/github-linguist/linguist/pull/6798), [FIRRTL](https://github.com/github-linguist/linguist/pull/6848), [Julia REPL](https://github.com/github-linguist/linguist/pull/6859), [Caddyfile](https://github.com/github-linguist/linguist/pull/6862). +feat: The following extensions or filenames in a repository are associated with the matching language: [.sublime-color-scheme](https://github.com/github-linguist/linguist/pull/6758), [MODULE.bazel.lock](https://github.com/github-linguist/linguist/pull/6783), [Cargo.toml.orig](https://github.com/github-linguist/linguist/pull/6787), [tsx](https://github.com/github-linguist/linguist/pull/6788), [justfile](https://github.com/github-linguist/linguist/pull/6795), [.zig.zon](https://github.com/github-linguist/linguist/pull/6820), [.envrc](https://github.com/github-linguist/linguist/pull/6865). From 2190b67507fb5dbd0c08d07ec2f971e534d39c3a Mon Sep 17 00:00:00 2001 From: floss4good Date: Mon, 26 Aug 2024 13:22:39 +0300 Subject: [PATCH 09/15] docs: replace Developer Guide link with the new Contributor Guide one. --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 77c6463fbf..18b613d3bd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,4 +4,4 @@ The Forgejo project is run by a community of people who are expected to follow t Sensitive security-related issues should be reported to [security@forgejo.org](mailto:security@forgejo.org) using [encryption](https://keyoxide.org/security@forgejo.org). -You can find links to the different aspects of Developer documentation on this page: [Forgejo developer guide](https://forgejo.org/docs/next/developer/). +You can find links to the different aspects of Developer documentation on this page: [Forgejo Contributor Guide](https://forgejo.org/docs/next/contributor/). From 3b7094965139e2cf35e4f99a4ae8faa8f04e734c Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Mon, 26 Aug 2024 13:25:34 +0200 Subject: [PATCH 10/15] feat: Trivial default quota configuration This adds a new configuration setting: `[quota.default].TOTAL`, which will be used if no groups are configured for a particular user. The new option makes it possible to entirely skip configuring quotas via the API if all that one wants is a total size. Signed-off-by: Gergely Nagy --- models/quota/default.go | 25 ++++++++++++++ models/quota/group.go | 4 +-- modules/setting/quota.go | 9 +++++ tests/integration/quota_use_test.go | 52 +++++++++++++++++++++++++++-- 4 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 models/quota/default.go diff --git a/models/quota/default.go b/models/quota/default.go new file mode 100644 index 0000000000..6b553d6f71 --- /dev/null +++ b/models/quota/default.go @@ -0,0 +1,25 @@ +// Copyright 2024 The Forgejo Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package quota + +import ( + "code.gitea.io/gitea/modules/setting" +) + +func EvaluateDefault(used Used, forSubject LimitSubject) bool { + groups := GroupList{ + &Group{ + Name: "builtin-default-group", + Rules: []Rule{ + { + Name: "builtin-default-rule", + Limit: setting.Quota.Default.Total, + Subjects: LimitSubjects{LimitSubjectSizeAll}, + }, + }, + }, + } + + return groups.Evaluate(used, forSubject) +} diff --git a/models/quota/group.go b/models/quota/group.go index 045a98ec21..0acb5b255e 100644 --- a/models/quota/group.go +++ b/models/quota/group.go @@ -230,9 +230,9 @@ func (g *Group) Evaluate(used Used, forSubject LimitSubject) (bool, bool) { } func (gl *GroupList) Evaluate(used Used, forSubject LimitSubject) bool { - // If there are no groups, default to success: + // If there are no groups, use the configured defaults: if gl == nil || len(*gl) == 0 { - return true + return EvaluateDefault(used, forSubject) } for _, group := range *gl { diff --git a/modules/setting/quota.go b/modules/setting/quota.go index 6dfadb59f6..05e14baa9c 100644 --- a/modules/setting/quota.go +++ b/modules/setting/quota.go @@ -7,9 +7,18 @@ package setting var Quota = struct { Enabled bool `ini:"ENABLED"` DefaultGroups []string `ini:"DEFAULT_GROUPS"` + + Default struct { + Total int64 + } `ini:"quota.default"` }{ Enabled: false, DefaultGroups: []string{}, + Default: struct { + Total int64 + }{ + Total: -1, + }, } func loadQuotaFrom(rootCfg ConfigProvider) { diff --git a/tests/integration/quota_use_test.go b/tests/integration/quota_use_test.go index 06f23c9c23..39c5c1ae5c 100644 --- a/tests/integration/quota_use_test.go +++ b/tests/integration/quota_use_test.go @@ -548,6 +548,42 @@ func TestGitQuotaEnforcement(t *testing.T) { }) } +func TestQuotaConfigDefault(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + env := createQuotaWebEnv(t) + defer env.Cleanup() + + t.Run("with config-based default", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + defer test.MockVariableValue(&setting.Quota.Default.Total, 0)() + + env.As(t, env.Users.Ungrouped). + With(Context{ + Payload: &Payload{ + "uid": env.Users.Ungrouped.ID().AsString(), + "repo_name": "quota-config-default", + }, + }). + PostToPage("/repo/create"). + ExpectStatus(http.StatusRequestEntityTooLarge) + }) + + t.Run("without config-based default", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + env.As(t, env.Users.Ungrouped). + With(Context{ + Payload: &Payload{ + "uid": env.Users.Ungrouped.ID().AsString(), + "repo_name": "quota-config-default", + }, + }). + PostToPage("/repo/create"). + ExpectStatus(http.StatusSeeOther) + }) + }) +} + /********************** * Here be dragons! * * * @@ -568,6 +604,7 @@ type quotaWebEnv struct { type quotaWebEnvUsers struct { Limited quotaWebEnvUser Contributor quotaWebEnvUser + Ungrouped quotaWebEnvUser } type quotaWebEnvOrgs struct { @@ -1005,8 +1042,7 @@ func createQuotaWebEnv(t *testing.T) *quotaWebEnv { // *** helpers *** - // Create a user, its quota group & rule - makeUser := func(t *testing.T, limit int64) quotaWebEnvUser { + makeUngroupedUser := func(t *testing.T) quotaWebEnvUser { t.Helper() user := quotaWebEnvUser{} @@ -1021,6 +1057,16 @@ func createQuotaWebEnv(t *testing.T) *quotaWebEnv { repo, _, _ := tests.CreateDeclarativeRepoWithOptions(t, user.User, tests.DeclarativeRepoOptions{}) user.Repo = repo + return user + } + + // Create a user, its quota group & rule + makeUser := func(t *testing.T, limit int64) quotaWebEnvUser { + t.Helper() + + user := makeUngroupedUser(t) + userName := user.User.Name + // Create a quota group for them group, err := quota_model.CreateGroup(db.DefaultContext, userName) require.NoError(t, err) @@ -1095,5 +1141,7 @@ func createQuotaWebEnv(t *testing.T) *quotaWebEnv { env.Orgs.Limited = makeOrg(t, env.Users.Limited.User, int64(0)) env.Orgs.Unlimited = makeOrg(t, env.Users.Limited.User, int64(-1)) + env.Users.Ungrouped = makeUngroupedUser(t) + return &env } From 018aefe29f8abba1e6a2c9d8f64ef7dda145457d Mon Sep 17 00:00:00 2001 From: floss4good Date: Mon, 26 Aug 2024 14:29:10 +0300 Subject: [PATCH 11/15] Replace Developer Guide links with the new Contributor Guide one for PR template and release workflows comments. --- .forgejo/pull_request_template.md | 2 +- .forgejo/workflows/build-release.yml | 2 +- .forgejo/workflows/publish-release.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.forgejo/pull_request_template.md b/.forgejo/pull_request_template.md index eca6f12ae6..d30af48446 100644 --- a/.forgejo/pull_request_template.md +++ b/.forgejo/pull_request_template.md @@ -10,7 +10,7 @@ labels: ## Checklist -The [developer guide](https://forgejo.org/docs/next/developer/) contains information that will be helpful to first time contributors. There also are a few [conditions for merging Pull Requests in Forgejo repositories](https://codeberg.org/forgejo/governance/src/branch/main/PullRequestsAgreement.md). You are also welcome to join the [Forgejo development chatroom](https://matrix.to/#/#forgejo-development:matrix.org). +The [contributor guide](https://forgejo.org/docs/next/contributor/) contains information that will be helpful to first time contributors. There also are a few [conditions for merging Pull Requests in Forgejo repositories](https://codeberg.org/forgejo/governance/src/branch/main/PullRequestsAgreement.md). You are also welcome to join the [Forgejo development chatroom](https://matrix.to/#/#forgejo-development:matrix.org). ### Tests diff --git a/.forgejo/workflows/build-release.yml b/.forgejo/workflows/build-release.yml index 097a7e7480..ce05f6d8ff 100644 --- a/.forgejo/workflows/build-release.yml +++ b/.forgejo/workflows/build-release.yml @@ -1,5 +1,5 @@ # -# See also https://forgejo.org/docs/next/developer/RELEASE/#release-process +# See also https://forgejo.org/docs/next/contributor/release/#stable-release-process # # https://codeberg.org/forgejo-integration/forgejo # diff --git a/.forgejo/workflows/publish-release.yml b/.forgejo/workflows/publish-release.yml index e22b4e8c25..41c884c2d1 100644 --- a/.forgejo/workflows/publish-release.yml +++ b/.forgejo/workflows/publish-release.yml @@ -1,6 +1,6 @@ # SPDX-License-Identifier: MIT # -# See also https://forgejo.org/docs/next/developer/RELEASE/#release-process +# See also https://forgejo.org/docs/next/contributor/release/#stable-release-process # # https://codeberg.org/forgejo-experimental/forgejo # From d97e36f6d724313ae729dcccdab9482829a02b4f Mon Sep 17 00:00:00 2001 From: Otto Richter Date: Sun, 25 Aug 2024 14:52:21 +0200 Subject: [PATCH 12/15] Playwright testing for commit diffs includes: - easier repo declaration for playwright tests by @Gusted - full backend build for pushing Git repos by @Gusted - playwright testing (which fails with the current diff algorithm, but passes with the new) - disable eslint rule for conditional expect, because it defeats the purpose (working around it would result in much more complex test code in our cases) --- .forgejo/workflows/e2e.yml | 4 +- tests/e2e/.eslintrc.yaml | 1 + tests/e2e/debugserver_test.go | 3 +- tests/e2e/declare_repos_test.go | 83 +++++++++++++++++++++++++++++++++ tests/e2e/e2e_test.go | 5 +- tests/e2e/repo-code.test.e2e.js | 26 +++++++++++ tests/e2e/utils_e2e_test.go | 6 +-- 7 files changed, 121 insertions(+), 7 deletions(-) create mode 100644 tests/e2e/declare_repos_test.go diff --git a/.forgejo/workflows/e2e.yml b/.forgejo/workflows/e2e.yml index 3cf3d86413..949177eb8b 100644 --- a/.forgejo/workflows/e2e.yml +++ b/.forgejo/workflows/e2e.yml @@ -22,7 +22,7 @@ jobs: go-version-file: "go.mod" - run: | apt-get -qq update - apt-get -qq install -q sudo + apt-get -qq install -q sudo git git-lfs sed -i -e 's/%sudo.*/%sudo ALL=(ALL:ALL) NOPASSWD:ALL/' /etc/sudoers git config --add safe.directory '*' adduser --quiet --comment forgejo --disabled-password forgejo @@ -30,6 +30,8 @@ jobs: chown -R forgejo:forgejo . - run: | su forgejo -c 'make deps-frontend frontend deps-backend' + - run: | + su forgejo -c 'make backend' - run: | su forgejo -c 'make generate test-e2e-sqlite' timeout-minutes: 40 diff --git a/tests/e2e/.eslintrc.yaml b/tests/e2e/.eslintrc.yaml index 390b2de5c4..1486431524 100644 --- a/tests/e2e/.eslintrc.yaml +++ b/tests/e2e/.eslintrc.yaml @@ -14,6 +14,7 @@ env: rules: playwright/no-conditional-in-test: [0] + playwright/no-conditional-expect: [0] playwright/no-networkidle: [0] playwright/no-skipped-test: [2, {allowConditional: true}] playwright/prefer-comparison-matcher: [2] diff --git a/tests/e2e/debugserver_test.go b/tests/e2e/debugserver_test.go index b1496b22a1..49461fabe5 100644 --- a/tests/e2e/debugserver_test.go +++ b/tests/e2e/debugserver_test.go @@ -24,7 +24,8 @@ func TestDebugserver(t *testing.T) { done := make(chan os.Signal, 1) signal.Notify(done, syscall.SIGINT, syscall.SIGTERM) - onGiteaRun(t, func(*testing.T, *url.URL) { + onForgejoRun(t, func(*testing.T, *url.URL) { + defer DeclareGitRepos(t)() fmt.Println(setting.AppURL) <-done }) diff --git a/tests/e2e/declare_repos_test.go b/tests/e2e/declare_repos_test.go new file mode 100644 index 0000000000..44ee79f388 --- /dev/null +++ b/tests/e2e/declare_repos_test.go @@ -0,0 +1,83 @@ +// Copyright 2024 The Forgejo Authors. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-or-later + +package e2e + +import ( + "fmt" + "strconv" + "strings" + "testing" + "time" + + unit_model "code.gitea.io/gitea/models/unit" + "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/git" + files_service "code.gitea.io/gitea/services/repository/files" + "code.gitea.io/gitea/tests" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +type FileChanges [][]string + +// put your Git repo declarations in here +// feel free to amend the helper function below or use the raw variant directly +func DeclareGitRepos(t *testing.T) func() { + var cleanupFunctions []func() + cleanupFunctions = append(cleanupFunctions, newRepo(t, 2, "diff-test", FileChanges{ + {"testfile", "hello", "hallo", "hola", "native", "ubuntu-latest", "- runs-on: ubuntu-latest", "- runs-on: debian-latest"}, + })) + + return func() { + for _, cleanup := range cleanupFunctions { + cleanup() + } + } +} + +func newRepo(t *testing.T, userID int64, repoName string, fileChanges FileChanges) func() { + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userID}) + somerepo, _, cleanupFunc := tests.CreateDeclarativeRepo(t, user, repoName, + []unit_model.Type{unit_model.TypeCode, unit_model.TypeIssues}, nil, + nil, + ) + + for _, file := range fileChanges { + changeLen := len(file) + for i := 1; i < changeLen; i++ { + operation := "create" + if i != 1 { + operation = "update" + } + resp, err := files_service.ChangeRepoFiles(git.DefaultContext, somerepo, user, &files_service.ChangeRepoFilesOptions{ + Files: []*files_service.ChangeRepoFile{{ + Operation: operation, + TreePath: file[0], + ContentReader: strings.NewReader(file[i]), + }}, + Message: fmt.Sprintf("Patch: %s-%s", file[0], strconv.Itoa(i)), + OldBranch: "main", + NewBranch: "main", + Author: &files_service.IdentityOptions{ + Name: user.Name, + Email: user.Email, + }, + Committer: &files_service.IdentityOptions{ + Name: user.Name, + Email: user.Email, + }, + Dates: &files_service.CommitDateOptions{ + Author: time.Now(), + Committer: time.Now(), + }, + }) + require.NoError(t, err) + assert.NotEmpty(t, resp) + } + } + + return cleanupFunc +} diff --git a/tests/e2e/e2e_test.go b/tests/e2e/e2e_test.go index 39974e00c0..44a6897bf4 100644 --- a/tests/e2e/e2e_test.go +++ b/tests/e2e/e2e_test.go @@ -37,7 +37,7 @@ func TestMain(m *testing.M) { graceful.InitManager(managerCtx) defer cancel() - tests.InitTest(false) + tests.InitTest(true) testE2eWebRoutes = routers.NormalRoutes() os.Unsetenv("GIT_AUTHOR_NAME") @@ -102,7 +102,8 @@ func TestE2e(t *testing.T) { t.Run(testname, func(t *testing.T) { // Default 2 minute timeout - onGiteaRun(t, func(*testing.T, *url.URL) { + onForgejoRun(t, func(*testing.T, *url.URL) { + defer DeclareGitRepos(t)() thisTest := runArgs thisTest = append(thisTest, path) cmd := exec.Command(runArgs[0], thisTest...) diff --git a/tests/e2e/repo-code.test.e2e.js b/tests/e2e/repo-code.test.e2e.js index 626af76305..01179d28d3 100644 --- a/tests/e2e/repo-code.test.e2e.js +++ b/tests/e2e/repo-code.test.e2e.js @@ -51,3 +51,29 @@ test('Line Range Selection', async ({browser}, workerInfo) => { await page.goto(`${filePath}#L1-L100`); await assertSelectedLines(page, ['1', '2', '3']); }); + +test('Readable diff', async ({page}, workerInfo) => { + // remove this when the test covers more (e.g. accessibility scans or interactive behaviour) + test.skip(workerInfo.project.name !== 'firefox', 'This currently only tests the backend-generated HTML code and it is not necessary to test with multiple browsers.'); + const expectedDiffs = [ + {id: 'testfile-2', removed: 'e', added: 'a'}, + {id: 'testfile-3', removed: 'allo', added: 'ola'}, + {id: 'testfile-4', removed: 'hola', added: 'native'}, + {id: 'testfile-5', removed: 'native', added: 'ubuntu-latest'}, + {id: 'testfile-6', added: '- runs-on: '}, + {id: 'testfile-7', removed: 'ubuntu', added: 'debian'}, + ]; + for (const thisDiff of expectedDiffs) { + const response = await page.goto('/user2/diff-test/commits/branch/main'); + await expect(response?.status()).toBe(200); // Status OK + await page.getByText(`Patch: ${thisDiff.id}`).click(); + if (thisDiff.removed) { + await expect(page.getByText(thisDiff.removed, {exact: true})).toHaveClass(/removed-code/); + await expect(page.getByText(thisDiff.removed, {exact: true})).toHaveCSS('background-color', 'rgb(252, 165, 165)'); + } + if (thisDiff.added) { + await expect(page.getByText(thisDiff.added, {exact: true})).toHaveClass(/added-code/); + await expect(page.getByText(thisDiff.added, {exact: true})).toHaveCSS('background-color', 'rgb(134, 239, 172)'); + } + } +}); diff --git a/tests/e2e/utils_e2e_test.go b/tests/e2e/utils_e2e_test.go index a0e940f1e7..cfd3ff9e3b 100644 --- a/tests/e2e/utils_e2e_test.go +++ b/tests/e2e/utils_e2e_test.go @@ -17,7 +17,7 @@ import ( "github.com/stretchr/testify/require" ) -func onGiteaRunTB(t testing.TB, callback func(testing.TB, *url.URL), prepare ...bool) { +func onForgejoRunTB(t testing.TB, callback func(testing.TB, *url.URL), prepare ...bool) { if len(prepare) == 0 || prepare[0] { defer tests.PrepareTestEnv(t, 1)() } @@ -49,8 +49,8 @@ func onGiteaRunTB(t testing.TB, callback func(testing.TB, *url.URL), prepare ... callback(t, u) } -func onGiteaRun(t *testing.T, callback func(*testing.T, *url.URL), prepare ...bool) { - onGiteaRunTB(t, func(t testing.TB, u *url.URL) { +func onForgejoRun(t *testing.T, callback func(*testing.T, *url.URL), prepare ...bool) { + onForgejoRunTB(t, func(t testing.TB, u *url.URL) { callback(t.(*testing.T), u) }, prepare...) } From 58ee9fdc4a217ea145ec60dd524953fff7d91743 Mon Sep 17 00:00:00 2001 From: Gusted Date: Sun, 18 Aug 2024 23:26:41 +0200 Subject: [PATCH 13/15] feat: Improve diff being generated Add `DiffCleanupSemantic` into the mix when generated diffs (PR review, commit view and issue/comment history). This avoids trying to produce a optimal diff and tries to reduce the amount of edits, by combing them into larger edits, which is nicer and easier to 'look at'. There's no need for a perfect minimal diff, as the output isn't being parsed by a computer, it's parsed by people. Ref: https://codeberg.org/forgejo/forgejo/issues/4996 --- routers/web/repo/issue_content_history.go | 1 + services/gitdiff/highlightdiff.go | 1 + 2 files changed, 2 insertions(+) diff --git a/routers/web/repo/issue_content_history.go b/routers/web/repo/issue_content_history.go index 31d2de6d53..16b250abda 100644 --- a/routers/web/repo/issue_content_history.go +++ b/routers/web/repo/issue_content_history.go @@ -154,6 +154,7 @@ func GetContentHistoryDetail(ctx *context.Context) { dmp := diffmatchpatch.New() // `checklines=false` makes better diff result diff := dmp.DiffMain(prevHistoryContentText, history.ContentText, false) + diff = dmp.DiffCleanupSemantic(diff) diff = dmp.DiffCleanupEfficiency(diff) // use chroma to render the diff html diff --git a/services/gitdiff/highlightdiff.go b/services/gitdiff/highlightdiff.go index 99313c5f36..c72959ea16 100644 --- a/services/gitdiff/highlightdiff.go +++ b/services/gitdiff/highlightdiff.go @@ -97,6 +97,7 @@ func (hcd *HighlightCodeDiff) diffWithHighlight(filename, language, codeA, codeB convertedCodeB := hcd.ConvertToPlaceholders(string(highlightCodeB)) diffs := diffMatchPatch.DiffMain(convertedCodeA, convertedCodeB, true) + diffs = diffMatchPatch.DiffCleanupSemantic(diffs) diffs = diffMatchPatch.DiffCleanupEfficiency(diffs) for i := range diffs { From 5879cdc6fa8b9f366a17a7c08625f2f2e090eca1 Mon Sep 17 00:00:00 2001 From: floss4good Date: Mon, 26 Aug 2024 17:43:35 +0300 Subject: [PATCH 14/15] Update the translator contributing guide from user language settings. --- templates/user/settings/appearance.tmpl | 2 +- tests/integration/user_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/user/settings/appearance.tmpl b/templates/user/settings/appearance.tmpl index 3e60b5cbcd..2aaf24adca 100644 --- a/templates/user/settings/appearance.tmpl +++ b/templates/user/settings/appearance.tmpl @@ -64,7 +64,7 @@
- {{ctx.Locale.Tr "settings.language.localization_project" "https://forgejo.org/docs/latest/developer/localization/"}} + {{ctx.Locale.Tr "settings.language.localization_project" "https://forgejo.org/docs/next/contributor/localization/"}}
diff --git a/tests/integration/user_test.go b/tests/integration/user_test.go index 035d0956f5..73976b9a35 100644 --- a/tests/integration/user_test.go +++ b/tests/integration/user_test.go @@ -389,7 +389,7 @@ func TestUserHints(t *testing.T) { assert.Equal(t, enabled, hintChecked) link, _ := htmlDoc.Find("form[action='/user/settings/appearance/language'] a").Attr("href") - assert.EqualValues(t, "https://forgejo.org/docs/latest/developer/localization/", link) + assert.EqualValues(t, "https://forgejo.org/docs/next/contributor/localization/", link) } t.Run("view", func(t *testing.T) { From 94af0e53e5b9012622f4f2a190fb487777eac64b Mon Sep 17 00:00:00 2001 From: Otto Richter Date: Tue, 27 Aug 2024 02:40:41 +0200 Subject: [PATCH 15/15] fix: correct doctor commands and rename to forgejo The syntax is `doctor check --run` , see https://forgejo.org/docs/latest/admin/command-line/#doctor --- services/doctor/authorizedkeys.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/services/doctor/authorizedkeys.go b/services/doctor/authorizedkeys.go index eb6dec613f..2920cf51d7 100644 --- a/services/doctor/authorizedkeys.go +++ b/services/doctor/authorizedkeys.go @@ -75,9 +75,9 @@ func checkAuthorizedKeys(ctx context.Context, logger log.Logger, autofix bool) e logger.Critical( "authorized_keys file %q is out of date.\nRegenerate it with:\n\t\"%s\"\nor\n\t\"%s\"", fPath, - "gitea admin regenerate keys", - "gitea doctor --run authorized-keys --fix") - return fmt.Errorf(`authorized_keys is out of date and should be regenerated with "gitea admin regenerate keys" or "gitea doctor --run authorized-keys --fix"`) + "forgejo admin regenerate keys", + "forgejo doctor check --run authorized-keys --fix") + return fmt.Errorf(`authorized_keys is out of date and should be regenerated with "forgejo admin regenerate keys" or "forgejo doctor check --run authorized-keys --fix"`) } logger.Warn("authorized_keys is out of date. Attempting rewrite...") err = asymkey_model.RewriteAllPublicKeys(ctx)