diff --git a/devfile.yaml b/devfile.yaml index a6071fc1..866caad9 100644 --- a/devfile.yaml +++ b/devfile.yaml @@ -10,6 +10,7 @@ parent: # uri: https://raw.githubusercontent.com/odo-devfiles/registry/master/devfiles/nodejs/devfile.yaml id: nodejs registryUrl: "https://registry.devfile.io" + version: latest commands: - id: install exec: diff --git a/go.mod b/go.mod index 59f8d54b..2f88954f 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/devfile/library go 1.15 require ( - github.com/devfile/api/v2 v2.0.0-20220117162434-6e6e6a8bc14c + github.com/devfile/api/v2 v2.0.0-20220309195345-48ebbf1e51cf github.com/fatih/color v1.7.0 github.com/fsnotify/fsnotify v1.4.9 github.com/gobwas/glob v0.2.3 diff --git a/go.sum b/go.sum index 53d6ff84..a1db5810 100644 --- a/go.sum +++ b/go.sum @@ -83,8 +83,8 @@ github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/devfile/api/v2 v2.0.0-20220117162434-6e6e6a8bc14c h1:sjghKUov/WT71dBreHYQcTgQctxHT/p4uAhUFdGQfSU= -github.com/devfile/api/v2 v2.0.0-20220117162434-6e6e6a8bc14c/go.mod h1:d99eTN6QxgzihOOFyOZA+VpUyD4Q1pYRYHZ/ci9J96Q= +github.com/devfile/api/v2 v2.0.0-20220309195345-48ebbf1e51cf h1:FkwAOQtepscB5B0j++9S/eoicXj707MaP5HPIScz0sA= +github.com/devfile/api/v2 v2.0.0-20220309195345-48ebbf1e51cf/go.mod h1:kLX/nW93gigOHXK3NLeJL2fSS/sgEe+OHu8bo3aoOi4= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= diff --git a/pkg/devfile/parser/data/v2/2.2.0/devfileJsonSchema220.go b/pkg/devfile/parser/data/v2/2.2.0/devfileJsonSchema220.go index 54e36df5..d729f7cf 100644 --- a/pkg/devfile/parser/data/v2/2.2.0/devfileJsonSchema220.go +++ b/pkg/devfile/parser/data/v2/2.2.0/devfileJsonSchema220.go @@ -1855,6 +1855,11 @@ const JsonSchema220 = `{ "additionalProperties": { "type": "string" } + }, + "version": { + "description": "Specific stack/sample version to pull the parent devfile from, when using id in the parent reference. To specify 'version', 'id' must be defined and used as the import reference source. 'version' can be either a specific stack version, or 'latest'. If no 'version' specified, default version will be used.", + "type": "string", + "pattern": "^(latest)|(([1-9])\\.([0-9]+)\\.([0-9]+)(\\-[0-9a-z-]+(\\.[0-9a-z-]+)*)?(\\+[0-9A-Za-z-]+(\\.[0-9A-Za-z-]+)*)?)$" } }, "additionalProperties": false diff --git a/pkg/devfile/parser/parse.go b/pkg/devfile/parser/parse.go index 066e14a1..0fa5012f 100644 --- a/pkg/devfile/parser/parse.go +++ b/pkg/devfile/parser/parse.go @@ -378,7 +378,7 @@ func parseFromRegistry(importReference v1.ImportReference, resolveCtx *resolutio id := importReference.Id registryURL := importReference.RegistryUrl if registryURL != "" { - devfileContent, err := getDevfileFromRegistry(id, registryURL) + devfileContent, err := getDevfileFromRegistry(id, registryURL, importReference.Version) if err != nil { return DevfileObj{}, err } @@ -392,7 +392,7 @@ func parseFromRegistry(importReference v1.ImportReference, resolveCtx *resolutio } else if tool.registryURLs != nil { for _, registryURL := range tool.registryURLs { - devfileContent, err := getDevfileFromRegistry(id, registryURL) + devfileContent, err := getDevfileFromRegistry(id, registryURL, importReference.Version) if devfileContent != nil && err == nil { d.Ctx, err = devfileCtx.NewByteContentDevfileCtx(devfileContent) if err != nil { @@ -411,12 +411,12 @@ func parseFromRegistry(importReference v1.ImportReference, resolveCtx *resolutio return DevfileObj{}, fmt.Errorf("failed to get id: %s from registry URLs provided", id) } -func getDevfileFromRegistry(id, registryURL string) ([]byte, error) { +func getDevfileFromRegistry(id, registryURL, version string) ([]byte, error) { if !strings.HasPrefix(registryURL, "http://") && !strings.HasPrefix(registryURL, "https://") { return nil, fmt.Errorf("the provided registryURL: %s is not a valid URL", registryURL) } param := util.HTTPRequestParams{ - URL: fmt.Sprintf("%s/devfiles/%s", registryURL, id), + URL: fmt.Sprintf("%s/devfiles/%s/%s", registryURL, id, version), } return util.HTTPGetRequest(param, 0) } diff --git a/pkg/devfile/parser/parse_test.go b/pkg/devfile/parser/parse_test.go index 7edd472d..1c476690 100644 --- a/pkg/devfile/parser/parse_test.go +++ b/pkg/devfile/parser/parse_test.go @@ -4074,6 +4074,32 @@ func Test_parseFromRegistry(t *testing.T) { }, } + latestParentDevfile := DevfileObj{ + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevfileHeader: devfilepkg.DevfileHeader{ + SchemaVersion: schemaVersion, + }, + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Components: []v1.Component{ + { + Name: "runtime-latest", + ComponentUnion: v1.ComponentUnion{ + Volume: &v1.VolumeComponent{ + Volume: v1.Volume{ + Size: "500Mi", + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + wantDevfile := DevfileObj{ Data: &v2.DevfileV2{ Devfile: v1.Devfile{ @@ -4100,6 +4126,32 @@ func Test_parseFromRegistry(t *testing.T) { }, } + latestWantDevfile := DevfileObj{ + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevfileHeader: devfilepkg.DevfileHeader{ + SchemaVersion: schemaVersion, + }, + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Components: []v1.Component{ + { + Name: "runtime-latest", + ComponentUnion: v1.ComponentUnion{ + Volume: &v1.VolumeComponent{ + Volume: v1.Volume{ + Size: "500Mi", + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + invalidURLErr := "the provided registryURL: .* is not a valid URL" URLNotFoundErr := "failed to retrieve .*, 404: Not Found" missingRegistryURLErr := "failed to fetch from registry, registry URL is not provided" @@ -4109,7 +4161,16 @@ func Test_parseFromRegistry(t *testing.T) { var data []byte var err error if strings.Contains(r.URL.Path, "/devfiles/"+registryId) { - data, err = yaml.Marshal(parentDevfile.Data) + if strings.Contains(r.URL.Path, "latest") { + data, err = yaml.Marshal(latestParentDevfile.Data) + } else if strings.Contains(r.URL.Path, "1.1.0") { + data, err = yaml.Marshal(parentDevfile.Data) + } else if r.URL.Path == fmt.Sprintf("/devfiles/%s/", registryId) { + data, err = yaml.Marshal(parentDevfile.Data) + } else { + w.WriteHeader(http.StatusNotFound) + return + } } else { w.WriteHeader(http.StatusNotFound) return @@ -4179,6 +4240,39 @@ func Test_parseFromRegistry(t *testing.T) { registryURLs: []string{"http://" + registry}, }, }, + { + name: "should be able to parse from provided registryUrl with latest version specified", + wantDevFile: latestWantDevfile, + importReference: v1.ImportReference{ + ImportReferenceUnion: v1.ImportReferenceUnion{ + Id: registryId, + }, + Version: "latest", + RegistryUrl: httpPrefix + registry, + }, + }, + { + name: "should be able to parse from provided registryUrl with version specified", + wantDevFile: wantDevfile, + importReference: v1.ImportReference{ + ImportReferenceUnion: v1.ImportReferenceUnion{ + Id: registryId, + }, + Version: "1.1.0", + RegistryUrl: httpPrefix + registry, + }, + }, + { + name: "should fail if version does not exist", + importReference: v1.ImportReference{ + ImportReferenceUnion: v1.ImportReferenceUnion{ + Id: registryId, + }, + Version: "999.9.9", + RegistryUrl: httpPrefix + registry, + }, + wantErr: &URLNotFoundErr, + }, { name: "should fail if registryId does not exist", importReference: v1.ImportReference{