Switch cmd/ to use constructor functions. (#36962)

This is a step towards potentially splitting command groups into their
own folders to clean up `cmd/` as one folder for all cli commands.
Returning fresh command instances will also aid in adding tests as you
don't need to concern yourself with the whole command tree being one
mutable variable.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
techknowlogick
2026-03-25 10:53:13 -04:00
committed by GitHub
parent bb1e22bba4
commit 435123fe65
26 changed files with 651 additions and 578 deletions
+7 -6
View File
@@ -13,17 +13,18 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
var ( func newActionsCommand() *cli.Command {
// CmdActions represents the available actions sub-commands. return &cli.Command{
CmdActions = &cli.Command{
Name: "actions", Name: "actions",
Usage: "Manage Gitea Actions", Usage: "Manage Gitea Actions",
Commands: []*cli.Command{ Commands: []*cli.Command{
subcmdActionsGenRunnerToken, newActionsGenerateRunnerTokenCommand(),
}, },
} }
}
subcmdActionsGenRunnerToken = &cli.Command{ func newActionsGenerateRunnerTokenCommand() *cli.Command {
return &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,
@@ -37,7 +38,7 @@ var (
}, },
}, },
} }
) }
func runGenerateActionsRunnerToken(ctx context.Context, c *cli.Command) error { func runGenerateActionsRunnerToken(ctx context.Context, c *cli.Command) error {
setting.MustInstalled() setting.MustInstalled()
+24 -17
View File
@@ -18,36 +18,41 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
var ( func newAdminCommand() *cli.Command {
// CmdAdmin represents the available admin sub-command. return &cli.Command{
CmdAdmin = &cli.Command{
Name: "admin", Name: "admin",
Usage: "Perform common administrative operations", Usage: "Perform common administrative operations",
Commands: []*cli.Command{ Commands: []*cli.Command{
subcmdUser, newUserCommand(),
subcmdRepoSyncReleases, newRepoSyncReleasesCommand(),
subcmdRegenerate, newRegenerateCommand(),
subcmdAuth, newAuthCommand(),
subcmdSendMail, newSendMailCommand(),
}, },
} }
}
subcmdRepoSyncReleases = &cli.Command{ func newRepoSyncReleasesCommand() *cli.Command {
return &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{ func newRegenerateCommand() *cli.Command {
return &cli.Command{
Name: "regenerate", Name: "regenerate",
Usage: "Regenerate specific files", Usage: "Regenerate specific files",
Commands: []*cli.Command{ Commands: []*cli.Command{
microcmdRegenHooks, newRegenerateHooksCommand(),
microcmdRegenKeys, newRegenerateKeysCommand(),
}, },
} }
}
subcmdAuth = &cli.Command{ func newAuthCommand() *cli.Command {
return &cli.Command{
Name: "auth", Name: "auth",
Usage: "Modify external auth providers", Usage: "Modify external auth providers",
Commands: []*cli.Command{ Commands: []*cli.Command{
@@ -59,12 +64,14 @@ var (
microcmdAuthUpdateLdapSimpleAuth(), microcmdAuthUpdateLdapSimpleAuth(),
microcmdAuthAddSMTP(), microcmdAuthAddSMTP(),
microcmdAuthUpdateSMTP(), microcmdAuthUpdateSMTP(),
microcmdAuthList, newAuthListCommand(),
microcmdAuthDelete, newAuthDeleteCommand(),
}, },
} }
}
subcmdSendMail = &cli.Command{ func newSendMailCommand() *cli.Command {
return &cli.Command{
Name: "sendmail", Name: "sendmail",
Usage: "Send a message to all users", Usage: "Send a message to all users",
Action: runSendMail, Action: runSendMail,
@@ -86,7 +93,7 @@ var (
}, },
}, },
} }
) }
func idFlag() *cli.Int64Flag { func idFlag() *cli.Int64Flag {
return &cli.Int64Flag{ return &cli.Int64Flag{
+7 -4
View File
@@ -17,14 +17,17 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
var ( func newAuthDeleteCommand() *cli.Command {
microcmdAuthDelete = &cli.Command{ return &cli.Command{
Name: "delete", Name: "delete",
Usage: "Delete specific auth source", Usage: "Delete specific auth source",
Flags: []cli.Flag{idFlag()}, Flags: []cli.Flag{idFlag()},
Action: runDeleteAuth, Action: runDeleteAuth,
} }
microcmdAuthList = &cli.Command{ }
func newAuthListCommand() *cli.Command {
return &cli.Command{
Name: "list", Name: "list",
Usage: "List auth sources", Usage: "List auth sources",
Action: runListAuth, Action: runListAuth,
@@ -55,7 +58,7 @@ var (
}, },
}, },
} }
) }
func runListAuth(ctx context.Context, c *cli.Command) error { func runListAuth(ctx context.Context, c *cli.Command) error {
if err := initDB(ctx); err != nil { if err := initDB(ctx); err != nil {
+6 -4
View File
@@ -13,19 +13,21 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
var ( func newRegenerateHooksCommand() *cli.Command {
microcmdRegenHooks = &cli.Command{ return &cli.Command{
Name: "hooks", Name: "hooks",
Usage: "Regenerate git-hooks", Usage: "Regenerate git-hooks",
Action: runRegenerateHooks, Action: runRegenerateHooks,
} }
}
microcmdRegenKeys = &cli.Command{ func newRegenerateKeysCommand() *cli.Command {
return &cli.Command{
Name: "keys", Name: "keys",
Usage: "Regenerate authorized_keys file", Usage: "Regenerate authorized_keys file",
Action: runRegenerateKeys, Action: runRegenerateKeys,
} }
) }
func runRegenerateHooks(ctx context.Context, _ *cli.Command) error { func runRegenerateHooks(ctx context.Context, _ *cli.Command) error {
if err := initDB(ctx); err != nil { if err := initDB(ctx); err != nil {
+5 -3
View File
@@ -7,15 +7,17 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
var subcmdUser = &cli.Command{ func newUserCommand() *cli.Command {
return &cli.Command{
Name: "user", Name: "user",
Usage: "Modify users", Usage: "Modify users",
Commands: []*cli.Command{ Commands: []*cli.Command{
microcmdUserCreate(), microcmdUserCreate(),
microcmdUserList, newUserListCommand(),
microcmdUserChangePassword(), microcmdUserChangePassword(),
microcmdUserDelete(), microcmdUserDelete(),
microcmdUserGenerateAccessToken, newUserGenerateAccessTokenCommand(),
microcmdUserMustChangePassword(), microcmdUserMustChangePassword(),
}, },
}
} }
+3 -1
View File
@@ -14,7 +14,8 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
var microcmdUserGenerateAccessToken = &cli.Command{ func newUserGenerateAccessTokenCommand() *cli.Command {
return &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{
@@ -40,6 +41,7 @@ var microcmdUserGenerateAccessToken = &cli.Command{
}, },
}, },
Action: runGenerateAccessToken, Action: runGenerateAccessToken,
}
} }
func runGenerateAccessToken(ctx context.Context, c *cli.Command) error { func runGenerateAccessToken(ctx context.Context, c *cli.Command) error {
+3 -1
View File
@@ -14,7 +14,8 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
var microcmdUserList = &cli.Command{ func newUserListCommand() *cli.Command {
return &cli.Command{
Name: "list", Name: "list",
Usage: "List users", Usage: "List users",
Action: runListUsers, Action: runListUsers,
@@ -24,6 +25,7 @@ var microcmdUserList = &cli.Command{
Usage: "List only admin users", Usage: "List only admin users",
}, },
}, },
}
} }
func runListUsers(ctx context.Context, c *cli.Command) error { func runListUsers(ctx context.Context, c *cli.Command) error {
+3 -2
View File
@@ -13,8 +13,8 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
// CmdDocs represents the available docs sub-command. func newDocsCommand() *cli.Command {
var CmdDocs = &cli.Command{ return &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.",
@@ -30,6 +30,7 @@ var CmdDocs = &cli.Command{
Usage: "Path to output to instead of stdout (will overwrite if exists)", Usage: "Path to output to instead of stdout (will overwrite if exists)",
}, },
}, },
}
} }
func runDocs(_ context.Context, cmd *cli.Command) error { func runDocs(_ context.Context, cmd *cli.Command) error {
+12 -8
View File
@@ -24,20 +24,21 @@ import (
"xorm.io/xorm" "xorm.io/xorm"
) )
// CmdDoctor represents the available doctor sub-command. func newDoctorCommand() *cli.Command {
var CmdDoctor = &cli.Command{ return &cli.Command{
Name: "doctor", Name: "doctor",
Usage: "Diagnose and optionally fix problems, convert or re-create database tables", Usage: "Diagnose and optionally fix problems, convert or re-create database tables",
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.",
Commands: []*cli.Command{ Commands: []*cli.Command{
cmdDoctorCheck, newDoctorCheckCommand(),
cmdRecreateTable, newRecreateTableCommand(),
cmdDoctorConvert, newDoctorConvertCommand(),
}, },
}
} }
var cmdDoctorCheck = &cli.Command{ func newDoctorCheckCommand() *cli.Command {
return &cli.Command{
Name: "check", Name: "check",
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.",
@@ -73,9 +74,11 @@ var cmdDoctorCheck = &cli.Command{
Usage: "Use color for outputted information", Usage: "Use color for outputted information",
}, },
}, },
}
} }
var cmdRecreateTable = &cli.Command{ func newRecreateTableCommand() *cli.Command {
return &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)",
@@ -91,6 +94,7 @@ This command will cause Xorm to recreate tables, copying over the data and delet
You should back-up your database before doing this and ensure that your database is up-to-date first.`, You should back-up your database before doing this and ensure that your database is up-to-date first.`,
Action: runRecreateTable, Action: runRecreateTable,
}
} }
func runRecreateTable(ctx context.Context, cmd *cli.Command) error { func runRecreateTable(ctx context.Context, cmd *cli.Command) error {
+3 -2
View File
@@ -14,12 +14,13 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
// cmdDoctorConvert represents the available convert sub-command. func newDoctorConvertCommand() *cli.Command {
var cmdDoctorConvert = &cli.Command{ return &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",
Action: runDoctorConvert, Action: runDoctorConvert,
}
} }
func runDoctorConvert(ctx context.Context, cmd *cli.Command) error { func runDoctorConvert(ctx context.Context, cmd *cli.Command) error {
+1 -1
View File
@@ -23,7 +23,7 @@ func TestDoctorRun(t *testing.T) {
SkipDatabaseInitialization: true, SkipDatabaseInitialization: true,
}) })
app := &cli.Command{ app := &cli.Command{
Commands: []*cli.Command{cmdDoctorCheck}, Commands: []*cli.Command{newDoctorCheckCommand()},
} }
err := app.Run(t.Context(), []string{"./gitea", "check", "--run", "test-check"}) err := app.Run(t.Context(), []string{"./gitea", "check", "--run", "test-check"})
assert.NoError(t, err) assert.NoError(t, err)
+3 -2
View File
@@ -23,8 +23,8 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
// CmdDump represents the available dump sub-command. func newDumpCommand() *cli.Command {
var CmdDump = &cli.Command{ return &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. It can be used for backup and capture Gitea server image to send to maintainer`, 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`,
@@ -95,6 +95,7 @@ var CmdDump = &cli.Command{
Usage: `Dump output format, default to "zip", supported types: ` + strings.Join(dump.SupportedOutputTypes, ", "), Usage: `Dump output format, default to "zip", supported types: ` + strings.Join(dump.SupportedOutputTypes, ", "),
}, },
}, },
}
} }
func fatal(format string, args ...any) { func fatal(format string, args ...any) {
+3 -2
View File
@@ -22,8 +22,8 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
// CmdDumpRepository represents the available dump repository sub-command. func newDumpRepositoryCommand() *cli.Command {
var CmdDumpRepository = &cli.Command{ return &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.",
@@ -77,6 +77,7 @@ var CmdDumpRepository = &cli.Command{
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.`,
}, },
}, },
}
} }
func runDumpRepository(ctx context.Context, cmd *cli.Command) error { func runDumpRepository(ctx context.Context, cmd *cli.Command) error {
+17 -12
View File
@@ -23,20 +23,23 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
// CmdEmbedded represents the available extract sub-command. var matchedAssetFiles []assetFile
var (
CmdEmbedded = &cli.Command{ func newEmbeddedCommand() *cli.Command {
return &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",
Commands: []*cli.Command{ Commands: []*cli.Command{
subcmdList, newEmbeddedListCommand(),
subcmdView, newEmbeddedViewCommand(),
subcmdExtract, newEmbeddedExtractCommand(),
}, },
} }
}
subcmdList = &cli.Command{ func newEmbeddedListCommand() *cli.Command {
return &cli.Command{
Name: "list", Name: "list",
Usage: "List files matching the given pattern", Usage: "List files matching the given pattern",
Action: runList, Action: runList,
@@ -48,8 +51,10 @@ var (
}, },
}, },
} }
}
subcmdView = &cli.Command{ func newEmbeddedViewCommand() *cli.Command {
return &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,
@@ -61,8 +66,10 @@ var (
}, },
}, },
} }
}
subcmdExtract = &cli.Command{ func newEmbeddedExtractCommand() *cli.Command {
return &cli.Command{
Name: "extract", Name: "extract",
Usage: "Extract resources", Usage: "Extract resources",
Action: runExtract, Action: runExtract,
@@ -91,9 +98,7 @@ var (
}, },
}, },
} }
}
matchedAssetFiles []assetFile
)
type assetFile struct { type assetFile struct {
fs *assetfs.LayeredFS fs *assetfs.LayeredFS
+19 -12
View File
@@ -15,45 +15,52 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
var ( func newGenerateCommand() *cli.Command {
// CmdGenerate represents the available generate sub-command. return &cli.Command{
CmdGenerate = &cli.Command{
Name: "generate", Name: "generate",
Usage: "Generate Gitea's secrets/keys/tokens", Usage: "Generate Gitea's secrets/keys/tokens",
Commands: []*cli.Command{ Commands: []*cli.Command{
subcmdSecret, newGenerateSecretCommand(),
}, },
} }
}
subcmdSecret = &cli.Command{ func newGenerateSecretCommand() *cli.Command {
return &cli.Command{
Name: "secret", Name: "secret",
Usage: "Generate a secret token", Usage: "Generate a secret token",
Commands: []*cli.Command{ Commands: []*cli.Command{
microcmdGenerateInternalToken, newGenerateInternalTokenCommand(),
microcmdGenerateLfsJwtSecret, newGenerateLfsJWTSecretCommand(),
microcmdGenerateSecretKey, newGenerateSecretKeyCommand(),
}, },
} }
}
microcmdGenerateInternalToken = &cli.Command{ func newGenerateInternalTokenCommand() *cli.Command {
return &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{ func newGenerateLfsJWTSecretCommand() *cli.Command {
return &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{ func newGenerateSecretKeyCommand() *cli.Command {
return &cli.Command{
Name: "SECRET_KEY", Name: "SECRET_KEY",
Usage: "Generate a new SECRET_KEY", Usage: "Generate a new SECRET_KEY",
Action: runGenerateSecretKey, Action: runGenerateSecretKey,
} }
) }
func runGenerateInternalToken(_ context.Context, c *cli.Command) error { func runGenerateInternalToken(_ context.Context, c *cli.Command) error {
internalToken, err := generate.NewInternalToken() internalToken, err := generate.NewInternalToken()
+23 -13
View File
@@ -28,23 +28,24 @@ const (
hookBatchSize = 500 hookBatchSize = 500
) )
var ( func newHookCommand() *cli.Command {
// CmdHook represents the available hooks sub-command. return &cli.Command{
CmdHook = &cli.Command{
Name: "hook", Name: "hook",
Usage: "(internal) Should only be called by Git", Usage: "(internal) Should only be called by Git",
Hidden: true, // internal commands shouldn't be visible Hidden: true, // internal commands shouldn't be visible
Description: "Delegate commands to corresponding Git hooks", Description: "Delegate commands to corresponding Git hooks",
Before: PrepareConsoleLoggerLevel(log.FATAL), Before: PrepareConsoleLoggerLevel(log.FATAL),
Commands: []*cli.Command{ Commands: []*cli.Command{
subcmdHookPreReceive, newHookPreReceiveCommand(),
subcmdHookUpdate, newHookUpdateCommand(),
subcmdHookPostReceive, newHookPostReceiveCommand(),
subcmdHookProcReceive, newHookProcReceiveCommand(),
}, },
} }
}
subcmdHookPreReceive = &cli.Command{ func newHookPreReceiveCommand() *cli.Command {
return &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",
@@ -55,7 +56,10 @@ var (
}, },
}, },
} }
subcmdHookUpdate = &cli.Command{ }
func newHookUpdateCommand() *cli.Command {
return &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",
@@ -66,7 +70,10 @@ var (
}, },
}, },
} }
subcmdHookPostReceive = &cli.Command{ }
func newHookPostReceiveCommand() *cli.Command {
return &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",
@@ -77,8 +84,11 @@ var (
}, },
}, },
} }
// Note: new hook since git 2.29 }
subcmdHookProcReceive = &cli.Command{
// Note: new hook since git 2.29
func newHookProcReceiveCommand() *cli.Command {
return &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",
@@ -89,7 +99,7 @@ var (
}, },
}, },
} }
) }
type delayWriter struct { type delayWriter struct {
internal io.Writer internal io.Writer
+4 -2
View File
@@ -15,8 +15,9 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
// CmdKeys represents the available keys sub-command // NewKeysCommand returns the internal SSH key lookup sub-command.
var CmdKeys = &cli.Command{ func NewKeysCommand() *cli.Command {
return &cli.Command{
Name: "keys", Name: "keys",
Usage: "(internal) Should only be called by SSH server", Usage: "(internal) Should only be called by SSH server",
Hidden: true, // internal commands shouldn't be visible Hidden: true, // internal commands shouldn't be visible
@@ -49,6 +50,7 @@ var CmdKeys = &cli.Command{
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)",
}, },
}, },
}
} }
func runKeys(ctx context.Context, c *cli.Command) error { func runKeys(ctx context.Context, c *cli.Command) error {
+18 -17
View File
@@ -112,35 +112,36 @@ func NewMainApp(appVer AppVersion) *cli.Command {
Usage: "Set custom path (defaults to '{WorkPath}/custom')", Usage: "Set custom path (defaults to '{WorkPath}/custom')",
}, },
} }
webCmd := newWebCommand()
// these sub-commands need to use a config file // these sub-commands need to use a config file
subCmdWithConfig := []*cli.Command{ subCmdWithConfig := []*cli.Command{
CmdWeb, webCmd,
CmdServ, newServCommand(),
CmdHook, newHookCommand(),
CmdKeys, NewKeysCommand(),
CmdDump, newDumpCommand(),
CmdAdmin, newAdminCommand(),
CmdMigrate, newMigrateCommand(),
CmdDoctor, newDoctorCommand(),
CmdManager, newManagerCommand(),
CmdEmbedded, newEmbeddedCommand(),
CmdMigrateStorage, newMigrateStorageCommand(),
CmdDumpRepository, newDumpRepositoryCommand(),
CmdRestoreRepository, newRestoreRepositoryCommand(),
CmdActions, newActionsCommand(),
} }
// these sub-commands do not need the config file, and they do not depend on any path or environment variable. // these sub-commands do not need the config file, and they do not depend on any path or environment variable.
subCmdStandalone := []*cli.Command{ subCmdStandalone := []*cli.Command{
cmdConfig(), cmdConfig(),
cmdCert(), cmdCert(),
CmdGenerate, newGenerateCommand(),
CmdDocs, newDocsCommand(),
} }
// TODO: we should eventually drop the default command, // TODO: we should eventually drop the default command,
// but not sure whether it would break Windows users who used to double-click the EXE to run. // but not sure whether it would break Windows users who used to double-click the EXE to run.
app.DefaultCommand = CmdWeb.Name app.DefaultCommand = webCmd.Name
app.Before = PrepareConsoleLoggerLevel(log.INFO) app.Before = PrepareConsoleLoggerLevel(log.INFO)
for i := range subCmdWithConfig { for i := range subCmdWithConfig {
+29 -15
View File
@@ -13,22 +13,24 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
var ( func newManagerCommand() *cli.Command {
// CmdManager represents the manager command return &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",
Commands: []*cli.Command{ Commands: []*cli.Command{
subcmdShutdown, newShutdownCommand(),
subcmdRestart, newRestartCommand(),
subcmdReloadTemplates, newReloadTemplatesCommand(),
subcmdFlushQueues, newFlushQueuesCommand(),
subcmdLogging, newLoggingCommand(),
subCmdProcesses, newProcessesCommand(),
}, },
} }
subcmdShutdown = &cli.Command{ }
func newShutdownCommand() *cli.Command {
return &cli.Command{
Name: "shutdown", Name: "shutdown",
Usage: "Gracefully shutdown the running process", Usage: "Gracefully shutdown the running process",
Flags: []cli.Flag{ Flags: []cli.Flag{
@@ -38,7 +40,10 @@ var (
}, },
Action: runShutdown, Action: runShutdown,
} }
subcmdRestart = &cli.Command{ }
func newRestartCommand() *cli.Command {
return &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{
@@ -48,7 +53,10 @@ var (
}, },
Action: runRestart, Action: runRestart,
} }
subcmdReloadTemplates = &cli.Command{ }
func newReloadTemplatesCommand() *cli.Command {
return &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{
@@ -58,7 +66,10 @@ var (
}, },
Action: runReloadTemplates, Action: runReloadTemplates,
} }
subcmdFlushQueues = &cli.Command{ }
func newFlushQueuesCommand() *cli.Command {
return &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,
@@ -77,7 +88,10 @@ var (
}, },
}, },
} }
subCmdProcesses = &cli.Command{ }
func newProcessesCommand() *cli.Command {
return &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,
@@ -107,7 +121,7 @@ var (
}, },
}, },
} }
) }
func runShutdown(ctx context.Context, c *cli.Command) error { func runShutdown(ctx context.Context, c *cli.Command) error {
setup(ctx, c.Bool("debug")) setup(ctx, c.Bool("debug"))
+8 -6
View File
@@ -15,8 +15,8 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
var ( func defaultLoggingFlags() []cli.Flag {
defaultLoggingFlags = []cli.Flag{ return []cli.Flag{
&cli.StringFlag{ &cli.StringFlag{
Name: "logger", Name: "logger",
Usage: `Logger name - will default to "default"`, Usage: `Logger name - will default to "default"`,
@@ -57,8 +57,10 @@ var (
Name: "debug", Name: "debug",
}, },
} }
}
subcmdLogging = &cli.Command{ func newLoggingCommand() *cli.Command {
return &cli.Command{
Name: "logging", Name: "logging",
Usage: "Adjust logging commands", Usage: "Adjust logging commands",
Commands: []*cli.Command{ Commands: []*cli.Command{
@@ -109,7 +111,7 @@ var (
{ {
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", Name: "filename",
Aliases: []string{"f"}, Aliases: []string{"f"},
@@ -150,7 +152,7 @@ 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", Name: "reconnect-on-message",
Aliases: []string{"R"}, Aliases: []string{"R"},
@@ -191,7 +193,7 @@ var (
}, },
}, },
} }
) }
func runRemoveLogger(ctx context.Context, c *cli.Command) error { func runRemoveLogger(ctx context.Context, c *cli.Command) error {
setup(ctx, c.Bool("debug")) setup(ctx, c.Bool("debug"))
+3 -2
View File
@@ -14,12 +14,13 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
// CmdMigrate represents the available migrate sub-command. func newMigrateCommand() *cli.Command {
var CmdMigrate = &cli.Command{ return &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.`,
Action: runMigrate, Action: runMigrate,
}
} }
func runMigrate(ctx context.Context, c *cli.Command) error { func runMigrate(ctx context.Context, c *cli.Command) error {
+3 -2
View File
@@ -25,8 +25,8 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
// CmdMigrateStorage represents the available migrate storage sub-command. func newMigrateStorageCommand() *cli.Command {
var CmdMigrateStorage = &cli.Command{ return &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",
@@ -126,6 +126,7 @@ var CmdMigrateStorage = &cli.Command{
Usage: "Azure Blob storage base path", Usage: "Azure Blob storage base path",
}, },
}, },
}
} }
func migrateAttachments(ctx context.Context, dstStorage storage.ObjectStorage) error { func migrateAttachments(ctx context.Context, dstStorage storage.ObjectStorage) error {
+3 -2
View File
@@ -13,8 +13,8 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
// CmdRestoreRepository represents the available restore a repository sub-command. func newRestoreRepositoryCommand() *cli.Command {
var CmdRestoreRepository = &cli.Command{ return &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.",
@@ -47,6 +47,7 @@ wiki, issues, labels, releases, release_assets, milestones, pull_requests, comme
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",
}, },
}, },
}
} }
func runRestoreRepository(ctx context.Context, c *cli.Command) error { func runRestoreRepository(ctx context.Context, c *cli.Command) error {
+3 -2
View File
@@ -35,8 +35,8 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
// CmdServ represents the available serv sub-command. func newServCommand() *cli.Command {
var CmdServ = &cli.Command{ return &cli.Command{
Name: "serv", Name: "serv",
Usage: "(internal) Should only be called by SSH shell", Usage: "(internal) Should only be called by SSH shell",
Description: "Serv provides access auth for repositories", Description: "Serv provides access auth for repositories",
@@ -51,6 +51,7 @@ var CmdServ = &cli.Command{
Name: "debug", Name: "debug",
}, },
}, },
}
} }
func setup(ctx context.Context, debug bool) { func setup(ctx context.Context, debug bool) {
+3 -2
View File
@@ -34,8 +34,8 @@ import (
// 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. func newWebCommand() *cli.Command {
var CmdWeb = &cli.Command{ return &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,
@@ -70,6 +70,7 @@ and it takes care of all the other things for you`,
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",
}, },
}, },
}
} }
func runHTTPRedirector() { func runHTTPRedirector() {
+3 -3
View File
@@ -10,7 +10,6 @@ import (
"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/test"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -38,13 +37,14 @@ 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) {
// FIXME: this test is not quite right. Each "command run" always re-initializes settings // FIXME: this test is not quite right. Each "command run" always re-initializes settings
defer test.MockVariableValue(&cmd.CmdKeys.Before, nil)() // don't re-initialize logger during the test keysCmd := cmd.NewKeysCommand()
keysCmd.Before = nil // don't re-initialize logger during the test
var stdout, stderr bytes.Buffer var stdout, stderr bytes.Buffer
app := &cli.Command{ app := &cli.Command{
Writer: &stdout, Writer: &stdout,
ErrWriter: &stderr, ErrWriter: &stderr,
Commands: []*cli.Command{cmd.CmdKeys}, Commands: []*cli.Command{keysCmd},
} }
err := app.Run(t.Context(), append([]string{"prog"}, tt.args...)) err := app.Run(t.Context(), append([]string{"prog"}, tt.args...))
if tt.wantErr { if tt.wantErr {