Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
64 changes: 38 additions & 26 deletions cli/azd/cmd/middleware/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,81 +14,90 @@ import (
"github.com/azure/azure-dev/cli/azd/pkg/ext"
"github.com/azure/azure-dev/cli/azd/pkg/input"
"github.com/azure/azure-dev/cli/azd/pkg/ioc"
"github.com/azure/azure-dev/cli/azd/pkg/lazy"
"github.com/azure/azure-dev/cli/azd/pkg/output/ux"
"github.com/azure/azure-dev/cli/azd/pkg/project"
)

type HooksMiddleware struct {
envManager environment.Manager
env *environment.Environment
projectConfig *project.ProjectConfig
importManager *project.ImportManager
commandRunner exec.CommandRunner
console input.Console
options *Options
serviceLocator ioc.ServiceLocator
envManager environment.Manager
env *environment.Environment
lazyProjectConfig *lazy.Lazy[*project.ProjectConfig]
importManager *project.ImportManager
commandRunner exec.CommandRunner
console input.Console
options *Options
serviceLocator ioc.ServiceLocator
}

// Creates a new instance of the Hooks middleware
func NewHooksMiddleware(
envManager environment.Manager,
env *environment.Environment,
projectConfig *project.ProjectConfig,
lazyProjectConfig *lazy.Lazy[*project.ProjectConfig],
importManager *project.ImportManager,
commandRunner exec.CommandRunner,
console input.Console,
options *Options,
serviceLocator ioc.ServiceLocator,
) Middleware {
return &HooksMiddleware{
envManager: envManager,
env: env,
projectConfig: projectConfig,
importManager: importManager,
commandRunner: commandRunner,
console: console,
options: options,
serviceLocator: serviceLocator,
envManager: envManager,
env: env,
lazyProjectConfig: lazyProjectConfig,
importManager: importManager,
commandRunner: commandRunner,
console: console,
options: options,
serviceLocator: serviceLocator,
}
}

// Runs the Hooks middleware
func (m *HooksMiddleware) Run(ctx context.Context, next NextFn) (*actions.ActionResult, error) {
projectConfig, err := m.lazyProjectConfig.GetValue()
if err != nil || projectConfig == nil {
log.Println("azd project is not available, skipping all hook registrations.")
return next(ctx)
}

// Validate hooks and display any warnings
if !m.options.IsChildAction(ctx) {
if err := m.validateHooks(ctx, m.projectConfig); err != nil {
if err := m.validateHooks(ctx, projectConfig); err != nil {
return nil, fmt.Errorf("failed validating hooks, %w", err)
}
}

if err := m.registerServiceHooks(ctx); err != nil {
if err := m.registerServiceHooks(ctx, projectConfig); err != nil {
return nil, fmt.Errorf("failed registering service hooks, %w", err)
}

return m.registerCommandHooks(ctx, next)
return m.registerCommandHooks(ctx, projectConfig, next)
}

// Register command level hooks for the executing cobra command & action
// Invokes the middleware next function

func (m *HooksMiddleware) registerCommandHooks(
ctx context.Context,
projectConfig *project.ProjectConfig,
next NextFn,
) (*actions.ActionResult, error) {
if len(m.projectConfig.Hooks) == 0 {
if len(projectConfig.Hooks) == 0 {
log.Println(
"azd project does not contain any command hooks, skipping command hook registrations.",
)
return next(ctx)
}

hooksManager := ext.NewHooksManager(m.projectConfig.Path, m.commandRunner)
hooksManager := ext.NewHooksManager(projectConfig.Path, m.commandRunner)
hooksRunner := ext.NewHooksRunner(
hooksManager,
m.commandRunner,
m.envManager,
m.console,
m.projectConfig.Path,
m.projectConfig.Hooks,
projectConfig.Path,
projectConfig.Hooks,
m.env,
m.serviceLocator,
)
Expand Down Expand Up @@ -117,8 +126,11 @@ func (m *HooksMiddleware) registerCommandHooks(

// Registers event handlers for all services within the project configuration
// Runs hooks for each matching event handler
func (m *HooksMiddleware) registerServiceHooks(ctx context.Context) error {
stableServices, err := m.importManager.ServiceStable(ctx, m.projectConfig)
func (m *HooksMiddleware) registerServiceHooks(
ctx context.Context,
projectConfig *project.ProjectConfig,
) error {
stableServices, err := m.importManager.ServiceStable(ctx, projectConfig)
if err != nil {
return fmt.Errorf("failed getting services: %w", err)
}
Expand Down
33 changes: 32 additions & 1 deletion cli/azd/cmd/middleware/hooks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/azure/azure-dev/cli/azd/pkg/environment/azdcontext"
"github.com/azure/azure-dev/cli/azd/pkg/exec"
"github.com/azure/azure-dev/cli/azd/pkg/ext"
"github.com/azure/azure-dev/cli/azd/pkg/lazy"
"github.com/azure/azure-dev/cli/azd/pkg/project"
"github.com/azure/azure-dev/cli/azd/test/mocks"
"github.com/azure/azure-dev/cli/azd/test/mocks/mockenv"
Expand Down Expand Up @@ -288,6 +289,34 @@ func Test_ServiceHooks_Registered(t *testing.T) {
require.Equal(t, 1, preDeployCount)
}

func Test_HooksMiddleware_SkipsWhenProjectUnavailable(t *testing.T) {
mockContext := mocks.NewMockContext(context.Background())
envManager := &mockenv.MockEnvManager{}
env := environment.New("test")

lazyProjectConfig := lazy.NewLazy(func() (*project.ProjectConfig, error) {
return nil, errors.New("failed to load project")
})

middleware := NewHooksMiddleware(
envManager,
env,
lazyProjectConfig,
project.NewImportManager(nil),
mockContext.CommandRunner,
mockContext.Console,
&Options{CommandPath: "command"},
mockContext.Container,
)

nextFn, actionRan := createNextFn()
result, err := middleware.Run(*mockContext.Context, nextFn)

require.NoError(t, err)
require.NotNil(t, result)
require.True(t, *actionRan)
}

func createAzdContext(t *testing.T) *azdcontext.AzdContext {
tempDir := t.TempDir()
ostest.Chdir(t, tempDir)
Expand Down Expand Up @@ -343,10 +372,12 @@ func runMiddleware(
envManager.On("Save", mock.Anything, mock.Anything).Return(nil)
envManager.On("Reload", mock.Anything, mock.Anything).Return(nil)

lazyProjectConfig := lazy.From(projectConfig)

middleware := NewHooksMiddleware(
envManager,
env,
projectConfig,
lazyProjectConfig,
project.NewImportManager(nil),
mockContext.CommandRunner,
mockContext.Console,
Expand Down
Loading