-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(sdk): create sdk version v1alpha2 #99
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
#!/bin/bash | ||
|
||
set -o errexit -o nounset -o pipefail | ||
|
||
INVALID_FILE_PATHS=('pkg/plugin/sdk') # Array of filepaths that are not allowed | ||
VALID_FILE_PATHS=('pkg/plugin/sdk/v1alpha2') # Array of filepaths that are allowed | ||
|
||
# by default the only local branch will be pull/PR#/merge | ||
# fetch only the latest commit from the 2 branches in question to avoid fetching the entire repo which could be costly | ||
git fetch --depth 1 origin "$1" | ||
git fetch --depth 1 origin "$2" | ||
|
||
git diff "origin/$1..origin/$2" --name-only | while read -r file; do | ||
|
||
# check if filepath matches a valid path. If so move to the next change | ||
for valid_path in "${VALID_FILE_PATHS[@]}"; do | ||
if [[ "${file}" == "${valid_path}"* ]]; then | ||
continue 2 | ||
fi | ||
done | ||
|
||
# check if filepath matches an invalid path | ||
for invalid_path in "${INVALID_FILE_PATHS[@]}"; do | ||
if [[ "${file}" == "${invalid_path}"* ]]; then | ||
echo "Branch contains changes to filepaths that are invalid" | ||
exit 1 | ||
fi | ||
done | ||
done |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# Plugin SDK v1alpha2 | ||
|
||
This is the SDK for creating plugins for the Aspect CLI using the Go language. | ||
|
||
This doc is a **work in progress**. Use the | ||
[fix-visibility plugin](/plugins/fix-visibility) as a reference for now. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
load("@io_bazel_rules_go//go:def.bzl", "go_library") | ||
|
||
go_library( | ||
name = "config", | ||
srcs = ["config.go"], | ||
importpath = "aspect.build/cli/pkg/plugin/sdk/v1alpha2/config", | ||
visibility = ["//visibility:public"], | ||
deps = [ | ||
"//pkg/plugin/sdk/v1alpha2/plugin", | ||
"@com_github_hashicorp_go_plugin//:go-plugin", | ||
], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/* | ||
Copyright © 2021 Aspect Build Systems Inc | ||
|
||
Not licensed for re-use. | ||
*/ | ||
|
||
package config | ||
|
||
import ( | ||
goplugin "github.com/hashicorp/go-plugin" | ||
|
||
"aspect.build/cli/pkg/plugin/sdk/v1alpha2/plugin" | ||
) | ||
|
||
// DefaultPluginName is the name each aspect plugin must provide. | ||
const DefaultPluginName = "aspectplugin" | ||
|
||
// Handshake is the shared handshake config for the v1alpha2 protocol. | ||
var Handshake = goplugin.HandshakeConfig{ | ||
ProtocolVersion: 1, | ||
MagicCookieKey: "PLUGIN", | ||
MagicCookieValue: "ASPECT", | ||
} | ||
|
||
// PluginMap represents the plugin interfaces allowed to be implemented by a | ||
// plugin executable. | ||
var PluginMap = map[string]goplugin.Plugin{ | ||
DefaultPluginName: &plugin.GRPCPlugin{}, | ||
} | ||
|
||
// NewConfigFor returns the default configuration for the passed Plugin | ||
// implementation. | ||
func NewConfigFor(p plugin.Plugin) *goplugin.ServeConfig { | ||
return &goplugin.ServeConfig{ | ||
HandshakeConfig: Handshake, | ||
Plugins: map[string]goplugin.Plugin{ | ||
DefaultPluginName: &plugin.GRPCPlugin{Impl: p}, | ||
}, | ||
GRPCServer: goplugin.DefaultGRPCServer, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
load("@io_bazel_rules_go//go:def.bzl", "go_library") | ||
|
||
go_library( | ||
name = "plugin", | ||
srcs = [ | ||
"grpc.go", | ||
"interface.go", | ||
], | ||
importpath = "aspect.build/cli/pkg/plugin/sdk/v1alpha2/plugin", | ||
visibility = ["//visibility:public"], | ||
deps = [ | ||
"//bazel/buildeventstream/proto", | ||
"//pkg/ioutils", | ||
"//pkg/plugin/sdk/v1alpha2/proto", | ||
"@com_github_hashicorp_go_plugin//:go-plugin", | ||
"@com_github_manifoldco_promptui//:promptui", | ||
"@org_golang_google_grpc//:go_default_library", | ||
], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
/* | ||
Copyright © 2021 Aspect Build Systems Inc | ||
|
||
Not licensed for re-use. | ||
*/ | ||
|
||
// grpc.go hides all the complexity of doing the gRPC calls between the aspect | ||
// Core and a Plugin implementation by providing simple abstractions from the | ||
// point of view of Plugin maintainers. | ||
package plugin | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
goplugin "github.com/hashicorp/go-plugin" | ||
"github.com/manifoldco/promptui" | ||
"google.golang.org/grpc" | ||
|
||
buildeventstream "aspect.build/cli/bazel/buildeventstream/proto" | ||
"aspect.build/cli/pkg/ioutils" | ||
"aspect.build/cli/pkg/plugin/sdk/v1alpha2/proto" | ||
) | ||
|
||
// GRPCPlugin represents a Plugin that communicates over gRPC. | ||
type GRPCPlugin struct { | ||
goplugin.Plugin | ||
Impl Plugin | ||
} | ||
|
||
// GRPCServer registers an instance of the GRPCServer in the Plugin binary. | ||
func (p *GRPCPlugin) GRPCServer(broker *goplugin.GRPCBroker, s *grpc.Server) error { | ||
proto.RegisterPluginServer(s, &GRPCServer{Impl: p.Impl, broker: broker}) | ||
return nil | ||
} | ||
|
||
// GRPCClient returns a client to perform the RPC calls to the Plugin | ||
// instance from the Core. | ||
func (p *GRPCPlugin) GRPCClient(ctx context.Context, broker *goplugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) { | ||
return &GRPCClient{client: proto.NewPluginClient(c), broker: broker}, nil | ||
} | ||
|
||
// GRPCServer implements the gRPC server that runs on the Plugin instances. | ||
type GRPCServer struct { | ||
Impl Plugin | ||
broker *goplugin.GRPCBroker | ||
} | ||
|
||
// BEPEventCallback translates the gRPC call to the Plugin BEPEventCallback | ||
// implementation. | ||
func (m *GRPCServer) BEPEventCallback( | ||
ctx context.Context, | ||
req *proto.BEPEventCallbackReq, | ||
) (*proto.BEPEventCallbackRes, error) { | ||
return &proto.BEPEventCallbackRes{}, m.Impl.BEPEventCallback(req.Event) | ||
} | ||
|
||
// PostBuildHook translates the gRPC call to the Plugin PostBuildHook | ||
// 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) PostBuildHook( | ||
ctx context.Context, | ||
req *proto.PostBuildHookReq, | ||
) (*proto.PostBuildHookRes, 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.PostBuildHookRes{}, | ||
m.Impl.PostBuildHook(req.IsInteractiveMode, prompter) | ||
} | ||
|
||
// GRPCClient implements the gRPC client that is used by the Core to communicate | ||
// with the Plugin instances. | ||
type GRPCClient struct { | ||
client proto.PluginClient | ||
broker *goplugin.GRPCBroker | ||
} | ||
|
||
// BEPEventCallback is called from the Core to execute the Plugin | ||
// BEPEventCallback. | ||
func (m *GRPCClient) BEPEventCallback(event *buildeventstream.BuildEvent) error { | ||
_, err := m.client.BEPEventCallback(context.Background(), &proto.BEPEventCallbackReq{Event: event}) | ||
return err | ||
} | ||
|
||
// PostBuildHook is called from the Core to execute the Plugin PostBuildHook. It | ||
// starts the prompt runner server with the provided PromptRunner. | ||
func (m *GRPCClient) PostBuildHook(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.PostBuildHookReq{ | ||
BrokerId: brokerID, | ||
IsInteractiveMode: isInteractiveMode, | ||
} | ||
_, err := m.client.PostBuildHook(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 { | ||
promptRunner ioutils.PromptRunner | ||
} | ||
|
||
// Run translates the gRPC call to perform a prompt Run on the Core. | ||
func (p *PrompterGRPCServer) Run( | ||
ctx context.Context, | ||
req *proto.PromptRunReq, | ||
) (*proto.PromptRunRes, error) { | ||
prompt := promptui.Prompt{ | ||
Label: req.GetLabel(), | ||
Default: req.GetDefault(), | ||
AllowEdit: req.GetAllowEdit(), | ||
Mask: []rune(req.GetMask())[0], | ||
HideEntered: req.GetHideEntered(), | ||
IsConfirm: req.GetIsConfirm(), | ||
IsVimMode: req.GetIsVimMode(), | ||
} | ||
|
||
result, err := p.promptRunner.Run(prompt) | ||
res := &proto.PromptRunRes{Result: result} | ||
if err != nil { | ||
res.Error = &proto.PromptRunRes_Error{ | ||
Happened: true, | ||
Message: err.Error(), | ||
} | ||
} | ||
|
||
return res, nil | ||
} | ||
|
||
// PrompterGRPCClient implements the gRPC client that is used by the Plugin | ||
// instance to communicate with the Core to request prompt actions from the | ||
// user. | ||
type PrompterGRPCClient struct { | ||
client proto.PrompterClient | ||
} | ||
|
||
// Run is called from the Plugin to request the Core to run the given | ||
// promptui.Prompt. | ||
func (p *PrompterGRPCClient) Run(prompt promptui.Prompt) (string, error) { | ||
label, isString := prompt.Label.(string) | ||
if !isString { | ||
return "", fmt.Errorf("label '%+v' must be a string", prompt.Label) | ||
} | ||
req := &proto.PromptRunReq{ | ||
Label: label, | ||
Default: prompt.Default, | ||
AllowEdit: prompt.AllowEdit, | ||
Mask: string(prompt.Mask), | ||
HideEntered: prompt.HideEntered, | ||
IsConfirm: prompt.IsConfirm, | ||
IsVimMode: prompt.IsVimMode, | ||
} | ||
res, err := p.client.Run(context.Background(), req) | ||
if err != nil { | ||
return "", err | ||
} | ||
if res.Error != nil && res.Error.Happened { | ||
return "", fmt.Errorf(res.Error.Message) | ||
} | ||
return res.Result, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/* | ||
Copyright © 2021 Aspect Build Systems Inc | ||
|
||
Not licensed for re-use. | ||
*/ | ||
|
||
package plugin | ||
|
||
import ( | ||
buildeventstream "aspect.build/cli/bazel/buildeventstream/proto" | ||
"aspect.build/cli/pkg/ioutils" | ||
) | ||
|
||
// Plugin determines how an aspect Plugin should be implemented. | ||
type Plugin interface { | ||
BEPEventCallback(event *buildeventstream.BuildEvent) error | ||
PostBuildHook( | ||
isInteractiveMode bool, | ||
promptRunner ioutils.PromptRunner, | ||
) error | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
load("@io_bazel_rules_go//go:def.bzl", "go_library") | ||
load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") | ||
load("@rules_proto//proto:defs.bzl", "proto_library") | ||
|
||
proto_library( | ||
name = "proto_proto", | ||
srcs = ["plugin.proto"], | ||
visibility = ["//visibility:public"], | ||
deps = ["//third-party/github.com/bazelbuild/bazel/src/main/java/com/google/devtools/build/lib/buildeventstream/proto:proto_proto"], | ||
) | ||
|
||
go_proto_library( | ||
name = "proto_go_proto", | ||
compilers = ["@io_bazel_rules_go//proto:go_grpc"], | ||
importpath = "aspect.build/cli/pkg/plugin/sdk/v1alpha2/proto", | ||
proto = ":proto_proto", | ||
visibility = ["//visibility:public"], | ||
deps = ["//third-party/github.com/bazelbuild/bazel/src/main/java/com/google/devtools/build/lib/buildeventstream/proto"], | ||
) | ||
|
||
go_library( | ||
name = "proto", | ||
embed = [":proto_go_proto"], | ||
importpath = "aspect.build/cli/pkg/plugin/sdk/v1alpha2/proto", | ||
visibility = ["//visibility:public"], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
//go:build dummy | ||
// +build dummy | ||
|
||
// This file exists to make the go tooling happy. This package is generated by | ||
// bazel. | ||
package proto |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the number of changes we will make to the SDK, this will have to bump. Not in this PR, though.