Skip to content

Commit 6554ee1

Browse files
committed
feat: update dependencies and add lifecycle helper functions
- Updated dependencies in go.mod and go.sum files across multiple extensions, including: - Added `github.com/dunglas/httpsfv v1.1.0` - Upgraded `github.com/quic-go/quic-go` to v0.59.0 - Upgraded `github.com/quic-go/webtransport-go` to v0.10.0 - Introduced lifecycle helper functions for better app lifecycle management: - `OnStarted`: Registers a hook that runs after the app has fully started. - `OnClose`: Registers a hook that runs before the app stops. - `OnBeforeRun`: Registers a hook that runs after Start but before the HTTP server begins listening. - `OnAfterRun`: Registers a hook that runs after the HTTP server starts listening. - `OnAfterRegister`: Registers a hook that runs after all extensions have been registered. - Added unit tests for the new lifecycle helper functions to ensure correct behavior and error handling.
1 parent 9476890 commit 6554ee1

102 files changed

Lines changed: 2159 additions & 284 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cli/app_runner.go

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
package cli
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"github.com/xraph/forge"
8+
)
9+
10+
// RunAppConfig configures the CLI app wrapper.
11+
type RunAppConfig struct {
12+
// App is the forge application to wrap (required).
13+
App forge.App
14+
15+
// Name overrides the CLI app name (defaults to app.Name()).
16+
Name string
17+
18+
// Version overrides the CLI version (defaults to app.Version()).
19+
Version string
20+
21+
// Description overrides the CLI description.
22+
Description string
23+
24+
// ExtraCommands are additional commands to register alongside
25+
// the built-in serve, migrate, info, health, and extensions commands.
26+
ExtraCommands []Command
27+
28+
// DisableMigrationCommands disables auto-registration of migrate commands
29+
// even when MigratableExtension extensions are present.
30+
DisableMigrationCommands bool
31+
32+
// DisableServeCommand disables the auto-registered serve command.
33+
DisableServeCommand bool
34+
35+
// AutoMigrateOnServe runs pending migrations before the HTTP server
36+
// starts when using the serve/start command. Migrations run during
37+
// PhaseBeforeRun, after all extensions are initialized.
38+
AutoMigrateOnServe bool
39+
}
40+
41+
// RunAppOption is a functional option for RunAppConfig.
42+
type RunAppOption func(*RunAppConfig)
43+
44+
// WithAutoMigrate enables running pending migrations before the app
45+
// starts serving when using the serve/start command.
46+
func WithAutoMigrate() RunAppOption {
47+
return func(c *RunAppConfig) { c.AutoMigrateOnServe = true }
48+
}
49+
50+
// WithExtraCommands adds additional commands to the CLI wrapper.
51+
func WithExtraCommands(cmds ...Command) RunAppOption {
52+
return func(c *RunAppConfig) { c.ExtraCommands = append(c.ExtraCommands, cmds...) }
53+
}
54+
55+
// WithDisableMigrationCommands disables auto-registration of migrate commands.
56+
func WithDisableMigrationCommands() RunAppOption {
57+
return func(c *RunAppConfig) { c.DisableMigrationCommands = true }
58+
}
59+
60+
// WithDisableServeCommand disables the auto-registered serve command.
61+
func WithDisableServeCommand() RunAppOption {
62+
return func(c *RunAppConfig) { c.DisableServeCommand = true }
63+
}
64+
65+
// WithCLIName overrides the CLI application name.
66+
func WithCLIName(name string) RunAppOption {
67+
return func(c *RunAppConfig) { c.Name = name }
68+
}
69+
70+
// WithCLIVersion overrides the CLI application version.
71+
func WithCLIVersion(version string) RunAppOption {
72+
return func(c *RunAppConfig) { c.Version = version }
73+
}
74+
75+
// WithCLIDescription overrides the CLI application description.
76+
func WithCLIDescription(description string) RunAppOption {
77+
return func(c *RunAppConfig) { c.Description = description }
78+
}
79+
80+
// RunApp wraps a forge app in a CLI application and runs it.
81+
// This is the primary entry point for CLI-wrapped forge applications.
82+
//
83+
// Default behavior:
84+
// - No args: runs the forge app via app.Run() (same as "serve")
85+
// - "serve" / "start" / "run": starts the forge app
86+
// - "migrate up": runs pending migrations from all MigratableExtension
87+
// - "migrate down": rolls back the last batch of migrations
88+
// - "migrate status": shows migration status
89+
// - "info": shows app information
90+
// - "health": checks app health
91+
// - "extensions": lists registered extensions
92+
// - Extensions implementing CLICommandProvider contribute their commands
93+
//
94+
// Example:
95+
//
96+
// func main() {
97+
// app := forge.New(
98+
// forge.WithAppName("my-app"),
99+
// forge.WithExtensions(groveExt),
100+
// )
101+
// cli.RunApp(app)
102+
// }
103+
//
104+
// // With auto-migration:
105+
// func main() {
106+
// app := forge.New(...)
107+
// cli.RunApp(app, cli.WithAutoMigrate())
108+
// }
109+
func RunApp(app forge.App, opts ...RunAppOption) {
110+
config := RunAppConfig{
111+
App: app,
112+
}
113+
for _, opt := range opts {
114+
opt(&config)
115+
}
116+
117+
if config.Name == "" {
118+
config.Name = app.Name()
119+
}
120+
if config.Version == "" {
121+
config.Version = app.Version()
122+
}
123+
124+
// Build CLI
125+
c := New(Config{
126+
Name: config.Name,
127+
Version: config.Version,
128+
Description: config.Description,
129+
App: app,
130+
})
131+
132+
// 1. Register serve command (default command)
133+
if !config.DisableServeCommand {
134+
serveCmd := buildServeCommand(app, config.AutoMigrateOnServe)
135+
if err := c.AddCommand(serveCmd); err != nil {
136+
app.Logger().Warn("failed to add serve command", forge.F("error", err))
137+
}
138+
}
139+
140+
// 2. Register migration commands from MigratableExtension extensions
141+
if !config.DisableMigrationCommands {
142+
migrateCmd := buildMigrateCommand(app)
143+
if err := c.AddCommand(migrateCmd); err != nil {
144+
app.Logger().Warn("failed to add migrate command", forge.F("error", err))
145+
}
146+
}
147+
148+
// 3. Register standard forge commands (info, health, extensions)
149+
addForgeCommands(c, app)
150+
151+
// 4. Register extension-contributed commands
152+
registerExtensionCommands(c, app)
153+
154+
// 5. Register extra commands
155+
for _, cmd := range config.ExtraCommands {
156+
if err := c.AddCommand(cmd); err != nil {
157+
app.Logger().Warn("failed to add extra command",
158+
forge.F("command", cmd.Name()),
159+
forge.F("error", err),
160+
)
161+
}
162+
}
163+
164+
// Run CLI — if no command provided, default to "serve"
165+
args := os.Args
166+
if len(args) <= 1 {
167+
args = append(args, "serve")
168+
}
169+
170+
if err := c.Run(args); err != nil {
171+
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
172+
os.Exit(GetExitCode(err))
173+
}
174+
}

0 commit comments

Comments
 (0)