diff --git a/assets/go-licenses.json b/assets/go-licenses.json index 313002e17..384a57cf4 100644 --- a/assets/go-licenses.json +++ b/assets/go-licenses.json @@ -985,9 +985,9 @@ "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": "github.com/urfave/cli", - "path": "github.com/urfave/cli/LICENSE", - "licenseText": "MIT License\n\nCopyright (c) 2023 Jeremy Saenz \u0026 Contributors\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": "github.com/urfave/cli/v2", + "path": "github.com/urfave/cli/v2/LICENSE", + "licenseText": "MIT License\n\nCopyright (c) 2022 urfave/cli maintainers\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": "github.com/valyala/bytebufferpool", @@ -1019,6 +1019,11 @@ "path": "github.com/xanzy/ssh-agent/LICENSE", "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/xrash/smetrics", + "path": "github.com/xrash/smetrics/LICENSE", + "licenseText": "Copyright (C) 2016 Felipe da Cunha Gonçalves\nAll Rights Reserved.\n\nMIT LICENSE\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 of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject 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, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n" + }, { "name": "github.com/yohcop/openid-go", "path": "github.com/yohcop/openid-go/LICENSE", diff --git a/cmd/actions.go b/cmd/actions.go index f52a91bd5..052afb9eb 100644 --- a/cmd/actions.go +++ b/cmd/actions.go @@ -9,30 +9,31 @@ import ( "code.gitea.io/gitea/modules/private" "code.gitea.io/gitea/modules/setting" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) var ( // CmdActions represents the available actions sub-commands. - CmdActions = cli.Command{ + CmdActions = &cli.Command{ Name: "actions", Usage: "", Description: "Commands for managing Gitea Actions", - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ subcmdActionsGenRunnerToken, }, } - subcmdActionsGenRunnerToken = cli.Command{ + subcmdActionsGenRunnerToken = &cli.Command{ Name: "generate-runner-token", Usage: "Generate a new token for a runner to use to register with the server", Action: runGenerateActionsRunnerToken, Aliases: []string{"grt"}, Flags: []cli.Flag{ - cli.StringFlag{ - Name: "scope, s", - Value: "", - Usage: "{owner}[/{repo}] - leave empty for a global runner", + &cli.StringFlag{ + Name: "scope", + Aliases: []string{"s"}, + Value: "", + Usage: "{owner}[/{repo}] - leave empty for a global runner", }, }, } diff --git a/cmd/admin.go b/cmd/admin.go index f9fb1b6c6..add3d67d7 100644 --- a/cmd/admin.go +++ b/cmd/admin.go @@ -26,15 +26,15 @@ import ( "code.gitea.io/gitea/services/auth/source/smtp" repo_service "code.gitea.io/gitea/services/repository" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) var ( // CmdAdmin represents the available admin sub-command. - CmdAdmin = cli.Command{ + CmdAdmin = &cli.Command{ Name: "admin", Usage: "Command line interface to perform common administrative operations", - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ subcmdUser, subcmdRepoSyncReleases, subcmdRegenerate, @@ -43,37 +43,37 @@ var ( }, } - subcmdRepoSyncReleases = cli.Command{ + subcmdRepoSyncReleases = &cli.Command{ Name: "repo-sync-releases", Usage: "Synchronize repository releases with tags", Action: runRepoSyncReleases, } - subcmdRegenerate = cli.Command{ + subcmdRegenerate = &cli.Command{ Name: "regenerate", Usage: "Regenerate specific files", - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ microcmdRegenHooks, microcmdRegenKeys, }, } - microcmdRegenHooks = cli.Command{ + microcmdRegenHooks = &cli.Command{ Name: "hooks", Usage: "Regenerate git-hooks", Action: runRegenerateHooks, } - microcmdRegenKeys = cli.Command{ + microcmdRegenKeys = &cli.Command{ Name: "keys", Usage: "Regenerate authorized_keys file", Action: runRegenerateKeys, } - subcmdAuth = cli.Command{ + subcmdAuth = &cli.Command{ Name: "auth", Usage: "Modify external auth providers", - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ microcmdAuthAddOauth, microcmdAuthUpdateOauth, cmdAuthAddLdapBindDn, @@ -87,44 +87,44 @@ var ( }, } - microcmdAuthList = cli.Command{ + microcmdAuthList = &cli.Command{ Name: "list", Usage: "List auth sources", Action: runListAuth, Flags: []cli.Flag{ - cli.IntFlag{ + &cli.IntFlag{ Name: "min-width", Usage: "Minimal cell width including any padding for the formatted table", Value: 0, }, - cli.IntFlag{ + &cli.IntFlag{ Name: "tab-width", Usage: "width of tab characters in formatted table (equivalent number of spaces)", Value: 8, }, - cli.IntFlag{ + &cli.IntFlag{ Name: "padding", Usage: "padding added to a cell before computing its width", Value: 1, }, - cli.StringFlag{ + &cli.StringFlag{ Name: "pad-char", Usage: `ASCII char used for padding if padchar == '\\t', the Writer will assume that the width of a '\\t' in the formatted output is tabwidth, and cells are left-aligned independent of align_left (for correct-looking results, tabwidth must correspond to the tab width in the viewer displaying the result)`, Value: "\t", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "vertical-bars", Usage: "Set to true to print vertical bars between columns", }, }, } - idFlag = cli.Int64Flag{ + idFlag = &cli.Int64Flag{ Name: "id", Usage: "ID of authentication source", } - microcmdAuthDelete = cli.Command{ + microcmdAuthDelete = &cli.Command{ Name: "delete", Usage: "Delete specific auth source", Flags: []cli.Flag{idFlag}, @@ -132,207 +132,208 @@ var ( } oauthCLIFlags = []cli.Flag{ - cli.StringFlag{ + &cli.StringFlag{ Name: "name", Value: "", Usage: "Application Name", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "provider", Value: "", Usage: "OAuth2 Provider", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "key", Value: "", Usage: "Client ID (Key)", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "secret", Value: "", Usage: "Client Secret", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "auto-discover-url", Value: "", Usage: "OpenID Connect Auto Discovery URL (only required when using OpenID Connect as provider)", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "use-custom-urls", Value: "false", Usage: "Use custom URLs for GitLab/GitHub OAuth endpoints", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "custom-tenant-id", Value: "", Usage: "Use custom Tenant ID for OAuth endpoints", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "custom-auth-url", Value: "", Usage: "Use a custom Authorization URL (option for GitLab/GitHub)", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "custom-token-url", Value: "", Usage: "Use a custom Token URL (option for GitLab/GitHub)", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "custom-profile-url", Value: "", Usage: "Use a custom Profile URL (option for GitLab/GitHub)", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "custom-email-url", Value: "", Usage: "Use a custom Email URL (option for GitHub)", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "icon-url", Value: "", Usage: "Custom icon URL for OAuth2 login source", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "skip-local-2fa", Usage: "Set to true to skip local 2fa for users authenticated by this source", }, - cli.StringSliceFlag{ + &cli.StringSliceFlag{ Name: "scopes", Value: nil, Usage: "Scopes to request when to authenticate against this OAuth2 source", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "required-claim-name", Value: "", Usage: "Claim name that has to be set to allow users to login with this source", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "required-claim-value", Value: "", Usage: "Claim value that has to be set to allow users to login with this source", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "group-claim-name", Value: "", Usage: "Claim name providing group names for this source", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "admin-group", Value: "", Usage: "Group Claim value for administrator users", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "restricted-group", Value: "", Usage: "Group Claim value for restricted users", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "group-team-map", Value: "", Usage: "JSON mapping between groups and org teams", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "group-team-map-removal", Usage: "Activate automatic team membership removal depending on groups", }, } - microcmdAuthUpdateOauth = cli.Command{ + microcmdAuthUpdateOauth = &cli.Command{ Name: "update-oauth", Usage: "Update existing Oauth authentication source", Action: runUpdateOauth, Flags: append(oauthCLIFlags[:1], append([]cli.Flag{idFlag}, oauthCLIFlags[1:]...)...), } - microcmdAuthAddOauth = cli.Command{ + microcmdAuthAddOauth = &cli.Command{ Name: "add-oauth", Usage: "Add new Oauth authentication source", Action: runAddOauth, Flags: oauthCLIFlags, } - subcmdSendMail = cli.Command{ + subcmdSendMail = &cli.Command{ Name: "sendmail", Usage: "Send a message to all users", Action: runSendMail, Flags: []cli.Flag{ - cli.StringFlag{ + &cli.StringFlag{ Name: "title", Usage: `a title of a message`, Value: "", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "content", Usage: "a content of a message", Value: "", }, - cli.BoolFlag{ - Name: "force,f", - Usage: "A flag to bypass a confirmation step", + &cli.BoolFlag{ + Name: "force", + Aliases: []string{"f"}, + Usage: "A flag to bypass a confirmation step", }, }, } smtpCLIFlags = []cli.Flag{ - cli.StringFlag{ + &cli.StringFlag{ Name: "name", Value: "", Usage: "Application Name", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "auth-type", Value: "PLAIN", Usage: "SMTP Authentication Type (PLAIN/LOGIN/CRAM-MD5) default PLAIN", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "host", Value: "", Usage: "SMTP Host", }, - cli.IntFlag{ + &cli.IntFlag{ Name: "port", Usage: "SMTP Port", }, - cli.BoolTFlag{ + &cli.BoolFlag{ Name: "force-smtps", Usage: "SMTPS is always used on port 465. Set this to force SMTPS on other ports.", }, - cli.BoolTFlag{ + &cli.BoolFlag{ Name: "skip-verify", Usage: "Skip TLS verify.", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "helo-hostname", Value: "", Usage: "Hostname sent with HELO. Leave blank to send current hostname", }, - cli.BoolTFlag{ + &cli.BoolFlag{ Name: "disable-helo", Usage: "Disable SMTP helo.", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "allowed-domains", Value: "", Usage: "Leave empty to allow all domains. Separate multiple domains with a comma (',')", }, - cli.BoolTFlag{ + &cli.BoolFlag{ Name: "skip-local-2fa", Usage: "Skip 2FA to log on.", }, - cli.BoolTFlag{ + &cli.BoolFlag{ Name: "active", Usage: "This Authentication Source is Activated.", }, } - microcmdAuthAddSMTP = cli.Command{ + microcmdAuthAddSMTP = &cli.Command{ Name: "add-smtp", Usage: "Add new SMTP authentication source", Action: runAddSMTP, Flags: smtpCLIFlags, } - microcmdAuthUpdateSMTP = cli.Command{ + microcmdAuthUpdateSMTP = &cli.Command{ Name: "update-smtp", Usage: "Update existing SMTP authentication source", Action: runUpdateSMTP, @@ -611,19 +612,19 @@ func parseSMTPConfig(c *cli.Context, conf *smtp.Source) error { conf.AllowedDomains = c.String("allowed-domains") } if c.IsSet("force-smtps") { - conf.ForceSMTPS = c.BoolT("force-smtps") + conf.ForceSMTPS = c.Bool("force-smtps") } if c.IsSet("skip-verify") { - conf.SkipVerify = c.BoolT("skip-verify") + conf.SkipVerify = c.Bool("skip-verify") } if c.IsSet("helo-hostname") { conf.HeloHostname = c.String("helo-hostname") } if c.IsSet("disable-helo") { - conf.DisableHelo = c.BoolT("disable-helo") + conf.DisableHelo = c.Bool("disable-helo") } if c.IsSet("skip-local-2fa") { - conf.SkipLocalTwoFA = c.BoolT("skip-local-2fa") + conf.SkipLocalTwoFA = c.Bool("skip-local-2fa") } return nil } @@ -647,7 +648,7 @@ func runAddSMTP(c *cli.Context) error { } active := true if c.IsSet("active") { - active = c.BoolT("active") + active = c.Bool("active") } var smtpConfig smtp.Source @@ -696,7 +697,7 @@ func runUpdateSMTP(c *cli.Context) error { } if c.IsSet("active") { - source.IsActive = c.BoolT("active") + source.IsActive = c.Bool("active") } source.Cfg = smtpConfig diff --git a/cmd/admin_auth_ldap.go b/cmd/admin_auth_ldap.go index 91276f221..cfa1a2323 100644 --- a/cmd/admin_auth_ldap.go +++ b/cmd/admin_auth_ldap.go @@ -11,7 +11,7 @@ import ( "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/services/auth/source/ldap" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) type ( @@ -25,117 +25,117 @@ type ( var ( commonLdapCLIFlags = []cli.Flag{ - cli.StringFlag{ + &cli.StringFlag{ Name: "name", Usage: "Authentication name.", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "not-active", Usage: "Deactivate the authentication source.", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "active", Usage: "Activate the authentication source.", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "security-protocol", Usage: "Security protocol name.", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "skip-tls-verify", Usage: "Disable TLS verification.", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "host", Usage: "The address where the LDAP server can be reached.", }, - cli.IntFlag{ + &cli.IntFlag{ Name: "port", Usage: "The port to use when connecting to the LDAP server.", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "user-search-base", Usage: "The LDAP base at which user accounts will be searched for.", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "user-filter", Usage: "An LDAP filter declaring how to find the user record that is attempting to authenticate.", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "admin-filter", Usage: "An LDAP filter specifying if a user should be given administrator privileges.", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "restricted-filter", Usage: "An LDAP filter specifying if a user should be given restricted status.", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "allow-deactivate-all", Usage: "Allow empty search results to deactivate all users.", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "username-attribute", Usage: "The attribute of the user’s LDAP record containing the user name.", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "firstname-attribute", Usage: "The attribute of the user’s LDAP record containing the user’s first name.", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "surname-attribute", Usage: "The attribute of the user’s LDAP record containing the user’s surname.", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "email-attribute", Usage: "The attribute of the user’s LDAP record containing the user’s email address.", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "public-ssh-key-attribute", Usage: "The attribute of the user’s LDAP record containing the user’s public ssh key.", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "skip-local-2fa", Usage: "Set to true to skip local 2fa for users authenticated by this source", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "avatar-attribute", Usage: "The attribute of the user’s LDAP record containing the user’s avatar.", }, } ldapBindDnCLIFlags = append(commonLdapCLIFlags, - cli.StringFlag{ + &cli.StringFlag{ Name: "bind-dn", Usage: "The DN to bind to the LDAP server with when searching for the user.", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "bind-password", Usage: "The password for the Bind DN, if any.", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "attributes-in-bind", Usage: "Fetch attributes in bind DN context.", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "synchronize-users", Usage: "Enable user synchronization.", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "disable-synchronize-users", Usage: "Disable user synchronization.", }, - cli.UintFlag{ + &cli.UintFlag{ Name: "page-size", Usage: "Search page size.", }) ldapSimpleAuthCLIFlags = append(commonLdapCLIFlags, - cli.StringFlag{ + &cli.StringFlag{ Name: "user-dn", Usage: "The user’s DN.", }) - cmdAuthAddLdapBindDn = cli.Command{ + cmdAuthAddLdapBindDn = &cli.Command{ Name: "add-ldap", Usage: "Add new LDAP (via Bind DN) authentication source", Action: func(c *cli.Context) error { @@ -144,7 +144,7 @@ var ( Flags: ldapBindDnCLIFlags, } - cmdAuthUpdateLdapBindDn = cli.Command{ + cmdAuthUpdateLdapBindDn = &cli.Command{ Name: "update-ldap", Usage: "Update existing LDAP (via Bind DN) authentication source", Action: func(c *cli.Context) error { @@ -153,7 +153,7 @@ var ( Flags: append([]cli.Flag{idFlag}, ldapBindDnCLIFlags...), } - cmdAuthAddLdapSimpleAuth = cli.Command{ + cmdAuthAddLdapSimpleAuth = &cli.Command{ Name: "add-ldap-simple", Usage: "Add new LDAP (simple auth) authentication source", Action: func(c *cli.Context) error { @@ -162,7 +162,7 @@ var ( Flags: ldapSimpleAuthCLIFlags, } - cmdAuthUpdateLdapSimpleAuth = cli.Command{ + cmdAuthUpdateLdapSimpleAuth = &cli.Command{ Name: "update-ldap-simple", Usage: "Update existing LDAP (simple auth) authentication source", Action: func(c *cli.Context) error { diff --git a/cmd/admin_auth_ldap_test.go b/cmd/admin_auth_ldap_test.go index 65f53aaf4..210a6463c 100644 --- a/cmd/admin_auth_ldap_test.go +++ b/cmd/admin_auth_ldap_test.go @@ -11,7 +11,7 @@ import ( "code.gitea.io/gitea/services/auth/source/ldap" "github.com/stretchr/testify/assert" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) func TestAddLdapBindDn(t *testing.T) { diff --git a/cmd/admin_user.go b/cmd/admin_user.go index a442b8fe9..967a6ed88 100644 --- a/cmd/admin_user.go +++ b/cmd/admin_user.go @@ -4,13 +4,13 @@ package cmd import ( - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) -var subcmdUser = cli.Command{ +var subcmdUser = &cli.Command{ Name: "user", Usage: "Modify users", - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ microcmdUserCreate, microcmdUserList, microcmdUserChangePassword, diff --git a/cmd/admin_user_change_password.go b/cmd/admin_user_change_password.go index 7866bde91..eebbfb3b6 100644 --- a/cmd/admin_user_change_password.go +++ b/cmd/admin_user_change_password.go @@ -12,23 +12,25 @@ import ( pwd "code.gitea.io/gitea/modules/auth/password" "code.gitea.io/gitea/modules/setting" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) -var microcmdUserChangePassword = cli.Command{ +var microcmdUserChangePassword = &cli.Command{ Name: "change-password", Usage: "Change a user's password", Action: runChangePassword, Flags: []cli.Flag{ - cli.StringFlag{ - Name: "username,u", - Value: "", - Usage: "The user to change password for", + &cli.StringFlag{ + Name: "username", + Aliases: []string{"u"}, + Value: "", + Usage: "The user to change password for", }, - cli.StringFlag{ - Name: "password,p", - Value: "", - Usage: "New password to set for user", + &cli.StringFlag{ + Name: "password", + Aliases: []string{"p"}, + Value: "", + Usage: "New password to set for user", }, }, } diff --git a/cmd/admin_user_create.go b/cmd/admin_user_create.go index 09eaad54b..260d72954 100644 --- a/cmd/admin_user_create.go +++ b/cmd/admin_user_create.go @@ -14,52 +14,52 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) -var microcmdUserCreate = cli.Command{ +var microcmdUserCreate = &cli.Command{ Name: "create", Usage: "Create a new user in database", Action: runCreateUser, Flags: []cli.Flag{ - cli.StringFlag{ + &cli.StringFlag{ Name: "name", Usage: "Username. DEPRECATED: use username instead", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "username", Usage: "Username", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "password", Usage: "User password", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "email", Usage: "User email address", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "admin", Usage: "User is an admin", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "random-password", Usage: "Generate a random password for the user", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "must-change-password", Usage: "Set this option to false to prevent forcing the user to change their password after initial login, (Default: true)", }, - cli.IntFlag{ + &cli.IntFlag{ Name: "random-password-length", Usage: "Length of the random password to be generated", Value: 12, }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "access-token", Usage: "Generate access token for the user", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "restricted", Usage: "Make a restricted user account", }, diff --git a/cmd/admin_user_delete.go b/cmd/admin_user_delete.go index 30d6d1157..1cbc6f752 100644 --- a/cmd/admin_user_delete.go +++ b/cmd/admin_user_delete.go @@ -11,26 +11,28 @@ import ( "code.gitea.io/gitea/modules/storage" user_service "code.gitea.io/gitea/services/user" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) -var microcmdUserDelete = cli.Command{ +var microcmdUserDelete = &cli.Command{ Name: "delete", Usage: "Delete specific user by id, name or email", Flags: []cli.Flag{ - cli.Int64Flag{ + &cli.Int64Flag{ Name: "id", Usage: "ID of user of the user to delete", }, - cli.StringFlag{ - Name: "username,u", - Usage: "Username of the user to delete", + &cli.StringFlag{ + Name: "username", + Aliases: []string{"u"}, + Usage: "Username of the user to delete", }, - cli.StringFlag{ - Name: "email,e", - Usage: "Email of the user to delete", + &cli.StringFlag{ + Name: "email", + Aliases: []string{"e"}, + Usage: "Email of the user to delete", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "purge", Usage: "Purge user, all their repositories, organizations and comments", }, diff --git a/cmd/admin_user_generate_access_token.go b/cmd/admin_user_generate_access_token.go index 822bc5c2b..9971c2ec9 100644 --- a/cmd/admin_user_generate_access_token.go +++ b/cmd/admin_user_generate_access_token.go @@ -9,27 +9,29 @@ import ( auth_model "code.gitea.io/gitea/models/auth" user_model "code.gitea.io/gitea/models/user" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) -var microcmdUserGenerateAccessToken = cli.Command{ +var microcmdUserGenerateAccessToken = &cli.Command{ Name: "generate-access-token", Usage: "Generate an access token for a specific user", Flags: []cli.Flag{ - cli.StringFlag{ - Name: "username,u", - Usage: "Username", + &cli.StringFlag{ + Name: "username", + Aliases: []string{"u"}, + Usage: "Username", }, - cli.StringFlag{ - Name: "token-name,t", - Usage: "Token name", - Value: "gitea-admin", + &cli.StringFlag{ + Name: "token-name", + Aliases: []string{"t"}, + Usage: "Token name", + Value: "gitea-admin", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "raw", Usage: "Display only the token value", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "scopes", Value: "", Usage: "Comma separated list of scopes to apply to access token", diff --git a/cmd/admin_user_list.go b/cmd/admin_user_list.go index 85490331e..9db9b5e56 100644 --- a/cmd/admin_user_list.go +++ b/cmd/admin_user_list.go @@ -10,15 +10,15 @@ import ( user_model "code.gitea.io/gitea/models/user" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) -var microcmdUserList = cli.Command{ +var microcmdUserList = &cli.Command{ Name: "list", Usage: "List users", Action: runListUsers, Flags: []cli.Flag{ - cli.BoolFlag{ + &cli.BoolFlag{ Name: "admin", Usage: "List only admin users", }, diff --git a/cmd/admin_user_must_change_password.go b/cmd/admin_user_must_change_password.go index eb13fbcae..279441425 100644 --- a/cmd/admin_user_must_change_password.go +++ b/cmd/admin_user_must_change_password.go @@ -9,23 +9,25 @@ import ( user_model "code.gitea.io/gitea/models/user" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) -var microcmdUserMustChangePassword = cli.Command{ +var microcmdUserMustChangePassword = &cli.Command{ Name: "must-change-password", Usage: "Set the must change password flag for the provided users or all users", Action: runMustChangePassword, Flags: []cli.Flag{ - cli.BoolFlag{ - Name: "all,A", - Usage: "All users must change password, except those explicitly excluded with --exclude", + &cli.BoolFlag{ + Name: "all", + Aliases: []string{"A"}, + Usage: "All users must change password, except those explicitly excluded with --exclude", }, - cli.StringSliceFlag{ - Name: "exclude,e", - Usage: "Do not change the must-change-password flag for these users", + &cli.StringSliceFlag{ + Name: "exclude", + Aliases: []string{"e"}, + Usage: "Do not change the must-change-password flag for these users", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "unset", Usage: "Instead of setting the must-change-password flag, unset it", }, @@ -48,7 +50,7 @@ func runMustChangePassword(c *cli.Context) error { return err } - n, err := user_model.SetMustChangePassword(ctx, all, mustChangePassword, c.Args(), exclude) + n, err := user_model.SetMustChangePassword(ctx, all, mustChangePassword, c.Args().Slice(), exclude) if err != nil { return err } diff --git a/cmd/cert.go b/cmd/cert.go index 897c10c89..9ae5ed06c 100644 --- a/cmd/cert.go +++ b/cmd/cert.go @@ -20,43 +20,43 @@ import ( "strings" "time" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) // CmdCert represents the available cert sub-command. -var CmdCert = cli.Command{ +var CmdCert = &cli.Command{ Name: "cert", Usage: "Generate self-signed certificate", Description: `Generate a self-signed X.509 certificate for a TLS server. Outputs to 'cert.pem' and 'key.pem' and will overwrite existing files.`, Action: runCert, Flags: []cli.Flag{ - cli.StringFlag{ + &cli.StringFlag{ Name: "host", Value: "", Usage: "Comma-separated hostnames and IPs to generate a certificate for", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "ecdsa-curve", Value: "", Usage: "ECDSA curve to use to generate a key. Valid values are P224, P256, P384, P521", }, - cli.IntFlag{ + &cli.IntFlag{ Name: "rsa-bits", Value: 2048, Usage: "Size of RSA key to generate. Ignored if --ecdsa-curve is set", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "start-date", Value: "", Usage: "Creation date formatted as Jan 1 15:04:05 2011", }, - cli.DurationFlag{ + &cli.DurationFlag{ Name: "duration", Value: 365 * 24 * time.Hour, Usage: "Duration that certificate is valid for", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "ca", Usage: "whether this cert should be its own Certificate Authority", }, diff --git a/cmd/cmd.go b/cmd/cmd.go index 4ed636a9b..423dce267 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -20,7 +20,7 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) // argsSet checks that all the required arguments are set. args is a list of @@ -109,15 +109,24 @@ func setupConsoleLogger(level log.Level, colorize bool, out io.Writer) { log.GetManager().GetLogger(log.DEFAULT).ReplaceAllWriters(writer) } +func globalBool(c *cli.Context, name string) bool { + for _, ctx := range c.Lineage() { + if ctx.Bool(name) { + return true + } + } + return false +} + // PrepareConsoleLoggerLevel by default, use INFO level for console logger, but some sub-commands (for git/ssh protocol) shouldn't output any log to stdout. // Any log appears in git stdout pipe will break the git protocol, eg: client can't push and hangs forever. func PrepareConsoleLoggerLevel(defaultLevel log.Level) func(*cli.Context) error { return func(c *cli.Context) error { level := defaultLevel - if c.Bool("quiet") || c.GlobalBoolT("quiet") { + if globalBool(c, "quiet") { level = log.FATAL } - if c.Bool("debug") || c.GlobalBool("debug") || c.Bool("verbose") || c.GlobalBool("verbose") { + if globalBool(c, "debug") || globalBool(c, "verbose") { level = log.TRACE } log.SetConsoleLogger(log.DEFAULT, "console-default", level) diff --git a/cmd/convert.go b/cmd/convert.go index 8c7746fdf..37a260cbd 100644 --- a/cmd/convert.go +++ b/cmd/convert.go @@ -10,11 +10,11 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) // CmdConvert represents the available convert sub-command. -var CmdConvert = cli.Command{ +var CmdConvert = &cli.Command{ Name: "convert", Usage: "Convert the database", Description: "A command to convert an existing MySQL database from utf8 to utf8mb4 or MSSQL database from varchar to nvarchar", diff --git a/cmd/docs.go b/cmd/docs.go index 901d0abd1..605d02e3e 100644 --- a/cmd/docs.go +++ b/cmd/docs.go @@ -8,11 +8,11 @@ import ( "os" "strings" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) // CmdDocs represents the available docs sub-command. -var CmdDocs = cli.Command{ +var CmdDocs = &cli.Command{ Name: "docs", Usage: "Output CLI documentation", Description: "A command to output Gitea's CLI documentation, optionally to a file.", @@ -23,8 +23,9 @@ var CmdDocs = cli.Command{ Usage: "Output man pages instead", }, &cli.StringFlag{ - Name: "output, o", - Usage: "Path to output to instead of stdout (will overwrite if exists)", + Name: "output", + Aliases: []string{"o"}, + Usage: "Path to output to instead of stdout (will overwrite if exists)", }, }, } diff --git a/cmd/doctor.go b/cmd/doctor.go index cd5f125e2..f8866c7b9 100644 --- a/cmd/doctor.go +++ b/cmd/doctor.go @@ -18,57 +18,58 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" "xorm.io/xorm" ) // CmdDoctor represents the available doctor sub-command. -var CmdDoctor = cli.Command{ +var CmdDoctor = &cli.Command{ Name: "doctor", Usage: "Diagnose and optionally fix problems", Description: "A command to diagnose problems with the current Gitea instance according to the given configuration. Some problems can optionally be fixed by modifying the database or data storage.", Action: runDoctor, Flags: []cli.Flag{ - cli.BoolFlag{ + &cli.BoolFlag{ Name: "list", Usage: "List the available checks", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "default", Usage: "Run the default checks (if neither --run or --all is set, this is the default behaviour)", }, - cli.StringSliceFlag{ + &cli.StringSliceFlag{ Name: "run", Usage: "Run the provided checks - (if --default is set, the default checks will also run)", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "all", Usage: "Run all the available checks", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "fix", Usage: "Automatically fix what we can", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "log-file", Usage: `Name of the log file (default: "doctor.log"). Set to "-" to output to stdout, set to "" to disable`, }, - cli.BoolFlag{ - Name: "color, H", - Usage: "Use color for outputted information", + &cli.BoolFlag{ + Name: "color", + Aliases: []string{"H"}, + Usage: "Use color for outputted information", }, }, - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ cmdRecreateTable, }, } -var cmdRecreateTable = cli.Command{ +var cmdRecreateTable = &cli.Command{ Name: "recreate-table", Usage: "Recreate tables from XORM definitions and copy the data.", ArgsUsage: "[TABLE]... : (TABLEs to recreate - leave blank for all)", Flags: []cli.Flag{ - cli.BoolFlag{ + &cli.BoolFlag{ Name: "debug", Usage: "Print SQL commands sent", }, diff --git a/cmd/dump.go b/cmd/dump.go index b1aed8aef..9b5259b86 100644 --- a/cmd/dump.go +++ b/cmd/dump.go @@ -22,7 +22,7 @@ import ( "gitea.com/go-chi/session" "github.com/mholt/archiver/v3" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) func addReader(w archiver.Writer, r io.ReadCloser, info os.FileInfo, customName string, verbose bool) error { @@ -96,64 +96,71 @@ var outputTypeEnum = &outputType{ } // CmdDump represents the available dump sub-command. -var CmdDump = cli.Command{ +var CmdDump = &cli.Command{ Name: "dump", Usage: "Dump Gitea files and database", Description: `Dump compresses all related files and database into zip file. It can be used for backup and capture Gitea server image to send to maintainer`, Action: runDump, Flags: []cli.Flag{ - cli.StringFlag{ - Name: "file, f", - Value: fmt.Sprintf("gitea-dump-%d.zip", time.Now().Unix()), - Usage: "Name of the dump file which will be created. Supply '-' for stdout. See type for available types.", + &cli.StringFlag{ + Name: "file", + Aliases: []string{"f"}, + Value: fmt.Sprintf("gitea-dump-%d.zip", time.Now().Unix()), + Usage: "Name of the dump file which will be created. Supply '-' for stdout. See type for available types.", }, - cli.BoolFlag{ - Name: "verbose, V", - Usage: "Show process details", + &cli.BoolFlag{ + Name: "verbose", + Aliases: []string{"V"}, + Usage: "Show process details", }, - cli.BoolFlag{ - Name: "quiet, q", - Usage: "Only display warnings and errors", + &cli.BoolFlag{ + Name: "quiet", + Aliases: []string{"q"}, + Usage: "Only display warnings and errors", }, - cli.StringFlag{ - Name: "tempdir, t", - Value: os.TempDir(), - Usage: "Temporary dir path", + &cli.StringFlag{ + Name: "tempdir", + Aliases: []string{"t"}, + Value: os.TempDir(), + Usage: "Temporary dir path", }, - cli.StringFlag{ - Name: "database, d", - Usage: "Specify the database SQL syntax", + &cli.StringFlag{ + Name: "database", + Aliases: []string{"d"}, + Usage: "Specify the database SQL syntax", }, - cli.BoolFlag{ - Name: "skip-repository, R", - Usage: "Skip the repository dumping", + &cli.BoolFlag{ + Name: "skip-repository", + Aliases: []string{"R"}, + Usage: "Skip the repository dumping", }, - cli.BoolFlag{ - Name: "skip-log, L", - Usage: "Skip the log dumping", + &cli.BoolFlag{ + Name: "skip-log", + Aliases: []string{"L"}, + Usage: "Skip the log dumping", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "skip-custom-dir", Usage: "Skip custom directory", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "skip-lfs-data", Usage: "Skip LFS data", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "skip-attachment-data", Usage: "Skip attachment data", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "skip-package-data", Usage: "Skip package data", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "skip-index", Usage: "Skip bleve index data", }, - cli.GenericFlag{ + &cli.GenericFlag{ Name: "type", Value: outputTypeEnum, Usage: fmt.Sprintf("Dump output format: %s", outputTypeEnum.Join()), diff --git a/cmd/dump_repo.go b/cmd/dump_repo.go index 0d3970466..3a24cf6c5 100644 --- a/cmd/dump_repo.go +++ b/cmd/dump_repo.go @@ -19,57 +19,58 @@ import ( "code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/migrations" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) // CmdDumpRepository represents the available dump repository sub-command. -var CmdDumpRepository = cli.Command{ +var CmdDumpRepository = &cli.Command{ Name: "dump-repo", Usage: "Dump the repository from git/github/gitea/gitlab", Description: "This is a command for dumping the repository data.", Action: runDumpRepository, Flags: []cli.Flag{ - cli.StringFlag{ + &cli.StringFlag{ Name: "git_service", Value: "", Usage: "Git service, git, github, gitea, gitlab. If clone_addr could be recognized, this could be ignored.", }, - cli.StringFlag{ - Name: "repo_dir, r", - Value: "./data", - Usage: "Repository dir path to store the data", + &cli.StringFlag{ + Name: "repo_dir", + Aliases: []string{"r"}, + Value: "./data", + Usage: "Repository dir path to store the data", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "clone_addr", Value: "", Usage: "The URL will be clone, currently could be a git/github/gitea/gitlab http/https URL", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "auth_username", Value: "", Usage: "The username to visit the clone_addr", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "auth_password", Value: "", Usage: "The password to visit the clone_addr", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "auth_token", Value: "", Usage: "The personal token to visit the clone_addr", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "owner_name", Value: "", Usage: "The data will be stored on a directory with owner name if not empty", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "repo_name", Value: "", Usage: "The data will be stored on a directory with repository name if not empty", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "units", Value: "", Usage: `Which items will be migrated, one or more units should be separated as comma. diff --git a/cmd/embedded.go b/cmd/embedded.go index 105acee26..71d483d11 100644 --- a/cmd/embedded.go +++ b/cmd/embedded.go @@ -19,70 +19,74 @@ import ( "code.gitea.io/gitea/modules/util" "github.com/gobwas/glob" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) // CmdEmbedded represents the available extract sub-command. var ( - CmdEmbedded = cli.Command{ + CmdEmbedded = &cli.Command{ Name: "embedded", Usage: "Extract embedded resources", Description: "A command for extracting embedded resources, like templates and images", - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ subcmdList, subcmdView, subcmdExtract, }, } - subcmdList = cli.Command{ + subcmdList = &cli.Command{ Name: "list", Usage: "List files matching the given pattern", Action: runList, Flags: []cli.Flag{ - cli.BoolFlag{ - Name: "include-vendored,vendor", - Usage: "Include files under public/vendor as well", + &cli.BoolFlag{ + Name: "include-vendored", + Aliases: []string{"vendor"}, + Usage: "Include files under public/vendor as well", }, }, } - subcmdView = cli.Command{ + subcmdView = &cli.Command{ Name: "view", Usage: "View a file matching the given pattern", Action: runView, Flags: []cli.Flag{ - cli.BoolFlag{ - Name: "include-vendored,vendor", - Usage: "Include files under public/vendor as well", + &cli.BoolFlag{ + Name: "include-vendored", + Aliases: []string{"vendor"}, + Usage: "Include files under public/vendor as well", }, }, } - subcmdExtract = cli.Command{ + subcmdExtract = &cli.Command{ Name: "extract", Usage: "Extract resources", Action: runExtract, Flags: []cli.Flag{ - cli.BoolFlag{ - Name: "include-vendored,vendor", - Usage: "Include files under public/vendor as well", + &cli.BoolFlag{ + Name: "include-vendored", + Aliases: []string{"vendor"}, + Usage: "Include files under public/vendor as well", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "overwrite", Usage: "Overwrite files if they already exist", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "rename", Usage: "Rename files as {name}.bak if they already exist (overwrites previous .bak)", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "custom", Usage: "Extract to the 'custom' directory as per app.ini", }, - cli.StringFlag{ - Name: "destination,dest-dir", - Usage: "Extract to the specified directory", + &cli.StringFlag{ + Name: "destination", + Aliases: []string{"dest-dir"}, + Usage: "Extract to the specified directory", }, }, } @@ -99,7 +103,7 @@ type assetFile struct { func initEmbeddedExtractor(c *cli.Context) error { setupConsoleLogger(log.ERROR, log.CanColorStderr, os.Stderr) - patterns, err := compileCollectPatterns(c.Args()) + patterns, err := compileCollectPatterns(c.Args().Slice()) if err != nil { return err } @@ -175,7 +179,7 @@ func runExtractDo(c *cli.Context) error { return err } - if len(c.Args()) == 0 { + if c.NArg() == 0 { return fmt.Errorf("a list of pattern of files to extract is mandatory (e.g. '**' for all)") } diff --git a/cmd/generate.go b/cmd/generate.go index f72ee1639..2cff24458 100644 --- a/cmd/generate.go +++ b/cmd/generate.go @@ -11,43 +11,43 @@ import ( "code.gitea.io/gitea/modules/generate" "github.com/mattn/go-isatty" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) var ( // CmdGenerate represents the available generate sub-command. - CmdGenerate = cli.Command{ + CmdGenerate = &cli.Command{ Name: "generate", Usage: "Command line interface for running generators", - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ subcmdSecret, }, } - subcmdSecret = cli.Command{ + subcmdSecret = &cli.Command{ Name: "secret", Usage: "Generate a secret token", - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ microcmdGenerateInternalToken, microcmdGenerateLfsJwtSecret, microcmdGenerateSecretKey, }, } - microcmdGenerateInternalToken = cli.Command{ + microcmdGenerateInternalToken = &cli.Command{ Name: "INTERNAL_TOKEN", Usage: "Generate a new INTERNAL_TOKEN", Action: runGenerateInternalToken, } - microcmdGenerateLfsJwtSecret = cli.Command{ + microcmdGenerateLfsJwtSecret = &cli.Command{ Name: "JWT_SECRET", Aliases: []string{"LFS_JWT_SECRET"}, Usage: "Generate a new JWT_SECRET", Action: runGenerateLfsJwtSecret, } - microcmdGenerateSecretKey = cli.Command{ + microcmdGenerateSecretKey = &cli.Command{ Name: "SECRET_KEY", Usage: "Generate a new SECRET_KEY", Action: runGenerateSecretKey, diff --git a/cmd/hook.go b/cmd/hook.go index ed6efc19e..f38fd8831 100644 --- a/cmd/hook.go +++ b/cmd/hook.go @@ -20,7 +20,7 @@ import ( repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) const ( @@ -29,12 +29,12 @@ const ( var ( // CmdHook represents the available hooks sub-command. - CmdHook = cli.Command{ + CmdHook = &cli.Command{ Name: "hook", Usage: "Delegate commands to corresponding Git hooks", Description: "This should only be called by Git", Before: PrepareConsoleLoggerLevel(log.FATAL), - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ subcmdHookPreReceive, subcmdHookUpdate, subcmdHookPostReceive, @@ -42,47 +42,47 @@ var ( }, } - subcmdHookPreReceive = cli.Command{ + subcmdHookPreReceive = &cli.Command{ Name: "pre-receive", Usage: "Delegate pre-receive Git hook", Description: "This command should only be called by Git", Action: runHookPreReceive, Flags: []cli.Flag{ - cli.BoolFlag{ + &cli.BoolFlag{ Name: "debug", }, }, } - subcmdHookUpdate = cli.Command{ + subcmdHookUpdate = &cli.Command{ Name: "update", Usage: "Delegate update Git hook", Description: "This command should only be called by Git", Action: runHookUpdate, Flags: []cli.Flag{ - cli.BoolFlag{ + &cli.BoolFlag{ Name: "debug", }, }, } - subcmdHookPostReceive = cli.Command{ + subcmdHookPostReceive = &cli.Command{ Name: "post-receive", Usage: "Delegate post-receive Git hook", Description: "This command should only be called by Git", Action: runHookPostReceive, Flags: []cli.Flag{ - cli.BoolFlag{ + &cli.BoolFlag{ Name: "debug", }, }, } // Note: new hook since git 2.29 - subcmdHookProcReceive = cli.Command{ + subcmdHookProcReceive = &cli.Command{ Name: "proc-receive", Usage: "Delegate proc-receive Git hook", Description: "This command should only be called by Git", Action: runHookProcReceive, Flags: []cli.Flag{ - cli.BoolFlag{ + &cli.BoolFlag{ Name: "debug", }, }, diff --git a/cmd/keys.go b/cmd/keys.go index 8aeee3752..b84678252 100644 --- a/cmd/keys.go +++ b/cmd/keys.go @@ -11,35 +11,39 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/private" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) // CmdKeys represents the available keys sub-command -var CmdKeys = cli.Command{ +var CmdKeys = &cli.Command{ Name: "keys", Usage: "This command queries the Gitea database to get the authorized command for a given ssh key fingerprint", Before: PrepareConsoleLoggerLevel(log.FATAL), Action: runKeys, Flags: []cli.Flag{ - cli.StringFlag{ - Name: "expected, e", - Value: "git", - Usage: "Expected user for whom provide key commands", + &cli.StringFlag{ + Name: "expected", + Aliases: []string{"e"}, + Value: "git", + Usage: "Expected user for whom provide key commands", }, - cli.StringFlag{ - Name: "username, u", - Value: "", - Usage: "Username trying to log in by SSH", + &cli.StringFlag{ + Name: "username", + Aliases: []string{"u"}, + Value: "", + Usage: "Username trying to log in by SSH", }, - cli.StringFlag{ - Name: "type, t", - Value: "", - Usage: "Type of the SSH key provided to the SSH Server (requires content to be provided too)", + &cli.StringFlag{ + Name: "type", + Aliases: []string{"t"}, + Value: "", + Usage: "Type of the SSH key provided to the SSH Server (requires content to be provided too)", }, - cli.StringFlag{ - Name: "content, k", - Value: "", - Usage: "Base64 encoded content of the SSH key provided to the SSH Server (requires type to be provided too)", + &cli.StringFlag{ + Name: "content", + Aliases: []string{"k"}, + Value: "", + Usage: "Base64 encoded content of the SSH key provided to the SSH Server (requires type to be provided too)", }, }, } @@ -73,6 +77,6 @@ func runKeys(c *cli.Context) error { if extra.Error != nil { return extra.Error } - fmt.Println(strings.TrimSpace(authorizedString)) + _, _ = fmt.Fprintln(c.App.Writer, strings.TrimSpace(authorizedString)) return nil } diff --git a/cmd/mailer.go b/cmd/mailer.go index eaa5a1afe..646330e85 100644 --- a/cmd/mailer.go +++ b/cmd/mailer.go @@ -9,7 +9,7 @@ import ( "code.gitea.io/gitea/modules/private" "code.gitea.io/gitea/modules/setting" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) func runSendMail(c *cli.Context) error { diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 000000000..b4a38a452 --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,196 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package cmd + +import ( + "fmt" + "os" + "reflect" + "strings" + + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + + "github.com/urfave/cli/v2" +) + +// cmdHelp is our own help subcommand with more information +func cmdHelp() *cli.Command { + c := &cli.Command{ + Name: "help", + Aliases: []string{"h"}, + Usage: "Shows a list of commands or help for one command", + ArgsUsage: "[command]", + Action: func(c *cli.Context) (err error) { + args := c.Args() + if args.Present() { + err = cli.ShowCommandHelp(c, args.First()) + } else { + err = cli.ShowAppHelp(c) + } + _, _ = fmt.Fprintf(c.App.Writer, ` +DEFAULT CONFIGURATION: + AppPath: %s + WorkPath: %s + CustomPath: %s + ConfigFile: %s + +`, setting.AppPath, setting.AppWorkPath, setting.CustomPath, setting.CustomConf) + return err + }, + } + return c +} + +var helpFlag = cli.HelpFlag + +func init() { + // cli.HelpFlag = nil TODO: after https://github.com/urfave/cli/issues/1794 we can use this +} + +func appGlobalFlags() []cli.Flag { + return []cli.Flag{ + // make the builtin flags at the top + helpFlag, + cli.VersionFlag, + + // shared configuration flags, they are for global and for each sub-command at the same time + // eg: such command is valid: "./gitea --config /tmp/app.ini web --config /tmp/app.ini", while it's discouraged indeed + // keep in mind that the short flags like "-C", "-c" and "-w" are globally polluted, they can't be used for sub-commands anymore. + &cli.StringFlag{ + Name: "custom-path", + Aliases: []string{"C"}, + Usage: "Set custom path (defaults to '{WorkPath}/custom')", + }, + &cli.StringFlag{ + Name: "config", + Aliases: []string{"c"}, + Value: setting.CustomConf, + Usage: "Set custom config file (defaults to '{WorkPath}/custom/conf/app.ini')", + }, + &cli.StringFlag{ + Name: "work-path", + Aliases: []string{"w"}, + Usage: "Set Gitea's working path (defaults to the Gitea's binary directory)", + }, + } +} + +func prepareSubcommandWithConfig(command *cli.Command, globalFlags []cli.Flag) { + command.Flags = append(append([]cli.Flag{}, globalFlags...), command.Flags...) + command.Action = prepareWorkPathAndCustomConf(command.Action) + command.HideHelp = true + if command.Name != "help" { + command.Subcommands = append(command.Subcommands, cmdHelp()) + } + for i := range command.Subcommands { + prepareSubcommandWithConfig(command.Subcommands[i], globalFlags) + } +} + +// prepareWorkPathAndCustomConf wraps the Action to prepare the work path and custom config +// It can't use "Before", because each level's sub-command's Before will be called one by one, so the "init" would be done multiple times +func prepareWorkPathAndCustomConf(action cli.ActionFunc) func(ctx *cli.Context) error { + return func(ctx *cli.Context) error { + var args setting.ArgWorkPathAndCustomConf + ctxLineage := ctx.Lineage() + for i := len(ctxLineage) - 1; i >= 0; i-- { + curCtx := ctxLineage[i] + if curCtx.IsSet("work-path") && args.WorkPath == "" { + args.WorkPath = curCtx.String("work-path") + } + if curCtx.IsSet("custom-path") && args.CustomPath == "" { + args.CustomPath = curCtx.String("custom-path") + } + if curCtx.IsSet("config") && args.CustomConf == "" { + args.CustomConf = curCtx.String("config") + } + } + setting.InitWorkPathAndCommonConfig(os.Getenv, args) + if ctx.Bool("help") || action == nil { + // the default behavior of "urfave/cli": "nil action" means "show help" + return cmdHelp().Action(ctx) + } + return action(ctx) + } +} + +func reflectGet(v any, fieldName string) any { + e := reflect.ValueOf(v).Elem() + return e.FieldByName(fieldName).Interface() +} + +// https://cli.urfave.org/migrate-v1-to-v2/#flag-aliases-are-done-differently +// Sadly v2 doesn't warn you if a comma is in the name. (https://github.com/urfave/cli/issues/1103) +func checkCommandFlags(c any) bool { + var cmds []*cli.Command + if app, ok := c.(*cli.App); ok { + cmds = app.Commands + } else { + cmds = c.(*cli.Command).Subcommands + } + ok := true + for _, cmd := range cmds { + for _, flag := range cmd.Flags { + flagName := reflectGet(flag, "Name").(string) + if strings.Contains(flagName, ",") { + ok = false + log.Error("cli.Flag can't have comma in its Name: %q, use Aliases instead", flagName) + } + } + if !checkCommandFlags(cmd) { + ok = false + } + } + return ok +} + +func NewMainApp() *cli.App { + app := cli.NewApp() + app.EnableBashCompletion = true + + // these sub-commands need to use config file + subCmdWithConfig := []*cli.Command{ + CmdWeb, + CmdServ, + CmdHook, + CmdDump, + CmdAdmin, + CmdMigrate, + CmdKeys, + CmdConvert, + CmdDoctor, + CmdManager, + CmdEmbedded, + CmdMigrateStorage, + CmdDumpRepository, + CmdRestoreRepository, + CmdActions, + cmdHelp(), // the "help" sub-command was used to show the more information for "work path" and "custom config" + } + + // these sub-commands do not need the config file, and they do not depend on any path or environment variable. + subCmdStandalone := []*cli.Command{ + CmdCert, + CmdGenerate, + CmdDocs, + } + + app.DefaultCommand = CmdWeb.Name + + globalFlags := appGlobalFlags() + app.Flags = append(app.Flags, globalFlags...) + app.HideHelp = true // use our own help action to show helps (with more information like default config) + app.Before = PrepareConsoleLoggerLevel(log.INFO) + for i := range subCmdWithConfig { + prepareSubcommandWithConfig(subCmdWithConfig[i], globalFlags) + } + app.Commands = append(app.Commands, subCmdWithConfig...) + app.Commands = append(app.Commands, subCmdStandalone...) + + if !checkCommandFlags(app) { + panic("some flags are incorrect") // this is a runtime check to help developers + } + return app +} diff --git a/cmd/main_test.go b/cmd/main_test.go index 6e20be694..e9204d09c 100644 --- a/cmd/main_test.go +++ b/cmd/main_test.go @@ -4,9 +4,17 @@ package cmd import ( + "fmt" + "os" + "path/filepath" + "strings" "testing" "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/setting" + + "github.com/stretchr/testify/assert" + "github.com/urfave/cli/v2" ) func TestMain(m *testing.M) { @@ -14,3 +22,110 @@ func TestMain(m *testing.M) { GiteaRootPath: "..", }) } + +func makePathOutput(workPath, customPath, customConf string) string { + return fmt.Sprintf("WorkPath=%s\nCustomPath=%s\nCustomConf=%s", workPath, customPath, customConf) +} + +func newTestApp() *cli.App { + app := NewMainApp() + testCmd := &cli.Command{ + Name: "test-cmd", + Action: func(ctx *cli.Context) error { + _, _ = fmt.Fprint(app.Writer, makePathOutput(setting.AppWorkPath, setting.CustomPath, setting.CustomConf)) + return nil + }, + } + prepareSubcommandWithConfig(testCmd, appGlobalFlags()) + app.Commands = append(app.Commands, testCmd) + app.DefaultCommand = testCmd.Name + return app +} + +func TestCliCmd(t *testing.T) { + defaultWorkPath := filepath.Dir(setting.AppPath) + defaultCustomPath := filepath.Join(defaultWorkPath, "custom") + defaultCustomConf := filepath.Join(defaultCustomPath, "conf/app.ini") + + cli.CommandHelpTemplate = "(command help template)" + cli.AppHelpTemplate = "(app help template)" + cli.SubcommandHelpTemplate = "(subcommand help template)" + + cases := []struct { + env map[string]string + cmd string + exp string + }{ + // main command help + { + cmd: "./gitea help", + exp: "DEFAULT CONFIGURATION:", + }, + + // parse paths + { + cmd: "./gitea test-cmd", + exp: makePathOutput(defaultWorkPath, defaultCustomPath, defaultCustomConf), + }, + { + cmd: "./gitea -c /tmp/app.ini test-cmd", + exp: makePathOutput(defaultWorkPath, defaultCustomPath, "/tmp/app.ini"), + }, + { + cmd: "./gitea test-cmd -c /tmp/app.ini", + exp: makePathOutput(defaultWorkPath, defaultCustomPath, "/tmp/app.ini"), + }, + { + env: map[string]string{"GITEA_WORK_DIR": "/tmp"}, + cmd: "./gitea test-cmd", + exp: makePathOutput("/tmp", "/tmp/custom", "/tmp/custom/conf/app.ini"), + }, + { + env: map[string]string{"GITEA_WORK_DIR": "/tmp"}, + cmd: "./gitea test-cmd --work-path /tmp/other", + exp: makePathOutput("/tmp/other", "/tmp/other/custom", "/tmp/other/custom/conf/app.ini"), + }, + { + env: map[string]string{"GITEA_WORK_DIR": "/tmp"}, + cmd: "./gitea test-cmd --config /tmp/app-other.ini", + exp: makePathOutput("/tmp", "/tmp/custom", "/tmp/app-other.ini"), + }, + } + + app := newTestApp() + var envBackup []string + for _, s := range os.Environ() { + if strings.HasPrefix(s, "GITEA_") && strings.Contains(s, "=") { + envBackup = append(envBackup, s) + } + } + clearGiteaEnv := func() { + for _, s := range os.Environ() { + if strings.HasPrefix(s, "GITEA_") { + _ = os.Unsetenv(s) + } + } + } + defer func() { + clearGiteaEnv() + for _, s := range envBackup { + k, v, _ := strings.Cut(s, "=") + _ = os.Setenv(k, v) + } + }() + + for _, c := range cases { + clearGiteaEnv() + for k, v := range c.env { + _ = os.Setenv(k, v) + } + args := strings.Split(c.cmd, " ") // for test only, "split" is good enough + out := new(strings.Builder) + app.Writer = out + err := app.Run(args) + assert.NoError(t, err, c.cmd) + assert.NotEmpty(t, c.exp, c.cmd) + outStr := out.String() + assert.Contains(t, outStr, c.exp, c.cmd) + } +} diff --git a/cmd/manager.go b/cmd/manager.go index 2024d5ebb..bd2da8edc 100644 --- a/cmd/manager.go +++ b/cmd/manager.go @@ -9,16 +9,16 @@ import ( "code.gitea.io/gitea/modules/private" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) var ( // CmdManager represents the manager command - CmdManager = cli.Command{ + CmdManager = &cli.Command{ Name: "manager", Usage: "Manage the running gitea process", Description: "This is a command for managing the running gitea process", - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ subcmdShutdown, subcmdRestart, subcmdReloadTemplates, @@ -27,80 +27,80 @@ var ( subCmdProcesses, }, } - subcmdShutdown = cli.Command{ + subcmdShutdown = &cli.Command{ Name: "shutdown", Usage: "Gracefully shutdown the running process", Flags: []cli.Flag{ - cli.BoolFlag{ + &cli.BoolFlag{ Name: "debug", }, }, Action: runShutdown, } - subcmdRestart = cli.Command{ + subcmdRestart = &cli.Command{ Name: "restart", Usage: "Gracefully restart the running process - (not implemented for windows servers)", Flags: []cli.Flag{ - cli.BoolFlag{ + &cli.BoolFlag{ Name: "debug", }, }, Action: runRestart, } - subcmdReloadTemplates = cli.Command{ + subcmdReloadTemplates = &cli.Command{ Name: "reload-templates", Usage: "Reload template files in the running process", Flags: []cli.Flag{ - cli.BoolFlag{ + &cli.BoolFlag{ Name: "debug", }, }, Action: runReloadTemplates, } - subcmdFlushQueues = cli.Command{ + subcmdFlushQueues = &cli.Command{ Name: "flush-queues", Usage: "Flush queues in the running process", Action: runFlushQueues, Flags: []cli.Flag{ - cli.DurationFlag{ + &cli.DurationFlag{ Name: "timeout", Value: 60 * time.Second, Usage: "Timeout for the flushing process", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "non-blocking", Usage: "Set to true to not wait for flush to complete before returning", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "debug", }, }, } - subCmdProcesses = cli.Command{ + subCmdProcesses = &cli.Command{ Name: "processes", Usage: "Display running processes within the current process", Action: runProcesses, Flags: []cli.Flag{ - cli.BoolFlag{ + &cli.BoolFlag{ Name: "debug", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "flat", Usage: "Show processes as flat table rather than as tree", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "no-system", Usage: "Do not show system processes", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "stacktraces", Usage: "Show stacktraces", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "json", Usage: "Output as json", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "cancel", Usage: "Process PID to cancel. (Only available for non-system processes.)", }, diff --git a/cmd/manager_logging.go b/cmd/manager_logging.go index 70d1beb26..84c962561 100644 --- a/cmd/manager_logging.go +++ b/cmd/manager_logging.go @@ -10,49 +10,61 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/private" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) var ( defaultLoggingFlags = []cli.Flag{ - cli.StringFlag{ + &cli.StringFlag{ Name: "logger", Usage: `Logger name - will default to "default"`, - }, cli.StringFlag{ + }, + &cli.StringFlag{ Name: "writer", Usage: "Name of the log writer - will default to mode", - }, cli.StringFlag{ + }, + &cli.StringFlag{ Name: "level", Usage: "Logging level for the new logger", - }, cli.StringFlag{ - Name: "stacktrace-level, L", - Usage: "Stacktrace logging level", - }, cli.StringFlag{ - Name: "flags, F", - Usage: "Flags for the logger", - }, cli.StringFlag{ - Name: "expression, e", - Usage: "Matching expression for the logger", - }, cli.StringFlag{ - Name: "prefix, p", - Usage: "Prefix for the logger", - }, cli.BoolFlag{ + }, + &cli.StringFlag{ + Name: "stacktrace-level", + Aliases: []string{"L"}, + Usage: "Stacktrace logging level", + }, + &cli.StringFlag{ + Name: "flags", + Aliases: []string{"F"}, + Usage: "Flags for the logger", + }, + &cli.StringFlag{ + Name: "expression", + Aliases: []string{"e"}, + Usage: "Matching expression for the logger", + }, + &cli.StringFlag{ + Name: "prefix", + Aliases: []string{"p"}, + Usage: "Prefix for the logger", + }, + &cli.BoolFlag{ Name: "color", Usage: "Use color in the logs", - }, cli.BoolFlag{ + }, + &cli.BoolFlag{ Name: "debug", }, } - subcmdLogging = cli.Command{ + subcmdLogging = &cli.Command{ Name: "logging", Usage: "Adjust logging commands", - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ { Name: "pause", Usage: "Pause logging (Gitea will buffer logs up to a certain point and will drop them after that point)", Flags: []cli.Flag{ - cli.BoolFlag{ + &cli.BoolFlag{ Name: "debug", }, }, @@ -61,7 +73,7 @@ var ( Name: "resume", Usage: "Resume logging", Flags: []cli.Flag{ - cli.BoolFlag{ + &cli.BoolFlag{ Name: "debug", }, }, @@ -70,7 +82,7 @@ var ( Name: "release-and-reopen", Usage: "Cause Gitea to release and re-open files used for logging", Flags: []cli.Flag{ - cli.BoolFlag{ + &cli.BoolFlag{ Name: "debug", }, }, @@ -80,9 +92,9 @@ var ( Usage: "Remove a logger", ArgsUsage: "[name] Name of logger to remove", Flags: []cli.Flag{ - cli.BoolFlag{ + &cli.BoolFlag{ Name: "debug", - }, cli.StringFlag{ + }, &cli.StringFlag{ Name: "logger", Usage: `Logger name - will default to "default"`, }, @@ -91,32 +103,45 @@ var ( }, { Name: "add", Usage: "Add a logger", - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ { Name: "file", Usage: "Add a file logger", Flags: append(defaultLoggingFlags, []cli.Flag{ - cli.StringFlag{ - Name: "filename, f", - Usage: "Filename for the logger - this must be set.", - }, cli.BoolTFlag{ - Name: "rotate, r", - Usage: "Rotate logs", - }, cli.Int64Flag{ - Name: "max-size, s", - Usage: "Maximum size in bytes before rotation", - }, cli.BoolTFlag{ - Name: "daily, d", - Usage: "Rotate logs daily", - }, cli.IntFlag{ - Name: "max-days, D", - Usage: "Maximum number of daily logs to keep", - }, cli.BoolTFlag{ - Name: "compress, z", - Usage: "Compress rotated logs", - }, cli.IntFlag{ - Name: "compression-level, Z", - Usage: "Compression level to use", + &cli.StringFlag{ + Name: "filename", + Aliases: []string{"f"}, + Usage: "Filename for the logger - this must be set.", + }, + &cli.BoolFlag{ + Name: "rotate", + Aliases: []string{"r"}, + Usage: "Rotate logs", + }, + &cli.Int64Flag{ + Name: "max-size", + Aliases: []string{"s"}, + Usage: "Maximum size in bytes before rotation", + }, + &cli.BoolFlag{ + Name: "daily", + Aliases: []string{"d"}, + Usage: "Rotate logs daily", + }, + &cli.IntFlag{ + Name: "max-days", + Aliases: []string{"D"}, + Usage: "Maximum number of daily logs to keep", + }, + &cli.BoolFlag{ + Name: "compress", + Aliases: []string{"z"}, + Usage: "Compress rotated logs", + }, + &cli.IntFlag{ + Name: "compression-level", + Aliases: []string{"Z"}, + Usage: "Compression level to use", }, }...), Action: runAddFileLogger, @@ -124,18 +149,25 @@ var ( Name: "conn", Usage: "Add a net conn logger", Flags: append(defaultLoggingFlags, []cli.Flag{ - cli.BoolFlag{ - Name: "reconnect-on-message, R", - Usage: "Reconnect to host for every message", - }, cli.BoolFlag{ - Name: "reconnect, r", - Usage: "Reconnect to host when connection is dropped", - }, cli.StringFlag{ - Name: "protocol, P", - Usage: "Set protocol to use: tcp, unix, or udp (defaults to tcp)", - }, cli.StringFlag{ - Name: "address, a", - Usage: "Host address and port to connect to (defaults to :7020)", + &cli.BoolFlag{ + Name: "reconnect-on-message", + Aliases: []string{"R"}, + Usage: "Reconnect to host for every message", + }, + &cli.BoolFlag{ + Name: "reconnect", + Aliases: []string{"r"}, + Usage: "Reconnect to host when connection is dropped", + }, + &cli.StringFlag{ + Name: "protocol", + Aliases: []string{"P"}, + Usage: "Set protocol to use: tcp, unix, or udp (defaults to tcp)", + }, + &cli.StringFlag{ + Name: "address", + Aliases: []string{"a"}, + Usage: "Host address and port to connect to (defaults to :7020)", }, }...), Action: runAddConnLogger, @@ -145,9 +177,10 @@ var ( Name: "log-sql", Usage: "Set LogSQL", Flags: []cli.Flag{ - cli.BoolFlag{ + &cli.BoolFlag{ Name: "debug", - }, cli.BoolFlag{ + }, + &cli.BoolFlag{ Name: "off", Usage: "Switch off SQL logging", }, diff --git a/cmd/migrate.go b/cmd/migrate.go index efa791bc6..4e4dd45af 100644 --- a/cmd/migrate.go +++ b/cmd/migrate.go @@ -11,11 +11,11 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) // CmdMigrate represents the available migrate sub-command. -var CmdMigrate = cli.Command{ +var CmdMigrate = &cli.Command{ Name: "migrate", Usage: "Migrate the database", Description: "This is a command for migrating the database, so that you can run gitea admin create-user before starting the server.", diff --git a/cmd/migrate_storage.go b/cmd/migrate_storage.go index 511db6cbf..7f94e11ea 100644 --- a/cmd/migrate_storage.go +++ b/cmd/migrate_storage.go @@ -20,70 +20,73 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) // CmdMigrateStorage represents the available migrate storage sub-command. -var CmdMigrateStorage = cli.Command{ +var CmdMigrateStorage = &cli.Command{ Name: "migrate-storage", Usage: "Migrate the storage", Description: "Copies stored files from storage configured in app.ini to parameter-configured storage", Action: runMigrateStorage, Flags: []cli.Flag{ - cli.StringFlag{ - Name: "type, t", - Value: "", - Usage: "Type of stored files to copy. Allowed types: 'attachments', 'lfs', 'avatars', 'repo-avatars', 'repo-archivers', 'packages', 'actions-log'", + &cli.StringFlag{ + Name: "type", + Aliases: []string{"t"}, + Value: "", + Usage: "Type of stored files to copy. Allowed types: 'attachments', 'lfs', 'avatars', 'repo-avatars', 'repo-archivers', 'packages', 'actions-log'", }, - cli.StringFlag{ - Name: "storage, s", - Value: "", - Usage: "New storage type: local (default) or minio", + &cli.StringFlag{ + Name: "storage", + Aliases: []string{"s"}, + Value: "", + Usage: "New storage type: local (default) or minio", }, - cli.StringFlag{ - Name: "path, p", - Value: "", - Usage: "New storage placement if store is local (leave blank for default)", + &cli.StringFlag{ + Name: "path", + Aliases: []string{"p"}, + Value: "", + Usage: "New storage placement if store is local (leave blank for default)", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "minio-endpoint", Value: "", Usage: "Minio storage endpoint", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "minio-access-key-id", Value: "", Usage: "Minio storage accessKeyID", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "minio-secret-access-key", Value: "", Usage: "Minio storage secretAccessKey", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "minio-bucket", Value: "", Usage: "Minio storage bucket", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "minio-location", Value: "", Usage: "Minio storage location to create bucket", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "minio-base-path", Value: "", Usage: "Minio storage base path on the bucket", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "minio-use-ssl", Usage: "Enable SSL for minio", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "minio-insecure-skip-verify", Usage: "Skip SSL verification", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "minio-checksum-algorithm", Value: "", Usage: "Minio checksum algorithm (default/md5)", diff --git a/cmd/restore_repo.go b/cmd/restore_repo.go index c19e28f13..37b32aa30 100644 --- a/cmd/restore_repo.go +++ b/cmd/restore_repo.go @@ -9,38 +9,39 @@ import ( "code.gitea.io/gitea/modules/private" "code.gitea.io/gitea/modules/setting" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) // CmdRestoreRepository represents the available restore a repository sub-command. -var CmdRestoreRepository = cli.Command{ +var CmdRestoreRepository = &cli.Command{ Name: "restore-repo", Usage: "Restore the repository from disk", Description: "This is a command for restoring the repository data.", Action: runRestoreRepository, Flags: []cli.Flag{ - cli.StringFlag{ - Name: "repo_dir, r", - Value: "./data", - Usage: "Repository dir path to restore from", + &cli.StringFlag{ + Name: "repo_dir", + Aliases: []string{"r"}, + Value: "./data", + Usage: "Repository dir path to restore from", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "owner_name", Value: "", Usage: "Restore destination owner name", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "repo_name", Value: "", Usage: "Restore destination repository name", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "units", Value: "", Usage: `Which items will be restored, one or more units should be separated as comma. wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments are allowed. Empty means all units.`, }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "validation", Usage: "Sanity check the content of the files before trying to load them", }, diff --git a/cmd/serv.go b/cmd/serv.go index 6b5cb7866..26fc91a3b 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -32,7 +32,7 @@ import ( "github.com/golang-jwt/jwt/v5" "github.com/kballard/go-shellquote" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) const ( @@ -40,17 +40,17 @@ const ( ) // CmdServ represents the available serv sub-command. -var CmdServ = cli.Command{ +var CmdServ = &cli.Command{ Name: "serv", Usage: "This command should only be called by SSH shell", Description: "Serv provides access auth for repositories", Before: PrepareConsoleLoggerLevel(log.FATAL), Action: runServ, Flags: []cli.Flag{ - cli.BoolFlag{ + &cli.BoolFlag{ Name: "enable-pprof", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "debug", }, }, @@ -119,7 +119,7 @@ func fail(ctx context.Context, userMessage, logMsgFmt string, args ...any) error } _ = private.SSHLog(ctx, true, logMsg) } - return cli.NewExitError("", 1) + return cli.Exit("", 1) } // handleCliResponseExtra handles the extra response from the cli sub-commands @@ -130,7 +130,7 @@ func handleCliResponseExtra(extra private.ResponseExtra) error { _, _ = fmt.Fprintln(os.Stdout, extra.UserMsg) } if extra.HasError() { - return cli.NewExitError(extra.Error, 1) + return cli.Exit(extra.Error, 1) } return nil } @@ -147,20 +147,20 @@ func runServ(c *cli.Context) error { return nil } - if len(c.Args()) < 1 { + if c.NArg() < 1 { if err := cli.ShowSubcommandHelp(c); err != nil { fmt.Printf("error showing subcommand help: %v\n", err) } return nil } - keys := strings.Split(c.Args()[0], "-") + keys := strings.Split(c.Args().First(), "-") if len(keys) != 2 || keys[0] != "key" { - return fail(ctx, "Key ID format error", "Invalid key argument: %s", c.Args()[0]) + return fail(ctx, "Key ID format error", "Invalid key argument: %s", c.Args().First()) } keyID, err := strconv.ParseInt(keys[1], 10, 64) if err != nil { - return fail(ctx, "Key ID parsing error", "Invalid key argument: %s", c.Args()[1]) + return fail(ctx, "Key ID parsing error", "Invalid key argument: %s", c.Args().Get(1)) } cmd := os.Getenv("SSH_ORIGINAL_COMMAND") diff --git a/cmd/web.go b/cmd/web.go index 05f3b2ddb..d9aafb1fa 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -23,14 +23,14 @@ import ( "code.gitea.io/gitea/routers/install" "github.com/felixge/fgprof" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) // PIDFile could be set from build tag var PIDFile = "/run/gitea.pid" // CmdWeb represents the available web sub-command. -var CmdWeb = cli.Command{ +var CmdWeb = &cli.Command{ Name: "web", Usage: "Start Gitea web server", Description: `Gitea web server is the only thing you need to run, @@ -38,26 +38,29 @@ and it takes care of all the other things for you`, Before: PrepareConsoleLoggerLevel(log.INFO), Action: runWeb, Flags: []cli.Flag{ - cli.StringFlag{ - Name: "port, p", - Value: "3000", - Usage: "Temporary port number to prevent conflict", + &cli.StringFlag{ + Name: "port", + Aliases: []string{"p"}, + Value: "3000", + Usage: "Temporary port number to prevent conflict", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "install-port", Value: "3000", Usage: "Temporary port number to run the install page on to prevent conflict", }, - cli.StringFlag{ - Name: "pid, P", - Value: PIDFile, - Usage: "Custom pid file path", + &cli.StringFlag{ + Name: "pid", + Aliases: []string{"P"}, + Value: PIDFile, + Usage: "Custom pid file path", }, - cli.BoolFlag{ - Name: "quiet, q", - Usage: "Only display Fatal logging errors until logging is set-up", + &cli.BoolFlag{ + Name: "quiet", + Aliases: []string{"q"}, + Usage: "Only display Fatal logging errors until logging is set-up", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "verbose", Usage: "Set initial logging to TRACE level until logging is properly set-up", }, diff --git a/contrib/backport/backport.go b/contrib/backport/backport.go index 9455d073c..5cd0fe0f6 100644 --- a/contrib/backport/backport.go +++ b/contrib/backport/backport.go @@ -18,7 +18,7 @@ import ( "syscall" "github.com/google/go-github/v53/github" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" "gopkg.in/yaml.v3" ) @@ -32,55 +32,55 @@ func main() { app.ArgsUsage = "" app.Flags = []cli.Flag{ - cli.StringFlag{ + &cli.StringFlag{ Name: "version", Usage: "Version branch to backport on to", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "upstream", Value: "origin", Usage: "Upstream remote for the Gitea upstream", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "release-branch", Value: "", Usage: "Release branch to backport on. Will default to release/", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "cherry-pick", Usage: "SHA to cherry-pick as backport", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "backport-branch", Usage: "Backport branch to backport on to (default: backport--", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "remote", Value: "", Usage: "Remote for your fork of the Gitea upstream", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "fork-user", Value: "", Usage: "Forked user name on Github", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "no-fetch", Usage: "Set this flag to prevent fetch of remote branches", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "no-amend-message", Usage: "Set this flag to prevent automatic amendment of the commit message", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "no-push", Usage: "Set this flag to prevent pushing the backport up to your fork", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "no-xdg-open", Usage: "Set this flag to not use xdg-open to open the PR URL", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "continue", Usage: "Set this flag to continue from a git cherry-pick that has broken", }, @@ -151,7 +151,7 @@ func runBackport(c *cli.Context) error { localReleaseBranch := path.Join(upstream, upstreamReleaseBranch) - args := c.Args() + args := c.Args().Slice() if len(args) == 0 && pr == "" { return fmt.Errorf("no PR number provided\nProvide a PR number to backport") } else if len(args) != 1 && pr == "" { diff --git a/contrib/environment-to-ini/environment-to-ini.go b/contrib/environment-to-ini/environment-to-ini.go index fb5fb7bda..7758045fd 100644 --- a/contrib/environment-to-ini/environment-to-ini.go +++ b/contrib/environment-to-ini/environment-to-ini.go @@ -9,7 +9,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) func main() { @@ -46,22 +46,22 @@ func main() { and "GITEA__LOG_0x2E_CONSOLE__STDERR=false". Other examples can be found on the configuration cheat sheet.` app.Flags = []cli.Flag{ - cli.StringFlag{ + &cli.StringFlag{ Name: "custom-path, C", Value: setting.CustomPath, Usage: "Custom path file path", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "config, c", Value: setting.CustomConf, Usage: "Custom configuration file path", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "work-path, w", Value: setting.AppWorkPath, Usage: "Set the gitea working path", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "out, o", Value: "", Usage: "Destination file to write to", diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 36ea7f3d9..db148c52a 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -12,7 +12,7 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; These values are environment-dependent but form the basis of a lot of values. They will be -;; reported as part of the default configuration when running `gitea --help` or on start-up. The order they are emitted there is slightly different but we will list them here in the order they are set-up. +;; reported as part of the default configuration when running `gitea help` or on start-up. The order they are emitted there is slightly different but we will list them here in the order they are set-up. ;; ;; - _`AppPath`_: This is the absolute path of the running gitea binary. ;; - _`AppWorkPath`_: This refers to "working path" of the `gitea` binary. It is determined by using the first set thing in the following hierarchy: diff --git a/docs/content/doc/administration/config-cheat-sheet.en-us.md b/docs/content/doc/administration/config-cheat-sheet.en-us.md index a78eff252..fc2184e88 100644 --- a/docs/content/doc/administration/config-cheat-sheet.en-us.md +++ b/docs/content/doc/administration/config-cheat-sheet.en-us.md @@ -40,7 +40,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. ## Default Configuration (non-`app.ini` configuration) These values are environment-dependent but form the basis of a lot of values. They will be -reported as part of the default configuration when running `gitea --help` or on start-up. The order they are emitted there is slightly different but we will list them here in the order they are set-up. +reported as part of the default configuration when running `gitea help` or on start-up. The order they are emitted there is slightly different but we will list them here in the order they are set-up. - _`AppPath`_: This is the absolute path of the running gitea binary. - _`AppWorkPath`_: This refers to "working path" of the `gitea` binary. It is determined by using the first set thing in the following hierarchy: diff --git a/go.mod b/go.mod index 9478ebee2..29a17b16a 100644 --- a/go.mod +++ b/go.mod @@ -98,7 +98,7 @@ require ( github.com/syndtr/goleveldb v1.0.0 github.com/tstranex/u2f v1.0.0 github.com/ulikunitz/xz v0.5.11 - github.com/urfave/cli v1.22.14 + github.com/urfave/cli/v2 v2.25.7 github.com/xanzy/go-gitlab v0.86.0 github.com/xeipuuv/gojsonschema v1.2.0 github.com/yohcop/openid-go v1.0.1 @@ -278,6 +278,7 @@ require ( github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect + github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/zeebo/blake3 v0.2.3 // indirect go.etcd.io/bbolt v1.3.7 // indirect go.mongodb.org/mongo-driver v1.12.0 // indirect diff --git a/go.sum b/go.sum index c438ea732..9c6250c10 100644 --- a/go.sum +++ b/go.sum @@ -80,7 +80,6 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2 github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/ClickHouse/ch-go v0.57.0 h1:X/QmUmFhpUvLgPSQb7fWOSi1wvqGn6tJ7w2a59c4xsg= github.com/ClickHouse/ch-go v0.57.0/go.mod h1:DR3iBn7OrrDj+KeUp1LbdxLEUDbW+5Qwdl/qkc+PQ+Y= @@ -1162,8 +1161,8 @@ github.com/unknwon/com v1.0.1 h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs= github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli v1.22.14 h1:ebbhrRiGK2i4naQJr+1Xj92HXZCrK7MsyTS/ob3HnAk= -github.com/urfave/cli v1.22.14/go.mod h1:X0eDS6pD6Exaclxm99NJ3FiCDRED7vIHpx2mDOHLvkA= +github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= +github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.37.1-0.20220607072126-8a320890c08d/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= @@ -1198,6 +1197,8 @@ github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofm github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yohcop/openid-go v1.0.1 h1:DPRd3iPO5F6O5zX2e62XpVAbPT6wV51cuucH0z9g3js= github.com/yohcop/openid-go v1.0.1/go.mod h1:b/AvD03P0KHj4yuihb+VtLD6bYYgsy0zqBzPCRjkCNs= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= diff --git a/main.go b/main.go index 9b561376c..652a71195 100644 --- a/main.go +++ b/main.go @@ -2,8 +2,7 @@ // Copyright 2016 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -// Gitea (git with a cup of tea) is a painless self-hosted Git Service. -package main // import "code.gitea.io/gitea" +package main import ( "fmt" @@ -22,17 +21,13 @@ import ( _ "code.gitea.io/gitea/modules/markup/csv" _ "code.gitea.io/gitea/modules/markup/markdown" _ "code.gitea.io/gitea/modules/markup/orgmode" - - "github.com/urfave/cli" ) +// these flags will be set by the build flags var ( - // Version holds the current Gitea version - Version = "development" - // Tags holds the build tags used - Tags = "" - // MakeVersion holds the current Make version if built with make - MakeVersion = "" + Version = "development" // program version for this build + Tags = "" // the Golang build tags + MakeVersion = "" // "make" program version if built with make ) func init() { @@ -41,110 +36,12 @@ func init() { setting.AppStartTime = time.Now().UTC() } -// cmdHelp is our own help subcommand with more information -// test cases: -// ./gitea help -// ./gitea -h -// ./gitea web help -// ./gitea web -h (due to cli lib limitation, this won't call our cmdHelp, so no extra info) -// ./gitea admin -// ./gitea admin help -// ./gitea admin auth help -// ./gitea -c /tmp/app.ini -h -// ./gitea -c /tmp/app.ini help -// ./gitea help -c /tmp/app.ini -// GITEA_WORK_DIR=/tmp ./gitea help -// GITEA_WORK_DIR=/tmp ./gitea help --work-path /tmp/other -// GITEA_WORK_DIR=/tmp ./gitea help --config /tmp/app-other.ini -var cmdHelp = cli.Command{ - Name: "help", - Aliases: []string{"h"}, - Usage: "Shows a list of commands or help for one command", - ArgsUsage: "[command]", - Action: func(c *cli.Context) (err error) { - args := c.Args() - if args.Present() { - err = cli.ShowCommandHelp(c, args.First()) - } else { - err = cli.ShowAppHelp(c) - } - _, _ = fmt.Fprintf(c.App.Writer, ` -DEFAULT CONFIGURATION: - AppPath: %s - WorkPath: %s - CustomPath: %s - ConfigFile: %s - -`, setting.AppPath, setting.AppWorkPath, setting.CustomPath, setting.CustomConf) - return err - }, -} - func main() { - app := cli.NewApp() + app := cmd.NewMainApp() app.Name = "Gitea" app.Usage = "A painless self-hosted Git service" app.Description = `By default, Gitea will start serving using the web-server with no argument, which can alternatively be run by running the subcommand "web".` app.Version = Version + formatBuiltWith() - app.EnableBashCompletion = true - - // these sub-commands need to use config file - subCmdWithIni := []cli.Command{ - cmd.CmdWeb, - cmd.CmdServ, - cmd.CmdHook, - cmd.CmdDump, - cmd.CmdAdmin, - cmd.CmdMigrate, - cmd.CmdKeys, - cmd.CmdConvert, - cmd.CmdDoctor, - cmd.CmdManager, - cmd.CmdEmbedded, - cmd.CmdMigrateStorage, - cmd.CmdDumpRepository, - cmd.CmdRestoreRepository, - cmd.CmdActions, - cmdHelp, // TODO: the "help" sub-command was used to show the more information for "work path" and "custom config", in the future, it should avoid doing so - } - // these sub-commands do not need the config file, and they do not depend on any path or environment variable. - subCmdStandalone := []cli.Command{ - cmd.CmdCert, - cmd.CmdGenerate, - cmd.CmdDocs, - } - - // shared configuration flags, they are for global and for each sub-command at the same time - // eg: such command is valid: "./gitea --config /tmp/app.ini web --config /tmp/app.ini", while it's discouraged indeed - // keep in mind that the short flags like "-C", "-c" and "-w" are globally polluted, they can't be used for sub-commands anymore. - globalFlags := []cli.Flag{ - cli.HelpFlag, - cli.StringFlag{ - Name: "custom-path, C", - Usage: "Set custom path (defaults to '{WorkPath}/custom')", - }, - cli.StringFlag{ - Name: "config, c", - Value: setting.CustomConf, - Usage: "Set custom config file (defaults to '{WorkPath}/custom/conf/app.ini')", - }, - cli.StringFlag{ - Name: "work-path, w", - Usage: "Set Gitea's working path (defaults to the Gitea's binary directory)", - }, - } - - // Set the default to be equivalent to cmdWeb and add the default flags - app.Flags = append(app.Flags, globalFlags...) - app.Flags = append(app.Flags, cmd.CmdWeb.Flags...) // TODO: the web flags polluted the global flags, they are not really global flags - app.Action = prepareWorkPathAndCustomConf(cmd.CmdWeb.Action) - app.HideHelp = true // use our own help action to show helps (with more information like default config) - app.Before = cmd.PrepareConsoleLoggerLevel(log.INFO) - for i := range subCmdWithIni { - prepareSubcommands(&subCmdWithIni[i], globalFlags) - } - app.Commands = append(app.Commands, subCmdWithIni...) - app.Commands = append(app.Commands, subCmdStandalone...) err := app.Run(os.Args) if err != nil { @@ -154,45 +51,6 @@ func main() { log.GetManager().Close() } -func prepareSubcommands(command *cli.Command, defaultFlags []cli.Flag) { - command.Flags = append(command.Flags, defaultFlags...) - command.Action = prepareWorkPathAndCustomConf(command.Action) - command.HideHelp = true - if command.Name != "help" { - command.Subcommands = append(command.Subcommands, cmdHelp) - } - for i := range command.Subcommands { - prepareSubcommands(&command.Subcommands[i], defaultFlags) - } -} - -// prepareWorkPathAndCustomConf wraps the Action to prepare the work path and custom config -// It can't use "Before", because each level's sub-command's Before will be called one by one, so the "init" would be done multiple times -func prepareWorkPathAndCustomConf(action any) func(ctx *cli.Context) error { - return func(ctx *cli.Context) error { - var args setting.ArgWorkPathAndCustomConf - curCtx := ctx - for curCtx != nil { - if curCtx.IsSet("work-path") && args.WorkPath == "" { - args.WorkPath = curCtx.String("work-path") - } - if curCtx.IsSet("custom-path") && args.CustomPath == "" { - args.CustomPath = curCtx.String("custom-path") - } - if curCtx.IsSet("config") && args.CustomConf == "" { - args.CustomConf = curCtx.String("config") - } - curCtx = curCtx.Parent() - } - setting.InitWorkPathAndCommonConfig(os.Getenv, args) - if ctx.Bool("help") || action == nil { - // the default behavior of "urfave/cli": "nil action" means "show help" - return cmdHelp.Action.(func(ctx *cli.Context) error)(ctx) - } - return action.(func(*cli.Context) error)(ctx) - } -} - func formatBuiltWith() string { version := runtime.Version() if len(MakeVersion) > 0 { diff --git a/tests/integration/cmd_keys_test.go b/tests/integration/cmd_keys_test.go index ccde04891..61f11c58b 100644 --- a/tests/integration/cmd_keys_test.go +++ b/tests/integration/cmd_keys_test.go @@ -5,17 +5,15 @@ package integration import ( "bytes" - "flag" - "io" "net/url" - "os" "testing" "code.gitea.io/gitea/cmd" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" - "github.com/urfave/cli" + "github.com/stretchr/testify/assert" + "github.com/urfave/cli/v2" ) func Test_CmdKeys(t *testing.T) { @@ -38,26 +36,18 @@ func Test_CmdKeys(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - realStdout := os.Stdout // Backup Stdout - r, w, _ := os.Pipe() - os.Stdout = w - - set := flag.NewFlagSet("keys", 0) - _ = set.Parse(tt.args) - context := cli.NewContext(&cli.App{Writer: os.Stdout}, set, nil) - err := cmd.CmdKeys.Run(context) - if (err != nil) != tt.wantErr { - t.Errorf("CmdKeys.Run() error = %v, wantErr %v", err, tt.wantErr) + out := new(bytes.Buffer) + app := cli.NewApp() + app.Writer = out + app.Commands = []*cli.Command{cmd.CmdKeys} + cmd.CmdKeys.HideHelp = true + err := app.Run(append([]string{"prog"}, tt.args...)) + if tt.wantErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) } - w.Close() - var buf bytes.Buffer - io.Copy(&buf, r) - commandOutput := buf.String() - if tt.expectedOutput != commandOutput { - t.Errorf("expectedOutput: %#v, commandOutput: %#v", tt.expectedOutput, commandOutput) - } - // Restore stdout - os.Stdout = realStdout + assert.Equal(t, tt.expectedOutput, out.String()) }) } })