feat(scaffolder): actually run the cookie cutter now in the folder and pass through the metadata to the cookiecutter.json
This commit is contained in:
@@ -7,10 +7,10 @@ import (
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"log"
|
||||
"os/exec"
|
||||
|
||||
identity "github.com/spotify/backstage/backend/proto/identity/v1"
|
||||
pb "github.com/spotify/backstage/backend/proto/scaffolder/v1"
|
||||
"github.com/spotify/backstage/scaffolder/cutter"
|
||||
"github.com/spotify/backstage/scaffolder/fs"
|
||||
"github.com/spotify/backstage/scaffolder/remote"
|
||||
"github.com/spotify/backstage/scaffolder/repository"
|
||||
@@ -21,6 +21,7 @@ type Server struct {
|
||||
repository *repository.Repository
|
||||
github *remote.Github
|
||||
fs *fs.Filesystem
|
||||
cookie *cutter.Cutter
|
||||
}
|
||||
|
||||
// NewServer creates a new server for with all the things
|
||||
@@ -34,38 +35,49 @@ func NewServer() *Server {
|
||||
func (s *Server) Create(ctx context.Context, req *pb.CreateRequest) (*pb.CreateReply, error) {
|
||||
// first create the repository with github
|
||||
log.Printf("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))
|
||||
// }
|
||||
|
||||
marshaller := &jsonpb.Marshaler{}
|
||||
d, e := marshaller.MarshalToString(req.Metadata)
|
||||
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, err := s.fs.PrepareTemplate(
|
||||
fs.Template{
|
||||
ID: req.TemplateId,
|
||||
Metadata: req.Metadata,
|
||||
ID: req.TemplateId,
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, fmt.Sprintf("Could not prepare the template"))
|
||||
return nil, status.Error(codes.Internal, "Could not prepare the template")
|
||||
}
|
||||
|
||||
log.Printf("Created temporary folder %s", tempFolder)
|
||||
// TODO(blam): Probably need to wrap this in a timeout or something to avoid waiting to long
|
||||
cmd := exec.Command("cookiecutter", "--no-input", "-v", tempFolder)
|
||||
cmd.Dir = tempFolder
|
||||
err := cmd.Run()
|
||||
// get the optional metadatafields from the json
|
||||
marshaler := &jsonpb.Marshaler{}
|
||||
cutterMetadata, err := marshaler.MarshalToString(req.Metadata)
|
||||
|
||||
fmt.Println(output)
|
||||
fmt.Println(err)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, "Could not marshal the cookiecutter metadata")
|
||||
}
|
||||
|
||||
cookieTemplate := cutter.CookieCutterTemplate{
|
||||
Path: tempFolder,
|
||||
ComponentID: req.ComponentId,
|
||||
Metadata: cutterMetadata,
|
||||
}
|
||||
|
||||
// create the cookicutter json
|
||||
if err := s.cookie.WriteMetadata(cookieTemplate); err != nil {
|
||||
return nil, status.Error(codes.Internal, "Could not write cookie metadata")
|
||||
}
|
||||
|
||||
// run the cookiecutter on the folder
|
||||
if err := s.cookie.Run(cookieTemplate); err != nil {
|
||||
return nil, status.Error(codes.Internal, "Failed to run the cookie cutter")
|
||||
}
|
||||
|
||||
// use git bindings to add the remote with access token and push to the directory
|
||||
return nil, nil
|
||||
@@ -73,7 +85,7 @@ func (s *Server) Create(ctx context.Context, req *pb.CreateRequest) (*pb.CreateR
|
||||
|
||||
// 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 🤷♂️
|
||||
// TODO(blam): yes we currently read the disk on every load. but it's fine for now 🤷♂️
|
||||
definitions, err := s.repository.Load()
|
||||
var templates []*pb.Template
|
||||
|
||||
@@ -82,6 +94,7 @@ func (s *Server) ListTemplates(ctx context.Context, req *pb.Empty) (*pb.ListTemp
|
||||
Id: definition.ID,
|
||||
Name: definition.Name,
|
||||
Description: definition.Description,
|
||||
|
||||
// need to actually call the idenity service here to get the
|
||||
// actual user and propgate back when needed.
|
||||
User: &identity.User{
|
||||
|
||||
@@ -1,13 +1,61 @@
|
||||
package cutter
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
// Cutter is the wrapper around cookiecutter
|
||||
type Cutter interface {
|
||||
type Cutter struct {
|
||||
}
|
||||
|
||||
type Template {
|
||||
|
||||
// CookieCutterTemplate holds the template ID and metadata for copying
|
||||
type CookieCutterTemplate struct {
|
||||
Path string
|
||||
Metadata string
|
||||
ComponentID string
|
||||
}
|
||||
// Run runs cookiecutter in the folder provided
|
||||
func (c *Cutter) Run() error {
|
||||
|
||||
// WriteMetadata runs cookiecutter in the folder provided
|
||||
func (c *Cutter) WriteMetadata(template CookieCutterTemplate) error {
|
||||
var temporaryCookieCutter map[string]interface{}
|
||||
err := json.Unmarshal([]byte(template.Metadata), &temporaryCookieCutter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
temporaryCookieCutter["component_id"] = template.ComponentID
|
||||
finalMetadata, _ := json.Marshal(temporaryCookieCutter)
|
||||
|
||||
file, err := os.Create(fmt.Sprintf("%s/cookiecutter.json", template.Path))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
_, err = file.Write(finalMetadata)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Run will run the cookie cutter
|
||||
func (c *Cutter) Run(template CookieCutterTemplate) error {
|
||||
// TODO(blam): Probably need to wrap this in a timeout or something to avoid waiting to long
|
||||
log.Printf("Running cookiecutter on %s", template.Path)
|
||||
log.Printf("With metadata %s", template.Metadata)
|
||||
|
||||
cmd := exec.Command("cookiecutter", "--no-input", "-v", template.Path)
|
||||
cmd.Dir = template.Path
|
||||
output, err := cmd.Output()
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Cookie cutter failed with output: %s", output)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user