From 0ea3f546cb7390c50e2b43bcc7c6bf4cddb52123 Mon Sep 17 00:00:00 2001 From: Thulio Ferraz Assis <3149049+f0rmiga@users.noreply.github.com> Date: Fri, 14 Jan 2022 08:53:03 -0800 Subject: [PATCH] feat: post-run hook (#111) --- cmd/aspect/run/run.go | 3 +- pkg/plugin/sdk/v1alpha2/plugin/grpc.go | 40 +++++++++++++++++++++ pkg/plugin/sdk/v1alpha2/plugin/interface.go | 4 +++ pkg/plugin/sdk/v1alpha2/proto/plugin.proto | 8 +++++ pkg/plugin/system/system.go | 7 ++++ plugins/fix-visibility/plugin.go | 15 +++++--- 6 files changed, 71 insertions(+), 6 deletions(-) diff --git a/cmd/aspect/run/run.go b/cmd/aspect/run/run.go index 56ea15a41..07fd9ea13 100644 --- a/cmd/aspect/run/run.go +++ b/cmd/aspect/run/run.go @@ -49,10 +49,9 @@ use 'bazel run --script_path' to write a script and then execute it. []interceptors.Interceptor{ interceptors.WorkspaceRootInterceptor(), pluginSystem.BESBackendInterceptor(), + pluginSystem.RunHooksInterceptor(streams), }, func(ctx context.Context, cmd *cobra.Command, args []string) (exitErr error) { - // TODO(f0rmiga): post-run hook. - workspaceRoot := ctx.Value(interceptors.WorkspaceRootKey).(string) bzl.SetWorkspaceRoot(workspaceRoot) r := run.New(streams, bzl) diff --git a/pkg/plugin/sdk/v1alpha2/plugin/grpc.go b/pkg/plugin/sdk/v1alpha2/plugin/grpc.go index bfafb05cf..3207c6262 100644 --- a/pkg/plugin/sdk/v1alpha2/plugin/grpc.go +++ b/pkg/plugin/sdk/v1alpha2/plugin/grpc.go @@ -93,6 +93,25 @@ func (m *GRPCServer) PostTestHook( m.Impl.PostTestHook(req.IsInteractiveMode, prompter) } +// PostRunHook translates the gRPC call to the Plugin PostRunHook +// implementation. It starts a prompt runner that is passed to the Plugin +// instance to be able to perform prompt actions to the CLI user. +func (m *GRPCServer) PostRunHook( + ctx context.Context, + req *proto.PostRunHookReq, +) (*proto.PostRunHookRes, error) { + conn, err := m.broker.Dial(req.BrokerId) + if err != nil { + return nil, err + } + defer conn.Close() + + client := proto.NewPrompterClient(conn) + prompter := &PrompterGRPCClient{client: client} + return &proto.PostRunHookRes{}, + m.Impl.PostRunHook(req.IsInteractiveMode, prompter) +} + // GRPCClient implements the gRPC client that is used by the Core to communicate // with the Plugin instances. type GRPCClient struct { @@ -149,6 +168,27 @@ func (m *GRPCClient) PostTestHook(isInteractiveMode bool, promptRunner ioutils.P return err } +// PostRunHook is called from the Core to execute the Plugin PostRunHook. It +// starts the prompt runner server with the provided PromptRunner. +func (m *GRPCClient) PostRunHook(isInteractiveMode bool, promptRunner ioutils.PromptRunner) error { + prompterServer := &PrompterGRPCServer{promptRunner: promptRunner} + var s *grpc.Server + serverFunc := func(opts []grpc.ServerOption) *grpc.Server { + s = grpc.NewServer(opts...) + proto.RegisterPrompterServer(s, prompterServer) + return s + } + brokerID := m.broker.NextId() + go m.broker.AcceptAndServe(brokerID, serverFunc) + req := &proto.PostRunHookReq{ + BrokerId: brokerID, + IsInteractiveMode: isInteractiveMode, + } + _, err := m.client.PostRunHook(context.Background(), req) + s.Stop() + return err +} + // PrompterGRPCServer implements the gRPC server that runs on the Core and is // passed to the Plugin to allow prompt actions to the CLI user. type PrompterGRPCServer struct { diff --git a/pkg/plugin/sdk/v1alpha2/plugin/interface.go b/pkg/plugin/sdk/v1alpha2/plugin/interface.go index fdc03448d..083bf1932 100644 --- a/pkg/plugin/sdk/v1alpha2/plugin/interface.go +++ b/pkg/plugin/sdk/v1alpha2/plugin/interface.go @@ -22,4 +22,8 @@ type Plugin interface { isInteractiveMode bool, promptRunner ioutils.PromptRunner, ) error + PostRunHook( + isInteractiveMode bool, + promptRunner ioutils.PromptRunner, + ) error } diff --git a/pkg/plugin/sdk/v1alpha2/proto/plugin.proto b/pkg/plugin/sdk/v1alpha2/proto/plugin.proto index 268db47ac..bc6606059 100644 --- a/pkg/plugin/sdk/v1alpha2/proto/plugin.proto +++ b/pkg/plugin/sdk/v1alpha2/proto/plugin.proto @@ -11,6 +11,7 @@ service Plugin { rpc BEPEventCallback(BEPEventCallbackReq) returns (BEPEventCallbackRes); rpc PostBuildHook(PostBuildHookReq) returns (PostBuildHookRes); rpc PostTestHook(PostTestHookReq) returns (PostTestHookRes); + rpc PostRunHook(PostRunHookReq) returns (PostRunHookRes); } message BEPEventCallbackReq { @@ -33,6 +34,13 @@ message PostTestHookReq { message PostTestHookRes {} +message PostRunHookReq { + uint32 broker_id = 1; + bool is_interactive_mode = 2; +} + +message PostRunHookRes {} + // Prompter is the service used by the Plugin instances to request prompt // actions to the Core from the CLI users. service Prompter { diff --git a/pkg/plugin/system/system.go b/pkg/plugin/system/system.go index 417f7cdac..1c4672400 100644 --- a/pkg/plugin/system/system.go +++ b/pkg/plugin/system/system.go @@ -35,6 +35,7 @@ type PluginSystem interface { BESBackendInterceptor() interceptors.Interceptor BuildHooksInterceptor(streams ioutils.Streams) interceptors.Interceptor TestHooksInterceptor(streams ioutils.Streams) interceptors.Interceptor + RunHooksInterceptor(streams ioutils.Streams) interceptors.Interceptor } type pluginSystem struct { @@ -160,6 +161,12 @@ func (ps *pluginSystem) TestHooksInterceptor(streams ioutils.Streams) intercepto return ps.commandHooksInterceptor("PostTestHook", streams) } +// TestHooksInterceptor returns an interceptor that runs the pre and post-test +// hooks from all plugins. +func (ps *pluginSystem) RunHooksInterceptor(streams ioutils.Streams) interceptors.Interceptor { + return ps.commandHooksInterceptor("PostRunHook", streams) +} + func (ps *pluginSystem) commandHooksInterceptor(methodName string, streams ioutils.Streams) interceptors.Interceptor { return func(ctx context.Context, cmd *cobra.Command, args []string, next interceptors.RunEContextFn) (exitErr error) { isInteractiveMode, err := cmd.Root().PersistentFlags().GetBool(rootFlags.InteractiveFlagName) diff --git a/plugins/fix-visibility/plugin.go b/plugins/fix-visibility/plugin.go index 4ce1dd1f0..ef0640ee3 100644 --- a/plugins/fix-visibility/plugin.go +++ b/plugins/fix-visibility/plugin.go @@ -154,10 +154,8 @@ func (plugin *FixVisibilityPlugin) PostBuildHook( return nil } -// PostTestHook satisfies the Plugin interface. It prompts the user for -// automatic fixes when in interactive mode. If the user rejects the automatic -// fixes, or if running in non-interactive mode, the commands to perform the fixes -// are printed to the terminal. +// PostTestHook satisfies the Plugin interface. In this case, it just calls the +// PostBuildHook. func (plugin *FixVisibilityPlugin) PostTestHook( isInteractiveMode bool, promptRunner ioutils.PromptRunner, @@ -165,6 +163,15 @@ func (plugin *FixVisibilityPlugin) PostTestHook( return plugin.PostBuildHook(isInteractiveMode, promptRunner) } +// PostRunHook satisfies the Plugin interface. In this case, it just calls the +// PostBuildHook. +func (plugin *FixVisibilityPlugin) PostRunHook( + isInteractiveMode bool, + promptRunner ioutils.PromptRunner, +) error { + return plugin.PostBuildHook(isInteractiveMode, promptRunner) +} + func (plugin *FixVisibilityPlugin) hasPrivateVisibility(toFix string) (bool, error) { visibility, err := plugin.buildozer.run("print visibility", toFix) if err != nil {