Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add command to provide starter project information #3173

Merged
merged 10 commits into from
Jun 26, 2020
20 changes: 20 additions & 0 deletions pkg/devfile/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,23 @@ func Parse(path string) (d devfileParser.DevfileObj, err error) {
// Successful
return d, nil
}

// ParseInMemory func parses and validates the devfile integrity.
// Creates devfile context and runtime objects
func ParseInMemory(data []byte) (d devfileParser.DevfileObj, err error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like it would make sense to make all file/path based functions extract their bytes and then call the "in-memory" functions instead of more or less duplicating code at several levels to do the same kind of thing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried doing this but found that some commands ran a lot slower as we would have to download the file to memory every time :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, let's not do that right now then, I'll take a look once this is merged.


// read and parse devfile from given data
d, err = devfileParser.ParseInMemory(data)
if err != nil {
return d, err
}

// odo specific validation on devfile content
err = validate.ValidateDevfileData(d.Data)
if err != nil {
return d, err
}

// Successful
return d, nil
}
9 changes: 8 additions & 1 deletion pkg/devfile/parser/context/content.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func hasPrefix(buf []byte, prefix []byte) bool {
return bytes.HasPrefix(trim, prefix)
}

// SetDevfileContent reads devfile and if devfile is in YAML format converts is to JSON
// SetDevfileContent reads devfile and if devfile is in YAML format converts it to JSON
func (d *DevfileCtx) SetDevfileContent() error {

// Read devfile
Expand All @@ -55,7 +55,14 @@ func (d *DevfileCtx) SetDevfileContent() error {
return errors.Wrapf(err, "failed to read devfile from path '%s'", d.absPath)
}

// set devfile content
return d.SetDevfileContentFromBytes(data)
}

// SetDevfileContentFromBytes sets devfile content from byte input
func (d *DevfileCtx) SetDevfileContentFromBytes(data []byte) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function should be called from SetDevfileContent once bytes are extracted from file to avoid code duplication

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

// If YAML file convert it to JSON
var err error
d.rawContent, err = YAMLToJSON(data)
if err != nil {
return err
Expand Down
83 changes: 79 additions & 4 deletions pkg/devfile/parser/context/content_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@ import (
"github.com/openshift/odo/pkg/testingutil/filesystem"
)

const (
TempJSONDevfilePrefix = "odo-devfile.*.json"
InvalidDevfileContent = ":: invalid :: content"
)

func TestSetDevfileContent(t *testing.T) {

const (
TempJsonDevfilePrefix = "odo-devfile.*.json"
InvalidDevfilePath = "/invalid/path"
InvalidDevfileContent = ":: invalid :: content"
InvalidDevfilePath = "/invalid/path"
)

// createTempDevfile helper creates temp devfile
Expand All @@ -21,7 +24,7 @@ func TestSetDevfileContent(t *testing.T) {
t.Helper()

// Create tempfile
f, err := fakeFs.TempFile(os.TempDir(), TempJsonDevfilePrefix)
f, err := fakeFs.TempFile(os.TempDir(), TempJSONDevfilePrefix)
if err != nil {
t.Errorf("failed to create temp devfile, %v", err)
return f
Expand Down Expand Up @@ -100,3 +103,75 @@ func TestSetDevfileContent(t *testing.T) {
}
})
}

func TestSetDevfileContentFromBytes(t *testing.T) {

// createTempDevfile helper creates temp devfile
createTempDevfile := func(t *testing.T, content []byte, fakeFs filesystem.Filesystem) (f filesystem.File) {

t.Helper()

// Create tempfile
f, err := fakeFs.TempFile(os.TempDir(), TempJSONDevfilePrefix)
if err != nil {
t.Errorf("failed to create temp devfile, %v", err)
return f
}

// Write content to devfile
if _, err := f.Write(content); err != nil {
t.Errorf("failed to write to temp devfile")
return f
}

// Successful
return f
}

t.Run("valid data passed", func(t *testing.T) {

var (
fakeFs = filesystem.NewFakeFs()
tempDevfile = createTempDevfile(t, validJsonRawContent100(), fakeFs)
d = DevfileCtx{
absPath: tempDevfile.Name(),
Fs: fakeFs,
}
)

defer os.Remove(tempDevfile.Name())

err := d.SetDevfileContentFromBytes(validJsonRawContent100())

if err != nil {
t.Errorf("unexpected error '%v'", err)
}

if err := tempDevfile.Close(); err != nil {
t.Errorf("failed to close temp devfile")
}
})

t.Run("invalid data passed", func(t *testing.T) {

var (
fakeFs = filesystem.NewFakeFs()
tempDevfile = createTempDevfile(t, []byte(validJsonRawContent100()), fakeFs)
d = DevfileCtx{
absPath: tempDevfile.Name(),
Fs: fakeFs,
}
)
defer os.Remove(tempDevfile.Name())

err := d.SetDevfileContentFromBytes([]byte(InvalidDevfileContent))

if err == nil {
t.Errorf("expected error, didn't get one ")
}

if err := tempDevfile.Close(); err != nil {
t.Errorf("failed to close temp devfile")
}
})
}
40 changes: 25 additions & 15 deletions pkg/devfile/parser/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,24 @@ func NewDevfileCtx(path string) DevfileCtx {
}
}

