Просмотр исходного кода

Separate runtimes for API and CLI for Node

Mohammed Nafees 4 лет назад
Родитель
Сommit
e1ed49f974

+ 1 - 1
Makefile

@@ -20,5 +20,5 @@ build-cli-dev:
 	go build -tags cli -o $(BINDIR)/porter ./cli
 
 test-runtime:
-	cp ./cmd/test-runtime/buildpacks/nodejs.buildpack.toml $(BINDIR)/
+	cp ./cmd/test-runtime/buildpacks-toml/nodejs.buildpack.toml $(BINDIR)/
 	go build -tags test-runtime -o $(BINDIR)/test-runtime ./cmd/test-runtime

+ 9 - 25
api/server/handlers/gitinstallation/get_buildpack.go

@@ -11,6 +11,7 @@ import (
 	"github.com/porter-dev/porter/api/server/shared/apierrors"
 	"github.com/porter-dev/porter/api/server/shared/config"
 	"github.com/porter-dev/porter/api/types"
+	"github.com/porter-dev/porter/internal/integrations/buildpacks"
 )
 
 type GithubGetBuildpackHandler struct {
@@ -71,34 +72,17 @@ func (c *GithubGetBuildpackHandler) ServeHTTP(w http.ResponseWriter, r *http.Req
 		return
 	}
 
-	var BREQS = map[string]string{
-		"requirements.txt": "Python",
-		"Gemfile":          "Ruby",
-		"package.json":     "Node.js",
-		"pom.xml":          "Java",
-		"composer.json":    "PHP",
-	}
-
-	res := &types.GetBuildpackResponse{
-		Valid: true,
-	}
-
-	matches := 0
+	res := &types.GetBuildpackResponse{}
 
-	for i := range directoryContents {
-		name := *directoryContents[i].Name
-
-		bname, ok := BREQS[name]
-		if ok {
-			matches++
-			res.Name = bname
+	nodeRuntime := buildpacks.NewAPINodeRuntime()
+	config := nodeRuntime.Detect(directoryContents)
+	if config != nil {
+		res.Name = "Node.js"
+		res.Runtime = config["runtime"].(string)
+		if res.Runtime != "node-standalone" {
+			res.Config = map[string]interface{}{"scripts": config["scripts"], "node_engine": config["node_engine"]}
 		}
 	}
 
-	if matches != 1 {
-		res.Valid = false
-		res.Name = ""
-	}
-
 	c.WriteResult(w, r, res)
 }

+ 3 - 2
api/types/git_installation.go

@@ -40,8 +40,9 @@ type GetBuildpackRequest struct {
 }
 
 type GetBuildpackResponse struct {
-	Valid bool   `json:"valid"`
-	Name  string `json:"name"`
+	Name    string                 `json:"name"`
+	Runtime string                 `json:"runtime"`
+	Config  map[string]interface{} `json:"config"`
 }
 
 type GetContentsRequest struct {

+ 0 - 0
cmd/test-runtime/buildpacks/nodejs.buildpack.toml → cmd/test-runtime/buildpacks-toml/nodejs.buildpack.toml


+ 2 - 2
cmd/test-runtime/main.go

@@ -14,7 +14,7 @@ import (
 	"github.com/paketo-buildpacks/rackup"
 	railsassets "github.com/paketo-buildpacks/rails-assets"
 	"github.com/paketo-buildpacks/rake"
-	"github.com/porter-dev/porter/cmd/test-runtime/runtimes"
+	"github.com/porter-dev/porter/internal/integrations/buildpacks"
 )
 
 const GoModLocation = "go.mod"
@@ -144,7 +144,7 @@ func main() {
 
 	workingDir = os.Args[1]
 
-	nodeRuntime := runtimes.NewNodeRuntime()
+	nodeRuntime := buildpacks.NewCLINodeRuntime()
 	buildpackInfo, data := nodeRuntime.Detect(workingDir)
 	if data != nil {
 		fmt.Println(data)

+ 164 - 0
internal/integrations/buildpacks/api_nodejs.go

@@ -0,0 +1,164 @@
+package buildpacks
+
+import (
+	"encoding/json"
+	"strings"
+	"sync"
+
+	"github.com/google/go-github/github"
+)
+
+type apiNodeRuntime struct {
+	wg sync.WaitGroup
+}
+
+func NewAPINodeRuntime() *apiNodeRuntime {
+	return &apiNodeRuntime{}
+}
+
+func (runtime *apiNodeRuntime) detectYarn(results chan struct {
+	string
+	bool
+}, directoryContent []*github.RepositoryContent) {
+	yarnLockFound := false
+	packageJSONFound := false
+	for i := 0; i < len(directoryContent); i++ {
+		name := directoryContent[i].GetName()
+		if name == "yarn.lock" {
+			yarnLockFound = true
+		} else if name == "package.json" {
+			packageJSONFound = true
+		}
+		if yarnLockFound && packageJSONFound {
+			break
+		}
+	}
+	if yarnLockFound && packageJSONFound {
+		results <- struct {
+			string
+			bool
+		}{yarn, true}
+	} else {
+		results <- struct {
+			string
+			bool
+		}{yarn, false}
+	}
+	runtime.wg.Done()
+}
+
+func (runtime *apiNodeRuntime) detectNPM(results chan struct {
+	string
+	bool
+}, directoryContent []*github.RepositoryContent) {
+	packageJSONFound := false
+	for i := 0; i < len(directoryContent); i++ {
+		name := directoryContent[i].GetName()
+		if name == "package.json" {
+			packageJSONFound = true
+			break
+		}
+	}
+	if packageJSONFound {
+		results <- struct {
+			string
+			bool
+		}{npm, true}
+	} else {
+		results <- struct {
+			string
+			bool
+		}{npm, false}
+	}
+	runtime.wg.Done()
+}
+
+func (runtime *apiNodeRuntime) detectStandalone(results chan struct {
+	string
+	bool
+}, directoryContent []*github.RepositoryContent) {
+	jsFileFound := false
+	for i := 0; i < len(directoryContent); i++ {
+		name := directoryContent[i].GetName()
+		if name == "server.js" || name == "app.js" || name == "main.js" || name == "index.js" {
+			jsFileFound = true
+			break
+		}
+	}
+	if jsFileFound {
+		results <- struct {
+			string
+			bool
+		}{standalone, true}
+	} else {
+		results <- struct {
+			string
+			bool
+		}{standalone, false}
+	}
+	runtime.wg.Done()
+}
+
+func (runtime *apiNodeRuntime) Detect(directoryContent []*github.RepositoryContent) map[string]interface{} {
+	results := make(chan struct {
+		string
+		bool
+	}, 3)
+
+	runtime.wg.Add(3)
+	go runtime.detectYarn(results, directoryContent)
+	go runtime.detectNPM(results, directoryContent)
+	go runtime.detectStandalone(results, directoryContent)
+	runtime.wg.Wait()
+	close(results)
+
+	atLeastOne := false
+	detected := make(map[string]bool)
+	for result := range results {
+		if result.bool {
+			atLeastOne = true
+		}
+		detected[result.string] = result.bool
+	}
+
+	if atLeastOne {
+		if detected[yarn] || detected[npm] {
+			// it is safe to assume that the project contains a package.json
+			var packageJSONRef *github.RepositoryContent
+			for i := 0; i < len(directoryContent); i++ {
+				name := directoryContent[i].GetName()
+				if name == "package.json" {
+					packageJSONRef = directoryContent[i]
+					break
+				}
+			}
+			content, err := packageJSONRef.GetContent()
+			if err != nil {
+				// FIXME: log somewhere
+				return nil
+			}
+			var packageJSON struct {
+				Scripts map[string]string `json:"scripts"`
+				Engines struct {
+					Node string `json:"node"`
+				} `json:"engines"`
+			}
+			err = json.NewDecoder(strings.NewReader(content)).Decode(&packageJSON)
+			if err != nil {
+				// FIXME: log somewhere
+				return nil
+			}
+
+			if detected[yarn] {
+				return map[string]interface{}{"runtime": yarn, "scripts": packageJSON.Scripts, "node_engine": packageJSON.Engines.Node}
+			} else {
+				return map[string]interface{}{"runtime": npm, "scripts": packageJSON.Scripts, "node_engine": packageJSON.Engines.Node}
+
+			}
+		}
+
+		return map[string]interface{}{"runtime": "node-standalone"}
+	}
+
+	return nil
+}

+ 8 - 8
cmd/test-runtime/runtimes/go.go → internal/integrations/buildpacks/cli_go.go

@@ -1,4 +1,4 @@
-package runtimes
+package buildpacks
 
 import (
 	"sync"
@@ -7,7 +7,7 @@ import (
 	"github.com/paketo-buildpacks/packit"
 )
 
-type goRuntime struct {
+type cliGoRuntime struct {
 	packs map[string]*BuildpackInfo
 	wg    sync.WaitGroup
 }
@@ -17,7 +17,7 @@ const (
 	dep = "dep"
 )
 
-func NewGoRuntime() *goRuntime {
+func NewCLIGoRuntime() *cliGoRuntime {
 	packs := make(map[string]*BuildpackInfo)
 
 	// mod
@@ -29,12 +29,12 @@ func NewGoRuntime() *goRuntime {
 	// go build
 	packs[standalone] = newBuildpackInfo()
 
-	return &goRuntime{
+	return &cliGoRuntime{
 		packs: packs,
 	}
 }
 
-func (runtime *goRuntime) detectMod(results chan struct {
+func (runtime *cliGoRuntime) detectMod(results chan struct {
 	string
 	bool
 }, workingDir string) {
@@ -58,7 +58,7 @@ func (runtime *goRuntime) detectMod(results chan struct {
 	runtime.wg.Done()
 }
 
-func (runtime *goRuntime) detectDep(results chan struct {
+func (runtime *cliGoRuntime) detectDep(results chan struct {
 	string
 	bool
 }, workingDir string) {
@@ -66,7 +66,7 @@ func (runtime *goRuntime) detectDep(results chan struct {
 	runtime.wg.Done()
 }
 
-func (runtime *goRuntime) detectStandalone(results chan struct {
+func (runtime *cliGoRuntime) detectStandalone(results chan struct {
 	string
 	bool
 }, workingDir string) {
@@ -74,7 +74,7 @@ func (runtime *goRuntime) detectStandalone(results chan struct {
 	runtime.wg.Done()
 }
 
-func (runtime *goRuntime) Detect(workingDir string) (BuildpackInfo, map[string]interface{}) {
+func (runtime *cliGoRuntime) Detect(workingDir string) (BuildpackInfo, map[string]interface{}) {
 	results := make(chan struct {
 		string
 		bool

+ 9 - 14
cmd/test-runtime/runtimes/nodejs.go → internal/integrations/buildpacks/cli_nodejs.go

@@ -1,4 +1,4 @@
-package runtimes
+package buildpacks
 
 import (
 	"fmt"
@@ -14,19 +14,14 @@ import (
 	"github.com/pelletier/go-toml"
 )
 
-const (
-	yarn = "yarn"
-	npm  = "npm"
+const nodejsTomlFile = "nodejs.buildpack.toml"
 
-	nodejsTomlFile = "nodejs.buildpack.toml"
-)
-
-type nodeRuntime struct {
+type cliNodeRuntime struct {
 	packs map[string]*BuildpackInfo
 	wg    sync.WaitGroup
 }
 
-func NewNodeRuntime() *nodeRuntime {
+func NewCLINodeRuntime() *cliNodeRuntime {
 	packs := make(map[string]*BuildpackInfo)
 
 	buildpackToml, err := toml.LoadFile(filepath.Join(getExecPath(), nodejsTomlFile))
@@ -94,12 +89,12 @@ func NewNodeRuntime() *nodeRuntime {
 	packs[standalone].addEnvVar("BP_LAUNCHPOINT", "")
 	packs[standalone].addEnvVar("BP_LIVE_RELOAD_ENABLED", "")
 
-	return &nodeRuntime{
+	return &cliNodeRuntime{
 		packs: packs,
 	}
 }
 
-func (runtime *nodeRuntime) detectYarn(results chan struct {
+func (runtime *cliNodeRuntime) detectYarn(results chan struct {
 	string
 	bool
 }, workingDir string) {
@@ -123,7 +118,7 @@ func (runtime *nodeRuntime) detectYarn(results chan struct {
 	runtime.wg.Done()
 }
 
-func (runtime *nodeRuntime) detectNPM(results chan struct {
+func (runtime *cliNodeRuntime) detectNPM(results chan struct {
 	string
 	bool
 }, workingDir string) {
@@ -147,7 +142,7 @@ func (runtime *nodeRuntime) detectNPM(results chan struct {
 	runtime.wg.Done()
 }
 
-func (runtime *nodeRuntime) detectStandalone(results chan struct {
+func (runtime *cliNodeRuntime) detectStandalone(results chan struct {
 	string
 	bool
 }, workingDir string) {
@@ -170,7 +165,7 @@ func (runtime *nodeRuntime) detectStandalone(results chan struct {
 	runtime.wg.Done()
 }
 
-func (runtime *nodeRuntime) Detect(workingDir string) (BuildpackInfo, map[string]interface{}) {
+func (runtime *cliNodeRuntime) Detect(workingDir string) (BuildpackInfo, map[string]interface{}) {
 	results := make(chan struct {
 		string
 		bool

+ 13 - 3
cmd/test-runtime/runtimes/common.go → internal/integrations/buildpacks/common.go

@@ -1,11 +1,17 @@
-package runtimes
+package buildpacks
 
 import (
 	"os"
 	"path/filepath"
+
+	"github.com/google/go-github/github"
 )
 
-const standalone = "standalone"
+const (
+	yarn       = "yarn"
+	npm        = "npm"
+	standalone = "standalone"
+)
 
 type buildpackOrderGroupInfo struct {
 	ID       string
@@ -42,6 +48,10 @@ func getExecPath() string {
 	return filepath.Dir(ex)
 }
 
-type Runtime interface {
+type CLIRuntime interface {
 	Detect(string) (BuildpackInfo, map[string]interface{})
 }
+
+type APIRuntime interface {
+	Detect([]*github.RepositoryContent) map[string]interface{}
+}