-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(sdk): Create sdk version v1alpha2 and add the ability to restric…
…t changes to certain files and folders
- Loading branch information
1 parent
e7b1aeb
commit d21f76a
Showing
11 changed files
with
408 additions
and
0 deletions.
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,31 @@ | ||
#!/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 | ||
|
||
git fetch # we need to be able to compare our current changes to the main branch | ||
|
||
CHANGED_FILES=$(git diff origin/main --name-only) | ||
|
||
# loop through changed files | ||
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 | ||
|
||
# if the give file matches an invalid filepath and loop has not been continued by the list of valid filepaths then fail | ||
done <<< "${CHANGED_FILES}" |
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.