From b844de0cd51e2b3029b137309e6a2c3c9af7c7ae Mon Sep 17 00:00:00 2001 From: blam Date: Thu, 6 Feb 2020 16:48:37 +0100 Subject: [PATCH 1/6] feat(scaffolder): Starting to add the cookiecutter support for running the template after we've got all the data --- backend/Dockerfile | 12 +++++++- backend/scaffolder/app/server.go | 45 ++++++++++++++++++++++------- backend/scaffolder/cutter/cutter.go | 13 +++++++++ backend/scaffolder/fs/fs.go | 4 +-- docker-compose.yaml | 2 ++ tools/cookiecutter/Dockerfile | 2 +- 6 files changed, 63 insertions(+), 15 deletions(-) create mode 100644 backend/scaffolder/cutter/cutter.go diff --git a/backend/Dockerfile b/backend/Dockerfile index a5aae4c2a8..ffd64d49b5 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,3 +1,4 @@ +### Builder Stage FROM golang:1.13 AS build ARG service @@ -13,7 +14,9 @@ COPY $service/ /build/$service/ RUN go build . -FROM debian:buster + +### Running Container Stage +FROM debian:buster AS run ARG service WORKDIR /app/ @@ -21,3 +24,10 @@ WORKDIR /app/ COPY --from=build /build/$service/$service /app/service CMD ["./service"] + + +### Scaffolder Stage +### needs extra cookiecutter +FROM run AS scaffolder +RUN apt-get update && apt-get install -y python-pip +RUN pip install cookiecutter==1.7.0 --index-url https://pypi.python.org/simple diff --git a/backend/scaffolder/app/server.go b/backend/scaffolder/app/server.go index b4bcb590ab..24a5af326f 100644 --- a/backend/scaffolder/app/server.go +++ b/backend/scaffolder/app/server.go @@ -3,8 +3,11 @@ package app import ( "context" "fmt" + "github.com/golang/protobuf/jsonpb" "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" @@ -30,20 +33,40 @@ func NewServer() *Server { // 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)) - } + 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) // move the template into a temporary directory - tempFolder, _ := s.fs.PrepareTemplate(fs.Template{req.TemplateId}) + tempFolder, err := s.fs.PrepareTemplate( + fs.Template{ + ID: req.TemplateId, + Metadata: req.Metadata, + }, + ) + if err != nil { + return nil, status.Error(codes.Internal, fmt.Sprintf("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() + + fmt.Println(output) + fmt.Println(err) - 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 } diff --git a/backend/scaffolder/cutter/cutter.go b/backend/scaffolder/cutter/cutter.go new file mode 100644 index 0000000000..43857ae99b --- /dev/null +++ b/backend/scaffolder/cutter/cutter.go @@ -0,0 +1,13 @@ +package cutter + +// Cutter is the wrapper around cookiecutter +type Cutter interface { +} + +type Template { + +} +// Run runs cookiecutter in the folder provided +func (c *Cutter) Run() error { + +} diff --git a/backend/scaffolder/fs/fs.go b/backend/scaffolder/fs/fs.go index f7766650ce..de4d720e66 100644 --- a/backend/scaffolder/fs/fs.go +++ b/backend/scaffolder/fs/fs.go @@ -9,7 +9,8 @@ import ( ) // Filesystem Repository -type Filesystem struct{} +type Filesystem struct { +} func file(src, dst string) error { var err error @@ -78,7 +79,6 @@ type Template struct { // 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 } diff --git a/docker-compose.yaml b/docker-compose.yaml index d9d5f2490b..d3903a3b15 100755 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -25,6 +25,7 @@ services: container_name: boss-builds build: context: backend + target: run args: service: builds restart: unless-stopped @@ -34,6 +35,7 @@ services: container_name: boss-scaffolder build: context: backend + target: scaffolder args: service: scaffolder restart: unless-stopped diff --git a/tools/cookiecutter/Dockerfile b/tools/cookiecutter/Dockerfile index 9affb40d0f..106337e3a5 100644 --- a/tools/cookiecutter/Dockerfile +++ b/tools/cookiecutter/Dockerfile @@ -1,3 +1,3 @@ -FROM python:3.8-slim +FROM python:3.8-slim AS scaffolder RUN pip install cookiecutter==1.7.0 --index-url https://pypi.python.org/simple ENTRYPOINT [ "cookiecutter" ] \ No newline at end of file From 4697245252f37d53662cddeab717e5e4675adc67 Mon Sep 17 00:00:00 2001 From: blam Date: Thu, 6 Feb 2020 17:42:23 +0100 Subject: [PATCH 2/6] feat(scaffolder): actually run the cookie cutter now in the folder and pass through the metadata to the cookiecutter.json --- backend/scaffolder/app/server.go | 61 +++++++++++++++++------------ backend/scaffolder/cutter/cutter.go | 58 ++++++++++++++++++++++++--- 2 files changed, 90 insertions(+), 29 deletions(-) diff --git a/backend/scaffolder/app/server.go b/backend/scaffolder/app/server.go index 24a5af326f..d22475d3a1 100644 --- a/backend/scaffolder/app/server.go +++ b/backend/scaffolder/app/server.go @@ -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{ diff --git a/backend/scaffolder/cutter/cutter.go b/backend/scaffolder/cutter/cutter.go index 43857ae99b..36180a4c87 100644 --- a/backend/scaffolder/cutter/cutter.go +++ b/backend/scaffolder/cutter/cutter.go @@ -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 } From d0dddf3a0a8dbc5d7e29b7fb68ce33a80f6472e2 Mon Sep 17 00:00:00 2001 From: blam Date: Thu, 6 Feb 2020 17:45:30 +0100 Subject: [PATCH 3/6] chore(scaffolder): remove the superfluous command --- docker-compose.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index d3903a3b15..ca3218fa0b 100755 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -25,7 +25,6 @@ services: container_name: boss-builds build: context: backend - target: run args: service: builds restart: unless-stopped From 76a6dc3c601e411f67a3fd87ecf6f70b4a7c99d5 Mon Sep 17 00:00:00 2001 From: blam Date: Thu, 6 Feb 2020 17:48:56 +0100 Subject: [PATCH 4/6] chore(scaffolder): setting the run context to default for all containers --- backend/Dockerfile | 4 ++-- docker-compose.yaml | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index ffd64d49b5..317ba42481 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -16,7 +16,7 @@ RUN go build . ### Running Container Stage -FROM debian:buster AS run +FROM debian:buster AS default ARG service WORKDIR /app/ @@ -28,6 +28,6 @@ CMD ["./service"] ### Scaffolder Stage ### needs extra cookiecutter -FROM run AS scaffolder +FROM default AS scaffolder RUN apt-get update && apt-get install -y python-pip RUN pip install cookiecutter==1.7.0 --index-url https://pypi.python.org/simple diff --git a/docker-compose.yaml b/docker-compose.yaml index ca3218fa0b..69ec6cb4e1 100755 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -15,6 +15,7 @@ services: container_name: boss-identity build: context: backend + target: default args: service: identity restart: unless-stopped @@ -25,6 +26,7 @@ services: container_name: boss-builds build: context: backend + target: default args: service: builds restart: unless-stopped From e238860186432e477ff7a668b9a061bae5536a96 Mon Sep 17 00:00:00 2001 From: blam Date: Fri, 7 Feb 2020 09:34:33 +0100 Subject: [PATCH 5/6] feat(scaffolder): Push the repository to github with the access token provided --- backend/scaffolder/app/server.go | 39 +++++--- backend/scaffolder/go.mod | 1 + backend/scaffolder/go.sum | 57 ++++++++++++ backend/scaffolder/{cutter => lib}/cutter.go | 2 +- backend/scaffolder/lib/git.go | 90 +++++++++++++++++++ backend/scaffolder/{remote => lib}/github.go | 7 +- .../react-ssr-template/cookiecutter.json | 5 -- .../react-ssr-template/custom-fields.json | 13 --- .../react-ssr-template/template-info.json | 19 +++- 9 files changed, 195 insertions(+), 38 deletions(-) rename backend/scaffolder/{cutter => lib}/cutter.go (98%) create mode 100644 backend/scaffolder/lib/git.go rename backend/scaffolder/{remote => lib}/github.go (92%) delete mode 100644 backend/scaffolder/templates/react-ssr-template/cookiecutter.json delete mode 100644 backend/scaffolder/templates/react-ssr-template/custom-fields.json diff --git a/backend/scaffolder/app/server.go b/backend/scaffolder/app/server.go index d22475d3a1..d3422e1819 100644 --- a/backend/scaffolder/app/server.go +++ b/backend/scaffolder/app/server.go @@ -4,30 +4,29 @@ import ( "context" "fmt" "github.com/golang/protobuf/jsonpb" + 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/lib" + "github.com/spotify/backstage/scaffolder/repository" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "log" - - 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" ) // Server is the inventory Grpc server type Server struct { repository *repository.Repository - github *remote.Github + github *lib.Github fs *fs.Filesystem - cookie *cutter.Cutter + cookie *lib.Cutter + git *lib.Git } // NewServer creates a new server for with all the things func NewServer() *Server { return &Server{ - github: remote.NewGithubClient(), + github: lib.NewGithubClient(), } } @@ -35,7 +34,7 @@ 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{ + repo := lib.Repository{ Name: req.ComponentId, Org: req.Org, Private: req.Private, @@ -63,7 +62,7 @@ func (s *Server) Create(ctx context.Context, req *pb.CreateRequest) (*pb.CreateR return nil, status.Error(codes.Internal, "Could not marshal the cookiecutter metadata") } - cookieTemplate := cutter.CookieCutterTemplate{ + cookieTemplate := lib.CookieCutterTemplate{ Path: tempFolder, ComponentID: req.ComponentId, Metadata: cutterMetadata, @@ -79,8 +78,20 @@ func (s *Server) Create(ctx context.Context, req *pb.CreateRequest) (*pb.CreateR 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 + // push to github + pushOptions := lib.PushRepositoryOptions{ + TempFolder: tempFolder, + ComponentID: req.ComponentId, + Org: req.Org, + } + + if err := s.git.Push(pushOptions); err != nil { + return nil, status.Error(codes.Internal, "Failed to push the repository to Github") + } + + return &pb.CreateReply{ + ComponentId: req.ComponentId, + }, nil } // ListTemplates returns the local templatess diff --git a/backend/scaffolder/go.mod b/backend/scaffolder/go.mod index c8df6d39e9..dd7fad4812 100644 --- a/backend/scaffolder/go.mod +++ b/backend/scaffolder/go.mod @@ -14,4 +14,5 @@ require ( 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 + gopkg.in/src-d/go-git.v4 v4.13.1 ) diff --git a/backend/scaffolder/go.sum b/backend/scaffolder/go.sum index d280642a93..a49ade72a3 100644 --- a/backend/scaffolder/go.sum +++ b/backend/scaffolder/go.sum @@ -1,9 +1,19 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= +github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -14,14 +24,41 @@ 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-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 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/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY= +github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= +github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= +github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= +golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 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/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 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= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -31,6 +68,10 @@ 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/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 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= @@ -39,12 +80,20 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e h1:D5TXcfTk7xF7hvieo4QErS3qqCB4teTffacDWr7CI+0= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= @@ -54,5 +103,13 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg= +gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= +gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= +gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE= +gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/backend/scaffolder/cutter/cutter.go b/backend/scaffolder/lib/cutter.go similarity index 98% rename from backend/scaffolder/cutter/cutter.go rename to backend/scaffolder/lib/cutter.go index 36180a4c87..501e643dec 100644 --- a/backend/scaffolder/cutter/cutter.go +++ b/backend/scaffolder/lib/cutter.go @@ -1,4 +1,4 @@ -package cutter +package lib import ( "encoding/json" diff --git a/backend/scaffolder/lib/git.go b/backend/scaffolder/lib/git.go new file mode 100644 index 0000000000..38306a208b --- /dev/null +++ b/backend/scaffolder/lib/git.go @@ -0,0 +1,90 @@ +package lib + +import ( + "fmt" + "gopkg.in/src-d/go-git.v4" + "gopkg.in/src-d/go-git.v4/config" + "gopkg.in/src-d/go-git.v4/plumbing/object" + "log" + "os" + "time" +) + +// Git is the wrapper around Git +type Git struct{} + +// PushRepositoryOptions holds the arguments for the push +type PushRepositoryOptions struct { + TempFolder string + ComponentID string + Org string +} + +// Push will push the repository to github +func (g *Git) Push(options PushRepositoryOptions) error { + // use git bindings to add the remote with access token and push to the directory + repo, err := git.PlainInit(options.TempFolder, false) + if err != nil { + log.Printf("Failed to init the git repository") + return err + } + + worktree, err := repo.Worktree() + if err != nil { + log.Printf("Failed to create the worktree") + return err + } + + _, err = worktree.Add(".") + if err != nil { + log.Printf("Failed to add the files to the worktre") + return err + } + + _, err = worktree.Commit("Initial Commit", &git.CommitOptions{ + Author: &object.Signature{ + Name: "Backstage", + Email: "backstage@spotfy.com", + When: time.Now(), + }, + }) + + if err != nil { + log.Printf("Failed to create the initial commit") + return err + } + + var org string = os.Getenv("BOSS_GH_USERNAME") + if options.Org != "" { + org = options.Org + } + + remote := fmt.Sprintf( + "https://%s:%s@github.com/%s/%s.git", + os.Getenv("BOSS_GH_USERNAME"), + os.Getenv("BOSS_GH_ACCESS_TOKEN"), + org, + options.ComponentID, + ) + + _, err = repo.CreateRemote(&config.RemoteConfig{ + Name: "github", + URLs: []string{remote}, + }) + + if err != nil { + log.Printf("Failed to create the remote") + return err + } + + err = repo.Push(&git.PushOptions{ + RemoteName: "github", + }) + + if err != nil { + log.Printf("Failled to push the repository") + return err + } + + return nil +} diff --git a/backend/scaffolder/remote/github.go b/backend/scaffolder/lib/github.go similarity index 92% rename from backend/scaffolder/remote/github.go rename to backend/scaffolder/lib/github.go index 3cc4b9e9e9..ef4bf6ee94 100644 --- a/backend/scaffolder/remote/github.go +++ b/backend/scaffolder/lib/github.go @@ -1,10 +1,10 @@ -package remote +package lib import ( "context" - "fmt" gh "github.com/google/go-github/v29/github" "golang.org/x/oauth2" + "log" "os" ) @@ -19,8 +19,7 @@ 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) + log.Panic("No BOSS_GH_ACCESS_TOKEN set. Cannot continue") } ctx := context.Background() diff --git a/backend/scaffolder/templates/react-ssr-template/cookiecutter.json b/backend/scaffolder/templates/react-ssr-template/cookiecutter.json deleted file mode 100644 index 3a1b2ae344..0000000000 --- a/backend/scaffolder/templates/react-ssr-template/cookiecutter.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "component_id": "", - "owner": "", - "description": "I promise to update this description // {{cookiecutter.owner}}", -} diff --git a/backend/scaffolder/templates/react-ssr-template/custom-fields.json b/backend/scaffolder/templates/react-ssr-template/custom-fields.json deleted file mode 100644 index 1acacc3a25..0000000000 --- a/backend/scaffolder/templates/react-ssr-template/custom-fields.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "schema": [{ - "id": "owner", - "title": "owner", - "type": "text", - "description": "The owner name used to identify the owner of this component", - "validators": [ - { "type": "required" }, - { "type": "string-range", "min": 4, "max": 33 }, - { "type": "regex", "match": "^[a-z][a-z0-9]+$", "message": "Owner names must consist only of lowercase letters" } - ] - }] -} diff --git a/backend/scaffolder/templates/react-ssr-template/template-info.json b/backend/scaffolder/templates/react-ssr-template/template-info.json index f1d3efd9fe..9d99168e07 100644 --- a/backend/scaffolder/templates/react-ssr-template/template-info.json +++ b/backend/scaffolder/templates/react-ssr-template/template-info.json @@ -2,5 +2,22 @@ "id": "react-ssr-template", "name": "React SSR", "description": "Next.js application skeleton for creating isomorphic web applications.", - "ownerId": "ownerId" + "ownerId": "ownerId", + "fields": [ + { + "id": "description", + "title": "description", + "type": "text", + "description": "Description of the component", + "validators": [ + { "type": "required" }, + { "type": "string-range", "min": 4, "max": 33 }, + { + "type": "regex", + "match": "^[a-z][a-z0-9]+$", + "message": "Owner names must consist only of lowercase letters" + } + ] + } + ] } \ No newline at end of file From 1157e333ad9b3b05e060bbf8e7bf7f3b86979726 Mon Sep 17 00:00:00 2001 From: blam Date: Fri, 7 Feb 2020 09:36:26 +0100 Subject: [PATCH 6/6] chore(scaffolder): Should be Fatal not Panic --- backend/scaffolder/lib/github.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/scaffolder/lib/github.go b/backend/scaffolder/lib/github.go index ef4bf6ee94..8c7f03bdf1 100644 --- a/backend/scaffolder/lib/github.go +++ b/backend/scaffolder/lib/github.go @@ -19,7 +19,7 @@ func NewGithubClient() *Github { accessToken := os.Getenv("BOSS_GH_ACCESS_TOKEN") if accessToken == "" { - log.Panic("No BOSS_GH_ACCESS_TOKEN set. Cannot continue") + log.Fatal("No BOSS_GH_ACCESS_TOKEN set. Cannot continue") } ctx := context.Background()