Merge pull request #55 from spotify/ben/listing-components
Create Component in Scaffolder
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
name: Scaffolder CI
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'backend/scaffolder/**'
|
||||
- '.github/workflows/scaffolder.yml'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.12
|
||||
- name: checkout code
|
||||
uses: actions/checkout@v1
|
||||
- name: setup env
|
||||
run: |
|
||||
echo "::set-env name=GOPATH::$(go env GOPATH)"
|
||||
echo "::add-path::$(go env GOPATH)/bin"
|
||||
shell: bash
|
||||
- name: build
|
||||
run: go build -v ./...
|
||||
working-directory: ./backend/scaffolder
|
||||
- name: test
|
||||
run: go test ./... -short
|
||||
working-directory: ./backend/scaffolder
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
context "context"
|
||||
fmt "fmt"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
_struct "github.com/golang/protobuf/ptypes/struct"
|
||||
v1 "github.com/spotify/backstage/backend/proto/identity/v1"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
@@ -56,45 +57,158 @@ func (m *Empty) XXX_DiscardUnknown() {
|
||||
|
||||
var xxx_messageInfo_Empty proto.InternalMessageInfo
|
||||
|
||||
type GetAllTemplatesReply struct {
|
||||
type ListTemplatesReply struct {
|
||||
Templates []*Template `protobuf:"bytes,1,rep,name=templates,proto3" json:"templates,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *GetAllTemplatesReply) Reset() { *m = GetAllTemplatesReply{} }
|
||||
func (m *GetAllTemplatesReply) String() string { return proto.CompactTextString(m) }
|
||||
func (*GetAllTemplatesReply) ProtoMessage() {}
|
||||
func (*GetAllTemplatesReply) Descriptor() ([]byte, []int) {
|
||||
func (m *ListTemplatesReply) Reset() { *m = ListTemplatesReply{} }
|
||||
func (m *ListTemplatesReply) String() string { return proto.CompactTextString(m) }
|
||||
func (*ListTemplatesReply) ProtoMessage() {}
|
||||
func (*ListTemplatesReply) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_6737326b433dc57d, []int{1}
|
||||
}
|
||||
|
||||
func (m *GetAllTemplatesReply) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_GetAllTemplatesReply.Unmarshal(m, b)
|
||||
func (m *ListTemplatesReply) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ListTemplatesReply.Unmarshal(m, b)
|
||||
}
|
||||
func (m *GetAllTemplatesReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_GetAllTemplatesReply.Marshal(b, m, deterministic)
|
||||
func (m *ListTemplatesReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_ListTemplatesReply.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *GetAllTemplatesReply) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_GetAllTemplatesReply.Merge(m, src)
|
||||
func (m *ListTemplatesReply) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_ListTemplatesReply.Merge(m, src)
|
||||
}
|
||||
func (m *GetAllTemplatesReply) XXX_Size() int {
|
||||
return xxx_messageInfo_GetAllTemplatesReply.Size(m)
|
||||
func (m *ListTemplatesReply) XXX_Size() int {
|
||||
return xxx_messageInfo_ListTemplatesReply.Size(m)
|
||||
}
|
||||
func (m *GetAllTemplatesReply) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_GetAllTemplatesReply.DiscardUnknown(m)
|
||||
func (m *ListTemplatesReply) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_ListTemplatesReply.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_GetAllTemplatesReply proto.InternalMessageInfo
|
||||
var xxx_messageInfo_ListTemplatesReply proto.InternalMessageInfo
|
||||
|
||||
func (m *GetAllTemplatesReply) GetTemplates() []*Template {
|
||||
func (m *ListTemplatesReply) GetTemplates() []*Template {
|
||||
if m != nil {
|
||||
return m.Templates
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type CreateReply struct {
|
||||
ComponentId string `protobuf:"bytes,1,opt,name=component_id,json=componentId,proto3" json:"component_id,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *CreateReply) Reset() { *m = CreateReply{} }
|
||||
func (m *CreateReply) String() string { return proto.CompactTextString(m) }
|
||||
func (*CreateReply) ProtoMessage() {}
|
||||
func (*CreateReply) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_6737326b433dc57d, []int{2}
|
||||
}
|
||||
|
||||
func (m *CreateReply) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_CreateReply.Unmarshal(m, b)
|
||||
}
|
||||
func (m *CreateReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_CreateReply.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *CreateReply) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_CreateReply.Merge(m, src)
|
||||
}
|
||||
func (m *CreateReply) XXX_Size() int {
|
||||
return xxx_messageInfo_CreateReply.Size(m)
|
||||
}
|
||||
func (m *CreateReply) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_CreateReply.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_CreateReply proto.InternalMessageInfo
|
||||
|
||||
func (m *CreateReply) GetComponentId() string {
|
||||
if m != nil {
|
||||
return m.ComponentId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type CreateRequest struct {
|
||||
TemplateId string `protobuf:"bytes,1,opt,name=template_id,json=templateId,proto3" json:"template_id,omitempty"`
|
||||
Org string `protobuf:"bytes,2,opt,name=org,proto3" json:"org,omitempty"`
|
||||
ComponentId string `protobuf:"bytes,3,opt,name=component_id,json=componentId,proto3" json:"component_id,omitempty"`
|
||||
Private bool `protobuf:"varint,4,opt,name=private,proto3" json:"private,omitempty"`
|
||||
// here's the cookiecutter.json that is used for the request.
|
||||
// make as a struct so that we can pass through the data in a nice way
|
||||
// withouth having to mess around with stuff and special types.
|
||||
Metadata *_struct.Struct `protobuf:"bytes,5,opt,name=metadata,proto3" json:"metadata,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *CreateRequest) Reset() { *m = CreateRequest{} }
|
||||
func (m *CreateRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*CreateRequest) ProtoMessage() {}
|
||||
func (*CreateRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_6737326b433dc57d, []int{3}
|
||||
}
|
||||
|
||||
func (m *CreateRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_CreateRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *CreateRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_CreateRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *CreateRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_CreateRequest.Merge(m, src)
|
||||
}
|
||||
func (m *CreateRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_CreateRequest.Size(m)
|
||||
}
|
||||
func (m *CreateRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_CreateRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_CreateRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *CreateRequest) GetTemplateId() string {
|
||||
if m != nil {
|
||||
return m.TemplateId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *CreateRequest) GetOrg() string {
|
||||
if m != nil {
|
||||
return m.Org
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *CreateRequest) GetComponentId() string {
|
||||
if m != nil {
|
||||
return m.ComponentId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *CreateRequest) GetPrivate() bool {
|
||||
if m != nil {
|
||||
return m.Private
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *CreateRequest) GetMetadata() *_struct.Struct {
|
||||
if m != nil {
|
||||
return m.Metadata
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Template struct {
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
@@ -109,7 +223,7 @@ func (m *Template) Reset() { *m = Template{} }
|
||||
func (m *Template) String() string { return proto.CompactTextString(m) }
|
||||
func (*Template) ProtoMessage() {}
|
||||
func (*Template) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_6737326b433dc57d, []int{2}
|
||||
return fileDescriptor_6737326b433dc57d, []int{4}
|
||||
}
|
||||
|
||||
func (m *Template) XXX_Unmarshal(b []byte) error {
|
||||
@@ -160,31 +274,42 @@ func (m *Template) GetUser() *v1.User {
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*Empty)(nil), "spotify.backstage.scaffolder.v1.Empty")
|
||||
proto.RegisterType((*GetAllTemplatesReply)(nil), "spotify.backstage.scaffolder.v1.GetAllTemplatesReply")
|
||||
proto.RegisterType((*ListTemplatesReply)(nil), "spotify.backstage.scaffolder.v1.ListTemplatesReply")
|
||||
proto.RegisterType((*CreateReply)(nil), "spotify.backstage.scaffolder.v1.CreateReply")
|
||||
proto.RegisterType((*CreateRequest)(nil), "spotify.backstage.scaffolder.v1.CreateRequest")
|
||||
proto.RegisterType((*Template)(nil), "spotify.backstage.scaffolder.v1.Template")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("scaffolder/v1/scaffolder.proto", fileDescriptor_6737326b433dc57d) }
|
||||
|
||||
var fileDescriptor_6737326b433dc57d = []byte{
|
||||
// 270 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x91, 0x4f, 0x4b, 0xc4, 0x30,
|
||||
0x10, 0xc5, 0xe9, 0x6e, 0xfd, 0xb3, 0x53, 0x59, 0x21, 0x78, 0x28, 0x3d, 0x68, 0xa9, 0x20, 0xf5,
|
||||
0x92, 0xa5, 0x15, 0xf1, 0xac, 0x20, 0x7b, 0xaf, 0x7a, 0xf1, 0x22, 0xdd, 0x76, 0x2a, 0xc1, 0xb6,
|
||||
0x09, 0xc9, 0x58, 0xe8, 0xc5, 0xbb, 0xdf, 0x5a, 0x8c, 0x74, 0xbb, 0xc8, 0x42, 0x6f, 0x93, 0x97,
|
||||
0xf7, 0x4b, 0xe6, 0xcd, 0xc0, 0xb9, 0x29, 0xf2, 0xaa, 0x92, 0x75, 0x89, 0x7a, 0xd5, 0x25, 0xab,
|
||||
0xf1, 0xc4, 0x95, 0x96, 0x24, 0xd9, 0x85, 0x51, 0x92, 0x44, 0xd5, 0xf3, 0x4d, 0x5e, 0x7c, 0x18,
|
||||
0xca, 0xdf, 0x91, 0xef, 0x78, 0xba, 0x24, 0x08, 0x44, 0x89, 0x2d, 0x09, 0xea, 0x7f, 0xf1, 0xa1,
|
||||
0xfe, 0x83, 0xa3, 0x23, 0x38, 0x78, 0x6c, 0x14, 0xf5, 0xd1, 0x1b, 0x9c, 0xad, 0x91, 0xee, 0xeb,
|
||||
0xfa, 0x19, 0x1b, 0x55, 0xe7, 0x84, 0x26, 0x43, 0x55, 0xf7, 0x6c, 0x0d, 0x0b, 0x1a, 0x14, 0xdf,
|
||||
0x09, 0xe7, 0xb1, 0x97, 0x5e, 0xf3, 0x89, 0x1f, 0xf9, 0xf0, 0x46, 0x36, 0xb2, 0xd1, 0xb7, 0x03,
|
||||
0xc7, 0x83, 0xce, 0x96, 0x30, 0x13, 0xa5, 0xef, 0x84, 0x4e, 0xbc, 0xc8, 0x66, 0xa2, 0x64, 0x0c,
|
||||
0xdc, 0x36, 0x6f, 0xd0, 0x9f, 0x59, 0xc5, 0xd6, 0x2c, 0x04, 0xaf, 0x44, 0x53, 0x68, 0xa1, 0x48,
|
||||
0xc8, 0xd6, 0x9f, 0xdb, 0xab, 0x5d, 0x89, 0xdd, 0x81, 0xfb, 0x69, 0x50, 0xfb, 0x6e, 0xe8, 0xc4,
|
||||
0x5e, 0x7a, 0xb9, 0xa7, 0xad, 0x6d, 0xda, 0x2e, 0xe1, 0x2f, 0x06, 0x75, 0x66, 0x81, 0xf4, 0x0b,
|
||||
0xe0, 0x69, 0xdb, 0x30, 0x53, 0x70, 0xfa, 0x2f, 0x3a, 0xbb, 0x9a, 0x8c, 0x68, 0xa7, 0x16, 0xdc,
|
||||
0x4e, 0xfa, 0xf6, 0x0d, 0xf5, 0x61, 0xf9, 0x7a, 0x32, 0xba, 0xba, 0x64, 0x73, 0x68, 0x97, 0x71,
|
||||
0xf3, 0x13, 0x00, 0x00, 0xff, 0xff, 0x5b, 0x4d, 0x79, 0x5e, 0xeb, 0x01, 0x00, 0x00,
|
||||
// 411 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0xd1, 0x8a, 0xd3, 0x40,
|
||||
0x14, 0x25, 0x6d, 0x77, 0xb7, 0x7b, 0xb3, 0xbb, 0xc8, 0xbc, 0x18, 0x82, 0xb8, 0x31, 0x82, 0x54,
|
||||
0x90, 0xa9, 0x6d, 0x1f, 0x7c, 0x57, 0x44, 0x16, 0x7c, 0xca, 0xea, 0x8b, 0x20, 0x32, 0x4d, 0x6e,
|
||||
0xca, 0x60, 0x92, 0x19, 0x67, 0x6e, 0x03, 0xf9, 0x04, 0xff, 0xc7, 0x2f, 0xf2, 0x4b, 0xa4, 0x53,
|
||||
0x27, 0xdd, 0x65, 0x0b, 0xd9, 0xb7, 0x7b, 0xcf, 0xbd, 0xe7, 0xce, 0xe1, 0x9c, 0x81, 0xe7, 0x36,
|
||||
0x17, 0x65, 0xa9, 0xaa, 0x02, 0xcd, 0xbc, 0x5d, 0xcc, 0x0f, 0x1d, 0xd7, 0x46, 0x91, 0x62, 0xd7,
|
||||
0x56, 0x2b, 0x92, 0x65, 0xc7, 0xd7, 0x22, 0xff, 0x69, 0x49, 0x6c, 0x90, 0xdf, 0xd9, 0x69, 0x17,
|
||||
0x71, 0x2c, 0x0b, 0x6c, 0x48, 0x52, 0xb7, 0xa3, 0xfb, 0x7a, 0x4f, 0x8e, 0x9f, 0x6d, 0x94, 0xda,
|
||||
0x54, 0x38, 0x77, 0xdd, 0x7a, 0x5b, 0xce, 0x2d, 0x99, 0x6d, 0x4e, 0xfb, 0x69, 0x7a, 0x06, 0x27,
|
||||
0x1f, 0x6b, 0x4d, 0x5d, 0xfa, 0x1d, 0xd8, 0x67, 0x69, 0xe9, 0x0b, 0xd6, 0xba, 0x12, 0x84, 0x36,
|
||||
0x43, 0x5d, 0x75, 0xec, 0x13, 0x9c, 0x93, 0x47, 0xa2, 0x20, 0x19, 0xcf, 0xc2, 0xe5, 0x6b, 0x3e,
|
||||
0xa0, 0x86, 0xfb, 0x1b, 0xd9, 0x81, 0x9b, 0xbe, 0x85, 0xf0, 0x83, 0xc1, 0x1d, 0xe8, 0xee, 0xbe,
|
||||
0x80, 0x8b, 0x5c, 0xd5, 0x5a, 0x35, 0xd8, 0xd0, 0x0f, 0x59, 0x44, 0x41, 0x12, 0xcc, 0xce, 0xb3,
|
||||
0xb0, 0xc7, 0x6e, 0x8a, 0xf4, 0x4f, 0x00, 0x97, 0x9e, 0xf2, 0x6b, 0x8b, 0x96, 0xd8, 0x35, 0x84,
|
||||
0xfe, 0xe0, 0x81, 0x03, 0x1e, 0xba, 0x29, 0xd8, 0x13, 0x18, 0x2b, 0xb3, 0x89, 0x46, 0x6e, 0xb0,
|
||||
0x2b, 0x1f, 0xbc, 0x33, 0x7e, 0xf0, 0x0e, 0x8b, 0xe0, 0x4c, 0x1b, 0xd9, 0x0a, 0xc2, 0x68, 0x92,
|
||||
0x04, 0xb3, 0x69, 0xe6, 0x5b, 0xb6, 0x82, 0x69, 0x8d, 0x24, 0x0a, 0x41, 0x22, 0x3a, 0x49, 0x82,
|
||||
0x59, 0xb8, 0x7c, 0xca, 0xf7, 0x66, 0x72, 0x6f, 0x26, 0xbf, 0x75, 0x66, 0x66, 0xfd, 0x62, 0xfa,
|
||||
0x3b, 0x80, 0xa9, 0x37, 0x80, 0x5d, 0xc1, 0xa8, 0x17, 0x3a, 0x92, 0x05, 0x63, 0x30, 0x69, 0x44,
|
||||
0x8d, 0xff, 0x15, 0xba, 0x9a, 0x25, 0x10, 0x16, 0x68, 0x73, 0x23, 0x35, 0x49, 0xd5, 0x78, 0x85,
|
||||
0x77, 0x20, 0xf6, 0x0e, 0x26, 0x5b, 0x8b, 0xc6, 0xc9, 0x0b, 0x97, 0x2f, 0x8f, 0xf8, 0xdf, 0x47,
|
||||
0xde, 0x2e, 0xf8, 0x57, 0x8b, 0x26, 0x73, 0x84, 0xe5, 0xdf, 0x00, 0xe0, 0xb6, 0x8f, 0x86, 0x55,
|
||||
0x70, 0x79, 0x2f, 0x62, 0xf6, 0x6a, 0x30, 0x4a, 0xf7, 0x37, 0xe2, 0xd5, 0xe0, 0xde, 0x91, 0xaf,
|
||||
0x53, 0xc2, 0xe9, 0x3e, 0x3e, 0xc6, 0x07, 0xe9, 0xf7, 0x72, 0x8e, 0xdf, 0x3c, 0x7a, 0x5f, 0x57,
|
||||
0xdd, 0xfb, 0xab, 0x6f, 0x17, 0x87, 0x61, 0xbb, 0x58, 0x9f, 0xba, 0x6c, 0x56, 0xff, 0x02, 0x00,
|
||||
0x00, 0xff, 0xff, 0xfc, 0x1f, 0xfc, 0xf0, 0x55, 0x03, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
@@ -199,7 +324,8 @@ const _ = grpc.SupportPackageIsVersion6
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type ScaffolderClient interface {
|
||||
GetAllTemplates(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*GetAllTemplatesReply, error)
|
||||
ListTemplates(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*ListTemplatesReply, error)
|
||||
Create(ctx context.Context, in *CreateRequest, opts ...grpc.CallOption) (*CreateReply, error)
|
||||
}
|
||||
|
||||
type scaffolderClient struct {
|
||||
@@ -210,9 +336,18 @@ func NewScaffolderClient(cc grpc.ClientConnInterface) ScaffolderClient {
|
||||
return &scaffolderClient{cc}
|
||||
}
|
||||
|
||||
func (c *scaffolderClient) GetAllTemplates(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*GetAllTemplatesReply, error) {
|
||||
out := new(GetAllTemplatesReply)
|
||||
err := c.cc.Invoke(ctx, "/spotify.backstage.scaffolder.v1.Scaffolder/GetAllTemplates", in, out, opts...)
|
||||
func (c *scaffolderClient) ListTemplates(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*ListTemplatesReply, error) {
|
||||
out := new(ListTemplatesReply)
|
||||
err := c.cc.Invoke(ctx, "/spotify.backstage.scaffolder.v1.Scaffolder/ListTemplates", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *scaffolderClient) Create(ctx context.Context, in *CreateRequest, opts ...grpc.CallOption) (*CreateReply, error) {
|
||||
out := new(CreateReply)
|
||||
err := c.cc.Invoke(ctx, "/spotify.backstage.scaffolder.v1.Scaffolder/Create", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -221,35 +356,57 @@ func (c *scaffolderClient) GetAllTemplates(ctx context.Context, in *Empty, opts
|
||||
|
||||
// ScaffolderServer is the server API for Scaffolder service.
|
||||
type ScaffolderServer interface {
|
||||
GetAllTemplates(context.Context, *Empty) (*GetAllTemplatesReply, error)
|
||||
ListTemplates(context.Context, *Empty) (*ListTemplatesReply, error)
|
||||
Create(context.Context, *CreateRequest) (*CreateReply, error)
|
||||
}
|
||||
|
||||
// UnimplementedScaffolderServer can be embedded to have forward compatible implementations.
|
||||
type UnimplementedScaffolderServer struct {
|
||||
}
|
||||
|
||||
func (*UnimplementedScaffolderServer) GetAllTemplates(ctx context.Context, req *Empty) (*GetAllTemplatesReply, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetAllTemplates not implemented")
|
||||
func (*UnimplementedScaffolderServer) ListTemplates(ctx context.Context, req *Empty) (*ListTemplatesReply, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListTemplates not implemented")
|
||||
}
|
||||
func (*UnimplementedScaffolderServer) Create(ctx context.Context, req *CreateRequest) (*CreateReply, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Create not implemented")
|
||||
}
|
||||
|
||||
func RegisterScaffolderServer(s *grpc.Server, srv ScaffolderServer) {
|
||||
s.RegisterService(&_Scaffolder_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _Scaffolder_GetAllTemplates_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
func _Scaffolder_ListTemplates_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(Empty)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ScaffolderServer).GetAllTemplates(ctx, in)
|
||||
return srv.(ScaffolderServer).ListTemplates(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/spotify.backstage.scaffolder.v1.Scaffolder/GetAllTemplates",
|
||||
FullMethod: "/spotify.backstage.scaffolder.v1.Scaffolder/ListTemplates",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ScaffolderServer).GetAllTemplates(ctx, req.(*Empty))
|
||||
return srv.(ScaffolderServer).ListTemplates(ctx, req.(*Empty))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Scaffolder_Create_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CreateRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ScaffolderServer).Create(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/spotify.backstage.scaffolder.v1.Scaffolder/Create",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ScaffolderServer).Create(ctx, req.(*CreateRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
@@ -259,8 +416,12 @@ var _Scaffolder_serviceDesc = grpc.ServiceDesc{
|
||||
HandlerType: (*ScaffolderServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "GetAllTemplates",
|
||||
Handler: _Scaffolder_GetAllTemplates_Handler,
|
||||
MethodName: "ListTemplates",
|
||||
Handler: _Scaffolder_ListTemplates_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Create",
|
||||
Handler: _Scaffolder_Create_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
|
||||
@@ -2,21 +2,56 @@ package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
identity "github.com/spotify/backstage/backend/proto/identity/v1"
|
||||
pb "github.com/spotify/backstage/backend/proto/scaffolder/v1"
|
||||
"github.com/spotify/backstage/scaffolder/fs"
|
||||
"github.com/spotify/backstage/scaffolder/remote"
|
||||
"github.com/spotify/backstage/scaffolder/repository"
|
||||
)
|
||||
|
||||
// Server is the inventory Grpc server
|
||||
type Server struct {
|
||||
Repository *repository.Repository
|
||||
repository *repository.Repository
|
||||
github *remote.Github
|
||||
fs *fs.Filesystem
|
||||
}
|
||||
|
||||
// GetAllTemplates returns the local templatess
|
||||
func (s *Server) GetAllTemplates(ctx context.Context, req *pb.Empty) (*pb.GetAllTemplatesReply, error) {
|
||||
// NewServer creates a new server for with all the things
|
||||
func NewServer() *Server {
|
||||
return &Server{
|
||||
github: remote.NewGithubClient(),
|
||||
}
|
||||
}
|
||||
|
||||
// Create scaffolds the repo in github and then will create push to the repository
|
||||
func (s *Server) Create(ctx context.Context, req *pb.CreateRequest) (*pb.CreateReply, error) {
|
||||
// first create the repository with github
|
||||
fmt.Sprintf("Creating repository for Component %s", req.ComponentId)
|
||||
repo := remote.Repository{
|
||||
Name: req.ComponentId,
|
||||
Org: req.Org,
|
||||
Private: req.Private,
|
||||
}
|
||||
if _, err := s.github.CreateRepository(repo); err != nil {
|
||||
return nil, status.Error(codes.Internal, fmt.Sprintf("Could not create repository %s/%s", req.Org, req.ComponentId))
|
||||
}
|
||||
|
||||
// move the template into a temporary directory
|
||||
tempFolder, _ := s.fs.PrepareTemplate(fs.Template{req.TemplateId})
|
||||
|
||||
fmt.Sprintf("Created temporary folder %s", tempFolder)
|
||||
// use git bindings to add the remote with access token and push to the directory
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// ListTemplates returns the local templatess
|
||||
func (s *Server) ListTemplates(ctx context.Context, req *pb.Empty) (*pb.ListTemplatesReply, error) {
|
||||
// todo (blam): yes we currently read the disk on every load. but it's fine for now 🤷♂️
|
||||
definitions, err := s.Repository.Load()
|
||||
definitions, err := s.repository.Load()
|
||||
var templates []*pb.Template
|
||||
|
||||
for _, definition := range definitions {
|
||||
@@ -35,7 +70,7 @@ func (s *Server) GetAllTemplates(ctx context.Context, req *pb.Empty) (*pb.GetAll
|
||||
templates = append(templates, template)
|
||||
}
|
||||
|
||||
return &pb.GetAllTemplatesReply{
|
||||
return &pb.ListTemplatesReply{
|
||||
Templates: templates,
|
||||
}, err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSample(t *testing.T) {
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package fs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
// Filesystem Repository
|
||||
type Filesystem struct{}
|
||||
|
||||
func file(src, dst string) error {
|
||||
var err error
|
||||
var srcfd *os.File
|
||||
var dstfd *os.File
|
||||
var srcinfo os.FileInfo
|
||||
|
||||
if srcfd, err = os.Open(src); err != nil {
|
||||
return err
|
||||
}
|
||||
defer srcfd.Close()
|
||||
|
||||
if dstfd, err = os.Create(dst); err != nil {
|
||||
return err
|
||||
}
|
||||
defer dstfd.Close()
|
||||
|
||||
if _, err = io.Copy(dstfd, srcfd); err != nil {
|
||||
return err
|
||||
}
|
||||
if srcinfo, err = os.Stat(src); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.Chmod(dst, srcinfo.Mode())
|
||||
}
|
||||
|
||||
func dir(src string, dst string) error {
|
||||
var err error
|
||||
var fds []os.FileInfo
|
||||
var srcinfo os.FileInfo
|
||||
|
||||
if srcinfo, err = os.Stat(src); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = os.MkdirAll(dst, srcinfo.Mode()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if fds, err = ioutil.ReadDir(src); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, fd := range fds {
|
||||
srcfp := path.Join(src, fd.Name())
|
||||
dstfp := path.Join(dst, fd.Name())
|
||||
|
||||
if fd.IsDir() {
|
||||
if err = dir(srcfp, dstfp); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
} else {
|
||||
if err = file(srcfp, dstfp); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Template holds the template ID for copying
|
||||
type Template struct {
|
||||
ID string
|
||||
}
|
||||
|
||||
// PrepareTemplate will copy the local template to temp folder
|
||||
// and return the temp location
|
||||
func (f *Filesystem) PrepareTemplate(template Template) (string, error) {
|
||||
tempDirectory, _ := ioutil.TempDir(os.TempDir(), template.ID)
|
||||
fmt.Println(tempDirectory)
|
||||
if err := dir("./templates/"+template.ID, tempDirectory); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return tempDirectory, nil
|
||||
}
|
||||
@@ -2,9 +2,16 @@ module github.com/spotify/backstage/scaffolder
|
||||
|
||||
go 1.13
|
||||
|
||||
replace github.com/spotify/backstage/backend/proto => ../proto
|
||||
replace (
|
||||
github.com/spotify/backstage/backend/proto => ./../proto
|
||||
github.com/spotify/backstage/proto => ../proto
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/golang/protobuf v1.3.3
|
||||
github.com/google/go-github/v29 v29.0.2
|
||||
github.com/spotify/backstage/backend/proto v0.0.0-00010101000000-000000000000
|
||||
github.com/spotify/backstage/proto v0.0.0-00010101000000-000000000000
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be
|
||||
google.golang.org/grpc v1.27.0
|
||||
)
|
||||
|
||||
@@ -14,7 +14,13 @@ github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
|
||||
github.com/google/go-github/v29 v29.0.2 h1:opYN6Wc7DOz7Ku3Oh4l7prmkOMwEcQxpFtxdU8N8Pts=
|
||||
github.com/google/go-github/v29 v29.0.2/go.mod h1:CHKiKKPHJ0REzfwc14QMklvtHwCveD0PxlMjLlzAM5E=
|
||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@@ -25,6 +31,7 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
|
||||
pb "github.com/spotify/backstage/backend/proto/scaffolder/v1"
|
||||
"github.com/spotify/backstage/scaffolder/app"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
@@ -21,7 +20,9 @@ func main() {
|
||||
}
|
||||
|
||||
grpcServer := grpc.NewServer()
|
||||
pb.RegisterScaffolderServer(grpcServer, &app.Server{})
|
||||
serverHandler := app.NewServer()
|
||||
|
||||
pb.RegisterScaffolderServer(grpcServer, serverHandler)
|
||||
log.Println("Serving Scaffolder Service")
|
||||
grpcServer.Serve(lis)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
package remote
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
gh "github.com/google/go-github/v29/github"
|
||||
"golang.org/x/oauth2"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Github is the exported struct
|
||||
type Github struct {
|
||||
client *gh.Client
|
||||
ctx *context.Context
|
||||
}
|
||||
|
||||
// NewGithubClient returns a new client with the correct access token enabled
|
||||
func NewGithubClient() *Github {
|
||||
accessToken := os.Getenv("BOSS_GH_ACCESS_TOKEN")
|
||||
|
||||
if accessToken == "" {
|
||||
fmt.Println("No BOSS_GH_ACCESS_TOKEN set. Cannot continue")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
ts := oauth2.StaticTokenSource(
|
||||
&oauth2.Token{AccessToken: accessToken},
|
||||
)
|
||||
tc := oauth2.NewClient(ctx, ts)
|
||||
client := gh.NewClient(tc)
|
||||
|
||||
return &Github{
|
||||
client: client,
|
||||
ctx: &ctx,
|
||||
}
|
||||
}
|
||||
|
||||
// Repository holds the information of the created repo
|
||||
type Repository struct {
|
||||
Org string
|
||||
Name string
|
||||
Private bool
|
||||
}
|
||||
|
||||
// CreateRepository will create the repository in Github ready for use by the scaffolder
|
||||
func (g *Github) CreateRepository(repo Repository) (*gh.Repository, error) {
|
||||
ghRepo := &gh.Repository{
|
||||
Name: &repo.Name,
|
||||
Private: &repo.Private,
|
||||
}
|
||||
|
||||
var org string
|
||||
|
||||
if repo.Org != "" {
|
||||
org = repo.Org
|
||||
}
|
||||
|
||||
created, _, err := g.client.Repositories.Create(*g.ctx, org, ghRepo)
|
||||
|
||||
return created, err
|
||||
}
|
||||
@@ -20,9 +20,10 @@ type TemplateDefinition struct {
|
||||
|
||||
// Load will return all the Repository templates
|
||||
func (s *Repository) Load() ([]*TemplateDefinition, error) {
|
||||
templateInfoFilePaths, err := filepath.Glob("templates/**/template-info.json")
|
||||
var templateDefinitions []*TemplateDefinition
|
||||
|
||||
templateInfoFilePaths, err := filepath.Glob("templates/**/template-info.json")
|
||||
|
||||
if err != nil {
|
||||
fmt.Errorf("failed to load template-info files")
|
||||
return nil, err
|
||||
@@ -45,5 +46,5 @@ func (s *Repository) Load() ([]*TemplateDefinition, error) {
|
||||
templateDefinitions = append(templateDefinitions, &definition)
|
||||
}
|
||||
|
||||
return templateDefinitions, err
|
||||
return templateDefinitions, nil
|
||||
}
|
||||
|
||||
@@ -3,22 +3,41 @@ syntax = "proto3";
|
||||
package spotify.backstage.scaffolder.v1;
|
||||
|
||||
import "identity/v1/identity.proto";
|
||||
import "google/protobuf/struct.proto";
|
||||
|
||||
option go_package = "scaffolderv1";
|
||||
|
||||
service Scaffolder {
|
||||
rpc GetAllTemplates(Empty) returns (GetAllTemplatesReply);
|
||||
rpc ListTemplates(Empty) returns (ListTemplatesReply);
|
||||
rpc Create(CreateRequest) returns (CreateReply);
|
||||
}
|
||||
|
||||
message Empty {}
|
||||
|
||||
message GetAllTemplatesReply {
|
||||
message ListTemplatesReply {
|
||||
repeated Template templates = 1;
|
||||
}
|
||||
|
||||
message Template {
|
||||
string id = 1;
|
||||
string name = 2;
|
||||
string description = 3;
|
||||
spotify.backstage.identity.v1.User user = 4;
|
||||
message CreateReply {
|
||||
string component_id = 1;
|
||||
|
||||
}
|
||||
|
||||
message CreateRequest {
|
||||
string template_id = 1;
|
||||
string org = 2;
|
||||
string component_id = 3;
|
||||
bool private = 4;
|
||||
|
||||
// here's the cookiecutter.json that is used for the request.
|
||||
// make as a struct so that we can pass through the data in a nice way
|
||||
// withouth having to mess around with stuff and special types.
|
||||
google.protobuf.Struct metadata = 5;
|
||||
}
|
||||
|
||||
message Template {
|
||||
string id = 1;
|
||||
string name = 2;
|
||||
string description = 3;
|
||||
spotify.backstage.identity.v1.User user = 4;
|
||||
}
|
||||
Reference in New Issue
Block a user