diff --git a/go/porcelain/deploy.go b/go/porcelain/deploy.go index e62f5755..55ac090c 100644 --- a/go/porcelain/deploy.go +++ b/go/porcelain/deploy.go @@ -41,6 +41,8 @@ const ( functionUpload lfsVersionString = "version https://git-lfs.github.com/spec/v1" + + edgeFunctionsInternalPath = ".netlify/internal/edge-functions/" ) var installDirs = []string{"node_modules/", "bower_components/"} @@ -75,6 +77,7 @@ type DeployOptions struct { SiteID string Dir string FunctionsDir string + EdgeFunctionsDir string BuildDir string LargeMediaEnabled bool @@ -210,6 +213,16 @@ func (n *Netlify) DoDeploy(ctx context.Context, options *DeployOptions, deploy * } } + if options.EdgeFunctionsDir != "" { + err = addEdgeFunctionsToDeployFiles(options.EdgeFunctionsDir, files, options.Observer) + if err != nil { + if options.Observer != nil { + options.Observer.OnFailedWalk() + } + return nil, err + } + } + options.files = files functions, schedules, err := bundle(ctx, options.FunctionsDir, options.Observer) @@ -513,6 +526,28 @@ func (n *Netlify) uploadFile(ctx context.Context, d *models.Deploy, f *FileBundl } } +func createFileBundle(rel, path string) (*FileBundle, error) { + o, err := os.Open(path) + if err != nil { + return nil, err + } + defer o.Close() + + file := &FileBundle{ + Name: rel, + Path: path, + } + + s := sha1.New() + if _, err := io.Copy(s, o); err != nil { + return nil, err + } + + file.Sum = hex.EncodeToString(s.Sum(nil)) + + return file, nil +} + func walk(dir string, observer DeployObserver, useLargeMedia, ignoreInstallDirs bool) (*deployFiles, error) { files := newDeployFiles() @@ -532,22 +567,10 @@ func walk(dir string, observer DeployObserver, useLargeMedia, ignoreInstallDirs return nil } - o, err := os.Open(path) + file, err := createFileBundle(rel, path) if err != nil { return err } - defer o.Close() - - file := &FileBundle{ - Name: rel, - Path: path, - } - - s := sha1.New() - if _, err := io.Copy(s, o); err != nil { - return err - } - file.Sum = hex.EncodeToString(s.Sum(nil)) if useLargeMedia { o, err := os.Open(path) @@ -585,6 +608,37 @@ func walk(dir string, observer DeployObserver, useLargeMedia, ignoreInstallDirs return files, err } +func addEdgeFunctionsToDeployFiles(dir string, files *deployFiles, observer DeployObserver) error { + return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + if !info.IsDir() && info.Mode().IsRegular() { + osRel, err := filepath.Rel(dir, path) + if err != nil { + return err + } + rel := edgeFunctionsInternalPath + forceSlashSeparators(osRel) + + file, err := createFileBundle(rel, path) + if err != nil { + return err + } + + files.Add(rel, file) + + if observer != nil { + if err := observer.OnSuccessfulStep(file); err != nil { + return err + } + } + } + + return nil + }) +} + func bundle(ctx context.Context, functionDir string, observer DeployObserver) (*deployFiles, []*models.FunctionSchedule, error) { if functionDir == "" { return nil, nil, nil diff --git a/go/porcelain/deploy_test.go b/go/porcelain/deploy_test.go index 7f49d4cd..c0034fc5 100644 --- a/go/porcelain/deploy_test.go +++ b/go/porcelain/deploy_test.go @@ -170,6 +170,66 @@ func TestWalk_IgnoreNodeModulesInRoot(t *testing.T) { assert.NotNil(t, files.Files["more/node_modules/inner-package"]) } +func TestWalk_EdgeFunctions(t *testing.T) { + files := newDeployFiles() + + netlifyDir, err := ioutil.TempDir("", ".netlify") + require.Nil(t, err) + defer os.RemoveAll(netlifyDir) + + edgeFunctionsDir, err := ioutil.TempDir(netlifyDir, "edge-functions-dist") + require.Nil(t, err) + defer os.RemoveAll(edgeFunctionsDir) + + err = ioutil.WriteFile(filepath.Join(edgeFunctionsDir, "manifest.json"), []byte{}, 0644) + require.Nil(t, err) + err = ioutil.WriteFile(filepath.Join(edgeFunctionsDir, "123456789.js"), []byte{}, 0644) + require.Nil(t, err) + + err = addEdgeFunctionsToDeployFiles(edgeFunctionsDir, files, mockObserver{}) + require.Nil(t, err) + + assert.NotNil(t, files.Files[".netlify/internal/edge-functions/manifest.json"]) + assert.NotNil(t, files.Files[".netlify/internal/edge-functions/123456789.js"]) +} + +func TestWalk_PublishedFilesAndEdgeFunctions(t *testing.T) { + publishDir, err := ioutil.TempDir("", "publish") + require.Nil(t, err) + defer os.RemoveAll(publishDir) + + netlifyDir, err := ioutil.TempDir("", ".netlify") + require.Nil(t, err) + defer os.RemoveAll(netlifyDir) + + edgeFunctionsDir, err := ioutil.TempDir(netlifyDir, "edge-functions-dist") + require.Nil(t, err) + defer os.RemoveAll(edgeFunctionsDir) + + err = os.Mkdir(filepath.Join(publishDir, "assets"), os.ModePerm) + require.Nil(t, err) + err = ioutil.WriteFile(filepath.Join(publishDir, "assets", "styles.css"), []byte{}, 0644) + require.Nil(t, err) + err = ioutil.WriteFile(filepath.Join(publishDir, "index.html"), []byte{}, 0644) + require.Nil(t, err) + + err = ioutil.WriteFile(filepath.Join(edgeFunctionsDir, "manifest.json"), []byte{}, 0644) + require.Nil(t, err) + err = ioutil.WriteFile(filepath.Join(edgeFunctionsDir, "123456789.js"), []byte{}, 0644) + require.Nil(t, err) + + files, err := walk(publishDir, mockObserver{}, false, false) + require.Nil(t, err) + + err = addEdgeFunctionsToDeployFiles(edgeFunctionsDir, files, mockObserver{}) + require.Nil(t, err) + + assert.NotNil(t, files.Files["assets/styles.css"]) + assert.NotNil(t, files.Files["index.html"]) + assert.NotNil(t, files.Files[".netlify/internal/edge-functions/manifest.json"]) + assert.NotNil(t, files.Files[".netlify/internal/edge-functions/123456789.js"]) +} + func TestUploadFiles_Cancelation(t *testing.T) { ctx, cancel := gocontext.WithCancel(gocontext.Background()) server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {