mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-26 12:27:06 +00:00 
			
		
		
		
	Refactor to use urfave/cli/v2 (#25959)
Replace #10912 And there are many new tests to cover the CLI behavior There were some concerns about the "option order in hook scripts" (https://github.com/go-gitea/gitea/pull/10912#issuecomment-1137543314), it's not a problem now. Because the hook script uses `/gitea hook --config=/app.ini pre-receive` format. The "config" is a global option, it can appear anywhere. ---- ## ⚠️ BREAKING ⚠️ This PR does it best to avoid breaking anything. The major changes are: * `gitea` itself won't accept web's options: `--install-port` / `--pid` / `--port` / `--quiet` / `--verbose` .... They are `web` sub-command's options. * Use `./gitea web --pid ....` instead * `./gitea` can still run the `web` sub-command as shorthand, with default options * The sub-command's options must follow the sub-command * Before: `./gitea --sub-opt subcmd` might equal to `./gitea subcmd --sub-opt` (well, might not ...) * After: only `./gitea subcmd --sub-opt` could be used * The global options like `--config` are not affected
This commit is contained in:
		
							
								
								
									
										11
									
								
								assets/go-licenses.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										11
									
								
								assets/go-licenses.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -9,28 +9,29 @@ import ( | |||||||
| 	"code.gitea.io/gitea/modules/private" | 	"code.gitea.io/gitea/modules/private" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
|  |  | ||||||
| 	"github.com/urfave/cli" | 	"github.com/urfave/cli/v2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var ( | var ( | ||||||
| 	// CmdActions represents the available actions sub-commands. | 	// CmdActions represents the available actions sub-commands. | ||||||
| 	CmdActions = cli.Command{ | 	CmdActions = &cli.Command{ | ||||||
| 		Name:        "actions", | 		Name:        "actions", | ||||||
| 		Usage:       "", | 		Usage:       "", | ||||||
| 		Description: "Commands for managing Gitea Actions", | 		Description: "Commands for managing Gitea Actions", | ||||||
| 		Subcommands: []cli.Command{ | 		Subcommands: []*cli.Command{ | ||||||
| 			subcmdActionsGenRunnerToken, | 			subcmdActionsGenRunnerToken, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	subcmdActionsGenRunnerToken = cli.Command{ | 	subcmdActionsGenRunnerToken = &cli.Command{ | ||||||
| 		Name:    "generate-runner-token", | 		Name:    "generate-runner-token", | ||||||
| 		Usage:   "Generate a new token for a runner to use to register with the server", | 		Usage:   "Generate a new token for a runner to use to register with the server", | ||||||
| 		Action:  runGenerateActionsRunnerToken, | 		Action:  runGenerateActionsRunnerToken, | ||||||
| 		Aliases: []string{"grt"}, | 		Aliases: []string{"grt"}, | ||||||
| 		Flags: []cli.Flag{ | 		Flags: []cli.Flag{ | ||||||
| 			cli.StringFlag{ | 			&cli.StringFlag{ | ||||||
| 				Name:  "scope, s", | 				Name:    "scope", | ||||||
|  | 				Aliases: []string{"s"}, | ||||||
| 				Value:   "", | 				Value:   "", | ||||||
| 				Usage:   "{owner}[/{repo}] - leave empty for a global runner", | 				Usage:   "{owner}[/{repo}] - leave empty for a global runner", | ||||||
| 			}, | 			}, | ||||||
|   | |||||||
							
								
								
									
										131
									
								
								cmd/admin.go
									
									
									
									
									
								
							
							
						
						
									
										131
									
								
								cmd/admin.go
									
									
									
									
									
								
							| @@ -26,15 +26,15 @@ import ( | |||||||
| 	"code.gitea.io/gitea/services/auth/source/smtp" | 	"code.gitea.io/gitea/services/auth/source/smtp" | ||||||
| 	repo_service "code.gitea.io/gitea/services/repository" | 	repo_service "code.gitea.io/gitea/services/repository" | ||||||
|  |  | ||||||
| 	"github.com/urfave/cli" | 	"github.com/urfave/cli/v2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var ( | var ( | ||||||
| 	// CmdAdmin represents the available admin sub-command. | 	// CmdAdmin represents the available admin sub-command. | ||||||
| 	CmdAdmin = cli.Command{ | 	CmdAdmin = &cli.Command{ | ||||||
| 		Name:  "admin", | 		Name:  "admin", | ||||||
| 		Usage: "Command line interface to perform common administrative operations", | 		Usage: "Command line interface to perform common administrative operations", | ||||||
| 		Subcommands: []cli.Command{ | 		Subcommands: []*cli.Command{ | ||||||
| 			subcmdUser, | 			subcmdUser, | ||||||
| 			subcmdRepoSyncReleases, | 			subcmdRepoSyncReleases, | ||||||
| 			subcmdRegenerate, | 			subcmdRegenerate, | ||||||
| @@ -43,37 +43,37 @@ var ( | |||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	subcmdRepoSyncReleases = cli.Command{ | 	subcmdRepoSyncReleases = &cli.Command{ | ||||||
| 		Name:   "repo-sync-releases", | 		Name:   "repo-sync-releases", | ||||||
| 		Usage:  "Synchronize repository releases with tags", | 		Usage:  "Synchronize repository releases with tags", | ||||||
| 		Action: runRepoSyncReleases, | 		Action: runRepoSyncReleases, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	subcmdRegenerate = cli.Command{ | 	subcmdRegenerate = &cli.Command{ | ||||||
| 		Name:  "regenerate", | 		Name:  "regenerate", | ||||||
| 		Usage: "Regenerate specific files", | 		Usage: "Regenerate specific files", | ||||||
| 		Subcommands: []cli.Command{ | 		Subcommands: []*cli.Command{ | ||||||
| 			microcmdRegenHooks, | 			microcmdRegenHooks, | ||||||
| 			microcmdRegenKeys, | 			microcmdRegenKeys, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	microcmdRegenHooks = cli.Command{ | 	microcmdRegenHooks = &cli.Command{ | ||||||
| 		Name:   "hooks", | 		Name:   "hooks", | ||||||
| 		Usage:  "Regenerate git-hooks", | 		Usage:  "Regenerate git-hooks", | ||||||
| 		Action: runRegenerateHooks, | 		Action: runRegenerateHooks, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	microcmdRegenKeys = cli.Command{ | 	microcmdRegenKeys = &cli.Command{ | ||||||
| 		Name:   "keys", | 		Name:   "keys", | ||||||
| 		Usage:  "Regenerate authorized_keys file", | 		Usage:  "Regenerate authorized_keys file", | ||||||
| 		Action: runRegenerateKeys, | 		Action: runRegenerateKeys, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	subcmdAuth = cli.Command{ | 	subcmdAuth = &cli.Command{ | ||||||
| 		Name:  "auth", | 		Name:  "auth", | ||||||
| 		Usage: "Modify external auth providers", | 		Usage: "Modify external auth providers", | ||||||
| 		Subcommands: []cli.Command{ | 		Subcommands: []*cli.Command{ | ||||||
| 			microcmdAuthAddOauth, | 			microcmdAuthAddOauth, | ||||||
| 			microcmdAuthUpdateOauth, | 			microcmdAuthUpdateOauth, | ||||||
| 			cmdAuthAddLdapBindDn, | 			cmdAuthAddLdapBindDn, | ||||||
| @@ -87,44 +87,44 @@ var ( | |||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	microcmdAuthList = cli.Command{ | 	microcmdAuthList = &cli.Command{ | ||||||
| 		Name:   "list", | 		Name:   "list", | ||||||
| 		Usage:  "List auth sources", | 		Usage:  "List auth sources", | ||||||
| 		Action: runListAuth, | 		Action: runListAuth, | ||||||
| 		Flags: []cli.Flag{ | 		Flags: []cli.Flag{ | ||||||
| 			cli.IntFlag{ | 			&cli.IntFlag{ | ||||||
| 				Name:  "min-width", | 				Name:  "min-width", | ||||||
| 				Usage: "Minimal cell width including any padding for the formatted table", | 				Usage: "Minimal cell width including any padding for the formatted table", | ||||||
| 				Value: 0, | 				Value: 0, | ||||||
| 			}, | 			}, | ||||||
| 			cli.IntFlag{ | 			&cli.IntFlag{ | ||||||
| 				Name:  "tab-width", | 				Name:  "tab-width", | ||||||
| 				Usage: "width of tab characters in formatted table (equivalent number of spaces)", | 				Usage: "width of tab characters in formatted table (equivalent number of spaces)", | ||||||
| 				Value: 8, | 				Value: 8, | ||||||
| 			}, | 			}, | ||||||
| 			cli.IntFlag{ | 			&cli.IntFlag{ | ||||||
| 				Name:  "padding", | 				Name:  "padding", | ||||||
| 				Usage: "padding added to a cell before computing its width", | 				Usage: "padding added to a cell before computing its width", | ||||||
| 				Value: 1, | 				Value: 1, | ||||||
| 			}, | 			}, | ||||||
| 			cli.StringFlag{ | 			&cli.StringFlag{ | ||||||
| 				Name:  "pad-char", | 				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)`, | 				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", | 				Value: "\t", | ||||||
| 			}, | 			}, | ||||||
| 			cli.BoolFlag{ | 			&cli.BoolFlag{ | ||||||
| 				Name:  "vertical-bars", | 				Name:  "vertical-bars", | ||||||
| 				Usage: "Set to true to print vertical bars between columns", | 				Usage: "Set to true to print vertical bars between columns", | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	idFlag = cli.Int64Flag{ | 	idFlag = &cli.Int64Flag{ | ||||||
| 		Name:  "id", | 		Name:  "id", | ||||||
| 		Usage: "ID of authentication source", | 		Usage: "ID of authentication source", | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	microcmdAuthDelete = cli.Command{ | 	microcmdAuthDelete = &cli.Command{ | ||||||
| 		Name:   "delete", | 		Name:   "delete", | ||||||
| 		Usage:  "Delete specific auth source", | 		Usage:  "Delete specific auth source", | ||||||
| 		Flags:  []cli.Flag{idFlag}, | 		Flags:  []cli.Flag{idFlag}, | ||||||
| @@ -132,207 +132,208 @@ var ( | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	oauthCLIFlags = []cli.Flag{ | 	oauthCLIFlags = []cli.Flag{ | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "name", | 			Name:  "name", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Application Name", | 			Usage: "Application Name", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "provider", | 			Name:  "provider", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "OAuth2 Provider", | 			Usage: "OAuth2 Provider", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "key", | 			Name:  "key", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Client ID (Key)", | 			Usage: "Client ID (Key)", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "secret", | 			Name:  "secret", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Client Secret", | 			Usage: "Client Secret", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "auto-discover-url", | 			Name:  "auto-discover-url", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "OpenID Connect Auto Discovery URL (only required when using OpenID Connect as provider)", | 			Usage: "OpenID Connect Auto Discovery URL (only required when using OpenID Connect as provider)", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "use-custom-urls", | 			Name:  "use-custom-urls", | ||||||
| 			Value: "false", | 			Value: "false", | ||||||
| 			Usage: "Use custom URLs for GitLab/GitHub OAuth endpoints", | 			Usage: "Use custom URLs for GitLab/GitHub OAuth endpoints", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "custom-tenant-id", | 			Name:  "custom-tenant-id", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Use custom Tenant ID for OAuth endpoints", | 			Usage: "Use custom Tenant ID for OAuth endpoints", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "custom-auth-url", | 			Name:  "custom-auth-url", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Use a custom Authorization URL (option for GitLab/GitHub)", | 			Usage: "Use a custom Authorization URL (option for GitLab/GitHub)", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "custom-token-url", | 			Name:  "custom-token-url", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Use a custom Token URL (option for GitLab/GitHub)", | 			Usage: "Use a custom Token URL (option for GitLab/GitHub)", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "custom-profile-url", | 			Name:  "custom-profile-url", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Use a custom Profile URL (option for GitLab/GitHub)", | 			Usage: "Use a custom Profile URL (option for GitLab/GitHub)", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "custom-email-url", | 			Name:  "custom-email-url", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Use a custom Email URL (option for GitHub)", | 			Usage: "Use a custom Email URL (option for GitHub)", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "icon-url", | 			Name:  "icon-url", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Custom icon URL for OAuth2 login source", | 			Usage: "Custom icon URL for OAuth2 login source", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "skip-local-2fa", | 			Name:  "skip-local-2fa", | ||||||
| 			Usage: "Set to true to skip local 2fa for users authenticated by this source", | 			Usage: "Set to true to skip local 2fa for users authenticated by this source", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringSliceFlag{ | 		&cli.StringSliceFlag{ | ||||||
| 			Name:  "scopes", | 			Name:  "scopes", | ||||||
| 			Value: nil, | 			Value: nil, | ||||||
| 			Usage: "Scopes to request when to authenticate against this OAuth2 source", | 			Usage: "Scopes to request when to authenticate against this OAuth2 source", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "required-claim-name", | 			Name:  "required-claim-name", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Claim name that has to be set to allow users to login with this source", | 			Usage: "Claim name that has to be set to allow users to login with this source", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "required-claim-value", | 			Name:  "required-claim-value", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Claim value that has to be set to allow users to login with this source", | 			Usage: "Claim value that has to be set to allow users to login with this source", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "group-claim-name", | 			Name:  "group-claim-name", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Claim name providing group names for this source", | 			Usage: "Claim name providing group names for this source", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "admin-group", | 			Name:  "admin-group", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Group Claim value for administrator users", | 			Usage: "Group Claim value for administrator users", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "restricted-group", | 			Name:  "restricted-group", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Group Claim value for restricted users", | 			Usage: "Group Claim value for restricted users", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "group-team-map", | 			Name:  "group-team-map", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "JSON mapping between groups and org teams", | 			Usage: "JSON mapping between groups and org teams", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "group-team-map-removal", | 			Name:  "group-team-map-removal", | ||||||
| 			Usage: "Activate automatic team membership removal depending on groups", | 			Usage: "Activate automatic team membership removal depending on groups", | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	microcmdAuthUpdateOauth = cli.Command{ | 	microcmdAuthUpdateOauth = &cli.Command{ | ||||||
| 		Name:   "update-oauth", | 		Name:   "update-oauth", | ||||||
| 		Usage:  "Update existing Oauth authentication source", | 		Usage:  "Update existing Oauth authentication source", | ||||||
| 		Action: runUpdateOauth, | 		Action: runUpdateOauth, | ||||||
| 		Flags:  append(oauthCLIFlags[:1], append([]cli.Flag{idFlag}, oauthCLIFlags[1:]...)...), | 		Flags:  append(oauthCLIFlags[:1], append([]cli.Flag{idFlag}, oauthCLIFlags[1:]...)...), | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	microcmdAuthAddOauth = cli.Command{ | 	microcmdAuthAddOauth = &cli.Command{ | ||||||
| 		Name:   "add-oauth", | 		Name:   "add-oauth", | ||||||
| 		Usage:  "Add new Oauth authentication source", | 		Usage:  "Add new Oauth authentication source", | ||||||
| 		Action: runAddOauth, | 		Action: runAddOauth, | ||||||
| 		Flags:  oauthCLIFlags, | 		Flags:  oauthCLIFlags, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	subcmdSendMail = cli.Command{ | 	subcmdSendMail = &cli.Command{ | ||||||
| 		Name:   "sendmail", | 		Name:   "sendmail", | ||||||
| 		Usage:  "Send a message to all users", | 		Usage:  "Send a message to all users", | ||||||
| 		Action: runSendMail, | 		Action: runSendMail, | ||||||
| 		Flags: []cli.Flag{ | 		Flags: []cli.Flag{ | ||||||
| 			cli.StringFlag{ | 			&cli.StringFlag{ | ||||||
| 				Name:  "title", | 				Name:  "title", | ||||||
| 				Usage: `a title of a message`, | 				Usage: `a title of a message`, | ||||||
| 				Value: "", | 				Value: "", | ||||||
| 			}, | 			}, | ||||||
| 			cli.StringFlag{ | 			&cli.StringFlag{ | ||||||
| 				Name:  "content", | 				Name:  "content", | ||||||
| 				Usage: "a content of a message", | 				Usage: "a content of a message", | ||||||
| 				Value: "", | 				Value: "", | ||||||
| 			}, | 			}, | ||||||
| 			cli.BoolFlag{ | 			&cli.BoolFlag{ | ||||||
| 				Name:  "force,f", | 				Name:    "force", | ||||||
|  | 				Aliases: []string{"f"}, | ||||||
| 				Usage:   "A flag to bypass a confirmation step", | 				Usage:   "A flag to bypass a confirmation step", | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	smtpCLIFlags = []cli.Flag{ | 	smtpCLIFlags = []cli.Flag{ | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "name", | 			Name:  "name", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Application Name", | 			Usage: "Application Name", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "auth-type", | 			Name:  "auth-type", | ||||||
| 			Value: "PLAIN", | 			Value: "PLAIN", | ||||||
| 			Usage: "SMTP Authentication Type (PLAIN/LOGIN/CRAM-MD5) default PLAIN", | 			Usage: "SMTP Authentication Type (PLAIN/LOGIN/CRAM-MD5) default PLAIN", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "host", | 			Name:  "host", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "SMTP Host", | 			Usage: "SMTP Host", | ||||||
| 		}, | 		}, | ||||||
| 		cli.IntFlag{ | 		&cli.IntFlag{ | ||||||
| 			Name:  "port", | 			Name:  "port", | ||||||
| 			Usage: "SMTP Port", | 			Usage: "SMTP Port", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolTFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "force-smtps", | 			Name:  "force-smtps", | ||||||
| 			Usage: "SMTPS is always used on port 465. Set this to force SMTPS on other ports.", | 			Usage: "SMTPS is always used on port 465. Set this to force SMTPS on other ports.", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolTFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "skip-verify", | 			Name:  "skip-verify", | ||||||
| 			Usage: "Skip TLS verify.", | 			Usage: "Skip TLS verify.", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "helo-hostname", | 			Name:  "helo-hostname", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Hostname sent with HELO. Leave blank to send current hostname", | 			Usage: "Hostname sent with HELO. Leave blank to send current hostname", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolTFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "disable-helo", | 			Name:  "disable-helo", | ||||||
| 			Usage: "Disable SMTP helo.", | 			Usage: "Disable SMTP helo.", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "allowed-domains", | 			Name:  "allowed-domains", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Leave empty to allow all domains. Separate multiple domains with a comma (',')", | 			Usage: "Leave empty to allow all domains. Separate multiple domains with a comma (',')", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolTFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "skip-local-2fa", | 			Name:  "skip-local-2fa", | ||||||
| 			Usage: "Skip 2FA to log on.", | 			Usage: "Skip 2FA to log on.", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolTFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "active", | 			Name:  "active", | ||||||
| 			Usage: "This Authentication Source is Activated.", | 			Usage: "This Authentication Source is Activated.", | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	microcmdAuthAddSMTP = cli.Command{ | 	microcmdAuthAddSMTP = &cli.Command{ | ||||||
| 		Name:   "add-smtp", | 		Name:   "add-smtp", | ||||||
| 		Usage:  "Add new SMTP authentication source", | 		Usage:  "Add new SMTP authentication source", | ||||||
| 		Action: runAddSMTP, | 		Action: runAddSMTP, | ||||||
| 		Flags:  smtpCLIFlags, | 		Flags:  smtpCLIFlags, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	microcmdAuthUpdateSMTP = cli.Command{ | 	microcmdAuthUpdateSMTP = &cli.Command{ | ||||||
| 		Name:   "update-smtp", | 		Name:   "update-smtp", | ||||||
| 		Usage:  "Update existing SMTP authentication source", | 		Usage:  "Update existing SMTP authentication source", | ||||||
| 		Action: runUpdateSMTP, | 		Action: runUpdateSMTP, | ||||||
| @@ -611,19 +612,19 @@ func parseSMTPConfig(c *cli.Context, conf *smtp.Source) error { | |||||||
| 		conf.AllowedDomains = c.String("allowed-domains") | 		conf.AllowedDomains = c.String("allowed-domains") | ||||||
| 	} | 	} | ||||||
| 	if c.IsSet("force-smtps") { | 	if c.IsSet("force-smtps") { | ||||||
| 		conf.ForceSMTPS = c.BoolT("force-smtps") | 		conf.ForceSMTPS = c.Bool("force-smtps") | ||||||
| 	} | 	} | ||||||
| 	if c.IsSet("skip-verify") { | 	if c.IsSet("skip-verify") { | ||||||
| 		conf.SkipVerify = c.BoolT("skip-verify") | 		conf.SkipVerify = c.Bool("skip-verify") | ||||||
| 	} | 	} | ||||||
| 	if c.IsSet("helo-hostname") { | 	if c.IsSet("helo-hostname") { | ||||||
| 		conf.HeloHostname = c.String("helo-hostname") | 		conf.HeloHostname = c.String("helo-hostname") | ||||||
| 	} | 	} | ||||||
| 	if c.IsSet("disable-helo") { | 	if c.IsSet("disable-helo") { | ||||||
| 		conf.DisableHelo = c.BoolT("disable-helo") | 		conf.DisableHelo = c.Bool("disable-helo") | ||||||
| 	} | 	} | ||||||
| 	if c.IsSet("skip-local-2fa") { | 	if c.IsSet("skip-local-2fa") { | ||||||
| 		conf.SkipLocalTwoFA = c.BoolT("skip-local-2fa") | 		conf.SkipLocalTwoFA = c.Bool("skip-local-2fa") | ||||||
| 	} | 	} | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| @@ -647,7 +648,7 @@ func runAddSMTP(c *cli.Context) error { | |||||||
| 	} | 	} | ||||||
| 	active := true | 	active := true | ||||||
| 	if c.IsSet("active") { | 	if c.IsSet("active") { | ||||||
| 		active = c.BoolT("active") | 		active = c.Bool("active") | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	var smtpConfig smtp.Source | 	var smtpConfig smtp.Source | ||||||
| @@ -696,7 +697,7 @@ func runUpdateSMTP(c *cli.Context) error { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if c.IsSet("active") { | 	if c.IsSet("active") { | ||||||
| 		source.IsActive = c.BoolT("active") | 		source.IsActive = c.Bool("active") | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	source.Cfg = smtpConfig | 	source.Cfg = smtpConfig | ||||||
|   | |||||||
| @@ -11,7 +11,7 @@ import ( | |||||||
| 	"code.gitea.io/gitea/models/auth" | 	"code.gitea.io/gitea/models/auth" | ||||||
| 	"code.gitea.io/gitea/services/auth/source/ldap" | 	"code.gitea.io/gitea/services/auth/source/ldap" | ||||||
|  |  | ||||||
| 	"github.com/urfave/cli" | 	"github.com/urfave/cli/v2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type ( | type ( | ||||||
| @@ -25,117 +25,117 @@ type ( | |||||||
|  |  | ||||||
| var ( | var ( | ||||||
| 	commonLdapCLIFlags = []cli.Flag{ | 	commonLdapCLIFlags = []cli.Flag{ | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "name", | 			Name:  "name", | ||||||
| 			Usage: "Authentication name.", | 			Usage: "Authentication name.", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "not-active", | 			Name:  "not-active", | ||||||
| 			Usage: "Deactivate the authentication source.", | 			Usage: "Deactivate the authentication source.", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "active", | 			Name:  "active", | ||||||
| 			Usage: "Activate the authentication source.", | 			Usage: "Activate the authentication source.", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "security-protocol", | 			Name:  "security-protocol", | ||||||
| 			Usage: "Security protocol name.", | 			Usage: "Security protocol name.", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "skip-tls-verify", | 			Name:  "skip-tls-verify", | ||||||
| 			Usage: "Disable TLS verification.", | 			Usage: "Disable TLS verification.", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "host", | 			Name:  "host", | ||||||
| 			Usage: "The address where the LDAP server can be reached.", | 			Usage: "The address where the LDAP server can be reached.", | ||||||
| 		}, | 		}, | ||||||
| 		cli.IntFlag{ | 		&cli.IntFlag{ | ||||||
| 			Name:  "port", | 			Name:  "port", | ||||||
| 			Usage: "The port to use when connecting to the LDAP server.", | 			Usage: "The port to use when connecting to the LDAP server.", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "user-search-base", | 			Name:  "user-search-base", | ||||||
| 			Usage: "The LDAP base at which user accounts will be searched for.", | 			Usage: "The LDAP base at which user accounts will be searched for.", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "user-filter", | 			Name:  "user-filter", | ||||||
| 			Usage: "An LDAP filter declaring how to find the user record that is attempting to authenticate.", | 			Usage: "An LDAP filter declaring how to find the user record that is attempting to authenticate.", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "admin-filter", | 			Name:  "admin-filter", | ||||||
| 			Usage: "An LDAP filter specifying if a user should be given administrator privileges.", | 			Usage: "An LDAP filter specifying if a user should be given administrator privileges.", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "restricted-filter", | 			Name:  "restricted-filter", | ||||||
| 			Usage: "An LDAP filter specifying if a user should be given restricted status.", | 			Usage: "An LDAP filter specifying if a user should be given restricted status.", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "allow-deactivate-all", | 			Name:  "allow-deactivate-all", | ||||||
| 			Usage: "Allow empty search results to deactivate all users.", | 			Usage: "Allow empty search results to deactivate all users.", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "username-attribute", | 			Name:  "username-attribute", | ||||||
| 			Usage: "The attribute of the user’s LDAP record containing the user name.", | 			Usage: "The attribute of the user’s LDAP record containing the user name.", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "firstname-attribute", | 			Name:  "firstname-attribute", | ||||||
| 			Usage: "The attribute of the user’s LDAP record containing the user’s first name.", | 			Usage: "The attribute of the user’s LDAP record containing the user’s first name.", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "surname-attribute", | 			Name:  "surname-attribute", | ||||||
| 			Usage: "The attribute of the user’s LDAP record containing the user’s surname.", | 			Usage: "The attribute of the user’s LDAP record containing the user’s surname.", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "email-attribute", | 			Name:  "email-attribute", | ||||||
| 			Usage: "The attribute of the user’s LDAP record containing the user’s email address.", | 			Usage: "The attribute of the user’s LDAP record containing the user’s email address.", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "public-ssh-key-attribute", | 			Name:  "public-ssh-key-attribute", | ||||||
| 			Usage: "The attribute of the user’s LDAP record containing the user’s public ssh key.", | 			Usage: "The attribute of the user’s LDAP record containing the user’s public ssh key.", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "skip-local-2fa", | 			Name:  "skip-local-2fa", | ||||||
| 			Usage: "Set to true to skip local 2fa for users authenticated by this source", | 			Usage: "Set to true to skip local 2fa for users authenticated by this source", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "avatar-attribute", | 			Name:  "avatar-attribute", | ||||||
| 			Usage: "The attribute of the user’s LDAP record containing the user’s avatar.", | 			Usage: "The attribute of the user’s LDAP record containing the user’s avatar.", | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	ldapBindDnCLIFlags = append(commonLdapCLIFlags, | 	ldapBindDnCLIFlags = append(commonLdapCLIFlags, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "bind-dn", | 			Name:  "bind-dn", | ||||||
| 			Usage: "The DN to bind to the LDAP server with when searching for the user.", | 			Usage: "The DN to bind to the LDAP server with when searching for the user.", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "bind-password", | 			Name:  "bind-password", | ||||||
| 			Usage: "The password for the Bind DN, if any.", | 			Usage: "The password for the Bind DN, if any.", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "attributes-in-bind", | 			Name:  "attributes-in-bind", | ||||||
| 			Usage: "Fetch attributes in bind DN context.", | 			Usage: "Fetch attributes in bind DN context.", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "synchronize-users", | 			Name:  "synchronize-users", | ||||||
| 			Usage: "Enable user synchronization.", | 			Usage: "Enable user synchronization.", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "disable-synchronize-users", | 			Name:  "disable-synchronize-users", | ||||||
| 			Usage: "Disable user synchronization.", | 			Usage: "Disable user synchronization.", | ||||||
| 		}, | 		}, | ||||||
| 		cli.UintFlag{ | 		&cli.UintFlag{ | ||||||
| 			Name:  "page-size", | 			Name:  "page-size", | ||||||
| 			Usage: "Search page size.", | 			Usage: "Search page size.", | ||||||
| 		}) | 		}) | ||||||
|  |  | ||||||
| 	ldapSimpleAuthCLIFlags = append(commonLdapCLIFlags, | 	ldapSimpleAuthCLIFlags = append(commonLdapCLIFlags, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "user-dn", | 			Name:  "user-dn", | ||||||
| 			Usage: "The user’s DN.", | 			Usage: "The user’s DN.", | ||||||
| 		}) | 		}) | ||||||
|  |  | ||||||
| 	cmdAuthAddLdapBindDn = cli.Command{ | 	cmdAuthAddLdapBindDn = &cli.Command{ | ||||||
| 		Name:  "add-ldap", | 		Name:  "add-ldap", | ||||||
| 		Usage: "Add new LDAP (via Bind DN) authentication source", | 		Usage: "Add new LDAP (via Bind DN) authentication source", | ||||||
| 		Action: func(c *cli.Context) error { | 		Action: func(c *cli.Context) error { | ||||||
| @@ -144,7 +144,7 @@ var ( | |||||||
| 		Flags: ldapBindDnCLIFlags, | 		Flags: ldapBindDnCLIFlags, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	cmdAuthUpdateLdapBindDn = cli.Command{ | 	cmdAuthUpdateLdapBindDn = &cli.Command{ | ||||||
| 		Name:  "update-ldap", | 		Name:  "update-ldap", | ||||||
| 		Usage: "Update existing LDAP (via Bind DN) authentication source", | 		Usage: "Update existing LDAP (via Bind DN) authentication source", | ||||||
| 		Action: func(c *cli.Context) error { | 		Action: func(c *cli.Context) error { | ||||||
| @@ -153,7 +153,7 @@ var ( | |||||||
| 		Flags: append([]cli.Flag{idFlag}, ldapBindDnCLIFlags...), | 		Flags: append([]cli.Flag{idFlag}, ldapBindDnCLIFlags...), | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	cmdAuthAddLdapSimpleAuth = cli.Command{ | 	cmdAuthAddLdapSimpleAuth = &cli.Command{ | ||||||
| 		Name:  "add-ldap-simple", | 		Name:  "add-ldap-simple", | ||||||
| 		Usage: "Add new LDAP (simple auth) authentication source", | 		Usage: "Add new LDAP (simple auth) authentication source", | ||||||
| 		Action: func(c *cli.Context) error { | 		Action: func(c *cli.Context) error { | ||||||
| @@ -162,7 +162,7 @@ var ( | |||||||
| 		Flags: ldapSimpleAuthCLIFlags, | 		Flags: ldapSimpleAuthCLIFlags, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	cmdAuthUpdateLdapSimpleAuth = cli.Command{ | 	cmdAuthUpdateLdapSimpleAuth = &cli.Command{ | ||||||
| 		Name:  "update-ldap-simple", | 		Name:  "update-ldap-simple", | ||||||
| 		Usage: "Update existing LDAP (simple auth) authentication source", | 		Usage: "Update existing LDAP (simple auth) authentication source", | ||||||
| 		Action: func(c *cli.Context) error { | 		Action: func(c *cli.Context) error { | ||||||
|   | |||||||
| @@ -11,7 +11,7 @@ import ( | |||||||
| 	"code.gitea.io/gitea/services/auth/source/ldap" | 	"code.gitea.io/gitea/services/auth/source/ldap" | ||||||
|  |  | ||||||
| 	"github.com/stretchr/testify/assert" | 	"github.com/stretchr/testify/assert" | ||||||
| 	"github.com/urfave/cli" | 	"github.com/urfave/cli/v2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func TestAddLdapBindDn(t *testing.T) { | func TestAddLdapBindDn(t *testing.T) { | ||||||
|   | |||||||
| @@ -4,13 +4,13 @@ | |||||||
| package cmd | package cmd | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"github.com/urfave/cli" | 	"github.com/urfave/cli/v2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var subcmdUser = cli.Command{ | var subcmdUser = &cli.Command{ | ||||||
| 	Name:  "user", | 	Name:  "user", | ||||||
| 	Usage: "Modify users", | 	Usage: "Modify users", | ||||||
| 	Subcommands: []cli.Command{ | 	Subcommands: []*cli.Command{ | ||||||
| 		microcmdUserCreate, | 		microcmdUserCreate, | ||||||
| 		microcmdUserList, | 		microcmdUserList, | ||||||
| 		microcmdUserChangePassword, | 		microcmdUserChangePassword, | ||||||
|   | |||||||
| @@ -12,21 +12,23 @@ import ( | |||||||
| 	pwd "code.gitea.io/gitea/modules/auth/password" | 	pwd "code.gitea.io/gitea/modules/auth/password" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"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", | 	Name:   "change-password", | ||||||
| 	Usage:  "Change a user's password", | 	Usage:  "Change a user's password", | ||||||
| 	Action: runChangePassword, | 	Action: runChangePassword, | ||||||
| 	Flags: []cli.Flag{ | 	Flags: []cli.Flag{ | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "username,u", | 			Name:    "username", | ||||||
|  | 			Aliases: []string{"u"}, | ||||||
| 			Value:   "", | 			Value:   "", | ||||||
| 			Usage:   "The user to change password for", | 			Usage:   "The user to change password for", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "password,p", | 			Name:    "password", | ||||||
|  | 			Aliases: []string{"p"}, | ||||||
| 			Value:   "", | 			Value:   "", | ||||||
| 			Usage:   "New password to set for user", | 			Usage:   "New password to set for user", | ||||||
| 		}, | 		}, | ||||||
|   | |||||||
| @@ -14,52 +14,52 @@ import ( | |||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
| 	"code.gitea.io/gitea/modules/util" | 	"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", | 	Name:   "create", | ||||||
| 	Usage:  "Create a new user in database", | 	Usage:  "Create a new user in database", | ||||||
| 	Action: runCreateUser, | 	Action: runCreateUser, | ||||||
| 	Flags: []cli.Flag{ | 	Flags: []cli.Flag{ | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "name", | 			Name:  "name", | ||||||
| 			Usage: "Username. DEPRECATED: use username instead", | 			Usage: "Username. DEPRECATED: use username instead", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "username", | 			Name:  "username", | ||||||
| 			Usage: "Username", | 			Usage: "Username", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "password", | 			Name:  "password", | ||||||
| 			Usage: "User password", | 			Usage: "User password", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "email", | 			Name:  "email", | ||||||
| 			Usage: "User email address", | 			Usage: "User email address", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "admin", | 			Name:  "admin", | ||||||
| 			Usage: "User is an admin", | 			Usage: "User is an admin", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "random-password", | 			Name:  "random-password", | ||||||
| 			Usage: "Generate a random password for the user", | 			Usage: "Generate a random password for the user", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "must-change-password", | 			Name:  "must-change-password", | ||||||
| 			Usage: "Set this option to false to prevent forcing the user to change their password after initial login, (Default: true)", | 			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", | 			Name:  "random-password-length", | ||||||
| 			Usage: "Length of the random password to be generated", | 			Usage: "Length of the random password to be generated", | ||||||
| 			Value: 12, | 			Value: 12, | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "access-token", | 			Name:  "access-token", | ||||||
| 			Usage: "Generate access token for the user", | 			Usage: "Generate access token for the user", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "restricted", | 			Name:  "restricted", | ||||||
| 			Usage: "Make a restricted user account", | 			Usage: "Make a restricted user account", | ||||||
| 		}, | 		}, | ||||||
|   | |||||||
| @@ -11,26 +11,28 @@ import ( | |||||||
| 	"code.gitea.io/gitea/modules/storage" | 	"code.gitea.io/gitea/modules/storage" | ||||||
| 	user_service "code.gitea.io/gitea/services/user" | 	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", | 	Name:  "delete", | ||||||
| 	Usage: "Delete specific user by id, name or email", | 	Usage: "Delete specific user by id, name or email", | ||||||
| 	Flags: []cli.Flag{ | 	Flags: []cli.Flag{ | ||||||
| 		cli.Int64Flag{ | 		&cli.Int64Flag{ | ||||||
| 			Name:  "id", | 			Name:  "id", | ||||||
| 			Usage: "ID of user of the user to delete", | 			Usage: "ID of user of the user to delete", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "username,u", | 			Name:    "username", | ||||||
|  | 			Aliases: []string{"u"}, | ||||||
| 			Usage:   "Username of the user to delete", | 			Usage:   "Username of the user to delete", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "email,e", | 			Name:    "email", | ||||||
|  | 			Aliases: []string{"e"}, | ||||||
| 			Usage:   "Email of the user to delete", | 			Usage:   "Email of the user to delete", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "purge", | 			Name:  "purge", | ||||||
| 			Usage: "Purge user, all their repositories, organizations and comments", | 			Usage: "Purge user, all their repositories, organizations and comments", | ||||||
| 		}, | 		}, | ||||||
|   | |||||||
| @@ -9,27 +9,29 @@ import ( | |||||||
| 	auth_model "code.gitea.io/gitea/models/auth" | 	auth_model "code.gitea.io/gitea/models/auth" | ||||||
| 	user_model "code.gitea.io/gitea/models/user" | 	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", | 	Name:  "generate-access-token", | ||||||
| 	Usage: "Generate an access token for a specific user", | 	Usage: "Generate an access token for a specific user", | ||||||
| 	Flags: []cli.Flag{ | 	Flags: []cli.Flag{ | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "username,u", | 			Name:    "username", | ||||||
|  | 			Aliases: []string{"u"}, | ||||||
| 			Usage:   "Username", | 			Usage:   "Username", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "token-name,t", | 			Name:    "token-name", | ||||||
|  | 			Aliases: []string{"t"}, | ||||||
| 			Usage:   "Token name", | 			Usage:   "Token name", | ||||||
| 			Value:   "gitea-admin", | 			Value:   "gitea-admin", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "raw", | 			Name:  "raw", | ||||||
| 			Usage: "Display only the token value", | 			Usage: "Display only the token value", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "scopes", | 			Name:  "scopes", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Comma separated list of scopes to apply to access token", | 			Usage: "Comma separated list of scopes to apply to access token", | ||||||
|   | |||||||
| @@ -10,15 +10,15 @@ import ( | |||||||
|  |  | ||||||
| 	user_model "code.gitea.io/gitea/models/user" | 	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", | 	Name:   "list", | ||||||
| 	Usage:  "List users", | 	Usage:  "List users", | ||||||
| 	Action: runListUsers, | 	Action: runListUsers, | ||||||
| 	Flags: []cli.Flag{ | 	Flags: []cli.Flag{ | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "admin", | 			Name:  "admin", | ||||||
| 			Usage: "List only admin users", | 			Usage: "List only admin users", | ||||||
| 		}, | 		}, | ||||||
|   | |||||||
| @@ -9,23 +9,25 @@ import ( | |||||||
|  |  | ||||||
| 	user_model "code.gitea.io/gitea/models/user" | 	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", | 	Name:   "must-change-password", | ||||||
| 	Usage:  "Set the must change password flag for the provided users or all users", | 	Usage:  "Set the must change password flag for the provided users or all users", | ||||||
| 	Action: runMustChangePassword, | 	Action: runMustChangePassword, | ||||||
| 	Flags: []cli.Flag{ | 	Flags: []cli.Flag{ | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "all,A", | 			Name:    "all", | ||||||
|  | 			Aliases: []string{"A"}, | ||||||
| 			Usage:   "All users must change password, except those explicitly excluded with --exclude", | 			Usage:   "All users must change password, except those explicitly excluded with --exclude", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringSliceFlag{ | 		&cli.StringSliceFlag{ | ||||||
| 			Name:  "exclude,e", | 			Name:    "exclude", | ||||||
|  | 			Aliases: []string{"e"}, | ||||||
| 			Usage:   "Do not change the must-change-password flag for these users", | 			Usage:   "Do not change the must-change-password flag for these users", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "unset", | 			Name:  "unset", | ||||||
| 			Usage: "Instead of setting the must-change-password flag, unset it", | 			Usage: "Instead of setting the must-change-password flag, unset it", | ||||||
| 		}, | 		}, | ||||||
| @@ -48,7 +50,7 @@ func runMustChangePassword(c *cli.Context) error { | |||||||
| 		return err | 		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 { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|   | |||||||
							
								
								
									
										16
									
								
								cmd/cert.go
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								cmd/cert.go
									
									
									
									
									
								
							| @@ -20,43 +20,43 @@ import ( | |||||||
| 	"strings" | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/urfave/cli" | 	"github.com/urfave/cli/v2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // CmdCert represents the available cert sub-command. | // CmdCert represents the available cert sub-command. | ||||||
| var CmdCert = cli.Command{ | var CmdCert = &cli.Command{ | ||||||
| 	Name:  "cert", | 	Name:  "cert", | ||||||
| 	Usage: "Generate self-signed certificate", | 	Usage: "Generate self-signed certificate", | ||||||
| 	Description: `Generate a self-signed X.509 certificate for a TLS server. | 	Description: `Generate a self-signed X.509 certificate for a TLS server. | ||||||
| Outputs to 'cert.pem' and 'key.pem' and will overwrite existing files.`, | Outputs to 'cert.pem' and 'key.pem' and will overwrite existing files.`, | ||||||
| 	Action: runCert, | 	Action: runCert, | ||||||
| 	Flags: []cli.Flag{ | 	Flags: []cli.Flag{ | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "host", | 			Name:  "host", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Comma-separated hostnames and IPs to generate a certificate for", | 			Usage: "Comma-separated hostnames and IPs to generate a certificate for", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "ecdsa-curve", | 			Name:  "ecdsa-curve", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "ECDSA curve to use to generate a key. Valid values are P224, P256, P384, P521", | 			Usage: "ECDSA curve to use to generate a key. Valid values are P224, P256, P384, P521", | ||||||
| 		}, | 		}, | ||||||
| 		cli.IntFlag{ | 		&cli.IntFlag{ | ||||||
| 			Name:  "rsa-bits", | 			Name:  "rsa-bits", | ||||||
| 			Value: 2048, | 			Value: 2048, | ||||||
| 			Usage: "Size of RSA key to generate. Ignored if --ecdsa-curve is set", | 			Usage: "Size of RSA key to generate. Ignored if --ecdsa-curve is set", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "start-date", | 			Name:  "start-date", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Creation date formatted as Jan 1 15:04:05 2011", | 			Usage: "Creation date formatted as Jan 1 15:04:05 2011", | ||||||
| 		}, | 		}, | ||||||
| 		cli.DurationFlag{ | 		&cli.DurationFlag{ | ||||||
| 			Name:  "duration", | 			Name:  "duration", | ||||||
| 			Value: 365 * 24 * time.Hour, | 			Value: 365 * 24 * time.Hour, | ||||||
| 			Usage: "Duration that certificate is valid for", | 			Usage: "Duration that certificate is valid for", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "ca", | 			Name:  "ca", | ||||||
| 			Usage: "whether this cert should be its own Certificate Authority", | 			Usage: "whether this cert should be its own Certificate Authority", | ||||||
| 		}, | 		}, | ||||||
|   | |||||||
							
								
								
									
										15
									
								
								cmd/cmd.go
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								cmd/cmd.go
									
									
									
									
									
								
							| @@ -20,7 +20,7 @@ import ( | |||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
| 	"code.gitea.io/gitea/modules/util" | 	"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 | // 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) | 	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. | // 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. | // 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 { | func PrepareConsoleLoggerLevel(defaultLevel log.Level) func(*cli.Context) error { | ||||||
| 	return func(c *cli.Context) error { | 	return func(c *cli.Context) error { | ||||||
| 		level := defaultLevel | 		level := defaultLevel | ||||||
| 		if c.Bool("quiet") || c.GlobalBoolT("quiet") { | 		if globalBool(c, "quiet") { | ||||||
| 			level = log.FATAL | 			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 | 			level = log.TRACE | ||||||
| 		} | 		} | ||||||
| 		log.SetConsoleLogger(log.DEFAULT, "console-default", level) | 		log.SetConsoleLogger(log.DEFAULT, "console-default", level) | ||||||
|   | |||||||
| @@ -10,11 +10,11 @@ import ( | |||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
|  |  | ||||||
| 	"github.com/urfave/cli" | 	"github.com/urfave/cli/v2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // CmdConvert represents the available convert sub-command. | // CmdConvert represents the available convert sub-command. | ||||||
| var CmdConvert = cli.Command{ | var CmdConvert = &cli.Command{ | ||||||
| 	Name:        "convert", | 	Name:        "convert", | ||||||
| 	Usage:       "Convert the database", | 	Usage:       "Convert the database", | ||||||
| 	Description: "A command to convert an existing MySQL database from utf8 to utf8mb4 or MSSQL database from varchar to nvarchar", | 	Description: "A command to convert an existing MySQL database from utf8 to utf8mb4 or MSSQL database from varchar to nvarchar", | ||||||
|   | |||||||
| @@ -8,11 +8,11 @@ import ( | |||||||
| 	"os" | 	"os" | ||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
| 	"github.com/urfave/cli" | 	"github.com/urfave/cli/v2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // CmdDocs represents the available docs sub-command. | // CmdDocs represents the available docs sub-command. | ||||||
| var CmdDocs = cli.Command{ | var CmdDocs = &cli.Command{ | ||||||
| 	Name:        "docs", | 	Name:        "docs", | ||||||
| 	Usage:       "Output CLI documentation", | 	Usage:       "Output CLI documentation", | ||||||
| 	Description: "A command to output Gitea's CLI documentation, optionally to a file.", | 	Description: "A command to output Gitea's CLI documentation, optionally to a file.", | ||||||
| @@ -23,7 +23,8 @@ var CmdDocs = cli.Command{ | |||||||
| 			Usage: "Output man pages instead", | 			Usage: "Output man pages instead", | ||||||
| 		}, | 		}, | ||||||
| 		&cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "output, o", | 			Name:    "output", | ||||||
|  | 			Aliases: []string{"o"}, | ||||||
| 			Usage:   "Path to output to instead of stdout (will overwrite if exists)", | 			Usage:   "Path to output to instead of stdout (will overwrite if exists)", | ||||||
| 		}, | 		}, | ||||||
| 	}, | 	}, | ||||||
|   | |||||||
| @@ -18,57 +18,58 @@ import ( | |||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
|  |  | ||||||
| 	"github.com/urfave/cli" | 	"github.com/urfave/cli/v2" | ||||||
| 	"xorm.io/xorm" | 	"xorm.io/xorm" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // CmdDoctor represents the available doctor sub-command. | // CmdDoctor represents the available doctor sub-command. | ||||||
| var CmdDoctor = cli.Command{ | var CmdDoctor = &cli.Command{ | ||||||
| 	Name:        "doctor", | 	Name:        "doctor", | ||||||
| 	Usage:       "Diagnose and optionally fix problems", | 	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.", | 	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, | 	Action:      runDoctor, | ||||||
| 	Flags: []cli.Flag{ | 	Flags: []cli.Flag{ | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "list", | 			Name:  "list", | ||||||
| 			Usage: "List the available checks", | 			Usage: "List the available checks", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "default", | 			Name:  "default", | ||||||
| 			Usage: "Run the default checks (if neither --run or --all is set, this is the default behaviour)", | 			Usage: "Run the default checks (if neither --run or --all is set, this is the default behaviour)", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringSliceFlag{ | 		&cli.StringSliceFlag{ | ||||||
| 			Name:  "run", | 			Name:  "run", | ||||||
| 			Usage: "Run the provided checks - (if --default is set, the default checks will also run)", | 			Usage: "Run the provided checks - (if --default is set, the default checks will also run)", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "all", | 			Name:  "all", | ||||||
| 			Usage: "Run all the available checks", | 			Usage: "Run all the available checks", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "fix", | 			Name:  "fix", | ||||||
| 			Usage: "Automatically fix what we can", | 			Usage: "Automatically fix what we can", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "log-file", | 			Name:  "log-file", | ||||||
| 			Usage: `Name of the log file (default: "doctor.log"). Set to "-" to output to stdout, set to "" to disable`, | 			Usage: `Name of the log file (default: "doctor.log"). Set to "-" to output to stdout, set to "" to disable`, | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "color, H", | 			Name:    "color", | ||||||
|  | 			Aliases: []string{"H"}, | ||||||
| 			Usage:   "Use color for outputted information", | 			Usage:   "Use color for outputted information", | ||||||
| 		}, | 		}, | ||||||
| 	}, | 	}, | ||||||
| 	Subcommands: []cli.Command{ | 	Subcommands: []*cli.Command{ | ||||||
| 		cmdRecreateTable, | 		cmdRecreateTable, | ||||||
| 	}, | 	}, | ||||||
| } | } | ||||||
|  |  | ||||||
| var cmdRecreateTable = cli.Command{ | var cmdRecreateTable = &cli.Command{ | ||||||
| 	Name:      "recreate-table", | 	Name:      "recreate-table", | ||||||
| 	Usage:     "Recreate tables from XORM definitions and copy the data.", | 	Usage:     "Recreate tables from XORM definitions and copy the data.", | ||||||
| 	ArgsUsage: "[TABLE]... : (TABLEs to recreate - leave blank for all)", | 	ArgsUsage: "[TABLE]... : (TABLEs to recreate - leave blank for all)", | ||||||
| 	Flags: []cli.Flag{ | 	Flags: []cli.Flag{ | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "debug", | 			Name:  "debug", | ||||||
| 			Usage: "Print SQL commands sent", | 			Usage: "Print SQL commands sent", | ||||||
| 		}, | 		}, | ||||||
|   | |||||||
							
								
								
									
										51
									
								
								cmd/dump.go
									
									
									
									
									
								
							
							
						
						
									
										51
									
								
								cmd/dump.go
									
									
									
									
									
								
							| @@ -22,7 +22,7 @@ import ( | |||||||
|  |  | ||||||
| 	"gitea.com/go-chi/session" | 	"gitea.com/go-chi/session" | ||||||
| 	"github.com/mholt/archiver/v3" | 	"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 { | 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. | // CmdDump represents the available dump sub-command. | ||||||
| var CmdDump = cli.Command{ | var CmdDump = &cli.Command{ | ||||||
| 	Name:  "dump", | 	Name:  "dump", | ||||||
| 	Usage: "Dump Gitea files and database", | 	Usage: "Dump Gitea files and database", | ||||||
| 	Description: `Dump compresses all related files and database into zip file. | 	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`, | It can be used for backup and capture Gitea server image to send to maintainer`, | ||||||
| 	Action: runDump, | 	Action: runDump, | ||||||
| 	Flags: []cli.Flag{ | 	Flags: []cli.Flag{ | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "file, f", | 			Name:    "file", | ||||||
|  | 			Aliases: []string{"f"}, | ||||||
| 			Value:   fmt.Sprintf("gitea-dump-%d.zip", time.Now().Unix()), | 			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.", | 			Usage:   "Name of the dump file which will be created. Supply '-' for stdout. See type for available types.", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "verbose, V", | 			Name:    "verbose", | ||||||
|  | 			Aliases: []string{"V"}, | ||||||
| 			Usage:   "Show process details", | 			Usage:   "Show process details", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "quiet, q", | 			Name:    "quiet", | ||||||
|  | 			Aliases: []string{"q"}, | ||||||
| 			Usage:   "Only display warnings and errors", | 			Usage:   "Only display warnings and errors", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "tempdir, t", | 			Name:    "tempdir", | ||||||
|  | 			Aliases: []string{"t"}, | ||||||
| 			Value:   os.TempDir(), | 			Value:   os.TempDir(), | ||||||
| 			Usage:   "Temporary dir path", | 			Usage:   "Temporary dir path", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "database, d", | 			Name:    "database", | ||||||
|  | 			Aliases: []string{"d"}, | ||||||
| 			Usage:   "Specify the database SQL syntax", | 			Usage:   "Specify the database SQL syntax", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "skip-repository, R", | 			Name:    "skip-repository", | ||||||
|  | 			Aliases: []string{"R"}, | ||||||
| 			Usage:   "Skip the repository dumping", | 			Usage:   "Skip the repository dumping", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "skip-log, L", | 			Name:    "skip-log", | ||||||
|  | 			Aliases: []string{"L"}, | ||||||
| 			Usage:   "Skip the log dumping", | 			Usage:   "Skip the log dumping", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "skip-custom-dir", | 			Name:  "skip-custom-dir", | ||||||
| 			Usage: "Skip custom directory", | 			Usage: "Skip custom directory", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "skip-lfs-data", | 			Name:  "skip-lfs-data", | ||||||
| 			Usage: "Skip LFS data", | 			Usage: "Skip LFS data", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "skip-attachment-data", | 			Name:  "skip-attachment-data", | ||||||
| 			Usage: "Skip attachment data", | 			Usage: "Skip attachment data", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "skip-package-data", | 			Name:  "skip-package-data", | ||||||
| 			Usage: "Skip package data", | 			Usage: "Skip package data", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "skip-index", | 			Name:  "skip-index", | ||||||
| 			Usage: "Skip bleve index data", | 			Usage: "Skip bleve index data", | ||||||
| 		}, | 		}, | ||||||
| 		cli.GenericFlag{ | 		&cli.GenericFlag{ | ||||||
| 			Name:  "type", | 			Name:  "type", | ||||||
| 			Value: outputTypeEnum, | 			Value: outputTypeEnum, | ||||||
| 			Usage: fmt.Sprintf("Dump output format: %s", outputTypeEnum.Join()), | 			Usage: fmt.Sprintf("Dump output format: %s", outputTypeEnum.Join()), | ||||||
|   | |||||||
| @@ -19,57 +19,58 @@ import ( | |||||||
| 	"code.gitea.io/gitea/services/convert" | 	"code.gitea.io/gitea/services/convert" | ||||||
| 	"code.gitea.io/gitea/services/migrations" | 	"code.gitea.io/gitea/services/migrations" | ||||||
|  |  | ||||||
| 	"github.com/urfave/cli" | 	"github.com/urfave/cli/v2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // CmdDumpRepository represents the available dump repository sub-command. | // CmdDumpRepository represents the available dump repository sub-command. | ||||||
| var CmdDumpRepository = cli.Command{ | var CmdDumpRepository = &cli.Command{ | ||||||
| 	Name:        "dump-repo", | 	Name:        "dump-repo", | ||||||
| 	Usage:       "Dump the repository from git/github/gitea/gitlab", | 	Usage:       "Dump the repository from git/github/gitea/gitlab", | ||||||
| 	Description: "This is a command for dumping the repository data.", | 	Description: "This is a command for dumping the repository data.", | ||||||
| 	Action:      runDumpRepository, | 	Action:      runDumpRepository, | ||||||
| 	Flags: []cli.Flag{ | 	Flags: []cli.Flag{ | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "git_service", | 			Name:  "git_service", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Git service, git, github, gitea, gitlab. If clone_addr could be recognized, this could be ignored.", | 			Usage: "Git service, git, github, gitea, gitlab. If clone_addr could be recognized, this could be ignored.", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "repo_dir, r", | 			Name:    "repo_dir", | ||||||
|  | 			Aliases: []string{"r"}, | ||||||
| 			Value:   "./data", | 			Value:   "./data", | ||||||
| 			Usage:   "Repository dir path to store the data", | 			Usage:   "Repository dir path to store the data", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "clone_addr", | 			Name:  "clone_addr", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "The URL will be clone, currently could be a git/github/gitea/gitlab http/https URL", | 			Usage: "The URL will be clone, currently could be a git/github/gitea/gitlab http/https URL", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "auth_username", | 			Name:  "auth_username", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "The username to visit the clone_addr", | 			Usage: "The username to visit the clone_addr", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "auth_password", | 			Name:  "auth_password", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "The password to visit the clone_addr", | 			Usage: "The password to visit the clone_addr", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "auth_token", | 			Name:  "auth_token", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "The personal token to visit the clone_addr", | 			Usage: "The personal token to visit the clone_addr", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "owner_name", | 			Name:  "owner_name", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "The data will be stored on a directory with owner name if not empty", | 			Usage: "The data will be stored on a directory with owner name if not empty", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "repo_name", | 			Name:  "repo_name", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "The data will be stored on a directory with repository name if not empty", | 			Usage: "The data will be stored on a directory with repository name if not empty", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "units", | 			Name:  "units", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: `Which items will be migrated, one or more units should be separated as comma. | 			Usage: `Which items will be migrated, one or more units should be separated as comma. | ||||||
|   | |||||||
| @@ -19,69 +19,73 @@ import ( | |||||||
| 	"code.gitea.io/gitea/modules/util" | 	"code.gitea.io/gitea/modules/util" | ||||||
|  |  | ||||||
| 	"github.com/gobwas/glob" | 	"github.com/gobwas/glob" | ||||||
| 	"github.com/urfave/cli" | 	"github.com/urfave/cli/v2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // CmdEmbedded represents the available extract sub-command. | // CmdEmbedded represents the available extract sub-command. | ||||||
| var ( | var ( | ||||||
| 	CmdEmbedded = cli.Command{ | 	CmdEmbedded = &cli.Command{ | ||||||
| 		Name:        "embedded", | 		Name:        "embedded", | ||||||
| 		Usage:       "Extract embedded resources", | 		Usage:       "Extract embedded resources", | ||||||
| 		Description: "A command for extracting embedded resources, like templates and images", | 		Description: "A command for extracting embedded resources, like templates and images", | ||||||
| 		Subcommands: []cli.Command{ | 		Subcommands: []*cli.Command{ | ||||||
| 			subcmdList, | 			subcmdList, | ||||||
| 			subcmdView, | 			subcmdView, | ||||||
| 			subcmdExtract, | 			subcmdExtract, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	subcmdList = cli.Command{ | 	subcmdList = &cli.Command{ | ||||||
| 		Name:   "list", | 		Name:   "list", | ||||||
| 		Usage:  "List files matching the given pattern", | 		Usage:  "List files matching the given pattern", | ||||||
| 		Action: runList, | 		Action: runList, | ||||||
| 		Flags: []cli.Flag{ | 		Flags: []cli.Flag{ | ||||||
| 			cli.BoolFlag{ | 			&cli.BoolFlag{ | ||||||
| 				Name:  "include-vendored,vendor", | 				Name:    "include-vendored", | ||||||
|  | 				Aliases: []string{"vendor"}, | ||||||
| 				Usage:   "Include files under public/vendor as well", | 				Usage:   "Include files under public/vendor as well", | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	subcmdView = cli.Command{ | 	subcmdView = &cli.Command{ | ||||||
| 		Name:   "view", | 		Name:   "view", | ||||||
| 		Usage:  "View a file matching the given pattern", | 		Usage:  "View a file matching the given pattern", | ||||||
| 		Action: runView, | 		Action: runView, | ||||||
| 		Flags: []cli.Flag{ | 		Flags: []cli.Flag{ | ||||||
| 			cli.BoolFlag{ | 			&cli.BoolFlag{ | ||||||
| 				Name:  "include-vendored,vendor", | 				Name:    "include-vendored", | ||||||
|  | 				Aliases: []string{"vendor"}, | ||||||
| 				Usage:   "Include files under public/vendor as well", | 				Usage:   "Include files under public/vendor as well", | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	subcmdExtract = cli.Command{ | 	subcmdExtract = &cli.Command{ | ||||||
| 		Name:   "extract", | 		Name:   "extract", | ||||||
| 		Usage:  "Extract resources", | 		Usage:  "Extract resources", | ||||||
| 		Action: runExtract, | 		Action: runExtract, | ||||||
| 		Flags: []cli.Flag{ | 		Flags: []cli.Flag{ | ||||||
| 			cli.BoolFlag{ | 			&cli.BoolFlag{ | ||||||
| 				Name:  "include-vendored,vendor", | 				Name:    "include-vendored", | ||||||
|  | 				Aliases: []string{"vendor"}, | ||||||
| 				Usage:   "Include files under public/vendor as well", | 				Usage:   "Include files under public/vendor as well", | ||||||
| 			}, | 			}, | ||||||
| 			cli.BoolFlag{ | 			&cli.BoolFlag{ | ||||||
| 				Name:  "overwrite", | 				Name:  "overwrite", | ||||||
| 				Usage: "Overwrite files if they already exist", | 				Usage: "Overwrite files if they already exist", | ||||||
| 			}, | 			}, | ||||||
| 			cli.BoolFlag{ | 			&cli.BoolFlag{ | ||||||
| 				Name:  "rename", | 				Name:  "rename", | ||||||
| 				Usage: "Rename files as {name}.bak if they already exist (overwrites previous .bak)", | 				Usage: "Rename files as {name}.bak if they already exist (overwrites previous .bak)", | ||||||
| 			}, | 			}, | ||||||
| 			cli.BoolFlag{ | 			&cli.BoolFlag{ | ||||||
| 				Name:  "custom", | 				Name:  "custom", | ||||||
| 				Usage: "Extract to the 'custom' directory as per app.ini", | 				Usage: "Extract to the 'custom' directory as per app.ini", | ||||||
| 			}, | 			}, | ||||||
| 			cli.StringFlag{ | 			&cli.StringFlag{ | ||||||
| 				Name:  "destination,dest-dir", | 				Name:    "destination", | ||||||
|  | 				Aliases: []string{"dest-dir"}, | ||||||
| 				Usage:   "Extract to the specified directory", | 				Usage:   "Extract to the specified directory", | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| @@ -99,7 +103,7 @@ type assetFile struct { | |||||||
| func initEmbeddedExtractor(c *cli.Context) error { | func initEmbeddedExtractor(c *cli.Context) error { | ||||||
| 	setupConsoleLogger(log.ERROR, log.CanColorStderr, os.Stderr) | 	setupConsoleLogger(log.ERROR, log.CanColorStderr, os.Stderr) | ||||||
|  |  | ||||||
| 	patterns, err := compileCollectPatterns(c.Args()) | 	patterns, err := compileCollectPatterns(c.Args().Slice()) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| @@ -175,7 +179,7 @@ func runExtractDo(c *cli.Context) error { | |||||||
| 		return err | 		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)") | 		return fmt.Errorf("a list of pattern of files to extract is mandatory (e.g. '**' for all)") | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -11,43 +11,43 @@ import ( | |||||||
| 	"code.gitea.io/gitea/modules/generate" | 	"code.gitea.io/gitea/modules/generate" | ||||||
|  |  | ||||||
| 	"github.com/mattn/go-isatty" | 	"github.com/mattn/go-isatty" | ||||||
| 	"github.com/urfave/cli" | 	"github.com/urfave/cli/v2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var ( | var ( | ||||||
| 	// CmdGenerate represents the available generate sub-command. | 	// CmdGenerate represents the available generate sub-command. | ||||||
| 	CmdGenerate = cli.Command{ | 	CmdGenerate = &cli.Command{ | ||||||
| 		Name:  "generate", | 		Name:  "generate", | ||||||
| 		Usage: "Command line interface for running generators", | 		Usage: "Command line interface for running generators", | ||||||
| 		Subcommands: []cli.Command{ | 		Subcommands: []*cli.Command{ | ||||||
| 			subcmdSecret, | 			subcmdSecret, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	subcmdSecret = cli.Command{ | 	subcmdSecret = &cli.Command{ | ||||||
| 		Name:  "secret", | 		Name:  "secret", | ||||||
| 		Usage: "Generate a secret token", | 		Usage: "Generate a secret token", | ||||||
| 		Subcommands: []cli.Command{ | 		Subcommands: []*cli.Command{ | ||||||
| 			microcmdGenerateInternalToken, | 			microcmdGenerateInternalToken, | ||||||
| 			microcmdGenerateLfsJwtSecret, | 			microcmdGenerateLfsJwtSecret, | ||||||
| 			microcmdGenerateSecretKey, | 			microcmdGenerateSecretKey, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	microcmdGenerateInternalToken = cli.Command{ | 	microcmdGenerateInternalToken = &cli.Command{ | ||||||
| 		Name:   "INTERNAL_TOKEN", | 		Name:   "INTERNAL_TOKEN", | ||||||
| 		Usage:  "Generate a new INTERNAL_TOKEN", | 		Usage:  "Generate a new INTERNAL_TOKEN", | ||||||
| 		Action: runGenerateInternalToken, | 		Action: runGenerateInternalToken, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	microcmdGenerateLfsJwtSecret = cli.Command{ | 	microcmdGenerateLfsJwtSecret = &cli.Command{ | ||||||
| 		Name:    "JWT_SECRET", | 		Name:    "JWT_SECRET", | ||||||
| 		Aliases: []string{"LFS_JWT_SECRET"}, | 		Aliases: []string{"LFS_JWT_SECRET"}, | ||||||
| 		Usage:   "Generate a new JWT_SECRET", | 		Usage:   "Generate a new JWT_SECRET", | ||||||
| 		Action:  runGenerateLfsJwtSecret, | 		Action:  runGenerateLfsJwtSecret, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	microcmdGenerateSecretKey = cli.Command{ | 	microcmdGenerateSecretKey = &cli.Command{ | ||||||
| 		Name:   "SECRET_KEY", | 		Name:   "SECRET_KEY", | ||||||
| 		Usage:  "Generate a new SECRET_KEY", | 		Usage:  "Generate a new SECRET_KEY", | ||||||
| 		Action: runGenerateSecretKey, | 		Action: runGenerateSecretKey, | ||||||
|   | |||||||
							
								
								
									
										22
									
								
								cmd/hook.go
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								cmd/hook.go
									
									
									
									
									
								
							| @@ -20,7 +20,7 @@ import ( | |||||||
| 	repo_module "code.gitea.io/gitea/modules/repository" | 	repo_module "code.gitea.io/gitea/modules/repository" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
|  |  | ||||||
| 	"github.com/urfave/cli" | 	"github.com/urfave/cli/v2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
| @@ -29,12 +29,12 @@ const ( | |||||||
|  |  | ||||||
| var ( | var ( | ||||||
| 	// CmdHook represents the available hooks sub-command. | 	// CmdHook represents the available hooks sub-command. | ||||||
| 	CmdHook = cli.Command{ | 	CmdHook = &cli.Command{ | ||||||
| 		Name:        "hook", | 		Name:        "hook", | ||||||
| 		Usage:       "Delegate commands to corresponding Git hooks", | 		Usage:       "Delegate commands to corresponding Git hooks", | ||||||
| 		Description: "This should only be called by Git", | 		Description: "This should only be called by Git", | ||||||
| 		Before:      PrepareConsoleLoggerLevel(log.FATAL), | 		Before:      PrepareConsoleLoggerLevel(log.FATAL), | ||||||
| 		Subcommands: []cli.Command{ | 		Subcommands: []*cli.Command{ | ||||||
| 			subcmdHookPreReceive, | 			subcmdHookPreReceive, | ||||||
| 			subcmdHookUpdate, | 			subcmdHookUpdate, | ||||||
| 			subcmdHookPostReceive, | 			subcmdHookPostReceive, | ||||||
| @@ -42,47 +42,47 @@ var ( | |||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	subcmdHookPreReceive = cli.Command{ | 	subcmdHookPreReceive = &cli.Command{ | ||||||
| 		Name:        "pre-receive", | 		Name:        "pre-receive", | ||||||
| 		Usage:       "Delegate pre-receive Git hook", | 		Usage:       "Delegate pre-receive Git hook", | ||||||
| 		Description: "This command should only be called by Git", | 		Description: "This command should only be called by Git", | ||||||
| 		Action:      runHookPreReceive, | 		Action:      runHookPreReceive, | ||||||
| 		Flags: []cli.Flag{ | 		Flags: []cli.Flag{ | ||||||
| 			cli.BoolFlag{ | 			&cli.BoolFlag{ | ||||||
| 				Name: "debug", | 				Name: "debug", | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| 	subcmdHookUpdate = cli.Command{ | 	subcmdHookUpdate = &cli.Command{ | ||||||
| 		Name:        "update", | 		Name:        "update", | ||||||
| 		Usage:       "Delegate update Git hook", | 		Usage:       "Delegate update Git hook", | ||||||
| 		Description: "This command should only be called by Git", | 		Description: "This command should only be called by Git", | ||||||
| 		Action:      runHookUpdate, | 		Action:      runHookUpdate, | ||||||
| 		Flags: []cli.Flag{ | 		Flags: []cli.Flag{ | ||||||
| 			cli.BoolFlag{ | 			&cli.BoolFlag{ | ||||||
| 				Name: "debug", | 				Name: "debug", | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| 	subcmdHookPostReceive = cli.Command{ | 	subcmdHookPostReceive = &cli.Command{ | ||||||
| 		Name:        "post-receive", | 		Name:        "post-receive", | ||||||
| 		Usage:       "Delegate post-receive Git hook", | 		Usage:       "Delegate post-receive Git hook", | ||||||
| 		Description: "This command should only be called by Git", | 		Description: "This command should only be called by Git", | ||||||
| 		Action:      runHookPostReceive, | 		Action:      runHookPostReceive, | ||||||
| 		Flags: []cli.Flag{ | 		Flags: []cli.Flag{ | ||||||
| 			cli.BoolFlag{ | 			&cli.BoolFlag{ | ||||||
| 				Name: "debug", | 				Name: "debug", | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| 	// Note: new hook since git 2.29 | 	// Note: new hook since git 2.29 | ||||||
| 	subcmdHookProcReceive = cli.Command{ | 	subcmdHookProcReceive = &cli.Command{ | ||||||
| 		Name:        "proc-receive", | 		Name:        "proc-receive", | ||||||
| 		Usage:       "Delegate proc-receive Git hook", | 		Usage:       "Delegate proc-receive Git hook", | ||||||
| 		Description: "This command should only be called by Git", | 		Description: "This command should only be called by Git", | ||||||
| 		Action:      runHookProcReceive, | 		Action:      runHookProcReceive, | ||||||
| 		Flags: []cli.Flag{ | 		Flags: []cli.Flag{ | ||||||
| 			cli.BoolFlag{ | 			&cli.BoolFlag{ | ||||||
| 				Name: "debug", | 				Name: "debug", | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
|   | |||||||
							
								
								
									
										26
									
								
								cmd/keys.go
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								cmd/keys.go
									
									
									
									
									
								
							| @@ -11,33 +11,37 @@ import ( | |||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
| 	"code.gitea.io/gitea/modules/private" | 	"code.gitea.io/gitea/modules/private" | ||||||
|  |  | ||||||
| 	"github.com/urfave/cli" | 	"github.com/urfave/cli/v2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // CmdKeys represents the available keys sub-command | // CmdKeys represents the available keys sub-command | ||||||
| var CmdKeys = cli.Command{ | var CmdKeys = &cli.Command{ | ||||||
| 	Name:   "keys", | 	Name:   "keys", | ||||||
| 	Usage:  "This command queries the Gitea database to get the authorized command for a given ssh key fingerprint", | 	Usage:  "This command queries the Gitea database to get the authorized command for a given ssh key fingerprint", | ||||||
| 	Before: PrepareConsoleLoggerLevel(log.FATAL), | 	Before: PrepareConsoleLoggerLevel(log.FATAL), | ||||||
| 	Action: runKeys, | 	Action: runKeys, | ||||||
| 	Flags: []cli.Flag{ | 	Flags: []cli.Flag{ | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "expected, e", | 			Name:    "expected", | ||||||
|  | 			Aliases: []string{"e"}, | ||||||
| 			Value:   "git", | 			Value:   "git", | ||||||
| 			Usage:   "Expected user for whom provide key commands", | 			Usage:   "Expected user for whom provide key commands", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "username, u", | 			Name:    "username", | ||||||
|  | 			Aliases: []string{"u"}, | ||||||
| 			Value:   "", | 			Value:   "", | ||||||
| 			Usage:   "Username trying to log in by SSH", | 			Usage:   "Username trying to log in by SSH", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "type, t", | 			Name:    "type", | ||||||
|  | 			Aliases: []string{"t"}, | ||||||
| 			Value:   "", | 			Value:   "", | ||||||
| 			Usage:   "Type of the SSH key provided to the SSH Server (requires content to be provided too)", | 			Usage:   "Type of the SSH key provided to the SSH Server (requires content to be provided too)", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "content, k", | 			Name:    "content", | ||||||
|  | 			Aliases: []string{"k"}, | ||||||
| 			Value:   "", | 			Value:   "", | ||||||
| 			Usage:   "Base64 encoded content of the SSH key provided to the SSH Server (requires type to be provided too)", | 			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 { | 	if extra.Error != nil { | ||||||
| 		return extra.Error | 		return extra.Error | ||||||
| 	} | 	} | ||||||
| 	fmt.Println(strings.TrimSpace(authorizedString)) | 	_, _ = fmt.Fprintln(c.App.Writer, strings.TrimSpace(authorizedString)) | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ import ( | |||||||
| 	"code.gitea.io/gitea/modules/private" | 	"code.gitea.io/gitea/modules/private" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
|  |  | ||||||
| 	"github.com/urfave/cli" | 	"github.com/urfave/cli/v2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func runSendMail(c *cli.Context) error { | func runSendMail(c *cli.Context) error { | ||||||
|   | |||||||
							
								
								
									
										196
									
								
								cmd/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										196
									
								
								cmd/main.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||||
|  | } | ||||||
							
								
								
									
										115
									
								
								cmd/main_test.go
									
									
									
									
									
								
							
							
						
						
									
										115
									
								
								cmd/main_test.go
									
									
									
									
									
								
							| @@ -4,9 +4,17 @@ | |||||||
| package cmd | package cmd | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"os" | ||||||
|  | 	"path/filepath" | ||||||
|  | 	"strings" | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	"code.gitea.io/gitea/models/unittest" | 	"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) { | func TestMain(m *testing.M) { | ||||||
| @@ -14,3 +22,110 @@ func TestMain(m *testing.M) { | |||||||
| 		GiteaRootPath: "..", | 		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) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|   | |||||||
| @@ -9,16 +9,16 @@ import ( | |||||||
|  |  | ||||||
| 	"code.gitea.io/gitea/modules/private" | 	"code.gitea.io/gitea/modules/private" | ||||||
|  |  | ||||||
| 	"github.com/urfave/cli" | 	"github.com/urfave/cli/v2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var ( | var ( | ||||||
| 	// CmdManager represents the manager command | 	// CmdManager represents the manager command | ||||||
| 	CmdManager = cli.Command{ | 	CmdManager = &cli.Command{ | ||||||
| 		Name:        "manager", | 		Name:        "manager", | ||||||
| 		Usage:       "Manage the running gitea process", | 		Usage:       "Manage the running gitea process", | ||||||
| 		Description: "This is a command for managing the running gitea process", | 		Description: "This is a command for managing the running gitea process", | ||||||
| 		Subcommands: []cli.Command{ | 		Subcommands: []*cli.Command{ | ||||||
| 			subcmdShutdown, | 			subcmdShutdown, | ||||||
| 			subcmdRestart, | 			subcmdRestart, | ||||||
| 			subcmdReloadTemplates, | 			subcmdReloadTemplates, | ||||||
| @@ -27,80 +27,80 @@ var ( | |||||||
| 			subCmdProcesses, | 			subCmdProcesses, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| 	subcmdShutdown = cli.Command{ | 	subcmdShutdown = &cli.Command{ | ||||||
| 		Name:  "shutdown", | 		Name:  "shutdown", | ||||||
| 		Usage: "Gracefully shutdown the running process", | 		Usage: "Gracefully shutdown the running process", | ||||||
| 		Flags: []cli.Flag{ | 		Flags: []cli.Flag{ | ||||||
| 			cli.BoolFlag{ | 			&cli.BoolFlag{ | ||||||
| 				Name: "debug", | 				Name: "debug", | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 		Action: runShutdown, | 		Action: runShutdown, | ||||||
| 	} | 	} | ||||||
| 	subcmdRestart = cli.Command{ | 	subcmdRestart = &cli.Command{ | ||||||
| 		Name:  "restart", | 		Name:  "restart", | ||||||
| 		Usage: "Gracefully restart the running process - (not implemented for windows servers)", | 		Usage: "Gracefully restart the running process - (not implemented for windows servers)", | ||||||
| 		Flags: []cli.Flag{ | 		Flags: []cli.Flag{ | ||||||
| 			cli.BoolFlag{ | 			&cli.BoolFlag{ | ||||||
| 				Name: "debug", | 				Name: "debug", | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 		Action: runRestart, | 		Action: runRestart, | ||||||
| 	} | 	} | ||||||
| 	subcmdReloadTemplates = cli.Command{ | 	subcmdReloadTemplates = &cli.Command{ | ||||||
| 		Name:  "reload-templates", | 		Name:  "reload-templates", | ||||||
| 		Usage: "Reload template files in the running process", | 		Usage: "Reload template files in the running process", | ||||||
| 		Flags: []cli.Flag{ | 		Flags: []cli.Flag{ | ||||||
| 			cli.BoolFlag{ | 			&cli.BoolFlag{ | ||||||
| 				Name: "debug", | 				Name: "debug", | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 		Action: runReloadTemplates, | 		Action: runReloadTemplates, | ||||||
| 	} | 	} | ||||||
| 	subcmdFlushQueues = cli.Command{ | 	subcmdFlushQueues = &cli.Command{ | ||||||
| 		Name:   "flush-queues", | 		Name:   "flush-queues", | ||||||
| 		Usage:  "Flush queues in the running process", | 		Usage:  "Flush queues in the running process", | ||||||
| 		Action: runFlushQueues, | 		Action: runFlushQueues, | ||||||
| 		Flags: []cli.Flag{ | 		Flags: []cli.Flag{ | ||||||
| 			cli.DurationFlag{ | 			&cli.DurationFlag{ | ||||||
| 				Name:  "timeout", | 				Name:  "timeout", | ||||||
| 				Value: 60 * time.Second, | 				Value: 60 * time.Second, | ||||||
| 				Usage: "Timeout for the flushing process", | 				Usage: "Timeout for the flushing process", | ||||||
| 			}, | 			}, | ||||||
| 			cli.BoolFlag{ | 			&cli.BoolFlag{ | ||||||
| 				Name:  "non-blocking", | 				Name:  "non-blocking", | ||||||
| 				Usage: "Set to true to not wait for flush to complete before returning", | 				Usage: "Set to true to not wait for flush to complete before returning", | ||||||
| 			}, | 			}, | ||||||
| 			cli.BoolFlag{ | 			&cli.BoolFlag{ | ||||||
| 				Name: "debug", | 				Name: "debug", | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| 	subCmdProcesses = cli.Command{ | 	subCmdProcesses = &cli.Command{ | ||||||
| 		Name:   "processes", | 		Name:   "processes", | ||||||
| 		Usage:  "Display running processes within the current process", | 		Usage:  "Display running processes within the current process", | ||||||
| 		Action: runProcesses, | 		Action: runProcesses, | ||||||
| 		Flags: []cli.Flag{ | 		Flags: []cli.Flag{ | ||||||
| 			cli.BoolFlag{ | 			&cli.BoolFlag{ | ||||||
| 				Name: "debug", | 				Name: "debug", | ||||||
| 			}, | 			}, | ||||||
| 			cli.BoolFlag{ | 			&cli.BoolFlag{ | ||||||
| 				Name:  "flat", | 				Name:  "flat", | ||||||
| 				Usage: "Show processes as flat table rather than as tree", | 				Usage: "Show processes as flat table rather than as tree", | ||||||
| 			}, | 			}, | ||||||
| 			cli.BoolFlag{ | 			&cli.BoolFlag{ | ||||||
| 				Name:  "no-system", | 				Name:  "no-system", | ||||||
| 				Usage: "Do not show system processes", | 				Usage: "Do not show system processes", | ||||||
| 			}, | 			}, | ||||||
| 			cli.BoolFlag{ | 			&cli.BoolFlag{ | ||||||
| 				Name:  "stacktraces", | 				Name:  "stacktraces", | ||||||
| 				Usage: "Show stacktraces", | 				Usage: "Show stacktraces", | ||||||
| 			}, | 			}, | ||||||
| 			cli.BoolFlag{ | 			&cli.BoolFlag{ | ||||||
| 				Name:  "json", | 				Name:  "json", | ||||||
| 				Usage: "Output as json", | 				Usage: "Output as json", | ||||||
| 			}, | 			}, | ||||||
| 			cli.StringFlag{ | 			&cli.StringFlag{ | ||||||
| 				Name:  "cancel", | 				Name:  "cancel", | ||||||
| 				Usage: "Process PID to cancel. (Only available for non-system processes.)", | 				Usage: "Process PID to cancel. (Only available for non-system processes.)", | ||||||
| 			}, | 			}, | ||||||
|   | |||||||
| @@ -10,49 +10,61 @@ import ( | |||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
| 	"code.gitea.io/gitea/modules/private" | 	"code.gitea.io/gitea/modules/private" | ||||||
|  |  | ||||||
| 	"github.com/urfave/cli" | 	"github.com/urfave/cli/v2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var ( | var ( | ||||||
| 	defaultLoggingFlags = []cli.Flag{ | 	defaultLoggingFlags = []cli.Flag{ | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "logger", | 			Name:  "logger", | ||||||
| 			Usage: `Logger name - will default to "default"`, | 			Usage: `Logger name - will default to "default"`, | ||||||
| 		}, cli.StringFlag{ | 		}, | ||||||
|  | 		&cli.StringFlag{ | ||||||
| 			Name:  "writer", | 			Name:  "writer", | ||||||
| 			Usage: "Name of the log writer - will default to mode", | 			Usage: "Name of the log writer - will default to mode", | ||||||
| 		}, cli.StringFlag{ | 		}, | ||||||
|  | 		&cli.StringFlag{ | ||||||
| 			Name:  "level", | 			Name:  "level", | ||||||
| 			Usage: "Logging level for the new logger", | 			Usage: "Logging level for the new logger", | ||||||
| 		}, cli.StringFlag{ | 		}, | ||||||
| 			Name:  "stacktrace-level, L", | 		&cli.StringFlag{ | ||||||
|  | 			Name:    "stacktrace-level", | ||||||
|  | 			Aliases: []string{"L"}, | ||||||
| 			Usage:   "Stacktrace logging level", | 			Usage:   "Stacktrace logging level", | ||||||
| 		}, cli.StringFlag{ | 		}, | ||||||
| 			Name:  "flags, F", | 		&cli.StringFlag{ | ||||||
|  | 			Name:    "flags", | ||||||
|  | 			Aliases: []string{"F"}, | ||||||
| 			Usage:   "Flags for the logger", | 			Usage:   "Flags for the logger", | ||||||
| 		}, cli.StringFlag{ | 		}, | ||||||
| 			Name:  "expression, e", | 		&cli.StringFlag{ | ||||||
|  | 			Name:    "expression", | ||||||
|  | 			Aliases: []string{"e"}, | ||||||
| 			Usage:   "Matching expression for the logger", | 			Usage:   "Matching expression for the logger", | ||||||
| 		}, cli.StringFlag{ | 		}, | ||||||
| 			Name:  "prefix, p", | 		&cli.StringFlag{ | ||||||
|  | 			Name:    "prefix", | ||||||
|  | 			Aliases: []string{"p"}, | ||||||
| 			Usage:   "Prefix for the logger", | 			Usage:   "Prefix for the logger", | ||||||
| 		}, cli.BoolFlag{ | 		}, | ||||||
|  | 		&cli.BoolFlag{ | ||||||
| 			Name:  "color", | 			Name:  "color", | ||||||
| 			Usage: "Use color in the logs", | 			Usage: "Use color in the logs", | ||||||
| 		}, cli.BoolFlag{ | 		}, | ||||||
|  | 		&cli.BoolFlag{ | ||||||
| 			Name: "debug", | 			Name: "debug", | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	subcmdLogging = cli.Command{ | 	subcmdLogging = &cli.Command{ | ||||||
| 		Name:  "logging", | 		Name:  "logging", | ||||||
| 		Usage: "Adjust logging commands", | 		Usage: "Adjust logging commands", | ||||||
| 		Subcommands: []cli.Command{ | 		Subcommands: []*cli.Command{ | ||||||
| 			{ | 			{ | ||||||
| 				Name:  "pause", | 				Name:  "pause", | ||||||
| 				Usage: "Pause logging (Gitea will buffer logs up to a certain point and will drop them after that point)", | 				Usage: "Pause logging (Gitea will buffer logs up to a certain point and will drop them after that point)", | ||||||
| 				Flags: []cli.Flag{ | 				Flags: []cli.Flag{ | ||||||
| 					cli.BoolFlag{ | 					&cli.BoolFlag{ | ||||||
| 						Name: "debug", | 						Name: "debug", | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| @@ -61,7 +73,7 @@ var ( | |||||||
| 				Name:  "resume", | 				Name:  "resume", | ||||||
| 				Usage: "Resume logging", | 				Usage: "Resume logging", | ||||||
| 				Flags: []cli.Flag{ | 				Flags: []cli.Flag{ | ||||||
| 					cli.BoolFlag{ | 					&cli.BoolFlag{ | ||||||
| 						Name: "debug", | 						Name: "debug", | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| @@ -70,7 +82,7 @@ var ( | |||||||
| 				Name:  "release-and-reopen", | 				Name:  "release-and-reopen", | ||||||
| 				Usage: "Cause Gitea to release and re-open files used for logging", | 				Usage: "Cause Gitea to release and re-open files used for logging", | ||||||
| 				Flags: []cli.Flag{ | 				Flags: []cli.Flag{ | ||||||
| 					cli.BoolFlag{ | 					&cli.BoolFlag{ | ||||||
| 						Name: "debug", | 						Name: "debug", | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| @@ -80,9 +92,9 @@ var ( | |||||||
| 				Usage:     "Remove a logger", | 				Usage:     "Remove a logger", | ||||||
| 				ArgsUsage: "[name] Name of logger to remove", | 				ArgsUsage: "[name] Name of logger to remove", | ||||||
| 				Flags: []cli.Flag{ | 				Flags: []cli.Flag{ | ||||||
| 					cli.BoolFlag{ | 					&cli.BoolFlag{ | ||||||
| 						Name: "debug", | 						Name: "debug", | ||||||
| 					}, cli.StringFlag{ | 					}, &cli.StringFlag{ | ||||||
| 						Name:  "logger", | 						Name:  "logger", | ||||||
| 						Usage: `Logger name - will default to "default"`, | 						Usage: `Logger name - will default to "default"`, | ||||||
| 					}, | 					}, | ||||||
| @@ -91,31 +103,44 @@ var ( | |||||||
| 			}, { | 			}, { | ||||||
| 				Name:  "add", | 				Name:  "add", | ||||||
| 				Usage: "Add a logger", | 				Usage: "Add a logger", | ||||||
| 				Subcommands: []cli.Command{ | 				Subcommands: []*cli.Command{ | ||||||
| 					{ | 					{ | ||||||
| 						Name:  "file", | 						Name:  "file", | ||||||
| 						Usage: "Add a file logger", | 						Usage: "Add a file logger", | ||||||
| 						Flags: append(defaultLoggingFlags, []cli.Flag{ | 						Flags: append(defaultLoggingFlags, []cli.Flag{ | ||||||
| 							cli.StringFlag{ | 							&cli.StringFlag{ | ||||||
| 								Name:  "filename, f", | 								Name:    "filename", | ||||||
|  | 								Aliases: []string{"f"}, | ||||||
| 								Usage:   "Filename for the logger - this must be set.", | 								Usage:   "Filename for the logger - this must be set.", | ||||||
| 							}, cli.BoolTFlag{ | 							}, | ||||||
| 								Name:  "rotate, r", | 							&cli.BoolFlag{ | ||||||
|  | 								Name:    "rotate", | ||||||
|  | 								Aliases: []string{"r"}, | ||||||
| 								Usage:   "Rotate logs", | 								Usage:   "Rotate logs", | ||||||
| 							}, cli.Int64Flag{ | 							}, | ||||||
| 								Name:  "max-size, s", | 							&cli.Int64Flag{ | ||||||
|  | 								Name:    "max-size", | ||||||
|  | 								Aliases: []string{"s"}, | ||||||
| 								Usage:   "Maximum size in bytes before rotation", | 								Usage:   "Maximum size in bytes before rotation", | ||||||
| 							}, cli.BoolTFlag{ | 							}, | ||||||
| 								Name:  "daily, d", | 							&cli.BoolFlag{ | ||||||
|  | 								Name:    "daily", | ||||||
|  | 								Aliases: []string{"d"}, | ||||||
| 								Usage:   "Rotate logs daily", | 								Usage:   "Rotate logs daily", | ||||||
| 							}, cli.IntFlag{ | 							}, | ||||||
| 								Name:  "max-days, D", | 							&cli.IntFlag{ | ||||||
|  | 								Name:    "max-days", | ||||||
|  | 								Aliases: []string{"D"}, | ||||||
| 								Usage:   "Maximum number of daily logs to keep", | 								Usage:   "Maximum number of daily logs to keep", | ||||||
| 							}, cli.BoolTFlag{ | 							}, | ||||||
| 								Name:  "compress, z", | 							&cli.BoolFlag{ | ||||||
|  | 								Name:    "compress", | ||||||
|  | 								Aliases: []string{"z"}, | ||||||
| 								Usage:   "Compress rotated logs", | 								Usage:   "Compress rotated logs", | ||||||
| 							}, cli.IntFlag{ | 							}, | ||||||
| 								Name:  "compression-level, Z", | 							&cli.IntFlag{ | ||||||
|  | 								Name:    "compression-level", | ||||||
|  | 								Aliases: []string{"Z"}, | ||||||
| 								Usage:   "Compression level to use", | 								Usage:   "Compression level to use", | ||||||
| 							}, | 							}, | ||||||
| 						}...), | 						}...), | ||||||
| @@ -124,17 +149,24 @@ var ( | |||||||
| 						Name:  "conn", | 						Name:  "conn", | ||||||
| 						Usage: "Add a net conn logger", | 						Usage: "Add a net conn logger", | ||||||
| 						Flags: append(defaultLoggingFlags, []cli.Flag{ | 						Flags: append(defaultLoggingFlags, []cli.Flag{ | ||||||
| 							cli.BoolFlag{ | 							&cli.BoolFlag{ | ||||||
| 								Name:  "reconnect-on-message, R", | 								Name:    "reconnect-on-message", | ||||||
|  | 								Aliases: []string{"R"}, | ||||||
| 								Usage:   "Reconnect to host for every message", | 								Usage:   "Reconnect to host for every message", | ||||||
| 							}, cli.BoolFlag{ | 							}, | ||||||
| 								Name:  "reconnect, r", | 							&cli.BoolFlag{ | ||||||
|  | 								Name:    "reconnect", | ||||||
|  | 								Aliases: []string{"r"}, | ||||||
| 								Usage:   "Reconnect to host when connection is dropped", | 								Usage:   "Reconnect to host when connection is dropped", | ||||||
| 							}, cli.StringFlag{ | 							}, | ||||||
| 								Name:  "protocol, P", | 							&cli.StringFlag{ | ||||||
|  | 								Name:    "protocol", | ||||||
|  | 								Aliases: []string{"P"}, | ||||||
| 								Usage:   "Set protocol to use: tcp, unix, or udp (defaults to tcp)", | 								Usage:   "Set protocol to use: tcp, unix, or udp (defaults to tcp)", | ||||||
| 							}, cli.StringFlag{ | 							}, | ||||||
| 								Name:  "address, a", | 							&cli.StringFlag{ | ||||||
|  | 								Name:    "address", | ||||||
|  | 								Aliases: []string{"a"}, | ||||||
| 								Usage:   "Host address and port to connect to (defaults to :7020)", | 								Usage:   "Host address and port to connect to (defaults to :7020)", | ||||||
| 							}, | 							}, | ||||||
| 						}...), | 						}...), | ||||||
| @@ -145,9 +177,10 @@ var ( | |||||||
| 				Name:  "log-sql", | 				Name:  "log-sql", | ||||||
| 				Usage: "Set LogSQL", | 				Usage: "Set LogSQL", | ||||||
| 				Flags: []cli.Flag{ | 				Flags: []cli.Flag{ | ||||||
| 					cli.BoolFlag{ | 					&cli.BoolFlag{ | ||||||
| 						Name: "debug", | 						Name: "debug", | ||||||
| 					}, cli.BoolFlag{ | 					}, | ||||||
|  | 					&cli.BoolFlag{ | ||||||
| 						Name:  "off", | 						Name:  "off", | ||||||
| 						Usage: "Switch off SQL logging", | 						Usage: "Switch off SQL logging", | ||||||
| 					}, | 					}, | ||||||
|   | |||||||
| @@ -11,11 +11,11 @@ import ( | |||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
|  |  | ||||||
| 	"github.com/urfave/cli" | 	"github.com/urfave/cli/v2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // CmdMigrate represents the available migrate sub-command. | // CmdMigrate represents the available migrate sub-command. | ||||||
| var CmdMigrate = cli.Command{ | var CmdMigrate = &cli.Command{ | ||||||
| 	Name:        "migrate", | 	Name:        "migrate", | ||||||
| 	Usage:       "Migrate the database", | 	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.", | 	Description: "This is a command for migrating the database, so that you can run gitea admin create-user before starting the server.", | ||||||
|   | |||||||
| @@ -20,70 +20,73 @@ import ( | |||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
| 	"code.gitea.io/gitea/modules/storage" | 	"code.gitea.io/gitea/modules/storage" | ||||||
|  |  | ||||||
| 	"github.com/urfave/cli" | 	"github.com/urfave/cli/v2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // CmdMigrateStorage represents the available migrate storage sub-command. | // CmdMigrateStorage represents the available migrate storage sub-command. | ||||||
| var CmdMigrateStorage = cli.Command{ | var CmdMigrateStorage = &cli.Command{ | ||||||
| 	Name:        "migrate-storage", | 	Name:        "migrate-storage", | ||||||
| 	Usage:       "Migrate the storage", | 	Usage:       "Migrate the storage", | ||||||
| 	Description: "Copies stored files from storage configured in app.ini to parameter-configured storage", | 	Description: "Copies stored files from storage configured in app.ini to parameter-configured storage", | ||||||
| 	Action:      runMigrateStorage, | 	Action:      runMigrateStorage, | ||||||
| 	Flags: []cli.Flag{ | 	Flags: []cli.Flag{ | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "type, t", | 			Name:    "type", | ||||||
|  | 			Aliases: []string{"t"}, | ||||||
| 			Value:   "", | 			Value:   "", | ||||||
| 			Usage:   "Type of stored files to copy.  Allowed types: 'attachments', 'lfs', 'avatars', 'repo-avatars', 'repo-archivers', 'packages', 'actions-log'", | 			Usage:   "Type of stored files to copy.  Allowed types: 'attachments', 'lfs', 'avatars', 'repo-avatars', 'repo-archivers', 'packages', 'actions-log'", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "storage, s", | 			Name:    "storage", | ||||||
|  | 			Aliases: []string{"s"}, | ||||||
| 			Value:   "", | 			Value:   "", | ||||||
| 			Usage:   "New storage type: local (default) or minio", | 			Usage:   "New storage type: local (default) or minio", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "path, p", | 			Name:    "path", | ||||||
|  | 			Aliases: []string{"p"}, | ||||||
| 			Value:   "", | 			Value:   "", | ||||||
| 			Usage:   "New storage placement if store is local (leave blank for default)", | 			Usage:   "New storage placement if store is local (leave blank for default)", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "minio-endpoint", | 			Name:  "minio-endpoint", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Minio storage endpoint", | 			Usage: "Minio storage endpoint", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "minio-access-key-id", | 			Name:  "minio-access-key-id", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Minio storage accessKeyID", | 			Usage: "Minio storage accessKeyID", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "minio-secret-access-key", | 			Name:  "minio-secret-access-key", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Minio storage secretAccessKey", | 			Usage: "Minio storage secretAccessKey", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "minio-bucket", | 			Name:  "minio-bucket", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Minio storage bucket", | 			Usage: "Minio storage bucket", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "minio-location", | 			Name:  "minio-location", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Minio storage location to create bucket", | 			Usage: "Minio storage location to create bucket", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "minio-base-path", | 			Name:  "minio-base-path", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Minio storage base path on the bucket", | 			Usage: "Minio storage base path on the bucket", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "minio-use-ssl", | 			Name:  "minio-use-ssl", | ||||||
| 			Usage: "Enable SSL for minio", | 			Usage: "Enable SSL for minio", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "minio-insecure-skip-verify", | 			Name:  "minio-insecure-skip-verify", | ||||||
| 			Usage: "Skip SSL verification", | 			Usage: "Skip SSL verification", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "minio-checksum-algorithm", | 			Name:  "minio-checksum-algorithm", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Minio checksum algorithm (default/md5)", | 			Usage: "Minio checksum algorithm (default/md5)", | ||||||
|   | |||||||
| @@ -9,38 +9,39 @@ import ( | |||||||
| 	"code.gitea.io/gitea/modules/private" | 	"code.gitea.io/gitea/modules/private" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
|  |  | ||||||
| 	"github.com/urfave/cli" | 	"github.com/urfave/cli/v2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // CmdRestoreRepository represents the available restore a repository sub-command. | // CmdRestoreRepository represents the available restore a repository sub-command. | ||||||
| var CmdRestoreRepository = cli.Command{ | var CmdRestoreRepository = &cli.Command{ | ||||||
| 	Name:        "restore-repo", | 	Name:        "restore-repo", | ||||||
| 	Usage:       "Restore the repository from disk", | 	Usage:       "Restore the repository from disk", | ||||||
| 	Description: "This is a command for restoring the repository data.", | 	Description: "This is a command for restoring the repository data.", | ||||||
| 	Action:      runRestoreRepository, | 	Action:      runRestoreRepository, | ||||||
| 	Flags: []cli.Flag{ | 	Flags: []cli.Flag{ | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "repo_dir, r", | 			Name:    "repo_dir", | ||||||
|  | 			Aliases: []string{"r"}, | ||||||
| 			Value:   "./data", | 			Value:   "./data", | ||||||
| 			Usage:   "Repository dir path to restore from", | 			Usage:   "Repository dir path to restore from", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "owner_name", | 			Name:  "owner_name", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Restore destination owner name", | 			Usage: "Restore destination owner name", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "repo_name", | 			Name:  "repo_name", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Restore destination repository name", | 			Usage: "Restore destination repository name", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "units", | 			Name:  "units", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: `Which items will be restored, one or more units should be separated as comma. | 			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.`, | wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments are allowed. Empty means all units.`, | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "validation", | 			Name:  "validation", | ||||||
| 			Usage: "Sanity check the content of the files before trying to load them", | 			Usage: "Sanity check the content of the files before trying to load them", | ||||||
| 		}, | 		}, | ||||||
|   | |||||||
							
								
								
									
										20
									
								
								cmd/serv.go
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								cmd/serv.go
									
									
									
									
									
								
							| @@ -32,7 +32,7 @@ import ( | |||||||
|  |  | ||||||
| 	"github.com/golang-jwt/jwt/v5" | 	"github.com/golang-jwt/jwt/v5" | ||||||
| 	"github.com/kballard/go-shellquote" | 	"github.com/kballard/go-shellquote" | ||||||
| 	"github.com/urfave/cli" | 	"github.com/urfave/cli/v2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
| @@ -40,17 +40,17 @@ const ( | |||||||
| ) | ) | ||||||
|  |  | ||||||
| // CmdServ represents the available serv sub-command. | // CmdServ represents the available serv sub-command. | ||||||
| var CmdServ = cli.Command{ | var CmdServ = &cli.Command{ | ||||||
| 	Name:        "serv", | 	Name:        "serv", | ||||||
| 	Usage:       "This command should only be called by SSH shell", | 	Usage:       "This command should only be called by SSH shell", | ||||||
| 	Description: "Serv provides access auth for repositories", | 	Description: "Serv provides access auth for repositories", | ||||||
| 	Before:      PrepareConsoleLoggerLevel(log.FATAL), | 	Before:      PrepareConsoleLoggerLevel(log.FATAL), | ||||||
| 	Action:      runServ, | 	Action:      runServ, | ||||||
| 	Flags: []cli.Flag{ | 	Flags: []cli.Flag{ | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name: "enable-pprof", | 			Name: "enable-pprof", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name: "debug", | 			Name: "debug", | ||||||
| 		}, | 		}, | ||||||
| 	}, | 	}, | ||||||
| @@ -119,7 +119,7 @@ func fail(ctx context.Context, userMessage, logMsgFmt string, args ...any) error | |||||||
| 		} | 		} | ||||||
| 		_ = private.SSHLog(ctx, true, logMsg) | 		_ = private.SSHLog(ctx, true, logMsg) | ||||||
| 	} | 	} | ||||||
| 	return cli.NewExitError("", 1) | 	return cli.Exit("", 1) | ||||||
| } | } | ||||||
|  |  | ||||||
| // handleCliResponseExtra handles the extra response from the cli sub-commands | // 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) | 		_, _ = fmt.Fprintln(os.Stdout, extra.UserMsg) | ||||||
| 	} | 	} | ||||||
| 	if extra.HasError() { | 	if extra.HasError() { | ||||||
| 		return cli.NewExitError(extra.Error, 1) | 		return cli.Exit(extra.Error, 1) | ||||||
| 	} | 	} | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| @@ -147,20 +147,20 @@ func runServ(c *cli.Context) error { | |||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if len(c.Args()) < 1 { | 	if c.NArg() < 1 { | ||||||
| 		if err := cli.ShowSubcommandHelp(c); err != nil { | 		if err := cli.ShowSubcommandHelp(c); err != nil { | ||||||
| 			fmt.Printf("error showing subcommand help: %v\n", err) | 			fmt.Printf("error showing subcommand help: %v\n", err) | ||||||
| 		} | 		} | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	keys := strings.Split(c.Args()[0], "-") | 	keys := strings.Split(c.Args().First(), "-") | ||||||
| 	if len(keys) != 2 || keys[0] != "key" { | 	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) | 	keyID, err := strconv.ParseInt(keys[1], 10, 64) | ||||||
| 	if err != nil { | 	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") | 	cmd := os.Getenv("SSH_ORIGINAL_COMMAND") | ||||||
|   | |||||||
							
								
								
									
										23
									
								
								cmd/web.go
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								cmd/web.go
									
									
									
									
									
								
							| @@ -23,14 +23,14 @@ import ( | |||||||
| 	"code.gitea.io/gitea/routers/install" | 	"code.gitea.io/gitea/routers/install" | ||||||
|  |  | ||||||
| 	"github.com/felixge/fgprof" | 	"github.com/felixge/fgprof" | ||||||
| 	"github.com/urfave/cli" | 	"github.com/urfave/cli/v2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // PIDFile could be set from build tag | // PIDFile could be set from build tag | ||||||
| var PIDFile = "/run/gitea.pid" | var PIDFile = "/run/gitea.pid" | ||||||
|  |  | ||||||
| // CmdWeb represents the available web sub-command. | // CmdWeb represents the available web sub-command. | ||||||
| var CmdWeb = cli.Command{ | var CmdWeb = &cli.Command{ | ||||||
| 	Name:  "web", | 	Name:  "web", | ||||||
| 	Usage: "Start Gitea web server", | 	Usage: "Start Gitea web server", | ||||||
| 	Description: `Gitea web server is the only thing you need to run, | 	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), | 	Before: PrepareConsoleLoggerLevel(log.INFO), | ||||||
| 	Action: runWeb, | 	Action: runWeb, | ||||||
| 	Flags: []cli.Flag{ | 	Flags: []cli.Flag{ | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "port, p", | 			Name:    "port", | ||||||
|  | 			Aliases: []string{"p"}, | ||||||
| 			Value:   "3000", | 			Value:   "3000", | ||||||
| 			Usage:   "Temporary port number to prevent conflict", | 			Usage:   "Temporary port number to prevent conflict", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "install-port", | 			Name:  "install-port", | ||||||
| 			Value: "3000", | 			Value: "3000", | ||||||
| 			Usage: "Temporary port number to run the install page on to prevent conflict", | 			Usage: "Temporary port number to run the install page on to prevent conflict", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "pid, P", | 			Name:    "pid", | ||||||
|  | 			Aliases: []string{"P"}, | ||||||
| 			Value:   PIDFile, | 			Value:   PIDFile, | ||||||
| 			Usage:   "Custom pid file path", | 			Usage:   "Custom pid file path", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "quiet, q", | 			Name:    "quiet", | ||||||
|  | 			Aliases: []string{"q"}, | ||||||
| 			Usage:   "Only display Fatal logging errors until logging is set-up", | 			Usage:   "Only display Fatal logging errors until logging is set-up", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "verbose", | 			Name:  "verbose", | ||||||
| 			Usage: "Set initial logging to TRACE level until logging is properly set-up", | 			Usage: "Set initial logging to TRACE level until logging is properly set-up", | ||||||
| 		}, | 		}, | ||||||
|   | |||||||
| @@ -18,7 +18,7 @@ import ( | |||||||
| 	"syscall" | 	"syscall" | ||||||
|  |  | ||||||
| 	"github.com/google/go-github/v53/github" | 	"github.com/google/go-github/v53/github" | ||||||
| 	"github.com/urfave/cli" | 	"github.com/urfave/cli/v2" | ||||||
| 	"gopkg.in/yaml.v3" | 	"gopkg.in/yaml.v3" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -32,55 +32,55 @@ func main() { | |||||||
| 	app.ArgsUsage = "<PR-to-backport>" | 	app.ArgsUsage = "<PR-to-backport>" | ||||||
|  |  | ||||||
| 	app.Flags = []cli.Flag{ | 	app.Flags = []cli.Flag{ | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "version", | 			Name:  "version", | ||||||
| 			Usage: "Version branch to backport on to", | 			Usage: "Version branch to backport on to", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "upstream", | 			Name:  "upstream", | ||||||
| 			Value: "origin", | 			Value: "origin", | ||||||
| 			Usage: "Upstream remote for the Gitea upstream", | 			Usage: "Upstream remote for the Gitea upstream", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "release-branch", | 			Name:  "release-branch", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Release branch to backport on. Will default to release/<version>", | 			Usage: "Release branch to backport on. Will default to release/<version>", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "cherry-pick", | 			Name:  "cherry-pick", | ||||||
| 			Usage: "SHA to cherry-pick as backport", | 			Usage: "SHA to cherry-pick as backport", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "backport-branch", | 			Name:  "backport-branch", | ||||||
| 			Usage: "Backport branch to backport on to (default: backport-<pr>-<version>", | 			Usage: "Backport branch to backport on to (default: backport-<pr>-<version>", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "remote", | 			Name:  "remote", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Remote for your fork of the Gitea upstream", | 			Usage: "Remote for your fork of the Gitea upstream", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "fork-user", | 			Name:  "fork-user", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Forked user name on Github", | 			Usage: "Forked user name on Github", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "no-fetch", | 			Name:  "no-fetch", | ||||||
| 			Usage: "Set this flag to prevent fetch of remote branches", | 			Usage: "Set this flag to prevent fetch of remote branches", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "no-amend-message", | 			Name:  "no-amend-message", | ||||||
| 			Usage: "Set this flag to prevent automatic amendment of the commit message", | 			Usage: "Set this flag to prevent automatic amendment of the commit message", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "no-push", | 			Name:  "no-push", | ||||||
| 			Usage: "Set this flag to prevent pushing the backport up to your fork", | 			Usage: "Set this flag to prevent pushing the backport up to your fork", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "no-xdg-open", | 			Name:  "no-xdg-open", | ||||||
| 			Usage: "Set this flag to not use xdg-open to open the PR URL", | 			Usage: "Set this flag to not use xdg-open to open the PR URL", | ||||||
| 		}, | 		}, | ||||||
| 		cli.BoolFlag{ | 		&cli.BoolFlag{ | ||||||
| 			Name:  "continue", | 			Name:  "continue", | ||||||
| 			Usage: "Set this flag to continue from a git cherry-pick that has broken", | 			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) | 	localReleaseBranch := path.Join(upstream, upstreamReleaseBranch) | ||||||
|  |  | ||||||
| 	args := c.Args() | 	args := c.Args().Slice() | ||||||
| 	if len(args) == 0 && pr == "" { | 	if len(args) == 0 && pr == "" { | ||||||
| 		return fmt.Errorf("no PR number provided\nProvide a PR number to backport") | 		return fmt.Errorf("no PR number provided\nProvide a PR number to backport") | ||||||
| 	} else if len(args) != 1 && pr == "" { | 	} else if len(args) != 1 && pr == "" { | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ import ( | |||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
|  |  | ||||||
| 	"github.com/urfave/cli" | 	"github.com/urfave/cli/v2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func main() { | func main() { | ||||||
| @@ -46,22 +46,22 @@ func main() { | |||||||
| 	and "GITEA__LOG_0x2E_CONSOLE__STDERR=false". Other examples can be found | 	and "GITEA__LOG_0x2E_CONSOLE__STDERR=false". Other examples can be found | ||||||
| 	on the configuration cheat sheet.` | 	on the configuration cheat sheet.` | ||||||
| 	app.Flags = []cli.Flag{ | 	app.Flags = []cli.Flag{ | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "custom-path, C", | 			Name:  "custom-path, C", | ||||||
| 			Value: setting.CustomPath, | 			Value: setting.CustomPath, | ||||||
| 			Usage: "Custom path file path", | 			Usage: "Custom path file path", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "config, c", | 			Name:  "config, c", | ||||||
| 			Value: setting.CustomConf, | 			Value: setting.CustomConf, | ||||||
| 			Usage: "Custom configuration file path", | 			Usage: "Custom configuration file path", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "work-path, w", | 			Name:  "work-path, w", | ||||||
| 			Value: setting.AppWorkPath, | 			Value: setting.AppWorkPath, | ||||||
| 			Usage: "Set the gitea working path", | 			Usage: "Set the gitea working path", | ||||||
| 		}, | 		}, | ||||||
| 		cli.StringFlag{ | 		&cli.StringFlag{ | ||||||
| 			Name:  "out, o", | 			Name:  "out, o", | ||||||
| 			Value: "", | 			Value: "", | ||||||
| 			Usage: "Destination file to write to", | 			Usage: "Destination file to write to", | ||||||
|   | |||||||
| @@ -12,7 +12,7 @@ | |||||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||||
| ;; | ;; | ||||||
| ;; These values are environment-dependent but form the basis of a lot of values. They will be | ;; 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. | ;; - _`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: | ;; - _`AppWorkPath`_: This refers to "working path" of the `gitea` binary. It is determined by using the first set thing in the following hierarchy: | ||||||
|   | |||||||
| @@ -40,7 +40,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. | |||||||
| ## Default Configuration (non-`app.ini` configuration) | ## Default Configuration (non-`app.ini` configuration) | ||||||
|  |  | ||||||
| These values are environment-dependent but form the basis of a lot of values. They will be | 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. | - _`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: | - _`AppWorkPath`_: This refers to "working path" of the `gitea` binary. It is determined by using the first set thing in the following hierarchy: | ||||||
|   | |||||||
							
								
								
									
										3
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								go.mod
									
									
									
									
									
								
							| @@ -98,7 +98,7 @@ require ( | |||||||
| 	github.com/syndtr/goleveldb v1.0.0 | 	github.com/syndtr/goleveldb v1.0.0 | ||||||
| 	github.com/tstranex/u2f v1.0.0 | 	github.com/tstranex/u2f v1.0.0 | ||||||
| 	github.com/ulikunitz/xz v0.5.11 | 	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/xanzy/go-gitlab v0.86.0 | ||||||
| 	github.com/xeipuuv/gojsonschema v1.2.0 | 	github.com/xeipuuv/gojsonschema v1.2.0 | ||||||
| 	github.com/yohcop/openid-go v1.0.1 | 	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/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect | ||||||
| 	github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect | 	github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect | ||||||
| 	github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // 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 | 	github.com/zeebo/blake3 v0.2.3 // indirect | ||||||
| 	go.etcd.io/bbolt v1.3.7 // indirect | 	go.etcd.io/bbolt v1.3.7 // indirect | ||||||
| 	go.mongodb.org/mongo-driver v1.12.0 // indirect | 	go.mongodb.org/mongo-driver v1.12.0 // indirect | ||||||
|   | |||||||
							
								
								
									
										7
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								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 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= | ||||||
| github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= | 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 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/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 h1:X/QmUmFhpUvLgPSQb7fWOSi1wvqGn6tJ7w2a59c4xsg= | ||||||
| github.com/ClickHouse/ch-go v0.57.0/go.mod h1:DR3iBn7OrrDj+KeUp1LbdxLEUDbW+5Qwdl/qkc+PQ+Y= | 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/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.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.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= | ||||||
| github.com/urfave/cli v1.22.14 h1:ebbhrRiGK2i4naQJr+1Xj92HXZCrK7MsyTS/ob3HnAk= | github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= | ||||||
| github.com/urfave/cli v1.22.14/go.mod h1:X0eDS6pD6Exaclxm99NJ3FiCDRED7vIHpx2mDOHLvkA= | 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 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= | ||||||
| github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= | 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= | 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/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/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/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 h1:DPRd3iPO5F6O5zX2e62XpVAbPT6wV51cuucH0z9g3js= | ||||||
| github.com/yohcop/openid-go v1.0.1/go.mod h1:b/AvD03P0KHj4yuihb+VtLD6bYYgsy0zqBzPCRjkCNs= | 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= | github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= | ||||||
|   | |||||||
							
								
								
									
										154
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										154
									
								
								main.go
									
									
									
									
									
								
							| @@ -2,8 +2,7 @@ | |||||||
| // Copyright 2016 The Gitea Authors. All rights reserved. | // Copyright 2016 The Gitea Authors. All rights reserved. | ||||||
| // SPDX-License-Identifier: MIT | // SPDX-License-Identifier: MIT | ||||||
|  |  | ||||||
| // Gitea (git with a cup of tea) is a painless self-hosted Git Service. | package main | ||||||
| package main // import "code.gitea.io/gitea" |  | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
| @@ -22,17 +21,13 @@ import ( | |||||||
| 	_ "code.gitea.io/gitea/modules/markup/csv" | 	_ "code.gitea.io/gitea/modules/markup/csv" | ||||||
| 	_ "code.gitea.io/gitea/modules/markup/markdown" | 	_ "code.gitea.io/gitea/modules/markup/markdown" | ||||||
| 	_ "code.gitea.io/gitea/modules/markup/orgmode" | 	_ "code.gitea.io/gitea/modules/markup/orgmode" | ||||||
|  |  | ||||||
| 	"github.com/urfave/cli" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | // these flags will be set by the build flags | ||||||
| var ( | var ( | ||||||
| 	// Version holds the current Gitea version | 	Version     = "development" // program version for this build | ||||||
| 	Version = "development" | 	Tags        = ""            // the Golang build tags | ||||||
| 	// Tags holds the build tags used | 	MakeVersion = ""            // "make" program version if built with make | ||||||
| 	Tags = "" |  | ||||||
| 	// MakeVersion holds the current Make version if built with make |  | ||||||
| 	MakeVersion = "" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func init() { | func init() { | ||||||
| @@ -41,110 +36,12 @@ func init() { | |||||||
| 	setting.AppStartTime = time.Now().UTC() | 	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() { | func main() { | ||||||
| 	app := cli.NewApp() | 	app := cmd.NewMainApp() | ||||||
| 	app.Name = "Gitea" | 	app.Name = "Gitea" | ||||||
| 	app.Usage = "A painless self-hosted Git service" | 	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.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.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) | 	err := app.Run(os.Args) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @@ -154,45 +51,6 @@ func main() { | |||||||
| 	log.GetManager().Close() | 	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 { | func formatBuiltWith() string { | ||||||
| 	version := runtime.Version() | 	version := runtime.Version() | ||||||
| 	if len(MakeVersion) > 0 { | 	if len(MakeVersion) > 0 { | ||||||
|   | |||||||
| @@ -5,17 +5,15 @@ package integration | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"bytes" | 	"bytes" | ||||||
| 	"flag" |  | ||||||
| 	"io" |  | ||||||
| 	"net/url" | 	"net/url" | ||||||
| 	"os" |  | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	"code.gitea.io/gitea/cmd" | 	"code.gitea.io/gitea/cmd" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
| 	"code.gitea.io/gitea/modules/util" | 	"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) { | func Test_CmdKeys(t *testing.T) { | ||||||
| @@ -38,26 +36,18 @@ func Test_CmdKeys(t *testing.T) { | |||||||
| 		} | 		} | ||||||
| 		for _, tt := range tests { | 		for _, tt := range tests { | ||||||
| 			t.Run(tt.name, func(t *testing.T) { | 			t.Run(tt.name, func(t *testing.T) { | ||||||
| 				realStdout := os.Stdout // Backup Stdout | 				out := new(bytes.Buffer) | ||||||
| 				r, w, _ := os.Pipe() | 				app := cli.NewApp() | ||||||
| 				os.Stdout = w | 				app.Writer = out | ||||||
|  | 				app.Commands = []*cli.Command{cmd.CmdKeys} | ||||||
| 				set := flag.NewFlagSet("keys", 0) | 				cmd.CmdKeys.HideHelp = true | ||||||
| 				_ = set.Parse(tt.args) | 				err := app.Run(append([]string{"prog"}, tt.args...)) | ||||||
| 				context := cli.NewContext(&cli.App{Writer: os.Stdout}, set, nil) | 				if tt.wantErr { | ||||||
| 				err := cmd.CmdKeys.Run(context) | 					assert.Error(t, err) | ||||||
| 				if (err != nil) != tt.wantErr { | 				} else { | ||||||
| 					t.Errorf("CmdKeys.Run() error = %v, wantErr %v", err, tt.wantErr) | 					assert.NoError(t, err) | ||||||
| 				} | 				} | ||||||
| 				w.Close() | 				assert.Equal(t, tt.expectedOutput, out.String()) | ||||||
| 				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 |  | ||||||
| 			}) | 			}) | ||||||
| 		} | 		} | ||||||
| 	}) | 	}) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 wxiaoguang
					wxiaoguang