feat(scaffolder): Added the ability to create the repos with optional org in github
This commit is contained in:
@@ -2,20 +2,53 @@ package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
identity "github.com/spotify/backstage/backend/proto/identity/v1"
|
||||
pb "github.com/spotify/backstage/proto/scaffolder/v1"
|
||||
"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
|
||||
}
|
||||
|
||||
// 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) {
|
||||
repo := remote.Repository{
|
||||
Name: req.ComponentId,
|
||||
Org: req.Org,
|
||||
Private: req.Private,
|
||||
}
|
||||
|
||||
err := s.github.CreateRepository(repo)
|
||||
|
||||
fmt.Println("Meta is")
|
||||
fmt.Println(req.Metadata)
|
||||
fmt.Println("error is")
|
||||
fmt.Println(err)
|
||||
|
||||
return nil, nil
|
||||
// first create the repository with github
|
||||
|
||||
// move the template into a temporary directory
|
||||
|
||||
// use git bindings to add the remote with access token and push to the directory
|
||||
}
|
||||
|
||||
// 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 {
|
||||
@@ -34,7 +67,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
|
||||
}
|
||||
|
||||
@@ -8,7 +8,9 @@ replace github.com/spotify/backstage/backend/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/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,65 @@
|
||||
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) error {
|
||||
ghRepo := &gh.Repository{
|
||||
Name: &repo.Name,
|
||||
Private: &repo.Private,
|
||||
}
|
||||
|
||||
var org string
|
||||
|
||||
if repo.Org != "" {
|
||||
org = repo.Org
|
||||
}
|
||||
|
||||
created, response, err := g.client.Repositories.Create(*g.ctx, org, ghRepo)
|
||||
|
||||
fmt.Println(created)
|
||||
fmt.Println(response)
|
||||
fmt.Println(err)
|
||||
return nil
|
||||
}
|
||||
@@ -45,5 +45,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