Merge pull request #74 from spotify/blam/run-cookie-cutter

Actually run the Cookie Cutter in the Folder
This commit is contained in:
Ben Lambert
2020-02-07 11:34:09 +01:00
committed by GitHub
13 changed files with 307 additions and 40 deletions
+11 -1
View File
@@ -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 default
ARG service
RUN apt-get update && apt-get install -y ca-certificates
@@ -23,3 +26,10 @@ WORKDIR /app/
COPY --from=build /build/$service/$service /app/service
CMD ["./service"]
### Scaffolder Stage
### needs extra cookiecutter
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
+60 -13
View File
@@ -3,35 +3,38 @@ package app
import (
"context"
"fmt"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"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/remote"
"github.com/spotify/backstage/scaffolder/lib"
"github.com/spotify/backstage/scaffolder/repository"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"log"
)
// Server is the inventory Grpc server
type Server struct {
repository *repository.Repository
github *remote.Github
github *lib.Github
fs *fs.Filesystem
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(),
}
}
// 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{
log.Printf("Creating repository for Component %s", req.ComponentId)
repo := lib.Repository{
Name: req.ComponentId,
Org: req.Org,
Private: req.Private,
@@ -41,16 +44,59 @@ func (s *Server) Create(ctx context.Context, req *pb.CreateRequest) (*pb.CreateR
}
// 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,
},
)
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
if err != nil {
return nil, status.Error(codes.Internal, "Could not prepare the template")
}
// get the optional metadatafields from the json
marshaler := &jsonpb.Marshaler{}
cutterMetadata, err := marshaler.MarshalToString(req.Metadata)
if err != nil {
return nil, status.Error(codes.Internal, "Could not marshal the cookiecutter metadata")
}
cookieTemplate := lib.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")
}
// 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
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
@@ -59,6 +105,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{
+2 -2
View File
@@ -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
}
+1
View File
@@ -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
)
+57
View File
@@ -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=
+61
View File
@@ -0,0 +1,61 @@
package lib
import (
"encoding/json"
"fmt"
"log"
"os"
"os/exec"
)
// Cutter is the wrapper around cookiecutter
type Cutter struct {
}
// CookieCutterTemplate holds the template ID and metadata for copying
type CookieCutterTemplate struct {
Path string
Metadata string
ComponentID string
}
// 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
}
+90
View File
@@ -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
}
@@ -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.Fatal("No BOSS_GH_ACCESS_TOKEN set. Cannot continue")
}
ctx := context.Background()
@@ -1,5 +0,0 @@
{
"component_id": "",
"owner": "",
"description": "I promise to update this description // {{cookiecutter.owner}}",
}
@@ -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" }
]
}]
}
@@ -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"
}
]
}
]
}
+3
View File
@@ -15,6 +15,7 @@ services:
container_name: boss-identity
build:
context: backend
target: default
args:
service: identity
restart: unless-stopped
@@ -33,6 +34,7 @@ services:
container_name: boss-builds
build:
context: backend
target: default
args:
service: builds
restart: unless-stopped
@@ -42,6 +44,7 @@ services:
container_name: boss-scaffolder
build:
context: backend
target: scaffolder
args:
service: scaffolder
restart: unless-stopped
+1 -1
View File
@@ -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" ]