diff --git a/cmd/up.go b/cmd/up.go new file mode 100644 index 000000000..924f00828 --- /dev/null +++ b/cmd/up.go @@ -0,0 +1,11 @@ +package cmd + +import ( + "context" + + "github.com/railwayapp/cli/entity" +) + +func (h *Handler) Up(ctx context.Context, req *entity.CommandRequest) error { + return h.ctrl.Up(ctx) +} diff --git a/controller/up.go b/controller/up.go new file mode 100644 index 000000000..4cfa2728c --- /dev/null +++ b/controller/up.go @@ -0,0 +1,95 @@ +package controller + +import ( + "archive/tar" + "bytes" + "compress/gzip" + "context" + "io" + "io/ioutil" + "os" + "path/filepath" + + "github.com/monochromegane/go-gitignore" +) + +func compress(src string, buf io.Writer) error { + // tar > gzip > buf + zr := gzip.NewWriter(buf) + tw := tar.NewWriter(zr) + + ignore, err := gitignore.NewGitIgnore(".gitignore", ".") + if err != nil { + return err + } + // walk through every file in the folder + filepath.Walk(src, func(file string, fi os.FileInfo, err error) error { + if ignore.Match(file, fi.IsDir()) { + return nil + } + // generate tar header + header, err := tar.FileInfoHeader(fi, file) + if err != nil { + return err + } + + if err != nil { + return err + } + // must provide real name + // (see https://golang.org/src/archive/tar/common.go?#L626) + header.Name = filepath.ToSlash(file) + + // write header + if err := tw.WriteHeader(header); err != nil { + return err + } + // if not a dir, write file content + if !fi.IsDir() { + data, err := os.Open(file) + if err != nil { + return err + } + if _, err := io.Copy(tw, data); err != nil { + return err + } + } + return nil + }) + + // produce tar + if err := tw.Close(); err != nil { + return err + } + // produce gzip + if err := zr.Close(); err != nil { + return err + } + return nil +} + +func (c *Controller) Up(ctx context.Context) error { + // projectID, err := c.cfg.GetProject() + // if err != nil { + // return err + // } + // environmentID, err := c.cfg.GetEnvironment() + // if err != nil { + // return err + // } + var buf bytes.Buffer + if err := compress("./", &buf); err != nil { + return err + } + ioutil.WriteFile("./out.tar.gz", buf.Bytes(), 0777) + // res, err := c.gtwy.Up(ctx, &entity.UpRequest{ + // Data: buf, + // ProjectID: projectID, + // EnvironmentID: environmentID, + // }) + // if err != nil { + // return err + // } + //fmt.Printf("Deploy available at %s\n", res.URL) + return nil +} diff --git a/entity/requests.go b/entity/requests.go new file mode 100644 index 000000000..9d93fdfd6 --- /dev/null +++ b/entity/requests.go @@ -0,0 +1,13 @@ +package entity + +import "bytes" + +type UpRequest struct { + Data bytes.Buffer + ProjectID string + EnvironmentID string +} + +type UpResponse struct { + URL string +} diff --git a/gateway/main.go b/gateway/main.go index 6f56d28c9..b8cde46e3 100644 --- a/gateway/main.go +++ b/gateway/main.go @@ -32,12 +32,16 @@ func (g *Gateway) setProjectToken(ctx context.Context, req *gql.Request) error { return nil } -func GetGQLHost() string { +func GetHost() string { baseURL := "https://backboard.railway.app" if configs.IsDevMode() { baseURL = fmt.Sprintf("http://localhost:8082") } + return baseURL +} +func GetGQLHost() string { + baseURL := GetHost() return fmt.Sprintf("%s/graphql", baseURL) } diff --git a/gateway/up.go b/gateway/up.go new file mode 100644 index 000000000..7a4698323 --- /dev/null +++ b/gateway/up.go @@ -0,0 +1,60 @@ +package gateway + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "mime/multipart" + "net/http" + + "github.com/railwayapp/cli/entity" +) + +func constructReq(ctx context.Context, req *entity.UpRequest) (*http.Request, error) { + body := new(bytes.Buffer) + writer := multipart.NewWriter(body) + part, err := writer.CreateFormFile("file", req.ProjectID) + if err != nil { + return nil, err + } + part.Write(req.Data.Bytes()) + + err = writer.Close() + if err != nil { + return nil, err + } + url := fmt.Sprintf("%s/project/%s/up", GetHost(), req.ProjectID) + httpReq, err := http.NewRequest("POST", url, body) + if err != nil { + return nil, err + } + httpReq.Header.Set("Content-Type", writer.FormDataContentType()) + return httpReq, nil +} + +func (g *Gateway) Up(ctx context.Context, req *entity.UpRequest) (*entity.UpResponse, error) { + httpReq, err := constructReq(ctx, req) + if err != nil { + return nil, err + } + client := &http.Client{} + resp, err := client.Do(httpReq) + if err != nil { + return nil, err + } + bodyBytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + if resp.StatusCode < 200 || resp.StatusCode >= 400 { + return nil, errors.New(string(bodyBytes)) + } + var res entity.UpResponse + if err := json.Unmarshal(bodyBytes, &res); err != nil { + return nil, err + } + return &res, nil +} diff --git a/go.mod b/go.mod index 1bb23bcdf..2303f316e 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 github.com/machinebox/graphql v0.2.2 github.com/manifoldco/promptui v0.7.0 + github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4 github.com/spf13/cobra v1.0.0 diff --git a/go.sum b/go.sum index d8aa617ba..b93de067c 100644 --- a/go.sum +++ b/go.sum @@ -148,6 +148,8 @@ github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQz github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= diff --git a/main.go b/main.go index f6492ca2a..a173353a8 100644 --- a/main.go +++ b/main.go @@ -92,6 +92,11 @@ func init() { Short: "Run command inside the Railway environment", RunE: contextualize(handler.Run), }) + rootCmd.AddCommand(&cobra.Command{ + Use: "up", + Short: "Upload and deploy", + RunE: contextualize(handler.Up), + }) } func main() {