// populateDevfile checks the API version is supported and returns the JSON schema for the given devfile API Version
func (d *DevfileCtx) populateDevfile() (err error) {

// Get devfile APIVersion
if err := d.SetDevfileAPIVersion(); err != nil {
return err
}

// Check if the apiVersion is supported
if !d.IsApiVersionSupported() {
return fmt.Errorf("devfile apiVersion '%s' not supported in odo", d.apiVersion)
}
klog.V(4).Infof("devfile apiVersion '%s' is supported in odo", d.apiVersion)

// Read and save devfile JSON schema for provided apiVersion
return d.SetDevfileJSONSchema()
}

// Populate fills the DevfileCtx struct with relevant context info
func (d *DevfileCtx) Populate() (err error) {

Expand All @@ -51,25 +69,17 @@ func (d *DevfileCtx) Populate() (err error) {
if err := d.SetDevfileContent(); err != nil {
return err
}
return d.populateDevfile()
}

// Get devfile APIVersion
if err := d.SetDevfileAPIVersion(); err != nil {
return err
}

// Check if the apiVersion is supported
if !d.IsApiVersionSupported() {
return fmt.Errorf("devfile apiVersion '%s' not supported in odo", d.apiVersion)
}
klog.V(4).Infof("devfile apiVersion '%s' is supported in odo", d.apiVersion)
// PopulateFromBytes fills the DevfileCtx struct with relevant context info
func (d *DevfileCtx) PopulateFromBytes(bytes []byte) (err error) {

// Read and save devfile JSON schema for provided apiVersion
if err := d.SetDevfileJSONSchema(); err != nil {
// Read and save devfile content
if err := d.SetDevfileContentFromBytes(bytes); err != nil {
return err
}

// Successful
return nil
return d.populateDevfile()
}

// Validate func validates devfile JSON schema for the given apiVersion
Expand Down
100 changes: 100 additions & 0 deletions pkg/devfile/parser/context/context_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package parser

import (
"os"
"testing"

"github.com/openshift/odo/pkg/testingutil/filesystem"
)

func TestPopulateFromBytes(t *testing.T) {

const (
InvalidDevfilePath = "/invalid/path"
)

// createTempDevfile helper creates temp devfile
createTempDevfile := func(t *testing.T, content []byte, fakeFs filesystem.Filesystem) (f filesystem.File) {

t.Helper()

// Create tempfile
f, err := fakeFs.TempFile(os.TempDir(), TempJSONDevfilePrefix)
if err != nil {
t.Errorf("failed to create temp devfile, %v", err)
return f
}

// Write content to devfile
if _, err := f.Write(content); err != nil {
t.Errorf("failed to write to temp devfile")
return f
}

// Successful
return f
}

t.Run("valid data passed", func(t *testing.T) {

var (
fakeFs = filesystem.NewFakeFs()
tempDevfile = createTempDevfile(t, validJsonRawContent100(), fakeFs)
d = DevfileCtx{
absPath: tempDevfile.Name(),
Fs: fakeFs,
}
)
defer os.Remove(tempDevfile.Name())

err := d.PopulateFromBytes(validJsonRawContent100())

if err != nil {
t.Errorf("unexpected error '%v'", err)
}

if err := tempDevfile.Close(); err != nil {
t.Errorf("failed to close temp devfile")
}
})

t.Run("invalid data passed", func(t *testing.T) {

var (
fakeFs = filesystem.NewFakeFs()
tempDevfile = createTempDevfile(t, []byte(validJsonRawContent100()), fakeFs)
d = DevfileCtx{
absPath: tempDevfile.Name(),
Fs: fakeFs,
}
)
defer os.Remove(tempDevfile.Name())

err := d.PopulateFromBytes([]byte(InvalidDevfileContent))

if err == nil {
t.Errorf("expected error, didn't get one ")
}

if err := tempDevfile.Close(); err != nil {
t.Errorf("failed to close temp devfile")
}
})

t.Run("invalid filepath", func(t *testing.T) {

var (
fakeFs = filesystem.NewFakeFs()
d = DevfileCtx{
absPath: InvalidDevfilePath,
Fs: fakeFs,
}
)

err := d.SetDevfileContent()

if err == nil {
t.Errorf("expected an error, didn't get one")
}
})
}
42 changes: 30 additions & 12 deletions pkg/devfile/parser/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,12 @@ import (
"github.com/pkg/errors"
)

// Parse func parses and validates the devfile integrity.
// ParseDevfile func validates the devfile integrity.
// Creates devfile context and runtime objects
func Parse(path string) (d DevfileObj, err error) {

// NewDevfileCtx
d.Ctx = devfileCtx.NewDevfileCtx(path)

// Fill the fields of DevfileCtx struct
err = d.Ctx.Populate()
if err != nil {
return d, err
}
func ParseDevfile(d DevfileObj) (DevfileObj, error) {

// Validate devfile
err = d.Ctx.Validate()
err := d.Ctx.Validate()
if err != nil {
return d, err
}
Expand All @@ -42,3 +33,30 @@ func Parse(path string) (d DevfileObj, err error) {
// Successful
return d, nil
}

// Parse func parses and validates the devfile integrity.
// Creates devfile context and runtime objects
func Parse(path string) (d DevfileObj, err error) {

// NewDevfileCtx
d.Ctx = devfileCtx.NewDevfileCtx(path)

// Fill the fields of DevfileCtx struct
err = d.Ctx.Populate()
if err != nil {
return d, err
}
return ParseDevfile(d)
}

// ParseInMemory func parses and validates the devfile integrity.
// Creates devfile context and runtime objects
func ParseInMemory(bytes []byte) (d DevfileObj, err error) {

// Fill the fields of DevfileCtx struct
err = d.Ctx.PopulateFromBytes(bytes)
if err != nil {
return d, err
}
return ParseDevfile(d)
}
3 changes: 2 additions & 1 deletion pkg/odo/cli/catalog/catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package catalog

import (
"fmt"

"github.com/openshift/odo/pkg/odo/cli/catalog/describe"
"github.com/openshift/odo/pkg/odo/cli/catalog/list"
"github.com/openshift/odo/pkg/odo/cli/catalog/search"
Expand All @@ -10,7 +11,7 @@ import (
"github.com/spf13/cobra"
)

// RecommendedCatalogCommandName is the recommended catalog command name
// RecommendedCommandName is the recommended catalog command name
const RecommendedCommandName = "catalog"

// NewCmdCatalog implements the odo catalog command
Expand Down
Loading