Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
cf638ac
chore: gitignore /tmp for storing temporary data
protibimbok Nov 6, 2026
109af1d
feat(support): add path.CleanRelative
protibimbok Nov 6, 2026
3e5a79a
fix(foundation): key service providers by their full type path
protibimbok Nov 6, 2026
95f8357
feat(modular): add the module contracts and registry
protibimbok Nov 6, 2026
210d46d
mocks: generated modular mocks
protibimbok Nov 6, 2026
41c56b2
feat(modular): add filesystems for module views, translations and static
protibimbok Nov 11, 2026
3f42756
feat(foundation): add WithModules and the module registry binding
protibimbok Nov 11, 2026
63e6d15
feat(foundation): merge module contributions into Build
protibimbok Nov 11, 2026
e5aa538
feat(packages): add module helpers to modify and match
protibimbok Nov 11, 2026
227870e
feat(modular): add modular:init
protibimbok Nov 11, 2026
9d86c10
feat(modular): add make:module
protibimbok Nov 11, 2026
d210351
feat(modular): add ProvidesSources and modular:publish
protibimbok Nov 11, 2026
69b6712
feat(modular): add modular:list
protibimbok Nov 11, 2026
126987a
Merge branch 'master' into feat/modular
protibimbok Nov 11, 2026
53ea74e
feat(vite): list modules and their entries in vite:inputs
protibimbok Nov 11, 2026
5a11ff3
feat(vite): resolve alias entries through the manifest and hot file
protibimbok Nov 11, 2026
c7896a1
feat(packages): add AddToModule and match.ModuleMethod
protibimbok Nov 11, 2026
d105579
feat(console): add the --module option to the make commands
protibimbok Nov 11, 2026
3a6eba6
feat(database): make:migration --module
protibimbok Nov 11, 2026
b5562eb
feat(modular): register generated commands, jobs, seeders and providers
protibimbok Nov 11, 2026
a2710da
chore: tidy tests/go.sum
protibimbok Nov 11, 2026
f4895f1
fix: improve code coverage
protibimbok Nov 11, 2026
6690c1c
fix(database): fall back to the framework facades in migration stubs
protibimbok Nov 13, 2026
abc4c49
fix(modular): require kebab-case module names
protibimbok Nov 13, 2026
16bf75a
fix(modular): keep edited stubs on make:module --force
protibimbok Nov 13, 2026
5904ce7
fix(foundation): do not change the WithEvents map when adding module
protibimbok Nov 13, 2026
395c57c
fix(vite): reject module Vite entries outside the module
protibimbok Nov 13, 2026
f5fd0d0
fix: apply correct directory separator on windows
protibimbok Nov 13, 2026
36cf220
test(modular): cover modular:init with an unparsable app.go
protibimbok Nov 13, 2026
17cc615
refactor: remove CreateIn and add dir param in the Create instead in
protibimbok Nov 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
.vscode
/vendor
coverage.out
.opencode
.opencode
/tmp
1 change: 1 addition & 0 deletions ai/console/agent_make_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func (r *AgentMakeCommand) Extend() command.Extend {
Aliases: []string{"f"},
Usage: "Create the agent even if it already exists",
},
supportconsole.ModuleFlag(),
},
}
}
Expand Down
7 changes: 6 additions & 1 deletion ai/console/agent_make_command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func TestAgentMakeCommand(t *testing.T) {

extend := agentMakeCommand.Extend()
assert.Equal(t, "make", extend.Category)
if assert.Len(t, extend.Flags, 1) {
if assert.Len(t, extend.Flags, 2) {
flag, ok := extend.Flags[0].(*command.BoolFlag)
assert.True(t, ok)
if ok {
Expand All @@ -44,17 +44,20 @@ func TestAgentMakeCommand(t *testing.T) {
assert.NoError(t, agentMakeCommand.Handle(mockContext))

mockContext.EXPECT().Arguments().Return([]string{"UserAgent"}).Once()
mockContext.EXPECT().Option("module").Return("").Once()
mockContext.EXPECT().OptionBool("force").Return(false).Once()
mockContext.EXPECT().Success("Agent created successfully").Once()
assert.NoError(t, agentMakeCommand.Handle(mockContext))
assert.True(t, file.Exists("app/ai/agents/user_agent.go"))

mockContext.EXPECT().Arguments().Return([]string{"UserAgent"}).Once()
mockContext.EXPECT().Option("module").Return("").Once()
mockContext.EXPECT().OptionBool("force").Return(false).Once()
mockContext.EXPECT().Error("the agent already exists. Use the --force or -f flag to overwrite").Once()
assert.NoError(t, agentMakeCommand.Handle(mockContext))

mockContext.EXPECT().Arguments().Return([]string{"user/SupportAgent"}).Once()
mockContext.EXPECT().Option("module").Return("").Once()
mockContext.EXPECT().OptionBool("force").Return(false).Once()
mockContext.EXPECT().Success("Agent created successfully").Once()
assert.NoError(t, agentMakeCommand.Handle(mockContext))
Expand All @@ -67,6 +70,7 @@ func TestAgentMakeCommand(t *testing.T) {

support.Config.Paths.Agents = "custom/agents"
mockContext.EXPECT().Arguments().Return([]string{"BillingAgent"}).Once()
mockContext.EXPECT().Option("module").Return("").Once()
mockContext.EXPECT().OptionBool("force").Return(false).Once()
mockContext.EXPECT().Success("Agent created successfully").Once()
assert.NoError(t, agentMakeCommand.Handle(mockContext))
Expand All @@ -81,6 +85,7 @@ func TestAgentMakeCommand_MultipleNames(t *testing.T) {
}()

mockContext.EXPECT().Arguments().Return([]string{"SupportAgent", "BillingAgent"}).Once()
mockContext.EXPECT().Option("module").Return("").Times(2)
mockContext.EXPECT().OptionBool("force").Return(false).Times(2)
mockContext.EXPECT().Success("Agent created successfully").Times(2)
assert.NoError(t, agentMakeCommand.Handle(mockContext))
Expand Down
1 change: 1 addition & 0 deletions ai/console/tool_make_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ func (r *ToolMakeCommand) Extend() command.Extend {
Aliases: []string{"f"},
Usage: "Create the tool even if it already exists",
},
supportconsole.ModuleFlag(),
},
}
}
Expand Down
7 changes: 6 additions & 1 deletion ai/console/tool_make_command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func TestToolMakeCommand(t *testing.T) {

extend := toolMakeCommand.Extend()
assert.Equal(t, "make", extend.Category)
if assert.Len(t, extend.Flags, 1) {
if assert.Len(t, extend.Flags, 2) {
flag, ok := extend.Flags[0].(*command.BoolFlag)
assert.True(t, ok)
if ok {
Expand All @@ -44,17 +44,20 @@ func TestToolMakeCommand(t *testing.T) {
assert.NoError(t, toolMakeCommand.Handle(mockContext))

mockContext.EXPECT().Arguments().Return([]string{"WeatherTool"}).Once()
mockContext.EXPECT().Option("module").Return("").Once()
mockContext.EXPECT().OptionBool("force").Return(false).Once()
mockContext.EXPECT().Success("Tool created successfully").Once()
assert.NoError(t, toolMakeCommand.Handle(mockContext))
assert.True(t, file.Exists("app/ai/tools/weather_tool.go"))

mockContext.EXPECT().Arguments().Return([]string{"WeatherTool"}).Once()
mockContext.EXPECT().Option("module").Return("").Once()
mockContext.EXPECT().OptionBool("force").Return(false).Once()
mockContext.EXPECT().Error("the tool already exists. Use the --force or -f flag to overwrite").Once()
assert.NoError(t, toolMakeCommand.Handle(mockContext))

mockContext.EXPECT().Arguments().Return([]string{"user/WeatherTool"}).Once()
mockContext.EXPECT().Option("module").Return("").Once()
mockContext.EXPECT().OptionBool("force").Return(false).Once()
mockContext.EXPECT().Success("Tool created successfully").Once()
assert.NoError(t, toolMakeCommand.Handle(mockContext))
Expand All @@ -71,6 +74,7 @@ func TestToolMakeCommand(t *testing.T) {

support.Config.Paths.Tools = "custom/tools"
mockContext.EXPECT().Arguments().Return([]string{"CurrencyTool"}).Once()
mockContext.EXPECT().Option("module").Return("").Once()
mockContext.EXPECT().OptionBool("force").Return(false).Once()
mockContext.EXPECT().Success("Tool created successfully").Once()
assert.NoError(t, toolMakeCommand.Handle(mockContext))
Expand All @@ -85,6 +89,7 @@ func TestToolMakeCommand_MultipleNames(t *testing.T) {
}()

mockContext.EXPECT().Arguments().Return([]string{"WeatherTool", "CurrencyTool"}).Once()
mockContext.EXPECT().Option("module").Return("").Times(2)
mockContext.EXPECT().OptionBool("force").Return(false).Times(2)
mockContext.EXPECT().Success("Tool created successfully").Times(2)
assert.NoError(t, toolMakeCommand.Handle(mockContext))
Expand Down
28 changes: 28 additions & 0 deletions auth/console/module_flag_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package console

import (
"testing"

"github.com/stretchr/testify/assert"

"github.com/goravel/framework/contracts/console"
"github.com/goravel/framework/contracts/console/command"
)

// Every make command of the package accepts --module.
func TestMakeCommands_ModuleFlag(t *testing.T) {
commands := []console.Command{
NewPolicyMakeCommand(),
}

for _, cmd := range commands {
var names []string
for _, flag := range cmd.Extend().Flags {
if f, ok := flag.(*command.StringFlag); ok {
names = append(names, f.Name)
}
}

assert.Contains(t, names, "module", cmd.Signature())
}
}
1 change: 1 addition & 0 deletions auth/console/policy_make_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ func (r *PolicyMakeCommand) Extend() command.Extend {
Aliases: []string{"f"},
Usage: "Create the policy even if it already exists",
},
supportconsole.ModuleFlag(),
},
}
}
Expand Down
4 changes: 4 additions & 0 deletions auth/console/policy_make_command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,20 @@ func TestPolicyMakeCommand(t *testing.T) {
assert.Nil(t, policyMakeCommand.Handle(mockContext))

mockContext.EXPECT().Arguments().Return([]string{"UserPolicy"}).Once()
mockContext.EXPECT().Option("module").Return("").Once()
mockContext.EXPECT().OptionBool("force").Return(false).Once()
mockContext.EXPECT().Success("Policy created successfully").Once()
assert.Nil(t, policyMakeCommand.Handle(mockContext))
assert.True(t, file.Exists("app/policies/user_policy.go"))

mockContext.EXPECT().Arguments().Return([]string{"UserPolicy"}).Once()
mockContext.EXPECT().Option("module").Return("").Once()
mockContext.EXPECT().OptionBool("force").Return(false).Once()
mockContext.EXPECT().Error("the policy already exists. Use the --force or -f flag to overwrite").Once()
assert.Nil(t, policyMakeCommand.Handle(mockContext))

mockContext.EXPECT().Arguments().Return([]string{"User/AuthPolicy"}).Once()
mockContext.EXPECT().Option("module").Return("").Once()
mockContext.EXPECT().OptionBool("force").Return(false).Once()
mockContext.EXPECT().Success("Policy created successfully").Once()
assert.Nil(t, policyMakeCommand.Handle(mockContext))
Expand All @@ -50,6 +53,7 @@ func TestPolicyMakeCommand_MultipleNames(t *testing.T) {
mockContext := mocksconsole.NewContext(t)

mockContext.EXPECT().Arguments().Return([]string{"PostPolicy", "CommentPolicy"}).Once()
mockContext.EXPECT().Option("module").Return("").Times(2)
mockContext.EXPECT().OptionBool("force").Return(false).Times(2)
mockContext.EXPECT().Success("Policy created successfully").Times(2)
assert.Nil(t, policyMakeCommand.Handle(mockContext))
Expand Down
1 change: 1 addition & 0 deletions broadcasting/console/channel_make_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func (r *ChannelMakeCommand) Extend() command.Extend {
Aliases: []string{"f"},
Usage: "Create the channel even if it already exists",
},
supportconsole.ModuleFlag(),
},
}
}
Expand Down
2 changes: 2 additions & 0 deletions broadcasting/console/channel_make_command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ func TestChannelMakeCommand(t *testing.T) {
t.Run("success", func(t *testing.T) {
mockContext := mocksconsole.NewContext(t)
mockContext.EXPECT().Arguments().Return([]string{"TestChannel"}).Once()
mockContext.EXPECT().Option("module").Return("").Once()
mockContext.EXPECT().OptionBool("force").Return(false).Once()
mockContext.EXPECT().Success("Channel created successfully").Once()
assert.Nil(t, cmd.Handle(mockContext))
Expand All @@ -51,6 +52,7 @@ func TestChannelMakeCommand_MultipleNames(t *testing.T) {
mockContext := mocksconsole.NewContext(t)

mockContext.EXPECT().Arguments().Return([]string{"OrderChannel", "UserChannel"}).Once()
mockContext.EXPECT().Option("module").Return("").Times(2)
mockContext.EXPECT().OptionBool("force").Return(false).Times(2)
mockContext.EXPECT().Success("Channel created successfully").Times(2)
assert.Nil(t, cmd.Handle(mockContext))
Expand Down
28 changes: 28 additions & 0 deletions broadcasting/console/module_flag_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package console

import (
"testing"

"github.com/stretchr/testify/assert"

"github.com/goravel/framework/contracts/console"
"github.com/goravel/framework/contracts/console/command"
)

// Every make command of the package accepts --module.
func TestMakeCommands_ModuleFlag(t *testing.T) {
commands := []console.Command{
NewChannelMakeCommand(),
}

for _, cmd := range commands {
var names []string
for _, flag := range cmd.Extend().Flags {
if f, ok := flag.(*command.StringFlag); ok {
names = append(names, f.Name)
}
}

assert.Contains(t, names, "module", cmd.Signature())
}
}
5 changes: 4 additions & 1 deletion console/console/make_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ func (r *MakeCommand) Extend() command.Extend {
Usage: "Create the command even if it already exists",
DisableDefaultText: true,
},
supportconsole.ModuleFlag(),
},
}
}
Expand All @@ -69,7 +70,9 @@ func (r *MakeCommand) makeOne(ctx console.Context, name string) error {

ctx.Success("Console command created successfully")

if env.IsBootstrapSetup() {
if dir := make.GetModuleDir(); dir != "" {
err = modify.AddToModule(dir, "Commands", make.GetPackageImportPath(), fmt.Sprintf("&%s.%s{}", make.GetPackageName(), make.GetStructName()))
} else if env.IsBootstrapSetup() {
err = modify.AddCommand(make.GetPackageImportPath(), fmt.Sprintf("&%s.%s{}", make.GetPackageName(), make.GetStructName()))
} else {
err = r.registerInKernel(make)
Expand Down
1 change: 1 addition & 0 deletions console/console/make_command_hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ func (r *MakeCommandHook) Extend() command.Extend {
Aliases: []string{"c"},
Usage: "The command signature or '*' pattern the hook runs for, default is '*'",
},
supportconsole.ModuleFlag(),
},
}
}
Expand Down
8 changes: 8 additions & 0 deletions console/console/make_command_hook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ func TestMakeCommandHook(t *testing.T) {
mockContext := mocksconsole.NewContext(t)
mockContext.EXPECT().Option("command").Return("").Once()
mockContext.EXPECT().Arguments().Return([]string{"AuditLog"}).Once()
mockContext.EXPECT().Option("module").Return("").Once()
mockContext.EXPECT().OptionBool("force").Return(false).Once()
mockContext.EXPECT().Error("the command hook already exists. Use the --force or -f flag to overwrite").Once()

Expand All @@ -130,6 +131,7 @@ func TestMakeCommandHook(t *testing.T) {
mockContext := mocksconsole.NewContext(t)
mockContext.EXPECT().Option("command").Return("*").Once()
mockContext.EXPECT().Arguments().Return([]string{"AuditLog"}).Once()
mockContext.EXPECT().Option("module").Return("").Once()
mockContext.EXPECT().OptionBool("force").Return(true).Once()
mockContext.EXPECT().Success("Command hook created successfully").Once()
mockContext.EXPECT().Warning(mock.Anything).Once()
Expand All @@ -145,6 +147,7 @@ func TestMakeCommandHook(t *testing.T) {
mockContext.EXPECT().Option("command").Return("").Once()
mockContext.EXPECT().Arguments().Return([]string{"AuditLog"}).Once()
mockContext.EXPECT().Ask("Enter the command signature the hook runs for", mock.Anything).Return("*", nil).Once()
mockContext.EXPECT().Option("module").Return("").Once()
mockContext.EXPECT().OptionBool("force").Return(false).Once()
mockContext.EXPECT().Success("Command hook created successfully").Once()
mockContext.EXPECT().Warning("Command hook created but not registered, add it to WithCommandHooks in bootstrap/app.go manually").Once()
Expand All @@ -168,6 +171,7 @@ func TestMakeCommandHook(t *testing.T) {
mockContext := mocksconsole.NewContext(t)
mockContext.EXPECT().Option("command").Return("migrate").Once()
mockContext.EXPECT().Arguments().Return([]string{"AuditLog"}).Once()
mockContext.EXPECT().Option("module").Return("").Once()
mockContext.EXPECT().OptionBool("force").Return(false).Once()
mockContext.EXPECT().Success("Command hook created successfully").Once()
mockContext.EXPECT().Success("Command hook registered successfully").Once()
Expand All @@ -191,6 +195,7 @@ func TestMakeCommandHook(t *testing.T) {
mockContext := mocksconsole.NewContext(t)
mockContext.EXPECT().Option("command").Return("migrate").Once()
mockContext.EXPECT().Arguments().Return([]string{"AuditLog"}).Once()
mockContext.EXPECT().Option("module").Return("").Once()
mockContext.EXPECT().OptionBool("force").Return(false).Once()
mockContext.EXPECT().Success("Command hook created successfully").Once()
mockContext.EXPECT().Success("Command hook registered successfully").Once()
Expand All @@ -217,6 +222,7 @@ func TestMakeCommandHook(t *testing.T) {
mockContext := mocksconsole.NewContext(t)
mockContext.EXPECT().Option("command").Return("migrate").Once()
mockContext.EXPECT().Arguments().Return([]string{"AuditLog"}).Once()
mockContext.EXPECT().Option("module").Return("").Once()
mockContext.EXPECT().OptionBool("force").Return(false).Once()
mockContext.EXPECT().Success("Command hook created successfully").Once()
mockContext.EXPECT().Success("Command hook registered successfully").Once()
Expand All @@ -242,6 +248,7 @@ func TestMakeCommandHook(t *testing.T) {
mockContext := mocksconsole.NewContext(t)
mockContext.EXPECT().Option("command").Return("migrate").Once()
mockContext.EXPECT().Arguments().Return([]string{"AuditLog"}).Once()
mockContext.EXPECT().Option("module").Return("").Once()
mockContext.EXPECT().OptionBool("force").Return(false).Once()
mockContext.EXPECT().Success("Command hook created successfully").Once()
mockContext.EXPECT().Error(mock.MatchedBy(func(message string) bool {
Expand All @@ -259,6 +266,7 @@ func TestMakeCommandHook(t *testing.T) {
mockContext := mocksconsole.NewContext(t)
mockContext.EXPECT().Option("command").Return("migrate").Once()
mockContext.EXPECT().Arguments().Return([]string{"AuditLog", "SlowQuery"}).Once()
mockContext.EXPECT().Option("module").Return("").Times(2)
mockContext.EXPECT().OptionBool("force").Return(false).Times(2)
mockContext.EXPECT().Success("Command hook created successfully").Times(2)
mockContext.EXPECT().Success("Command hook registered successfully").Times(2)
Expand Down
Loading
Loading