diff --git a/.wwhrd.yml b/.wwhrd.yml index af5657326..dbcf4b5f1 100644 --- a/.wwhrd.yml +++ b/.wwhrd.yml @@ -13,6 +13,7 @@ whitelist: - BSD-3-Clause - BSD-2-Clause - MPL-2.0-no-copyleft-exception + - EPL-2.0 exceptions: # wwhrd currently does not detect ISC which is compatible with Odo so, add it under exceptions to avoid errors due to it being not recognised diff --git a/go.mod b/go.mod index 92e0d8668..de71f9404 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,8 @@ require ( github.com/Netflix/go-expect v0.0.0-20200312175327-da48e75238e2 github.com/blang/semver v3.5.1+incompatible github.com/containerd/containerd v1.3.3 // indirect + github.com/devfile/api v0.0.0-20201103130402-29b8738e196e + github.com/devfile/library v0.0.0-20201112211805-e68d67cf4204 github.com/docker/docker v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+incompatible github.com/docker/go-connections v0.4.1-0.20200120150455-7dc0a2d6ddce github.com/fatih/color v1.7.0 @@ -42,7 +44,6 @@ require ( github.com/spf13/cobra v0.0.5 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.6.1 - github.com/xeipuuv/gojsonschema v1.2.0 github.com/zalando/go-keyring v0.1.0 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 gopkg.in/AlecAivazis/survey.v1 v1.8.0 @@ -53,7 +54,6 @@ require ( k8s.io/client-go v12.0.0+incompatible k8s.io/klog v1.0.0 k8s.io/kubectl v0.0.0 - sigs.k8s.io/controller-runtime v0.6.0 // indirect sigs.k8s.io/yaml v1.2.0 ) diff --git a/go.sum b/go.sum index 80ce8a2de..a3d2e160d 100644 --- a/go.sum +++ b/go.sum @@ -217,6 +217,10 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= github.com/deislabs/oras v0.7.0/go.mod h1:sqMKPG3tMyIX9xwXUBRLhZ24o+uT4y6jgBD2RzUTKDM= github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= +github.com/devfile/api v0.0.0-20201103130402-29b8738e196e h1:Ha6wyKs7VWqQTz2Fm1o4PAYpKX6SIiYjgWmGzNW8cBE= +github.com/devfile/api v0.0.0-20201103130402-29b8738e196e/go.mod h1:hp5Lmob7ESmtSZXZ7xRN9o8vemsen9111+ASi2YuXs4= +github.com/devfile/library v0.0.0-20201112211805-e68d67cf4204 h1:rWcsIrGErsVIYRUopre3XkZ/ko+o+LYqs9YZzn+UpvY= +github.com/devfile/library v0.0.0-20201112211805-e68d67cf4204/go.mod h1:jQTcvSRQuAofQPuVuC//B04v+ay4ttwqE4NVZp/p+uQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= 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= @@ -550,6 +554,8 @@ github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/U github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.0.0-20180201235237-0fb14efe8c47/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -596,6 +602,8 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jsonnet-bundler/jsonnet-bundler v0.1.0/go.mod h1:YKsSFc9VFhhLITkJS3X2PrRqWG9u2Jq99udTdDjQLfM= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jteeuwen/go-bindata v3.0.8-0.20151023091102-a0ff2567cfb7+incompatible/go.mod h1:JVvhzYOiGBnFSYRyV00iY8q7/0PThjIYav1p9h5dmKs= @@ -672,6 +680,7 @@ github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx github.com/mattn/go-isatty v0.0.6/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.13-0.20200128103942-cb30d6282491 h1:jygFUAtCyqjM5JGFNAWcXLqlXArQqxDZ3DqQer1BIik= github.com/mattn/go-isatty v0.0.13-0.20200128103942-cb30d6282491/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= @@ -709,6 +718,7 @@ github.com/mitchellh/hashstructure v1.0.0/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1D github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/moby/buildkit v0.0.0-20181107081847-c3a857e3fca0/go.mod h1:nnELdKPRkUAQR6pAB3mRU3+IlbqL3SSaAWqQL8k/K+4= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= @@ -1105,7 +1115,9 @@ golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1160,6 +1172,7 @@ golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191028164358-195ce5e7f934/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1167,8 +1180,10 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1323,6 +1338,7 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= @@ -1412,6 +1428,7 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8 rsc.io/letsencrypt v0.0.1/go.mod h1:buyQKZ6IXrRnB7TdkHP0RyEybLx18HHyOSoTyoOLqNY= sigs.k8s.io/controller-runtime v0.1.10/go.mod h1:HFAYoOh6XMV+jKF1UjFwrknPbowfyHEHHRdJMf2jMX8= sigs.k8s.io/controller-runtime v0.4.0/go.mod h1:ApC79lpY3PHW9xj/w9pj+lYkLgwAAUZwfXkME1Lajns= +sigs.k8s.io/controller-runtime v0.5.2/go.mod h1:JZUwSMVbxDupo0lTJSSFP5pimEyxGynROImSsqIOx1A= sigs.k8s.io/controller-runtime v0.6.0 h1:Fzna3DY7c4BIP6KwfSlrfnj20DJ+SeMBK8HSFvOk9NM= sigs.k8s.io/controller-runtime v0.6.0/go.mod h1:CpYf5pdNY/B352A1TFLAS2JVSlnGQ5O2cftPHndTroo= sigs.k8s.io/controller-tools v0.1.10/go.mod h1:6g08p9m9G/So3sBc1AOQifHfhxH/mb6Sc4z0LMI8XMw= diff --git a/pkg/component/component.go b/pkg/component/component.go index 0aeb7bff1..4ed2c7200 100644 --- a/pkg/component/component.go +++ b/pkg/component/component.go @@ -14,10 +14,10 @@ import ( v1 "k8s.io/api/apps/v1" - devfileParser "github.com/openshift/odo/pkg/devfile/parser" + devfileParser "github.com/devfile/library/pkg/devfile/parser" + "github.com/devfile/library/pkg/devfile/parser" "github.com/openshift/odo/pkg/devfile/adapters/common" - "github.com/openshift/odo/pkg/devfile/parser" "github.com/openshift/odo/pkg/kclient" "github.com/openshift/odo/pkg/envinfo" @@ -25,11 +25,11 @@ import ( "github.com/pkg/errors" "k8s.io/klog" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" applabels "github.com/openshift/odo/pkg/application/labels" "github.com/openshift/odo/pkg/catalog" componentlabels "github.com/openshift/odo/pkg/component/labels" "github.com/openshift/odo/pkg/config" - parsercommon "github.com/openshift/odo/pkg/devfile/parser/data/common" "github.com/openshift/odo/pkg/log" "github.com/openshift/odo/pkg/occlient" "github.com/openshift/odo/pkg/odo/util/validation" @@ -587,7 +587,7 @@ func ensureAndLogProperResourceUsage(resourceMin, resourceMax *string, resourceN // isS2I: Legacy option. Set as true if you want to use the old S2I method as it differentiates slightly. // Returns: // err: Errors if any else nil -func ApplyConfig(client *occlient.Client, kClient *kclient.Client, componentConfig config.LocalConfigInfo, envSpecificInfo envinfo.EnvSpecificInfo, stdout io.Writer, cmpExist bool, containerComponents []parsercommon.DevfileComponent, isS2I bool) (err error) { +func ApplyConfig(client *occlient.Client, kClient *kclient.Client, componentConfig config.LocalConfigInfo, envSpecificInfo envinfo.EnvSpecificInfo, stdout io.Writer, cmpExist bool, containerComponents []devfilev1.Component, isS2I bool) (err error) { if client == nil { var err error diff --git a/pkg/component/component_full_description.go b/pkg/component/component_full_description.go index 01e6fb5fb..dde79e956 100644 --- a/pkg/component/component_full_description.go +++ b/pkg/component/component_full_description.go @@ -5,8 +5,8 @@ import ( "fmt" "strings" - devfileParser "github.com/openshift/odo/pkg/devfile/parser" - "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + devfileParser "github.com/devfile/library/pkg/devfile/parser" "github.com/openshift/odo/pkg/envinfo" "github.com/openshift/odo/pkg/kclient" "github.com/openshift/odo/pkg/kclient/generator" @@ -156,7 +156,7 @@ func NewComponentFullDescriptionFromClientAndLocalConfig(client *occlient.Client if e != nil { return cfd, e } - var components []common.DevfileComponent + var components []devfilev1.Component var configProvider envinfo.LocalConfigProvider = localConfigInfo if envInfo != nil { configProvider = envInfo diff --git a/pkg/component/devfile_repr.go b/pkg/component/devfile_repr.go index 6ac1bca4f..a5d2d4a35 100644 --- a/pkg/component/devfile_repr.go +++ b/pkg/component/devfile_repr.go @@ -1,8 +1,8 @@ package component import ( + "github.com/devfile/library/pkg/devfile/parser" "github.com/openshift/odo/pkg/config" - "github.com/openshift/odo/pkg/devfile/parser" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -69,6 +69,6 @@ type ContainerRepr struct { type PortRepr struct { Name string `yaml:"Name" json:"Name"` - ExposedPort int32 `yaml:"ExposedPort" json:"ExposedPort"` + ExposedPort int `yaml:"ExposedPort" json:"ExposedPort"` Protocol string `yaml:"Protocol" json:"Protocol"` } diff --git a/pkg/config/config.go b/pkg/config/config.go index c2201d1f7..a21a229ee 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -2,7 +2,6 @@ package config import ( "fmt" - "github.com/openshift/odo/pkg/envinfo" "io" "net/url" "os" @@ -10,6 +9,9 @@ import ( "strconv" "strings" + "github.com/openshift/odo/pkg/envinfo" + + "github.com/devfile/library/pkg/devfile/parser" "github.com/openshift/odo/pkg/testingutil/filesystem" "github.com/pkg/errors" @@ -602,6 +604,15 @@ var ( lowerCaseLocalParameters = util.GetLowerCaseParameters(GetLocallySupportedParameters()) ) +var ( + supportedDevfileParameterDescriptions = map[string]string{ + Name: NameDescription, + Ports: PortsDescription, + Memory: MemoryDescription, + } + lowerCaseDevfileParameters = util.GetLowerCaseParameters(GetDevfileSupportedParameters()) +) + // FormatLocallySupportedParameters outputs supported parameters and their description func FormatLocallySupportedParameters() (result string) { for _, v := range GetLocallySupportedParameters() { @@ -610,6 +621,18 @@ func FormatLocallySupportedParameters() (result string) { return "\nAvailable Parameters for s2i Components:\n" + result } +// FormatDevfileSupportedParameters outputs supported parameters and their description +func FormatDevfileSupportedParameters() (result string) { + for _, v := range GetDevfileSupportedParameters() { + result = result + " " + v + " - " + supportedDevfileParameterDescriptions[v] + "\n" + } + return "\nAvailable Parameters for Devfile Components:\n" + result +} + +func GetDevfileSupportedParameters() []string { + return util.GetSortedKeys(supportedDevfileParameterDescriptions) +} + // AsLocallySupportedParameter returns the parameter in lower case and a boolean indicating if it is a supported parameter func AsLocallySupportedParameter(param string) (string, bool) { lower := strings.ToLower(param) @@ -621,6 +644,67 @@ func GetLocallySupportedParameters() []string { return util.GetSortedKeys(supportedLocalParameterDescriptions) } +// AsDevfileSupportedParameter returns the parameter in lower case and a boolean indicating if it is a supported parameter +func AsDevfileSupportedParameter(param string) (string, bool) { + lower := strings.ToLower(param) + return lower, lowerCaseDevfileParameters[lower] +} + +// SetDevfileConfiguration allows setting all the parameters that are configurable in a devfile +func SetDevfileConfiguration(d parser.DevfileObj, parameter string, value interface{}) error { + + // we are ignoring this error becase a developer is usually aware of the type of value that is + // being passed. So consider this a shortcut, if you know its a string value use this strValue + // else parse it inside the switch case. + strValue, _ := value.(string) + if parameter, ok := AsDevfileSupportedParameter(parameter); ok { + switch parameter { + case "name": + return d.SetMetadataName(strValue) + case "ports": + arrValue := strings.Split(strValue, ",") + return d.SetPorts(arrValue...) + case "memory": + return d.SetMemory(strValue) + } + + } + return errors.Errorf("unknown parameter :'%s' is not a configurable parameter in the devfile", parameter) + +} + +// DeleteConfiguration allows deleting the parameters that are configurable in a devfile +func DeleteDevfileConfiguration(d parser.DevfileObj, parameter string) error { + if parameter, ok := AsDevfileSupportedParameter(parameter); ok { + switch parameter { + case "name": + return d.SetMetadataName("") + case "ports": + return d.RemovePorts() + case "memory": + return d.SetMemory("") + } + } + return errors.Errorf("unknown parameter :'%s' is not a configurable parameter in the devfile", parameter) +} + +// IsSet checks if a parameter is set in the devfile +func IsSetInDevfile(d parser.DevfileObj, parameter string) bool { + + if parameter, ok := AsDevfileSupportedParameter(parameter); ok { + switch parameter { + case "name": + return d.GetMetadataName() != "" + case "ports": + return d.HasPorts() + case "memory": + return d.GetMemory() != "" + } + } + return false + +} + // SrcType is an enum to indicate the type of source of component -- local source/binary or git for the generation of app/component names type SrcType string diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index f0dde239f..a7d5588da 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -5,8 +5,15 @@ import ( "io/ioutil" "os" "path/filepath" + "reflect" "testing" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + "github.com/devfile/library/pkg/devfile/parser" + devfileCtx "github.com/devfile/library/pkg/devfile/parser/context" + devfilefs "github.com/devfile/library/pkg/testingutil/filesystem" + "github.com/kylelemons/godebug/pretty" + "github.com/openshift/odo/pkg/testingutil" "github.com/openshift/odo/pkg/testingutil/filesystem" ) @@ -497,6 +504,178 @@ func TestDeleteConfigDirIfEmpty(t *testing.T) { } } +func TestSetDevfileConfiguration(t *testing.T) { + + // Use fakeFs + fs := devfilefs.NewFakeFs() + + tests := []struct { + name string + args map[string]string + currentDevfile parser.DevfileObj + wantDevFile parser.DevfileObj + wantErr bool + }{ + { + name: "case 1: set memory to 500Mi", + args: map[string]string{ + "memory": "500Mi", + }, + currentDevfile: testingutil.GetTestDevfileObj(fs), + wantDevFile: parser.DevfileObj{ + Ctx: devfileCtx.FakeContext(fs, parser.OutputDevfileYamlPath), + Data: &testingutil.TestDevfileData{ + Commands: []devfilev1.Command{ + { + Id: "devbuild", + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + WorkingDir: "/projects/nodejs-starter", + }, + }, + }, + }, + Components: []devfilev1.Component{ + { + Name: "runtime", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "quay.io/nodejs-12", + MemoryLimit: "500Mi", + }, + Endpoints: []devfilev1.Endpoint{ + { + Name: "port-3030", + TargetPort: 3000, + }, + }, + }, + }, + }, + { + Name: "loadbalancer", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "quay.io/nginx", + MemoryLimit: "500Mi", + }, + }, + }, + }, + }, + }, + }, + }, + { + name: "case 2: set ports array", + args: map[string]string{ + "ports": "8080,8081/UDP,8080/TCP", + }, + currentDevfile: testingutil.GetTestDevfileObj(fs), + wantDevFile: parser.DevfileObj{ + Ctx: devfileCtx.FakeContext(fs, parser.OutputDevfileYamlPath), + Data: &testingutil.TestDevfileData{ + Commands: []devfilev1.Command{ + { + Id: "devbuild", + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + WorkingDir: "/projects/nodejs-starter", + }, + }, + }, + }, + Components: []devfilev1.Component{ + { + Name: "runtime", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "quay.io/nodejs-12", + }, + Endpoints: []devfilev1.Endpoint{ + { + Name: "port-3030", + TargetPort: 3000, + }, + { + Name: "port-8080-tcp", + TargetPort: 8080, + Protocol: "tcp", + }, { + Name: "port-8081-udp", + TargetPort: 8081, + Protocol: "udp", + }, + }, + }, + }, + }, + { + Name: "loadbalancer", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "quay.io/nginx", + }, + Endpoints: []devfilev1.Endpoint{ + { + Name: "port-8080-tcp", + TargetPort: 8080, + Protocol: "tcp", + }, { + Name: "port-8081-udp", + TargetPort: 8081, + Protocol: "udp", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + name: "case 3: set ports array fails due to validation", + args: map[string]string{ + "ports": "8080,8081/UDP,8083/", + }, + currentDevfile: testingutil.GetTestDevfileObj(fs), + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + for key, value := range tt.args { + err := SetDevfileConfiguration(tt.currentDevfile, key, value) + if tt.wantErr { + if err == nil { + t.Errorf("expected error but got nil") + } + // we dont expect an error here + } else { + if err != nil { + t.Errorf("error while setting configuration %+v", err.Error()) + } + } + } + + if !tt.wantErr { + if !reflect.DeepEqual(tt.currentDevfile.Data, tt.wantDevFile.Data) { + t.Errorf("wanted: %v, got: %v, difference at %v", tt.wantDevFile, tt.currentDevfile, pretty.Compare(tt.currentDevfile.Data, tt.wantDevFile.Data)) + } + } + + }) + } + +} + func createDirectoryAndFile(create bool, fs filesystem.Filesystem, odoDir string) error { if !create { return nil diff --git a/pkg/config/env_var.go b/pkg/config/env_var.go index e4a6d0871..9bed51b50 100644 --- a/pkg/config/env_var.go +++ b/pkg/config/env_var.go @@ -5,7 +5,7 @@ import ( "fmt" "strings" - "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" "github.com/openshift/odo/pkg/util" ) @@ -30,10 +30,10 @@ func (evl EnvVarList) ToStringSlice() []string { } // ToDevfileEnv converts the EnvVarList to the list of Envs supported by devfile -func (evl EnvVarList) ToDevfileEnv() []common.Env { - var envList []common.Env +func (evl EnvVarList) ToDevfileEnv() []devfilev1.EnvVar { + var envList []devfilev1.EnvVar for _, ev := range evl { - envList = append(envList, common.Env{ + envList = append(envList, devfilev1.EnvVar{ Name: ev.Name, Value: ev.Value, }) @@ -96,7 +96,7 @@ func NewEnvVarListFromSlice(envList []string) (EnvVarList, error) { } // NewEnvVarListFromDevfileEnv creates an EnvVarList from the list of envs present in a devfile. -func NewEnvVarListFromDevfileEnv(envList []common.Env) EnvVarList { +func NewEnvVarListFromDevfileEnv(envList []devfilev1.EnvVar) EnvVarList { var envVarList EnvVarList for _, env := range envList { envVarList = append(envVarList, EnvVar{ diff --git a/pkg/devfile/adapters/common/command.go b/pkg/devfile/adapters/common/command.go index 91fc2764b..f6b131817 100644 --- a/pkg/devfile/adapters/common/command.go +++ b/pkg/devfile/adapters/common/command.go @@ -5,8 +5,9 @@ import ( "reflect" "strings" - "github.com/openshift/odo/pkg/devfile/parser/data" - "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + "github.com/devfile/library/pkg/devfile/parser/data" + parsercommon "github.com/devfile/library/pkg/devfile/parser/data/v2/common" "github.com/pkg/errors" "k8s.io/klog" ) @@ -17,7 +18,7 @@ type command interface { } // New returns a new command implementation based on the specified devfile command and the known commands -func New(devfile common.DevfileCommand, knowCommands map[string]common.DevfileCommand, executor commandExecutor) (command, error) { +func New(devfile devfilev1.Command, knowCommands map[string]devfilev1.Command, executor commandExecutor) (command, error) { composite := devfile.Composite if composite != nil { cmds := composite.Commands @@ -44,9 +45,9 @@ func New(devfile common.DevfileCommand, knowCommands map[string]common.DevfileCo // getCommand iterates through the devfile commands and returns the devfile command associated with the group // commands mentioned via the flags are passed via commandName, empty otherwise -func getCommand(data data.DevfileData, commandName string, groupType common.DevfileCommandGroupType) (supportedCommand common.DevfileCommand, err error) { +func getCommand(data data.DevfileData, commandName string, groupType devfilev1.CommandGroupKind) (supportedCommand devfilev1.Command, err error) { - var command common.DevfileCommand + var command devfilev1.Command if commandName == "" { command, err = getCommandFromDevfile(data, groupType) @@ -58,9 +59,9 @@ func getCommand(data data.DevfileData, commandName string, groupType common.Devf } // getCommandFromDevfile iterates through the devfile commands and returns the command associated with the group -func getCommandFromDevfile(data data.DevfileData, groupType common.DevfileCommandGroupType) (supportedCommand common.DevfileCommand, err error) { +func getCommandFromDevfile(data data.DevfileData, groupType devfilev1.CommandGroupKind) (supportedCommand devfilev1.Command, err error) { commands := data.GetCommands() - var onlyCommand common.DevfileCommand + var onlyCommand devfilev1.Command // validate the command groups before searching for a command match // if the command groups are invalid, err out @@ -68,15 +69,15 @@ func getCommandFromDevfile(data data.DevfileData, groupType common.DevfileComman // since we know the command kind from the push flags err = validateCommandsForGroup(data, groupType) if err != nil { - return common.DevfileCommand{}, err + return devfilev1.Command{}, err } for _, command := range commands { - cmdGroup := command.GetGroup() + cmdGroup := parsercommon.GetGroup(command) if cmdGroup != nil && cmdGroup.Kind == groupType { if cmdGroup.IsDefault { return command, nil - } else if reflect.DeepEqual(onlyCommand, common.DevfileCommand{}) { + } else if reflect.DeepEqual(onlyCommand, devfilev1.Command{}) { // return the only remaining command for the group if there is no default command // NOTE: we return outside the for loop since the next iteration can have a default command onlyCommand = command @@ -85,13 +86,13 @@ func getCommandFromDevfile(data data.DevfileData, groupType common.DevfileComman } // if default command is not found return the first command found for the matching type. - if !reflect.DeepEqual(onlyCommand, common.DevfileCommand{}) { + if !reflect.DeepEqual(onlyCommand, devfilev1.Command{}) { return onlyCommand, nil } msg := fmt.Sprintf("the command group of kind \"%v\" is not found in the devfile", groupType) // if run command or test command is not found in devfile then it is an error - if groupType == common.RunCommandGroupType || groupType == common.TestCommandGroupType { + if groupType == devfilev1.RunCommandGroupKind || groupType == devfilev1.TestCommandGroupKind { err = fmt.Errorf(msg) } else { klog.V(2).Info(msg) @@ -101,7 +102,7 @@ func getCommandFromDevfile(data data.DevfileData, groupType common.DevfileComman } // getCommandFromFlag iterates through the devfile commands and returns the command specified associated with the group -func getCommandFromFlag(data data.DevfileData, groupType common.DevfileCommandGroupType, commandName string) (supportedCommand common.DevfileCommand, err error) { +func getCommandFromFlag(data data.DevfileData, groupType devfilev1.CommandGroupKind, commandName string) (supportedCommand devfilev1.Command, err error) { commands := data.GetCommands() for _, command := range commands { @@ -116,7 +117,7 @@ func getCommandFromFlag(data data.DevfileData, groupType common.DevfileCommandGr // id: mybuild // group: // kind: build - cmdGroup := command.GetGroup() + cmdGroup := parsercommon.GetGroup(command) if cmdGroup != nil && cmdGroup.Kind != groupType { return command, fmt.Errorf("command group mismatched, command %s is of group %v in devfile.yaml", commandName, command.Exec.Group.Kind) } @@ -134,7 +135,7 @@ func getCommandFromFlag(data data.DevfileData, groupType common.DevfileCommandGr // validateCommandsForGroup validates the commands in a devfile for a group // 1. multiple commands belonging to a single group should have at least one default // 2. multiple commands belonging to a single group cannot have more than one default -func validateCommandsForGroup(data data.DevfileData, groupType common.DevfileCommandGroupType) error { +func validateCommandsForGroup(data data.DevfileData, groupType devfilev1.CommandGroupKind) error { commands := getCommandsByGroup(data, groupType) @@ -142,7 +143,7 @@ func validateCommandsForGroup(data data.DevfileData, groupType common.DevfileCom if len(commands) > 1 { for _, command := range commands { - if command.GetGroup().IsDefault { + if parsercommon.GetGroup(command).IsDefault { defaultCommandCount++ } } @@ -161,33 +162,33 @@ func validateCommandsForGroup(data data.DevfileData, groupType common.DevfileCom } // GetBuildCommand iterates through the components in the devfile and returns the build command -func GetBuildCommand(data data.DevfileData, devfileBuildCmd string) (buildCommand common.DevfileCommand, err error) { +func GetBuildCommand(data data.DevfileData, devfileBuildCmd string) (buildCommand devfilev1.Command, err error) { - return getCommand(data, devfileBuildCmd, common.BuildCommandGroupType) + return getCommand(data, devfileBuildCmd, devfilev1.BuildCommandGroupKind) } // GetDebugCommand iterates through the components in the devfile and returns the debug command -func GetDebugCommand(data data.DevfileData, devfileDebugCmd string) (debugCommand common.DevfileCommand, err error) { - return getCommand(data, devfileDebugCmd, common.DebugCommandGroupType) +func GetDebugCommand(data data.DevfileData, devfileDebugCmd string) (debugCommand devfilev1.Command, err error) { + return getCommand(data, devfileDebugCmd, devfilev1.DebugCommandGroupKind) } // GetRunCommand iterates through the components in the devfile and returns the run command -func GetRunCommand(data data.DevfileData, devfileRunCmd string) (runCommand common.DevfileCommand, err error) { +func GetRunCommand(data data.DevfileData, devfileRunCmd string) (runCommand devfilev1.Command, err error) { - return getCommand(data, devfileRunCmd, common.RunCommandGroupType) + return getCommand(data, devfileRunCmd, devfilev1.RunCommandGroupKind) } // GetTestCommand iterates through the components in the devfile and returns the test command -func GetTestCommand(data data.DevfileData, devfileTestCmd string) (runCommand common.DevfileCommand, err error) { +func GetTestCommand(data data.DevfileData, devfileTestCmd string) (runCommand devfilev1.Command, err error) { - return getCommand(data, devfileTestCmd, common.TestCommandGroupType) + return getCommand(data, devfileTestCmd, devfilev1.TestCommandGroupKind) } // ValidateAndGetPushDevfileCommands validates the build and the run command, // if provided through odo push or else checks the devfile for devBuild and devRun. // It returns the build and run commands if its validated successfully, error otherwise. func ValidateAndGetPushDevfileCommands(data data.DevfileData, devfileBuildCmd, devfileRunCmd string) (commandMap PushCommandsMap, err error) { - var emptyCommand common.DevfileCommand + var emptyCommand devfilev1.Command commandMap = NewPushCommandMap() isBuildCommandValid, isRunCommandValid := false, false @@ -201,14 +202,14 @@ func ValidateAndGetPushDevfileCommands(data data.DevfileData, devfileBuildCmd, d klog.V(2).Infof("No build command was provided") } else if !reflect.DeepEqual(emptyCommand, buildCommand) && buildCmdErr == nil { isBuildCommandValid = true - commandMap[common.BuildCommandGroupType] = buildCommand + commandMap[devfilev1.BuildCommandGroupKind] = buildCommand klog.V(2).Infof("Build command: %v", buildCommand.Id) } runCommand, runCmdErr := GetRunCommand(data, devfileRunCmd) if runCmdErr == nil && !reflect.DeepEqual(emptyCommand, runCommand) { isRunCommandValid = true - commandMap[common.RunCommandGroupType] = runCommand + commandMap[devfilev1.RunCommandGroupKind] = runCommand klog.V(2).Infof("Run command: %v", runCommand.Id) } @@ -229,19 +230,19 @@ func ValidateAndGetPushDevfileCommands(data data.DevfileData, devfileBuildCmd, d } // Need to update group on custom commands specified by odo flags -func updateCommandGroupIfReqd(groupType common.DevfileCommandGroupType, command common.DevfileCommand) common.DevfileCommand { +func updateCommandGroupIfReqd(groupType devfilev1.CommandGroupKind, command devfilev1.Command) devfilev1.Command { // Update Group only for exec commands // Update Group only when Group is not nil, devfile v2 might contain group for custom commands. if command.Exec != nil && command.Exec.Group == nil { - command.Exec.Group = &common.Group{Kind: groupType} + command.Exec.Group = &devfilev1.CommandGroup{Kind: groupType} return command } return command } // ValidateAndGetDebugDevfileCommands validates the debug command -func ValidateAndGetDebugDevfileCommands(data data.DevfileData, devfileDebugCmd string) (pushDebugCommand common.DevfileCommand, err error) { - var emptyCommand common.DevfileCommand +func ValidateAndGetDebugDevfileCommands(data data.DevfileData, devfileDebugCmd string) (pushDebugCommand devfilev1.Command, err error) { + var emptyCommand devfilev1.Command isDebugCommandValid := false debugCommand, debugCmdErr := GetDebugCommand(data, devfileDebugCmd) @@ -255,15 +256,15 @@ func ValidateAndGetDebugDevfileCommands(data data.DevfileData, devfileDebugCmd s if debugCmdErr != nil { commandErrors += debugCmdErr.Error() } - return common.DevfileCommand{}, fmt.Errorf(commandErrors) + return devfilev1.Command{}, fmt.Errorf(commandErrors) } return debugCommand, nil } // ValidateAndGetTestDevfileCommands validates the test command -func ValidateAndGetTestDevfileCommands(data data.DevfileData, devfileTestCmd string) (testCommand common.DevfileCommand, err error) { - var emptyCommand common.DevfileCommand +func ValidateAndGetTestDevfileCommands(data data.DevfileData, devfileTestCmd string) (testCommand devfilev1.Command, err error) { + var emptyCommand devfilev1.Command isTestCommandValid := false testCommand, testCmdErr := GetTestCommand(data, devfileTestCmd) if testCmdErr == nil && !reflect.DeepEqual(emptyCommand, testCommand) { @@ -272,7 +273,7 @@ func ValidateAndGetTestDevfileCommands(data data.DevfileData, devfileTestCmd str } if !isTestCommandValid && testCmdErr != nil { - return common.DevfileCommand{}, testCmdErr + return devfilev1.Command{}, testCmdErr } return testCommand, nil diff --git a/pkg/devfile/adapters/common/command_simple.go b/pkg/devfile/adapters/common/command_simple.go index 8b088ff77..7ae27b6bc 100644 --- a/pkg/devfile/adapters/common/command_simple.go +++ b/pkg/devfile/adapters/common/command_simple.go @@ -3,7 +3,7 @@ package common import ( "fmt" - "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" "github.com/openshift/odo/pkg/log" "github.com/openshift/odo/pkg/machineoutput" "github.com/pkg/errors" @@ -23,7 +23,7 @@ type simpleCommand struct { // newSimpleCommand creates a new simpleCommand instance, adapting the devfile-defined command to run in the target component's // container, modifying it to add environment variables or adapting the path as needed. -func newSimpleCommand(command common.DevfileCommand, executor commandExecutor) (command, error) { +func newSimpleCommand(command devfilev1.Command, executor commandExecutor) (command, error) { exe := command.Exec // deal with environment variables @@ -54,7 +54,7 @@ func newSimpleCommand(command common.DevfileCommand, executor commandExecutor) ( // Note that the specified command will be run as-is in the target component's container so needs to be set accordingly as // opposed to the implementation provided by newSimpleCommand which will take the devfile's command definition and adapt it to // run in the container. -func newOverriddenSimpleCommand(command common.DevfileCommand, executor commandExecutor, cmd []string) (*simpleCommand, error) { +func newOverriddenSimpleCommand(command devfilev1.Command, executor commandExecutor, cmd []string) (*simpleCommand, error) { // create the component info associated with the command info, err := executor.ComponentInfo(command) if err != nil { diff --git a/pkg/devfile/adapters/common/command_supervisor.go b/pkg/devfile/adapters/common/command_supervisor.go index f7fb51054..ffc4ae711 100644 --- a/pkg/devfile/adapters/common/command_supervisor.go +++ b/pkg/devfile/adapters/common/command_supervisor.go @@ -3,7 +3,7 @@ package common import ( "fmt" - "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" "github.com/openshift/odo/pkg/machineoutput" ) @@ -16,7 +16,7 @@ type supervisorCommand struct { // newSupervisorInitCommand creates a command that initializes the supervisor for the specified devfile if needed // nil is returned if no devfile-specified container needing supervisor initialization is found -func newSupervisorInitCommand(command common.DevfileCommand, adapter commandExecutor) (command, error) { +func newSupervisorInitCommand(command devfilev1.Command, adapter commandExecutor) (command, error) { cmd := []string{SupervisordBinaryPath, "-c", SupervisordConfFile, "-d"} info, err := adapter.SupervisorComponentInfo(command) if err != nil { @@ -34,7 +34,7 @@ func newSupervisorInitCommand(command common.DevfileCommand, adapter commandExec } // newSupervisorStopCommand creates a command implementation that stops the specified command via the supervisor -func newSupervisorStopCommand(command common.DevfileCommand, executor commandExecutor) (command, error) { +func newSupervisorStopCommand(command devfilev1.Command, executor commandExecutor) (command, error) { cmd := []string{SupervisordBinaryPath, SupervisordCtlSubCommand, "stop", "all"} if stop, err := newOverriddenSimpleCommand(command, executor, cmd); err == nil { // use empty spinner message to avoid showing it altogether @@ -46,7 +46,7 @@ func newSupervisorStopCommand(command common.DevfileCommand, executor commandExe } // newSupervisorStartCommand creates a command implementation that starts the specified command via the supervisor -func newSupervisorStartCommand(command common.DevfileCommand, cmd string, adapter commandExecutor, restart bool) (command, error) { +func newSupervisorStartCommand(command devfilev1.Command, cmd string, adapter commandExecutor, restart bool) (command, error) { cmdLine := []string{SupervisordBinaryPath, SupervisordCtlSubCommand, "start", cmd} start, err := newOverriddenSimpleCommand(command, adapter, cmdLine) if err != nil { diff --git a/pkg/devfile/adapters/common/command_test.go b/pkg/devfile/adapters/common/command_test.go index 58bb37f47..1425c9b24 100644 --- a/pkg/devfile/adapters/common/command_test.go +++ b/pkg/devfile/adapters/common/command_test.go @@ -5,16 +5,16 @@ import ( "reflect" "testing" - devfileParser "github.com/openshift/odo/pkg/devfile/parser" - "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + devfileParser "github.com/devfile/library/pkg/devfile/parser" "github.com/openshift/odo/pkg/testingutil" "github.com/openshift/odo/pkg/util" ) -var buildGroup = common.BuildCommandGroupType -var runGroup = common.RunCommandGroupType -var testGroup = common.TestCommandGroupType -var debugGroup = common.DebugCommandGroupType +var buildGroup = devfilev1.BuildCommandGroupKind +var runGroup = devfilev1.RunCommandGroupKind +var testGroup = devfilev1.TestCommandGroupKind +var debugGroup = devfilev1.DebugCommandGroupKind func TestGetCommand(t *testing.T) { @@ -23,122 +23,164 @@ func TestGetCommand(t *testing.T) { tests := []struct { name string - requestedType []common.DevfileCommandGroupType - execCommands []common.DevfileCommand - compCommands []common.DevfileCommand + requestedType []devfilev1.CommandGroupKind + execCommands []devfilev1.Command + compCommands []devfilev1.Command reqCommandName string retCommandName string wantErr bool }{ { name: "Case 1: Valid devfile", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ getExecCommand("build", buildGroup), getExecCommand("run", runGroup), }, - requestedType: []common.DevfileCommandGroupType{buildGroup, runGroup}, + requestedType: []devfilev1.CommandGroupKind{buildGroup, runGroup}, wantErr: false, }, { name: "Case 2: Valid devfile with devrun and devbuild", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ getExecCommand("build", buildGroup), getExecCommand("run", runGroup), }, - requestedType: []common.DevfileCommandGroupType{buildGroup, runGroup}, + requestedType: []devfilev1.CommandGroupKind{buildGroup, runGroup}, wantErr: false, }, { name: "Case 3: Valid devfile with empty workdir", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { - Exec: &common.Exec{ - CommandLine: commands[0], - Component: components[0], - Group: &common.Group{Kind: runGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: commands[0], + Component: components[0], + }, }, }, }, - requestedType: []common.DevfileCommandGroupType{runGroup}, + requestedType: []devfilev1.CommandGroupKind{runGroup}, wantErr: false, }, { name: "Case 4: Mismatched command type", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "build command", - Exec: &common.Exec{ - CommandLine: commands[0], - Component: components[0], - Group: &common.Group{Kind: runGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: commands[0], + Component: components[0], + }, }, }, }, reqCommandName: "build command", - requestedType: []common.DevfileCommandGroupType{buildGroup}, + requestedType: []devfilev1.CommandGroupKind{buildGroup}, wantErr: true, }, { name: "Case 5: Default command is returned", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "defaultRunCommand", - Exec: &common.Exec{ - CommandLine: commands[0], - Component: components[0], - Group: &common.Group{Kind: runGroup, IsDefault: true}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup, IsDefault: true}, + }, + }, + CommandLine: commands[0], + Component: components[0], + }, }, }, { Id: "runCommand", - Exec: &common.Exec{ - CommandLine: commands[0], - Component: components[0], - Group: &common.Group{Kind: runGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: commands[0], + Component: components[0], + }, }, }, }, retCommandName: "defaultruncommand", - requestedType: []common.DevfileCommandGroupType{runGroup}, + requestedType: []devfilev1.CommandGroupKind{runGroup}, wantErr: false, }, { name: "Case 6: Composite command is returned", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "build", - Exec: &common.Exec{ - CommandLine: commands[0], - Component: components[0], - Group: &common.Group{Kind: buildGroup, IsDefault: false}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup, IsDefault: false}, + }, + }, + CommandLine: commands[0], + Component: components[0], + }, }, }, { Id: "run", - Exec: &common.Exec{ - CommandLine: commands[0], - Component: components[0], - Group: &common.Group{Kind: runGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: commands[0], + Component: components[0], + }, }, }, }, - compCommands: []common.DevfileCommand{ + compCommands: []devfilev1.Command{ { Id: "myComposite", - Composite: &common.Composite{ - Commands: []string{"build", "run"}, - Group: &common.Group{Kind: buildGroup, IsDefault: true}, + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup, IsDefault: true}, + }, + }, + Commands: []string{"build", "run"}, + }, }, }, }, retCommandName: "mycomposite", - requestedType: []common.DevfileCommandGroupType{buildGroup}, + requestedType: []devfilev1.CommandGroupKind{buildGroup}, wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - components := []common.DevfileComponent{testingutil.GetFakeContainerComponent(tt.execCommands[0].Exec.Component)} + components := []devfilev1.Component{testingutil.GetFakeContainerComponent(tt.execCommands[0].Exec.Component)} devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ Commands: append(tt.execCommands, tt.compCommands...), @@ -171,153 +213,219 @@ func TestGetCommandFromDevfile(t *testing.T) { tests := []struct { name string - requestedType []common.DevfileCommandGroupType - execCommands []common.DevfileCommand - compCommands []common.DevfileCommand + requestedType []devfilev1.CommandGroupKind + execCommands []devfilev1.Command + compCommands []devfilev1.Command retCommandName string wantErr bool }{ { name: "Case 1: Valid devfile", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ getExecCommand("", buildGroup), getExecCommand("", runGroup), }, - requestedType: []common.DevfileCommandGroupType{buildGroup, runGroup}, + requestedType: []devfilev1.CommandGroupKind{buildGroup, runGroup}, wantErr: false, }, { name: "Case 2: Valid devfile with devrun and devbuild", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ getExecCommand("", buildGroup), getExecCommand("", runGroup), }, - requestedType: []common.DevfileCommandGroupType{buildGroup, runGroup}, + requestedType: []devfilev1.CommandGroupKind{buildGroup, runGroup}, wantErr: false, }, { name: "Case 3: Valid devfile with empty workdir", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { - Exec: &common.Exec{ - CommandLine: commands[0], - Component: components[0], - Group: &common.Group{Kind: runGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: commands[0], + Component: components[0], + }, }, }, }, - requestedType: []common.DevfileCommandGroupType{runGroup}, + requestedType: []devfilev1.CommandGroupKind{runGroup}, wantErr: false, }, { name: "Case 4: Default command is returned", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "defaultruncommand", - Exec: &common.Exec{ - CommandLine: commands[0], - Component: components[0], - Group: &common.Group{Kind: runGroup, IsDefault: true}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup, IsDefault: true}, + }, + }, + CommandLine: commands[0], + Component: components[0], + }, }, }, { Id: "runcommand", - Exec: &common.Exec{ - CommandLine: commands[0], - Component: components[0], - Group: &common.Group{Kind: runGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: commands[0], + Component: components[0], + }, }, }, }, retCommandName: "defaultruncommand", - requestedType: []common.DevfileCommandGroupType{runGroup}, + requestedType: []devfilev1.CommandGroupKind{runGroup}, wantErr: false, }, { name: "Case 5: Valid devfile, has composite command", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "build1", - Exec: &common.Exec{ - CommandLine: commands[0], - Component: components[0], - Group: &common.Group{Kind: buildGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup}, + }, + }, + CommandLine: commands[0], + Component: components[0], + }, }, }, { Id: "build2", - Exec: &common.Exec{ - CommandLine: commands[0], - Component: components[0], - Group: &common.Group{Kind: buildGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup}, + }, + }, + CommandLine: commands[0], + Component: components[0], + }, }, }, { Id: "run", - Exec: &common.Exec{ - CommandLine: commands[0], - Component: components[0], - Group: &common.Group{Kind: runGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: commands[0], + Component: components[0], + }, }, }, }, - compCommands: []common.DevfileCommand{ + compCommands: []devfilev1.Command{ { Id: "mycomp", - Composite: &common.Composite{ - Commands: []string{"build1", "run"}, - Group: &common.Group{Kind: buildGroup, IsDefault: true}, + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup, IsDefault: true}, + }, + }, + Commands: []string{"build1", "run"}, + }, }, }, }, retCommandName: "mycomp", - requestedType: []common.DevfileCommandGroupType{buildGroup}, + requestedType: []devfilev1.CommandGroupKind{buildGroup}, wantErr: false, }, { name: "Case 6: Default composite command", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "build", - Exec: &common.Exec{ - CommandLine: commands[0], - Component: components[0], - Group: &common.Group{Kind: buildGroup, IsDefault: false}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup, IsDefault: false}, + }, + }, + CommandLine: commands[0], + Component: components[0], + }, }, }, { Id: "run", - Exec: &common.Exec{ - CommandLine: commands[0], - Component: components[0], - Group: &common.Group{Kind: runGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: commands[0], + Component: components[0], + }, }, }, }, - compCommands: []common.DevfileCommand{ + compCommands: []devfilev1.Command{ { Id: "mycomp", - Composite: &common.Composite{ - Commands: []string{"build", "run"}, - Group: &common.Group{Kind: buildGroup, IsDefault: true}, + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup, IsDefault: true}, + }, + }, + Commands: []string{"build", "run"}, + }, }, }, { Id: "mycomp2", - Composite: &common.Composite{ - Commands: []string{"build", "run"}, - Group: &common.Group{Kind: buildGroup, IsDefault: false}, + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup, IsDefault: false}, + }, + }, + Commands: []string{"build", "run"}, + }, }, }, }, retCommandName: "mycomp", - requestedType: []common.DevfileCommandGroupType{buildGroup}, + requestedType: []devfilev1.CommandGroupKind{buildGroup}, wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - components := []common.DevfileComponent{testingutil.GetFakeContainerComponent(tt.execCommands[0].Exec.Component)} + components := []devfilev1.Component{testingutil.GetFakeContainerComponent(tt.execCommands[0].Exec.Component)} devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ Commands: append(tt.execCommands, tt.compCommands...), @@ -351,16 +459,16 @@ func TestGetCommandFromFlag(t *testing.T) { tests := []struct { name string - requestedType common.DevfileCommandGroupType - execCommands []common.DevfileCommand - compCommands []common.DevfileCommand + requestedType devfilev1.CommandGroupKind + execCommands []devfilev1.Command + compCommands []devfilev1.Command reqCommandName string retCommandName string wantErr bool }{ { name: "Case 1: Valid devfile", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ getExecCommand("a", buildGroup), getExecCommand("b", runGroup), }, @@ -371,13 +479,19 @@ func TestGetCommandFromFlag(t *testing.T) { }, { name: "Case 2: Valid devfile with empty workdir", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "build command", - Exec: &common.Exec{ - CommandLine: commands[0], - Component: components[0], - Group: &common.Group{Kind: runGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: commands[0], + Component: components[0], + }, }, }, }, @@ -388,13 +502,19 @@ func TestGetCommandFromFlag(t *testing.T) { }, { name: "Case 3: Invalid command", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "build command", - Exec: &common.Exec{ - CommandLine: commands[0], - Component: invalidComponent, - Group: &common.Group{Kind: runGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: commands[0], + Component: invalidComponent, + }, }, }, }, @@ -404,13 +524,19 @@ func TestGetCommandFromFlag(t *testing.T) { }, { name: "Case 4: Mismatched command type", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "build command", - Exec: &common.Exec{ - CommandLine: commands[0], - Component: components[0], - Group: &common.Group{Kind: runGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: commands[0], + Component: components[0], + }, }, }, }, @@ -420,21 +546,33 @@ func TestGetCommandFromFlag(t *testing.T) { }, { name: "Case 5: Multiple default commands but should be with the flag", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "defaultruncommand", - Exec: &common.Exec{ - CommandLine: commands[0], - Component: components[0], - Group: &common.Group{Kind: runGroup, IsDefault: true}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup, IsDefault: true}, + }, + }, + CommandLine: commands[0], + Component: components[0], + }, }, }, { Id: "runcommand", - Exec: &common.Exec{ - CommandLine: commands[0], - Component: components[0], - Group: &common.Group{Kind: runGroup, IsDefault: true}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup, IsDefault: true}, + }, + }, + CommandLine: commands[0], + Component: components[0], + }, }, }, }, @@ -445,21 +583,33 @@ func TestGetCommandFromFlag(t *testing.T) { }, { name: "Case 6: No default command but should be with the flag", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "defaultruncommand", - Exec: &common.Exec{ - CommandLine: commands[0], - Component: components[0], - Group: &common.Group{Kind: runGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: commands[0], + Component: components[0], + }, }, }, { Id: "runcommand", - Exec: &common.Exec{ - CommandLine: commands[0], - Component: components[0], - Group: &common.Group{Kind: runGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: commands[0], + Component: components[0], + }, }, }, }, @@ -470,12 +620,14 @@ func TestGetCommandFromFlag(t *testing.T) { }, { name: "Case 7: No Command Group", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "defaultruncommand", - Exec: &common.Exec{ - CommandLine: commands[0], - Component: components[0], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + CommandLine: commands[0], + Component: components[0], + }, }, }, }, @@ -486,37 +638,61 @@ func TestGetCommandFromFlag(t *testing.T) { }, { name: "Case 8: Valid devfile with composite commands", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "build", - Exec: &common.Exec{ - CommandLine: commands[0], - Component: components[0], - Group: &common.Group{Kind: buildGroup, IsDefault: false}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup, IsDefault: false}, + }, + }, + CommandLine: commands[0], + Component: components[0], + }, }, }, { Id: "run", - Exec: &common.Exec{ - CommandLine: commands[0], - Component: components[0], - Group: &common.Group{Kind: runGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: commands[0], + Component: components[0], + }, }, }, }, - compCommands: []common.DevfileCommand{ + compCommands: []devfilev1.Command{ { Id: "mycomp", - Composite: &common.Composite{ - Commands: []string{"build", "run"}, - Group: &common.Group{Kind: buildGroup, IsDefault: true}, + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup, IsDefault: true}, + }, + }, + Commands: []string{"build", "run"}, + }, }, }, { Id: "mycomp2", - Composite: &common.Composite{ - Commands: []string{"build", "run"}, - Group: &common.Group{Kind: buildGroup, IsDefault: false}, + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup, IsDefault: false}, + }, + }, + Commands: []string{"build", "run"}, + }, }, }, }, @@ -527,30 +703,48 @@ func TestGetCommandFromFlag(t *testing.T) { }, { name: "Case 9: Valid devfile with invalid composite commands", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "build", - Exec: &common.Exec{ - CommandLine: commands[0], - Component: components[0], - Group: &common.Group{Kind: buildGroup, IsDefault: false}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup, IsDefault: false}, + }, + }, + CommandLine: commands[0], + Component: components[0], + }, }, }, { Id: "run", - Exec: &common.Exec{ - CommandLine: commands[0], - Component: components[0], - Group: &common.Group{Kind: runGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: commands[0], + Component: components[0], + }, }, }, }, - compCommands: []common.DevfileCommand{ + compCommands: []devfilev1.Command{ { Id: "myComp", - Composite: &common.Composite{ - Commands: []string{"fake"}, - Group: &common.Group{Kind: buildGroup, IsDefault: true}, + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup, IsDefault: true}, + }, + }, + Commands: []string{"fake"}, + }, }, }, }, @@ -562,9 +756,9 @@ func TestGetCommandFromFlag(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - components := []common.DevfileComponent{testingutil.GetFakeContainerComponent(tt.execCommands[0].Exec.Component)} + components := []devfilev1.Component{testingutil.GetFakeContainerComponent(tt.execCommands[0].Exec.Component)} if tt.execCommands[0].Exec.Component == invalidComponent { - components = []common.DevfileComponent{testingutil.GetFakeContainerComponent("randomComponent")} + components = []devfilev1.Component{testingutil.GetFakeContainerComponent("randomComponent")} } devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ @@ -599,35 +793,47 @@ func TestValidateCommandsForGroup(t *testing.T) { tests := []struct { name string - groupType common.DevfileCommandGroupType - execCommands []common.DevfileCommand - compCommands []common.DevfileCommand + groupType devfilev1.CommandGroupKind + execCommands []devfilev1.Command + compCommands []devfilev1.Command wantErr bool }{ { name: "Case 1: Two default run commands", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "run command", - Exec: &common.Exec{ - CommandLine: command, - Component: componentName, - WorkingDir: workDir, - Group: &common.Group{ - Kind: runGroup, - IsDefault: true, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{ + Kind: runGroup, + IsDefault: true, + }, + }, + }, + CommandLine: command, + Component: componentName, + WorkingDir: workDir, }, }, }, { Id: "customcommand", - Exec: &common.Exec{ - CommandLine: command, - Component: componentName, - WorkingDir: workDir, - Group: &common.Group{ - Kind: runGroup, - IsDefault: true, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{ + Kind: runGroup, + IsDefault: true, + }, + }, + }, + CommandLine: command, + Component: componentName, + WorkingDir: workDir, }, }, }, @@ -637,23 +843,35 @@ func TestValidateCommandsForGroup(t *testing.T) { }, { name: "Case 2: No default for more than one build commands", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "build command", - Exec: &common.Exec{ - CommandLine: command, - Component: componentName, - WorkingDir: workDir, - Group: &common.Group{Kind: buildGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup}, + }, + }, + CommandLine: command, + Component: componentName, + WorkingDir: workDir, + }, }, }, { Id: "build command 2", - Exec: &common.Exec{ - CommandLine: command, - Component: componentName, - WorkingDir: workDir, - Group: &common.Group{Kind: buildGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup}, + }, + }, + CommandLine: command, + Component: componentName, + WorkingDir: workDir, + }, }, }, }, @@ -662,14 +880,20 @@ func TestValidateCommandsForGroup(t *testing.T) { }, { name: "Case 3: One command does not need default", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "test command", - Exec: &common.Exec{ - CommandLine: command, - Component: componentName, - WorkingDir: workDir, - Group: &common.Group{Kind: testGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: testGroup}, + }, + }, + CommandLine: command, + Component: componentName, + WorkingDir: workDir, + }, }, }, }, @@ -678,16 +902,22 @@ func TestValidateCommandsForGroup(t *testing.T) { }, { name: "Case 4: One command can have default", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "debug command", - Exec: &common.Exec{ - CommandLine: command, - Component: componentName, - WorkingDir: workDir, - Group: &common.Group{ - Kind: debugGroup, - IsDefault: true, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{ + Kind: debugGroup, + IsDefault: true, + }, + }, + }, + CommandLine: command, + Component: componentName, + WorkingDir: workDir, }, }, }, @@ -697,32 +927,50 @@ func TestValidateCommandsForGroup(t *testing.T) { }, { name: "Case 5: Composite commands in group", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "build command", - Exec: &common.Exec{ - CommandLine: command, - Component: componentName, - WorkingDir: workDir, - Group: &common.Group{Kind: buildGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup}, + }, + }, + CommandLine: command, + Component: componentName, + WorkingDir: workDir, + }, }, }, { Id: "build command 2", - Exec: &common.Exec{ - CommandLine: command, - Component: componentName, - WorkingDir: workDir, - Group: &common.Group{Kind: buildGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup}, + }, + }, + CommandLine: command, + Component: componentName, + WorkingDir: workDir, + }, }, }, }, - compCommands: []common.DevfileCommand{ + compCommands: []devfilev1.Command{ { Id: "composite1", - Composite: &common.Composite{ - Commands: []string{"build command", "build command 2"}, - Group: &common.Group{Kind: buildGroup, IsDefault: true}, + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup, IsDefault: true}, + }, + }, + Commands: []string{"build command", "build command 2"}, + }, }, }, }, @@ -734,7 +982,7 @@ func TestValidateCommandsForGroup(t *testing.T) { t.Run(tt.name, func(t *testing.T) { devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ - Components: []common.DevfileComponent{ + Components: []devfilev1.Component{ testingutil.GetFakeContainerComponent("alias1"), }, Commands: append(tt.compCommands, tt.execCommands...), @@ -757,24 +1005,30 @@ func TestGetBuildCommand(t *testing.T) { workDir := "/" emptyString := "" - var emptyCommand common.DevfileCommand + var emptyCommand devfilev1.Command tests := []struct { name string commandName string - execCommands []common.DevfileCommand + execCommands []devfilev1.Command wantErr bool }{ { name: "Case 1: Default Build Command", commandName: emptyString, - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &common.Group{Kind: buildGroup, IsDefault: true}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup, IsDefault: true}, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, + }, }, }, }, @@ -783,23 +1037,35 @@ func TestGetBuildCommand(t *testing.T) { { name: "Case 2: Build Command passed through the odo flag", commandName: "flagcommand", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "flagcommand", - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &common.Group{Kind: buildGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup}, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, + }, }, }, { Id: "build command", - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &common.Group{Kind: buildGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup}, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, + }, }, }, }, @@ -808,14 +1074,20 @@ func TestGetBuildCommand(t *testing.T) { { name: "Case 3: Missing Build Command", commandName: "customcommand123", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "build command", - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &common.Group{Kind: buildGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup}, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, + }, }, }, }, @@ -828,7 +1100,7 @@ func TestGetBuildCommand(t *testing.T) { devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ Commands: tt.execCommands, - Components: []common.DevfileComponent{testingutil.GetFakeContainerComponent(component)}, + Components: []devfilev1.Component{testingutil.GetFakeContainerComponent(component)}, }, } @@ -852,26 +1124,32 @@ func TestGetDebugCommand(t *testing.T) { workDir := "/" emptyString := "" - var emptyCommand common.DevfileCommand + var emptyCommand devfilev1.Command tests := []struct { name string commandName string - execCommands []common.DevfileCommand + execCommands []devfilev1.Command wantErr bool }{ { name: "Case: Default Debug Command", commandName: emptyString, - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &common.Group{ - IsDefault: true, - Kind: common.DebugCommandGroupType, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{ + IsDefault: true, + Kind: devfilev1.DebugCommandGroupKind, + }, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, }, }, }, @@ -881,16 +1159,22 @@ func TestGetDebugCommand(t *testing.T) { { name: "Case: Custom Debug Command", commandName: "customdebugcommand", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "customdebugcommand", - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &common.Group{ - IsDefault: false, - Kind: common.DebugCommandGroupType, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{ + IsDefault: false, + Kind: devfilev1.DebugCommandGroupKind, + }, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, }, }, }, @@ -900,15 +1184,21 @@ func TestGetDebugCommand(t *testing.T) { { name: "Case: Missing Debug Command", commandName: "customcommand123", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &common.Group{ - IsDefault: true, - Kind: common.BuildCommandGroupType, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{ + IsDefault: true, + Kind: devfilev1.BuildCommandGroupKind, + }, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, }, }, }, @@ -921,7 +1211,7 @@ func TestGetDebugCommand(t *testing.T) { t.Run(tt.name, func(t *testing.T) { devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ - Components: []common.DevfileComponent{testingutil.GetFakeContainerComponent(component)}, + Components: []devfilev1.Component{testingutil.GetFakeContainerComponent(component)}, Commands: tt.execCommands, }, } @@ -948,26 +1238,32 @@ func TestGetTestCommand(t *testing.T) { workDir := "/" emptyString := "" - var emptyCommand common.DevfileCommand + var emptyCommand devfilev1.Command tests := []struct { name string commandName string - execCommands []common.DevfileCommand + execCommands []devfilev1.Command wantErr bool }{ { name: "Case: Default Test Command", commandName: emptyString, - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &common.Group{ - IsDefault: true, - Kind: common.TestCommandGroupType, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{ + IsDefault: true, + Kind: devfilev1.TestCommandGroupKind, + }, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, }, }, }, @@ -977,16 +1273,22 @@ func TestGetTestCommand(t *testing.T) { { name: "Case: Custom Test Command", commandName: "customtestcommand", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "customtestcommand", - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &common.Group{ - IsDefault: false, - Kind: common.TestCommandGroupType, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{ + IsDefault: false, + Kind: devfilev1.TestCommandGroupKind, + }, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, }, }, }, @@ -996,15 +1298,21 @@ func TestGetTestCommand(t *testing.T) { { name: "Case: Missing Test Command", commandName: "customcommand123", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &common.Group{ - IsDefault: true, - Kind: common.BuildCommandGroupType, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{ + IsDefault: true, + Kind: devfilev1.BuildCommandGroupKind, + }, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, }, }, }, @@ -1017,7 +1325,7 @@ func TestGetTestCommand(t *testing.T) { t.Run(tt.name, func(t *testing.T) { devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ - Components: []common.DevfileComponent{testingutil.GetFakeContainerComponent(component)}, + Components: []devfilev1.Component{testingutil.GetFakeContainerComponent(component)}, Commands: tt.execCommands, }, } @@ -1044,24 +1352,30 @@ func TestGetRunCommand(t *testing.T) { workDir := "/" emptyString := "" - var emptyCommand common.DevfileCommand + var emptyCommand devfilev1.Command tests := []struct { name string commandName string - execCommands []common.DevfileCommand + execCommands []devfilev1.Command wantErr bool }{ { name: "Case 1: Default Run Command", commandName: emptyString, - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &common.Group{Kind: runGroup, IsDefault: true}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup, IsDefault: true}, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, + }, }, }, }, @@ -1070,23 +1384,35 @@ func TestGetRunCommand(t *testing.T) { { name: "Case 2: Run Command passed through odo flag", commandName: "flagcommand", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "flagcommand", - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &common.Group{Kind: runGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, + }, }, }, { Id: "run command", - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &common.Group{Kind: runGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, + }, }, }, }, @@ -1095,13 +1421,19 @@ func TestGetRunCommand(t *testing.T) { { name: "Case 3: Missing Run Command", commandName: "", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &common.Group{Kind: buildGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup}, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, + }, }, }, }, @@ -1114,7 +1446,7 @@ func TestGetRunCommand(t *testing.T) { devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ Commands: tt.execCommands, - Components: []common.DevfileComponent{testingutil.GetFakeContainerComponent(component)}, + Components: []devfilev1.Component{testingutil.GetFakeContainerComponent(component)}, }, } @@ -1137,27 +1469,39 @@ func TestValidateAndGetDebugDevfileCommands(t *testing.T) { workDir := "/" emptyString := "" - execCommands := []common.DevfileCommand{ + execCommands := []devfilev1.Command{ { - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &common.Group{ - IsDefault: true, - Kind: common.DebugCommandGroupType, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{ + IsDefault: true, + Kind: devfilev1.DebugCommandGroupKind, + }, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, }, }, }, { Id: "customdebugcommand", - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &common.Group{ - IsDefault: false, - Kind: common.DebugCommandGroupType, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{ + IsDefault: false, + Kind: devfilev1.DebugCommandGroupKind, + }, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, }, }, }, @@ -1166,25 +1510,25 @@ func TestValidateAndGetDebugDevfileCommands(t *testing.T) { tests := []struct { name string debugCommand string - componentType common.DevfileComponentType + componentType devfilev1.ComponentType wantErr bool }{ { name: "Case: Default Devfile Commands", debugCommand: emptyString, - componentType: common.ContainerComponentType, + componentType: devfilev1.ContainerComponentType, wantErr: false, }, { name: "Case: provided debug Command", debugCommand: "customdebugcommand", - componentType: common.ContainerComponentType, + componentType: devfilev1.ContainerComponentType, wantErr: false, }, { name: "Case: invalid debug Command", debugCommand: "invaliddebugcommand", - componentType: common.ContainerComponentType, + componentType: devfilev1.ContainerComponentType, wantErr: true, }, } @@ -1193,7 +1537,7 @@ func TestValidateAndGetDebugDevfileCommands(t *testing.T) { t.Run(tt.name, func(t *testing.T) { devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ - Components: []common.DevfileComponent{testingutil.GetFakeContainerComponent(component)}, + Components: []devfilev1.Component{testingutil.GetFakeContainerComponent(component)}, Commands: execCommands, }, } @@ -1226,49 +1570,73 @@ func TestValidateAndGetPushDevfileCommands(t *testing.T) { workDir := "/" emptyString := "" - execCommands := []common.DevfileCommand{ + execCommands := []devfilev1.Command{ { Id: "run command", - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &common.Group{ - Kind: runGroup, - IsDefault: true, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{ + Kind: runGroup, + IsDefault: true, + }, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, }, }, }, { Id: "build command", - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &common.Group{Kind: buildGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup}, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, + }, }, }, { Id: "customcommand", - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &common.Group{Kind: runGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, + }, }, }, } - wrongCompTypeCmd := common.DevfileCommand{ + wrongCompTypeCmd := devfilev1.Command{ Id: "wrong", - Exec: &common.Exec{ - CommandLine: command, - Component: "", - WorkingDir: workDir, - Group: &common.Group{Kind: runGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: command, + Component: "", + WorkingDir: workDir, + }, }, } @@ -1276,7 +1644,7 @@ func TestValidateAndGetPushDevfileCommands(t *testing.T) { name string buildCommand string runCommand string - execCommands []common.DevfileCommand + execCommands []devfilev1.Command numberOfCommands int missingBuildCommand bool wantErr bool @@ -1317,13 +1685,19 @@ func TestValidateAndGetPushDevfileCommands(t *testing.T) { name: "Case 5: Missing Build Command, and Provided Run Command", buildCommand: emptyString, runCommand: "customcommand", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "customcommand", - Exec: &common.Exec{ - Group: &common.Group{Kind: runGroup}, - Component: component, - CommandLine: command, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + Component: component, + CommandLine: command, + }, }, }, }, @@ -1337,7 +1711,7 @@ func TestValidateAndGetPushDevfileCommands(t *testing.T) { devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ Commands: tt.execCommands, - Components: []common.DevfileComponent{testingutil.GetFakeContainerComponent(component)}, + Components: []devfilev1.Component{testingutil.GetFakeContainerComponent(component)}, }, } @@ -1363,27 +1737,39 @@ func TestValidateAndGetTestDevfileCommands(t *testing.T) { workDir := "/" emptyString := "" - execCommands := []common.DevfileCommand{ + execCommands := []devfilev1.Command{ { - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &common.Group{ - IsDefault: true, - Kind: common.TestCommandGroupType, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{ + IsDefault: true, + Kind: devfilev1.TestCommandGroupKind, + }, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, }, }, }, { Id: "customtestcommand", - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &common.Group{ - IsDefault: false, - Kind: common.TestCommandGroupType, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{ + IsDefault: false, + Kind: devfilev1.TestCommandGroupKind, + }, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, }, }, }, @@ -1392,25 +1778,25 @@ func TestValidateAndGetTestDevfileCommands(t *testing.T) { tests := []struct { name string testCommand string - componentType common.DevfileComponentType + componentType devfilev1.ComponentType wantErr bool }{ { name: "Case: Default Devfile Commands", testCommand: emptyString, - componentType: common.ContainerComponentType, + componentType: devfilev1.ContainerComponentType, wantErr: false, }, { name: "Case: provided test Command", testCommand: "customtestcommand", - componentType: common.ContainerComponentType, + componentType: devfilev1.ContainerComponentType, wantErr: false, }, { name: "Case: invalid test Command", testCommand: "invalidtestcommand", - componentType: common.ContainerComponentType, + componentType: devfilev1.ContainerComponentType, wantErr: true, }, } @@ -1419,7 +1805,7 @@ func TestValidateAndGetTestDevfileCommands(t *testing.T) { t.Run(tt.name, func(t *testing.T) { devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ - Components: []common.DevfileComponent{testingutil.GetFakeContainerComponent(component)}, + Components: []devfilev1.Component{testingutil.GetFakeContainerComponent(component)}, Commands: execCommands, }, } @@ -1445,7 +1831,7 @@ func TestValidateAndGetTestDevfileCommands(t *testing.T) { } } -func getExecCommand(id string, group common.DevfileCommandGroupType) common.DevfileCommand { +func getExecCommand(id string, group devfilev1.CommandGroupKind) devfilev1.Command { if len(id) == 0 { id = fmt.Sprintf("%s-%s", "cmd", util.GenerateRandomString(10)) } @@ -1453,13 +1839,19 @@ func getExecCommand(id string, group common.DevfileCommandGroupType) common.Devf components := [...]string{"alias1", "alias2"} workDir := [...]string{"/", "/root"} - return common.DevfileCommand{ + return devfilev1.Command{ Id: id, - Exec: &common.Exec{ - CommandLine: commands[0], - Component: components[0], - WorkingDir: workDir[0], - Group: &common.Group{Kind: group}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: group}, + }, + }, + CommandLine: commands[0], + Component: components[0], + WorkingDir: workDir[0], + }, }, } diff --git a/pkg/devfile/adapters/common/executor.go b/pkg/devfile/adapters/common/executor.go index 6017e72e7..485e4fd88 100644 --- a/pkg/devfile/adapters/common/executor.go +++ b/pkg/devfile/adapters/common/executor.go @@ -1,7 +1,7 @@ package common import ( - "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" "github.com/openshift/odo/pkg/machineoutput" ) @@ -11,7 +11,7 @@ type commandExecutor interface { // Logger returns the MachineEventLoggingClient associated with this executor Logger() machineoutput.MachineEventLoggingClient // ComponentInfo retrieves the component information associated with the specified command - ComponentInfo(command common.DevfileCommand) (ComponentInfo, error) + ComponentInfo(command devfilev1.Command) (ComponentInfo, error) // ComponentInfo retrieves the component information associated with the specified command for supervisor initialization purposes - SupervisorComponentInfo(command common.DevfileCommand) (ComponentInfo, error) + SupervisorComponentInfo(command devfilev1.Command) (ComponentInfo, error) } diff --git a/pkg/devfile/adapters/common/generic.go b/pkg/devfile/adapters/common/generic.go index f16721e5e..98a2a127a 100644 --- a/pkg/devfile/adapters/common/generic.go +++ b/pkg/devfile/adapters/common/generic.go @@ -4,7 +4,7 @@ import ( "io" "strings" - "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" "github.com/openshift/odo/pkg/log" "github.com/openshift/odo/pkg/machineoutput" "github.com/pkg/errors" @@ -13,7 +13,7 @@ import ( // ComponentInfoFactory defines a type for a function which creates a ComponentInfo based on the information provided by the specified DevfileCommand. // This is used by adapters to provide the proper ComponentInfo identifying which component (including supervisor) to target when executing the command. -type ComponentInfoFactory func(command common.DevfileCommand) (ComponentInfo, error) +type ComponentInfoFactory func(command devfilev1.Command) (ComponentInfo, error) // GenericAdapter provides common code that can be reused by adapters allowing them to focus on more specific behavior type GenericAdapter struct { @@ -53,11 +53,11 @@ func (a *GenericAdapter) SetLogger(loggingClient machineoutput.MachineEventLoggi a.logger = loggingClient } -func (a GenericAdapter) ComponentInfo(command common.DevfileCommand) (ComponentInfo, error) { +func (a GenericAdapter) ComponentInfo(command devfilev1.Command) (ComponentInfo, error) { return a.componentInfo(command) } -func (a GenericAdapter) SupervisorComponentInfo(command common.DevfileCommand) (ComponentInfo, error) { +func (a GenericAdapter) SupervisorComponentInfo(command devfilev1.Command) (ComponentInfo, error) { return a.supervisordComponentInfo(command) } @@ -67,7 +67,7 @@ func (a GenericAdapter) ExecuteCommand(compInfo ComponentInfo, command []string, } // ExecuteDevfileCommand executes the devfile init, build and test command actions synchronously -func (a GenericAdapter) ExecuteDevfileCommand(command common.DevfileCommand, show bool) error { +func (a GenericAdapter) ExecuteDevfileCommand(command devfilev1.Command, show bool) error { c, err := New(command, a.Devfile.Data.GetCommands(), a) if err != nil { return err @@ -88,7 +88,7 @@ func closeWriterAndWaitForAck(stdoutWriter *io.PipeWriter, stdoutChannel chan in } } -func convertGroupKindToString(exec *common.Exec) string { +func convertGroupKindToString(exec *devfilev1.ExecCommand) string { if exec.Group == nil { return "" } @@ -109,16 +109,16 @@ func (a GenericAdapter) ExecDevfile(commandsMap PushCommandsMap, componentExists commands := make([]command, 0, 7) // Get Build Command - commands, err = a.addToComposite(commandsMap, common.BuildCommandGroupType, devfileCommandMap, commands) + commands, err = a.addToComposite(commandsMap, devfilev1.BuildCommandGroupKind, devfileCommandMap, commands) if err != nil { return err } - group := common.RunCommandGroupType + group := devfilev1.RunCommandGroupKind defaultCmd := string(DefaultDevfileRunCommand) if params.Debug { - group = common.DebugCommandGroupType + group = devfilev1.DebugCommandGroupKind defaultCmd = string(DefaultDevfileDebugCommand) } @@ -168,7 +168,7 @@ func (a GenericAdapter) ExecDevfile(commandsMap PushCommandsMap, componentExists return nil } -func (a GenericAdapter) addToComposite(commandsMap PushCommandsMap, groupType common.DevfileCommandGroupType, devfileCommandMap map[string]common.DevfileCommand, commands []command) ([]command, error) { +func (a GenericAdapter) addToComposite(commandsMap PushCommandsMap, groupType devfilev1.CommandGroupKind, devfileCommandMap map[string]devfilev1.Command, commands []command) ([]command, error) { command, ok := commandsMap[groupType] if ok { if c, err := New(command, devfileCommandMap, a); err == nil { diff --git a/pkg/devfile/adapters/common/generic_test.go b/pkg/devfile/adapters/common/generic_test.go index 5af6313c6..827da5363 100644 --- a/pkg/devfile/adapters/common/generic_test.go +++ b/pkg/devfile/adapters/common/generic_test.go @@ -2,12 +2,12 @@ package common import ( "fmt" - devfileParser "github.com/openshift/odo/pkg/devfile/parser" - "github.com/openshift/odo/pkg/testingutil" "io" "testing" - "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + devfileParser "github.com/devfile/library/pkg/devfile/parser" + "github.com/openshift/odo/pkg/testingutil" ) // Create a simple mock client for the ExecClient interface for the devfile exec unit tests. @@ -31,36 +31,42 @@ func TestExecuteDevfileCommand(t *testing.T) { compInfo := ComponentInfo{ ContainerName: "some-container", } - cif := func(command common.DevfileCommand) (ComponentInfo, error) { + cif := func(command devfilev1.Command) (ComponentInfo, error) { return compInfo, nil } commands := []string{"command1", "command2", "command3", "command4"} tests := []struct { name string - commands []common.DevfileCommand - cmd common.DevfileCommand + commands []devfilev1.Command + cmd devfilev1.Command execClient ExecClient wantErr bool }{ { name: "Case 1: Non-parallel, successful exec", - commands: []common.DevfileCommand{ + commands: []devfilev1.Command{ { - Id: commands[0], - Exec: &common.Exec{HotReloadCapable: false}, + Id: commands[0], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{HotReloadCapable: false}, + }, }, { - Id: commands[1], - Exec: &common.Exec{HotReloadCapable: false}, + Id: commands[1], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{HotReloadCapable: false}, + }, }, { - Id: commands[2], - Composite: &common.Composite{Commands: []string{""}}, + Id: commands[2], + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{Commands: []string{""}}, + }, }, }, cmd: createCommandFrom(commands[2], - common.Composite{ + devfilev1.CompositeCommand{ Commands: []string{commands[0], commands[1]}, Parallel: false, }), @@ -69,21 +75,27 @@ func TestExecuteDevfileCommand(t *testing.T) { }, { name: "Case 2: Non-parallel, failed exec", - commands: []common.DevfileCommand{ + commands: []devfilev1.Command{ { - Id: commands[0], - Exec: &common.Exec{HotReloadCapable: false}, + Id: commands[0], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{HotReloadCapable: false}, + }, }, { - Id: commands[1], - Exec: &common.Exec{HotReloadCapable: false}, + Id: commands[1], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{HotReloadCapable: false}, + }, }, { - Id: commands[2], - Composite: &common.Composite{Commands: []string{""}}, + Id: commands[2], + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{Commands: []string{""}}, + }, }, }, - cmd: createCommandFrom(commands[2], common.Composite{ + cmd: createCommandFrom(commands[2], devfilev1.CompositeCommand{ Commands: []string{commands[0], commands[1]}, Parallel: false, }), @@ -92,18 +104,27 @@ func TestExecuteDevfileCommand(t *testing.T) { }, { name: "Case 3: Parallel, successful exec", - commands: []common.DevfileCommand{ + commands: []devfilev1.Command{ { - Id: commands[0], - Exec: &common.Exec{HotReloadCapable: false}}, + Id: commands[0], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{HotReloadCapable: false}, + }, + }, { - Id: commands[1], - Exec: &common.Exec{HotReloadCapable: false}}, + Id: commands[1], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{HotReloadCapable: false}, + }, + }, { - Id: commands[2], - Composite: &common.Composite{Commands: []string{""}}}, + Id: commands[2], + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{Commands: []string{""}}, + }, + }, }, - cmd: createCommandFrom(commands[2], common.Composite{ + cmd: createCommandFrom(commands[2], devfilev1.CompositeCommand{ Commands: []string{commands[0], commands[1]}, Parallel: true, }), @@ -112,18 +133,27 @@ func TestExecuteDevfileCommand(t *testing.T) { }, { name: "Case 4: Parallel, failed exec", - commands: []common.DevfileCommand{ + commands: []devfilev1.Command{ { - Id: commands[0], - Exec: &common.Exec{HotReloadCapable: false}}, + Id: commands[0], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{HotReloadCapable: false}, + }, + }, { - Id: commands[1], - Exec: &common.Exec{HotReloadCapable: false}}, + Id: commands[1], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{HotReloadCapable: false}, + }, + }, { - Id: commands[2], - Composite: &common.Composite{Commands: []string{""}}}, + Id: commands[2], + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{Commands: []string{""}}, + }, + }, }, - cmd: createCommandFrom(commands[2], common.Composite{ + cmd: createCommandFrom(commands[2], devfilev1.CompositeCommand{ Commands: []string{commands[0], commands[1]}, Parallel: true, }), @@ -132,21 +162,27 @@ func TestExecuteDevfileCommand(t *testing.T) { }, { name: "Case 5: Non-Parallel, command not found", - commands: []common.DevfileCommand{ + commands: []devfilev1.Command{ { - Id: commands[0], - Exec: &common.Exec{HotReloadCapable: false}, + Id: commands[0], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{HotReloadCapable: false}, + }, }, { - Id: commands[1], - Exec: &common.Exec{HotReloadCapable: false}, + Id: commands[1], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{HotReloadCapable: false}, + }, }, { - Id: commands[2], - Composite: &common.Composite{Commands: []string{""}}, + Id: commands[2], + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{Commands: []string{""}}, + }, }, }, - cmd: createCommandFrom(commands[2], common.Composite{ + cmd: createCommandFrom(commands[2], devfilev1.CompositeCommand{ Commands: []string{commands[0], "fake-command"}, Parallel: false, }), @@ -155,21 +191,27 @@ func TestExecuteDevfileCommand(t *testing.T) { }, { name: "Case 6: Parallel, command not found", - commands: []common.DevfileCommand{ + commands: []devfilev1.Command{ { - Id: commands[0], - Exec: &common.Exec{HotReloadCapable: false}, + Id: commands[0], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{HotReloadCapable: false}, + }, }, { - Id: commands[1], - Exec: &common.Exec{HotReloadCapable: false}, + Id: commands[1], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{HotReloadCapable: false}, + }, }, { - Id: commands[2], - Composite: &common.Composite{Commands: []string{""}}, + Id: commands[2], + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{Commands: []string{""}}, + }, }, }, - cmd: createCommandFrom(commands[2], common.Composite{ + cmd: createCommandFrom(commands[2], devfilev1.CompositeCommand{ Commands: []string{commands[0], "fake-command"}, Parallel: true, }), @@ -178,25 +220,33 @@ func TestExecuteDevfileCommand(t *testing.T) { }, { name: "Case 7: Nested composite commands", - commands: []common.DevfileCommand{ + commands: []devfilev1.Command{ { - Id: commands[0], - Exec: &common.Exec{HotReloadCapable: false}, + Id: commands[0], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{HotReloadCapable: false}, + }, }, { - Id: commands[1], - Exec: &common.Exec{HotReloadCapable: false}, + Id: commands[1], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{HotReloadCapable: false}, + }, }, { - Id: commands[2], - Composite: &common.Composite{Commands: []string{commands[0], commands[1]}}, + Id: commands[2], + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{Commands: []string{commands[0], commands[1]}}, + }, }, { - Id: commands[3], - Composite: &common.Composite{Commands: []string{""}}, + Id: commands[3], + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{Commands: []string{""}}, + }, }, }, - cmd: createCommandFrom(commands[3], common.Composite{ + cmd: createCommandFrom(commands[3], devfilev1.CompositeCommand{ Commands: []string{commands[0], commands[2]}, Parallel: false, }), @@ -205,25 +255,33 @@ func TestExecuteDevfileCommand(t *testing.T) { }, { name: "Case 8: Nested parallel composite commands", - commands: []common.DevfileCommand{ + commands: []devfilev1.Command{ { - Id: commands[0], - Exec: &common.Exec{HotReloadCapable: false}, + Id: commands[0], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{HotReloadCapable: false}, + }, }, { - Id: commands[1], - Exec: &common.Exec{HotReloadCapable: false}, + Id: commands[1], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{HotReloadCapable: false}, + }, }, { - Id: commands[2], - Composite: &common.Composite{Commands: []string{commands[0], commands[1]}}, + Id: commands[2], + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{Commands: []string{commands[0], commands[1]}}, + }, }, { - Id: commands[3], - Composite: &common.Composite{Commands: []string{""}}, + Id: commands[3], + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{Commands: []string{""}}, + }, }, }, - cmd: createCommandFrom(commands[3], common.Composite{ + cmd: createCommandFrom(commands[3], devfilev1.CompositeCommand{ Commands: []string{commands[0], commands[2]}, Parallel: true, }), @@ -241,7 +299,7 @@ func TestExecuteDevfileCommand(t *testing.T) { } } -func adapter(fakeExecClient ExecClient, commands []common.DevfileCommand, cif func(command common.DevfileCommand) (ComponentInfo, error)) *GenericAdapter { +func adapter(fakeExecClient ExecClient, commands []devfilev1.Command, cif func(command devfilev1.Command) (ComponentInfo, error)) *GenericAdapter { data := &testingutil.TestDevfileData{} _ = data.AddCommands(commands...) devObj := devfileParser.DevfileObj{ @@ -256,6 +314,6 @@ func adapter(fakeExecClient ExecClient, commands []common.DevfileCommand, cif fu return a } -func createCommandFrom(id string, composite common.Composite) common.DevfileCommand { - return common.DevfileCommand{Composite: &composite} +func createCommandFrom(id string, composite devfilev1.CompositeCommand) devfilev1.Command { + return devfilev1.Command{CommandUnion: devfilev1.CommandUnion{Composite: &composite}} } diff --git a/pkg/devfile/adapters/common/types.go b/pkg/devfile/adapters/common/types.go index c4067b1de..fe3be107c 100644 --- a/pkg/devfile/adapters/common/types.go +++ b/pkg/devfile/adapters/common/types.go @@ -1,8 +1,9 @@ package common import ( - devfileParser "github.com/openshift/odo/pkg/devfile/parser" - "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + devfileParser "github.com/devfile/library/pkg/devfile/parser" + "github.com/openshift/odo/pkg/envinfo" ) @@ -65,9 +66,9 @@ func (ci ComponentInfo) IsEmpty() bool { } // PushCommandsMap stores the commands to be executed as per their types. -type PushCommandsMap map[common.DevfileCommandGroupType]common.DevfileCommand +type PushCommandsMap map[devfilev1.CommandGroupKind]devfilev1.Command // NewPushCommandMap returns the instance of PushCommandsMap func NewPushCommandMap() PushCommandsMap { - return make(map[common.DevfileCommandGroupType]common.DevfileCommand) + return make(map[devfilev1.CommandGroupKind]devfilev1.Command) } diff --git a/pkg/devfile/adapters/common/utils.go b/pkg/devfile/adapters/common/utils.go index 34b713d33..ef4dd0fde 100644 --- a/pkg/devfile/adapters/common/utils.go +++ b/pkg/devfile/adapters/common/utils.go @@ -6,9 +6,10 @@ import ( "k8s.io/klog" - devfileParser "github.com/openshift/odo/pkg/devfile/parser" - "github.com/openshift/odo/pkg/devfile/parser/data" - "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + devfileParser "github.com/devfile/library/pkg/devfile/parser" + "github.com/devfile/library/pkg/devfile/parser/data" + parsercommon "github.com/devfile/library/pkg/devfile/parser/data/v2/common" "github.com/openshift/odo/pkg/kclient/generator" ) @@ -120,11 +121,11 @@ func GetBootstrapperImage() string { } // getCommandsByGroup gets commands by the group kind -func getCommandsByGroup(data data.DevfileData, groupType common.DevfileCommandGroupType) []common.DevfileCommand { - var commands []common.DevfileCommand +func getCommandsByGroup(data data.DevfileData, groupType devfilev1.CommandGroupKind) []devfilev1.Command { + var commands []devfilev1.Command for _, command := range data.GetCommands() { - commandGroup := command.GetGroup() + commandGroup := parsercommon.GetGroup(command) if commandGroup != nil && commandGroup.Kind == groupType { commands = append(commands, command) } @@ -134,7 +135,7 @@ func getCommandsByGroup(data data.DevfileData, groupType common.DevfileCommandGr } // GetVolumeMountPath gets the volume mount's path -func GetVolumeMountPath(volumeMount common.VolumeMount) string { +func GetVolumeMountPath(volumeMount devfilev1.VolumeMount) string { // if there is no volume mount path, default to volume mount name as per devfile schema if volumeMount.Path == "" { volumeMount.Path = "/" + volumeMount.Name @@ -183,7 +184,7 @@ func IsRestartRequired(hotReload bool, runModeChanged bool) bool { } // IsEnvPresent checks if the env variable is present in an array of env variables -func IsEnvPresent(envVars []common.Env, envVarName string) bool { +func IsEnvPresent(envVars []devfilev1.EnvVar, envVarName string) bool { for _, envVar := range envVars { if envVar.Name == envVarName { return true @@ -194,9 +195,9 @@ func IsEnvPresent(envVars []common.Env, envVarName string) bool { } // IsPortPresent checks if the port is present in the endpoints array -func IsPortPresent(endpoints []common.Endpoint, port int) bool { +func IsPortPresent(endpoints []devfilev1.Endpoint, port int) bool { for _, endpoint := range endpoints { - if endpoint.TargetPort == int32(port) { + if endpoint.TargetPort == port { return true } } @@ -206,7 +207,7 @@ func IsPortPresent(endpoints []common.Endpoint, port int) bool { // GetComponentEnvVar returns true if a list of env vars contains the specified env var // If the env exists, it returns the value of it -func GetComponentEnvVar(env string, envs []common.Env) string { +func GetComponentEnvVar(env string, envs []devfilev1.EnvVar) string { for _, envVar := range envs { if envVar.Name == env { return envVar.Value @@ -217,7 +218,7 @@ func GetComponentEnvVar(env string, envs []common.Env) string { // GetCommandsFromEvent returns the list of commands from the event name. // If the event is a composite command, it returns the sub-commands from the tree -func GetCommandsFromEvent(commandsMap map[string]common.DevfileCommand, eventName string) []string { +func GetCommandsFromEvent(commandsMap map[string]devfilev1.Command, eventName string) []string { var commands []string if command, ok := commandsMap[eventName]; ok { diff --git a/pkg/devfile/adapters/common/utils_test.go b/pkg/devfile/adapters/common/utils_test.go index bce980fa0..db9f7395e 100644 --- a/pkg/devfile/adapters/common/utils_test.go +++ b/pkg/devfile/adapters/common/utils_test.go @@ -5,9 +5,8 @@ import ( "reflect" "testing" - devfileParser "github.com/openshift/odo/pkg/devfile/parser" - "github.com/openshift/odo/pkg/devfile/parser/data/common" - versionsCommon "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + devfileParser "github.com/devfile/library/pkg/devfile/parser" "github.com/openshift/odo/pkg/testingutil" ) @@ -17,12 +16,12 @@ func TestGetVolumes(t *testing.T) { tests := []struct { name string - component []versionsCommon.DevfileComponent + component []devfilev1.Component wantContainerNameToVolumes map[string][]DevfileVolume }{ { name: "Case 1: Valid devfile with container referencing a volume component", - component: []versionsCommon.DevfileComponent{testingutil.GetFakeContainerComponent("comp1"), testingutil.GetFakeVolumeComponent("myvolume1", size)}, + component: []devfilev1.Component{testingutil.GetFakeContainerComponent("comp1"), testingutil.GetFakeVolumeComponent("myvolume1", size)}, wantContainerNameToVolumes: map[string][]DevfileVolume{ "comp1": { { @@ -35,22 +34,26 @@ func TestGetVolumes(t *testing.T) { }, { name: "Case 2: Valid devfile with container referencing multiple volume components", - component: []versionsCommon.DevfileComponent{ + component: []devfilev1.Component{ testingutil.GetFakeVolumeComponent("myvolume1", size), testingutil.GetFakeVolumeComponent("myvolume2", size), testingutil.GetFakeVolumeComponent("myvolume3", size), { Name: "mycontainer", - Container: &versionsCommon.Container{ - Image: "image", - VolumeMounts: []versionsCommon.VolumeMount{ - { - Name: "myvolume1", - Path: "/myvolume1", - }, - { - Name: "myvolume2", - Path: "/myvolume2", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "image", + VolumeMounts: []devfilev1.VolumeMount{ + { + Name: "myvolume1", + Path: "/myvolume1", + }, + { + Name: "myvolume2", + Path: "/myvolume2", + }, + }, }, }, }, @@ -73,7 +76,7 @@ func TestGetVolumes(t *testing.T) { }, { name: "Case 3: Valid devfile with container referencing no volume component", - component: []versionsCommon.DevfileComponent{testingutil.GetFakeContainerComponent("comp1"), testingutil.GetFakeVolumeComponent("myvolume2", size)}, + component: []devfilev1.Component{testingutil.GetFakeContainerComponent("comp1"), testingutil.GetFakeVolumeComponent("myvolume2", size)}, wantContainerNameToVolumes: map[string][]DevfileVolume{ "comp1": { { @@ -86,12 +89,16 @@ func TestGetVolumes(t *testing.T) { }, { name: "Case 4: Valid devfile with no container volume mounts", - component: []versionsCommon.DevfileComponent{ + component: []devfilev1.Component{ testingutil.GetFakeVolumeComponent("myvolume2", size), { Name: "mycontainer", - Container: &versionsCommon.Container{ - Image: "image", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "image", + }, + }, }, }, }, @@ -99,15 +106,19 @@ func TestGetVolumes(t *testing.T) { }, { name: "Case 5: Valid devfile with container referencing no volume mount path", - component: []versionsCommon.DevfileComponent{ + component: []devfilev1.Component{ testingutil.GetFakeVolumeComponent("myvolume1", size), { Name: "mycontainer", - Container: &versionsCommon.Container{ - Image: "image", - VolumeMounts: []versionsCommon.VolumeMount{ - { - Name: "myvolume1", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "image", + VolumeMounts: []devfilev1.VolumeMount{ + { + Name: "myvolume1", + }, + }, }, }, }, @@ -147,7 +158,7 @@ func TestIsEnvPresent(t *testing.T) { envName := "myenv" envValue := "myenvvalue" - envVars := []common.Env{ + envVars := []devfilev1.EnvVar{ { Name: envName, Value: envValue, @@ -184,9 +195,9 @@ func TestIsEnvPresent(t *testing.T) { func TestIsPortPresent(t *testing.T) { endpointName := "8080/tcp" - var endpointPort int32 = 8080 + var endpointPort int = 8080 - endpoints := []common.Endpoint{ + endpoints := []devfilev1.Endpoint{ { Name: endpointName, TargetPort: endpointPort, @@ -259,12 +270,12 @@ func TestGetVolumeMountPath(t *testing.T) { tests := []struct { name string - volumeMount common.VolumeMount + volumeMount devfilev1.VolumeMount wantPath string }{ { name: "Case 1: Mount Path is present", - volumeMount: common.VolumeMount{ + volumeMount: devfilev1.VolumeMount{ Name: "name1", Path: "/path1", }, @@ -272,7 +283,7 @@ func TestGetVolumeMountPath(t *testing.T) { }, { name: "Case 2: Mount Path is absent", - volumeMount: common.VolumeMount{ + volumeMount: devfilev1.VolumeMount{ Name: "name1", }, wantPath: "/name1", @@ -292,59 +303,89 @@ func TestGetVolumeMountPath(t *testing.T) { func TestGetCommandsForGroup(t *testing.T) { - component := []versionsCommon.DevfileComponent{ + component := []devfilev1.Component{ testingutil.GetFakeContainerComponent("alias1"), } componentName := "alias1" command := "ls -la" workDir := "/" - execCommands := []common.DevfileCommand{ + execCommands := []devfilev1.Command{ { Id: "run command", - Exec: &common.Exec{ - CommandLine: command, - Component: componentName, - WorkingDir: workDir, - Group: &versionsCommon.Group{ - Kind: runGroup, - IsDefault: true, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{ + Kind: runGroup, + IsDefault: true, + }, + }, + }, + CommandLine: command, + Component: componentName, + WorkingDir: workDir, }, }, }, { Id: "build command", - Exec: &common.Exec{ - CommandLine: command, - Component: componentName, - WorkingDir: workDir, - Group: &versionsCommon.Group{Kind: buildGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup}, + }, + }, + CommandLine: command, + Component: componentName, + WorkingDir: workDir, + }, }, }, { Id: "test command", - Exec: &common.Exec{ - CommandLine: command, - Component: componentName, - WorkingDir: workDir, - Group: &versionsCommon.Group{Kind: testGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: testGroup}, + }, + }, + CommandLine: command, + Component: componentName, + WorkingDir: workDir, + }, }, }, { Id: "debug command", - Exec: &common.Exec{ - CommandLine: command, - Component: componentName, - WorkingDir: workDir, - Group: &versionsCommon.Group{Kind: debugGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: debugGroup}, + }, + }, + CommandLine: command, + Component: componentName, + WorkingDir: workDir, + }, }, }, { Id: "customcommand", - Exec: &common.Exec{ - CommandLine: command, - Component: componentName, - WorkingDir: workDir, - Group: &versionsCommon.Group{Kind: runGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: command, + Component: componentName, + WorkingDir: workDir, + }, }, }, } @@ -358,7 +399,7 @@ func TestGetCommandsForGroup(t *testing.T) { tests := []struct { name string - groupType common.DevfileCommandGroupType + groupType devfilev1.CommandGroupKind numberOfCommands int }{ { @@ -402,76 +443,92 @@ func TestGetCommandsForGroup(t *testing.T) { func TestGetCommands(t *testing.T) { - component := []versionsCommon.DevfileComponent{ + component := []devfilev1.Component{ testingutil.GetFakeContainerComponent("alias1"), } tests := []struct { name string - execCommands []common.DevfileCommand - compCommands []common.DevfileCommand - expectedCommands []versionsCommon.DevfileCommand + execCommands []devfilev1.Command + compCommands []devfilev1.Command + expectedCommands []devfilev1.Command }{ { name: "Case 1: One command", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "somecommand", - Exec: &common.Exec{ - HotReloadCapable: false, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + HotReloadCapable: false, + }, }, }, }, - expectedCommands: []versionsCommon.DevfileCommand{ + expectedCommands: []devfilev1.Command{ { Id: "somecommand", - Exec: &common.Exec{ - HotReloadCapable: false, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + HotReloadCapable: false, + }, }, }, }, }, { name: "Case 2: Multiple commands", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "somecommand", - Exec: &common.Exec{ - HotReloadCapable: false, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + HotReloadCapable: false, + }, }, }, { Id: "somecommand2", - Exec: &common.Exec{ - HotReloadCapable: false, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + HotReloadCapable: false, + }, }, }, }, - compCommands: []common.DevfileCommand{ + compCommands: []devfilev1.Command{ { Id: "mycomposite", - Composite: &common.Composite{ - Commands: []string{}, + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{ + Commands: []string{}, + }, }, }, }, - expectedCommands: []versionsCommon.DevfileCommand{ + expectedCommands: []devfilev1.Command{ { Id: "somecommand", - Exec: &common.Exec{ - HotReloadCapable: false, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + HotReloadCapable: false, + }, }, }, { Id: "somecommand2", - Exec: &common.Exec{ - HotReloadCapable: false, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + HotReloadCapable: false, + }, }, }, { Id: "mycomposite", - Composite: &common.Composite{ - Commands: []string{}, + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{ + Commands: []string{}, + }, }, }, }, @@ -506,7 +563,7 @@ func TestGetComponentEnvVar(t *testing.T) { tests := []struct { name string env string - envs []common.Env + envs []devfilev1.EnvVar want string }{ { @@ -518,7 +575,7 @@ func TestGetComponentEnvVar(t *testing.T) { { name: "Case 2: Has env", env: "PROJECTS_ROOT", - envs: []common.Env{ + envs: []devfilev1.EnvVar{ { Name: "SOME_ENV", Value: "test", @@ -537,7 +594,7 @@ func TestGetComponentEnvVar(t *testing.T) { { name: "Case 3: No env, multiple values", env: "PROJECTS_ROOT", - envs: []common.Env{ + envs: []devfilev1.EnvVar{ { Name: "TESTER", Value: "fake", @@ -568,28 +625,36 @@ func TestGetComponentEnvVar(t *testing.T) { func TestGetCommandsFromEvent(t *testing.T) { - execCommands := []versionsCommon.DevfileCommand{ + execCommands := []devfilev1.Command{ { - Id: "exec1", - Exec: &versionsCommon.Exec{}, + Id: "exec1", + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{}, + }, }, { - Id: "exec2", - Exec: &versionsCommon.Exec{}, + Id: "exec2", + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{}, + }, }, { - Id: "exec3", - Exec: &versionsCommon.Exec{}, + Id: "exec3", + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{}, + }, }, } - compCommands := []versionsCommon.DevfileCommand{ + compCommands := []devfilev1.Command{ { Id: "comp1", - Composite: &common.Composite{ - Commands: []string{ - "exec1", - "exec3", + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{ + Commands: []string{ + "exec1", + "exec3", + }, }, }, }, diff --git a/pkg/devfile/adapters/docker/adapter.go b/pkg/devfile/adapters/docker/adapter.go index 528915f92..ed01e2a10 100644 --- a/pkg/devfile/adapters/docker/adapter.go +++ b/pkg/devfile/adapters/docker/adapter.go @@ -3,7 +3,7 @@ package docker import ( "io" - versionsCommon "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" "github.com/openshift/odo/pkg/machineoutput" "github.com/openshift/odo/pkg/devfile/adapters/common" @@ -70,11 +70,11 @@ func (d Adapter) Logger() machineoutput.MachineEventLoggingClient { return d.componentAdapter.Logger() } -func (d Adapter) ComponentInfo(command versionsCommon.DevfileCommand) (common.ComponentInfo, error) { +func (d Adapter) ComponentInfo(command devfilev1.Command) (common.ComponentInfo, error) { return d.componentAdapter.ComponentInfo(command) } -func (d Adapter) SupervisorComponentInfo(command versionsCommon.DevfileCommand) (common.ComponentInfo, error) { +func (d Adapter) SupervisorComponentInfo(command devfilev1.Command) (common.ComponentInfo, error) { return d.componentAdapter.SupervisorComponentInfo(command) } diff --git a/pkg/devfile/adapters/docker/component/adapter.go b/pkg/devfile/adapters/docker/component/adapter.go index 01e7107d8..796956664 100644 --- a/pkg/devfile/adapters/docker/component/adapter.go +++ b/pkg/devfile/adapters/docker/component/adapter.go @@ -11,8 +11,8 @@ import ( "github.com/pkg/errors" "k8s.io/klog" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" "github.com/openshift/odo/pkg/devfile/adapters/common" - versionsCommon "github.com/openshift/odo/pkg/devfile/parser/data/common" "github.com/openshift/odo/pkg/devfile/adapters/docker/storage" "github.com/openshift/odo/pkg/devfile/adapters/docker/utils" @@ -56,7 +56,7 @@ func (a *Adapter) getContainers() ([]types.Container, error) { return a.containers, nil } -func (a Adapter) ComponentInfo(command versionsCommon.DevfileCommand) (common.ComponentInfo, error) { +func (a Adapter) ComponentInfo(command devfilev1.Command) (common.ComponentInfo, error) { containers, err := a.getContainers() if err != nil { return common.ComponentInfo{}, err @@ -66,7 +66,7 @@ func (a Adapter) ComponentInfo(command versionsCommon.DevfileCommand) (common.Co return compInfo, nil } -func (a Adapter) SupervisorComponentInfo(command versionsCommon.DevfileCommand) (common.ComponentInfo, error) { +func (a Adapter) SupervisorComponentInfo(command devfilev1.Command) (common.ComponentInfo, error) { containers, err := a.getContainers() if err != nil { return common.ComponentInfo{}, err @@ -360,13 +360,13 @@ func (a Adapter) Log(follow, debug bool) (io.ReadCloser, error) { return nil, errors.Wrapf(err, "error while retrieving container for odo component %s", a.ComponentName) } - var command versionsCommon.DevfileCommand + var command devfilev1.Command if debug { command, err = common.GetDebugCommand(a.Devfile.Data, "") if err != nil { return nil, err } - if reflect.DeepEqual(versionsCommon.DevfileCommand{}, command) { + if reflect.DeepEqual(devfilev1.Command{}, command) { return nil, errors.Errorf("no debug command found in devfile, please run \"odo log\" for run command logs") } diff --git a/pkg/devfile/adapters/docker/component/adapter_test.go b/pkg/devfile/adapters/docker/component/adapter_test.go index bb142f390..e772e9c68 100644 --- a/pkg/devfile/adapters/docker/component/adapter_test.go +++ b/pkg/devfile/adapters/docker/component/adapter_test.go @@ -5,14 +5,13 @@ import ( "os" "testing" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + devfileParser "github.com/devfile/library/pkg/devfile/parser" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/mount" volumeTypes "github.com/docker/docker/api/types/volume" "github.com/golang/mock/gomock" adaptersCommon "github.com/openshift/odo/pkg/devfile/adapters/common" - devfileParser "github.com/openshift/odo/pkg/devfile/parser" - "github.com/openshift/odo/pkg/devfile/parser/data/common" - versionsCommon "github.com/openshift/odo/pkg/devfile/parser/data/common" "github.com/openshift/odo/pkg/lclient" "github.com/openshift/odo/pkg/testingutil" ) @@ -41,52 +40,62 @@ func TestPush(t *testing.T) { ForceBuild: false, } - execCommands := []versionsCommon.DevfileCommand{ + execCommands := []devfilev1.Command{ { - Exec: &versionsCommon.Exec{ - CommandLine: command, - Component: component, - Group: &versionsCommon.Group{ - Kind: versionsCommon.RunCommandGroupType, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{ + Kind: devfilev1.RunCommandGroupKind, + }, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, }, - WorkingDir: workDir, }, }, } - validComponents := []versionsCommon.DevfileComponent{ + validComponents := []devfilev1.Component{ { Name: component, - Container: &versionsCommon.Container{ - Image: "image", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "image", + }, + }, }, }, } tests := []struct { name string - components []versionsCommon.DevfileComponent - componentType versionsCommon.DevfileComponentType + components []devfilev1.Component + componentType devfilev1.ComponentType client *lclient.Client wantErr bool }{ { name: "Case 1: Invalid devfile", componentType: "", - components: []versionsCommon.DevfileComponent{}, + components: []devfilev1.Component{}, client: fakeClient, wantErr: true, }, { name: "Case 2: Valid devfile", components: validComponents, - componentType: versionsCommon.ContainerComponentType, + componentType: devfilev1.ContainerComponentType, client: fakeClient, wantErr: false, }, { name: "Case 3: Valid devfile, docker client error", components: validComponents, - componentType: versionsCommon.ContainerComponentType, + componentType: devfilev1.ContainerComponentType, client: fakeErrorClient, wantErr: true, }, @@ -141,27 +150,31 @@ func TestDockerTest(t *testing.T) { t.Errorf("TestPush error: error creating temporary directory for the indexer: %v", err) } - validComponents := []versionsCommon.DevfileComponent{ + validComponents := []devfilev1.Component{ { Name: component, - Container: &versionsCommon.Container{ - Image: "image", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "image", + }, + }, }, }, } tests := []struct { name string - components []versionsCommon.DevfileComponent - componentType versionsCommon.DevfileComponentType + components []devfilev1.Component + componentType devfilev1.ComponentType client *lclient.Client - execCommands []versionsCommon.DevfileCommand + execCommands []devfilev1.Command wantErr bool }{ { name: "Case 1: Invalid devfile", components: validComponents, - execCommands: []versionsCommon.DevfileCommand{}, + execCommands: []devfilev1.Command{}, client: fakeClient, wantErr: true, }, @@ -169,16 +182,22 @@ func TestDockerTest(t *testing.T) { name: "Case 2: Valid devfile", components: validComponents, client: fakeClient, - execCommands: []versionsCommon.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: id, - Exec: &versionsCommon.Exec{ - CommandLine: command, - Component: component, - Group: &versionsCommon.Group{ - Kind: versionsCommon.TestCommandGroupType, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{ + Kind: devfilev1.TestCommandGroupKind, + }, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, }, - WorkingDir: workDir, }, }, }, @@ -192,17 +211,23 @@ func TestDockerTest(t *testing.T) { }, { name: "Case 4: No valid containers", - components: []versionsCommon.DevfileComponent{}, - execCommands: []versionsCommon.DevfileCommand{ + components: []devfilev1.Component{}, + execCommands: []devfilev1.Command{ { Id: id, - Exec: &versionsCommon.Exec{ - CommandLine: command, - Component: component, - Group: &versionsCommon.Group{ - Kind: versionsCommon.TestCommandGroupType, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{ + Kind: devfilev1.TestCommandGroupKind, + }, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, }, - WorkingDir: workDir, }, }, }, @@ -211,17 +236,23 @@ func TestDockerTest(t *testing.T) { }, { name: "Case 5: Invalid command", - components: []versionsCommon.DevfileComponent{}, - execCommands: []versionsCommon.DevfileCommand{ + components: []devfilev1.Component{}, + execCommands: []devfilev1.Command{ { Id: id, - Exec: &versionsCommon.Exec{ - CommandLine: "", - Component: component, - Group: &versionsCommon.Group{ - Kind: versionsCommon.TestCommandGroupType, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{ + Kind: devfilev1.TestCommandGroupKind, + }, + }, + }, + CommandLine: "", + Component: component, + WorkingDir: workDir, }, - WorkingDir: workDir, }, }, }, @@ -230,17 +261,23 @@ func TestDockerTest(t *testing.T) { }, { name: "Case 6: No valid command group", - components: []versionsCommon.DevfileComponent{}, - execCommands: []versionsCommon.DevfileCommand{ + components: []devfilev1.Component{}, + execCommands: []devfilev1.Command{ { Id: id, - Exec: &versionsCommon.Exec{ - CommandLine: command, - Component: component, - Group: &versionsCommon.Group{ - Kind: versionsCommon.RunCommandGroupType, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{ + Kind: devfilev1.RunCommandGroupKind, + }, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, }, - WorkingDir: workDir, }, }, }, @@ -287,7 +324,7 @@ func TestDoesComponentExist(t *testing.T) { tests := []struct { name string client *lclient.Client - components []common.DevfileComponent + components []devfilev1.Component componentName string getComponentName string want bool @@ -296,7 +333,7 @@ func TestDoesComponentExist(t *testing.T) { { name: "Case 1: Valid component name", client: fakeClient, - components: []common.DevfileComponent{ + components: []devfilev1.Component{ testingutil.GetFakeContainerComponent("alias1"), testingutil.GetFakeContainerComponent("alias2"), }, @@ -308,7 +345,7 @@ func TestDoesComponentExist(t *testing.T) { { name: "Case 2: Non-existent component name", client: fakeClient, - components: []common.DevfileComponent{ + components: []devfilev1.Component{ testingutil.GetFakeContainerComponent("alias1"), }, componentName: "test", @@ -321,14 +358,14 @@ func TestDoesComponentExist(t *testing.T) { componentName: "test", getComponentName: "golang", client: fakeClient, - components: []common.DevfileComponent{}, + components: []devfilev1.Component{}, want: true, wantErr: true, }, { name: "Case 4: Docker client error", client: fakeErrorClient, - components: []common.DevfileComponent{ + components: []devfilev1.Component{ testingutil.GetFakeContainerComponent("alias1"), }, componentName: "test", @@ -417,7 +454,7 @@ func TestAdapterDelete(t *testing.T) { devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ - Components: []versionsCommon.DevfileComponent{}, + Components: []devfilev1.Component{}, }, } @@ -791,7 +828,7 @@ func TestAdapterDeleteVolumes(t *testing.T) { devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ - Components: []versionsCommon.DevfileComponent{}, + Components: []devfilev1.Component{}, }, } diff --git a/pkg/devfile/adapters/docker/component/utils.go b/pkg/devfile/adapters/docker/component/utils.go index 9960d08de..c166a2530 100644 --- a/pkg/devfile/adapters/docker/component/utils.go +++ b/pkg/devfile/adapters/docker/component/utils.go @@ -12,10 +12,10 @@ import ( "github.com/pkg/errors" "k8s.io/klog" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" "github.com/openshift/odo/pkg/devfile/adapters/common" "github.com/openshift/odo/pkg/devfile/adapters/docker/storage" "github.com/openshift/odo/pkg/devfile/adapters/docker/utils" - versionsCommon "github.com/openshift/odo/pkg/devfile/parser/data/common" "github.com/openshift/odo/pkg/envinfo" "github.com/openshift/odo/pkg/kclient/generator" "github.com/openshift/odo/pkg/lclient" @@ -160,7 +160,7 @@ func (a Adapter) updateComponent() (componentExists bool, err error) { return } -func (a Adapter) pullAndStartContainer(mounts []mount.Mount, comp versionsCommon.DevfileComponent) error { +func (a Adapter) pullAndStartContainer(mounts []mount.Mount, comp devfilev1.Component) error { // Container doesn't exist, so need to pull its image (to be safe) and start a new container s := log.Spinnerf("Pulling image %s", comp.Container.Image) @@ -181,7 +181,7 @@ func (a Adapter) pullAndStartContainer(mounts []mount.Mount, comp versionsCommon return nil } -func (a Adapter) startComponent(mounts []mount.Mount, comp versionsCommon.DevfileComponent) error { +func (a Adapter) startComponent(mounts []mount.Mount, comp devfilev1.Component) error { hostConfig, namePortMapping, err := a.generateAndGetHostConfig(comp.Container.Endpoints) hostConfig.Mounts = mounts if err != nil { @@ -196,7 +196,8 @@ func (a Adapter) startComponent(mounts []mount.Mount, comp versionsCommon.Devfil updateComponentWithSupervisord(&comp, runCommand, a.supervisordVolumeName, &hostConfig) // If the component set `mountSources` to true, add the source volume and env PROJECTS_ROOT to it - if comp.Container.MountSources { + // Default mountSources is true + if comp.Container.MountSources == nil || *comp.Container.MountSources { var syncFolder, projectsRoot string if comp.Container.SourceMapping != "" { syncFolder = comp.Container.SourceMapping @@ -211,7 +212,7 @@ func (a Adapter) startComponent(mounts []mount.Mount, comp versionsCommon.Devfil if projectsRoot == "" { envName := common.EnvProjectsRoot envValue := syncFolder - comp.Container.Env = append(comp.Container.Env, versionsCommon.Env{ + comp.Container.Env = append(comp.Container.Env, devfilev1.EnvVar{ Name: envName, Value: envValue, }) @@ -236,7 +237,7 @@ func (a Adapter) startComponent(mounts []mount.Mount, comp versionsCommon.Devfil return nil } -func (a Adapter) generateAndGetContainerConfig(componentName string, comp versionsCommon.DevfileComponent) container.Config { +func (a Adapter) generateAndGetContainerConfig(componentName string, comp devfilev1.Component) container.Config { // Convert the env vars in the Devfile to the format expected by Docker envVars := utils.ConvertEnvs(comp.Container.Env) ports := utils.ConvertPorts(comp.Container.Endpoints) @@ -246,7 +247,7 @@ func (a Adapter) generateAndGetContainerConfig(componentName string, comp versio return containerConfig } -func (a Adapter) generateAndGetHostConfig(endpoints []versionsCommon.Endpoint) (container.HostConfig, map[nat.Port]string, error) { +func (a Adapter) generateAndGetHostConfig(endpoints []devfilev1.Endpoint) (container.HostConfig, map[nat.Port]string, error) { // Convert the port bindings from env.yaml and generate docker host config portMap, namePortMapping, err := getPortMap(a.Context, endpoints, true) if err != nil { @@ -261,7 +262,7 @@ func (a Adapter) generateAndGetHostConfig(endpoints []versionsCommon.Endpoint) ( return hostConfig, namePortMapping, nil } -func getPortMap(context string, endpoints []versionsCommon.Endpoint, show bool) (nat.PortMap, map[nat.Port]string, error) { +func getPortMap(context string, endpoints []devfilev1.Endpoint, show bool) (nat.PortMap, map[nat.Port]string, error) { // Convert the exposed and internal port pairs saved in env.yaml file to PortMap // Todo: Use context to get the appropriate envinfo after context is supported in experimental mode portmap := nat.PortMap{} @@ -445,7 +446,7 @@ func (a Adapter) startBootstrapSupervisordInitContainer(supervisordVolumeName st // UpdateComponentWithSupervisord updates the devfile component's // 1. command and args with supervisord, if absent // 2. env with ODO_COMMAND_RUN and ODO_COMMAND_RUN_WORKING_DIR, if absent -func updateComponentWithSupervisord(comp *versionsCommon.DevfileComponent, runCommand versionsCommon.DevfileCommand, supervisordVolumeName string, hostConfig *container.HostConfig) { +func updateComponentWithSupervisord(comp *devfilev1.Component, runCommand devfilev1.Command, supervisordVolumeName string, hostConfig *container.HostConfig) { // Mount the supervisord volume for the run command container if runCommand.Exec.Component == comp.Name { @@ -460,7 +461,7 @@ func updateComponentWithSupervisord(comp *versionsCommon.DevfileComponent, runCo if !common.IsEnvPresent(comp.Container.Env, common.EnvOdoCommandRun) { envName := common.EnvOdoCommandRun envValue := runCommand.Exec.CommandLine - comp.Container.Env = append(comp.Container.Env, versionsCommon.Env{ + comp.Container.Env = append(comp.Container.Env, devfilev1.EnvVar{ Name: envName, Value: envValue, }) @@ -469,7 +470,7 @@ func updateComponentWithSupervisord(comp *versionsCommon.DevfileComponent, runCo if !common.IsEnvPresent(comp.Container.Env, common.EnvOdoCommandRunWorkingDir) && runCommand.Exec.WorkingDir != "" { envName := common.EnvOdoCommandRunWorkingDir envValue := runCommand.Exec.WorkingDir - comp.Container.Env = append(comp.Container.Env, versionsCommon.Env{ + comp.Container.Env = append(comp.Container.Env, devfilev1.EnvVar{ Name: envName, Value: envValue, }) diff --git a/pkg/devfile/adapters/docker/component/utils_test.go b/pkg/devfile/adapters/docker/component/utils_test.go index f4af73664..3b0565a1c 100644 --- a/pkg/devfile/adapters/docker/component/utils_test.go +++ b/pkg/devfile/adapters/docker/component/utils_test.go @@ -7,11 +7,11 @@ import ( "github.com/docker/go-connections/nat" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + devfileParser "github.com/devfile/library/pkg/devfile/parser" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/mount" adaptersCommon "github.com/openshift/odo/pkg/devfile/adapters/common" - devfileParser "github.com/openshift/odo/pkg/devfile/parser" - versionsCommon "github.com/openshift/odo/pkg/devfile/parser/data/common" "github.com/openshift/odo/pkg/envinfo" "github.com/openshift/odo/pkg/lclient" "github.com/openshift/odo/pkg/testingutil" @@ -25,25 +25,25 @@ func TestCreateComponent(t *testing.T) { tests := []struct { name string - components []versionsCommon.DevfileComponent + components []devfilev1.Component client *lclient.Client wantErr bool }{ { name: "Case 1: Invalid devfile", - components: []versionsCommon.DevfileComponent{}, + components: []devfilev1.Component{}, client: fakeClient, wantErr: true, }, { name: "Case 2: Valid devfile", - components: []versionsCommon.DevfileComponent{testingutil.GetFakeContainerComponent("alias1")}, + components: []devfilev1.Component{testingutil.GetFakeContainerComponent("alias1")}, client: fakeClient, wantErr: false, }, { name: "Case 3: Valid devfile, docker client error", - components: []versionsCommon.DevfileComponent{testingutil.GetFakeContainerComponent("alias1")}, + components: []devfilev1.Component{testingutil.GetFakeContainerComponent("alias1")}, client: fakeErrorClient, wantErr: true, }, @@ -81,39 +81,43 @@ func TestUpdateComponent(t *testing.T) { tests := []struct { name string - components []versionsCommon.DevfileComponent + components []devfilev1.Component componentName string client *lclient.Client wantErr bool }{ { name: "Case 1: Invalid devfile", - components: []versionsCommon.DevfileComponent{}, + components: []devfilev1.Component{}, componentName: "", client: fakeClient, wantErr: true, }, { name: "Case 2: Valid devfile", - components: []versionsCommon.DevfileComponent{testingutil.GetFakeContainerComponent("alias1")}, + components: []devfilev1.Component{testingutil.GetFakeContainerComponent("alias1")}, componentName: "test", client: fakeClient, wantErr: false, }, { name: "Case 3: Valid devfile, docker client error", - components: []versionsCommon.DevfileComponent{testingutil.GetFakeContainerComponent("alias1")}, + components: []devfilev1.Component{testingutil.GetFakeContainerComponent("alias1")}, componentName: "", client: fakeErrorClient, wantErr: true, }, { name: "Case 4: Valid devfile, missing component", - components: []versionsCommon.DevfileComponent{ + components: []devfilev1.Component{ { Name: "alias1", - Container: &versionsCommon.Container{ - Image: "someimage", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "someimage", + }, + }, }, }, }, @@ -158,28 +162,28 @@ func TestPullAndStartContainer(t *testing.T) { tests := []struct { name string - componentType versionsCommon.DevfileComponentType + componentType devfilev1.ComponentType client *lclient.Client mounts []mount.Mount wantErr bool }{ { name: "Case 1: Successfully start container, no mount", - componentType: versionsCommon.ContainerComponentType, + componentType: devfilev1.ContainerComponentType, client: fakeClient, mounts: []mount.Mount{}, wantErr: false, }, { name: "Case 2: Docker client error", - componentType: versionsCommon.ContainerComponentType, + componentType: devfilev1.ContainerComponentType, client: fakeErrorClient, mounts: []mount.Mount{}, wantErr: true, }, { name: "Case 3: Successfully start container, one mount", - componentType: versionsCommon.ContainerComponentType, + componentType: devfilev1.ContainerComponentType, client: fakeClient, mounts: []mount.Mount{ { @@ -191,7 +195,7 @@ func TestPullAndStartContainer(t *testing.T) { }, { name: "Case 4: Successfully start container, multiple mounts", - componentType: versionsCommon.ContainerComponentType, + componentType: devfilev1.ContainerComponentType, client: fakeClient, mounts: []mount.Mount{ { @@ -210,7 +214,7 @@ func TestPullAndStartContainer(t *testing.T) { t.Run(tt.name, func(t *testing.T) { devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ - Components: []versionsCommon.DevfileComponent{ + Components: []devfilev1.Component{ testingutil.GetFakeContainerComponent("alias1"), }, Commands: testingutil.GetFakeExecRunCommands(), @@ -224,7 +228,7 @@ func TestPullAndStartContainer(t *testing.T) { componentAdapter := New(adapterCtx, *tt.client) componentAdapter.projectVolumeName = testVolumeName - err := componentAdapter.pullAndStartContainer(tt.mounts, adapterCtx.Devfile.Data.GetAliasedComponents()[0]) + err := componentAdapter.pullAndStartContainer(tt.mounts, adapterCtx.Devfile.Data.GetComponents()[0]) // Checks for unexpected error cases if !tt.wantErr == (err != nil) { @@ -292,7 +296,7 @@ func TestStartContainer(t *testing.T) { t.Run(tt.name, func(t *testing.T) { devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ - Components: []versionsCommon.DevfileComponent{ + Components: []devfilev1.Component{ testingutil.GetFakeContainerComponent("alias1"), }, Commands: testingutil.GetFakeExecRunCommands(), @@ -306,7 +310,7 @@ func TestStartContainer(t *testing.T) { componentAdapter := New(adapterCtx, *tt.client) componentAdapter.projectVolumeName = testVolumeName - err := componentAdapter.startComponent(tt.mounts, adapterCtx.Devfile.Data.GetAliasedComponents()[0]) + err := componentAdapter.startComponent(tt.mounts, adapterCtx.Devfile.Data.GetComponents()[0]) // Checks for unexpected error cases if !tt.wantErr == (err != nil) { @@ -322,7 +326,7 @@ func TestGenerateAndGetHostConfig(t *testing.T) { testComponentName := "test" endpointName := []string{"8080/tcp", "9090/tcp", "9080/tcp"} - var endpointPort = []int32{8080, 9090, 9080} + var endpointPort = []int{8080, 9090, 9080} var expectPortNameMapping = map[nat.Port]string{ nat.Port("8080/tcp"): "url1", nat.Port("9090/tcp"): "url2", @@ -334,14 +338,14 @@ func TestGenerateAndGetHostConfig(t *testing.T) { urlValue []envinfo.EnvInfoURL expectResult nat.PortMap client *lclient.Client - endpoints []versionsCommon.Endpoint + endpoints []devfilev1.Endpoint }{ { name: "Case 1: no port mappings", urlValue: []envinfo.EnvInfoURL{}, expectResult: nil, client: fakeClient, - endpoints: []versionsCommon.Endpoint{}, + endpoints: []devfilev1.Endpoint{}, }, { name: "Case 2: only one port mapping", @@ -357,7 +361,7 @@ func TestGenerateAndGetHostConfig(t *testing.T) { }, }, client: fakeClient, - endpoints: []versionsCommon.Endpoint{ + endpoints: []devfilev1.Endpoint{ { Name: endpointName[0], TargetPort: endpointPort[0], @@ -392,7 +396,7 @@ func TestGenerateAndGetHostConfig(t *testing.T) { }, }, client: fakeClient, - endpoints: []versionsCommon.Endpoint{ + endpoints: []devfilev1.Endpoint{ { Name: endpointName[0], TargetPort: endpointPort[0], @@ -413,7 +417,7 @@ func TestGenerateAndGetHostConfig(t *testing.T) { devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ - Components: []versionsCommon.DevfileComponent{}, + Components: []devfilev1.Component{}, }, } @@ -484,23 +488,31 @@ func TestExecDevfile(t *testing.T) { name: "Case 1: Successful devfile command exec of devbuild and devrun", client: fakeClient, pushDevfileCommands: adaptersCommon.PushCommandsMap{ - versionsCommon.RunCommandGroupType: versionsCommon.DevfileCommand{ - Exec: &versionsCommon.Exec{ - CommandLine: command, - WorkingDir: workDir, - Component: component, - Group: &versionsCommon.Group{ - Kind: versionsCommon.RunCommandGroupType, + devfilev1.RunCommandGroupKind: devfilev1.Command{ + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: devfilev1.RunCommandGroupKind}, + }, + }, + CommandLine: command, + WorkingDir: workDir, + Component: component, }, }, }, - versionsCommon.BuildCommandGroupType: versionsCommon.DevfileCommand{ - Exec: &versionsCommon.Exec{ - CommandLine: command, - WorkingDir: workDir, - Component: component, - Group: &versionsCommon.Group{ - Kind: versionsCommon.BuildCommandGroupType, + devfilev1.BuildCommandGroupKind: devfilev1.Command{ + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: devfilev1.BuildCommandGroupKind}, + }, + }, + CommandLine: command, + WorkingDir: workDir, + Component: component, }, }, }, @@ -512,13 +524,17 @@ func TestExecDevfile(t *testing.T) { name: "Case 2: Successful devfile command exec of devrun", client: fakeClient, pushDevfileCommands: adaptersCommon.PushCommandsMap{ - versionsCommon.RunCommandGroupType: versionsCommon.DevfileCommand{ - Exec: &versionsCommon.Exec{ - CommandLine: command, - WorkingDir: workDir, - Component: component, - Group: &versionsCommon.Group{ - Kind: versionsCommon.RunCommandGroupType, + devfilev1.RunCommandGroupKind: devfilev1.Command{ + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: devfilev1.RunCommandGroupKind}, + }, + }, + CommandLine: command, + WorkingDir: workDir, + Component: component, }, }, }, @@ -537,13 +553,17 @@ func TestExecDevfile(t *testing.T) { name: "Case 4: Unsuccessful devfile command exec of devrun", client: fakeErrorClient, pushDevfileCommands: adaptersCommon.PushCommandsMap{ - versionsCommon.RunCommandGroupType: versionsCommon.DevfileCommand{ - Exec: &versionsCommon.Exec{ - CommandLine: command, - WorkingDir: workDir, - Component: component, - Group: &versionsCommon.Group{ - Kind: versionsCommon.RunCommandGroupType, + devfilev1.RunCommandGroupKind: devfilev1.Command{ + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: devfilev1.RunCommandGroupKind}, + }, + }, + CommandLine: command, + WorkingDir: workDir, + Component: component, }, }, }, @@ -557,7 +577,7 @@ func TestExecDevfile(t *testing.T) { devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ - Components: []versionsCommon.DevfileComponent{}, + Components: []devfilev1.Component{}, }, } @@ -582,11 +602,15 @@ func TestExecTestCmd(t *testing.T) { workDir := "/tmp" component := "alias1" - validComponents := []versionsCommon.DevfileComponent{ + validComponents := []devfilev1.Component{ { Name: component, - Container: &versionsCommon.Container{ - Image: "image", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "image", + }, + }, }, }, } @@ -597,19 +621,23 @@ func TestExecTestCmd(t *testing.T) { tests := []struct { name string client *lclient.Client - testDevfileCommand versionsCommon.DevfileCommand + testDevfileCommand devfilev1.Command wantErr bool }{ { name: "Case 1: Successful execute test command", client: fakeClient, - testDevfileCommand: versionsCommon.DevfileCommand{ - Exec: &versionsCommon.Exec{ - CommandLine: command, - WorkingDir: workDir, - Component: component, - Group: &versionsCommon.Group{ - Kind: versionsCommon.TestCommandGroupType, + testDevfileCommand: devfilev1.Command{ + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: devfilev1.TestCommandGroupKind}, + }, + }, + CommandLine: command, + WorkingDir: workDir, + Component: component, }, }, }, @@ -618,13 +646,17 @@ func TestExecTestCmd(t *testing.T) { { name: "Case 2: No devfile test commands should result in an err", client: fakeClient, - testDevfileCommand: versionsCommon.DevfileCommand{ - Exec: &versionsCommon.Exec{ - CommandLine: command, - WorkingDir: workDir, - Component: component, - Group: &versionsCommon.Group{ - Kind: versionsCommon.BuildCommandGroupType, + testDevfileCommand: devfilev1.Command{ + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: devfilev1.BuildCommandGroupKind}, + }, + }, + CommandLine: command, + WorkingDir: workDir, + Component: component, }, }, }, @@ -633,13 +665,17 @@ func TestExecTestCmd(t *testing.T) { { name: "Case 3: Unsuccessful exec test command", client: fakeErrorClient, - testDevfileCommand: versionsCommon.DevfileCommand{ - Exec: &versionsCommon.Exec{ - CommandLine: command, - WorkingDir: workDir, - Component: component, - Group: &versionsCommon.Group{ - Kind: versionsCommon.TestCommandGroupType, + testDevfileCommand: devfilev1.Command{ + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: devfilev1.TestCommandGroupKind}, + }, + }, + CommandLine: command, + WorkingDir: workDir, + Component: component, }, }, }, @@ -714,7 +750,7 @@ func TestCreateProjectVolumeIfReqd(t *testing.T) { t.Run(tt.name, func(t *testing.T) { devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ - Components: []versionsCommon.DevfileComponent{}, + Components: []devfilev1.Component{}, }, } @@ -762,7 +798,7 @@ func TestStartBootstrapSupervisordInitContainer(t *testing.T) { t.Run(tt.name, func(t *testing.T) { devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ - Components: []versionsCommon.DevfileComponent{}, + Components: []devfilev1.Component{}, }, } @@ -808,7 +844,7 @@ func TestCreateAndInitSupervisordVolumeIfReqd(t *testing.T) { t.Run(tt.name, func(t *testing.T) { devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ - Components: []versionsCommon.DevfileComponent{}, + Components: []devfilev1.Component{}, }, } @@ -842,37 +878,45 @@ func TestUpdateComponentWithSupervisord(t *testing.T) { tests := []struct { name string - commandExecs []versionsCommon.DevfileCommand + commandExecs []devfilev1.Command commandName string - comp versionsCommon.DevfileComponent + comp devfilev1.Component supervisordVolumeName string hostConfig container.HostConfig wantHostConfig container.HostConfig wantCommand []string wantArgs []string - wantEnv []versionsCommon.Env + wantEnv []devfilev1.EnvVar }{ { name: "Case 1: No component commands, args, env", - commandExecs: []versionsCommon.DevfileCommand{ + commandExecs: []devfilev1.Command{ { - Exec: &versionsCommon.Exec{ - CommandLine: command, - Component: component, - Group: &versionsCommon.Group{ - Kind: versionsCommon.RunCommandGroupType, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: devfilev1.RunCommandGroupKind}, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, }, - WorkingDir: workDir, }, }, }, commandName: emptyString, - comp: versionsCommon.DevfileComponent{ + comp: devfilev1.Component{ Name: component, - Container: &versionsCommon.Container{ - Command: []string{}, - Args: []string{}, - Env: []versionsCommon.Env{}, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Command: []string{}, + Args: []string{}, + Env: []devfilev1.EnvVar{}, + }, + }, }, }, supervisordVolumeName: supervisordVolumeName, @@ -888,7 +932,7 @@ func TestUpdateComponentWithSupervisord(t *testing.T) { }, wantCommand: []string{adaptersCommon.SupervisordBinaryPath}, wantArgs: []string{"-c", adaptersCommon.SupervisordConfFile}, - wantEnv: []versionsCommon.Env{ + wantEnv: []devfilev1.EnvVar{ { Name: defaultWorkDirEnv, Value: workDir, @@ -901,25 +945,33 @@ func TestUpdateComponentWithSupervisord(t *testing.T) { }, { name: "Case 2: Existing component command and no args, env", - commandExecs: []versionsCommon.DevfileCommand{ + commandExecs: []devfilev1.Command{ { - Exec: &versionsCommon.Exec{ - CommandLine: command, - Component: component, - Group: &versionsCommon.Group{ - Kind: versionsCommon.RunCommandGroupType, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: devfilev1.RunCommandGroupKind}, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, }, - WorkingDir: workDir, }, }, }, commandName: emptyString, - comp: versionsCommon.DevfileComponent{ + comp: devfilev1.Component{ Name: component, - Container: &versionsCommon.Container{ - Command: []string{"some", "command"}, - Args: []string{}, - Env: []versionsCommon.Env{}, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Command: []string{"some", "command"}, + Args: []string{}, + Env: []devfilev1.EnvVar{}, + }, + }, }, }, supervisordVolumeName: supervisordVolumeName, @@ -935,7 +987,7 @@ func TestUpdateComponentWithSupervisord(t *testing.T) { }, wantCommand: []string{"some", "command"}, wantArgs: []string{}, - wantEnv: []versionsCommon.Env{ + wantEnv: []devfilev1.EnvVar{ { Name: defaultWorkDirEnv, Value: workDir, @@ -948,25 +1000,33 @@ func TestUpdateComponentWithSupervisord(t *testing.T) { }, { name: "Case 3: Existing component command and args and no env", - commandExecs: []versionsCommon.DevfileCommand{ + commandExecs: []devfilev1.Command{ { - Exec: &versionsCommon.Exec{ - CommandLine: command, - Component: component, - Group: &versionsCommon.Group{ - Kind: versionsCommon.RunCommandGroupType, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: devfilev1.RunCommandGroupKind}, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, }, - WorkingDir: workDir, }, }, }, commandName: emptyString, - comp: versionsCommon.DevfileComponent{ + comp: devfilev1.Component{ Name: component, - Container: &versionsCommon.Container{ - Command: []string{"some", "command"}, - Args: []string{"some", "args"}, - Env: []versionsCommon.Env{}, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Command: []string{"some", "command"}, + Args: []string{"some", "args"}, + Env: []devfilev1.EnvVar{}, + }, + }, }, }, supervisordVolumeName: supervisordVolumeName, @@ -982,7 +1042,7 @@ func TestUpdateComponentWithSupervisord(t *testing.T) { }, wantCommand: []string{"some", "command"}, wantArgs: []string{"some", "args"}, - wantEnv: []versionsCommon.Env{ + wantEnv: []devfilev1.EnvVar{ { Name: defaultWorkDirEnv, Value: workDir, @@ -995,32 +1055,40 @@ func TestUpdateComponentWithSupervisord(t *testing.T) { }, { name: "Case 4: Existing component command, args and env", - commandExecs: []versionsCommon.DevfileCommand{ + commandExecs: []devfilev1.Command{ { - Exec: &versionsCommon.Exec{ - CommandLine: command, - Component: component, - Group: &versionsCommon.Group{ - Kind: versionsCommon.RunCommandGroupType, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: devfilev1.RunCommandGroupKind}, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, }, - WorkingDir: workDir, }, }, }, commandName: emptyString, - comp: versionsCommon.DevfileComponent{ + comp: devfilev1.Component{ Name: component, - Container: &versionsCommon.Container{ - Command: []string{"some", "command"}, - Args: []string{"some", "args"}, - Env: []versionsCommon.Env{ - { - Name: defaultWorkDirEnv, - Value: garbageString, - }, - { - Name: defaultCommandEnv, - Value: garbageString, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Command: []string{"some", "command"}, + Args: []string{"some", "args"}, + Env: []devfilev1.EnvVar{ + { + Name: defaultWorkDirEnv, + Value: garbageString, + }, + { + Name: defaultCommandEnv, + Value: garbageString, + }, + }, }, }, }, @@ -1038,7 +1106,7 @@ func TestUpdateComponentWithSupervisord(t *testing.T) { }, wantCommand: []string{"some", "command"}, wantArgs: []string{"some", "args"}, - wantEnv: []versionsCommon.Env{ + wantEnv: []devfilev1.EnvVar{ { Name: defaultWorkDirEnv, Value: garbageString, @@ -1051,32 +1119,40 @@ func TestUpdateComponentWithSupervisord(t *testing.T) { }, { name: "Case 5: Existing host config, should append to it", - commandExecs: []versionsCommon.DevfileCommand{ + commandExecs: []devfilev1.Command{ { - Exec: &versionsCommon.Exec{ - CommandLine: command, - Component: component, - Group: &versionsCommon.Group{ - Kind: versionsCommon.RunCommandGroupType, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: devfilev1.RunCommandGroupKind}, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, }, - WorkingDir: workDir, }, }, }, commandName: emptyString, - comp: versionsCommon.DevfileComponent{ + comp: devfilev1.Component{ Name: component, - Container: &versionsCommon.Container{ - Command: []string{"some", "command"}, - Args: []string{"some", "args"}, - Env: []versionsCommon.Env{ - { - Name: defaultWorkDirEnv, - Value: garbageString, - }, - { - Name: defaultCommandEnv, - Value: garbageString, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Command: []string{"some", "command"}, + Args: []string{"some", "args"}, + Env: []devfilev1.EnvVar{ + { + Name: defaultWorkDirEnv, + Value: garbageString, + }, + { + Name: defaultCommandEnv, + Value: garbageString, + }, + }, }, }, }, @@ -1107,7 +1183,7 @@ func TestUpdateComponentWithSupervisord(t *testing.T) { }, wantCommand: []string{"some", "command"}, wantArgs: []string{"some", "args"}, - wantEnv: []versionsCommon.Env{ + wantEnv: []devfilev1.EnvVar{ { Name: defaultWorkDirEnv, Value: garbageString, @@ -1124,11 +1200,15 @@ func TestUpdateComponentWithSupervisord(t *testing.T) { devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ Commands: tt.commandExecs, - Components: []versionsCommon.DevfileComponent{ + Components: []devfilev1.Component{ { Name: tt.comp.Name, - Container: &versionsCommon.Container{ - Image: "image", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "image", + }, + }, }, }, }, diff --git a/pkg/devfile/adapters/docker/storage/adapter_test.go b/pkg/devfile/adapters/docker/storage/adapter_test.go index 65cdf7c53..b404801bd 100644 --- a/pkg/devfile/adapters/docker/storage/adapter_test.go +++ b/pkg/devfile/adapters/docker/storage/adapter_test.go @@ -3,10 +3,10 @@ package storage import ( "testing" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + devfileParser "github.com/devfile/library/pkg/devfile/parser" "github.com/openshift/odo/pkg/devfile/adapters/common" adaptersCommon "github.com/openshift/odo/pkg/devfile/adapters/common" - devfileParser "github.com/openshift/odo/pkg/devfile/parser" - versionsCommon "github.com/openshift/odo/pkg/devfile/parser/data/common" "github.com/openshift/odo/pkg/lclient" "github.com/openshift/odo/pkg/testingutil" ) @@ -79,7 +79,7 @@ func TestCreate(t *testing.T) { t.Run(tt.name, func(t *testing.T) { devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ - Components: []versionsCommon.DevfileComponent{}, + Components: []devfilev1.Component{}, }, } diff --git a/pkg/devfile/adapters/docker/utils/utils.go b/pkg/devfile/adapters/docker/utils/utils.go index da351be92..ef39450b3 100644 --- a/pkg/devfile/adapters/docker/utils/utils.go +++ b/pkg/devfile/adapters/docker/utils/utils.go @@ -11,9 +11,9 @@ import ( "github.com/docker/docker/api/types/mount" "github.com/openshift/odo/pkg/kclient/generator" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + "github.com/devfile/library/pkg/devfile/parser/data" adaptersCommon "github.com/openshift/odo/pkg/devfile/adapters/common" - "github.com/openshift/odo/pkg/devfile/parser/data" - "github.com/openshift/odo/pkg/devfile/parser/data/common" "github.com/openshift/odo/pkg/lclient" "github.com/openshift/odo/pkg/util" @@ -75,7 +75,7 @@ func GetContainerIDForAlias(containers []types.Container, alias string) string { } // ConvertEnvs converts environment variables from the devfile structure to an array of strings, as expected by Docker -func ConvertEnvs(vars []common.Env) []string { +func ConvertEnvs(vars []devfilev1.EnvVar) []string { dockerVars := []string{} for _, env := range vars { envString := fmt.Sprintf("%s=%s", env.Name, env.Value) @@ -85,7 +85,7 @@ func ConvertEnvs(vars []common.Env) []string { } // ConvertPorts converts endpoints from the devfile structure to PortSet, which is expected by Docker -func ConvertPorts(endpoints []common.Endpoint) nat.PortSet { +func ConvertPorts(endpoints []devfilev1.Endpoint) nat.PortSet { portSet := nat.PortSet{} for _, endpoint := range endpoints { port := nat.Port(strconv.Itoa(int(endpoint.TargetPort)) + "/tcp") @@ -99,7 +99,7 @@ func ConvertPorts(endpoints []common.Endpoint) nat.PortSet { // If any of the values between the two differ, a restart is required (and this function returns true) // Unlike Kube, Docker doesn't provide a mechanism to update a container in place only when necesary // so this function is necessary to prevent having to restart the container on every odo pushs -func DoesContainerNeedUpdating(component common.DevfileComponent, containerConfig *container.Config, hostConfig *container.HostConfig, devfileMounts []mount.Mount, containerMounts []types.MountPoint, portMap nat.PortMap) bool { +func DoesContainerNeedUpdating(component devfilev1.Component, containerConfig *container.Config, hostConfig *container.HostConfig, devfileMounts []mount.Mount, containerMounts []types.MountPoint, portMap nat.PortMap) bool { // If the image was changed in the devfile, the container needs to be updated if component.Container.Image != containerConfig.Image { return true diff --git a/pkg/devfile/adapters/docker/utils/utils_test.go b/pkg/devfile/adapters/docker/utils/utils_test.go index e9220005a..10d5017ec 100644 --- a/pkg/devfile/adapters/docker/utils/utils_test.go +++ b/pkg/devfile/adapters/docker/utils/utils_test.go @@ -7,12 +7,12 @@ import ( "github.com/docker/go-connections/nat" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + devfileParser "github.com/devfile/library/pkg/devfile/parser" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/mount" adaptersCommon "github.com/openshift/odo/pkg/devfile/adapters/common" - devfileParser "github.com/openshift/odo/pkg/devfile/parser" - "github.com/openshift/odo/pkg/devfile/parser/data/common" "github.com/openshift/odo/pkg/lclient" "github.com/openshift/odo/pkg/testingutil" "github.com/openshift/odo/pkg/util" @@ -26,7 +26,7 @@ func TestComponentExists(t *testing.T) { name string componentName string client *lclient.Client - components []common.DevfileComponent + components []devfilev1.Component want bool wantErr bool }{ @@ -34,7 +34,7 @@ func TestComponentExists(t *testing.T) { name: "Case 1: Component exists", componentName: "golang", client: fakeClient, - components: []common.DevfileComponent{ + components: []devfilev1.Component{ testingutil.GetFakeContainerComponent("alias1"), testingutil.GetFakeContainerComponent("alias2"), }, @@ -45,7 +45,7 @@ func TestComponentExists(t *testing.T) { name: "Case 2: Component doesn't exist", componentName: "fakecomponent", client: fakeClient, - components: []common.DevfileComponent{ + components: []devfilev1.Component{ testingutil.GetFakeContainerComponent("alias1"), }, want: false, @@ -55,7 +55,7 @@ func TestComponentExists(t *testing.T) { name: "Case 3: Error with docker client", componentName: "golang", client: fakeErrorClient, - components: []common.DevfileComponent{ + components: []devfilev1.Component{ testingutil.GetFakeContainerComponent("alias1"), }, want: false, @@ -65,7 +65,7 @@ func TestComponentExists(t *testing.T) { name: "Case 4: Container and devfile component mismatch", componentName: "test", client: fakeClient, - components: []common.DevfileComponent{}, + components: []devfilev1.Component{}, want: true, wantErr: true, }, @@ -73,9 +73,11 @@ func TestComponentExists(t *testing.T) { name: "Case 5: Devfile does not have supported components", componentName: "abc", client: fakeClient, - components: []common.DevfileComponent{ + components: []devfilev1.Component{ { - Kubernetes: &common.Kubernetes{}, + ComponentUnion: devfilev1.ComponentUnion{ + Kubernetes: &devfilev1.KubernetesComponent{}, + }, }, }, want: false, @@ -175,12 +177,12 @@ func TestConvertEnvs(t *testing.T) { envVarsValues := []string{"value1", "value2", "value3"} tests := []struct { name string - envVars []common.Env + envVars []devfilev1.EnvVar want []string }{ { name: "Case 1: One env var", - envVars: []common.Env{ + envVars: []devfilev1.EnvVar{ { Name: envVarsNames[0], Value: envVarsValues[0], @@ -190,7 +192,7 @@ func TestConvertEnvs(t *testing.T) { }, { name: "Case 2: Multiple env vars", - envVars: []common.Env{ + envVars: []devfilev1.EnvVar{ { Name: envVarsNames[0], Value: envVarsValues[0], @@ -208,7 +210,7 @@ func TestConvertEnvs(t *testing.T) { }, { name: "Case 3: No env vars", - envVars: []common.Env{}, + envVars: []devfilev1.EnvVar{}, want: []string{}, }, } @@ -232,7 +234,7 @@ func TestDoesContainerNeedUpdating(t *testing.T) { tests := []struct { name string - envVars []common.Env + envVars []devfilev1.EnvVar mounts []mount.Mount image string containerConfig container.Config @@ -243,7 +245,7 @@ func TestDoesContainerNeedUpdating(t *testing.T) { }{ { name: "Case 1: No changes", - envVars: []common.Env{ + envVars: []devfilev1.EnvVar{ { Name: envVarsNames[0], Value: envVarsValues[0], @@ -274,7 +276,7 @@ func TestDoesContainerNeedUpdating(t *testing.T) { }, { name: "Case 2: Update required, env var changed", - envVars: []common.Env{ + envVars: []devfilev1.EnvVar{ { Name: envVarsNames[2], Value: envVarsValues[2], @@ -289,7 +291,7 @@ func TestDoesContainerNeedUpdating(t *testing.T) { }, { name: "Case 3: Update required, image changed", - envVars: []common.Env{ + envVars: []devfilev1.EnvVar{ { Name: envVarsNames[2], Value: envVarsValues[2], @@ -304,7 +306,7 @@ func TestDoesContainerNeedUpdating(t *testing.T) { }, { name: "Case 4: Update required, volumes changed", - envVars: []common.Env{ + envVars: []devfilev1.EnvVar{ { Name: envVarsNames[0], Value: envVarsValues[0], @@ -339,7 +341,7 @@ func TestDoesContainerNeedUpdating(t *testing.T) { }, { name: "Case 5: Update required, port changed", - envVars: []common.Env{ + envVars: []devfilev1.EnvVar{ { Name: envVarsNames[0], Value: envVarsValues[0], @@ -377,7 +379,7 @@ func TestDoesContainerNeedUpdating(t *testing.T) { }, { name: "Case 6: Update required, exposed port changed", - envVars: []common.Env{ + envVars: []devfilev1.EnvVar{ { Name: envVarsNames[0], Value: envVarsValues[0], @@ -433,7 +435,7 @@ func TestDoesContainerNeedUpdating(t *testing.T) { }, { name: "Case 7: Update not required, exposed port unchanged", - envVars: []common.Env{ + envVars: []devfilev1.EnvVar{ { Name: envVarsNames[0], Value: envVarsValues[0], @@ -491,10 +493,14 @@ func TestDoesContainerNeedUpdating(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - component := common.DevfileComponent{ - Container: &common.Container{ - Image: tt.image, - Env: tt.envVars, + component := devfilev1.Component{ + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: tt.image, + Env: tt.envVars, + }, + }, }, } needsUpdating := DoesContainerNeedUpdating(component, &tt.containerConfig, &tt.hostConfig, tt.mounts, tt.containerMounts, tt.portmap) diff --git a/pkg/devfile/adapters/helper.go b/pkg/devfile/adapters/helper.go index 300a69639..af8fd5f87 100644 --- a/pkg/devfile/adapters/helper.go +++ b/pkg/devfile/adapters/helper.go @@ -3,10 +3,10 @@ package adapters import ( "fmt" + devfileParser "github.com/devfile/library/pkg/devfile/parser" "github.com/openshift/odo/pkg/devfile/adapters/common" "github.com/openshift/odo/pkg/devfile/adapters/docker" "github.com/openshift/odo/pkg/devfile/adapters/kubernetes" - devfileParser "github.com/openshift/odo/pkg/devfile/parser" "github.com/openshift/odo/pkg/kclient" "github.com/openshift/odo/pkg/lclient" "github.com/openshift/odo/pkg/odo/util/pushtarget" diff --git a/pkg/devfile/adapters/helper_test.go b/pkg/devfile/adapters/helper_test.go index 6a0dc6593..13bf8cf85 100644 --- a/pkg/devfile/adapters/helper_test.go +++ b/pkg/devfile/adapters/helper_test.go @@ -4,9 +4,9 @@ import ( "reflect" "testing" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + devfileParser "github.com/devfile/library/pkg/devfile/parser" adaptersCommon "github.com/openshift/odo/pkg/devfile/adapters/common" - devfileParser "github.com/openshift/odo/pkg/devfile/parser" - versionsCommon "github.com/openshift/odo/pkg/devfile/parser/data/common" "github.com/openshift/odo/pkg/kclient" "github.com/openshift/odo/pkg/testingutil" ) @@ -16,14 +16,14 @@ func TestNewPlatformAdapter(t *testing.T) { adapterType string name string componentName string - componentType versionsCommon.DevfileComponentType + componentType devfilev1.ComponentType wantErr bool }{ { adapterType: "kubernetes.Adapter", name: "get platform adapter", componentName: "test", - componentType: versionsCommon.ContainerComponentType, + componentType: devfilev1.ContainerComponentType, wantErr: false, }, } @@ -31,7 +31,7 @@ func TestNewPlatformAdapter(t *testing.T) { t.Run("get platform adapter", func(t *testing.T) { devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ - Components: []versionsCommon.DevfileComponent{}, + Components: []devfilev1.Component{}, }, } diff --git a/pkg/devfile/adapters/kubernetes/adapter.go b/pkg/devfile/adapters/kubernetes/adapter.go index 5cbffaa4b..f1a7f5385 100644 --- a/pkg/devfile/adapters/kubernetes/adapter.go +++ b/pkg/devfile/adapters/kubernetes/adapter.go @@ -1,10 +1,11 @@ package kubernetes import ( - versionsCommon "github.com/openshift/odo/pkg/devfile/parser/data/common" - "github.com/openshift/odo/pkg/machineoutput" "io" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + "github.com/openshift/odo/pkg/machineoutput" + "github.com/openshift/odo/pkg/devfile/adapters/common" "github.com/openshift/odo/pkg/devfile/adapters/kubernetes/component" "github.com/openshift/odo/pkg/kclient" @@ -79,11 +80,11 @@ func (k Adapter) Logger() machineoutput.MachineEventLoggingClient { return k.componentAdapter.Logger() } -func (k Adapter) ComponentInfo(command versionsCommon.DevfileCommand) (common.ComponentInfo, error) { +func (k Adapter) ComponentInfo(command devfilev1.Command) (common.ComponentInfo, error) { return k.componentAdapter.ComponentInfo(command) } -func (k Adapter) SupervisorComponentInfo(command versionsCommon.DevfileCommand) (common.ComponentInfo, error) { +func (k Adapter) SupervisorComponentInfo(command devfilev1.Command) (common.ComponentInfo, error) { return k.componentAdapter.SupervisorComponentInfo(command) } diff --git a/pkg/devfile/adapters/kubernetes/component/adapter.go b/pkg/devfile/adapters/kubernetes/component/adapter.go index 38e33b1f3..cef84b199 100644 --- a/pkg/devfile/adapters/kubernetes/component/adapter.go +++ b/pkg/devfile/adapters/kubernetes/component/adapter.go @@ -18,12 +18,12 @@ import ( "github.com/pkg/errors" "k8s.io/klog" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" "github.com/openshift/odo/pkg/component" "github.com/openshift/odo/pkg/config" "github.com/openshift/odo/pkg/devfile/adapters/common" "github.com/openshift/odo/pkg/devfile/adapters/kubernetes/storage" "github.com/openshift/odo/pkg/devfile/adapters/kubernetes/utils" - versionsCommon "github.com/openshift/odo/pkg/devfile/parser/data/common" "github.com/openshift/odo/pkg/kclient" "github.com/openshift/odo/pkg/log" odoutil "github.com/openshift/odo/pkg/odo/util" @@ -58,7 +58,7 @@ func (a Adapter) getPod(refresh bool) (*corev1.Pod, error) { return a.pod, nil } -func (a Adapter) ComponentInfo(command versionsCommon.DevfileCommand) (common.ComponentInfo, error) { +func (a Adapter) ComponentInfo(command devfilev1.Command) (common.ComponentInfo, error) { pod, err := a.getPod(false) if err != nil { return common.ComponentInfo{}, err @@ -69,7 +69,7 @@ func (a Adapter) ComponentInfo(command versionsCommon.DevfileCommand) (common.Co }, nil } -func (a Adapter) SupervisorComponentInfo(command versionsCommon.DevfileCommand) (common.ComponentInfo, error) { +func (a Adapter) SupervisorComponentInfo(command devfilev1.Command) (common.ComponentInfo, error) { pod, err := a.getPod(false) if err != nil { return common.ComponentInfo{}, err @@ -152,7 +152,7 @@ func (a Adapter) Push(parameters common.PushParameters) (err error) { if err != nil { return fmt.Errorf("debug command is not valid") } - pushDevfileCommands[versionsCommon.DebugCommandGroupType] = pushDevfileDebugCommands + pushDevfileCommands[devfilev1.DebugCommandGroupKind] = pushDevfileDebugCommands currentMode = envinfo.Debug } @@ -529,13 +529,13 @@ func (a Adapter) Log(follow, debug bool) (io.ReadCloser, error) { return nil, errors.Errorf("unable to show logs, component is not in running state. current status=%v", pod.Status.Phase) } - var command versionsCommon.DevfileCommand + var command devfilev1.Command if debug { command, err = common.GetDebugCommand(a.Devfile.Data, "") if err != nil { return nil, err } - if reflect.DeepEqual(versionsCommon.DevfileCommand{}, command) { + if reflect.DeepEqual(devfilev1.Command{}, command) { return nil, errors.Errorf("no debug command found in devfile, please run \"odo log\" for run command logs") } diff --git a/pkg/devfile/adapters/kubernetes/component/adapter_test.go b/pkg/devfile/adapters/kubernetes/component/adapter_test.go index 4fef68c09..5e1d25285 100644 --- a/pkg/devfile/adapters/kubernetes/component/adapter_test.go +++ b/pkg/devfile/adapters/kubernetes/component/adapter_test.go @@ -8,10 +8,9 @@ import ( "github.com/openshift/odo/pkg/util" "github.com/pkg/errors" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + devfileParser "github.com/devfile/library/pkg/devfile/parser" adaptersCommon "github.com/openshift/odo/pkg/devfile/adapters/common" - devfileParser "github.com/openshift/odo/pkg/devfile/parser" - "github.com/openshift/odo/pkg/devfile/parser/data/common" - versionsCommon "github.com/openshift/odo/pkg/devfile/parser/data/common" "github.com/openshift/odo/pkg/kclient" "github.com/openshift/odo/pkg/testingutil" @@ -40,7 +39,7 @@ func TestCreateOrUpdateComponent(t *testing.T) { tests := []struct { name string - componentType versionsCommon.DevfileComponentType + componentType devfilev1.ComponentType envInfo envinfo.EnvSpecificInfo running bool wantErr bool @@ -54,7 +53,7 @@ func TestCreateOrUpdateComponent(t *testing.T) { }, { name: "Case 2: Valid devfile", - componentType: versionsCommon.ContainerComponentType, + componentType: devfilev1.ContainerComponentType, envInfo: envinfo.EnvSpecificInfo{}, running: false, wantErr: false, @@ -68,7 +67,7 @@ func TestCreateOrUpdateComponent(t *testing.T) { }, { name: "Case 4: Valid devfile, already running component", - componentType: versionsCommon.ContainerComponentType, + componentType: devfilev1.ContainerComponentType, envInfo: envinfo.EnvSpecificInfo{}, running: true, wantErr: false, @@ -76,14 +75,14 @@ func TestCreateOrUpdateComponent(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - var comp versionsCommon.DevfileComponent + var comp devfilev1.Component if tt.componentType != "" { comp = testingutil.GetFakeContainerComponent("component") } devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ - Components: []versionsCommon.DevfileComponent{comp}, - Commands: []versionsCommon.DevfileCommand{getExecCommand("run", versionsCommon.RunCommandGroupType)}, + Components: []devfilev1.Component{comp}, + Commands: []devfilev1.Command{getExecCommand("run", devfilev1.RunCommandGroupKind)}, }, } @@ -224,7 +223,7 @@ func TestDoesComponentExist(t *testing.T) { tests := []struct { name string - componentType versionsCommon.DevfileComponentType + componentType devfilev1.ComponentType componentName string getComponentName string envInfo envinfo.EnvSpecificInfo @@ -260,8 +259,8 @@ func TestDoesComponentExist(t *testing.T) { t.Run(tt.name, func(t *testing.T) { devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ - Components: []versionsCommon.DevfileComponent{testingutil.GetFakeContainerComponent("component")}, - Commands: []versionsCommon.DevfileCommand{getExecCommand("run", versionsCommon.RunCommandGroupType)}, + Components: []devfilev1.Component{testingutil.GetFakeContainerComponent("component")}, + Commands: []devfilev1.Command{getExecCommand("run", devfilev1.RunCommandGroupKind)}, }, } @@ -318,7 +317,7 @@ func TestWaitAndGetComponentPod(t *testing.T) { tests := []struct { name string - componentType versionsCommon.DevfileComponentType + componentType devfilev1.ComponentType status corev1.PodPhase wantErr bool }{ @@ -342,7 +341,7 @@ func TestWaitAndGetComponentPod(t *testing.T) { t.Run(tt.name, func(t *testing.T) { devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ - Components: []versionsCommon.DevfileComponent{testingutil.GetFakeContainerComponent("component")}, + Components: []devfilev1.Component{testingutil.GetFakeContainerComponent("component")}, }, } @@ -507,19 +506,25 @@ func TestAdapterDelete(t *testing.T) { } } -func getExecCommand(id string, group common.DevfileCommandGroupType) versionsCommon.DevfileCommand { +func getExecCommand(id string, group devfilev1.CommandGroupKind) devfilev1.Command { commands := [...]string{"ls -la", "pwd"} component := "component" workDir := [...]string{"/", "/root"} - return versionsCommon.DevfileCommand{ + return devfilev1.Command{ Id: id, - Exec: &common.Exec{ - CommandLine: commands[0], - Component: component, - WorkingDir: workDir[0], - Group: &common.Group{Kind: group}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: group}, + }, + }, + CommandLine: commands[0], + Component: component, + WorkingDir: workDir[0], + }, }, } diff --git a/pkg/devfile/adapters/kubernetes/component/podwatcher_test.go b/pkg/devfile/adapters/kubernetes/component/podwatcher_test.go index d9a60a4ae..fb8ff15c8 100644 --- a/pkg/devfile/adapters/kubernetes/component/podwatcher_test.go +++ b/pkg/devfile/adapters/kubernetes/component/podwatcher_test.go @@ -7,8 +7,8 @@ import ( "testing" "time" + devfileParser "github.com/devfile/library/pkg/devfile/parser" adaptersCommon "github.com/openshift/odo/pkg/devfile/adapters/common" - devfileParser "github.com/openshift/odo/pkg/devfile/parser" "github.com/openshift/odo/pkg/kclient" "github.com/openshift/odo/pkg/machineoutput" "github.com/openshift/odo/pkg/testingutil" diff --git a/pkg/devfile/adapters/kubernetes/component/status_test.go b/pkg/devfile/adapters/kubernetes/component/status_test.go index d144e65d5..d7b853d65 100644 --- a/pkg/devfile/adapters/kubernetes/component/status_test.go +++ b/pkg/devfile/adapters/kubernetes/component/status_test.go @@ -5,9 +5,9 @@ import ( "github.com/openshift/odo/pkg/envinfo" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + devfileParser "github.com/devfile/library/pkg/devfile/parser" adaptersCommon "github.com/openshift/odo/pkg/devfile/adapters/common" - devfileParser "github.com/openshift/odo/pkg/devfile/parser" - versionsCommon "github.com/openshift/odo/pkg/devfile/parser/data/common" "github.com/openshift/odo/pkg/kclient" "github.com/openshift/odo/pkg/testingutil" @@ -163,9 +163,9 @@ func TestGetDeploymentStatus(t *testing.T) { comp := testingutil.GetFakeContainerComponent(testComponentName) devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ - Components: []versionsCommon.DevfileComponent{comp}, - Commands: []versionsCommon.DevfileCommand{ - getExecCommand("run", versionsCommon.RunCommandGroupType), + Components: []devfilev1.Component{comp}, + Commands: []devfilev1.Command{ + getExecCommand("run", devfilev1.RunCommandGroupKind), }, }, } diff --git a/pkg/devfile/adapters/kubernetes/storage/utils_test.go b/pkg/devfile/adapters/kubernetes/storage/utils_test.go index 233ee1f16..02e87546e 100644 --- a/pkg/devfile/adapters/kubernetes/storage/utils_test.go +++ b/pkg/devfile/adapters/kubernetes/storage/utils_test.go @@ -2,10 +2,11 @@ package storage import ( "fmt" - v1 "k8s.io/api/core/v1" "reflect" "testing" + v1 "k8s.io/api/core/v1" + "github.com/openshift/odo/pkg/devfile/adapters/common" "github.com/openshift/odo/pkg/kclient" "github.com/openshift/odo/pkg/testingutil" diff --git a/pkg/devfile/adapters/kubernetes/utils/utils.go b/pkg/devfile/adapters/kubernetes/utils/utils.go index 9ed8b6330..6647b94f3 100644 --- a/pkg/devfile/adapters/kubernetes/utils/utils.go +++ b/pkg/devfile/adapters/kubernetes/utils/utils.go @@ -5,8 +5,9 @@ import ( "strconv" "strings" + devfileParser "github.com/devfile/library/pkg/devfile/parser" + parsercommon "github.com/devfile/library/pkg/devfile/parser/data/v2/common" adaptersCommon "github.com/openshift/odo/pkg/devfile/adapters/common" - devfileParser "github.com/openshift/odo/pkg/devfile/parser" "github.com/openshift/odo/pkg/envinfo" "github.com/openshift/odo/pkg/kclient" "github.com/openshift/odo/pkg/log" @@ -270,9 +271,9 @@ func GetPreStartInitContainers(devfile devfileParser.DevfileObj, containers []co for i, commandName := range eventCommands { if command, ok := commandsMap[commandName]; ok { - component := command.GetExecComponent() - commandLine := command.GetExecCommandLine() - workingDir := command.GetExecWorkingDir() + component := parsercommon.GetExecComponent(command) + commandLine := parsercommon.GetExecCommandLine(command) + workingDir := parsercommon.GetExecWorkingDir(command) var cmdArr []string if workingDir != "" { diff --git a/pkg/devfile/adapters/kubernetes/utils/utils_test.go b/pkg/devfile/adapters/kubernetes/utils/utils_test.go index 76f059630..95bbe156b 100644 --- a/pkg/devfile/adapters/kubernetes/utils/utils_test.go +++ b/pkg/devfile/adapters/kubernetes/utils/utils_test.go @@ -6,10 +6,9 @@ import ( "strings" "testing" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + devfileParser "github.com/devfile/library/pkg/devfile/parser" adaptersCommon "github.com/openshift/odo/pkg/devfile/adapters/common" - devfileParser "github.com/openshift/odo/pkg/devfile/parser" - "github.com/openshift/odo/pkg/devfile/parser/data/common" - versionsCommon "github.com/openshift/odo/pkg/devfile/parser/data/common" "github.com/openshift/odo/pkg/kclient" "github.com/openshift/odo/pkg/testingutil" "github.com/openshift/odo/pkg/util" @@ -26,7 +25,7 @@ func TestComponentExists(t *testing.T) { tests := []struct { name string - componentType versionsCommon.DevfileComponentType + componentType devfilev1.ComponentType componentName string getComponentName string want bool @@ -167,13 +166,13 @@ func TestUpdateContainersWithSupervisord(t *testing.T) { workDir := "/root" emptyString := "" defaultCommand := []string{"tail"} - execRunGroup := versionsCommon.Group{ + execRunGroup := devfilev1.CommandGroup{ IsDefault: true, - Kind: versionsCommon.RunCommandGroupType, + Kind: devfilev1.RunCommandGroupKind, } - execDebugGroup := versionsCommon.Group{ + execDebugGroup := devfilev1.CommandGroup{ IsDefault: true, - Kind: versionsCommon.DebugCommandGroupType, + Kind: devfilev1.DebugCommandGroupKind, } defaultArgs := []string{"-f", "/dev/null"} supervisordCommand := []string{adaptersCommon.SupervisordBinaryPath} @@ -185,8 +184,8 @@ func TestUpdateContainersWithSupervisord(t *testing.T) { debugCommand string debugPort int containers []corev1.Container - execCommands []common.DevfileCommand - componentType common.DevfileComponentType + execCommands []devfilev1.Command + componentType devfilev1.ComponentType expectRunCommand string expectDebugCommand string isSupervisordEntrypoint bool @@ -205,17 +204,23 @@ func TestUpdateContainersWithSupervisord(t *testing.T) { Env: []corev1.EnvVar{}, }, }, - execCommands: []versionsCommon.DevfileCommand{ + execCommands: []devfilev1.Command{ { - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &execRunGroup, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &execRunGroup, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, + }, }, }, }, - componentType: common.ContainerComponentType, + componentType: devfilev1.ContainerComponentType, expectRunCommand: command, isSupervisordEntrypoint: false, wantErr: false, @@ -233,16 +238,22 @@ func TestUpdateContainersWithSupervisord(t *testing.T) { Env: []corev1.EnvVar{}, }, }, - execCommands: []versionsCommon.DevfileCommand{ + execCommands: []devfilev1.Command{ { - Exec: &common.Exec{ - CommandLine: command, - Component: component, - Group: &execRunGroup, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &execRunGroup, + }, + }, + CommandLine: command, + Component: component, + }, }, }, }, - componentType: common.ContainerComponentType, + componentType: devfilev1.ContainerComponentType, expectRunCommand: command, isSupervisordEntrypoint: false, wantErr: false, @@ -258,17 +269,23 @@ func TestUpdateContainersWithSupervisord(t *testing.T) { Env: []corev1.EnvVar{}, }, }, - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &execRunGroup, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &execRunGroup, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, + }, }, }, }, - componentType: common.ContainerComponentType, + componentType: devfilev1.ContainerComponentType, expectRunCommand: command, isSupervisordEntrypoint: true, wantErr: false, @@ -284,18 +301,24 @@ func TestUpdateContainersWithSupervisord(t *testing.T) { Env: []corev1.EnvVar{}, }, }, - execCommands: []versionsCommon.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "customcommand", - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &execRunGroup, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &execRunGroup, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, + }, }, }, }, - componentType: common.ContainerComponentType, + componentType: devfilev1.ContainerComponentType, expectRunCommand: command, isSupervisordEntrypoint: true, wantErr: false, @@ -311,17 +334,23 @@ func TestUpdateContainersWithSupervisord(t *testing.T) { Env: []corev1.EnvVar{}, }, }, - execCommands: []versionsCommon.DevfileCommand{ + execCommands: []devfilev1.Command{ { - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &execRunGroup, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &execRunGroup, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, + }, }, }, }, - componentType: common.ContainerComponentType, + componentType: devfilev1.ContainerComponentType, expectRunCommand: command, isSupervisordEntrypoint: true, wantErr: true, @@ -346,26 +375,38 @@ func TestUpdateContainersWithSupervisord(t *testing.T) { Env: []corev1.EnvVar{}, }, }, - execCommands: []versionsCommon.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "customruncommand", - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &execRunGroup, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &execRunGroup, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, + }, }, }, { - Exec: &common.Exec{ - CommandLine: debugCommand, - Component: debugComponent, - WorkingDir: workDir, - Group: &execDebugGroup, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &execDebugGroup, + }, + }, + CommandLine: debugCommand, + Component: debugComponent, + WorkingDir: workDir, + }, }, }, }, - componentType: common.ContainerComponentType, + componentType: devfilev1.ContainerComponentType, expectDebugCommand: debugCommand, expectRunCommand: command, isSupervisordEntrypoint: true, @@ -384,26 +425,38 @@ func TestUpdateContainersWithSupervisord(t *testing.T) { Env: []corev1.EnvVar{}, }, }, - execCommands: []versionsCommon.DevfileCommand{ + execCommands: []devfilev1.Command{ { - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &execRunGroup, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &execRunGroup, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, + }, }, }, { Id: "customdebugcommand", - Exec: &common.Exec{ - CommandLine: debugCommand, - Component: component, - WorkingDir: workDir, - Group: &execDebugGroup, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &execDebugGroup, + }, + }, + CommandLine: debugCommand, + Component: component, + WorkingDir: workDir, + }, }, }, }, - componentType: common.ContainerComponentType, + componentType: devfilev1.ContainerComponentType, expectDebugCommand: debugCommand, expectRunCommand: command, isSupervisordEntrypoint: true, @@ -428,30 +481,42 @@ func TestUpdateContainersWithSupervisord(t *testing.T) { Env: []corev1.EnvVar{}, }, }, - execCommands: []versionsCommon.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "run", - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &execRunGroup, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &execRunGroup, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, + }, }, }, { Id: "debug", - Exec: &common.Exec{ - CommandLine: debugCommand, - Component: debugComponent, - WorkingDir: workDir, - Group: &versionsCommon.Group{ - IsDefault: true, - Kind: versionsCommon.BuildCommandGroupType, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{ + IsDefault: true, + Kind: devfilev1.BuildCommandGroupKind, + }, + }, + }, + CommandLine: debugCommand, + Component: debugComponent, + WorkingDir: workDir, }, }, }, }, - componentType: common.ContainerComponentType, + componentType: devfilev1.ContainerComponentType, expectDebugCommand: debugCommand, expectRunCommand: command, isSupervisordEntrypoint: true, @@ -468,24 +533,30 @@ func TestUpdateContainersWithSupervisord(t *testing.T) { Env: []corev1.EnvVar{}, }, }, - execCommands: []versionsCommon.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "customruncommand", - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &execRunGroup, - Env: []versionsCommon.Env{ - { - Name: "env1", - Value: "value1", + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &execRunGroup, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, + Env: []devfilev1.EnvVar{ + { + Name: "env1", + Value: "value1", + }, }, }, }, }, }, - componentType: common.ContainerComponentType, + componentType: devfilev1.ContainerComponentType, expectRunCommand: "env1=\"value1\" && " + command, isSupervisordEntrypoint: true, wantErr: false, @@ -501,28 +572,34 @@ func TestUpdateContainersWithSupervisord(t *testing.T) { Env: []corev1.EnvVar{}, }, }, - execCommands: []versionsCommon.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "customruncommand", - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &execRunGroup, - Env: []versionsCommon.Env{ - { - Name: "env1", - Value: "value1", + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &execRunGroup, + }, }, - { - Name: "env2", - Value: "value2 with space", + CommandLine: command, + Component: component, + WorkingDir: workDir, + Env: []devfilev1.EnvVar{ + { + Name: "env1", + Value: "value1", + }, + { + Name: "env2", + Value: "value2 with space", + }, }, }, }, }, }, - componentType: common.ContainerComponentType, + componentType: devfilev1.ContainerComponentType, expectRunCommand: "env1=\"value1\" env2=\"value2 with space\" && " + command, isSupervisordEntrypoint: true, wantErr: false, @@ -540,32 +617,44 @@ func TestUpdateContainersWithSupervisord(t *testing.T) { Env: []corev1.EnvVar{}, }, }, - execCommands: []versionsCommon.DevfileCommand{ + execCommands: []devfilev1.Command{ { - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &execRunGroup, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &execRunGroup, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, + }, }, }, { Id: "customdebugcommand", - Exec: &common.Exec{ - CommandLine: debugCommand, - Component: component, - WorkingDir: workDir, - Group: &execDebugGroup, - Env: []versionsCommon.Env{ - { - Name: "env1", - Value: "value1", + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &execDebugGroup, + }, + }, + CommandLine: debugCommand, + Component: component, + WorkingDir: workDir, + Env: []devfilev1.EnvVar{ + { + Name: "env1", + Value: "value1", + }, }, }, }, }, }, - componentType: common.ContainerComponentType, + componentType: devfilev1.ContainerComponentType, expectDebugCommand: "env1=\"value1\" && " + debugCommand, expectRunCommand: command, isSupervisordEntrypoint: true, @@ -584,36 +673,48 @@ func TestUpdateContainersWithSupervisord(t *testing.T) { Env: []corev1.EnvVar{}, }, }, - execCommands: []versionsCommon.DevfileCommand{ + execCommands: []devfilev1.Command{ { - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &execRunGroup, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &execRunGroup, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, + }, }, }, { Id: "customdebugcommand", - Exec: &common.Exec{ - CommandLine: debugCommand, - Component: component, - WorkingDir: workDir, - Group: &execDebugGroup, - Env: []versionsCommon.Env{ - { - Name: "env1", - Value: "value1", + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &execDebugGroup, + }, }, - { - Name: "env2", - Value: "value2 with space", + CommandLine: debugCommand, + Component: component, + WorkingDir: workDir, + Env: []devfilev1.EnvVar{ + { + Name: "env1", + Value: "value1", + }, + { + Name: "env2", + Value: "value2 with space", + }, }, }, }, }, }, - componentType: common.ContainerComponentType, + componentType: devfilev1.ContainerComponentType, expectDebugCommand: "env1=\"value1\" env2=\"value2 with space\" && " + debugCommand, expectRunCommand: command, isSupervisordEntrypoint: true, @@ -624,17 +725,26 @@ func TestUpdateContainersWithSupervisord(t *testing.T) { t.Run(tt.name, func(t *testing.T) { devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ - Components: []versionsCommon.DevfileComponent{ + Components: []devfilev1.Component{ { Name: component, - Container: &versionsCommon.Container{ - SourceMapping: "", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + SourceMapping: "", + }, + }, }, }, { Name: debugComponent, - Container: &versionsCommon.Container{ - SourceMapping: ""}, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + SourceMapping: "", + }, + }, + }, }, }, Commands: tt.execCommands, @@ -737,40 +847,48 @@ func TestGetPreStartInitContainers(t *testing.T) { testingutil.CreateFakeContainer("container2"), } - execCommands := []versionsCommon.DevfileCommand{ + execCommands := []devfilev1.Command{ { Id: "exec1", - Exec: &versionsCommon.Exec{ - CommandLine: "execcommand1", - WorkingDir: "execworkdir1", - Component: "container1", + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + CommandLine: "execcommand1", + WorkingDir: "execworkdir1", + Component: "container1", + }, }, }, { Id: "exec2", - Exec: &versionsCommon.Exec{ - CommandLine: "execcommand2", - WorkingDir: "", - Component: "container1", + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + CommandLine: "execcommand2", + WorkingDir: "", + Component: "container1", + }, }, }, { Id: "exec3", - Exec: &versionsCommon.Exec{ - CommandLine: "execcommand3", - WorkingDir: "execworkdir3", - Component: "container2", + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + CommandLine: "execcommand3", + WorkingDir: "execworkdir3", + Component: "container2", + }, }, }, } - compCommands := []versionsCommon.DevfileCommand{ + compCommands := []devfilev1.Command{ { Id: "comp1", - Composite: &versionsCommon.Composite{ - Commands: []string{ - "exec1", - "exec3", + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{ + Commands: []string{ + "exec1", + "exec3", + }, }, }, }, @@ -828,8 +946,10 @@ func TestGetPreStartInitContainers(t *testing.T) { devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ Commands: append(execCommands, compCommands...), - Events: common.DevfileEvents{ - PreStart: tt.eventCommands, + Events: devfilev1.Events{ + WorkspaceEvents: devfilev1.WorkspaceEvents{ + PreStart: tt.eventCommands, + }, }, }, } diff --git a/pkg/devfile/parser/configurables.go b/pkg/devfile/parser/configurables.go deleted file mode 100644 index 3b3e143dd..000000000 --- a/pkg/devfile/parser/configurables.go +++ /dev/null @@ -1,254 +0,0 @@ -package parser - -import ( - "fmt" - "strings" - - "github.com/openshift/odo/pkg/config" - "github.com/openshift/odo/pkg/devfile/parser/data/common" - "github.com/openshift/odo/pkg/util" - "github.com/pkg/errors" -) - -// This file contains all the parameters that can be change via odo config - -const ( - Name = "Name" - Ports = "Ports" - Memory = "Memory" - PortsDescription = "Ports to be opened in all component containers" - MemoryDescription = "The Maximum memory all the component containers can consume" - NameDescription = "The name of the component" -) - -var ( - supportedDevfileParameterDescriptions = map[string]string{ - Name: NameDescription, - Ports: PortsDescription, - Memory: MemoryDescription, - } - - lowerCaseDevfileParameters = util.GetLowerCaseParameters(GetDevfileSupportedParameters()) -) - -// SetConfiguration allows setting all the parameters that are configurable in a devfile -func (d DevfileObj) SetConfiguration(parameter string, value interface{}) error { - - // we are ignoring this error because a developer is usually aware of the type of value that is - // being passed. So consider this a shortcut, if you know its a string value use this strValue - // else parse it inside the switch case. - strValue, _ := value.(string) - if parameter, ok := AsDevfileSupportedParameter(parameter); ok { - switch parameter { - case "name": - return d.setMetadataName(strValue) - case "ports": - arrValue := strings.Split(strValue, ",") - return d.setPorts(arrValue...) - case "memory": - return d.setMemory(strValue) - } - - } - return errors.Errorf("unknown parameter :'%s' is not a configurable parameter in the devfile", parameter) - -} - -// DeleteConfiguration allows deleting the parameters that are configurable in a devfile -func (d DevfileObj) DeleteConfiguration(parameter string) error { - if parameter, ok := AsDevfileSupportedParameter(parameter); ok { - switch parameter { - case "name": - return d.setMetadataName("") - case "ports": - return d.removePorts() - case "memory": - return d.setMemory("") - } - } - return errors.Errorf("unknown parameter :'%s' is not a configurable parameter in the devfile", parameter) -} - -// IsSet checks if a parameter is set in the devfile -func (d DevfileObj) IsSet(parameter string) bool { - - if parameter, ok := AsDevfileSupportedParameter(parameter); ok { - switch parameter { - case "name": - return d.GetMetadataName() != "" - case "ports": - return d.hasPorts() - case "memory": - return d.GetMemory() != "" - } - } - return false - -} - -func (d DevfileObj) setMetadataName(name string) error { - metadata := d.Data.GetMetadata() - d.Data.SetMetadata(name, metadata.Version) - return d.WriteYamlDevfile() -} - -// AddEnvVars adds environment variables to all the components in a devfile -func (d DevfileObj) AddEnvVars(otherList config.EnvVarList) error { - components := d.Data.GetComponents() - for _, component := range components { - if component.Container != nil { - currentlist := config.NewEnvVarListFromDevfileEnv(component.Container.Env) - component.Container.Env = currentlist.Merge(otherList).ToDevfileEnv() - d.Data.UpdateComponent(component) - } - } - return d.WriteYamlDevfile() -} - -// RemoveEnvVars removes the environment variables which have the keys from all the components in a devfile -func (d DevfileObj) RemoveEnvVars(keys []string) error { - components := d.Data.GetComponents() - for _, component := range components { - if component.Container != nil { - - currentlist := config.NewEnvVarListFromDevfileEnv(component.Container.Env) - envList, err := config.RemoveEnvVarsFromList(currentlist, keys) - if err != nil { - return err - } - component.Container.Env = envList.ToDevfileEnv() - d.Data.UpdateComponent(component) - } - } - return d.WriteYamlDevfile() -} - -func (d DevfileObj) setPorts(ports ...string) error { - components := d.Data.GetComponents() - endpoints, err := portsToEndpoints(ports...) - if err != nil { - return err - } - for _, component := range components { - if component.Container != nil { - component.Container.Endpoints = addEndpoints(component.Container.Endpoints, endpoints) - d.Data.UpdateComponent(component) - } - } - return d.WriteYamlDevfile() -} - -func (d DevfileObj) removePorts() error { - components := d.Data.GetComponents() - for _, component := range components { - if component.Container != nil { - component.Container.Endpoints = []common.Endpoint{} - d.Data.UpdateComponent(component) - } - } - return d.WriteYamlDevfile() -} - -func (d DevfileObj) hasPorts() bool { - components := d.Data.GetComponents() - for _, component := range components { - if component.Container != nil { - if len(component.Container.Endpoints) > 0 { - return true - } - } - } - return false -} - -func (d DevfileObj) setMemory(memory string) error { - components := d.Data.GetComponents() - for _, component := range components { - if component.Container != nil { - component.Container.MemoryLimit = memory - d.Data.UpdateComponent(component) - } - } - return d.WriteYamlDevfile() -} -func (d DevfileObj) GetMemory() string { - components := d.Data.GetComponents() - for _, component := range components { - if component.Container != nil { - if component.Container.MemoryLimit != "" { - return component.Container.MemoryLimit - } - } - - } - return "" -} - -func (d DevfileObj) GetMetadataName() string { - return d.Data.GetMetadata().Name -} - -// FormatDevfileSupportedParameters outputs supported parameters and their description -func FormatDevfileSupportedParameters() (result string) { - for _, v := range GetDevfileSupportedParameters() { - result = result + " " + v + " - " + supportedDevfileParameterDescriptions[v] + "\n" - } - return "\nAvailable Parameters for Devfile Components:\n" + result -} - -// AsDevfileSupportedParameter returns the parameter in lower case and a boolean indicating if it is a supported parameter -func AsDevfileSupportedParameter(param string) (string, bool) { - lower := strings.ToLower(param) - return lower, lowerCaseDevfileParameters[lower] -} - -// GetDevfileSupportedParameters returns the name of the supported global parameters -func GetDevfileSupportedParameters() []string { - return util.GetSortedKeys(supportedDevfileParameterDescriptions) -} - -func portsToEndpoints(ports ...string) ([]common.Endpoint, error) { - var endpoints []common.Endpoint - conPorts, err := util.GetContainerPortsFromStrings(ports) - if err != nil { - return nil, err - } - for _, port := range conPorts { - - endpoint := common.Endpoint{ - Name: fmt.Sprintf("port-%d-%s", port.ContainerPort, strings.ToLower(string(port.Protocol))), - TargetPort: port.ContainerPort, - Protocol: common.ProtocolType(strings.ToLower(string(port.Protocol))), - } - endpoints = append(endpoints, endpoint) - } - return endpoints, nil - -} - -func addEndpoints(current []common.Endpoint, other []common.Endpoint) []common.Endpoint { - newList := make([]common.Endpoint, len(current)) - copy(newList, current) - for _, ep := range other { - present := false - - for _, presentep := range newList { - - protocol := presentep.Protocol - if protocol == "" { - // endpoint protocol default value is http - protocol = "http" - } - // if the target port and protocol match, we add a case where the protocol is not provided and hence we assume that to be "tcp" - if presentep.TargetPort == ep.TargetPort && (ep.Protocol == protocol) { - present = true - break - } - } - if !present { - newList = append(newList, ep) - } - } - - return newList -} diff --git a/pkg/devfile/parser/configurables_test.go b/pkg/devfile/parser/configurables_test.go deleted file mode 100644 index eaa34d212..000000000 --- a/pkg/devfile/parser/configurables_test.go +++ /dev/null @@ -1,365 +0,0 @@ -package parser - -import ( - "reflect" - "testing" - - "github.com/kylelemons/godebug/pretty" - "github.com/openshift/odo/pkg/config" - devfileCtx "github.com/openshift/odo/pkg/devfile/parser/context" - v200 "github.com/openshift/odo/pkg/devfile/parser/data/2.0.0" - "github.com/openshift/odo/pkg/devfile/parser/data/common" - "github.com/openshift/odo/pkg/testingutil/filesystem" -) - -func TestSetConfiguration(t *testing.T) { - - // Use fakeFs - fs := filesystem.NewFakeFs() - - tests := []struct { - name string - args map[string]string - currentDevfile DevfileObj - wantDevFile DevfileObj - wantErr bool - }{ - { - name: "case 1: set memory to 500Mi", - args: map[string]string{ - "memory": "500Mi", - }, - currentDevfile: testDevfileObj(fs), - wantDevFile: DevfileObj{ - Ctx: devfileCtx.FakeContext(fs, OutputDevfileYamlPath), - Data: &v200.Devfile200{ - Commands: []common.DevfileCommand{ - { - Id: "devbuild", - Exec: &common.Exec{ - WorkingDir: "/projects/nodejs-starter", - }, - }, - }, - Components: []common.DevfileComponent{ - { - Name: "runtime", - Container: &common.Container{ - Image: "quay.io/nodejs-12", - MemoryLimit: "500Mi", - Endpoints: []common.Endpoint{ - { - Name: "port-3030", - TargetPort: 3000, - }, - }, - }, - }, - { - Name: "loadbalancer", - Container: &common.Container{ - Image: "quay.io/nginx", - MemoryLimit: "500Mi", - }, - }, - }, - Events: common.DevfileEvents{ - PostStop: []string{"post-stop"}, - }, - Projects: []common.DevfileProject{ - { - ClonePath: "/projects", - Name: "nodejs-starter-build", - }, - }, - StarterProjects: []common.DevfileStarterProject{ - { - SubDir: "/projects", - Name: "starter-project-2", - }, - }, - }, - }, - }, - { - name: "case 2: set ports array", - args: map[string]string{ - "ports": "8080,8081/UDP,8080/TCP", - }, - currentDevfile: testDevfileObj(fs), - wantDevFile: DevfileObj{ - Ctx: devfileCtx.FakeContext(fs, OutputDevfileYamlPath), - Data: &v200.Devfile200{ - Commands: []common.DevfileCommand{ - { - Id: "devbuild", - Exec: &common.Exec{ - WorkingDir: "/projects/nodejs-starter", - }, - }, - }, - Components: []common.DevfileComponent{ - { - Name: "runtime", - Container: &common.Container{ - Image: "quay.io/nodejs-12", - Endpoints: []common.Endpoint{ - { - Name: "port-3030", - TargetPort: 3000, - }, - { - Name: "port-8080-tcp", - TargetPort: 8080, - Protocol: "tcp", - }, { - Name: "port-8081-udp", - TargetPort: 8081, - Protocol: "udp", - }, - }, - }, - }, - { - Name: "loadbalancer", - Container: &common.Container{ - Image: "quay.io/nginx", - Endpoints: []common.Endpoint{ - { - Name: "port-8080-tcp", - TargetPort: 8080, - Protocol: "tcp", - }, { - Name: "port-8081-udp", - TargetPort: 8081, - Protocol: "udp", - }, - }, - }, - }, - }, - Events: common.DevfileEvents{ - PostStop: []string{"post-stop"}, - }, - Projects: []common.DevfileProject{ - { - ClonePath: "/projects", - Name: "nodejs-starter-build", - }, - }, - StarterProjects: []common.DevfileStarterProject{ - { - SubDir: "/projects", - Name: "starter-project-2", - }, - }, - }, - }, - }, - { - name: "case 3: set ports array fails due to validation", - args: map[string]string{ - "ports": "8080,8081/UDP,8083/", - }, - currentDevfile: testDevfileObj(fs), - wantErr: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - - for key, value := range tt.args { - err := tt.currentDevfile.SetConfiguration(key, value) - if tt.wantErr { - if err == nil { - t.Errorf("expected error but got nil") - } - // we dont expect an error here - } else { - if err != nil { - t.Errorf("error while setting configuration %+v", err.Error()) - } - } - } - - if !tt.wantErr { - if !reflect.DeepEqual(tt.currentDevfile.Data, tt.wantDevFile.Data) { - t.Errorf("wanted: %v, got: %v, difference at %v", tt.wantDevFile, tt.currentDevfile, pretty.Compare(tt.currentDevfile.Data, tt.wantDevFile.Data)) - } - } - - }) - } - -} - -func TestAddAndRemoveEnvVars(t *testing.T) { - - // Use fakeFs - fs := filesystem.NewFakeFs() - - tests := []struct { - name string - listToAdd config.EnvVarList - listToRemove []string - currentDevfile DevfileObj - wantDevFile DevfileObj - }{ - { - name: "case 1: add and remove env vars", - listToAdd: config.EnvVarList{ - { - Name: "DATABASE_PASSWORD", - Value: "苦痛", - }, - { - Name: "PORT", - Value: "3003", - }, - { - Name: "PORT", - Value: "4342", - }, - }, - listToRemove: []string{ - "PORT", - }, - currentDevfile: testDevfileObj(fs), - wantDevFile: DevfileObj{ - Ctx: devfileCtx.FakeContext(fs, OutputDevfileYamlPath), - Data: &v200.Devfile200{ - Commands: []common.DevfileCommand{ - { - Id: "devbuild", - Exec: &common.Exec{ - WorkingDir: "/projects/nodejs-starter", - }, - }, - }, - Components: []common.DevfileComponent{ - { - Name: "runtime", - Container: &common.Container{ - Image: "quay.io/nodejs-12", - Endpoints: []common.Endpoint{ - { - Name: "port-3030", - TargetPort: 3000, - }, - }, - Env: []common.Env{ - { - Name: "DATABASE_PASSWORD", - Value: "苦痛", - }, - }, - }, - }, - { - Name: "loadbalancer", - Container: &common.Container{ - Image: "quay.io/nginx", - Env: []common.Env{ - { - Name: "DATABASE_PASSWORD", - Value: "苦痛", - }, - }, - }, - }, - }, - Events: common.DevfileEvents{ - PostStop: []string{"post-stop"}, - }, - Projects: []common.DevfileProject{ - { - ClonePath: "/projects", - Name: "nodejs-starter-build", - }, - }, - StarterProjects: []common.DevfileStarterProject{ - { - SubDir: "/projects", - Name: "starter-project-2", - }, - }, - }, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - - err := tt.currentDevfile.AddEnvVars(tt.listToAdd) - - if err != nil { - t.Errorf("error while adding env vars %+v", err.Error()) - } - - err = tt.currentDevfile.RemoveEnvVars(tt.listToRemove) - - if err != nil { - t.Errorf("error while removing env vars %+v", err.Error()) - } - - if !reflect.DeepEqual(tt.currentDevfile.Data, tt.wantDevFile.Data) { - t.Errorf("wanted: %v, got: %v, difference at %v", tt.wantDevFile, tt.currentDevfile, pretty.Compare(tt.currentDevfile.Data, tt.wantDevFile.Data)) - } - - }) - } - -} - -func testDevfileObj(fs filesystem.Filesystem) DevfileObj { - return DevfileObj{ - Ctx: devfileCtx.FakeContext(fs, OutputDevfileYamlPath), - Data: &v200.Devfile200{ - Commands: []common.DevfileCommand{ - { - Id: "devbuild", - Exec: &common.Exec{ - WorkingDir: "/projects/nodejs-starter", - }, - }, - }, - Components: []common.DevfileComponent{ - { - Name: "runtime", - Container: &common.Container{ - Image: "quay.io/nodejs-12", - Endpoints: []common.Endpoint{ - { - Name: "port-3030", - TargetPort: 3000, - }, - }, - }, - }, - { - Name: "loadbalancer", - Container: &common.Container{ - Image: "quay.io/nginx", - }, - }, - }, - Events: common.DevfileEvents{ - PostStop: []string{"post-stop"}, - }, - Projects: []common.DevfileProject{ - { - ClonePath: "/projects", - Name: "nodejs-starter-build", - }, - }, - StarterProjects: []common.DevfileStarterProject{ - { - SubDir: "/projects", - Name: "starter-project-2", - }, - }, - }, - } -} diff --git a/pkg/devfile/parser/context/apiVersion_test.go b/pkg/devfile/parser/context/apiVersion_test.go deleted file mode 100644 index 6a87b7fcb..000000000 --- a/pkg/devfile/parser/context/apiVersion_test.go +++ /dev/null @@ -1,84 +0,0 @@ -package parser - -import ( - "fmt" - "reflect" - "testing" -) - -func TestSetDevfileAPIVersion(t *testing.T) { - - const ( - apiVersion = "2.0.0" - validJson = `{"schemaVersion": "2.0.0"}` - emptyJson = "{}" - emptyApiVersionJson = `{"apiVersion": ""}` - ) - - // test table - tests := []struct { - name string - rawJson []byte - want string - wantErr error - }{ - { - name: "valid apiVersion", - rawJson: []byte(validJson), - want: apiVersion, - wantErr: nil, - }, - { - name: "apiVersion not present", - rawJson: []byte(emptyJson), - want: "", - wantErr: fmt.Errorf("apiVersion or schemaVersion not present in devfile"), - }, - { - name: "apiVersion empty", - rawJson: []byte(emptyApiVersionJson), - want: "", - wantErr: fmt.Errorf("apiVersion in devfile cannot be empty"), - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - - // new devfile context object - d := DevfileCtx{rawContent: tt.rawJson} - - // SetDevfileAPIVersion - gotErr := d.SetDevfileAPIVersion() - got := d.apiVersion - - if !reflect.DeepEqual(gotErr, tt.wantErr) { - t.Errorf("unexpected error: '%v', wantErr: '%v'", gotErr, tt.wantErr) - } - - if got != tt.want { - t.Errorf("want: '%v', got: '%v'", tt.want, got) - } - }) - } -} - -func TestGetApiVersion(t *testing.T) { - - const ( - apiVersion = "2.0.0" - ) - - t.Run("get apiVersion", func(t *testing.T) { - - var ( - d = DevfileCtx{apiVersion: apiVersion} - want = apiVersion - got = d.GetApiVersion() - ) - - if got != want { - t.Errorf("want: '%v', got: '%v'", want, got) - } - }) -} diff --git a/pkg/devfile/parser/context/content_test.go b/pkg/devfile/parser/context/content_test.go deleted file mode 100644 index 1ef056f6a..000000000 --- a/pkg/devfile/parser/context/content_test.go +++ /dev/null @@ -1,181 +0,0 @@ -package parser - -import ( - "os" - "testing" - - "github.com/openshift/odo/pkg/testingutil/filesystem" -) - -const ( - TempJSONDevfilePrefix = "odo-devfile.*.json" - InvalidDevfileContent = ":: invalid :: content" - validJson200 = `{ "schemaVersion": "2.0.0", "metadata": { "name": "java-maven", "version": "1.0.0" }, "components": [ { "name": "tools", "container": { "image": "quay.io/eclipse/che-java11-maven:nightly", "memoryLimit": "512Mi", "mountSources": true, "endpoints": [ { "name": "http-8080", "targetPort": 8080 } ], "volumeMounts": [ { "name": "m2", "path": "/home/user/.m2" } ] } }, { "name": "m2", "volume": { "size": "1Gi" } } ], "commands": [ { "id": "mvn-package", "exec": { "component": "tools", "commandLine": "mvn package", "group": { "kind": "build", "isDefault": true } } }, { "id": "run", "exec": { "component": "tools", "commandLine": "java -jar target/*.jar", "group": { "kind": "run", "isDefault": true } } }, { "id": "debug", "exec": { "component": "tools", "commandLine": "java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=${DEBUG_PORT},suspend=n -jar target/*.jar", "group": { "kind": "debug", "isDefault": true } } } ] }` -) - -func validJsonRawContent200() []byte { - return []byte(validJson200) -} -func TestSetDevfileContent(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 file", func(t *testing.T) { - - var ( - fakeFs = filesystem.NewFakeFs() - tempDevfile = createTempDevfile(t, validJsonRawContent200(), fakeFs) - d = DevfileCtx{ - absPath: tempDevfile.Name(), - Fs: fakeFs, - } - ) - defer os.Remove(tempDevfile.Name()) - - err := d.SetDevfileContent() - - 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 content", func(t *testing.T) { - - var ( - fakeFs = filesystem.NewFakeFs() - tempDevfile = createTempDevfile(t, []byte(InvalidDevfileContent), fakeFs) - d = DevfileCtx{ - absPath: tempDevfile.Name(), - Fs: fakeFs, - } - ) - defer os.Remove(tempDevfile.Name()) - - err := d.SetDevfileContent() - - 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") - } - }) -} - -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, validJsonRawContent200(), fakeFs) - d = DevfileCtx{ - absPath: tempDevfile.Name(), - Fs: fakeFs, - } - ) - - defer os.Remove(tempDevfile.Name()) - - err := d.SetDevfileContentFromBytes(validJsonRawContent200()) - - 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(validJsonRawContent200()), 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") - } - }) -} diff --git a/pkg/devfile/parser/context/context_test.go b/pkg/devfile/parser/context/context_test.go deleted file mode 100644 index 2db1fdc79..000000000 --- a/pkg/devfile/parser/context/context_test.go +++ /dev/null @@ -1,75 +0,0 @@ -package parser - -import ( - "net/http" - "net/http/httptest" - "testing" -) - -func TestPopulateFromBytes(t *testing.T) { - - const ( - InvalidURL = "blah" - ) - - t.Run("valid data passed", func(t *testing.T) { - - testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - _, err := w.Write(validJsonRawContent200()) - if err != nil { - t.Error(err) - } - })) - - var ( - d = DevfileCtx{ - url: testServer.URL, - } - ) - defer testServer.Close() - - err := d.PopulateFromURL() - - if err != nil { - t.Errorf("unexpected error '%v'", err) - } - }) - - t.Run("invalid data passed", func(t *testing.T) { - - testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - _, err := w.Write([]byte(InvalidDevfileContent)) - if err != nil { - t.Error(err) - } - })) - - var ( - d = DevfileCtx{ - url: testServer.URL, - } - ) - defer testServer.Close() - - err := d.PopulateFromURL() - - if err == nil { - t.Errorf("expected error, didn't get one ") - } - }) - - t.Run("invalid filepath", func(t *testing.T) { - - var ( - d = DevfileCtx{ - url: InvalidURL, - } - ) - - err := d.PopulateFromURL() - - if err == nil { - t.Errorf("expected an error, didn't get one") - } - }) -} diff --git a/pkg/devfile/parser/context/schema_test.go b/pkg/devfile/parser/context/schema_test.go deleted file mode 100644 index 0d5286d54..000000000 --- a/pkg/devfile/parser/context/schema_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package parser - -import ( - "testing" - - v200 "github.com/openshift/odo/pkg/devfile/parser/data/2.0.0" -) - -func TestValidateDevfileSchema(t *testing.T) { - - t.Run("valid 2.0.0 json schema", func(t *testing.T) { - - var ( - d = DevfileCtx{ - jsonSchema: v200.JsonSchema200, - rawContent: validJsonRawContent200(), - } - ) - - err := d.ValidateDevfileSchema() - if err != nil { - t.Errorf("unexpected error: '%v'", err) - } - }) - - t.Run("invalid 2.0.0 json schema", func(t *testing.T) { - - var ( - d = DevfileCtx{ - jsonSchema: v200.JsonSchema200, - rawContent: []byte("{}"), - } - ) - - err := d.ValidateDevfileSchema() - if err == nil { - t.Errorf("expected error, didn't get one") - } - }) -} diff --git a/pkg/devfile/parser/data/2.0.0/components.go b/pkg/devfile/parser/data/2.0.0/components.go deleted file mode 100644 index bdf9b24c8..000000000 --- a/pkg/devfile/parser/data/2.0.0/components.go +++ /dev/null @@ -1,357 +0,0 @@ -package version200 - -import ( - "fmt" - "strings" - - "github.com/openshift/odo/pkg/devfile/parser/data/common" -) - -//SetSchemaVersion sets devfile schema version -func (d *Devfile200) SetSchemaVersion(version string) { - d.SchemaVersion = version -} - -// GetMetadata returns the DevfileMetadata Object parsed from devfile -func (d *Devfile200) GetMetadata() common.DevfileMetadata { - return d.Metadata -} - -// SetMetadata sets the metadata for devfile -func (d *Devfile200) SetMetadata(name, version string) { - d.Metadata = common.DevfileMetadata{ - Name: name, - Version: version, - } -} - -// GetParent returns the DevfileParent object parsed from devfile -func (d *Devfile200) GetParent() common.DevfileParent { - return d.Parent -} - -// SetParent sets the parent for the devfile -func (d *Devfile200) SetParent(parent common.DevfileParent) { - d.Parent = parent -} - -// GetProjects returns the DevfileProject Object parsed from devfile -func (d *Devfile200) GetProjects() []common.DevfileProject { - return d.Projects -} - -// AddProjects adss the slice of Devfile projects to the Devfile's project list -// if a project is already defined, error out -func (d *Devfile200) AddProjects(projects []common.DevfileProject) error { - projectsMap := make(map[string]bool) - for _, project := range d.Projects { - projectsMap[project.Name] = true - } - - for _, project := range projects { - if _, ok := projectsMap[project.Name]; !ok { - d.Projects = append(d.Projects, project) - } else { - return &common.AlreadyExistError{Name: project.Name, Field: "project"} - } - } - return nil -} - -// UpdateProject updates the slice of DevfileCommand projects parsed from the Devfile -func (d *Devfile200) UpdateProject(project common.DevfileProject) { - for i := range d.Projects { - if d.Projects[i].Name == strings.ToLower(project.Name) { - d.Projects[i] = project - } - } -} - -// GetComponents returns the slice of DevfileComponent objects parsed from the Devfile -func (d *Devfile200) GetComponents() []common.DevfileComponent { - return d.Components -} - -// GetAliasedComponents returns the slice of DevfileComponent objects that each have an alias -func (d *Devfile200) GetAliasedComponents() []common.DevfileComponent { - // V2 has name required in jsonSchema - return d.Components -} - -// AddComponents adds the slice of DevfileComponent objects to the devfile's components -// if a component is already defined, error out -func (d *Devfile200) AddComponents(components []common.DevfileComponent) error { - - // different map for volume and container component as a volume and a container with same name - // can exist in devfile - containerMap := make(map[string]bool) - volumeMap := make(map[string]bool) - - for _, component := range d.Components { - if component.Volume != nil { - volumeMap[component.Name] = true - } - if component.Container != nil { - containerMap[component.Name] = true - } - } - - for _, component := range components { - - if component.Volume != nil { - if _, ok := volumeMap[component.Name]; !ok { - d.Components = append(d.Components, component) - } else { - return &common.AlreadyExistError{Name: component.Name, Field: "component"} - } - } - - if component.Container != nil { - if _, ok := containerMap[component.Name]; !ok { - d.Components = append(d.Components, component) - } else { - return &common.AlreadyExistError{Name: component.Name, Field: "component"} - } - } - } - return nil -} - -// UpdateComponent updates the component with the given name -func (d *Devfile200) UpdateComponent(component common.DevfileComponent) { - index := -1 - for i := range d.Components { - if d.Components[i].Name == strings.ToLower(component.Name) { - index = i - break - } - } - if index != -1 { - d.Components[index] = component - } -} - -// GetCommands returns the slice of DevfileCommand objects parsed from the Devfile -func (d *Devfile200) GetCommands() map[string]common.DevfileCommand { - commands := make(map[string]common.DevfileCommand, len(d.Commands)) - - for _, command := range d.Commands { - // we convert devfile command id to lowercase so that we can handle - // cases efficiently without being error prone - // we also convert the odo push commands from build-command and run-command flags - commands[command.SetIDToLower()] = command - } - - return commands -} - -// AddCommands adds the slice of DevfileCommand objects to the Devfile's commands -// if a command is already defined, error out -func (d *Devfile200) AddCommands(commands ...common.DevfileCommand) error { - commandsMap := d.GetCommands() - - for _, command := range commands { - id := command.Id - if _, ok := commandsMap[id]; !ok { - d.Commands = append(d.Commands, command) - } else { - return &common.AlreadyExistError{Name: id, Field: "command"} - } - } - return nil -} - -// UpdateCommand updates the command with the given id -func (d *Devfile200) UpdateCommand(command common.DevfileCommand) { - id := strings.ToLower(command.Id) - for i := range d.Commands { - if d.Commands[i].SetIDToLower() == id { - d.Commands[i] = command - } - } -} - -//GetStarterProjects returns the DevfileStarterProject parsed from devfile -func (d *Devfile200) GetStarterProjects() []common.DevfileStarterProject { - return d.StarterProjects -} - -// AddStarterProjects adds the slice of Devfile starter projects to the Devfile's starter project list -// if a starter project is already defined, error out -func (d *Devfile200) AddStarterProjects(projects []common.DevfileStarterProject) error { - projectsMap := make(map[string]bool) - for _, project := range d.StarterProjects { - projectsMap[project.Name] = true - } - - for _, project := range projects { - if _, ok := projectsMap[project.Name]; !ok { - d.StarterProjects = append(d.StarterProjects, project) - } else { - return &common.AlreadyExistError{Name: project.Name, Field: "starterProject"} - } - } - return nil -} - -// UpdateStarterProject updates the slice of Devfile starter projects parsed from the Devfile -func (d *Devfile200) UpdateStarterProject(project common.DevfileStarterProject) { - for i := range d.StarterProjects { - if d.StarterProjects[i].Name == strings.ToLower(project.Name) { - d.StarterProjects[i] = project - } - } -} - -// GetEvents returns the Events Object parsed from devfile -func (d *Devfile200) GetEvents() common.DevfileEvents { - return d.Events -} - -// AddEvents adds the Events Object to the devfile's events -// if the event is already defined in the devfile, error out -func (d *Devfile200) AddEvents(events common.DevfileEvents) error { - if len(events.PreStop) > 0 { - if len(d.Events.PreStop) > 0 { - return &common.AlreadyExistError{Field: "pre stop"} - } - d.Events.PreStop = events.PreStop - } - - if len(events.PreStart) > 0 { - if len(d.Events.PreStart) > 0 { - return &common.AlreadyExistError{Field: "pre start"} - } - d.Events.PreStart = events.PreStart - } - - if len(events.PostStop) > 0 { - if len(d.Events.PostStop) > 0 { - return &common.AlreadyExistError{Field: "post stop"} - } - d.Events.PostStop = events.PostStop - } - - if len(events.PostStart) > 0 { - if len(d.Events.PostStart) > 0 { - return &common.AlreadyExistError{Field: "post start"} - } - d.Events.PostStart = events.PostStart - } - - return nil -} - -// UpdateEvents updates the devfile's events -// it only updates the events passed to it -func (d *Devfile200) UpdateEvents(postStart, postStop, preStart, preStop []string) { - if len(postStart) != 0 { - d.Events.PostStart = postStart - } - if len(postStop) != 0 { - d.Events.PostStop = postStop - } - if len(preStart) != 0 { - d.Events.PreStart = preStart - } - if len(preStop) != 0 { - d.Events.PreStop = preStop - } -} - -// AddVolume adds the volume to the devFile and mounts it to all the container components -func (d *Devfile200) AddVolume(volumeComponent common.DevfileComponent, path string) error { - volumeExists := false - var pathErrorContainers []string - for _, component := range d.Components { - if component.Container != nil { - for _, volumeMount := range component.Container.VolumeMounts { - if volumeMount.Path == path { - var err = fmt.Errorf("another volume, %s, is mounted to the same path: %s, on the container: %s", volumeMount.Name, path, component.Name) - pathErrorContainers = append(pathErrorContainers, err.Error()) - } - } - component.Container.VolumeMounts = append(component.Container.VolumeMounts, common.VolumeMount{ - Name: volumeComponent.Name, - Path: path, - }) - } else if component.Volume != nil && component.Name == volumeComponent.Name { - volumeExists = true - break - } - } - - if volumeExists { - return &common.AlreadyExistError{ - Field: "volume", - Name: volumeComponent.Name, - } - } - - if len(pathErrorContainers) > 0 { - return fmt.Errorf("errors while creating volume:\n%s", strings.Join(pathErrorContainers, "\n")) - } - - d.Components = append(d.Components, volumeComponent) - - return nil -} - -// DeleteVolume removes the volume from the devFile and removes all the related volume mounts -func (d *Devfile200) DeleteVolume(name string) error { - found := false - for i := len(d.Components) - 1; i >= 0; i-- { - if d.Components[i].Container != nil { - var tmp []common.VolumeMount - for _, volumeMount := range d.Components[i].Container.VolumeMounts { - if volumeMount.Name != name { - tmp = append(tmp, volumeMount) - } - } - d.Components[i].Container.VolumeMounts = tmp - } else if d.Components[i].Volume != nil { - if d.Components[i].Name == name { - found = true - d.Components = append(d.Components[:i], d.Components[i+1:]...) - } - } - } - - if !found { - return &common.NotFoundError{ - Field: "volume", - Name: name, - } - } - - return nil -} - -// GetVolumeMountPath gets the mount path of the required volume -func (d *Devfile200) GetVolumeMountPath(name string) (string, error) { - volumeFound := false - mountFound := false - path := "" - - for _, component := range d.Components { - if component.Container != nil { - for _, volumeMount := range component.Container.VolumeMounts { - if volumeMount.Name == name { - mountFound = true - path = volumeMount.Path - } - } - } else if component.Volume != nil { - volumeFound = true - } - } - if volumeFound && mountFound { - return path, nil - } else if !mountFound && volumeFound { - return "", fmt.Errorf("volume not mounted to any component") - } - return "", &common.NotFoundError{ - Field: "volume", - Name: "name", - } -} diff --git a/pkg/devfile/parser/data/2.0.0/components_test.go b/pkg/devfile/parser/data/2.0.0/components_test.go deleted file mode 100644 index 5a3b1c9a4..000000000 --- a/pkg/devfile/parser/data/2.0.0/components_test.go +++ /dev/null @@ -1,485 +0,0 @@ -package version200 - -import ( - "reflect" - "testing" - - "github.com/kylelemons/godebug/pretty" - "github.com/openshift/odo/pkg/devfile/parser/data/common" - "github.com/openshift/odo/pkg/testingutil" -) - -func TestDevfile200_AddVolume(t *testing.T) { - image0 := "some-image-0" - container0 := "container0" - - image1 := "some-image-1" - container1 := "container1" - - volume0 := "volume0" - volume1 := "volume1" - - type args struct { - volumeComponent common.DevfileComponent - path string - } - tests := []struct { - name string - currentComponents []common.DevfileComponent - wantComponents []common.DevfileComponent - args args - wantErr bool - }{ - { - name: "case 1: it should add the volume to all the containers", - currentComponents: []common.DevfileComponent{ - { - Name: container0, - Container: &common.Container{ - Image: image0, - }, - }, - { - Name: container1, - Container: &common.Container{ - Image: image1, - }, - }, - }, - args: args{ - volumeComponent: testingutil.GetFakeVolumeComponent(volume0, "5Gi"), - path: "/path", - }, - wantComponents: []common.DevfileComponent{ - { - Name: container0, - Container: &common.Container{ - Image: image0, - VolumeMounts: []common.VolumeMount{ - testingutil.GetFakeVolumeMount(volume0, "/path"), - }, - }, - }, - { - Name: container1, - Container: &common.Container{ - Image: image1, - VolumeMounts: []common.VolumeMount{ - testingutil.GetFakeVolumeMount(volume0, "/path"), - }, - }, - }, - testingutil.GetFakeVolumeComponent(volume0, "5Gi"), - }, - }, - { - name: "case 2: it should add the volume when other volumes are present", - currentComponents: []common.DevfileComponent{ - { - Name: container0, - Container: &common.Container{ - Image: image0, - VolumeMounts: []common.VolumeMount{ - testingutil.GetFakeVolumeMount(volume1, "/data"), - }, - }, - }, - }, - args: args{ - volumeComponent: testingutil.GetFakeVolumeComponent(volume0, "5Gi"), - path: "/path", - }, - wantComponents: []common.DevfileComponent{ - { - Name: container0, - Container: &common.Container{ - Image: image0, - VolumeMounts: []common.VolumeMount{ - testingutil.GetFakeVolumeMount(volume1, "/data"), - testingutil.GetFakeVolumeMount(volume0, "/path"), - }, - }, - }, - testingutil.GetFakeVolumeComponent(volume0, "5Gi"), - }, - }, - { - name: "case 3: error out when same volume is present", - currentComponents: []common.DevfileComponent{ - testingutil.GetFakeVolumeComponent(volume0, "1Gi"), - }, - args: args{ - volumeComponent: testingutil.GetFakeVolumeComponent(volume0, "5Gi"), - path: "/path", - }, - wantErr: true, - }, - { - name: "case 4: it should error out when another volume is mounted to the same path", - currentComponents: []common.DevfileComponent{ - { - Name: container0, - Container: &common.Container{ - Image: image0, - VolumeMounts: []common.VolumeMount{ - testingutil.GetFakeVolumeMount(volume1, "/path"), - }, - }, - }, - testingutil.GetFakeVolumeComponent(volume1, "5Gi"), - }, - args: args{ - volumeComponent: testingutil.GetFakeVolumeComponent(volume0, "5Gi"), - path: "/path", - }, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - d := &Devfile200{ - Components: tt.currentComponents, - } - - err := d.AddVolume(tt.args.volumeComponent, tt.args.path) - if (err != nil) != tt.wantErr { - t.Errorf("AddVolume() error = %v, wantErr %v", err, tt.wantErr) - } - - if err != nil && tt.wantErr { - return - } - - if !reflect.DeepEqual(d.Components, tt.wantComponents) { - t.Errorf("wanted: %v, got: %v, difference at %v", tt.wantComponents, d.Components, pretty.Compare(tt.wantComponents, d.Components)) - } - }) - } -} - -func TestDevfile200_DeleteVolume(t *testing.T) { - image0 := "some-image-0" - container0 := "container0" - - image1 := "some-image-1" - container1 := "container1" - - volume0 := "volume0" - volume1 := "volume1" - - type args struct { - name string - } - tests := []struct { - name string - currentComponents []common.DevfileComponent - wantComponents []common.DevfileComponent - args args - wantErr bool - }{ - { - name: "case 1: volume is present and mounted to multiple components", - currentComponents: []common.DevfileComponent{ - { - Name: container0, - Container: &common.Container{ - Image: image0, - VolumeMounts: []common.VolumeMount{ - testingutil.GetFakeVolumeMount(volume0, "/path"), - }, - }, - }, - { - Name: container1, - Container: &common.Container{ - Image: image1, - VolumeMounts: []common.VolumeMount{ - { - Name: volume0, - Path: "/path", - }, - }, - }, - }, - testingutil.GetFakeVolumeComponent(volume0, "5Gi"), - }, - wantComponents: []common.DevfileComponent{ - { - Name: container0, - Container: &common.Container{ - Image: image0, - }, - }, - { - Name: container1, - Container: &common.Container{ - Image: image1, - }, - }, - }, - args: args{ - name: volume0, - }, - wantErr: false, - }, - { - name: "case 2: delete only the required volume in case of multiples", - currentComponents: []common.DevfileComponent{ - { - Name: container0, - Container: &common.Container{ - Image: image0, - VolumeMounts: []common.VolumeMount{ - testingutil.GetFakeVolumeMount(volume0, "/path"), - testingutil.GetFakeVolumeMount(volume1, "/data"), - }, - }, - }, - { - Name: container1, - Container: &common.Container{ - Image: image1, - VolumeMounts: []common.VolumeMount{ - testingutil.GetFakeVolumeMount(volume1, "/data"), - }, - }, - }, - testingutil.GetFakeVolumeComponent(volume0, "5Gi"), - testingutil.GetFakeVolumeComponent(volume1, "5Gi"), - }, - wantComponents: []common.DevfileComponent{ - { - Name: container0, - Container: &common.Container{ - Image: image0, - VolumeMounts: []common.VolumeMount{ - testingutil.GetFakeVolumeMount(volume1, "/data"), - }, - }, - }, - { - Name: container1, - Container: &common.Container{ - Image: image1, - VolumeMounts: []common.VolumeMount{ - testingutil.GetFakeVolumeMount(volume1, "/data"), - }, - }, - }, - testingutil.GetFakeVolumeComponent(volume1, "5Gi"), - }, - args: args{ - name: volume0, - }, - wantErr: false, - }, - { - name: "case 3: volume is not present", - currentComponents: []common.DevfileComponent{ - { - Name: container0, - Container: &common.Container{ - Image: image0, - VolumeMounts: []common.VolumeMount{ - testingutil.GetFakeVolumeMount(volume1, "/data"), - }, - }, - }, - testingutil.GetFakeVolumeComponent(volume1, "5Gi"), - }, - wantComponents: []common.DevfileComponent{}, - args: args{ - name: volume0, - }, - wantErr: true, - }, - { - name: "case 4: volume is present but not mounted to any component", - currentComponents: []common.DevfileComponent{ - testingutil.GetFakeVolumeComponent(volume0, "5Gi"), - }, - wantComponents: []common.DevfileComponent{}, - args: args{ - name: volume0, - }, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - d := &Devfile200{ - Components: tt.currentComponents, - } - err := d.DeleteVolume(tt.args.name) - if (err != nil) != tt.wantErr { - t.Errorf("DeleteVolume() error = %v, wantErr %v", err, tt.wantErr) - } - - if err != nil && tt.wantErr { - return - } - - if !reflect.DeepEqual(d.Components, tt.wantComponents) { - t.Errorf("wanted: %v, got: %v, difference at %v", tt.wantComponents, d.Components, pretty.Compare(tt.wantComponents, d.Components)) - } - }) - } -} - -func TestDevfile200_GetVolumeMountPath(t *testing.T) { - volume1 := "volume1" - - type args struct { - name string - } - tests := []struct { - name string - currentComponents []common.DevfileComponent - wantPath string - args args - wantErr bool - }{ - { - name: "case 1: volume is present and mounted on a component", - currentComponents: []common.DevfileComponent{ - { - Container: &common.Container{ - VolumeMounts: []common.VolumeMount{ - testingutil.GetFakeVolumeMount(volume1, "/path"), - }, - }, - }, - testingutil.GetFakeVolumeComponent(volume1, "5Gi"), - }, - wantPath: "/path", - args: args{ - name: volume1, - }, - wantErr: false, - }, - { - name: "case 2: volume is not present but mounted on a component", - currentComponents: []common.DevfileComponent{ - { - Container: &common.Container{ - VolumeMounts: []common.VolumeMount{ - testingutil.GetFakeVolumeMount(volume1, "/path"), - }, - }, - }, - }, - args: args{ - name: volume1, - }, - wantErr: true, - }, - { - name: "case 3: volume is not present and not mounted on a component", - currentComponents: []common.DevfileComponent{}, - args: args{ - name: volume1, - }, - wantErr: true, - }, - { - name: "case 4: volume is present but not mounted", - currentComponents: []common.DevfileComponent{ - testingutil.GetFakeVolumeComponent(volume1, "5Gi"), - }, - args: args{ - name: volume1, - }, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - d := &Devfile200{ - Components: tt.currentComponents, - } - got, err := d.GetVolumeMountPath(tt.args.name) - if (err != nil) != tt.wantErr { - t.Errorf("GetVolumeMountPath() error = %v, wantErr %v", err, tt.wantErr) - } - - if err != nil && tt.wantErr { - return - } - - if !reflect.DeepEqual(got, tt.wantPath) { - t.Errorf("wanted: %v, got: %v, difference at %v", tt.wantPath, got, pretty.Compare(tt.wantPath, got)) - } - }) - } -} - -func TestAddStarterProjects(t *testing.T) { - currentProject := []common.DevfileStarterProject{ - { - Name: "java-starter", - Description: "starter project for java", - }, - { - Name: "quarkus-starter", - Description: "starter project for quarkus", - }, - } - - d := &Devfile200{ - StarterProjects: currentProject, - } - - tests := []struct { - name string - wantErr bool - args []common.DevfileStarterProject - }{ - { - name: "case:1 It should add starter project", - wantErr: false, - args: []common.DevfileStarterProject{ - { - Name: "nodejs", - Description: "starter project for nodejs", - }, - { - Name: "spring-pet-clinic", - Description: "starter project for springboot", - }, - }, - }, - - { - name: "case:2 It should give error if tried to add already present starter project", - wantErr: true, - args: []common.DevfileStarterProject{ - { - Name: "quarkus-starter", - Description: "starter project for quarkus", - }, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := d.AddStarterProjects(tt.args) - if err != nil { - if !tt.wantErr { - t.Errorf("unexpected error: %v", err) - } - return - } - if tt.wantErr { - t.Errorf("expected error, got %v", err) - return - } - wantProjects := append(currentProject, tt.args...) - - if !reflect.DeepEqual(d.StarterProjects, wantProjects) { - t.Errorf("wanted: %v, got: %v, difference at %v", wantProjects, d.StarterProjects, pretty.Compare(wantProjects, d.StarterProjects)) - } - }) - } - -} diff --git a/pkg/devfile/parser/data/2.0.0/types.go b/pkg/devfile/parser/data/2.0.0/types.go deleted file mode 100644 index 40735994c..000000000 --- a/pkg/devfile/parser/data/2.0.0/types.go +++ /dev/null @@ -1,30 +0,0 @@ -package version200 - -import "github.com/openshift/odo/pkg/devfile/parser/data/common" - -// Devfile200 Devfile schema. -type Devfile200 struct { - // Devfile schema version - SchemaVersion string `json:"schemaVersion" yaml:"schemaVersion"` - - // Optional metadata - Metadata common.DevfileMetadata `json:"metadata,omitempty" yaml:"metadata,omitempty"` - - // Parent workspace template - Parent common.DevfileParent `json:"parent,omitempty" yaml:"parent,omitempty"` - - // Projects worked on in the workspace, containing names and sources locations - Projects []common.DevfileProject `json:"projects,omitempty" yaml:"projects,omitempty"` - - // StarterProjects is a project that can be used as a starting point when bootstrapping new projects - StarterProjects []common.DevfileStarterProject `json:"starterProjects,omitempty" yaml:"starterProjects,omitempty"` - - // List of the workspace components, such as editor and plugins, user-provided containers, or other types of components - Components []common.DevfileComponent `json:"components,omitempty" yaml:"components,omitempty"` - - // Predefined, ready-to-use, workspace-related commands - Commands []common.DevfileCommand `json:"commands,omitempty" yaml:"commands,omitempty"` - - // Bindings of commands to events. Each command is referred-to by its name. - Events common.DevfileEvents `json:"events,omitempty" yaml:"events,omitempty"` -} diff --git a/pkg/devfile/parser/data/common/command_helper.go b/pkg/devfile/parser/data/common/command_helper.go deleted file mode 100644 index 5146c7654..000000000 --- a/pkg/devfile/parser/data/common/command_helper.go +++ /dev/null @@ -1,51 +0,0 @@ -package common - -import "strings" - -// SetIDToLower converts the command's id to lower case for more efficient processing and returns the new id -func (dc *DevfileCommand) SetIDToLower() string { - var newId string - if dc.Exec != nil || dc.Composite != nil { - newId = strings.ToLower(dc.Id) - dc.Id = newId - } - return newId -} - -// GetGroup returns the group the command belongs to -func (dc DevfileCommand) GetGroup() *Group { - if dc.Composite != nil { - return dc.Composite.Group - } else if dc.Exec != nil { - return dc.Exec.Group - } - - return nil -} - -// GetExecComponent returns the component of the exec command -func (dc DevfileCommand) GetExecComponent() string { - if dc.Exec != nil { - return dc.Exec.Component - } - - return "" -} - -// GetExecCommandLine returns the command line of the exec command -func (dc DevfileCommand) GetExecCommandLine() string { - if dc.Exec != nil { - return dc.Exec.CommandLine - } - - return "" -} - -// GetExecWorkingDir returns the working dir of the exec command -func (dc DevfileCommand) GetExecWorkingDir() string { - if dc.Exec != nil { - return dc.Exec.WorkingDir - } - - return "" -} diff --git a/pkg/devfile/parser/data/common/command_helper_test.go b/pkg/devfile/parser/data/common/command_helper_test.go deleted file mode 100644 index 9b5480d9a..000000000 --- a/pkg/devfile/parser/data/common/command_helper_test.go +++ /dev/null @@ -1,188 +0,0 @@ -package common - -import ( - "reflect" - "testing" -) - -func TestGetGroup(t *testing.T) { - - tests := []struct { - name string - command DevfileCommand - want *Group - }{ - { - name: "Case 1: Exec command group", - command: DevfileCommand{ - Id: "exec1", - Exec: &Exec{ - Group: &Group{ - IsDefault: true, - Kind: RunCommandGroupType, - }, - }, - }, - want: &Group{ - IsDefault: true, - Kind: RunCommandGroupType, - }, - }, - { - name: "Case 2: Composite command group", - command: DevfileCommand{ - Id: "composite1", - Composite: &Composite{ - Group: &Group{ - IsDefault: true, - Kind: BuildCommandGroupType, - }, - }, - }, - want: &Group{ - IsDefault: true, - Kind: BuildCommandGroupType, - }, - }, - { - name: "Case 3: Empty command", - command: DevfileCommand{}, - want: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - commandGroup := tt.command.GetGroup() - if !reflect.DeepEqual(commandGroup, tt.want) { - t.Errorf("expected %v, actual %v", tt.want, commandGroup) - } - }) - } - -} - -func TestGetExecComponent(t *testing.T) { - - tests := []struct { - name string - command DevfileCommand - want string - }{ - { - name: "Case 1: Exec component present", - command: DevfileCommand{ - Id: "exec1", - Exec: &Exec{ - Component: "component1", - }, - }, - want: "component1", - }, - { - name: "Case 2: Exec component absent", - command: DevfileCommand{ - Id: "exec1", - Exec: &Exec{}, - }, - want: "", - }, - { - name: "Case 3: Empty command", - command: DevfileCommand{}, - want: "", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - component := tt.command.GetExecComponent() - if component != tt.want { - t.Errorf("expected %v, actual %v", tt.want, component) - } - }) - } - -} - -func TestGetExecCommandLine(t *testing.T) { - - tests := []struct { - name string - command DevfileCommand - want string - }{ - { - name: "Case 1: Exec command line present", - command: DevfileCommand{ - Id: "exec1", - Exec: &Exec{ - CommandLine: "commandline1", - }, - }, - want: "commandline1", - }, - { - name: "Case 2: Exec command line absent", - command: DevfileCommand{ - Id: "exec1", - Exec: &Exec{}, - }, - want: "", - }, - { - name: "Case 3: Empty command", - command: DevfileCommand{}, - want: "", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - commandLine := tt.command.GetExecCommandLine() - if commandLine != tt.want { - t.Errorf("expected %v, actual %v", tt.want, commandLine) - } - }) - } - -} - -func TestGetExecWorkingDir(t *testing.T) { - - tests := []struct { - name string - command DevfileCommand - want string - }{ - { - name: "Case 1: Exec working dir present", - command: DevfileCommand{ - Id: "exec1", - Exec: &Exec{ - WorkingDir: "workingdir1", - }, - }, - want: "workingdir1", - }, - { - name: "Case 2: Exec working dir absent", - command: DevfileCommand{ - Id: "exec1", - Exec: &Exec{}, - }, - want: "", - }, - { - name: "Case 3: Empty command", - command: DevfileCommand{}, - want: "", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - workingDir := tt.command.GetExecWorkingDir() - if workingDir != tt.want { - t.Errorf("expected %v, actual %v", tt.want, workingDir) - } - }) - } - -} diff --git a/pkg/devfile/parser/data/common/errors.go b/pkg/devfile/parser/data/common/errors.go deleted file mode 100644 index 72b0d42da..000000000 --- a/pkg/devfile/parser/data/common/errors.go +++ /dev/null @@ -1,27 +0,0 @@ -package common - -import "fmt" - -// AlreadyExistError error returned if tried to add already existing field -type AlreadyExistError struct { - // field which already exist - Field string - // field name - Name string -} - -func (e *AlreadyExistError) Error() string { - return fmt.Sprintf("%s %s already exists in the devfile", e.Field, e.Name) -} - -// NotFoundError error returned if the field with the name is not found -type NotFoundError struct { - // field which doesn't exist - Field string - // field name - Name string -} - -func (e *NotFoundError) Error() string { - return fmt.Sprintf("%s %s is not found in the devfile", e.Field, e.Name) -} diff --git a/pkg/devfile/parser/data/common/project_helper_test.go b/pkg/devfile/parser/data/common/project_helper_test.go deleted file mode 100644 index 1598b6847..000000000 --- a/pkg/devfile/parser/data/common/project_helper_test.go +++ /dev/null @@ -1,115 +0,0 @@ -package common - -import "testing" - -func TestGitLikeProjectSource_GetDefaultSource(t *testing.T) { - - tests := []struct { - name string - gitLikeProjectSource GitLikeProjectSource - want1 string - want2 string - want3 string - wantErr bool - }{ - { - name: "only one remote", - gitLikeProjectSource: GitLikeProjectSource{ - Remotes: map[string]string{ - "origin": "url", - }, - }, - want1: "origin", - want2: "url", - want3: "", - wantErr: false, - }, - { - name: "multiple remotes, checkoutFrom with only branch", - gitLikeProjectSource: GitLikeProjectSource{ - Remotes: map[string]string{ - "origin": "urlO", - }, - CheckoutFrom: &CheckoutFrom{Revision: "dev"}, - }, - want1: "origin", - want2: "urlO", - want3: "dev", - wantErr: false, - }, - { - name: "multiple remotes, checkoutFrom without revision", - gitLikeProjectSource: GitLikeProjectSource{ - Remotes: map[string]string{ - "origin": "urlO", - "upstream": "urlU", - }, - CheckoutFrom: &CheckoutFrom{Remote: "upstream"}, - }, - want1: "upstream", - want2: "urlU", - want3: "", - wantErr: false, - }, - { - name: "multiple remotes, checkoutFrom with revision", - gitLikeProjectSource: GitLikeProjectSource{ - Remotes: map[string]string{ - "origin": "urlO", - "upstream": "urlU", - }, - CheckoutFrom: &CheckoutFrom{Remote: "upstream", Revision: "v1"}, - }, - want1: "upstream", - want2: "urlU", - want3: "v1", - wantErr: false, - }, - { - name: "multiple remotes, checkoutFrom with unknown remote", - gitLikeProjectSource: GitLikeProjectSource{ - Remotes: map[string]string{ - "origin": "urlO", - "upstream": "urlU", - }, - CheckoutFrom: &CheckoutFrom{Remote: "non"}, - }, - want1: "", - want2: "", - want3: "", - wantErr: true, - }, - { - name: "multiple remotes, no checkoutFrom", - gitLikeProjectSource: GitLikeProjectSource{ - Remotes: map[string]string{ - "origin": "urlO", - "upstream": "urlU", - }, - }, - want1: "", - want2: "", - want3: "", - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - - got1, got2, got3, err := tt.gitLikeProjectSource.GetDefaultSource() - if (err != nil) != tt.wantErr { - t.Errorf("GitLikeProjectSource.GetDefaultSource() error = %v, wantErr %v", err, tt.wantErr) - return - } - if got1 != tt.want1 { - t.Errorf("GitLikeProjectSource.GetDefaultSource() got1 = %v, want %v", got1, tt.want1) - } - if got2 != tt.want2 { - t.Errorf("GitLikeProjectSource.GetDefaultSource() got2 = %v, want %v", got2, tt.want2) - } - if got3 != tt.want3 { - t.Errorf("GitLikeProjectSource.GetDefaultSource() got2 = %v, want %v", got3, tt.want3) - } - }) - } -} diff --git a/pkg/devfile/parser/data/common/types.go b/pkg/devfile/parser/data/common/types.go deleted file mode 100644 index 4e3f2f991..000000000 --- a/pkg/devfile/parser/data/common/types.go +++ /dev/null @@ -1,388 +0,0 @@ -package common - -// DevfileComponentType describes the type of component. -// Only one of the following component type may be specified -// To support some print actions -type DevfileComponentType string - -const ( - ContainerComponentType DevfileComponentType = "Container" - KubernetesComponentType DevfileComponentType = "Kubernetes" - OpenshiftComponentType DevfileComponentType = "Openshift" - PluginComponentType DevfileComponentType = "Plugin" - VolumeComponentType DevfileComponentType = "Volume" - CustomComponentType DevfileComponentType = "Custom" -) - -// DevfileCommandGroupType describes the kind of command group. -// +kubebuilder:validation:Enum=build;run;test;debug -type DevfileCommandGroupType string - -const ( - BuildCommandGroupType DevfileCommandGroupType = "build" - RunCommandGroupType DevfileCommandGroupType = "run" - TestCommandGroupType DevfileCommandGroupType = "test" - DebugCommandGroupType DevfileCommandGroupType = "debug" -) - -// ExposureType is an enum to indicate the exposure type of the endpoint -type ExposureType string - -const ( - Public ExposureType = "public" - Internal ExposureType = "internal" - None ExposureType = "none" -) - -// ProtocolType is an enum to indicate the protocol type of the endpoint -type ProtocolType string - -const ( - HTTP ProtocolType = "http" - HTTPS ProtocolType = "https" - WS ProtocolType = "ws" - WSS ProtocolType = "wss" - TCP ProtocolType = "tcp" - UDP ProtocolType = "udp" -) - -// DevfileMetadata metadata for devfile -type DevfileMetadata struct { - - // Name Optional devfile name - Name string `json:"name,omitempty" yaml:"name,omitempty"` - - // Version Optional semver-compatible version - Version string `json:"version,omitempty" yaml:"version,omitempty"` - - AlphaBuildDockerfile string `json:"alpha.build-dockerfile,omitempty" yaml:"alpha.build-dockerfile,omitempty"` - - AlphaDeploymentManifest string `json:"alpha.deployment-manifest,omitempty" yaml:"alpha.deployment-manifest,omitempty"` -} - -// DevfileCommand command specified in devfile -type DevfileCommand struct { - - // Composite command executed in a component container - Composite *Composite `json:"composite,omitempty" yaml:"composite,omitempty"` - // CLI Command executed in a component container - Exec *Exec `json:"exec,omitempty" yaml:"exec,omitempty"` - - // Mandatory identifier that allows referencing this command in composite commands, from a parent, or in events. - Id string `json:"id" yaml:"id"` -} - -// DevfileComponent component specified in devfile -type DevfileComponent struct { - - // Mandatory name that allows referencing the component from other elements (such as commands) or from an external devfile that may reference this component through a parent or a plugin. - Name string `json:"name" yaml:"name"` - - // Allows adding and configuring workspace-related containers - Container *Container `json:"container,omitempty" yaml:"container,omitempty"` - - // Allows importing into the workspace the Kubernetes resources defined in a given manifest. For example this allows reusing the Kubernetes definitions used to deploy some runtime components in production. - Kubernetes *Kubernetes `json:"kubernetes,omitempty" yaml:"kubernetes,omitempty"` - - // Allows importing into the workspace the OpenShift resources defined in a given manifest. For example this allows reusing the OpenShift definitions used to deploy some runtime components in production. - Openshift *Openshift `json:"openshift,omitempty" yaml:"openshift,omitempty"` - - // Allows specifying the definition of a volume shared by several other components - Volume *Volume `json:"volume,omitempty" yaml:"volume,omitempty"` -} - -// Container Allows adding and configuring workspace-related containers -type Container struct { - - // The arguments to supply to the command running the dockerimage component. The arguments are supplied either to the default command provided in the image or to the overridden command. Defaults to an empty array, meaning use whatever is defined in the image. - Args []string `json:"args,omitempty" yaml:"args,omitempty" ` - - // The command to run in the dockerimage component instead of the default one provided in the image. Defaults to an empty array, meaning use whatever is defined in the image. - Command []string `json:"command,omitempty" yaml:"command,omitempty"` - - Endpoints []Endpoint `json:"endpoints,omitempty" yaml:"endpoints,omitempty" patchStrategy:"merge" patchMergeKey:"name"` - - // Environment variables used in this container - Env []Env `json:"env,omitempty" yaml:"env,omitempty" patchStrategy:"merge" patchMergeKey:"name"` - - // Image is a required field but we use omitempty - // because a empty image value will override a parent's image value with a empty string value - Image string `json:"image,omitempty" yaml:"image,omitempty"` - MemoryLimit string `json:"memoryLimit,omitempty" yaml:"memoryLimit,omitempty"` - MountSources bool `json:"mountSources,omitempty" yaml:"mountSources,omitempty"` - - // Optional specification of the path in the container where project sources should be transferred/mounted when `mountSources` is `true`. When omitted, the value of the `PROJECTS_ROOT` environment variable is used. - SourceMapping string `json:"sourceMapping,omitempty" yaml:"sourceMapping,omitempty"` - - // List of volumes mounts that should be mounted is this container. - VolumeMounts []VolumeMount `json:"volumeMounts,omitempty" yaml:"volumeMounts,omitempty" patchStrategy:"merge" patchMergeKey:"name"` -} - -// Endpoint holds information about how an application is exposed -type Endpoint struct { - Attributes map[string]string `json:"attributes,omitempty" yaml:"attributes,omitempty"` - - // Describes how the endpoint should be exposed on the network. public|internal|none. Default value is "public" - Exposure ExposureType `json:"exposure,omitempty" yaml:"exposure,omitempty"` - - Path string `json:"path,omitempty" yaml:"path,omitempty"` - Secure bool `json:"secure,omitempty" yaml:"secure,omitempty"` - Name string `json:"name" yaml:"name"` - TargetPort int32 `json:"targetPort" yaml:"targetPort"` - - // Describes the application and transport protocols of the traffic that will go through this endpoint. Default value is "http" - Protocol ProtocolType `json:"protocol,omitempty" yaml:"protocol,omitempty"` -} - -// Env -type Env struct { - Name string `json:"name" yaml:"name"` - Value string `json:"value" yaml:"value"` -} - -// Events Bindings of commands to events. Each command is referred-to by its name. -type DevfileEvents struct { - - // Names of commands that should be executed after the workspace is completely started. In the case of Che-Theia, these commands should be executed after all plugins and extensions have started, including project cloning. This means that those commands are not triggered until the user opens the IDE in his browser. - PostStart []string `json:"postStart,omitempty" yaml:"postStart,omitempty"` - - // Names of commands that should be executed after stopping the workspace. - PostStop []string `json:"postStop,omitempty" yaml:"postStop,omitempty"` - - // Names of commands that should be executed before the workspace start. Kubernetes-wise, these commands would typically be executed in init containers of the workspace POD. - PreStart []string `json:"preStart,omitempty" yaml:"preStart,omitempty"` - - // Names of commands that should be executed before stopping the workspace. - PreStop []string `json:"preStop,omitempty" yaml:"preStop,omitempty"` -} - -// Exec CLI Command executed in a component container -type Exec struct { - - // Optional map of free-form additional command attributes - Attributes map[string]string `json:"attributes,omitempty" yaml:"attributes,omitempty" patchStrategy:"merge"` - - // The actual command-line string - CommandLine string `json:"commandLine,omitempty" yaml:"commandLine,omitempty"` - - // Describes component to which given action relates - Component string `json:"component,omitempty" yaml:"component,omitempty"` - - // Optional list of environment variables that have to be set before running the command - Env []Env `json:"env,omitempty" yaml:"env,omitempty" patchStrategy:"merge" patchMergeKey:"name"` - - // Defines the group this command is part of - Group *Group `json:"group,omitempty" yaml:"group,omitempty"` - - // Optional label that provides a label for this command to be used in Editor UI menus for example - Label string `json:"label,omitempty" yaml:"label,omitempty"` - - // Working directory where the command should be executed - WorkingDir string `json:"workingDir,omitempty" yaml:"workingDir,omitempty"` - - // +optional - // Whether the command is capable to reload itself when source code changes. - // If set to `true` the command won't be restarted and it is expected to handle file changes on its own. - // - // Default value is `false` - HotReloadCapable bool `json:"hotReloadCapable,omitempty" yaml:"hotReloadCapable,omitempty"` -} - -// Composite command containing a list of commands to execute in a component container -type Composite struct { - // Optional map of free-form additional command attributes - Attributes map[string]string `json:"attributes,omitempty"` - - // The list of commands to execute in this composite command. - Commands []string `json:"commands,omitempty"` - - // Defines the group this command is part of - Group *Group `json:"group,omitempty"` - - // Optional label that provides a label for this command to be used in Editor UI menus for example - Label string `json:"label,omitempty"` - - // Whether or not the composite command should be executed in parallel - Parallel bool `json:"parallel,omitempty"` -} - -type GitLikeProjectSource struct { - // The remotes map which should be initialized in the git project. Must have at least one remote configured - Remotes map[string]string `json:"remotes,omitempty" yaml:"remotes,omitempty"` - - // Defines from what the project should be checked out. Required if there are more than one remote configured - // +optional - CheckoutFrom *CheckoutFrom `json:"checkoutFrom,omitempty" yaml:"checkoutFrom,omitempty"` -} - -// Git Project's Git source -// Github Project's GitHub source -type Git struct { - GitLikeProjectSource `json:",inline" yaml:",inline"` -} - -// Github Project's GitHub source -type Github struct { - GitLikeProjectSource `json:",inline" yaml:",inline"` -} - -// Group Defines the group this command is part of -type Group struct { - - // Identifies the default command for a given group kind - IsDefault bool `json:"isDefault,omitempty" yaml:"isDefault,omitempty"` - - // Kind of group the command is part of - Kind DevfileCommandGroupType `json:"kind" yaml:"kind"` -} - -// Kubernetes Allows importing into the workspace the Kubernetes resources defined in a given manifest. For example this allows reusing the Kubernetes definitions used to deploy some runtime components in production. -type Kubernetes struct { - - // Inlined manifest - Inlined string `json:"inlined,omitempty" yaml:"inlined,omitempty"` - - // Mandatory name that allows referencing the component in commands, or inside a parent - Name string `json:"name" yaml:"name"` - - // Location in a file fetched from a uri. - Uri string `json:"uri,omitempty" yaml:"uri,omitempty"` -} - -// Openshift Configuration overriding for an OpenShift component -type Openshift struct { - - // Inlined manifest - Inlined string `json:"inlined,omitempty" yaml:"inlined,omitempty"` - - // Mandatory name that allows referencing the component in commands, or inside a parent - Name string `json:"name" yaml:"name"` - - // Location in a file fetched from a uri. - Uri string `json:"uri,omitempty" yaml:"uri,omitempty"` -} - -// DevfileParent Parent workspace template -type DevfileParent struct { - - // Id in a registry that contains a Devfile yaml file - Id string `json:"id,omitempty" yaml:"id,omitempty"` - - // Reference to a Kubernetes CRD of type DevWorkspaceTemplate - Kubernetes Kubernetes `json:"kubernetes,omitempty" yaml:"kubernetes,omitempty"` - - // Uri of a Devfile yaml file - Uri string `json:"uri,omitempty" yaml:"uri,omitempty"` - - RegistryUrl string `json:"registryUrl,omitempty" yaml:"registryUrl,omitempty"` - - // Projects worked on in the workspace, containing names and sources locations - Projects []DevfileProject `json:"projects,omitempty" yaml:"projects,omitempty"` - - // Predefined, ready-to-use, workspace-related commands - Commands []DevfileCommand `json:"commands,omitempty" yaml:"commands,omitempty"` - - // List of the workspace components, such as editor and plugins, user-provided containers, or other types of components - Components []DevfileComponent `json:"components,omitempty" yaml:"components,omitempty"` - - // StarterProjects is a project that can be used as a starting point when bootstrapping new projects - StarterProjects []DevfileStarterProject `json:"starterProjects,omitempty" yaml:"starterProjects,omitempty"` -} - -// Plugin Allows importing a plugin. Plugins are mainly imported devfiles that contribute components, commands and events as a consistent single unit. They are defined in either YAML files following the devfile syntax, or as `DevWorkspaceTemplate` Kubernetes Custom Resources -type Plugin struct { - - // Overrides of commands encapsulated in a plugin. Overriding is done using a strategic merge - Commands []*DevfileCommand `json:"commands,omitempty" yaml:"commands,omitempty"` - - // Overrides of components encapsulated in a plugin. Overriding is done using a strategic merge - Components []*DevfileComponent `json:"components,omitempty" yaml:"components,omitempty"` - - // Id in a registry that contains a Devfile yaml file - Id string `json:"id,omitempty" yaml:"id,omitempty"` - - // Reference to a Kubernetes CRD of type DevWorkspaceTemplate - Kubernetes *Kubernetes `json:"kubernetes,omitempty" yaml:"kubernetes,omitempty"` - - // Optional name that allows referencing the component in commands, or inside a parent If omitted it will be inferred from the location (uri or registryEntry) - Name string `json:"name,omitempty" yaml:"name,omitempty"` - RegistryUrl string `json:"registryUrl,omitempty" yaml:"registryUrl,omitempty"` - - // Uri of a Devfile yaml file - Uri string `json:"uri,omitempty" yaml:"uri,omitempty"` -} - -// DevfileProject project defined in devfile -type DevfileProject struct { - - // Path relative to the root of the projects to which this project should be cloned into. This is a unix-style relative path (i.e. uses forward slashes). The path is invalid if it is absolute or tries to escape the project root through the usage of '..'. If not specified, defaults to the project name. - ClonePath string `json:"clonePath,omitempty" yaml:"clonePath,omitempty"` - - // Project's Git source - Git *Git `json:"git,omitempty" yaml:"git,omitempty"` - - // Project's GitHub source - Github *Github `json:"github,omitempty" yaml:"github,omitempty"` - - // Project name - Name string `json:"name" yaml:"name"` - - // Project's Zip source - Zip *Zip `json:"zip,omitempty" yaml:"zip,omitempty"` -} - -// DevfileStarterProject getting started project -type DevfileStarterProject struct { - - // Project name - Name string `json:"name" yaml:"name"` - - // Description of a starter project - Description string `json:"description,omitempty" yaml:"description,omitempty"` - - // Project's Git source - Git *Git `json:"git,omitempty" yaml:"git,omitempty"` - - // Project's GitHub source - Github *Github `json:"github,omitempty" yaml:"github,omitempty"` - - // Project's Zip source - Zip *Zip `json:"zip,omitempty" yaml:"zip,omitempty"` - - // Sub-directory from a starter project to be used as root for starter project. - SubDir string `json:"subDir,omitempty" yaml:"subDir,omitempty"` -} - -// Volume Allows specifying the definition of a volume shared by several other components -type Volume struct { - - // Size of the volume - Size string `json:"size,omitempty" yaml:"size,omitempty"` -} - -// VolumeMount describes a path where a volume should be mounted to a component container -type VolumeMount struct { - - // The volume mount name is the name of an existing `Volume` component. If several containers mount the same volume name then they will reuse the same volume and will be able to access to the same files. - Name string `json:"name" yaml:"name"` - - // The path in the component container where the volume should be mounted. If not path is mentioned, default path is the is `/`. - Path string `json:"path,omitempty" yaml:"path,omitempty"` -} - -// Zip Project's Zip source -type Zip struct { - - // Project's source location address. Should be URL for git and github located projects, or; file:// for zip - Location string `json:"location,omitempty" yaml:"location,omitempty"` -} - -// CheckoutFrom Defines from what the project should be checked out. Required if there are more than one remote configured -type CheckoutFrom struct { - - // The remote name should be used as init. Required if there are more than one remote configured - Remote string `json:"remote,omitempty"` - - // The revision to checkout from. Should be branch name, tag or commit id. Default branch is used if missing or specified revision is not found. - Revision string `json:"revision,omitempty"` -} diff --git a/pkg/devfile/parser/data/helper_test.go b/pkg/devfile/parser/data/helper_test.go deleted file mode 100644 index 46eb42ca2..000000000 --- a/pkg/devfile/parser/data/helper_test.go +++ /dev/null @@ -1,106 +0,0 @@ -package data - -import ( - "reflect" - "strings" - "testing" - - v200 "github.com/openshift/odo/pkg/devfile/parser/data/2.0.0" -) - -func TestNewDevfileData(t *testing.T) { - - t.Run("valid devfile apiVersion", func(t *testing.T) { - - var ( - version = APIVersion200 - want = reflect.TypeOf(&v200.Devfile200{}) - obj, err = NewDevfileData(string(version)) - got = reflect.TypeOf(obj) - ) - - // got and want should be equal - if !reflect.DeepEqual(got, want) { - t.Errorf("got: '%v', want: '%s'", got, want) - } - - // no error should be received - if err != nil { - t.Errorf("did not expect an error '%v'", err) - } - }) - - t.Run("invalid devfile apiVersion", func(t *testing.T) { - - var ( - version = "invalidVersion" - _, err = NewDevfileData(string(version)) - ) - - // no error should be received - if err == nil { - t.Errorf("did not expect an error '%v'", err) - } - }) -} - -func TestGetDevfileJSONSchema(t *testing.T) { - - t.Run("valid devfile apiVersion", func(t *testing.T) { - - var ( - version = APIVersion200 - want = v200.JsonSchema200 - got, err = GetDevfileJSONSchema(string(version)) - ) - - if err != nil { - t.Errorf("did not expect an error '%v'", err) - } - - if strings.Compare(got, want) != 0 { - t.Errorf("incorrect json schema") - } - }) - - t.Run("invalid devfile apiVersion", func(t *testing.T) { - - var ( - version = "invalidVersion" - _, err = GetDevfileJSONSchema(string(version)) - ) - - if err == nil { - t.Errorf("expected an error, didn't get one") - } - }) -} - -func TestIsApiVersionSupported(t *testing.T) { - - t.Run("valid devfile apiVersion", func(t *testing.T) { - - var ( - version = APIVersion200 - want = true - got = IsApiVersionSupported(string(version)) - ) - - if got != want { - t.Errorf("want: '%t', got: '%t'", want, got) - } - }) - - t.Run("invalid devfile apiVersion", func(t *testing.T) { - - var ( - version = "invalidVersion" - want = false - got = IsApiVersionSupported(string(version)) - ) - - if got != want { - t.Errorf("expected an error, didn't get one") - } - }) -} diff --git a/pkg/devfile/parser/data/interface.go b/pkg/devfile/parser/data/interface.go deleted file mode 100644 index a1de0aa4e..000000000 --- a/pkg/devfile/parser/data/interface.go +++ /dev/null @@ -1,47 +0,0 @@ -package data - -import ( - "github.com/openshift/odo/pkg/devfile/parser/data/common" -) - -// DevfileData is an interface that defines functions for Devfile data operations -type DevfileData interface { - SetSchemaVersion(version string) - - GetMetadata() common.DevfileMetadata - SetMetadata(name, version string) - - // parent related methods - GetParent() common.DevfileParent - SetParent(parent common.DevfileParent) - - // event related methods - GetEvents() common.DevfileEvents - AddEvents(events common.DevfileEvents) error - UpdateEvents(postStart, postStop, preStart, preStop []string) - - // component related methods - GetComponents() []common.DevfileComponent - AddComponents(components []common.DevfileComponent) error - UpdateComponent(component common.DevfileComponent) - GetAliasedComponents() []common.DevfileComponent - - // project related methods - GetProjects() []common.DevfileProject - AddProjects(projects []common.DevfileProject) error - UpdateProject(project common.DevfileProject) - - // starter projects related commands - GetStarterProjects() []common.DevfileStarterProject - AddStarterProjects(projects []common.DevfileStarterProject) error - UpdateStarterProject(project common.DevfileStarterProject) - - // command related methods - GetCommands() map[string]common.DevfileCommand - AddCommands(commands ...common.DevfileCommand) error - UpdateCommand(command common.DevfileCommand) - - AddVolume(volume common.DevfileComponent, path string) error - DeleteVolume(name string) error - GetVolumeMountPath(name string) (string, error) -} diff --git a/pkg/devfile/parser/parse_test.go b/pkg/devfile/parser/parse_test.go deleted file mode 100644 index 6100520d7..000000000 --- a/pkg/devfile/parser/parse_test.go +++ /dev/null @@ -1,597 +0,0 @@ -package parser - -import ( - "net/http" - "net/http/httptest" - "reflect" - "testing" - - "github.com/ghodss/yaml" - "github.com/kylelemons/godebug/pretty" - parser "github.com/openshift/odo/pkg/devfile/parser/context" - v200 "github.com/openshift/odo/pkg/devfile/parser/data/2.0.0" - "github.com/openshift/odo/pkg/devfile/parser/data/common" -) - -const schemaV200 = "2.0.0" - -func Test_parseParent(t *testing.T) { - type args struct { - devFileObj DevfileObj - } - tests := []struct { - name string - args args - parentDevFile DevfileObj - wantDevFile DevfileObj - wantErr bool - }{ - { - name: "case 1: it should override the requested parent's data and add the local devfile's data", - args: args{ - devFileObj: DevfileObj{ - Ctx: parser.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Parent: common.DevfileParent{ - Commands: []common.DevfileCommand{ - { - Id: "devrun", - Exec: &common.Exec{ - WorkingDir: "/projects/nodejs-starter", - }, - }, - }, - Components: []common.DevfileComponent{ - { - Name: "nodejs", - Container: &common.Container{ - Image: "quay.io/nodejs-12", - }, - }, - }, - Projects: []common.DevfileProject{ - { - ClonePath: "/projects", - Name: "nodejs-starter", - }, - }, - StarterProjects: []common.DevfileStarterProject{ - { - SubDir: "/projects", - Name: "starter-project-1", - }, - }, - }, - - Commands: []common.DevfileCommand{ - { - Id: "devbuild", - Exec: &common.Exec{ - Component: "runtime", - WorkingDir: "/projects/nodejs-starter", - }, - }, - }, - Components: []common.DevfileComponent{ - { - Name: "runtime", - Container: &common.Container{ - Image: "quay.io/nodejs-12", - }, - }, - }, - Events: common.DevfileEvents{ - PostStop: []string{"post-stop"}, - }, - Projects: []common.DevfileProject{ - { - ClonePath: "/projects", - Name: "nodejs-starter-build", - }, - }, - StarterProjects: []common.DevfileStarterProject{ - { - SubDir: "/projects", - Name: "starter-project-2", - }, - }, - }, - }, - }, - parentDevFile: DevfileObj{ - Data: &v200.Devfile200{ - SchemaVersion: schemaV200, - Commands: []common.DevfileCommand{ - { - Id: "devrun", - Exec: &common.Exec{ - Component: "nodejs", - WorkingDir: "/projects", - CommandLine: "npm run", - }, - }, - }, - Components: []common.DevfileComponent{ - { - Name: "nodejs", - Container: &common.Container{ - Image: "quay.io/nodejs-10", - }, - }, - }, - Events: common.DevfileEvents{ - PostStart: []string{"post-start-0"}, - }, - Projects: []common.DevfileProject{ - { - ClonePath: "/data", - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &common.CheckoutFrom{Revision: "master"}, - }, - }, - Name: "nodejs-starter", - }, - }, - StarterProjects: []common.DevfileStarterProject{ - { - SubDir: "/data", - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &common.CheckoutFrom{Revision: "master"}, - }, - }, - Name: "starter-project-1", - }, - }, - }, - }, - wantDevFile: DevfileObj{ - Data: &v200.Devfile200{ - Commands: []common.DevfileCommand{ - { - Id: "devbuild", - Exec: &common.Exec{ - Component: "runtime", - WorkingDir: "/projects/nodejs-starter", - }, - }, - { - Id: "devrun", - Exec: &common.Exec{ - Component: "nodejs", - CommandLine: "npm run", - WorkingDir: "/projects/nodejs-starter", - }, - }, - }, - Components: []common.DevfileComponent{ - { - Name: "runtime", - Container: &common.Container{ - Image: "quay.io/nodejs-12", - }, - }, - { - Name: "nodejs", - Container: &common.Container{ - Image: "quay.io/nodejs-12", - }, - }, - }, - Events: common.DevfileEvents{ - PostStop: []string{"post-stop"}, - PostStart: []string{"post-start-0"}, - }, - Projects: []common.DevfileProject{ - { - ClonePath: "/projects", - Name: "nodejs-starter-build", - }, - { - ClonePath: "/projects", - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &common.CheckoutFrom{Revision: "master"}, - }, - }, - Name: "nodejs-starter", - }, - }, - StarterProjects: []common.DevfileStarterProject{ - { - SubDir: "/projects", - Name: "starter-project-2", - }, - { - SubDir: "/projects", - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &common.CheckoutFrom{Revision: "master"}, - }, - }, - Name: "starter-project-1", - }, - }, - }, - }, - }, - { - name: "case 2: handle a parent's data without any local override and add the local devfile's data", - args: args{ - devFileObj: DevfileObj{ - Ctx: parser.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Commands: []common.DevfileCommand{ - { - Id: "devbuild", - Exec: &common.Exec{ - Component: "runtime", - WorkingDir: "/projects/nodejs-starter", - }, - }, - }, - Components: []common.DevfileComponent{ - { - Name: "runtime", - Container: &common.Container{ - Image: "quay.io/nodejs-12", - }, - }, - }, - Events: common.DevfileEvents{ - PostStop: []string{"post-stop"}, - }, - Projects: []common.DevfileProject{ - { - ClonePath: "/projects", - Name: "nodejs-starter-build", - }, - }, - - StarterProjects: []common.DevfileStarterProject{ - { - SubDir: "/projects", - Name: "starter-project-1", - }, - }, - }, - }, - }, - parentDevFile: DevfileObj{ - Data: &v200.Devfile200{ - SchemaVersion: schemaV200, - Commands: []common.DevfileCommand{ - { - Id: "devrun", - Exec: &common.Exec{ - Component: "nodejs", - WorkingDir: "/projects", - CommandLine: "npm run", - }, - }, - }, - Components: []common.DevfileComponent{ - { - Name: "nodejs", - Container: &common.Container{ - Image: "quay.io/nodejs-10", - }, - }, - }, - Events: common.DevfileEvents{ - PostStart: []string{"post-start-0"}, - }, - Projects: []common.DevfileProject{ - { - ClonePath: "/data", - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &common.CheckoutFrom{Revision: "master"}, - }, - }, - Name: "nodejs-starter", - }, - }, - StarterProjects: []common.DevfileStarterProject{ - { - SubDir: "/data", - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &common.CheckoutFrom{Revision: "master"}, - }, - }, - Name: "starter-project-2", - }, - }, - }, - }, - wantDevFile: DevfileObj{ - Data: &v200.Devfile200{ - Commands: []common.DevfileCommand{ - { - Id: "devbuild", - Exec: &common.Exec{ - Component: "runtime", - WorkingDir: "/projects/nodejs-starter", - }, - }, - { - Id: "devrun", - Exec: &common.Exec{ - Component: "nodejs", - CommandLine: "npm run", - WorkingDir: "/projects", - }, - }, - }, - Components: []common.DevfileComponent{ - { - Name: "runtime", - Container: &common.Container{ - Image: "quay.io/nodejs-12", - }, - }, - { - Name: "nodejs", - Container: &common.Container{ - Image: "quay.io/nodejs-10", - }, - }, - }, - Events: common.DevfileEvents{ - PostStart: []string{"post-start-0"}, - PostStop: []string{"post-stop"}, - }, - Projects: []common.DevfileProject{ - { - ClonePath: "/projects", - Name: "nodejs-starter-build", - }, - { - ClonePath: "/data", - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &common.CheckoutFrom{Revision: "master"}, - }, - }, - Name: "nodejs-starter", - }, - }, - StarterProjects: []common.DevfileStarterProject{ - { - SubDir: "/projects", - Name: "starter-project-1", - }, - { - SubDir: "/data", - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &common.CheckoutFrom{Revision: "master"}, - }, - }, - Name: "starter-project-2", - }, - }, - }, - }, - }, - { - name: "case 3: it should error out when the override is invalid", - args: args{ - devFileObj: DevfileObj{ - Ctx: parser.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Parent: common.DevfileParent{ - Commands: []common.DevfileCommand{ - { - Id: "devrun", - Exec: &common.Exec{ - WorkingDir: "/projects/nodejs-starter", - }, - }, - }, - Components: []common.DevfileComponent{ - { - Name: "nodejs", - Container: &common.Container{ - Image: "quay.io/nodejs-12", - }, - }, - }, - Projects: []common.DevfileProject{ - { - ClonePath: "/projects", - Name: "nodejs-starter", - }, - }, - }, - }, - }, - }, - parentDevFile: DevfileObj{ - Data: &v200.Devfile200{ - SchemaVersion: schemaV200, - Commands: []common.DevfileCommand{}, - Components: []common.DevfileComponent{}, - Projects: []common.DevfileProject{}, - }, - }, - wantDevFile: DevfileObj{ - Data: &v200.Devfile200{}, - }, - wantErr: true, - }, - { - name: "case 4: error out if the same parent command is defined again in the local devfile", - args: args{ - devFileObj: DevfileObj{ - Ctx: parser.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Commands: []common.DevfileCommand{ - { - Id: "devbuild", - Exec: &common.Exec{ - WorkingDir: "/projects/nodejs-starter", - }, - }, - }, - }, - }, - }, - parentDevFile: DevfileObj{ - Data: &v200.Devfile200{ - SchemaVersion: schemaV200, - Commands: []common.DevfileCommand{ - { - Id: "devbuild", - Exec: &common.Exec{ - WorkingDir: "/projects/nodejs-starter", - }, - }, - }, - }, - }, - wantDevFile: DevfileObj{ - Data: &v200.Devfile200{}, - }, - wantErr: true, - }, - { - name: "case 5: error out if the same parent component is defined again in the local devfile", - args: args{ - devFileObj: DevfileObj{ - Ctx: parser.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Components: []common.DevfileComponent{ - { - Name: "runtime", - Container: &common.Container{ - Image: "quay.io/nodejs-12", - }, - }, - }, - }, - }, - }, - parentDevFile: DevfileObj{ - Data: &v200.Devfile200{ - SchemaVersion: schemaV200, - Components: []common.DevfileComponent{ - { - Name: "runtime", - Container: &common.Container{ - Image: "quay.io/nodejs-12", - }, - }, - }, - }, - }, - wantDevFile: DevfileObj{ - Data: &v200.Devfile200{}, - }, - wantErr: true, - }, - { - name: "case 6: error out if the same event is defined again in the local devfile", - args: args{ - devFileObj: DevfileObj{ - Ctx: parser.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Events: common.DevfileEvents{ - PostStop: []string{"post-stop"}, - }, - }, - }, - }, - parentDevFile: DevfileObj{ - Data: &v200.Devfile200{ - SchemaVersion: schemaV200, - Events: common.DevfileEvents{ - PostStop: []string{"post-stop"}, - }, - }, - }, - wantDevFile: DevfileObj{ - Data: &v200.Devfile200{}, - }, - wantErr: true, - }, - { - name: "case 7: error out if the same project is defined again in the local devfile", - args: args{ - devFileObj: DevfileObj{ - Ctx: parser.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Projects: []common.DevfileProject{ - { - ClonePath: "/projects", - Name: "nodejs-starter-build", - }, - }, - }, - }, - }, - parentDevFile: DevfileObj{ - Data: &v200.Devfile200{ - SchemaVersion: schemaV200, - Projects: []common.DevfileProject{ - { - ClonePath: "/projects", - Name: "nodejs-starter-build", - }, - }, - }, - }, - wantDevFile: DevfileObj{ - Data: &v200.Devfile200{}, - }, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - - testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - data, err := yaml.Marshal(tt.parentDevFile.Data) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - _, err = w.Write(data) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - })) - - defer testServer.Close() - - parent := tt.args.devFileObj.Data.GetParent() - parent.Uri = testServer.URL - - tt.args.devFileObj.Data.SetParent(parent) - tt.wantDevFile.Data.SetParent(parent) - - err := parseParent(tt.args.devFileObj) - - if (err != nil) != tt.wantErr { - t.Errorf("parseParent() error = %v, wantErr %v", err, tt.wantErr) - } - - if tt.wantErr && err != nil { - return - } - - if !reflect.DeepEqual(tt.args.devFileObj.Data, tt.wantDevFile.Data) { - t.Errorf("wanted: %v, got: %v, difference at %v", tt.wantDevFile, tt.args.devFileObj, pretty.Compare(tt.args.devFileObj.Data, tt.wantDevFile.Data)) - } - }) - } -} diff --git a/pkg/devfile/parser/types_test.go b/pkg/devfile/parser/types_test.go deleted file mode 100644 index f86477c1d..000000000 --- a/pkg/devfile/parser/types_test.go +++ /dev/null @@ -1,1044 +0,0 @@ -package parser - -import ( - "reflect" - "testing" - - "github.com/kylelemons/godebug/pretty" - devfileCtx "github.com/openshift/odo/pkg/devfile/parser/context" - v200 "github.com/openshift/odo/pkg/devfile/parser/data/2.0.0" - "github.com/openshift/odo/pkg/devfile/parser/data/common" - "github.com/openshift/odo/pkg/testingutil" -) - -const devfileTempPath = "devfile.yaml" - -func TestDevfileObj_OverrideCommands(t *testing.T) { - componentName0 := "component-0" - overrideComponent0 := "override-component-0" - - commandLineBuild := "npm build" - overrideBuild := "npm custom build" - commandLineRun := "npm run" - - workingDir := "/project" - overrideWorkingDir := "/data" - - type args struct { - overridePatch []common.DevfileCommand - } - tests := []struct { - name string - devFileObj DevfileObj - args args - wantDevFileObj DevfileObj - wantErr bool - }{ - { - name: "case 1: override a command's non list/map fields", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Commands: []common.DevfileCommand{ - { - Id: "devbuild", - Exec: &common.Exec{ - CommandLine: commandLineBuild, - Component: componentName0, - Env: nil, - Group: &common.Group{ - IsDefault: false, - Kind: common.BuildCommandGroupType, - }, - WorkingDir: workingDir, - }, - }, - }, - }, - }, - args: args{ - overridePatch: []common.DevfileCommand{ - { - Id: "devbuild", - Exec: &common.Exec{ - CommandLine: overrideBuild, - Component: overrideComponent0, - Group: &common.Group{ - IsDefault: true, - Kind: common.BuildCommandGroupType, - }, - WorkingDir: overrideWorkingDir, - }, - }, - }, - }, - wantDevFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Commands: []common.DevfileCommand{ - { - Id: "devbuild", - Exec: &common.Exec{ - CommandLine: overrideBuild, - Component: overrideComponent0, - Group: &common.Group{ - IsDefault: true, - Kind: common.BuildCommandGroupType, - }, - WorkingDir: overrideWorkingDir, - }, - }, - }, - }, - }, - }, - { - name: "case 2: append/override a command's list fields based on the key", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Commands: []common.DevfileCommand{ - { - Id: "devbuild", - Exec: &common.Exec{ - Attributes: map[string]string{ - "key-0": "value-0", - }, - Env: []common.Env{ - testingutil.GetFakeEnv("env-0", "value-0"), - }, - }, - }, - }, - }, - }, - args: args{ - overridePatch: []common.DevfileCommand{ - { - Id: "devbuild", - Exec: &common.Exec{ - Attributes: map[string]string{ - "key-1": "value-1", - }, - Env: []common.Env{ - testingutil.GetFakeEnv("env-0", "value-0-0"), - testingutil.GetFakeEnv("env-1", "value-1"), - }, - }, - }, - }, - }, - wantDevFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Commands: []common.DevfileCommand{ - { - Id: "devbuild", - Exec: &common.Exec{ - Attributes: map[string]string{ - "key-0": "value-0", - "key-1": "value-1", - }, - Env: []common.Env{ - testingutil.GetFakeEnv("env-0", "value-0-0"), - testingutil.GetFakeEnv("env-1", "value-1"), - }, - }, - }, - }, - }, - }, - }, - { - name: "case 3: if multiple, override the correct command", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Commands: []common.DevfileCommand{ - { - Id: "devbuild", - Exec: &common.Exec{ - CommandLine: commandLineBuild, - }, - }, - { - Id: "devrun", - Exec: &common.Exec{ - CommandLine: commandLineRun, - }, - }, - }, - }, - }, - args: args{ - overridePatch: []common.DevfileCommand{ - { - Id: "devbuild", - Exec: &common.Exec{ - CommandLine: overrideBuild, - }, - }, - }, - }, - wantDevFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Commands: []common.DevfileCommand{ - { - Id: "devbuild", - Exec: &common.Exec{ - CommandLine: overrideBuild, - }, - }, - { - Id: "devrun", - Exec: &common.Exec{ - CommandLine: commandLineRun, - }, - }, - }, - }, - }, - wantErr: false, - }, - { - name: "case 4: throw error if command to override is not found", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Commands: []common.DevfileCommand{ - { - Id: "devbuild", - Exec: &common.Exec{ - Env: []common.Env{ - testingutil.GetFakeEnv("env-0", "value-0"), - }, - }, - }, - }, - }, - }, - args: args{ - overridePatch: []common.DevfileCommand{ - { - Id: "devbuild-custom", - Exec: &common.Exec{ - Env: []common.Env{ - testingutil.GetFakeEnv("env-0", "value-0-0"), - testingutil.GetFakeEnv("env-1", "value-1"), - }, - }, - }, - }, - }, - wantDevFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Commands: []common.DevfileCommand{}, - }, - }, - wantErr: true, - }, - { - name: "case 6: override a composite command", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Commands: []common.DevfileCommand{ - { - Id: "exec1", - Exec: &common.Exec{ - CommandLine: commandLineBuild, - }, - }, - { - Id: "exec2", - Exec: &common.Exec{ - CommandLine: commandLineBuild, - }, - }, - { - Id: "exec3", - Exec: &common.Exec{ - CommandLine: commandLineBuild, - }, - }, - { - Id: "mycomposite", - Composite: &common.Composite{ - Commands: []string{"exec1", "exec2"}, - }, - }, - }, - }, - }, - args: args{ - overridePatch: []common.DevfileCommand{ - { - Id: "mycomposite", - Composite: &common.Composite{ - Commands: []string{"exec1", "exec3"}, - }, - }, - }, - }, - wantDevFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Commands: []common.DevfileCommand{ - { - Id: "exec1", - Exec: &common.Exec{ - CommandLine: commandLineBuild, - }, - }, - { - Id: "exec2", - Exec: &common.Exec{ - CommandLine: commandLineBuild, - }, - }, - { - Id: "exec3", - Exec: &common.Exec{ - CommandLine: commandLineBuild, - }, - }, - { - Id: "mycomposite", - Composite: &common.Composite{ - Commands: []string{"exec1", "exec3"}, - }, - }, - }, - }, - }, - }, - { - name: "case 7: throw error if trying to overide command with different type", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Commands: []common.DevfileCommand{ - { - Id: "devbuild", - Exec: &common.Exec{ - Env: []common.Env{ - testingutil.GetFakeEnv("env-0", "value-0"), - }, - }, - }, - }, - }, - }, - args: args{ - overridePatch: []common.DevfileCommand{ - { - Id: "devbuild", - Composite: &common.Composite{}, - }, - }, - }, - wantDevFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Commands: []common.DevfileCommand{}, - }, - }, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := tt.devFileObj.OverrideCommands(tt.args.overridePatch) - - if (err != nil) != tt.wantErr { - t.Errorf("OverrideCommands() error = %v, wantErr %v", err, tt.wantErr) - return - } - - if tt.wantErr && err != nil { - return - } - - if !reflect.DeepEqual(tt.wantDevFileObj, tt.devFileObj) { - t.Errorf("expected devfile and got devfile are different: %v", pretty.Compare(tt.wantDevFileObj, tt.devFileObj)) - } - }) - } -} - -func TestDevfileObj_OverrideComponents(t *testing.T) { - - containerImage0 := "image-0" - containerImage1 := "image-1" - - overrideContainerImage := "image-0-override" - - type args struct { - overridePatch []common.DevfileComponent - } - tests := []struct { - name string - devFileObj DevfileObj - args args - wantDevFileObj DevfileObj - wantErr bool - }{ - { - name: "case 1: override a container's non list/map fields", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Components: []common.DevfileComponent{ - { - Name: "nodejs", - Container: &common.Container{ - Args: []string{"arg-0", "arg-1"}, - Command: []string{"cmd-0", "cmd-1"}, - Image: containerImage0, - MemoryLimit: "512Mi", - MountSources: false, - SourceMapping: "/source", - }, - }, - }, - }, - }, - args: args{ - overridePatch: []common.DevfileComponent{ - { - Name: "nodejs", - Container: &common.Container{ - Args: []string{"arg-0-0", "arg-1-1"}, - Command: []string{"cmd-0-0", "cmd-1-1"}, - Image: overrideContainerImage, - MemoryLimit: "1Gi", - MountSources: true, - SourceMapping: "/data", - }, - }, - }, - }, - wantDevFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Components: []common.DevfileComponent{ - { - Name: "nodejs", - Container: &common.Container{ - Args: []string{"arg-0-0", "arg-1-1"}, - Command: []string{"cmd-0-0", "cmd-1-1"}, - Image: overrideContainerImage, - MemoryLimit: "1Gi", - MountSources: true, - SourceMapping: "/data", - }, - }, - }, - }, - }, - wantErr: false, - }, - { - name: "case 2: append/override a command's list fields based on the key", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Components: []common.DevfileComponent{ - { - Name: "nodejs", - Container: &common.Container{ - Endpoints: []common.Endpoint{ - { - Attributes: map[string]string{ - "key-0": "value-0", - "key-1": "value-1", - }, - Name: "endpoint-0", - TargetPort: 8080, - }, - }, - Env: []common.Env{ - testingutil.GetFakeEnv("env-0", "value-0"), - }, - VolumeMounts: []common.VolumeMount{ - testingutil.GetFakeVolumeMount("volume-0", "path-0"), - }, - }, - }, - }, - }, - }, - args: args{ - overridePatch: []common.DevfileComponent{ - { - Name: "nodejs", - Container: &common.Container{ - Endpoints: []common.Endpoint{ - { - Attributes: map[string]string{ - "key-1": "value-1-1", - "key-append": "value-append", - }, - Name: "endpoint-0", - TargetPort: 9090, - }, - { - Attributes: map[string]string{ - "key-0": "value-0", - }, - Name: "endpoint-1", - TargetPort: 3000, - }, - }, - Env: []common.Env{ - testingutil.GetFakeEnv("env-0", "value-0-0"), - testingutil.GetFakeEnv("env-1", "value-1"), - }, - VolumeMounts: []common.VolumeMount{ - testingutil.GetFakeVolumeMount("volume-0", "path-0-0"), - testingutil.GetFakeVolumeMount("volume-1", "path-1"), - }, - }, - }, - }, - }, - wantDevFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Components: []common.DevfileComponent{ - { - Name: "nodejs", - Container: &common.Container{ - Env: []common.Env{ - testingutil.GetFakeEnv("env-0", "value-0-0"), - testingutil.GetFakeEnv("env-1", "value-1"), - }, - VolumeMounts: []common.VolumeMount{ - testingutil.GetFakeVolumeMount("volume-0", "path-0-0"), - testingutil.GetFakeVolumeMount("volume-1", "path-1"), - }, - Endpoints: []common.Endpoint{ - { - Attributes: map[string]string{ - "key-0": "value-0", - "key-1": "value-1-1", - "key-append": "value-append", - }, - Name: "endpoint-0", - TargetPort: 9090, - }, - { - Attributes: map[string]string{ - "key-0": "value-0", - }, - Name: "endpoint-1", - TargetPort: 3000, - }, - }, - }, - }, - }, - }, - }, - wantErr: false, - }, - { - name: "case 3: if multiple, override the correct command", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Components: []common.DevfileComponent{ - { - Name: "nodejs", - Container: &common.Container{ - Image: containerImage0, - }, - }, - { - Name: "runtime", - Container: &common.Container{ - Image: containerImage1, - }, - }, - }, - }, - }, - args: args{ - overridePatch: []common.DevfileComponent{ - { - Name: "nodejs", - Container: &common.Container{ - Image: overrideContainerImage, - }, - }, - { - Name: "runtime", - Container: &common.Container{ - Image: containerImage1, - }, - }, - }, - }, - wantDevFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Components: []common.DevfileComponent{ - { - Name: "nodejs", - Container: &common.Container{ - Image: overrideContainerImage, - }, - }, - { - Name: "runtime", - Container: &common.Container{ - Image: containerImage1, - }, - }, - }, - }, - }, - wantErr: false, - }, - { - name: "case 4: throw error if component to override is not found", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Components: []common.DevfileComponent{ - { - Name: "nodejs", - Container: &common.Container{ - Image: containerImage0, - }, - }, - }, - }, - }, - args: args{ - overridePatch: []common.DevfileComponent{ - { - Name: "nodejs-custom", - Container: &common.Container{ - Image: containerImage0, - }, - }, - }, - }, - wantDevFileObj: DevfileObj{}, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := tt.devFileObj.OverrideComponents(tt.args.overridePatch) - if (err != nil) != tt.wantErr { - t.Errorf("OverrideComponents() error = %v, wantErr %v", err, tt.wantErr) - } - - if tt.wantErr && err != nil { - return - } - - if !reflect.DeepEqual(tt.wantDevFileObj, tt.devFileObj) { - t.Errorf("expected devfile and got devfile are different: %v", pretty.Compare(tt.wantDevFileObj, tt.devFileObj)) - } - }) - } -} - -func TestDevfileObj_OverrideProjects(t *testing.T) { - projectName0 := "project-0" - projectName1 := "project-1" - - type args struct { - overridePatch []common.DevfileProject - } - tests := []struct { - name string - devFileObj DevfileObj - wantDevFileObj DevfileObj - args args - wantErr bool - }{ - { - name: "case 1: override a project's fields", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Projects: []common.DevfileProject{ - { - ClonePath: "/data", - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &common.CheckoutFrom{Revision: "master"}, - }, - }, - Name: projectName0, - Zip: nil, - }, - }, - }, - }, - args: args{ - overridePatch: []common.DevfileProject{ - { - ClonePath: "/source", - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &common.CheckoutFrom{Revision: "release-1.0.0"}, - }, - }, - Name: projectName0, - Zip: nil, - }, - }, - }, - wantDevFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Projects: []common.DevfileProject{ - { - ClonePath: "/source", - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &common.CheckoutFrom{Revision: "release-1.0.0"}, - }, - }, - Name: projectName0, - Zip: nil, - }, - }, - }, - }, - }, - { - name: "case 2: if multiple, override the correct project", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Projects: []common.DevfileProject{ - { - ClonePath: "/data", - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &common.CheckoutFrom{Revision: "master"}, - }, - }, - Name: projectName0, - Zip: nil, - }, - { - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &common.CheckoutFrom{Revision: "master"}, - }, - }, - Name: projectName1, - }, - }, - }, - }, - args: args{ - overridePatch: []common.DevfileProject{ - { - ClonePath: "/source", - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &common.CheckoutFrom{Revision: "release-1.0.0"}, - }, - }, - Name: projectName0, - Zip: nil, - }, - }, - }, - wantDevFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Projects: []common.DevfileProject{ - { - ClonePath: "/source", - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &common.CheckoutFrom{Revision: "release-1.0.0"}, - }, - }, - Name: projectName0, - Zip: nil, - }, - { - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &common.CheckoutFrom{Revision: "master"}, - }, - }, - Name: projectName1, - }, - }, - }, - }, - }, - { - name: "case 3: throw error if project to override is not found", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - Projects: []common.DevfileProject{ - { - ClonePath: "/data", - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &common.CheckoutFrom{Revision: "master"}, - }, - }, - Name: projectName0, - Zip: nil, - }, - }, - }, - }, - args: args{ - overridePatch: []common.DevfileProject{ - { - ClonePath: "/source", - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &common.CheckoutFrom{Revision: "release-1.0.0"}, - }, - }, - Name: "custom-project", - Zip: nil, - }, - }, - }, - wantDevFileObj: DevfileObj{}, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := tt.devFileObj.OverrideProjects(tt.args.overridePatch) - - if (err != nil) != tt.wantErr { - t.Errorf("OverrideProjects() error = %v, wantErr %v", err, tt.wantErr) - return - } - - if tt.wantErr && err != nil { - return - } - - if !reflect.DeepEqual(tt.wantDevFileObj, tt.devFileObj) { - t.Errorf("expected devfile and got devfile are different: %v", pretty.Compare(tt.wantDevFileObj, tt.devFileObj)) - } - }) - } -} - -func TestDevfileObj_OverrideStarterProjects(t *testing.T) { - projectName1 := "starter-1" - projectName2 := "starter-2" - - type args struct { - overridePatch []common.DevfileStarterProject - } - tests := []struct { - name string - devFileObj DevfileObj - wantDevFileObj DevfileObj - args args - wantErr bool - }{ - { - name: "Case 1: override a starter projects fields", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - StarterProjects: []common.DevfileStarterProject{ - { - SubDir: "/data", - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &common.CheckoutFrom{Revision: "master"}, - }, - }, - Name: projectName1, - }, - }, - }, - }, - args: args{ - overridePatch: []common.DevfileStarterProject{ - { - SubDir: "/source", - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &common.CheckoutFrom{Revision: "release-1.0.0"}, - }, - }, - Name: projectName1, - Zip: nil, - }, - }, - }, - wantDevFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - StarterProjects: []common.DevfileStarterProject{ - { - SubDir: "/source", - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &common.CheckoutFrom{Revision: "release-1.0.0"}, - }, - }, - Name: projectName1, - }, - }, - }, - }, - }, - { - name: "Case 2: if multiple, override the correct starter project", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - StarterProjects: []common.DevfileStarterProject{ - { - SubDir: "/data", - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &common.CheckoutFrom{Revision: "master"}, - }, - }, - Name: projectName1, - }, - { - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &common.CheckoutFrom{Revision: "master"}, - }, - }, - Name: projectName2, - }, - }, - }, - }, - args: args{ - overridePatch: []common.DevfileStarterProject{ - { - SubDir: "/source", - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &common.CheckoutFrom{Revision: "release-1.0.0"}, - }, - }, - Name: projectName1, - }, - }, - }, - wantDevFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - StarterProjects: []common.DevfileStarterProject{ - { - SubDir: "/source", - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &common.CheckoutFrom{Revision: "release-1.0.0"}, - }, - }, - Name: projectName1, - Zip: nil, - }, - { - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &common.CheckoutFrom{Revision: "master"}, - }, - }, - Name: projectName2, - }, - }, - }, - }, - }, - { - name: "Case 3: throw error if starter project to override is not found", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v200.Devfile200{ - StarterProjects: []common.DevfileStarterProject{ - { - SubDir: "/data", - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &common.CheckoutFrom{Revision: "master"}, - }, - }, - Name: projectName1, - Zip: nil, - }, - }, - }, - }, - args: args{ - overridePatch: []common.DevfileStarterProject{ - { - SubDir: "/source", - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &common.CheckoutFrom{Revision: "release-1.0.0"}, - }, - }, - Name: "custom-starter-project", - Zip: nil, - }, - }, - }, - wantDevFileObj: DevfileObj{}, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := tt.devFileObj.OverrideStarterProjects(tt.args.overridePatch) - - if (err != nil) != tt.wantErr { - t.Errorf("OverrideStarterProjects() error = %v, wantErr %v", err, tt.wantErr) - return - } - - if tt.wantErr && err != nil { - return - } - - if !reflect.DeepEqual(tt.wantDevFileObj, tt.devFileObj) { - t.Errorf("expected devfile and got devfile are different: %v", pretty.Compare(tt.wantDevFileObj, tt.devFileObj)) - } - }) - } -} diff --git a/pkg/devfile/parser/writer_test.go b/pkg/devfile/parser/writer_test.go deleted file mode 100644 index a579f7827..000000000 --- a/pkg/devfile/parser/writer_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package parser - -import ( - "testing" - - devfileCtx "github.com/openshift/odo/pkg/devfile/parser/context" - v200 "github.com/openshift/odo/pkg/devfile/parser/data/2.0.0" - "github.com/openshift/odo/pkg/devfile/parser/data/common" - "github.com/openshift/odo/pkg/testingutil/filesystem" -) - -func TestWriteJsonDevfile(t *testing.T) { - - var ( - schemaVersion = "2.0.0" - testName = "TestName" - ) - - t.Run("write json devfile", func(t *testing.T) { - - // Use fakeFs - fs := filesystem.NewFakeFs() - - // DevfileObj - devfileObj := DevfileObj{ - Ctx: devfileCtx.FakeContext(fs, OutputDevfileJsonPath), - Data: &v200.Devfile200{ - SchemaVersion: schemaVersion, - Metadata: common.DevfileMetadata{ - Name: testName, - }, - }, - } - - // test func() - err := devfileObj.WriteJsonDevfile() - if err != nil { - t.Errorf("unexpected error: '%v'", err) - } - - if _, err := fs.Stat(OutputDevfileJsonPath); err != nil { - t.Errorf("unexpected error: '%v'", err) - } - }) - - t.Run("write yaml devfile", func(t *testing.T) { - - // Use fakeFs - fs := filesystem.NewFakeFs() - - // DevfileObj - devfileObj := DevfileObj{ - Ctx: devfileCtx.FakeContext(fs, OutputDevfileYamlPath), - Data: &v200.Devfile200{ - SchemaVersion: schemaVersion, - Metadata: common.DevfileMetadata{ - Name: testName, - }, - }, - } - - // test func() - err := devfileObj.WriteYamlDevfile() - if err != nil { - t.Errorf("unexpected error: '%v'", err) - } - - if _, err := fs.Stat(OutputDevfileYamlPath); err != nil { - t.Errorf("unexpected error: '%v'", err) - } - }) -} diff --git a/pkg/devfile/validate/commands.go b/pkg/devfile/validate/commands.go index 779d37a73..012cd4989 100644 --- a/pkg/devfile/validate/commands.go +++ b/pkg/devfile/validate/commands.go @@ -1,13 +1,13 @@ package validate import ( - "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" ) // validateCommands validates the devfile commands: // 1. checks if its either an exec or composite command // 2. checks if the composite is a non run kind command -func validateCommands(commandsMap map[string]common.DevfileCommand) (err error) { +func validateCommands(commandsMap map[string]devfilev1.Command) (err error) { for _, command := range commandsMap { err = validateCommand(command) @@ -22,7 +22,7 @@ func validateCommands(commandsMap map[string]common.DevfileCommand) (err error) // validateCommand validates the given command // 1. command has to be of type exec or composite, // 2. if composite command, it should not be of kind run -func validateCommand(command common.DevfileCommand) (err error) { +func validateCommand(command devfilev1.Command) (err error) { // devfile command type for odo must be exec or composite if command.Exec == nil && command.Composite == nil { @@ -38,8 +38,8 @@ func validateCommand(command common.DevfileCommand) (err error) { } // validateCompositeCommand checks that the specified composite command is valid in odo ie; it should not be of kind run -func validateCompositeCommand(command common.DevfileCommand) error { - if command.Composite.Group != nil && command.Composite.Group.Kind == common.RunCommandGroupType { +func validateCompositeCommand(command devfilev1.Command) error { + if command.Composite.Group != nil && command.Composite.Group.Kind == devfilev1.RunCommandGroupKind { return &CompositeRunKindError{} } diff --git a/pkg/devfile/validate/commands_test.go b/pkg/devfile/validate/commands_test.go index b91c544da..f215b5bad 100644 --- a/pkg/devfile/validate/commands_test.go +++ b/pkg/devfile/validate/commands_test.go @@ -3,43 +3,57 @@ package validate import ( "testing" - "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" ) -var buildGroup = common.BuildCommandGroupType -var runGroup = common.RunCommandGroupType +var buildGroup = devfilev1.BuildCommandGroupKind +var runGroup = devfilev1.RunCommandGroupKind func TestValidateCommand(t *testing.T) { tests := []struct { name string - command common.DevfileCommand + command devfilev1.Command wantErr bool }{ { name: "Case 1: Valid Exec Command", - command: common.DevfileCommand{ - Id: "somecommand", - Exec: &common.Exec{}, + command: devfilev1.Command{ + Id: "somecommand", + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{}, + }, }, wantErr: false, }, { name: "Case 2: Valid Composite Command", - command: common.DevfileCommand{ + command: devfilev1.Command{ Id: "composite1", - Composite: &common.Composite{ - Group: &common.Group{Kind: buildGroup, IsDefault: true}, + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup, IsDefault: true}, + }, + }, + }, }, }, wantErr: false, }, { name: "Case 3: Invalid Composite Command with Run Kind", - command: common.DevfileCommand{ + command: devfilev1.Command{ Id: "composite1", - Composite: &common.Composite{ - Group: &common.Group{Kind: runGroup, IsDefault: true}, + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup, IsDefault: true}, + }, + }, + }, }, }, wantErr: true, @@ -61,26 +75,38 @@ func TestValidateCompositeCommand(t *testing.T) { tests := []struct { name string - command common.DevfileCommand + command devfilev1.Command wantErr bool }{ { name: "Case 1: Valid Composite Command", - command: common.DevfileCommand{ + command: devfilev1.Command{ Id: "command1", - Composite: &common.Composite{ - Group: &common.Group{Kind: buildGroup}, + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup}, + }, + }, + }, }, }, wantErr: false, }, { name: "Case 2: Invalid Composite Run Kind Command", - command: common.DevfileCommand{ + command: devfilev1.Command{ Id: "command1", - Composite: &common.Composite{ - Group: &common.Group{Kind: runGroup}, + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + }, }, }, wantErr: true, diff --git a/pkg/devfile/validate/components.go b/pkg/devfile/validate/components.go index dc7cee6d1..454d30de8 100644 --- a/pkg/devfile/validate/components.go +++ b/pkg/devfile/validate/components.go @@ -1,13 +1,13 @@ package validate import ( - "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" ) // validateComponents validates the devfile components: // 1. there should be at least one component // 2. there should be at least one container component -func validateComponents(components []common.DevfileComponent) error { +func validateComponents(components []devfilev1.Component) error { // components cannot be empty if len(components) < 1 { diff --git a/pkg/devfile/validate/components_test.go b/pkg/devfile/validate/components_test.go index be71819b1..46a2297e2 100644 --- a/pkg/devfile/validate/components_test.go +++ b/pkg/devfile/validate/components_test.go @@ -4,7 +4,7 @@ import ( "reflect" "testing" - "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" ) func TestValidateComponents(t *testing.T) { @@ -12,7 +12,7 @@ func TestValidateComponents(t *testing.T) { t.Run("No components present", func(t *testing.T) { // Empty components - components := []common.DevfileComponent{} + components := []devfilev1.Component{} got := validateComponents(components) want := &NoComponentsError{} @@ -24,11 +24,15 @@ func TestValidateComponents(t *testing.T) { t.Run("Container type component present", func(t *testing.T) { - components := []common.DevfileComponent{ + components := []devfilev1.Component{ { Name: "container", - Container: &common.Container{ - Image: "image", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "image", + }, + }, }, }, } diff --git a/pkg/devfile/validate/errors.go b/pkg/devfile/validate/errors.go index a31fd4542..e3cc0ec7a 100644 --- a/pkg/devfile/validate/errors.go +++ b/pkg/devfile/validate/errors.go @@ -3,7 +3,7 @@ package validate import ( "fmt" - "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" ) // NoComponentsError returns an error if no component is found @@ -19,7 +19,7 @@ type NoContainerComponentError struct { } func (e *NoContainerComponentError) Error() string { - return fmt.Sprintf("odo requires atleast one component of type '%s' in devfile", common.ContainerComponentType) + return fmt.Sprintf("odo requires atleast one component of type '%s' in devfile", devfilev1.ContainerComponentType) } // UnsupportedOdoCommandError returns an error if the command is neither exec nor composite diff --git a/pkg/devfile/validate/generic/commands.go b/pkg/devfile/validate/generic/commands.go index 8df99e78f..2e94c834f 100644 --- a/pkg/devfile/validate/generic/commands.go +++ b/pkg/devfile/validate/generic/commands.go @@ -4,19 +4,20 @@ import ( "fmt" "strings" - "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + parsercommon "github.com/devfile/library/pkg/devfile/parser/data/v2/common" ) // validateCommands validates the devfile commands: // 1. if there are commands with duplicate IDs, an error is returned // 2. checks if its either a valid exec or composite command -func validateCommands(commands []common.DevfileCommand, commandsMap map[string]common.DevfileCommand, components []common.DevfileComponent) (err error) { +func validateCommands(commands []devfilev1.Command, commandsMap map[string]devfilev1.Command, components []devfilev1.Component) (err error) { processedCommands := make(map[string]string, len(commands)) for _, command := range commands { // Check if the command is in the list of already processed commands // If there's a hit, it means more than one command share the same ID and we should error out - commandID := command.SetIDToLower() + commandID := strings.ToLower(command.Id) if _, exists := processedCommands[commandID]; exists { return &InvalidCommandError{commandId: command.Id, reason: "duplicate commands present with the same id"} } @@ -32,7 +33,7 @@ func validateCommands(commands []common.DevfileCommand, commandsMap map[string]c } // validateCommand validates a given devfile command -func validateCommand(command common.DevfileCommand, devfileCommands map[string]common.DevfileCommand, components []common.DevfileComponent) (err error) { +func validateCommand(command devfilev1.Command, devfileCommands map[string]devfilev1.Command, components []devfilev1.Component) (err error) { // If the command is a composite command, need to validate that it is valid if command.Composite != nil { @@ -47,7 +48,7 @@ func validateCommand(command common.DevfileCommand, devfileCommands map[string]c // 1. have a component // 2. have a command line // 3. map to a valid container component -func validateExecCommand(command common.DevfileCommand, components []common.DevfileComponent) (err error) { +func validateExecCommand(command devfilev1.Command, components []devfilev1.Component) (err error) { if command.Exec == nil { return &InvalidCommandError{commandId: command.Id, reason: "should be of type exec"} @@ -57,12 +58,12 @@ func validateExecCommand(command common.DevfileCommand, components []common.Devf // since these are required fields in a devfile.yaml // component must be specified - if command.GetExecComponent() == "" { + if parsercommon.GetExecComponent(command) == "" { return &InvalidCommandError{commandId: command.Id, reason: "command must reference a component"} } // must specify a command - if command.GetExecCommandLine() == "" { + if parsercommon.GetExecCommandLine(command) == "" { return &InvalidCommandError{commandId: command.Id, reason: "command must have a commandLine"} } @@ -85,7 +86,7 @@ func validateExecCommand(command common.DevfileCommand, components []common.Devf // 2. should not indirectly reference itself via a subcommand which is a composite command // 3. should reference a valid devfile command // 4. should have a valid exec sub command -func validateCompositeCommand(command *common.DevfileCommand, parentCommands map[string]string, devfileCommands map[string]common.DevfileCommand, components []common.DevfileComponent) error { +func validateCompositeCommand(command *devfilev1.Command, parentCommands map[string]string, devfileCommands map[string]devfilev1.Command, components []devfilev1.Component) error { // Store the command ID in a map of parent commands parentCommands[command.Id] = command.Id diff --git a/pkg/devfile/validate/generic/commands_test.go b/pkg/devfile/validate/generic/commands_test.go index a827eb3f9..7d2c1fc59 100644 --- a/pkg/devfile/validate/generic/commands_test.go +++ b/pkg/devfile/validate/generic/commands_test.go @@ -3,13 +3,13 @@ package generic import ( "testing" - devfileParser "github.com/openshift/odo/pkg/devfile/parser" - "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + devfileParser "github.com/devfile/library/pkg/devfile/parser" "github.com/openshift/odo/pkg/testingutil" ) -var buildGroup = common.BuildCommandGroupType -var runGroup = common.RunCommandGroupType +var buildGroup = devfilev1.BuildCommandGroupKind +var runGroup = devfilev1.RunCommandGroupKind func TestValidateCommands(t *testing.T) { @@ -19,20 +19,26 @@ func TestValidateCommands(t *testing.T) { tests := []struct { name string - exec []common.DevfileCommand - comp []common.DevfileCommand + exec []devfilev1.Command + comp []devfilev1.Command wantErr bool }{ { name: "Case 1: Valid Exec Command", - exec: []common.DevfileCommand{ + exec: []devfilev1.Command{ { Id: "somecommand", - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &common.Group{Kind: runGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, + }, }, }, }, @@ -40,30 +46,40 @@ func TestValidateCommands(t *testing.T) { }, { name: "Case 6: Valid Composite Command", - exec: []common.DevfileCommand{ + exec: []devfilev1.Command{ { Id: "somecommand1", - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + CommandLine: command, + Component: component, + WorkingDir: workDir, + }, }, }, { Id: "somecommand2", - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + CommandLine: command, + Component: component, + WorkingDir: workDir, + }, }, }, }, - comp: []common.DevfileCommand{ + comp: []devfilev1.Command{ { Id: "composite1", - Composite: &common.Composite{ - Commands: []string{"somecommand1", "somecommand2"}, - Group: &common.Group{Kind: buildGroup, IsDefault: true}, + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup, IsDefault: true}, + }, + }, + Commands: []string{"somecommand1", "somecommand2"}, + }, }, }, }, @@ -71,29 +87,35 @@ func TestValidateCommands(t *testing.T) { }, { name: "Case 8: Duplicate commands", - exec: []common.DevfileCommand{ + exec: []devfilev1.Command{ { Id: "somecommand1", - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + CommandLine: command, + Component: component, + WorkingDir: workDir, + }, }, }, { Id: "somecommand1", - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + CommandLine: command, + Component: component, + WorkingDir: workDir, + }, }, }, { Id: "somecommand2", - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + CommandLine: command, + Component: component, + WorkingDir: workDir, + }, }, }, }, @@ -101,30 +123,40 @@ func TestValidateCommands(t *testing.T) { }, { name: "Case 9: Duplicate commands, different types", - exec: []common.DevfileCommand{ + exec: []devfilev1.Command{ { Id: "somecommand1", - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + CommandLine: command, + Component: component, + WorkingDir: workDir, + }, }, }, { Id: "somecommand2", - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + CommandLine: command, + Component: component, + WorkingDir: workDir, + }, }, }, }, - comp: []common.DevfileCommand{ + comp: []devfilev1.Command{ { Id: "somecommand1", - Composite: &common.Composite{ - Commands: []string{"fakecommand"}, - Group: &common.Group{Kind: buildGroup, IsDefault: true}, + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup, IsDefault: true}, + }, + }, + Commands: []string{"fakecommand"}, + }, }, }, }, @@ -134,7 +166,7 @@ func TestValidateCommands(t *testing.T) { for _, tt := range tests { devfileData := testingutil.TestDevfileData{ Commands: append(tt.comp, tt.exec...), - Components: []common.DevfileComponent{testingutil.GetFakeContainerComponent(component)}, + Components: []devfilev1.Component{testingutil.GetFakeContainerComponent(component)}, } devObj := devfileParser.DevfileObj{ Data: &devfileData, @@ -163,69 +195,95 @@ func TestValidateExecCommand(t *testing.T) { tests := []struct { name string - exec common.DevfileCommand + exec devfilev1.Command wantErr bool }{ { name: "Case 1: Valid Exec Command", - exec: common.DevfileCommand{ + exec: devfilev1.Command{ Id: "somecommand", - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, - Group: &common.Group{Kind: runGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: command, + Component: component, + WorkingDir: workDir, + }, }, }, wantErr: false, }, { name: "Case 2: Invalid Exec Command with empty command", - exec: common.DevfileCommand{ + exec: devfilev1.Command{ Id: "somecommand", - Exec: &common.Exec{ - CommandLine: "", - Component: component, - WorkingDir: workDir, - Group: &common.Group{Kind: runGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: "", + Component: component, + WorkingDir: workDir, + }, }, }, wantErr: true, }, { name: "Case 3: Invalid Exec Command with missing component", - exec: common.DevfileCommand{ + exec: devfilev1.Command{ Id: "somecommand", - Exec: &common.Exec{ - CommandLine: command, - WorkingDir: workDir, - Group: &common.Group{Kind: runGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: command, + WorkingDir: workDir, + }, }, }, wantErr: true, }, { name: "Case 4: Valid Exec Command with invalid component", - exec: common.DevfileCommand{ + exec: devfilev1.Command{ Id: "somecommand", - Exec: &common.Exec{ - CommandLine: command, - Component: invalidComponent, - WorkingDir: workDir, - Group: &common.Group{Kind: runGroup}, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: command, + Component: invalidComponent, + WorkingDir: workDir, + }, }, }, wantErr: true, }, { name: "Case 5: valid Exec Command with Group nil", - exec: common.DevfileCommand{ + exec: devfilev1.Command{ Id: "somecommand", - Exec: &common.Exec{ - CommandLine: command, - Component: component, - WorkingDir: workDir, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + CommandLine: command, + Component: component, + WorkingDir: workDir, + }, }, }, wantErr: false, @@ -233,7 +291,7 @@ func TestValidateExecCommand(t *testing.T) { } for _, tt := range tests { devfileData := testingutil.TestDevfileData{ - Components: []common.DevfileComponent{testingutil.GetFakeContainerComponent(component)}, + Components: []devfilev1.Component{testingutil.GetFakeContainerComponent(component)}, } devObj := devfileParser.DevfileObj{ Data: &devfileData, @@ -261,47 +319,71 @@ func TestValidateCompositeCommand(t *testing.T) { tests := []struct { name string - compositeCommands []common.DevfileCommand - execCommands []common.DevfileCommand + compositeCommands []devfilev1.Command + execCommands []devfilev1.Command wantErr bool }{ { name: "Case 1: Valid Composite Command", - compositeCommands: []common.DevfileCommand{ + compositeCommands: []devfilev1.Command{ { Id: id[3], - Composite: &common.Composite{ - Commands: []string{id[0], id[1], id[2]}, - Group: &common.Group{Kind: buildGroup}, + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup}, + }, + }, + Commands: []string{id[0], id[1], id[2]}, + }, }, }, }, - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: id[0], - Exec: &common.Exec{ - CommandLine: command[0], - Component: component, - Group: &common.Group{Kind: runGroup}, - WorkingDir: workDir[0], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: command[0], + Component: component, + WorkingDir: workDir[0], + }, }, }, { Id: id[1], - Exec: &common.Exec{ - CommandLine: command[1], - Component: component, - Group: &common.Group{Kind: buildGroup}, - WorkingDir: workDir[1], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup}, + }, + }, + CommandLine: command[1], + Component: component, + WorkingDir: workDir[1], + }, }, }, { Id: id[2], - Exec: &common.Exec{ - CommandLine: command[2], - Component: component, - Group: &common.Group{Kind: runGroup}, - WorkingDir: workDir[2], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: command[2], + Component: component, + WorkingDir: workDir[2], + }, }, }, }, @@ -309,41 +391,65 @@ func TestValidateCompositeCommand(t *testing.T) { }, { name: "Case 2: Invalid composite command, references non-existent command", - compositeCommands: []common.DevfileCommand{ + compositeCommands: []devfilev1.Command{ { Id: id[3], - Composite: &common.Composite{ - Commands: []string{id[0], "fakecommand", id[2]}, - Group: &common.Group{Kind: buildGroup}, + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup}, + }, + }, + Commands: []string{id[0], "fakecommand", id[2]}, + }, }, }, }, - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: id[0], - Exec: &common.Exec{ - CommandLine: command[0], - Component: component, - Group: &common.Group{Kind: runGroup}, - WorkingDir: workDir[0], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: command[0], + Component: component, + WorkingDir: workDir[0], + }, }, }, { Id: id[1], - Exec: &common.Exec{ - CommandLine: command[1], - Component: component, - Group: &common.Group{Kind: buildGroup}, - WorkingDir: workDir[1], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup}, + }, + }, + CommandLine: command[1], + Component: component, + WorkingDir: workDir[1], + }, }, }, { Id: id[2], - Exec: &common.Exec{ - CommandLine: command[2], - Component: component, - Group: &common.Group{Kind: runGroup}, - WorkingDir: workDir[2], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: command[2], + Component: component, + WorkingDir: workDir[2], + }, }, }, }, @@ -351,41 +457,65 @@ func TestValidateCompositeCommand(t *testing.T) { }, { name: "Case 3: Invalid composite command, references itself", - compositeCommands: []common.DevfileCommand{ + compositeCommands: []devfilev1.Command{ { Id: id[3], - Composite: &common.Composite{ - Commands: []string{id[0], id[3], id[2]}, - Group: &common.Group{Kind: buildGroup}, + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup}, + }, + }, + Commands: []string{id[0], id[3], id[2]}, + }, }, }, }, - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: id[0], - Exec: &common.Exec{ - CommandLine: command[0], - Component: component, - Group: &common.Group{Kind: runGroup}, - WorkingDir: workDir[0], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: command[0], + Component: component, + WorkingDir: workDir[0], + }, }, }, { Id: id[1], - Exec: &common.Exec{ - CommandLine: command[1], - Component: component, - Group: &common.Group{Kind: buildGroup}, - WorkingDir: workDir[1], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup}, + }, + }, + CommandLine: command[1], + Component: component, + WorkingDir: workDir[1], + }, }, }, { Id: id[2], - Exec: &common.Exec{ - CommandLine: command[2], - Component: component, - Group: &common.Group{Kind: runGroup}, - WorkingDir: workDir[2], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: command[2], + Component: component, + WorkingDir: workDir[2], + }, }, }, }, @@ -393,48 +523,78 @@ func TestValidateCompositeCommand(t *testing.T) { }, { name: "Case 4: Invalid composite command, indirectly references itself", - compositeCommands: []common.DevfileCommand{ + compositeCommands: []devfilev1.Command{ { Id: id[3], - Composite: &common.Composite{ - Commands: []string{id[4], id[3], id[2]}, - Group: &common.Group{Kind: buildGroup}, + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup}, + }, + }, + Commands: []string{id[4], id[3], id[2]}, + }, }, }, { Id: id[4], - Composite: &common.Composite{ - Commands: []string{id[0], id[3], id[2]}, - Group: &common.Group{Kind: buildGroup}, + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup}, + }, + }, + Commands: []string{id[0], id[3], id[2]}, + }, }, }, }, - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: id[0], - Exec: &common.Exec{ - CommandLine: command[0], - Component: component, - Group: &common.Group{Kind: runGroup}, - WorkingDir: workDir[0], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: command[0], + Component: component, + WorkingDir: workDir[0], + }, }, }, { Id: id[1], - Exec: &common.Exec{ - CommandLine: command[1], - Component: component, - Group: &common.Group{Kind: buildGroup}, - WorkingDir: workDir[1], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup}, + }, + }, + CommandLine: command[1], + Component: component, + WorkingDir: workDir[1], + }, }, }, { Id: id[2], - Exec: &common.Exec{ - CommandLine: command[2], - Component: component, - Group: &common.Group{Kind: runGroup}, - WorkingDir: workDir[2], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: command[2], + Component: component, + WorkingDir: workDir[2], + }, }, }, }, @@ -442,32 +602,50 @@ func TestValidateCompositeCommand(t *testing.T) { }, { name: "Case 5: Invalid composite command, points to invalid exec command", - compositeCommands: []common.DevfileCommand{ + compositeCommands: []devfilev1.Command{ { Id: id[3], - Composite: &common.Composite{ - Commands: []string{id[0], id[1]}, - Group: &common.Group{Kind: buildGroup}, + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: buildGroup}, + }, + }, + Commands: []string{id[0], id[1]}, + }, }, }, }, - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: id[0], - Exec: &common.Exec{ - CommandLine: command[0], - Component: component, - Group: &common.Group{Kind: runGroup}, - WorkingDir: workDir[0], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: command[0], + Component: component, + WorkingDir: workDir[0], + }, }, }, { Id: id[1], - Exec: &common.Exec{ - CommandLine: command[1], - Component: "some-fake-component", - Group: &common.Group{Kind: runGroup}, - WorkingDir: workDir[1], + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{Kind: runGroup}, + }, + }, + CommandLine: command[1], + Component: "some-fake-component", + WorkingDir: workDir[1], + }, }, }, }, @@ -478,7 +656,7 @@ func TestValidateCompositeCommand(t *testing.T) { devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ Commands: append(tt.execCommands, tt.compositeCommands...), - Components: []common.DevfileComponent{testingutil.GetFakeContainerComponent(component)}, + Components: []devfilev1.Component{testingutil.GetFakeContainerComponent(component)}, }, } diff --git a/pkg/devfile/validate/generic/components.go b/pkg/devfile/validate/generic/components.go index 3b6942742..739fd01c2 100644 --- a/pkg/devfile/validate/generic/components.go +++ b/pkg/devfile/validate/generic/components.go @@ -4,8 +4,8 @@ import ( "fmt" "strings" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" adaptersCommon "github.com/openshift/odo/pkg/devfile/adapters/common" - "github.com/openshift/odo/pkg/devfile/parser/data/common" "github.com/openshift/odo/pkg/util" "k8s.io/apimachinery/pkg/api/resource" ) @@ -13,12 +13,12 @@ import ( // validateComponents validates that the components // 1. makes sure the container components reference a valid volume component if it uses volume mounts // 2. makes sure the volume components are unique -func validateComponents(components []common.DevfileComponent) error { +func validateComponents(components []devfilev1.Component) error { processedVolumes := make(map[string]bool) processedVolumeMounts := make(map[string]bool) processedEndPointName := make(map[string]bool) - processedEndPointPort := make(map[int32]bool) + processedEndPointPort := make(map[int]bool) for _, component := range components { @@ -49,7 +49,7 @@ func validateComponents(components []common.DevfileComponent) error { // two component containers cannot have the same target port but two endpoints // in a single component container can have the same target port - processedContainerEndPointPort := make(map[int32]bool) + processedContainerEndPointPort := make(map[int]bool) for _, endPoint := range component.Container.Endpoints { if _, ok := processedEndPointName[endPoint.Name]; ok { diff --git a/pkg/devfile/validate/generic/components_test.go b/pkg/devfile/validate/generic/components_test.go index af3f24433..c8d618854 100644 --- a/pkg/devfile/validate/generic/components_test.go +++ b/pkg/devfile/validate/generic/components_test.go @@ -3,31 +3,39 @@ package generic import ( "testing" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" adaptersCommon "github.com/openshift/odo/pkg/devfile/adapters/common" - "github.com/openshift/odo/pkg/devfile/parser/data/common" ) func TestValidateComponents(t *testing.T) { tests := []struct { name string - components []common.DevfileComponent + components []devfilev1.Component wantErr bool wantErrType error }{ { name: "Case 1: Duplicate volume components present", - components: []common.DevfileComponent{ + components: []devfilev1.Component{ { Name: "myvol", - Volume: &common.Volume{ - Size: "1Gi", + ComponentUnion: devfilev1.ComponentUnion{ + Volume: &devfilev1.VolumeComponent{ + Volume: devfilev1.Volume{ + Size: "1Gi", + }, + }, }, }, { Name: "myvol", - Volume: &common.Volume{ - Size: "1Gi", + ComponentUnion: devfilev1.ComponentUnion{ + Volume: &devfilev1.VolumeComponent{ + Volume: devfilev1.Volume{ + Size: "1Gi", + }, + }, }, }, }, @@ -35,7 +43,7 @@ func TestValidateComponents(t *testing.T) { }, { name: "Case 2: Long component name", - components: []common.DevfileComponent{ + components: []devfilev1.Component{ { Name: "myvolmyvolmyvolmyvolmyvolmyvolmyvolmyvolmyvolmyvolmyvolmyvolmyvolmyvolmyvolmyvolmyvol", }, @@ -44,30 +52,42 @@ func TestValidateComponents(t *testing.T) { }, { name: "Case 3: Valid container and volume component", - components: []common.DevfileComponent{ + components: []devfilev1.Component{ { Name: "myvol", - Volume: &common.Volume{ - Size: "1Gi", + ComponentUnion: devfilev1.ComponentUnion{ + Volume: &devfilev1.VolumeComponent{ + Volume: devfilev1.Volume{ + Size: "1Gi", + }, + }, }, }, { Name: "container", - Container: &common.Container{ - VolumeMounts: []common.VolumeMount{ - { - Name: "myvol", - Path: "/some/path/", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + VolumeMounts: []devfilev1.VolumeMount{ + { + Name: "myvol", + Path: "/some/path/", + }, + }, }, }, }, }, { Name: "container2", - Container: &common.Container{ - VolumeMounts: []common.VolumeMount{ - { - Name: "myvol", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + VolumeMounts: []devfilev1.VolumeMount{ + { + Name: "myvol", + }, + }, }, }, }, @@ -77,14 +97,18 @@ func TestValidateComponents(t *testing.T) { }, { name: "Case 4: Invalid container using reserved env PROJECT_SOURCE", - components: []common.DevfileComponent{ + components: []devfilev1.Component{ { Name: "container", - Container: &common.Container{ - Env: []common.Env{ - { - Name: adaptersCommon.EnvProjectsSrc, - Value: "/some/path/", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Env: []devfilev1.EnvVar{ + { + Name: adaptersCommon.EnvProjectsSrc, + Value: "/some/path/", + }, + }, }, }, }, @@ -94,14 +118,18 @@ func TestValidateComponents(t *testing.T) { }, { name: "Case 5: Invalid container using reserved env PROJECTS_ROOT", - components: []common.DevfileComponent{ + components: []devfilev1.Component{ { Name: "container", - Container: &common.Container{ - Env: []common.Env{ - { - Name: adaptersCommon.EnvProjectsRoot, - Value: "/some/path/", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Env: []devfilev1.EnvVar{ + { + Name: adaptersCommon.EnvProjectsRoot, + Value: "/some/path/", + }, + }, }, }, }, @@ -111,20 +139,28 @@ func TestValidateComponents(t *testing.T) { }, { name: "Case 6: Invalid volume component size", - components: []common.DevfileComponent{ + components: []devfilev1.Component{ { Name: "myvol", - Volume: &common.Volume{ - Size: "randomgarbage", + ComponentUnion: devfilev1.ComponentUnion{ + Volume: &devfilev1.VolumeComponent{ + Volume: devfilev1.Volume{ + Size: "randomgarbage", + }, + }, }, }, { Name: "container", - Container: &common.Container{ - VolumeMounts: []common.VolumeMount{ - { - Name: "myvol", - Path: "/some/path/", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + VolumeMounts: []devfilev1.VolumeMount{ + { + Name: "myvol", + Path: "/some/path/", + }, + }, }, }, }, @@ -134,22 +170,30 @@ func TestValidateComponents(t *testing.T) { }, { name: "Case 7: Invalid volume mount", - components: []common.DevfileComponent{ + components: []devfilev1.Component{ { Name: "myvol", - Volume: &common.Volume{ - Size: "2Gi", + ComponentUnion: devfilev1.ComponentUnion{ + Volume: &devfilev1.VolumeComponent{ + Volume: devfilev1.Volume{ + Size: "2Gi", + }, + }, }, }, { Name: "container", - Container: &common.Container{ - VolumeMounts: []common.VolumeMount{ - { - Name: "myinvalidvol", - }, - { - Name: "myinvalidvol2", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + VolumeMounts: []devfilev1.VolumeMount{ + { + Name: "myinvalidvol", + }, + { + Name: "myinvalidvol2", + }, + }, }, }, }, @@ -159,7 +203,7 @@ func TestValidateComponents(t *testing.T) { }, { name: "Case 8: Special character in container name", - components: []common.DevfileComponent{ + components: []devfilev1.Component{ { Name: "run@time", }, @@ -168,7 +212,7 @@ func TestValidateComponents(t *testing.T) { }, { name: "Case 9: Numeric container name", - components: []common.DevfileComponent{ + components: []devfilev1.Component{ { Name: "12345", }, @@ -177,7 +221,7 @@ func TestValidateComponents(t *testing.T) { }, { name: "Case 10: Container name with capitalised character", - components: []common.DevfileComponent{ + components: []devfilev1.Component{ { Name: "runTime", }, @@ -186,31 +230,37 @@ func TestValidateComponents(t *testing.T) { }, { name: "Case 11: Invalid container with same endpoint names", - components: []common.DevfileComponent{ + components: []devfilev1.Component{ { Name: "name1", - Container: &common.Container{ - Image: "image1", - - Endpoints: []common.Endpoint{ - { - Name: "url1", - TargetPort: 8080, - Exposure: common.Public, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + { + Name: "url1", + TargetPort: 8080, + Exposure: devfilev1.PublicEndpointExposure, + }, + }, + Container: devfilev1.Container{ + Image: "image1", }, }, }, }, { Name: "name2", - Container: &common.Container{ - Image: "image2", - - Endpoints: []common.Endpoint{ - { - Name: "url1", - TargetPort: 8081, - Exposure: common.Public, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + { + Name: "url1", + TargetPort: 8081, + Exposure: devfilev1.PublicEndpointExposure, + }, + }, + Container: devfilev1.Container{ + Image: "image2", }, }, }, @@ -220,27 +270,35 @@ func TestValidateComponents(t *testing.T) { }, { name: "Case 12: Invalid container with same endpoint target ports", - components: []common.DevfileComponent{ + components: []devfilev1.Component{ { Name: "name1", - Container: &common.Container{ - Image: "image1", - Endpoints: []common.Endpoint{ - { - Name: "url1", - TargetPort: 8080, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "image1", + }, + Endpoints: []devfilev1.Endpoint{ + { + Name: "url1", + TargetPort: 8080, + }, }, }, }, }, { Name: "name2", - Container: &common.Container{ - Image: "image2", - Endpoints: []common.Endpoint{ - { - Name: "url2", - TargetPort: 8080, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "image2", + }, + Endpoints: []devfilev1.Endpoint{ + { + Name: "url2", + TargetPort: 8080, + }, }, }, }, diff --git a/pkg/devfile/validate/generic/errors.go b/pkg/devfile/validate/generic/errors.go index 80683333b..865274691 100644 --- a/pkg/devfile/validate/generic/errors.go +++ b/pkg/devfile/validate/generic/errors.go @@ -54,14 +54,14 @@ func (e *MissingVolumeMountError) Error() string { // InvalidEndpointError returns an error if the component endpoint is invalid type InvalidEndpointError struct { name string - port int32 + port int } func (e *InvalidEndpointError) Error() string { var errMsg string if e.name != "" { errMsg = fmt.Sprintf("devfile contains multiple endpoint entries with same name: %v", e.name) - } else if string(e.port) != "" { + } else if fmt.Sprint(e.port) != "" { errMsg = fmt.Sprintf("devfile contains multiple containers with same TargetPort: %v", e.port) } diff --git a/pkg/devfile/validate/generic/events.go b/pkg/devfile/validate/generic/events.go index f77418d1f..69e7d6447 100644 --- a/pkg/devfile/validate/generic/events.go +++ b/pkg/devfile/validate/generic/events.go @@ -4,12 +4,12 @@ import ( "fmt" "strings" - "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" "k8s.io/klog" ) // validateEvents validates all the devfile events -func validateEvents(events common.DevfileEvents, commands map[string]common.DevfileCommand) error { +func validateEvents(events devfilev1.Events, commands map[string]devfilev1.Command) error { eventErrors := "" @@ -48,7 +48,7 @@ func validateEvents(events common.DevfileEvents, commands map[string]common.Devf } // isEventValid checks if events belonging to a specific event type are valid ie; event should map to a valid devfile command -func isEventValid(eventNames []string, eventType string, commands map[string]common.DevfileCommand) error { +func isEventValid(eventNames []string, eventType string, commands map[string]devfilev1.Command) error { var invalidEvents []string for _, eventName := range eventNames { diff --git a/pkg/devfile/validate/generic/events_test.go b/pkg/devfile/validate/generic/events_test.go index d4b4fbab5..2bf70b8fa 100644 --- a/pkg/devfile/validate/generic/events_test.go +++ b/pkg/devfile/validate/generic/events_test.go @@ -4,8 +4,8 @@ import ( "strings" "testing" - "github.com/openshift/odo/pkg/devfile/parser" - "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + "github.com/devfile/library/pkg/devfile/parser" "github.com/openshift/odo/pkg/testingutil" ) @@ -16,8 +16,8 @@ func TestIsEventValid(t *testing.T) { tests := []struct { name string eventType string - execCommands []common.DevfileCommand - compCommands []common.DevfileCommand + execCommands []devfilev1.Command + compCommands []devfilev1.Command eventNames []string wantErr bool wantErrMsg string @@ -25,29 +25,35 @@ func TestIsEventValid(t *testing.T) { { name: "Case 1: Valid events", eventType: "preStart", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "command1", - Exec: &common.Exec{ - CommandLine: "/some/command1", - Component: containers[0], - WorkingDir: "workDir", + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + CommandLine: "/some/command1", + Component: containers[0], + WorkingDir: "workDir", + }, }, }, { Id: "command2", - Exec: &common.Exec{ - CommandLine: "/some/command2", - Component: containers[1], - WorkingDir: "workDir", + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + CommandLine: "/some/command2", + Component: containers[1], + WorkingDir: "workDir", + }, }, }, }, - compCommands: []common.DevfileCommand{ + compCommands: []devfilev1.Command{ { Id: "composite1", - Composite: &common.Composite{ - Commands: []string{"command1", "command2"}, + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{ + Commands: []string{"command1", "command2"}, + }, }, }, }, @@ -60,29 +66,35 @@ func TestIsEventValid(t *testing.T) { { name: "Case 2: Invalid events with wrong mapping to devfile command", eventType: "preStart", - execCommands: []common.DevfileCommand{ + execCommands: []devfilev1.Command{ { Id: "command1", - Exec: &common.Exec{ - CommandLine: "/some/command1", - Component: containers[0], - WorkingDir: "workDir", + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + CommandLine: "/some/command1", + Component: containers[0], + WorkingDir: "workDir", + }, }, }, { Id: "command2", - Exec: &common.Exec{ - CommandLine: "/some/command2", - Component: containers[1], - WorkingDir: "workDir", + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + CommandLine: "/some/command2", + Component: containers[1], + WorkingDir: "workDir", + }, }, }, }, - compCommands: []common.DevfileCommand{ + compCommands: []devfilev1.Command{ { Id: "composite1", - Composite: &common.Composite{ - Commands: []string{"command1", "command2"}, + CommandUnion: devfilev1.CommandUnion{ + Composite: &devfilev1.CompositeCommand{ + Commands: []string{"command1", "command2"}, + }, }, }, }, diff --git a/pkg/devfile/validate/generic/validate.go b/pkg/devfile/validate/generic/validate.go index 6c97886d2..5456e0ca2 100644 --- a/pkg/devfile/validate/generic/validate.go +++ b/pkg/devfile/validate/generic/validate.go @@ -3,20 +3,20 @@ package generic import ( "fmt" - "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" "k8s.io/klog" - v200 "github.com/openshift/odo/pkg/devfile/parser/data/2.0.0" + v2 "github.com/devfile/library/pkg/devfile/parser/data/v2" ) // ValidateDevfileData validates whether sections of devfile are odo compatible func ValidateDevfileData(data interface{}) error { - var components []common.DevfileComponent - var commandsMap map[string]common.DevfileCommand - var events common.DevfileEvents + var components []devfilev1.Component + var commandsMap map[string]devfilev1.Command + var events devfilev1.Events switch d := data.(type) { - case *v200.Devfile200: + case *v2.DevfileV2: components = d.GetComponents() commandsMap = d.GetCommands() events = d.GetEvents() diff --git a/pkg/devfile/validate/validate.go b/pkg/devfile/validate/validate.go index 14981a573..b57c90505 100644 --- a/pkg/devfile/validate/validate.go +++ b/pkg/devfile/validate/validate.go @@ -3,8 +3,8 @@ package validate import ( "fmt" - v200 "github.com/openshift/odo/pkg/devfile/parser/data/2.0.0" - "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + "github.com/devfile/library/pkg/devfile/parser/data/v2" "github.com/openshift/odo/pkg/devfile/validate/generic" "k8s.io/klog" @@ -13,8 +13,8 @@ import ( // ValidateDevfileData validates whether sections of devfile are odo compatible // after invoking the generic devfile validation func ValidateDevfileData(data interface{}) error { - var components []common.DevfileComponent - var commandsMap map[string]common.DevfileCommand + var components []devfilev1.Component + var commandsMap map[string]devfilev1.Command // Validate the generic devfile data before validating odo specific logic if err := generic.ValidateDevfileData(data); err != nil { @@ -22,7 +22,7 @@ func ValidateDevfileData(data interface{}) error { } switch d := data.(type) { - case *v200.Devfile200: + case *v2.DevfileV2: components = d.GetComponents() commandsMap = d.GetCommands() diff --git a/pkg/kclient/deployments_test.go b/pkg/kclient/deployments_test.go index d71ed03fa..c1aa3ddd7 100644 --- a/pkg/kclient/deployments_test.go +++ b/pkg/kclient/deployments_test.go @@ -3,8 +3,8 @@ package kclient import ( "testing" - "github.com/openshift/odo/pkg/devfile/parser" - "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + devfileParser "github.com/devfile/library/pkg/devfile/parser" "github.com/openshift/odo/pkg/kclient/generator" "github.com/openshift/odo/pkg/testingutil" "github.com/openshift/odo/pkg/util" @@ -23,9 +23,9 @@ import ( func createFakeDeployment(fkclient *Client, fkclientset *FakeClientset, podName string, labels map[string]string) (*appsv1.Deployment, error) { fakeUID := types.UID("12345") - devObj := parser.DevfileObj{ + devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ - Components: []common.DevfileComponent{ + Components: []devfilev1.Component{ testingutil.GetFakeContainerComponent("container1"), }, }, @@ -187,9 +187,9 @@ func TestUpdateDeployment(t *testing.T) { "component": "frontend", } - devObj := parser.DevfileObj{ + devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ - Components: []common.DevfileComponent{ + Components: []devfilev1.Component{ testingutil.GetFakeContainerComponent("container1"), }, }, diff --git a/pkg/kclient/generator/generators.go b/pkg/kclient/generator/generators.go index 5a30b9e50..b425ea6c9 100644 --- a/pkg/kclient/generator/generators.go +++ b/pkg/kclient/generator/generators.go @@ -13,8 +13,8 @@ import ( "k8s.io/apimachinery/pkg/api/resource" - devfileParser "github.com/openshift/odo/pkg/devfile/parser" - versionsCommon "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + devfileParser "github.com/devfile/library/pkg/devfile/parser" ) const ( @@ -65,7 +65,7 @@ func GetContainers(devfileObj devfileParser.DevfileObj) ([]corev1.Container, err // If `mountSources: true` was set, add an empty dir volume to the container to sync the source to // Sync to `Container.SourceMapping` and/or devfile projects if set - if comp.Container.MountSources { + if comp.Container.MountSources == nil || *comp.Container.MountSources { syncRootFolder := addSyncRootFolder(container, comp.Container.SourceMapping) err := addSyncFolder(container, syncRootFolder, devfileObj.Data.GetProjects()) @@ -158,7 +158,7 @@ func GetService(devfileObj devfileParser.DevfileObj, selectorLabels map[string]s } } // if Exposure == none, should not create a service for that port - if !portExist && portExposureMap[port.ContainerPort] != versionsCommon.None { + if !portExist && portExposureMap[int(port.ContainerPort)] != devfilev1.NoneEndpointExposure { port.Name = fmt.Sprintf("port-%v", port.ContainerPort) containerPorts = append(containerPorts, port) } diff --git a/pkg/kclient/generator/generators_test.go b/pkg/kclient/generator/generators_test.go index a1d260405..c2e562963 100644 --- a/pkg/kclient/generator/generators_test.go +++ b/pkg/kclient/generator/generators_test.go @@ -5,8 +5,8 @@ import ( "strings" "testing" - devfileParser "github.com/openshift/odo/pkg/devfile/parser" - "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + devfileParser "github.com/devfile/library/pkg/devfile/parser" "github.com/openshift/odo/pkg/testingutil" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" @@ -23,10 +23,11 @@ func TestGetContainers(t *testing.T) { containerNames := []string{"testcontainer1", "testcontainer2"} containerImages := []string{"image1", "image2"} - + trueMountSources := true + falseMountSources := false tests := []struct { name string - containerComponents []common.DevfileComponent + containerComponents []devfilev1.Component wantContainerName string wantContainerImage string wantContainerEnv []corev1.EnvVar @@ -35,12 +36,16 @@ func TestGetContainers(t *testing.T) { }{ { name: "Case 1: Container with default project root", - containerComponents: []common.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: containerNames[0], - Container: &common.Container{ - Image: containerImages[0], - MountSources: true, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: containerImages[0], + MountSources: &trueMountSources, + }, + }, }, }, }, @@ -66,13 +71,17 @@ func TestGetContainers(t *testing.T) { }, { name: "Case 2: Container with source mapping", - containerComponents: []common.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: containerNames[0], - Container: &common.Container{ - Image: containerImages[0], - MountSources: true, - SourceMapping: "/myroot", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: containerImages[0], + MountSources: &trueMountSources, + SourceMapping: "/myroot", + }, + }, }, }, }, @@ -98,11 +107,16 @@ func TestGetContainers(t *testing.T) { }, { name: "Case 3: Container with no mount source", - containerComponents: []common.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: containerNames[0], - Container: &common.Container{ - Image: containerImages[0], + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: containerImages[0], + MountSources: &falseMountSources, + }, + }, }, }, }, @@ -367,25 +381,27 @@ func TestGetService(t *testing.T) { tests := []struct { name string - containerComponents []common.DevfileComponent + containerComponents []devfilev1.Component labels map[string]string wantPorts []corev1.ServicePort wantErr bool }{ { name: "Case 1: multiple endpoints share the same port", - containerComponents: []common.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: "testcontainer1", - Container: &common.Container{ - Endpoints: []common.Endpoint{ - { - Name: endpointNames[0], - TargetPort: 8080, - }, - { - Name: endpointNames[1], - TargetPort: 8080, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + { + Name: endpointNames[0], + TargetPort: 8080, + }, + { + Name: endpointNames[1], + TargetPort: 8080, + }, }, }, }, @@ -403,18 +419,20 @@ func TestGetService(t *testing.T) { }, { name: "Case 2: multiple endpoints have different ports", - containerComponents: []common.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: "testcontainer1", - Container: &common.Container{ - Endpoints: []common.Endpoint{ - { - Name: endpointNames[0], - TargetPort: 8080, - }, - { - Name: endpointNames[2], - TargetPort: 9090, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + { + Name: endpointNames[0], + TargetPort: 8080, + }, + { + Name: endpointNames[2], + TargetPort: 9090, + }, }, }, }, diff --git a/pkg/kclient/generator/utils.go b/pkg/kclient/generator/utils.go index 9bbe0e8f0..54453e6b8 100644 --- a/pkg/kclient/generator/utils.go +++ b/pkg/kclient/generator/utils.go @@ -5,8 +5,8 @@ import ( "path/filepath" "strings" - "github.com/openshift/odo/pkg/devfile/parser/data" - "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + "github.com/devfile/library/pkg/devfile/parser/data" "github.com/openshift/odo/pkg/util" corev1 "k8s.io/api/core/v1" @@ -15,7 +15,7 @@ import ( ) // convertEnvs converts environment variables from the devfile structure to kubernetes structure -func convertEnvs(vars []common.Env) []corev1.EnvVar { +func convertEnvs(vars []devfilev1.EnvVar) []corev1.EnvVar { kVars := []corev1.EnvVar{} for _, env := range vars { kVars = append(kVars, corev1.EnvVar{ @@ -27,7 +27,7 @@ func convertEnvs(vars []common.Env) []corev1.EnvVar { } // convertPorts converts endpoint variables from the devfile structure to kubernetes ContainerPort -func convertPorts(endpoints []common.Endpoint) []corev1.ContainerPort { +func convertPorts(endpoints []devfilev1.Endpoint) []corev1.ContainerPort { containerPorts := []corev1.ContainerPort{} for _, endpoint := range endpoints { name := strings.TrimSpace(util.GetDNS1123Name(strings.ToLower(endpoint.Name))) @@ -35,14 +35,14 @@ func convertPorts(endpoints []common.Endpoint) []corev1.ContainerPort { containerPorts = append(containerPorts, corev1.ContainerPort{ Name: name, - ContainerPort: endpoint.TargetPort, + ContainerPort: int32(endpoint.TargetPort), }) } return containerPorts } // getResourceReqs creates a kubernetes ResourceRequirements object based on resource requirements set in the devfile -func getResourceReqs(comp common.DevfileComponent) corev1.ResourceRequirements { +func getResourceReqs(comp devfilev1.Component) corev1.ResourceRequirements { reqs := corev1.ResourceRequirements{} limits := make(corev1.ResourceList) if comp.Container != nil && comp.Container.MemoryLimit != "" { @@ -78,7 +78,7 @@ func addSyncRootFolder(container *corev1.Container, sourceMapping string) string // addSyncFolder adds the sync folder path for the container // sourceVolumePath: mount path of the empty dir volume to sync source code // projects: list of projects from devfile -func addSyncFolder(container *corev1.Container, sourceVolumePath string, projects []common.DevfileProject) error { +func addSyncFolder(container *corev1.Container, sourceVolumePath string, projects []devfilev1.Project) error { var syncFolder string // if there are no projects in the devfile, source would be synced to $PROJECTS_ROOT @@ -114,17 +114,17 @@ func addSyncFolder(container *corev1.Container, sourceVolumePath string, project // GetPortExposure iterate through all endpoints and returns the highest exposure level of all TargetPort. // exposure level: public > internal > none // This function should be under parser pkg -func GetPortExposure(containerComponents []common.DevfileComponent) map[int32]common.ExposureType { - portExposureMap := make(map[int32]common.ExposureType) +func GetPortExposure(containerComponents []devfilev1.Component) map[int]devfilev1.EndpointExposure { + portExposureMap := make(map[int]devfilev1.EndpointExposure) for _, comp := range containerComponents { for _, endpoint := range comp.Container.Endpoints { // if exposure=public, no need to check for existence - if endpoint.Exposure == common.Public || endpoint.Exposure == "" { - portExposureMap[endpoint.TargetPort] = common.Public + if endpoint.Exposure == devfilev1.PublicEndpointExposure || endpoint.Exposure == "" { + portExposureMap[endpoint.TargetPort] = devfilev1.PublicEndpointExposure } else if exposure, exist := portExposureMap[endpoint.TargetPort]; exist { // if a container has multiple identical ports with different exposure levels, save the highest level in the map - if endpoint.Exposure == common.Internal && exposure == common.None { - portExposureMap[endpoint.TargetPort] = common.Internal + if endpoint.Exposure == devfilev1.InternalEndpointExposure && exposure == devfilev1.NoneEndpointExposure { + portExposureMap[endpoint.TargetPort] = devfilev1.InternalEndpointExposure } } else { portExposureMap[endpoint.TargetPort] = endpoint.Exposure @@ -137,8 +137,9 @@ func GetPortExposure(containerComponents []common.DevfileComponent) map[int32]co // GetDevfileContainerComponents iterates through the components in the devfile and returns a list of devfile container components // This function should be under parser pkg -func GetDevfileContainerComponents(data data.DevfileData) []common.DevfileComponent { - var components []common.DevfileComponent +func GetDevfileContainerComponents(data data.DevfileData) []devfilev1.Component { + var components []devfilev1.Component + // Only components with aliases are considered because without an alias commands cannot reference them for _, comp := range data.GetComponents() { if comp.Container != nil { components = append(components, comp) @@ -148,9 +149,9 @@ func GetDevfileContainerComponents(data data.DevfileData) []common.DevfileCompon } // GetDevfileVolumeComponents iterates through the components in the devfile and returns a map of devfile volume components -// This function should be under parser pkg -func GetDevfileVolumeComponents(data data.DevfileData) []common.DevfileComponent { - var components []common.DevfileComponent +func GetDevfileVolumeComponents(data data.DevfileData) []devfilev1.Component { + var components []devfilev1.Component + // Only components with aliases are considered because without an alias commands cannot reference them for _, comp := range data.GetComponents() { if comp.Volume != nil { components = append(components, comp) diff --git a/pkg/kclient/generator/utils_test.go b/pkg/kclient/generator/utils_test.go index 7f9d430de..877a0c6bc 100644 --- a/pkg/kclient/generator/utils_test.go +++ b/pkg/kclient/generator/utils_test.go @@ -5,8 +5,8 @@ import ( "reflect" "testing" - devfileParser "github.com/openshift/odo/pkg/devfile/parser" - "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + devfileParser "github.com/devfile/library/pkg/devfile/parser" "github.com/openshift/odo/pkg/testingutil" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" @@ -17,12 +17,12 @@ func TestConvertEnvs(t *testing.T) { envVarsValues := []string{"value1", "value2", "value3"} tests := []struct { name string - envVars []common.Env + envVars []devfilev1.EnvVar want []corev1.EnvVar }{ { name: "Case 1: One env var", - envVars: []common.Env{ + envVars: []devfilev1.EnvVar{ { Name: envVarsNames[0], Value: envVarsValues[0], @@ -37,7 +37,7 @@ func TestConvertEnvs(t *testing.T) { }, { name: "Case 2: Multiple env vars", - envVars: []common.Env{ + envVars: []devfilev1.EnvVar{ { Name: envVarsNames[0], Value: envVarsValues[0], @@ -68,7 +68,7 @@ func TestConvertEnvs(t *testing.T) { }, { name: "Case 3: No env vars", - envVars: []common.Env{}, + envVars: []devfilev1.EnvVar{}, want: []corev1.EnvVar{}, }, } @@ -85,15 +85,15 @@ func TestConvertEnvs(t *testing.T) { func TestConvertPorts(t *testing.T) { endpointsNames := []string{"endpoint1", "endpoint2"} - endpointsPorts := []int32{8080, 9090} + endpointsPorts := []int{8080, 9090} tests := []struct { name string - endpoints []common.Endpoint + endpoints []devfilev1.Endpoint want []corev1.ContainerPort }{ { name: "Case 1: One Endpoint", - endpoints: []common.Endpoint{ + endpoints: []devfilev1.Endpoint{ { Name: endpointsNames[0], TargetPort: endpointsPorts[0], @@ -102,13 +102,13 @@ func TestConvertPorts(t *testing.T) { want: []corev1.ContainerPort{ { Name: endpointsNames[0], - ContainerPort: endpointsPorts[0], + ContainerPort: int32(endpointsPorts[0]), }, }, }, { name: "Case 2: Multiple env vars", - endpoints: []common.Endpoint{ + endpoints: []devfilev1.Endpoint{ { Name: endpointsNames[0], TargetPort: endpointsPorts[0], @@ -121,17 +121,17 @@ func TestConvertPorts(t *testing.T) { want: []corev1.ContainerPort{ { Name: endpointsNames[0], - ContainerPort: endpointsPorts[0], + ContainerPort: int32(endpointsPorts[0]), }, { Name: endpointsNames[1], - ContainerPort: endpointsPorts[1], + ContainerPort: int32(endpointsPorts[1]), }, }, }, { name: "Case 3: No endpoints", - endpoints: []common.Endpoint{}, + endpoints: []devfilev1.Endpoint{}, want: []corev1.ContainerPort{}, }, } @@ -154,15 +154,19 @@ func TestGetResourceReqs(t *testing.T) { } tests := []struct { name string - component common.DevfileComponent + component devfilev1.Component want corev1.ResourceRequirements }{ { name: "Case 1: One Endpoint", - component: common.DevfileComponent{ + component: devfilev1.Component{ Name: "testcomponent", - Container: &common.Container{ - MemoryLimit: "1024Mi", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + MemoryLimit: "1024Mi", + }, + }, }, }, want: corev1.ResourceRequirements{ @@ -173,16 +177,21 @@ func TestGetResourceReqs(t *testing.T) { }, { name: "Case 2: Empty DevfileComponent", - component: common.DevfileComponent{}, + component: devfilev1.Component{}, want: corev1.ResourceRequirements{}, }, { name: "Case 3: Valid container, but empty memoryLimit", - component: common.DevfileComponent{ + component: devfilev1.Component{ Name: "testcomponent", - Container: &common.Container{ - Image: "testimage", - }}, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "testimage", + }, + }, + }, + }, want: corev1.ResourceRequirements{}, }, } @@ -201,29 +210,41 @@ func TestGetDevfileContainerComponents(t *testing.T) { tests := []struct { name string - component []common.DevfileComponent + component []devfilev1.Component alias []string expectedMatchesCount int }{ { name: "Case 1: Invalid devfile", - component: []common.DevfileComponent{}, + component: []devfilev1.Component{}, expectedMatchesCount: 0, }, { - name: "Case 2: Valid devfile with wrong component type (Openshift)", - component: []common.DevfileComponent{{Openshift: &common.Openshift{}}}, + name: "Case 2: Valid devfile with wrong component type (Openshift)", + component: []devfilev1.Component{ + { + ComponentUnion: devfilev1.ComponentUnion{ + Openshift: &devfilev1.OpenshiftComponent{}, + }, + }, + }, expectedMatchesCount: 0, }, { - name: "Case 3: Valid devfile with wrong component type (Kubernetes)", - component: []common.DevfileComponent{{Kubernetes: &common.Kubernetes{}}}, + name: "Case 3: Valid devfile with wrong component type (Kubernetes)", + component: []devfilev1.Component{ + { + ComponentUnion: devfilev1.ComponentUnion{ + Kubernetes: &devfilev1.KubernetesComponent{}, + }, + }, + }, expectedMatchesCount: 0, }, { name: "Case 4 : Valid devfile with correct component type (Container)", - component: []common.DevfileComponent{testingutil.GetFakeContainerComponent("comp1"), testingutil.GetFakeContainerComponent("comp2")}, + component: []devfilev1.Component{testingutil.GetFakeContainerComponent("comp1"), testingutil.GetFakeContainerComponent("comp2")}, expectedMatchesCount: 2, }, } @@ -249,35 +270,47 @@ func TestGetDevfileVolumeComponents(t *testing.T) { tests := []struct { name string - component []common.DevfileComponent + component []devfilev1.Component alias []string expectedMatchesCount int }{ { name: "Case 1: Invalid devfile", - component: []common.DevfileComponent{}, + component: []devfilev1.Component{}, expectedMatchesCount: 0, }, { - name: "Case 2: Valid devfile with wrong component type (Openshift)", - component: []common.DevfileComponent{{Openshift: &common.Openshift{}}}, + name: "Case 2: Valid devfile with wrong component type (Openshift)", + component: []devfilev1.Component{ + { + ComponentUnion: devfilev1.ComponentUnion{ + Openshift: &devfilev1.OpenshiftComponent{}, + }, + }, + }, expectedMatchesCount: 0, }, { - name: "Case 3: Valid devfile with wrong component type (Kubernetes)", - component: []common.DevfileComponent{{Kubernetes: &common.Kubernetes{}}}, + name: "Case 3: Valid devfile with wrong component type (Kubernetes)", + component: []devfilev1.Component{ + { + ComponentUnion: devfilev1.ComponentUnion{ + Kubernetes: &devfilev1.KubernetesComponent{}, + }, + }, + }, expectedMatchesCount: 0, }, { name: "Case 4 : Valid devfile with wrong component type (Container)", - component: []common.DevfileComponent{testingutil.GetFakeContainerComponent("comp1"), testingutil.GetFakeContainerComponent("comp2")}, + component: []devfilev1.Component{testingutil.GetFakeContainerComponent("comp1"), testingutil.GetFakeContainerComponent("comp2")}, expectedMatchesCount: 0, }, { name: "Case 5: Valid devfile with correct component type (Volume)", - component: []common.DevfileComponent{testingutil.GetFakeContainerComponent("comp1"), testingutil.GetFakeVolumeComponent("myvol", "4Gi")}, + component: []devfilev1.Component{testingutil.GetFakeContainerComponent("comp1"), testingutil.GetFakeVolumeComponent("myvol", "4Gi")}, expectedMatchesCount: 1, }, } @@ -304,25 +337,29 @@ func TestGetPortExposure(t *testing.T) { urlName2 := "testurl2" tests := []struct { name string - containerComponents []common.DevfileComponent - wantMap map[int32]common.ExposureType + containerComponents []devfilev1.Component + wantMap map[int]devfilev1.EndpointExposure wantErr bool }{ { name: "Case 1: devfile has single container with single endpoint", - wantMap: map[int32]common.ExposureType{ - 8080: common.Public, + wantMap: map[int]devfilev1.EndpointExposure{ + 8080: devfilev1.PublicEndpointExposure, }, - containerComponents: []common.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: "testcontainer1", - Container: &common.Container{ - Image: "quay.io/nodejs-12", - Endpoints: []common.Endpoint{ - { - Name: urlName, - TargetPort: 8080, - Exposure: common.Public, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "quay.io/nodejs-12", + }, + Endpoints: []devfilev1.Endpoint{ + { + Name: urlName, + TargetPort: 8080, + Exposure: devfilev1.PublicEndpointExposure, + }, }, }, }, @@ -331,36 +368,44 @@ func TestGetPortExposure(t *testing.T) { }, { name: "Case 2: devfile no endpoints", - wantMap: map[int32]common.ExposureType{}, - containerComponents: []common.DevfileComponent{ + wantMap: map[int]devfilev1.EndpointExposure{}, + containerComponents: []devfilev1.Component{ { Name: "testcontainer1", - Container: &common.Container{ - Image: "quay.io/nodejs-12", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "quay.io/nodejs-12", + }, + }, }, }, }, }, { name: "Case 3: devfile has multiple endpoints with same port, 1 public and 1 internal, should assign public", - wantMap: map[int32]common.ExposureType{ - 8080: common.Public, + wantMap: map[int]devfilev1.EndpointExposure{ + 8080: devfilev1.PublicEndpointExposure, }, - containerComponents: []common.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: "testcontainer1", - Container: &common.Container{ - Image: "quay.io/nodejs-12", - Endpoints: []common.Endpoint{ - { - Name: urlName, - TargetPort: 8080, - Exposure: common.Public, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "quay.io/nodejs-12", }, - { - Name: urlName, - TargetPort: 8080, - Exposure: common.Internal, + Endpoints: []devfilev1.Endpoint{ + { + Name: urlName, + TargetPort: 8080, + Exposure: devfilev1.PublicEndpointExposure, + }, + { + Name: urlName, + TargetPort: 8080, + Exposure: devfilev1.InternalEndpointExposure, + }, }, }, }, @@ -369,24 +414,28 @@ func TestGetPortExposure(t *testing.T) { }, { name: "Case 4: devfile has multiple endpoints with same port, 1 public and 1 none, should assign public", - wantMap: map[int32]common.ExposureType{ - 8080: common.Public, + wantMap: map[int]devfilev1.EndpointExposure{ + 8080: devfilev1.PublicEndpointExposure, }, - containerComponents: []common.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: "testcontainer1", - Container: &common.Container{ - Image: "quay.io/nodejs-12", - Endpoints: []common.Endpoint{ - { - Name: urlName, - TargetPort: 8080, - Exposure: common.Public, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "quay.io/nodejs-12", }, - { - Name: urlName, - TargetPort: 8080, - Exposure: common.None, + Endpoints: []devfilev1.Endpoint{ + { + Name: urlName, + TargetPort: 8080, + Exposure: devfilev1.PublicEndpointExposure, + }, + { + Name: urlName, + TargetPort: 8080, + Exposure: devfilev1.NoneEndpointExposure, + }, }, }, }, @@ -395,24 +444,28 @@ func TestGetPortExposure(t *testing.T) { }, { name: "Case 5: devfile has multiple endpoints with same port, 1 internal and 1 none, should assign internal", - wantMap: map[int32]common.ExposureType{ - 8080: common.Internal, + wantMap: map[int]devfilev1.EndpointExposure{ + 8080: devfilev1.InternalEndpointExposure, }, - containerComponents: []common.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: "testcontainer1", - Container: &common.Container{ - Image: "quay.io/nodejs-12", - Endpoints: []common.Endpoint{ - { - Name: urlName, - TargetPort: 8080, - Exposure: common.Internal, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "quay.io/nodejs-12", }, - { - Name: urlName, - TargetPort: 8080, - Exposure: common.None, + Endpoints: []devfilev1.Endpoint{ + { + Name: urlName, + TargetPort: 8080, + Exposure: devfilev1.InternalEndpointExposure, + }, + { + Name: urlName, + TargetPort: 8080, + Exposure: devfilev1.NoneEndpointExposure, + }, }, }, }, @@ -421,40 +474,46 @@ func TestGetPortExposure(t *testing.T) { }, { name: "Case 6: devfile has multiple endpoints with different port", - wantMap: map[int32]common.ExposureType{ - 8080: common.Public, - 9090: common.Internal, - 3000: common.None, + wantMap: map[int]devfilev1.EndpointExposure{ + 8080: devfilev1.PublicEndpointExposure, + 9090: devfilev1.InternalEndpointExposure, + 3000: devfilev1.NoneEndpointExposure, }, - containerComponents: []common.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: "testcontainer1", - Container: &common.Container{ - Image: "quay.io/nodejs-12", - Endpoints: []common.Endpoint{ - { - Name: urlName, - TargetPort: 8080, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "quay.io/nodejs-12", }, - { - Name: urlName, - TargetPort: 3000, - Exposure: common.None, + Endpoints: []devfilev1.Endpoint{ + { + Name: urlName, + TargetPort: 8080, + }, + { + Name: urlName, + TargetPort: 3000, + Exposure: devfilev1.NoneEndpointExposure, + }, }, }, }, }, { Name: "testcontainer2", - Container: &common.Container{ - Endpoints: []common.Endpoint{ - { - Name: urlName2, - TargetPort: 9090, - Secure: true, - Path: "/testpath", - Exposure: common.Internal, - Protocol: common.HTTPS, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + { + Name: urlName2, + TargetPort: 9090, + Secure: true, + Path: "/testpath", + Exposure: devfilev1.InternalEndpointExposure, + Protocol: devfilev1.HTTPSEndpointProtocol, + }, }, }, }, @@ -520,24 +579,26 @@ func TestAddSyncFolder(t *testing.T) { tests := []struct { name string - projects []common.DevfileProject + projects []devfilev1.Project want string wantErr bool }{ { name: "Case 1: No projects", - projects: []common.DevfileProject{}, + projects: []devfilev1.Project{}, want: sourceVolumePath, wantErr: false, }, { name: "Case 2: One project", - projects: []common.DevfileProject{ + projects: []devfilev1.Project{ { Name: projectNames[0], - Git: &common.Git{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": projectRepos[0]}, + ProjectSource: devfilev1.ProjectSource{ + Git: &devfilev1.GitProjectSource{ + GitLikeProjectSource: devfilev1.GitLikeProjectSource{ + Remotes: map[string]string{"origin": projectRepos[0]}, + }, }, }, }, @@ -547,27 +608,33 @@ func TestAddSyncFolder(t *testing.T) { }, { name: "Case 3: Multiple projects", - projects: []common.DevfileProject{ + projects: []devfilev1.Project{ { Name: projectNames[0], - Git: &common.Git{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": projectRepos[0]}, + ProjectSource: devfilev1.ProjectSource{ + Git: &devfilev1.GitProjectSource{ + GitLikeProjectSource: devfilev1.GitLikeProjectSource{ + Remotes: map[string]string{"origin": projectRepos[0]}, + }, }, }, }, { Name: projectNames[1], - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": projectRepos[1]}, + ProjectSource: devfilev1.ProjectSource{ + Github: &devfilev1.GithubProjectSource{ + GitLikeProjectSource: devfilev1.GitLikeProjectSource{ + Remotes: map[string]string{"origin": projectRepos[1]}, + }, }, }, }, { Name: projectNames[1], - Zip: &common.Zip{ - Location: projectRepos[1], + ProjectSource: devfilev1.ProjectSource{ + Zip: &devfilev1.ZipProjectSource{ + Location: projectRepos[1], + }, }, }, }, @@ -576,12 +643,14 @@ func TestAddSyncFolder(t *testing.T) { }, { name: "Case 4: Clone path set", - projects: []common.DevfileProject{ + projects: []devfilev1.Project{ { ClonePath: projectClonePath, Name: projectNames[0], - Zip: &common.Zip{ - Location: projectRepos[0], + ProjectSource: devfilev1.ProjectSource{ + Zip: &devfilev1.ZipProjectSource{ + Location: projectRepos[0], + }, }, }, }, @@ -590,13 +659,15 @@ func TestAddSyncFolder(t *testing.T) { }, { name: "Case 5: Invalid clone path, set with absolute path", - projects: []common.DevfileProject{ + projects: []devfilev1.Project{ { ClonePath: invalidClonePaths[0], Name: projectNames[0], - Github: &common.Github{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": projectRepos[0]}, + ProjectSource: devfilev1.ProjectSource{ + Github: &devfilev1.GithubProjectSource{ + GitLikeProjectSource: devfilev1.GitLikeProjectSource{ + Remotes: map[string]string{"origin": projectRepos[0]}, + }, }, }, }, @@ -606,13 +677,15 @@ func TestAddSyncFolder(t *testing.T) { }, { name: "Case 6: Invalid clone path, starts with ..", - projects: []common.DevfileProject{ + projects: []devfilev1.Project{ { ClonePath: invalidClonePaths[1], Name: projectNames[0], - Git: &common.Git{ - GitLikeProjectSource: common.GitLikeProjectSource{ - Remotes: map[string]string{"origin": projectRepos[0]}, + ProjectSource: devfilev1.ProjectSource{ + Git: &devfilev1.GitProjectSource{ + GitLikeProjectSource: devfilev1.GitLikeProjectSource{ + Remotes: map[string]string{"origin": projectRepos[0]}, + }, }, }, }, @@ -622,12 +695,14 @@ func TestAddSyncFolder(t *testing.T) { }, { name: "Case 7: Invalid clone path, contains ..", - projects: []common.DevfileProject{ + projects: []devfilev1.Project{ { ClonePath: invalidClonePaths[2], Name: projectNames[0], - Zip: &common.Zip{ - Location: projectRepos[0], + ProjectSource: devfilev1.ProjectSource{ + Zip: &devfilev1.ZipProjectSource{ + Location: projectRepos[0], + }, }, }, }, diff --git a/pkg/kclient/services_test.go b/pkg/kclient/services_test.go index 1dd451519..02d77ad8f 100644 --- a/pkg/kclient/services_test.go +++ b/pkg/kclient/services_test.go @@ -3,8 +3,8 @@ package kclient import ( "testing" - "github.com/openshift/odo/pkg/devfile/parser" - "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + devfileParser "github.com/devfile/library/pkg/devfile/parser" "github.com/openshift/odo/pkg/kclient/generator" "github.com/openshift/odo/pkg/testingutil" "github.com/pkg/errors" @@ -17,9 +17,9 @@ import ( func TestCreateService(t *testing.T) { - devObj := parser.DevfileObj{ + devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ - Components: []common.DevfileComponent{ + Components: []devfilev1.Component{ testingutil.GetFakeContainerComponent("container1"), }, }, @@ -93,9 +93,9 @@ func TestCreateService(t *testing.T) { func TestUpdateService(t *testing.T) { - devObj := parser.DevfileObj{ + devObj := devfileParser.DevfileObj{ Data: &testingutil.TestDevfileData{ - Components: []common.DevfileComponent{ + Components: []devfilev1.Component{ testingutil.GetFakeContainerComponent("container1"), }, }, diff --git a/pkg/odo/cli/catalog/describe/component.go b/pkg/odo/cli/catalog/describe/component.go index 3c3052409..fda98bf31 100644 --- a/pkg/odo/cli/catalog/describe/component.go +++ b/pkg/odo/cli/catalog/describe/component.go @@ -5,11 +5,12 @@ import ( "os" "text/tabwriter" - "github.com/openshift/odo/pkg/devfile" + "github.com/devfile/library/pkg/devfile" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + "github.com/devfile/library/pkg/devfile/parser" "github.com/openshift/odo/pkg/catalog" - "github.com/openshift/odo/pkg/devfile/parser" - "github.com/openshift/odo/pkg/devfile/parser/data/common" + "github.com/openshift/odo/pkg/devfile/validate" "github.com/openshift/odo/pkg/log" "github.com/openshift/odo/pkg/machineoutput" "github.com/openshift/odo/pkg/odo/genericclioptions" @@ -182,12 +183,16 @@ func GetDevfile(devfileComponent catalog.DevfileComponentType) (parser.DevfileOb if err != nil { return devObj, errors.Wrapf(err, "Failed to download devfile.yaml for devfile component: %s", devfileComponent.Name) } + err = validate.ValidateDevfileData(devObj.Data) + if err != nil { + return devObj, err + } return devObj, nil } // PrintDevfileStarterProjects prints all the starter projects in a devfile // If no starter projects exists in the devfile, it prints the whole devfile -func (o *DescribeComponentOptions) PrintDevfileStarterProjects(w *tabwriter.Writer, projects []common.DevfileStarterProject, devObj parser.DevfileObj) error { +func (o *DescribeComponentOptions) PrintDevfileStarterProjects(w *tabwriter.Writer, projects []devfilev1.StarterProject, devObj parser.DevfileObj) error { if len(projects) > 0 { fmt.Fprintln(w, "\nStarter Projects:") for _, project := range projects { diff --git a/pkg/odo/cli/component/common_push.go b/pkg/odo/cli/component/common_push.go index 7f5c5dc99..909d128da 100644 --- a/pkg/odo/cli/component/common_push.go +++ b/pkg/odo/cli/component/common_push.go @@ -7,11 +7,11 @@ import ( "path/filepath" "strings" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + "github.com/devfile/library/pkg/devfile/parser" "github.com/fatih/color" "github.com/openshift/odo/pkg/component" "github.com/openshift/odo/pkg/config" - "github.com/openshift/odo/pkg/devfile/parser" - parsercommon "github.com/openshift/odo/pkg/devfile/parser/data/common" "github.com/openshift/odo/pkg/envinfo" "github.com/openshift/odo/pkg/kclient" "github.com/openshift/odo/pkg/log" @@ -128,7 +128,7 @@ func (cpo *CommonPushOptions) createCmpIfNotExistsAndApplyCmpConfig(stdout io.Wr } } // Apply config - err := component.ApplyConfig(cpo.Context.Client, nil, *cpo.LocalConfigInfo, envinfo.EnvSpecificInfo{}, stdout, cpo.doesComponentExist, []parsercommon.DevfileComponent{}, true) + err := component.ApplyConfig(cpo.Context.Client, nil, *cpo.LocalConfigInfo, envinfo.EnvSpecificInfo{}, stdout, cpo.doesComponentExist, []devfilev1.Component{}, true) if err != nil { odoutil.LogErrorAndExit(err, "Failed to update config to component deployed.") } diff --git a/pkg/odo/cli/component/create.go b/pkg/odo/cli/component/create.go index fd22e20f6..32b6a4f59 100644 --- a/pkg/odo/cli/component/create.go +++ b/pkg/odo/cli/component/create.go @@ -7,15 +7,21 @@ import ( "path/filepath" "strings" + "github.com/pkg/errors" + "github.com/spf13/cobra" + "github.com/zalando/go-keyring" + "k8s.io/klog" + + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + "github.com/devfile/library/pkg/devfile" + "github.com/devfile/library/pkg/devfile/parser" + parsercommon "github.com/devfile/library/pkg/devfile/parser/data/v2/common" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/transport/http" "github.com/openshift/odo/pkg/catalog" "github.com/openshift/odo/pkg/component" "github.com/openshift/odo/pkg/config" - "github.com/openshift/odo/pkg/devfile" - "github.com/openshift/odo/pkg/devfile/parser" - "github.com/openshift/odo/pkg/devfile/parser/data/common" "github.com/openshift/odo/pkg/devfile/validate" "github.com/openshift/odo/pkg/envinfo" "github.com/openshift/odo/pkg/kclient" @@ -33,11 +39,8 @@ import ( "github.com/openshift/odo/pkg/odo/util/pushtarget" "github.com/openshift/odo/pkg/preference" "github.com/openshift/odo/pkg/util" - "github.com/pkg/errors" - "github.com/spf13/cobra" - "github.com/zalando/go-keyring" + corev1 "k8s.io/api/core/v1" - "k8s.io/klog" ktemplates "k8s.io/kubectl/pkg/util/templates" ) @@ -888,7 +891,7 @@ func (co *CreateOptions) downloadStarterProject(devObj parser.DevfileObj, projec // Retrieve starter projects starterProjects := devObj.Data.GetStarterProjects() - var starterProject *common.DevfileStarterProject + var starterProject *devfilev1.StarterProject var err error if interactive { starterProject = getStarterProjectInteractiveMode(starterProjects) @@ -927,14 +930,14 @@ func (co *CreateOptions) downloadStarterProject(devObj parser.DevfileObj, projec if starterProject.Git != nil || starterProject.Github != nil { - projectSource := common.GitLikeProjectSource{} + var projectSource devfilev1.GitLikeProjectSource if starterProject.Git != nil { projectSource = starterProject.Git.GitLikeProjectSource } else { projectSource = starterProject.Github.GitLikeProjectSource } - remoteName, remoteUrl, revision, err := projectSource.GetDefaultSource() + remoteName, remoteUrl, revision, err := parsercommon.GetDefaultSource(projectSource) if err != nil { return errors.Wrapf(err, "unable to get default project source for starter project %s", starterProject.Name) } @@ -1202,7 +1205,7 @@ func (co *CreateOptions) checkoutProject(subDir, zipURL, path string) error { } // getStarterProjectInteractiveMode gets starter project value by asking user in interactive mode. -func getStarterProjectInteractiveMode(projects []common.DevfileStarterProject) *common.DevfileStarterProject { +func getStarterProjectInteractiveMode(projects []devfilev1.StarterProject) *devfilev1.StarterProject { projectName := ui.SelectStarterProject(projects) // if user do not wish to download starter project or there are no projects in devfile, project name would be empty @@ -1210,7 +1213,7 @@ func getStarterProjectInteractiveMode(projects []common.DevfileStarterProject) * return nil } - var project common.DevfileStarterProject + var project devfilev1.StarterProject for _, value := range projects { if value.Name == projectName { @@ -1223,7 +1226,7 @@ func getStarterProjectInteractiveMode(projects []common.DevfileStarterProject) * } // getStarterProjectFromFlag gets starter project value from flag --starter. -func getStarterProjectFromFlag(projects []common.DevfileStarterProject, projectPassed string) (project *common.DevfileStarterProject, err error) { +func getStarterProjectFromFlag(projects []devfilev1.StarterProject, projectPassed string) (project *devfilev1.StarterProject, err error) { nOfProjects := len(projects) diff --git a/pkg/odo/cli/component/devfile.go b/pkg/odo/cli/component/devfile.go index 2fe996cd5..9bbb3cdc2 100644 --- a/pkg/odo/cli/component/devfile.go +++ b/pkg/odo/cli/component/devfile.go @@ -5,7 +5,8 @@ import ( "path/filepath" "strings" - "github.com/openshift/odo/pkg/devfile" + "github.com/devfile/library/pkg/devfile" + "github.com/openshift/odo/pkg/devfile/validate" "github.com/openshift/odo/pkg/envinfo" "github.com/openshift/odo/pkg/machineoutput" "github.com/openshift/odo/pkg/odo/genericclioptions" @@ -79,6 +80,12 @@ func (po *PushOptions) devfilePushInner() (err error) { // Parse devfile and validate devObj, err := devfile.ParseAndValidate(po.DevfilePath) + + if err != nil { + return err + } + + err = validate.ValidateDevfileData(devObj.Data) if err != nil { return err } @@ -149,6 +156,10 @@ func (lo LogOptions) DevfileComponentLog() error { if err != nil { return err } + err = validate.ValidateDevfileData(devObj.Data) + if err != nil { + return err + } componentName := lo.Context.EnvSpecificInfo.GetName() var platformContext interface{} @@ -188,6 +199,10 @@ func (do *DeleteOptions) DevfileComponentDelete() error { if err != nil { return err } + err = validate.ValidateDevfileData(devObj.Data) + if err != nil { + return err + } componentName := do.EnvSpecificInfo.GetName() kc := kubernetes.KubernetesContext{ @@ -258,6 +273,10 @@ func (eo *ExecOptions) DevfileComponentExec(command []string) error { if err != nil { return err } + err = validate.ValidateDevfileData(devObj.Data) + if err != nil { + return err + } componentName := eo.componentOptions.EnvSpecificInfo.GetName() diff --git a/pkg/odo/cli/component/list.go b/pkg/odo/cli/component/list.go index f7b9b3252..fb223dbd0 100644 --- a/pkg/odo/cli/component/list.go +++ b/pkg/odo/cli/component/list.go @@ -8,8 +8,9 @@ import ( appsv1 "k8s.io/api/apps/v1" + "github.com/devfile/library/pkg/devfile" "github.com/openshift/odo/pkg/application" - "github.com/openshift/odo/pkg/devfile" + "github.com/openshift/odo/pkg/devfile/validate" "github.com/openshift/odo/pkg/machineoutput" "github.com/openshift/odo/pkg/project" "github.com/openshift/odo/pkg/util" @@ -67,11 +68,15 @@ func (lo *ListOptions) Complete(name string, cmd *cobra.Command, args []string) if err != nil { return err } - devfile, err := devfile.ParseAndValidate(lo.devfilePath) + devObj, err := devfile.ParseAndValidate(lo.devfilePath) if err != nil { return err } - lo.componentType = devfile.Data.GetMetadata().Name + err = validate.ValidateDevfileData(devObj.Data) + if err != nil { + return err + } + lo.componentType = devObj.Data.GetMetadata().Name } else { // here we use the config.yaml derived context if its present, else we use information from user's kubeconfig diff --git a/pkg/odo/cli/component/push.go b/pkg/odo/cli/component/push.go index ac2767799..571875bdf 100644 --- a/pkg/odo/cli/component/push.go +++ b/pkg/odo/cli/component/push.go @@ -4,13 +4,14 @@ import ( "fmt" "path/filepath" - "github.com/openshift/odo/pkg/devfile" + "github.com/devfile/library/pkg/devfile" + "github.com/openshift/odo/pkg/devfile/validate" "github.com/openshift/odo/pkg/envinfo" "github.com/openshift/odo/pkg/odo/util/pushtarget" ktemplates "k8s.io/kubectl/pkg/util/templates" + "github.com/devfile/library/pkg/devfile/parser" "github.com/openshift/odo/pkg/component" - "github.com/openshift/odo/pkg/devfile/parser" "github.com/openshift/odo/pkg/log" projectCmd "github.com/openshift/odo/pkg/odo/cli/project" "github.com/openshift/odo/pkg/odo/genericclioptions" @@ -90,6 +91,10 @@ func (po *PushOptions) Complete(name string, cmd *cobra.Command, args []string) if err != nil { return errors.Wrap(err, "unable to parse devfile") } + err = validate.ValidateDevfileData(po.Devfile.Data) + if err != nil { + return err + } // We retrieve the configuration information. If this does not exist, then BLANK is returned (important!). envFileInfo, err := envinfo.NewEnvSpecificInfo(po.componentContext) diff --git a/pkg/odo/cli/component/status.go b/pkg/odo/cli/component/status.go index a49731d79..0ba32d6c4 100644 --- a/pkg/odo/cli/component/status.go +++ b/pkg/odo/cli/component/status.go @@ -8,11 +8,12 @@ import ( "fmt" - "github.com/openshift/odo/pkg/devfile" + "github.com/devfile/library/pkg/devfile" + "github.com/devfile/library/pkg/devfile/parser" "github.com/openshift/odo/pkg/devfile/adapters" "github.com/openshift/odo/pkg/devfile/adapters/common" "github.com/openshift/odo/pkg/devfile/adapters/kubernetes" - "github.com/openshift/odo/pkg/devfile/parser" + "github.com/openshift/odo/pkg/devfile/validate" "github.com/openshift/odo/pkg/envinfo" "github.com/openshift/odo/pkg/kclient/generator" "github.com/openshift/odo/pkg/log" @@ -88,6 +89,10 @@ func (so *StatusOptions) Complete(name string, cmd *cobra.Command, args []string if err != nil { return err } + err = validate.ValidateDevfileData(devObj.Data) + if err != nil { + return err + } so.devObj = devObj var platformContext interface{} diff --git a/pkg/odo/cli/component/test.go b/pkg/odo/cli/component/test.go index 902135b60..9b9e4db81 100644 --- a/pkg/odo/cli/component/test.go +++ b/pkg/odo/cli/component/test.go @@ -3,15 +3,15 @@ package component import ( "fmt" "path/filepath" - "reflect" "github.com/pkg/errors" - "github.com/openshift/odo/pkg/devfile" + "github.com/devfile/library/pkg/devfile" + "github.com/openshift/odo/pkg/devfile/validate" appCmd "github.com/openshift/odo/pkg/odo/cli/application" "github.com/openshift/odo/pkg/util" - devfileParser "github.com/openshift/odo/pkg/devfile/parser" + devfileParser "github.com/devfile/library/pkg/devfile/parser" projectCmd "github.com/openshift/odo/pkg/odo/cli/project" "github.com/openshift/odo/pkg/odo/genericclioptions" odoutil "github.com/openshift/odo/pkg/odo/util" @@ -65,8 +65,9 @@ func (to *TestOptions) Validate() (err error) { if err != nil { return errors.Wrap(err, "fail to parse devfile") } - if reflect.DeepEqual(devObj.Ctx.GetApiVersion(), "1.0.0") { - return fmt.Errorf("'odo test' is not supported in devfile 1.0.0") + err = validate.ValidateDevfileData(devObj.Data) + if err != nil { + return err } to.devObj = devObj return diff --git a/pkg/odo/cli/component/ui/ui.go b/pkg/odo/cli/component/ui/ui.go index 49db811d0..3c75e0c9f 100644 --- a/pkg/odo/cli/component/ui/ui.go +++ b/pkg/odo/cli/component/ui/ui.go @@ -7,10 +7,10 @@ import ( "gopkg.in/AlecAivazis/survey.v1" "k8s.io/klog" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" "github.com/openshift/odo/pkg/catalog" "github.com/openshift/odo/pkg/component" "github.com/openshift/odo/pkg/config" - "github.com/openshift/odo/pkg/devfile/parser/data/common" "github.com/openshift/odo/pkg/odo/cli/ui" "github.com/openshift/odo/pkg/odo/genericclioptions" "github.com/openshift/odo/pkg/odo/util/validation" @@ -18,7 +18,7 @@ import ( ) // SelectStarterProject allows user to select starter project in the prompt -func SelectStarterProject(projects []common.DevfileStarterProject) string { +func SelectStarterProject(projects []devfilev1.StarterProject) string { if len(projects) == 0 { return "" @@ -110,7 +110,7 @@ func getDevfileComponentTypeNameCandidates(options []catalog.DevfileComponentTyp return result } -func getProjectNames(projects []common.DevfileStarterProject) []string { +func getProjectNames(projects []devfilev1.StarterProject) []string { result := make([]string, len(projects)) for i, project := range projects { result[i] = project.Name diff --git a/pkg/odo/cli/component/watch.go b/pkg/odo/cli/component/watch.go index 1101bb23a..f42283a7b 100644 --- a/pkg/odo/cli/component/watch.go +++ b/pkg/odo/cli/component/watch.go @@ -7,9 +7,10 @@ import ( "strings" "github.com/openshift/odo/pkg/devfile/adapters/common" + "github.com/openshift/odo/pkg/devfile/validate" + "github.com/devfile/library/pkg/devfile" "github.com/openshift/odo/pkg/config" - "github.com/openshift/odo/pkg/devfile" "github.com/openshift/odo/pkg/devfile/adapters" "github.com/openshift/odo/pkg/devfile/adapters/kubernetes" "github.com/openshift/odo/pkg/occlient" @@ -102,6 +103,10 @@ func (wo *WatchOptions) Complete(name string, cmd *cobra.Command, args []string) if err != nil { return err } + err = validate.ValidateDevfileData(devObj.Data) + if err != nil { + return err + } var platformContext interface{} if !pushtarget.IsPushTargetDocker() { @@ -313,6 +318,10 @@ func (wo *WatchOptions) regenerateComponentAdapterFromWatchParams(parameters wat if err != nil { return nil, errors.Wrapf(err, "unable to parse and validate '%s'", wo.devfilePath) } + err = validate.ValidateDevfileData(devObj.Data) + if err != nil { + return nil, err + } var platformContext interface{} if !pushtarget.IsPushTargetDocker() { diff --git a/pkg/odo/cli/config/config.go b/pkg/odo/cli/config/config.go index 50b70cd11..3b53ff4a6 100644 --- a/pkg/odo/cli/config/config.go +++ b/pkg/odo/cli/config/config.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/openshift/odo/pkg/config" - "github.com/openshift/odo/pkg/devfile/parser" "github.com/openshift/odo/pkg/odo/util" "github.com/spf13/cobra" @@ -28,7 +27,7 @@ func NewCmdConfiguration(name, fullName string) *cobra.Command { configurationCmd := &cobra.Command{ Use: name, Short: "Change or view configuration", - Long: fmt.Sprintf(configLongDesc, parser.FormatDevfileSupportedParameters(), config.FormatLocallySupportedParameters()), + Long: fmt.Sprintf(configLongDesc, config.FormatDevfileSupportedParameters(), config.FormatLocallySupportedParameters()), Example: fmt.Sprintf("%s\n%s\n%s", configurationViewCmd.Example, configurationSetCmd.Example, diff --git a/pkg/odo/cli/config/set.go b/pkg/odo/cli/config/set.go index 4939c331a..69f1d6fcd 100644 --- a/pkg/odo/cli/config/set.go +++ b/pkg/odo/cli/config/set.go @@ -5,8 +5,8 @@ import ( "path/filepath" "strings" + "github.com/devfile/library/pkg/devfile/parser" "github.com/openshift/odo/pkg/config" - "github.com/openshift/odo/pkg/devfile/parser" "github.com/openshift/odo/pkg/log" clicomponent "github.com/openshift/odo/pkg/odo/cli/component" "github.com/openshift/odo/pkg/odo/cli/ui" @@ -135,7 +135,7 @@ func (o *SetOptions) DevfileRun() (err error) { if err != nil { return err } - err = o.devfileObj.AddEnvVars(newEnvVarList) + err = o.devfileObj.AddEnvVars(newEnvVarList.ToDevfileEnv()) if err != nil { return err } @@ -145,7 +145,7 @@ func (o *SetOptions) DevfileRun() (err error) { } if !o.configForceFlag { - if o.devfileObj.IsSet(o.paramName) { + if config.IsSetInDevfile(o.devfileObj, o.paramName) { if !ui.Proceed(fmt.Sprintf("%v is already set. Do you want to override it in the devfile", o.paramName)) { fmt.Println("Aborted by the user.") return nil @@ -153,7 +153,7 @@ func (o *SetOptions) DevfileRun() (err error) { } } - err = o.devfileObj.SetConfiguration(strings.ToLower(o.paramName), o.paramValue) + err = config.SetDevfileConfiguration(o.devfileObj, strings.ToLower(o.paramName), o.paramValue) if err != nil { return err } @@ -274,7 +274,7 @@ func NewCmdSet(name, fullName string) *cobra.Command { configurationSetCmd := &cobra.Command{ Use: name, Short: "Set a value in odo config file", - Long: fmt.Sprintf(setLongDesc, parser.FormatDevfileSupportedParameters(), config.FormatLocallySupportedParameters()), + Long: fmt.Sprintf(setLongDesc, config.FormatDevfileSupportedParameters(), config.FormatLocallySupportedParameters()), Example: getSetExampleString(fullName), Args: func(cmd *cobra.Command, args []string) error { if o.envArray != nil { diff --git a/pkg/odo/cli/config/unset.go b/pkg/odo/cli/config/unset.go index 8722c3438..5ab5a19f4 100644 --- a/pkg/odo/cli/config/unset.go +++ b/pkg/odo/cli/config/unset.go @@ -5,7 +5,7 @@ import ( "path/filepath" "strings" - "github.com/openshift/odo/pkg/devfile/parser" + "github.com/devfile/library/pkg/devfile/parser" "github.com/openshift/odo/pkg/odo/genericclioptions" "github.com/openshift/odo/pkg/util" @@ -133,12 +133,12 @@ func (o *UnsetOptions) DevfileRun() (err error) { log.Italic("\nRun `odo push` command to apply changes to the cluster") return err } - if isSet := o.devfileObj.IsSet(o.paramName); isSet { + if isSet := config.IsSetInDevfile(o.devfileObj, o.paramName); isSet { if !o.configForceFlag && !ui.Proceed(fmt.Sprintf("Do you want to unset %s in the devfile", o.paramName)) { fmt.Println("Aborted by the user.") return nil } - err = o.devfileObj.DeleteConfiguration(strings.ToLower(o.paramName)) + err = config.DeleteDevfileConfiguration(o.devfileObj, strings.ToLower(o.paramName)) log.Success("Devfile was successfully updated.") return err } @@ -215,7 +215,7 @@ func NewCmdUnset(name, fullName string) *cobra.Command { configurationUnsetCmd := &cobra.Command{ Use: name, Short: "Unset a value in odo config file", - Long: fmt.Sprintf(unsetLongDesc, parser.FormatDevfileSupportedParameters(), config.FormatLocallySupportedParameters()), + Long: fmt.Sprintf(unsetLongDesc, config.FormatDevfileSupportedParameters(), config.FormatLocallySupportedParameters()), Example: getUnSetExampleString(fullName), Args: func(cmd *cobra.Command, args []string) error { if o.envArray != nil { diff --git a/pkg/odo/cli/config/view.go b/pkg/odo/cli/config/view.go index 10092fee6..4fe72810d 100644 --- a/pkg/odo/cli/config/view.go +++ b/pkg/odo/cli/config/view.go @@ -8,9 +8,9 @@ import ( "strings" "text/tabwriter" + "github.com/devfile/library/pkg/devfile/parser" "github.com/openshift/odo/pkg/component" "github.com/openshift/odo/pkg/config" - "github.com/openshift/odo/pkg/devfile/parser" "github.com/openshift/odo/pkg/log" "github.com/openshift/odo/pkg/machineoutput" "github.com/openshift/odo/pkg/odo/genericclioptions" diff --git a/pkg/odo/cli/storage/create.go b/pkg/odo/cli/storage/create.go index b443da894..40f6cef8d 100644 --- a/pkg/odo/cli/storage/create.go +++ b/pkg/odo/cli/storage/create.go @@ -4,9 +4,10 @@ import ( "fmt" "path/filepath" - "github.com/openshift/odo/pkg/devfile" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + "github.com/devfile/library/pkg/devfile" adapterCommon "github.com/openshift/odo/pkg/devfile/adapters/common" - "github.com/openshift/odo/pkg/devfile/parser/data/common" + "github.com/openshift/odo/pkg/devfile/validate" "github.com/openshift/odo/pkg/log" "github.com/openshift/odo/pkg/machineoutput" "github.com/openshift/odo/pkg/odo/cli/component" @@ -98,11 +99,19 @@ func (o *StorageCreateOptions) devfileRun() error { if err != nil { return err } + err = validate.ValidateDevfileData(devFile.Data) + if err != nil { + return err + } - err = devFile.Data.AddVolume(common.DevfileComponent{ + err = devFile.Data.AddVolume(devfilev1.Component{ Name: o.storageName, - Volume: &common.Volume{ - Size: o.storageSize, + ComponentUnion: devfilev1.ComponentUnion{ + Volume: &devfilev1.VolumeComponent{ + Volume: devfilev1.Volume{ + Size: o.storageSize, + }, + }, }, }, o.storagePath) diff --git a/pkg/odo/cli/storage/delete.go b/pkg/odo/cli/storage/delete.go index 7b91f8b2e..e986ba57d 100644 --- a/pkg/odo/cli/storage/delete.go +++ b/pkg/odo/cli/storage/delete.go @@ -2,8 +2,11 @@ package storage import ( "fmt" - "github.com/openshift/odo/pkg/devfile" - devfileParser "github.com/openshift/odo/pkg/devfile/parser" + "path/filepath" + + "github.com/devfile/library/pkg/devfile" + devfileParser "github.com/devfile/library/pkg/devfile/parser" + "github.com/openshift/odo/pkg/devfile/validate" "github.com/openshift/odo/pkg/log" "github.com/openshift/odo/pkg/odo/cli/component" "github.com/openshift/odo/pkg/odo/cli/ui" @@ -13,7 +16,6 @@ import ( "github.com/openshift/odo/pkg/util" "github.com/spf13/cobra" ktemplates "k8s.io/kubectl/pkg/util/templates" - "path/filepath" ) const deleteRecommendedCommandName = "delete" @@ -86,6 +88,10 @@ func (o *StorageDeleteOptions) Run() (err error) { if err != nil { return err } + err = validate.ValidateDevfileData(devFile.Data) + if err != nil { + return err + } mPath, err = devFile.Data.GetVolumeMountPath(o.storageName) if err != nil { return err diff --git a/pkg/odo/cli/storage/list.go b/pkg/odo/cli/storage/list.go index e4e696ee7..8190071ed 100644 --- a/pkg/odo/cli/storage/list.go +++ b/pkg/odo/cli/storage/list.go @@ -2,15 +2,17 @@ package storage import ( "fmt" - "github.com/openshift/odo/pkg/devfile" - "github.com/openshift/odo/pkg/devfile/parser" - "github.com/openshift/odo/pkg/devfile/parser/data/common" - "github.com/openshift/odo/pkg/odo/cli/component" - odoutil "github.com/openshift/odo/pkg/util" "os" "path/filepath" "text/tabwriter" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + "github.com/devfile/library/pkg/devfile" + "github.com/devfile/library/pkg/devfile/parser" + "github.com/openshift/odo/pkg/devfile/validate" + "github.com/openshift/odo/pkg/odo/cli/component" + odoutil "github.com/openshift/odo/pkg/util" + "github.com/openshift/odo/pkg/log" "github.com/openshift/odo/pkg/machineoutput" "github.com/openshift/odo/pkg/odo/util/completion" @@ -58,6 +60,10 @@ func (o *StorageListOptions) Complete(name string, cmd *cobra.Command, args []st if err != nil { return err } + err = validate.ValidateDevfileData(o.DevfileObj.Data) + if err != nil { + return err + } } else { // this also initializes the context as well o.Context = genericclioptions.NewContext(cmd) @@ -155,7 +161,7 @@ func printStorageWithContainer(storageList storage.StorageList, compName string) } // isContainerDisplay checks whether the container name should be included in the output -func isContainerDisplay(storageList storage.StorageList, components []common.DevfileComponent) bool { +func isContainerDisplay(storageList storage.StorageList, components []devfilev1.Component) bool { // get all the container names componentsMap := make(map[string]bool) diff --git a/pkg/odo/cli/storage/list_test.go b/pkg/odo/cli/storage/list_test.go index 7c45f879a..13e997b0b 100644 --- a/pkg/odo/cli/storage/list_test.go +++ b/pkg/odo/cli/storage/list_test.go @@ -1,10 +1,11 @@ package storage import ( - "github.com/openshift/odo/pkg/devfile/parser/data/common" + "testing" + + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" "github.com/openshift/odo/pkg/storage" "github.com/openshift/odo/pkg/testingutil" - "testing" ) func Test_isContainerDisplay(t *testing.T) { @@ -16,7 +17,7 @@ func Test_isContainerDisplay(t *testing.T) { type args struct { storageList storage.StorageList - obj []common.DevfileComponent + obj []devfilev1.Component } tests := []struct { name string @@ -32,7 +33,7 @@ func Test_isContainerDisplay(t *testing.T) { generateStorage(storage.GetMachineReadableFormat("pvc-1", "1Gi", "/data"), storage.StateTypePushed, "container-1"), }, }, - obj: []common.DevfileComponent{ + obj: []devfilev1.Component{ testingutil.GetFakeContainerComponent("container-0"), testingutil.GetFakeContainerComponent("container-1"), }, @@ -48,7 +49,7 @@ func Test_isContainerDisplay(t *testing.T) { generateStorage(storage.GetMachineReadableFormat("pvc-1", "1Gi", "/path"), storage.StateTypePushed, "container-1"), }, }, - obj: []common.DevfileComponent{ + obj: []devfilev1.Component{ testingutil.GetFakeContainerComponent("container-0"), testingutil.GetFakeContainerComponent("container-1"), }, @@ -64,7 +65,7 @@ func Test_isContainerDisplay(t *testing.T) { generateStorage(storage.GetMachineReadableFormat("pvc-1", "1Gi", "/data"), storage.StateTypeNotPushed, "container-1"), }, }, - obj: []common.DevfileComponent{ + obj: []devfilev1.Component{ testingutil.GetFakeContainerComponent("container-0"), testingutil.GetFakeContainerComponent("container-1"), }, @@ -79,7 +80,7 @@ func Test_isContainerDisplay(t *testing.T) { generateStorage(storage.GetMachineReadableFormat("pvc-1", "1Gi", "/data"), storage.StateTypePushed, "container-0"), }, }, - obj: []common.DevfileComponent{ + obj: []devfilev1.Component{ testingutil.GetFakeContainerComponent("container-0"), testingutil.GetFakeContainerComponent("container-1"), }, @@ -95,7 +96,7 @@ func Test_isContainerDisplay(t *testing.T) { generateStorage(storage.GetMachineReadableFormat("pvc-1", "1Gi", "/data"), storage.StateTypePushed, "container-1"), }, }, - obj: []common.DevfileComponent{ + obj: []devfilev1.Component{ testingutil.GetFakeContainerComponent("container-0"), }, }, diff --git a/pkg/odo/cli/url/create.go b/pkg/odo/cli/url/create.go index ddca731f0..62cc2e1b8 100644 --- a/pkg/odo/cli/url/create.go +++ b/pkg/odo/cli/url/create.go @@ -5,9 +5,10 @@ import ( "strconv" "strings" - "github.com/openshift/odo/pkg/devfile" - "github.com/openshift/odo/pkg/devfile/parser" - "github.com/openshift/odo/pkg/devfile/parser/data/common" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + "github.com/devfile/library/pkg/devfile" + "github.com/devfile/library/pkg/devfile/parser" + "github.com/openshift/odo/pkg/devfile/validate" "github.com/openshift/odo/pkg/envinfo" "github.com/openshift/odo/pkg/kclient/generator" "github.com/openshift/odo/pkg/log" @@ -149,6 +150,10 @@ func (o *URLCreateOptions) Complete(_ string, cmd *cobra.Command, args []string) if err != nil { return fmt.Errorf("failed to parse the devfile %s, with error: %s", o.DevfilePath, err) } + err = validate.ValidateDevfileData(devObj.Data) + if err != nil { + return err + } o.devObj = devObj componentName := o.EnvSpecificInfo.GetName() @@ -287,9 +292,9 @@ func (o *URLCreateOptions) Validate() (err error) { } else if o.urlType == envinfo.INGRESS { errorList = append(errorList, "host must be provided in order to create URLS of Ingress Kind") } - if len(o.protocol) > 0 && (strings.ToLower(o.protocol) != string(common.HTTP) && strings.ToLower(o.protocol) != string(common.HTTPS) && strings.ToLower(o.protocol) != string(common.WS) && - strings.ToLower(o.protocol) != string(common.WSS) && strings.ToLower(o.protocol) != string(common.TCP) && strings.ToLower(o.protocol) != string(common.UDP)) { - errorList = append(errorList, fmt.Sprintf("endpoint protocol only supports %v|%v|%v|%v|%v|%v", common.HTTP, common.HTTPS, common.WSS, common.WS, common.TCP, common.UDP)) + if len(o.protocol) > 0 && (strings.ToLower(o.protocol) != string(devfilev1.HTTPEndpointProtocol) && strings.ToLower(o.protocol) != string(devfilev1.HTTPSEndpointProtocol) && strings.ToLower(o.protocol) != string(devfilev1.WSEndpointProtocol) && + strings.ToLower(o.protocol) != string(devfilev1.WSSEndpointProtocol) && strings.ToLower(o.protocol) != string(devfilev1.TCPEndpointProtocol) && strings.ToLower(o.protocol) != string(devfilev1.UDPEndpointProtocol)) { + errorList = append(errorList, fmt.Sprintf("endpoint protocol only supports %v|%v|%v|%v|%v|%v", devfilev1.HTTPEndpointProtocol, devfilev1.HTTPSEndpointProtocol, devfilev1.WSSEndpointProtocol, devfilev1.WSEndpointProtocol, devfilev1.TCPEndpointProtocol, devfilev1.UDPEndpointProtocol)) } for _, localURL := range o.EnvSpecificInfo.GetURL() { if o.urlName == localURL.Name { @@ -347,13 +352,13 @@ func (o *URLCreateOptions) Run() (err error) { } err = o.EnvSpecificInfo.SetConfiguration("url", envinfo.EnvInfoURL{Name: o.urlName, Port: o.componentPort, ExposedPort: o.exposedPort, Kind: o.urlType}) } else { - newEndpointEntry := common.Endpoint{ + newEndpointEntry := devfilev1.Endpoint{ Name: o.urlName, Path: o.path, Secure: o.secureURL, - Exposure: common.Public, - TargetPort: int32(o.componentPort), - Protocol: common.ProtocolType(strings.ToLower(o.protocol)), + Exposure: devfilev1.PublicEndpointExposure, + TargetPort: o.componentPort, + Protocol: devfilev1.EndpointProtocol(strings.ToLower(o.protocol)), } err = url.AddEndpointInDevfile(o.devObj, newEndpointEntry, o.container) @@ -427,7 +432,7 @@ func NewCmdURLCreate(name, fullName string) *cobra.Command { urlCreateCmd.Flags().BoolVar(&o.wantIngress, "ingress", false, "Create an Ingress instead of Route on OpenShift clusters") urlCreateCmd.Flags().BoolVarP(&o.secureURL, "secure", "", false, "Create a secure HTTPS URL") urlCreateCmd.Flags().StringVarP(&o.path, "path", "", "", "path for this URL") - urlCreateCmd.Flags().StringVarP(&o.protocol, "protocol", "", string(common.HTTP), "protocol for this URL") + urlCreateCmd.Flags().StringVarP(&o.protocol, "protocol", "", string(devfilev1.HTTPEndpointProtocol), "protocol for this URL") urlCreateCmd.Flags().StringVarP(&o.container, "container", "", "", "container of the endpoint in devfile") urlCreateCmd.Example = fmt.Sprintf(urlCreateExampleExperimental, fullName) diff --git a/pkg/odo/cli/url/delete.go b/pkg/odo/cli/url/delete.go index 55fff2ffe..4554a8d3b 100644 --- a/pkg/odo/cli/url/delete.go +++ b/pkg/odo/cli/url/delete.go @@ -3,8 +3,9 @@ package url import ( "fmt" - "github.com/openshift/odo/pkg/devfile" - "github.com/openshift/odo/pkg/devfile/parser" + "github.com/devfile/library/pkg/devfile" + "github.com/devfile/library/pkg/devfile/parser" + "github.com/openshift/odo/pkg/devfile/validate" "github.com/openshift/odo/pkg/log" clicomponent "github.com/openshift/odo/pkg/odo/cli/component" "github.com/openshift/odo/pkg/odo/cli/ui" @@ -86,6 +87,10 @@ func (o *URLDeleteOptions) Validate() (err error) { if err != nil { return fmt.Errorf("failed to parse the devfile %s, with error: %s", o.DevfilePath, err) } + err = validate.ValidateDevfileData(devObj.Data) + if err != nil { + return err + } o.devObj = devObj } else { urls := o.LocalConfigInfo.GetURL() diff --git a/pkg/odo/cli/url/list.go b/pkg/odo/cli/url/list.go index 1e191d1d0..f553d28d6 100644 --- a/pkg/odo/cli/url/list.go +++ b/pkg/odo/cli/url/list.go @@ -7,8 +7,9 @@ import ( "strconv" "text/tabwriter" + "github.com/devfile/library/pkg/devfile" routev1 "github.com/openshift/api/route/v1" - "github.com/openshift/odo/pkg/devfile" + "github.com/openshift/odo/pkg/devfile/validate" "github.com/openshift/odo/pkg/envinfo" "github.com/openshift/odo/pkg/kclient/generator" pkgutil "github.com/openshift/odo/pkg/util" @@ -131,6 +132,10 @@ func (o *URLListOptions) Run() (err error) { if err != nil { return errors.Wrap(err, "fail to parse the devfile") } + err = validate.ValidateDevfileData(devObj.Data) + if err != nil { + return err + } containerComponents := generator.GetDevfileContainerComponents(devObj.Data) urls, err := url.ListIngressAndRoute(o.Context.Client, o.EnvSpecificInfo, containerComponents, componentName, routeSupported) diff --git a/pkg/odo/cli/utils/convert.go b/pkg/odo/cli/utils/convert.go index fc9f286cc..62f030222 100644 --- a/pkg/odo/cli/utils/convert.go +++ b/pkg/odo/cli/utils/convert.go @@ -7,11 +7,11 @@ import ( "github.com/fatih/color" imagev1 "github.com/openshift/api/image/v1" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + "github.com/devfile/library/pkg/devfile/parser" + devfileCtx "github.com/devfile/library/pkg/devfile/parser/context" + "github.com/devfile/library/pkg/devfile/parser/data" "github.com/openshift/odo/pkg/config" - "github.com/openshift/odo/pkg/devfile/parser" - devfileCtx "github.com/openshift/odo/pkg/devfile/parser/context" - "github.com/openshift/odo/pkg/devfile/parser/data" - "github.com/openshift/odo/pkg/devfile/parser/data/common" "github.com/openshift/odo/pkg/envinfo" "github.com/openshift/odo/pkg/log" "github.com/openshift/odo/pkg/occlient" @@ -275,30 +275,41 @@ func getImageforDevfile(client *occlient.Client, componentType string) (*imagev1 func setDevfileCommandsForS2I(d data.DevfileData) { klog.V(2).Info("Set devfile commands from s2i data") - buildCommand := common.DevfileCommand{ + buildCommand := devfilev1.Command{ Id: buildCommandID, - Exec: &common.Exec{ - Component: containerName, - CommandLine: buildCommandS2i, - Group: &common.Group{ - Kind: common.BuildCommandGroupType, - IsDefault: true, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + Component: containerName, + CommandLine: buildCommandS2i, + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{ + Kind: devfilev1.BuildCommandGroupKind, + IsDefault: true, + }, + }, + }, }, }, } - runCommand := common.DevfileCommand{ + runCommand := devfilev1.Command{ Id: runCommandID, - Exec: &common.Exec{ - Component: containerName, - CommandLine: runCommandS2i, - Group: &common.Group{ - Kind: common.RunCommandGroupType, - IsDefault: true, + CommandUnion: devfilev1.CommandUnion{ + Exec: &devfilev1.ExecCommand{ + Component: containerName, + CommandLine: runCommandS2i, + LabeledCommand: devfilev1.LabeledCommand{ + BaseCommand: devfilev1.BaseCommand{ + Group: &devfilev1.CommandGroup{ + Kind: devfilev1.RunCommandGroupKind, + IsDefault: true, + }, + }, + }, }, }, } - // Ignoring error as we are writing new file _ = d.AddCommands(buildCommand, runCommand) @@ -311,20 +322,28 @@ func setDevfileComponentsForS2I(d data.DevfileData, s2iImage string, localConfig maxMemory := localConfig.GetMaxMemory() volumes := localConfig.GetStorage() urls := localConfig.GetURL() + mountSources := true - var endpoints []common.Endpoint - var envs []common.Env - var volumeMounts []common.VolumeMount - var components []common.DevfileComponent + var endpoints []devfilev1.Endpoint + var envs []devfilev1.EnvVar + var volumeMounts []devfilev1.VolumeMount + var components []devfilev1.Component // convert s2i storage to devfile volumes for _, vol := range volumes { - volume := common.Volume{ - Size: vol.Size, + volume := devfilev1.Component{ + Name: vol.Name, + ComponentUnion: devfilev1.ComponentUnion{ + Volume: &devfilev1.VolumeComponent{ + Volume: devfilev1.Volume{ + Size: vol.Size, + }, + }, + }, } - components = append(components, common.DevfileComponent{Name: vol.Name, Volume: &volume}) + components = append(components, volume) - volumeMount := common.VolumeMount{ + volumeMount := devfilev1.VolumeMount{ Name: vol.Name, Path: vol.Path, } @@ -334,13 +353,13 @@ func setDevfileComponentsForS2I(d data.DevfileData, s2iImage string, localConfig // Add s2i specific env variable in devfile for _, env := range s2iEnv { - env := common.Env{ + env := devfilev1.EnvVar{ Name: env.Name, Value: env.Value, } envs = append(envs, env) } - env := common.Env{ + env := devfilev1.EnvVar{ Name: envS2iConvertedDevfile, Value: "true", } @@ -349,26 +368,33 @@ func setDevfileComponentsForS2I(d data.DevfileData, s2iImage string, localConfig // convert s2i ports to devfile endpoints for _, url := range urls { - endpoint := common.Endpoint{ + endpoint := devfilev1.Endpoint{ Name: url.Name, - TargetPort: int32(url.Port), + TargetPort: url.Port, Secure: url.Secure, } endpoints = append(endpoints, endpoint) } - container := common.Container{ - Image: s2iImage, - MountSources: true, - SourceMapping: sourceMappingS2i, - MemoryLimit: maxMemory, - Endpoints: endpoints, - Env: envs, - VolumeMounts: volumeMounts, + container := devfilev1.Component{ + Name: containerName, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: s2iImage, + MountSources: &mountSources, + SourceMapping: sourceMappingS2i, + MemoryLimit: maxMemory, + Env: envs, + VolumeMounts: volumeMounts, + }, + Endpoints: endpoints, + }, + }, } - components = append(components, common.DevfileComponent{Name: containerName, Container: &container}) + components = append(components, container) // Ignoring error here as we are writing a new file _ = d.AddComponents(components) diff --git a/pkg/storage/storage.go b/pkg/storage/storage.go index 1ca9d2a8c..30af1982f 100644 --- a/pkg/storage/storage.go +++ b/pkg/storage/storage.go @@ -6,8 +6,8 @@ import ( "github.com/openshift/odo/pkg/devfile/adapters/common" + "github.com/devfile/library/pkg/devfile/parser/data" "github.com/openshift/odo/pkg/config" - "github.com/openshift/odo/pkg/devfile/parser/data" "github.com/openshift/odo/pkg/log" "github.com/openshift/odo/pkg/machineoutput" diff --git a/pkg/storage/storage_test.go b/pkg/storage/storage_test.go index 75b796fc1..83cab8896 100644 --- a/pkg/storage/storage_test.go +++ b/pkg/storage/storage_test.go @@ -4,9 +4,9 @@ import ( "reflect" "testing" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + "github.com/devfile/library/pkg/devfile/parser/data" "github.com/kylelemons/godebug/pretty" - "github.com/openshift/odo/pkg/devfile/parser/data" - "github.com/openshift/odo/pkg/devfile/parser/data/common" "github.com/openshift/odo/pkg/kclient" "github.com/openshift/odo/pkg/config" @@ -962,29 +962,37 @@ func TestGetLocalDevfileStorage(t *testing.T) { name: "case 1: list all the volumes in the devfile along with their respective size and containers", args: args{ devfileData: &testingutil.TestDevfileData{ - Components: []common.DevfileComponent{ + Components: []devfilev1.Component{ { Name: "container-0", - Container: &common.Container{ - VolumeMounts: []common.VolumeMount{ - { - Name: "volume-0", - Path: "/path", - }, - { - Name: "volume-1", - Path: "/data", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + VolumeMounts: []devfilev1.VolumeMount{ + { + Name: "volume-0", + Path: "/path", + }, + { + Name: "volume-1", + Path: "/data", + }, + }, }, }, }, }, { Name: "container-1", - Container: &common.Container{ - VolumeMounts: []common.VolumeMount{ - { - Name: "volume-1", - Path: "/data", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + VolumeMounts: []devfilev1.VolumeMount{ + { + Name: "volume-1", + Path: "/data", + }, + }, }, }, }, @@ -1006,18 +1014,22 @@ func TestGetLocalDevfileStorage(t *testing.T) { name: "case 2: list all the volumes in the devfile with the default size when no size is mentioned", args: args{ devfileData: &testingutil.TestDevfileData{ - Components: []common.DevfileComponent{ + Components: []devfilev1.Component{ { Name: "container-0", - Container: &common.Container{ - VolumeMounts: []common.VolumeMount{ - { - Name: "volume-0", - Path: "/path", - }, - { - Name: "volume-1", - Path: "/data", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + VolumeMounts: []devfilev1.VolumeMount{ + { + Name: "volume-0", + Path: "/path", + }, + { + Name: "volume-1", + Path: "/data", + }, + }, }, }, }, @@ -1038,13 +1050,17 @@ func TestGetLocalDevfileStorage(t *testing.T) { name: "case 3: list all the volumes in the devfile with the default mount path when no path is mentioned", args: args{ devfileData: &testingutil.TestDevfileData{ - Components: []common.DevfileComponent{ + Components: []devfilev1.Component{ { Name: "container-0", - Container: &common.Container{ - VolumeMounts: []common.VolumeMount{ - { - Name: "volume-0", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + VolumeMounts: []devfilev1.VolumeMount{ + { + Name: "volume-0", + }, + }, }, }, }, @@ -1063,10 +1079,14 @@ func TestGetLocalDevfileStorage(t *testing.T) { name: "case 4: return empty when no volumes is mounted", args: args{ devfileData: &testingutil.TestDevfileData{ - Components: []common.DevfileComponent{ + Components: []devfilev1.Component{ { - Name: "container-0", - Container: &common.Container{}, + Name: "container-0", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{}, + }, + }, }, testingutil.GetFakeVolumeComponent("volume-0", ""), testingutil.GetFakeVolumeComponent("volume-1", "10Gi"), @@ -1289,7 +1309,7 @@ func TestDevfileList(t *testing.T) { name: "case 1: no volume on devfile and no pod on cluster", args: args{ devfileData: &testingutil.TestDevfileData{ - Components: []common.DevfileComponent{ + Components: []devfilev1.Component{ testingutil.GetFakeContainerComponent("runtime"), }, }, @@ -1308,7 +1328,7 @@ func TestDevfileList(t *testing.T) { name: "case 2: no volume on devfile and pod", args: args{ devfileData: &testingutil.TestDevfileData{ - Components: []common.DevfileComponent{ + Components: []devfilev1.Component{ testingutil.GetFakeContainerComponent("runtime"), }, }, @@ -1330,18 +1350,22 @@ func TestDevfileList(t *testing.T) { args: args{ componentName: "nodejs", devfileData: &testingutil.TestDevfileData{ - Components: []common.DevfileComponent{ + Components: []devfilev1.Component{ { Name: "container-0", - Container: &common.Container{ - VolumeMounts: []common.VolumeMount{ - { - Name: "volume-0", - Path: "/data", - }, - { - Name: "volume-1", - Path: "/path", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + VolumeMounts: []devfilev1.VolumeMount{ + { + Name: "volume-0", + Path: "/data", + }, + { + Name: "volume-1", + Path: "/path", + }, + }, }, }, }, @@ -1378,18 +1402,22 @@ func TestDevfileList(t *testing.T) { args: args{ componentName: "nodejs", devfileData: &testingutil.TestDevfileData{ - Components: []common.DevfileComponent{ + Components: []devfilev1.Component{ { Name: "container-0", - Container: &common.Container{ - VolumeMounts: []common.VolumeMount{ - { - Name: "volume-0", - Path: "/data", - }, - { - Name: "volume-1", - Path: "/path", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + VolumeMounts: []devfilev1.VolumeMount{ + { + Name: "volume-0", + Path: "/data", + }, + { + Name: "volume-1", + Path: "/path", + }, + }, }, }, }, @@ -1428,25 +1456,33 @@ func TestDevfileList(t *testing.T) { args: args{ componentName: "nodejs", devfileData: &testingutil.TestDevfileData{ - Components: []common.DevfileComponent{ + Components: []devfilev1.Component{ { Name: "container-0", - Container: &common.Container{ - VolumeMounts: []common.VolumeMount{ - { - Name: "volume-0", - Path: "/data", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + VolumeMounts: []devfilev1.VolumeMount{ + { + Name: "volume-0", + Path: "/data", + }, + }, }, }, }, }, { Name: "container-1", - Container: &common.Container{ - VolumeMounts: []common.VolumeMount{ - { - Name: "volume-1", - Path: "/data", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + VolumeMounts: []devfilev1.VolumeMount{ + { + Name: "volume-1", + Path: "/data", + }, + }, }, }, }, @@ -1481,14 +1517,18 @@ func TestDevfileList(t *testing.T) { args: args{ componentName: "nodejs", devfileData: &testingutil.TestDevfileData{ - Components: []common.DevfileComponent{ + Components: []devfilev1.Component{ { Name: "container-0", - Container: &common.Container{ - VolumeMounts: []common.VolumeMount{ - { - Name: "volume-0", - Path: "/data", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + VolumeMounts: []devfilev1.VolumeMount{ + { + Name: "volume-0", + Path: "/data", + }, + }, }, }, }, @@ -1525,14 +1565,18 @@ func TestDevfileList(t *testing.T) { args: args{ componentName: "nodejs", devfileData: &testingutil.TestDevfileData{ - Components: []common.DevfileComponent{ + Components: []devfilev1.Component{ { Name: "container-0", - Container: &common.Container{ - VolumeMounts: []common.VolumeMount{ - { - Name: "volume-0", - Path: "/data", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + VolumeMounts: []devfilev1.VolumeMount{ + { + Name: "volume-0", + Path: "/data", + }, + }, }, }, }, @@ -1556,13 +1600,17 @@ func TestDevfileList(t *testing.T) { args: args{ componentName: "nodejs", devfileData: &testingutil.TestDevfileData{ - Components: []common.DevfileComponent{ + Components: []devfilev1.Component{ { Name: "container-0", - Container: &common.Container{ - VolumeMounts: []common.VolumeMount{ - { - Name: "volume-0", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + VolumeMounts: []devfilev1.VolumeMount{ + { + Name: "volume-0", + }, + }, }, }, }, diff --git a/pkg/sync/adapter_test.go b/pkg/sync/adapter_test.go index b2eeb3111..1c7e44852 100644 --- a/pkg/sync/adapter_test.go +++ b/pkg/sync/adapter_test.go @@ -8,9 +8,9 @@ import ( "reflect" "testing" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + "github.com/devfile/library/pkg/devfile/parser" "github.com/openshift/odo/pkg/devfile/adapters/common" - "github.com/openshift/odo/pkg/devfile/parser" - versionsCommon "github.com/openshift/odo/pkg/devfile/parser/data/common" "github.com/openshift/odo/pkg/kclient/generator" "github.com/openshift/odo/pkg/lclient" "github.com/openshift/odo/pkg/testingutil" @@ -181,7 +181,7 @@ func TestSyncFiles(t *testing.T) { t.Run(tt.name, func(t *testing.T) { devObj := parser.DevfileObj{ Data: &testingutil.TestDevfileData{ - Components: []versionsCommon.DevfileComponent{}, + Components: []devfilev1.Component{}, }, } @@ -314,7 +314,7 @@ func TestPushLocal(t *testing.T) { t.Run(tt.name, func(t *testing.T) { devObj := parser.DevfileObj{ Data: &testingutil.TestDevfileData{ - Components: []versionsCommon.DevfileComponent{}, + Components: []devfilev1.Component{}, }, } diff --git a/pkg/testingutil/devfile.go b/pkg/testingutil/devfile.go index 90bffbc23..956f38bf4 100644 --- a/pkg/testingutil/devfile.go +++ b/pkg/testingutil/devfile.go @@ -1,102 +1,102 @@ package testingutil import ( - "github.com/openshift/odo/pkg/devfile/parser/data/common" - versionsCommon "github.com/openshift/odo/pkg/devfile/parser/data/common" + "strings" + + v1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + devfilepkg "github.com/devfile/api/pkg/devfile" + "github.com/devfile/library/pkg/devfile/parser" + devfileCtx "github.com/devfile/library/pkg/devfile/parser/context" + "github.com/devfile/library/pkg/devfile/parser/data/v2/common" + devfilefs "github.com/devfile/library/pkg/testingutil/filesystem" ) // TestDevfileData is a convenience data type used to mock up a devfile configuration type TestDevfileData struct { - Components []versionsCommon.DevfileComponent - Commands []versionsCommon.DevfileCommand - Events common.DevfileEvents + Components []v1.Component + Commands []v1.Command + Events v1.Events } // GetComponents is a mock function to get the components from a devfile -func (d TestDevfileData) GetComponents() []versionsCommon.DevfileComponent { +func (d TestDevfileData) GetComponents() []v1.Component { return d.Components } // GetMetadata is a mock function to get metadata from devfile -func (d TestDevfileData) GetMetadata() versionsCommon.DevfileMetadata { - return versionsCommon.DevfileMetadata{} +func (d TestDevfileData) GetMetadata() devfilepkg.DevfileMetadata { + return devfilepkg.DevfileMetadata{} } // GetEvents is a mock function to get events from devfile -func (d TestDevfileData) GetEvents() versionsCommon.DevfileEvents { +func (d TestDevfileData) GetEvents() v1.Events { return d.Events } // GetParent is a mock function to get parent from devfile -func (d TestDevfileData) GetParent() versionsCommon.DevfileParent { - return versionsCommon.DevfileParent{} -} - -// GetAliasedComponents is a mock function to get the components that have an alias from a devfile -func (d TestDevfileData) GetAliasedComponents() []versionsCommon.DevfileComponent { - var aliasedComponents = []common.DevfileComponent{} - - for _, comp := range d.Components { - if comp.Container != nil { - if comp.Name != "" { - aliasedComponents = append(aliasedComponents, comp) - } - } - } - return aliasedComponents - +func (d TestDevfileData) GetParent() *v1.Parent { + return &v1.Parent{} } // GetProjects is a mock function to get the components that have an alias from a devfile -func (d TestDevfileData) GetProjects() []versionsCommon.DevfileProject { +func (d TestDevfileData) GetProjects() []v1.Project { projectName := [...]string{"test-project", "anotherproject"} clonePath := [...]string{"test-project/", "anotherproject/"} sourceLocation := [...]string{"https://github.com/someproject/test-project.git", "https://github.com/another/project.git"} - project1 := versionsCommon.DevfileProject{ + project1 := v1.Project{ ClonePath: clonePath[0], Name: projectName[0], - Git: &versionsCommon.Git{ - GitLikeProjectSource: versionsCommon.GitLikeProjectSource{ - Remotes: map[string]string{"origin": sourceLocation[0]}, + ProjectSource: v1.ProjectSource{ + Git: &v1.GitProjectSource{ + GitLikeProjectSource: v1.GitLikeProjectSource{ + Remotes: map[string]string{ + "origin": sourceLocation[0], + }, + }, }, }, } - project2 := versionsCommon.DevfileProject{ + project2 := v1.Project{ ClonePath: clonePath[1], Name: projectName[1], - Git: &versionsCommon.Git{ - GitLikeProjectSource: versionsCommon.GitLikeProjectSource{ - Remotes: map[string]string{"origin": sourceLocation[1]}, + ProjectSource: v1.ProjectSource{ + Git: &v1.GitProjectSource{ + GitLikeProjectSource: v1.GitLikeProjectSource{ + Remotes: map[string]string{ + "origin": sourceLocation[1], + }, + }, }, }, } - return []versionsCommon.DevfileProject{project1, project2} + return []v1.Project{project1, project2} } // GetStarterProjects returns the fake starter projects -func (d TestDevfileData) GetStarterProjects() []versionsCommon.DevfileStarterProject { - return []versionsCommon.DevfileStarterProject{} +func (d TestDevfileData) GetStarterProjects() []v1.StarterProject { + return []v1.StarterProject{} } // GetCommands is a mock function to get the commands from a devfile -func (d *TestDevfileData) GetCommands() map[string]versionsCommon.DevfileCommand { - commands := make(map[string]common.DevfileCommand, len(d.Commands)) +func (d TestDevfileData) GetCommands() map[string]v1.Command { + + commands := make(map[string]v1.Command, len(d.Commands)) for _, command := range d.Commands { // we convert devfile command id to lowercase so that we can handle // cases efficiently without being error prone // we also convert the odo push commands from build-command and run-command flags - commands[command.SetIDToLower()] = command - + command.Id = strings.ToLower(command.Id) + commands[command.Id] = command } return commands } -func (d TestDevfileData) AddVolume(volumeComponent common.DevfileComponent, path string) error { +func (d TestDevfileData) AddVolume(volume v1.Component, path string) error { return nil } @@ -117,11 +117,25 @@ func (d TestDevfileData) SetMetadata(name, version string) {} // SetSchemaVersion sets schema version for devfile func (d TestDevfileData) SetSchemaVersion(version string) {} -func (d TestDevfileData) AddComponents(components []common.DevfileComponent) error { return nil } +func (d TestDevfileData) AddComponents(components []v1.Component) error { return nil } -func (d TestDevfileData) UpdateComponent(component common.DevfileComponent) {} +func (d TestDevfileData) UpdateComponent(component v1.Component) {} -func (d *TestDevfileData) AddCommands(commands ...common.DevfileCommand) error { +func (d TestDevfileData) UpdateCommand(command v1.Command) {} + +func (d TestDevfileData) SetEvents(events v1.Events) {} + +func (d TestDevfileData) AddProjects(projects []v1.Project) error { return nil } + +func (d TestDevfileData) UpdateProject(project v1.Project) {} + +func (d TestDevfileData) AddEvents(events v1.Events) error { return nil } + +func (d TestDevfileData) UpdateEvents(postStart, postStop, preStart, preStop []string) {} + +func (d TestDevfileData) SetParent(parent *v1.Parent) {} + +func (d *TestDevfileData) AddCommands(commands ...v1.Command) error { commandsMap := d.GetCommands() for _, command := range commands { @@ -129,98 +143,137 @@ func (d *TestDevfileData) AddCommands(commands ...common.DevfileCommand) error { if _, ok := commandsMap[id]; !ok { d.Commands = append(d.Commands, command) } else { - return &common.AlreadyExistError{Name: id, Field: "command"} + return &common.FieldAlreadyExistError{Name: id, Field: "command"} } } return nil } -func (d TestDevfileData) UpdateCommand(command common.DevfileCommand) {} - -func (d TestDevfileData) SetEvents(events common.DevfileEvents) {} - -func (d TestDevfileData) AddProjects(projects []common.DevfileProject) error { return nil } - -func (d TestDevfileData) UpdateProject(project common.DevfileProject) {} - -func (d TestDevfileData) AddStarterProjects(projects []common.DevfileStarterProject) error { +func (d TestDevfileData) AddStarterProjects(projects []v1.StarterProject) error { return nil } -func (d TestDevfileData) UpdateStarterProject(project common.DevfileStarterProject) {} - -func (d TestDevfileData) AddEvents(events common.DevfileEvents) error { return nil } - -func (d TestDevfileData) UpdateEvents(postStart, postStop, preStart, preStop []string) {} - -func (d TestDevfileData) SetParent(parent common.DevfileParent) {} +func (d TestDevfileData) UpdateStarterProject(project v1.StarterProject) {} // GetFakeContainerComponent returns a fake container component for testing -func GetFakeContainerComponent(name string) versionsCommon.DevfileComponent { +func GetFakeContainerComponent(name string) v1.Component { image := "docker.io/maven:latest" memoryLimit := "128Mi" volumeName := "myvolume1" volumePath := "/my/volume/mount/path1" + mountSources := true - return versionsCommon.DevfileComponent{ + return v1.Component{ Name: name, - Container: &versionsCommon.Container{ - Image: image, - Env: []versionsCommon.Env{}, - MemoryLimit: memoryLimit, - VolumeMounts: []versionsCommon.VolumeMount{{ - Name: volumeName, - Path: volumePath, - }}, - MountSources: true, - Endpoints: []common.Endpoint{ - { - Name: "port1", - TargetPort: 9090, + ComponentUnion: v1.ComponentUnion{ + Container: &v1.ContainerComponent{ + Container: v1.Container{ + Image: image, + Env: []v1.EnvVar{}, + MemoryLimit: memoryLimit, + VolumeMounts: []v1.VolumeMount{{ + Name: volumeName, + Path: volumePath, + }}, + MountSources: &mountSources, }, - }, - }} + }}} } // GetFakeVolumeComponent returns a fake volume component for testing -func GetFakeVolumeComponent(name, size string) versionsCommon.DevfileComponent { - return versionsCommon.DevfileComponent{ +func GetFakeVolumeComponent(name, size string) v1.Component { + return v1.Component{ Name: name, - Volume: &versionsCommon.Volume{ - Size: size, - }} + ComponentUnion: v1.ComponentUnion{ + Volume: &v1.VolumeComponent{ + Volume: v1.Volume{ + Size: size, + }}}} } // GetFakeExecRunCommands returns fake commands for testing -func GetFakeExecRunCommands() []versionsCommon.DevfileCommand { - return []versionsCommon.DevfileCommand{ +func GetFakeExecRunCommands() []v1.Command { + return []v1.Command{ { - Exec: &common.Exec{ - CommandLine: "ls -a", - Component: "alias1", - Group: &versionsCommon.Group{ - Kind: versionsCommon.RunCommandGroupType, + CommandUnion: v1.CommandUnion{ + Exec: &v1.ExecCommand{ + LabeledCommand: v1.LabeledCommand{ + BaseCommand: v1.BaseCommand{ + Group: &v1.CommandGroup{ + Kind: v1.RunCommandGroupKind, + }, + }, + }, + CommandLine: "ls -a", + Component: "alias1", + WorkingDir: "/root", }, - WorkingDir: "/root", }, }, } } // GetFakeExecRunCommands returns a fake env for testing -func GetFakeEnv(name, value string) versionsCommon.Env { - return versionsCommon.Env{ +func GetFakeEnv(name, value string) v1.EnvVar { + return v1.EnvVar{ Name: name, Value: value, } } // GetFakeVolumeMount returns a fake volume mount for testing -func GetFakeVolumeMount(name, path string) versionsCommon.VolumeMount { - return versionsCommon.VolumeMount{ +func GetFakeVolumeMount(name, path string) v1.VolumeMount { + return v1.VolumeMount{ Name: name, Path: path, } } + +// GetTestDevfileObj returns a devfile object for testing +func GetTestDevfileObj(fs devfilefs.Filesystem) parser.DevfileObj { + return parser.DevfileObj{ + Ctx: devfileCtx.FakeContext(fs, parser.OutputDevfileYamlPath), + Data: &TestDevfileData{ + Commands: []v1.Command{ + { + Id: "devbuild", + CommandUnion: v1.CommandUnion{ + Exec: &v1.ExecCommand{ + WorkingDir: "/projects/nodejs-starter", + }, + }, + }, + }, + Components: []v1.Component{ + { + Name: "runtime", + ComponentUnion: v1.ComponentUnion{ + Container: &v1.ContainerComponent{ + Container: v1.Container{ + Image: "quay.io/nodejs-12", + }, + Endpoints: []v1.Endpoint{ + { + Name: "port-3030", + TargetPort: 3000, + }, + }, + }, + }, + }, + { + Name: "loadbalancer", + ComponentUnion: v1.ComponentUnion{ + Container: &v1.ContainerComponent{ + Container: v1.Container{ + Image: "quay.io/nginx", + }, + }, + }, + }, + }, + }, + } +} diff --git a/pkg/url/status.go b/pkg/url/status.go index 7d0bfbf51..d7b30ba3c 100644 --- a/pkg/url/status.go +++ b/pkg/url/status.go @@ -7,8 +7,8 @@ import ( "strconv" "time" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" routev1 "github.com/openshift/api/route/v1" - "github.com/openshift/odo/pkg/devfile/parser/data/common" "github.com/openshift/odo/pkg/envinfo" "github.com/openshift/odo/pkg/kclient" "github.com/openshift/odo/pkg/lclient" @@ -25,7 +25,7 @@ const ( ) // StartURLHttpRequestStatusWatchForK8S begins testing URLs for responses, outputting the result to console -func StartURLHttpRequestStatusWatchForK8S(occlient *occlient.Client, client *kclient.Client, envInfo *envinfo.EnvSpecificInfo, loggingClient machineoutput.MachineEventLoggingClient, containerComponents []common.DevfileComponent) { +func StartURLHttpRequestStatusWatchForK8S(occlient *occlient.Client, client *kclient.Client, envInfo *envinfo.EnvSpecificInfo, loggingClient machineoutput.MachineEventLoggingClient, containerComponents []devfilev1.Component) { // This is a non-blocking function so that other status watchers may start as needed go func() { @@ -94,7 +94,7 @@ func startURLTester(urlsToTest [][]statusURL, loggingClient machineoutput.Machin } } -func getURLsForKubernetes(oclient *occlient.Client, client *kclient.Client, envInfo *envinfo.EnvSpecificInfo, ignoreUnpushed bool, containerComponents []common.DevfileComponent) ([]statusURL, error) { +func getURLsForKubernetes(oclient *occlient.Client, client *kclient.Client, envInfo *envinfo.EnvSpecificInfo, ignoreUnpushed bool, containerComponents []devfilev1.Component) ([]statusURL, error) { componentName := envInfo.GetName() routesSupported := false diff --git a/pkg/url/status_test.go b/pkg/url/status_test.go index 24c5d5626..ece8c6e51 100644 --- a/pkg/url/status_test.go +++ b/pkg/url/status_test.go @@ -4,15 +4,16 @@ import ( "reflect" "testing" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + "github.com/devfile/library/pkg/devfile/parser" + devfileCtx "github.com/devfile/library/pkg/devfile/parser/context" + "github.com/devfile/library/pkg/testingutil/filesystem" routev1 "github.com/openshift/api/route/v1" - "github.com/openshift/odo/pkg/devfile/parser" - devfileCtx "github.com/openshift/odo/pkg/devfile/parser/context" - versionsCommon "github.com/openshift/odo/pkg/devfile/parser/data/common" "github.com/openshift/odo/pkg/envinfo" "github.com/openshift/odo/pkg/kclient" "github.com/openshift/odo/pkg/occlient" "github.com/openshift/odo/pkg/testingutil" - "github.com/openshift/odo/pkg/testingutil/filesystem" + extensionsv1 "k8s.io/api/extensions/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -186,7 +187,7 @@ func TestGetURLsForKubernetes(t *testing.T) { devObj := parser.DevfileObj{ Ctx: devfileCtx.FakeContext(fs, parser.OutputDevfileYamlPath), Data: &testingutil.TestDevfileData{ - Components: []versionsCommon.DevfileComponent{}, + Components: []devfilev1.Component{}, }, } containerComponents := generator.GetDevfileContainerComponents(devObj.Data) diff --git a/pkg/url/url.go b/pkg/url/url.go index e387fb668..e29687de4 100644 --- a/pkg/url/url.go +++ b/pkg/url/url.go @@ -12,6 +12,8 @@ import ( "github.com/openshift/odo/pkg/kclient/generator" "github.com/openshift/odo/pkg/log" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + "github.com/devfile/library/pkg/devfile/parser" types "github.com/docker/docker/api/types" routev1 "github.com/openshift/api/route/v1" applabels "github.com/openshift/odo/pkg/application/labels" @@ -19,9 +21,6 @@ import ( "github.com/openshift/odo/pkg/config" dockercomponent "github.com/openshift/odo/pkg/devfile/adapters/docker/component" dockerutils "github.com/openshift/odo/pkg/devfile/adapters/docker/utils" - "github.com/openshift/odo/pkg/devfile/parser" - "github.com/openshift/odo/pkg/devfile/parser/data/common" - parsercommon "github.com/openshift/odo/pkg/devfile/parser/data/common" "github.com/openshift/odo/pkg/kclient" "github.com/openshift/odo/pkg/lclient" "github.com/openshift/odo/pkg/occlient" @@ -51,7 +50,7 @@ func (urls URLList) Get(urlName string) URL { } // GetIngressOrRoute returns ingress/route spec for given URL name -func GetIngressOrRoute(client *occlient.Client, kClient *kclient.Client, envSpecificInfo *envinfo.EnvSpecificInfo, urlName string, containerComponents []common.DevfileComponent, componentName string, routeSupported bool) (URL, error) { +func GetIngressOrRoute(client *occlient.Client, kClient *kclient.Client, envSpecificInfo *envinfo.EnvSpecificInfo, urlName string, containerComponents []devfilev1.Component, componentName string, routeSupported bool) (URL, error) { remoteExist := true var ingress *iextensionsv1.Ingress var route *routev1.Route @@ -88,7 +87,7 @@ func GetIngressOrRoute(client *occlient.Client, kClient *kclient.Client, envSpec continue } - if localEndpoint.Exposure == common.None || localEndpoint.Exposure == common.Internal { + if localEndpoint.Exposure == devfilev1.NoneEndpointExposure || localEndpoint.Exposure == devfilev1.InternalEndpointExposure { return URL{}, errors.New(fmt.Sprintf("the url %v is defined in devfile, but is not exposed", urlName)) } var devfileURL envinfo.EnvInfoURL @@ -439,7 +438,7 @@ func (s sortableURLs) Swap(i, j int) { } // ListIngressAndRoute returns all Ingress and Route for given component. -func ListIngressAndRoute(oclient *occlient.Client, configProvider envinfo.LocalConfigProvider, containerComponents []parsercommon.DevfileComponent, componentName string, routeSupported bool) (URLList, error) { +func ListIngressAndRoute(oclient *occlient.Client, configProvider envinfo.LocalConfigProvider, containerComponents []devfilev1.Component, componentName string, routeSupported bool) (URLList, error) { labelSelector := fmt.Sprintf("%v=%v", componentlabels.ComponentLabel, componentName) klog.V(4).Infof("Listing ingresses with label selector: %v", labelSelector) ingresses, err := oclient.GetKubeClient().ListIngresses(labelSelector) @@ -488,7 +487,7 @@ func ListIngressAndRoute(oclient *occlient.Client, configProvider envinfo.LocalC for _, comp := range containerComponents { for _, localEndpoint := range comp.Container.Endpoints { // only exposed endpoint will be shown as a URL in `odo url list` - if localEndpoint.Exposure == common.None || localEndpoint.Exposure == common.Internal { + if localEndpoint.Exposure == devfilev1.NoneEndpointExposure || localEndpoint.Exposure == devfilev1.InternalEndpointExposure { continue } var devfileURL envinfo.EnvInfoURL @@ -885,7 +884,7 @@ type PushParameters struct { EnvURLS []envinfo.EnvInfoURL IsRouteSupported bool IsExperimentalModeEnabled bool - ContainerComponents []common.DevfileComponent + ContainerComponents []devfilev1.Component IsS2I bool } @@ -906,7 +905,7 @@ func Push(client *occlient.Client, kClient *kclient.Client, parameters PushParam for _, comp := range parameters.ContainerComponents { for _, endpoint := range comp.Container.Endpoints { // skip URL creation if the URL is not publicly exposed - if endpoint.Exposure == common.None || endpoint.Exposure == common.Internal { + if endpoint.Exposure == devfilev1.NoneEndpointExposure || endpoint.Exposure == devfilev1.InternalEndpointExposure { continue } secure := false @@ -1077,7 +1076,7 @@ func Push(client *occlient.Client, kClient *kclient.Client, parameters PushParam } // AddEndpointInDevfile writes the provided endpoint information into devfile -func AddEndpointInDevfile(devObj parser.DevfileObj, endpoint parsercommon.Endpoint, container string) error { +func AddEndpointInDevfile(devObj parser.DevfileObj, endpoint devfilev1.Endpoint, container string) error { components := devObj.Data.GetComponents() for _, component := range components { if component.Container != nil && component.Name == container { diff --git a/pkg/url/url_test.go b/pkg/url/url_test.go index 873fbeb12..ad58be722 100644 --- a/pkg/url/url_test.go +++ b/pkg/url/url_test.go @@ -6,15 +6,16 @@ import ( "strings" "testing" + devfilev1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + "github.com/devfile/library/pkg/devfile/parser" + devfileCtx "github.com/devfile/library/pkg/devfile/parser/context" + "github.com/devfile/library/pkg/testingutil/filesystem" "github.com/kylelemons/godebug/pretty" appsv1 "github.com/openshift/api/apps/v1" routev1 "github.com/openshift/api/route/v1" applabels "github.com/openshift/odo/pkg/application/labels" componentlabels "github.com/openshift/odo/pkg/component/labels" dockercomponent "github.com/openshift/odo/pkg/devfile/adapters/docker/component" - "github.com/openshift/odo/pkg/devfile/parser" - devfileCtx "github.com/openshift/odo/pkg/devfile/parser/context" - versionsCommon "github.com/openshift/odo/pkg/devfile/parser/data/common" "github.com/openshift/odo/pkg/envinfo" "github.com/openshift/odo/pkg/kclient" "github.com/openshift/odo/pkg/kclient/fake" @@ -22,7 +23,6 @@ import ( "github.com/openshift/odo/pkg/lclient" "github.com/openshift/odo/pkg/occlient" "github.com/openshift/odo/pkg/testingutil" - "github.com/openshift/odo/pkg/testingutil/filesystem" "github.com/openshift/odo/pkg/url/labels" "github.com/openshift/odo/pkg/util" v1 "k8s.io/api/core/v1" @@ -759,7 +759,7 @@ func TestPush(t *testing.T) { existingEnvInfoURLs []envinfo.EnvInfoURL returnedRoutes *routev1.RouteList returnedIngress *extensionsv1.IngressList - containerComponents []versionsCommon.DevfileComponent + containerComponents []devfilev1.Component deletedURLs []URL createdURLs []URL wantErr bool @@ -921,20 +921,22 @@ func TestPush(t *testing.T) { Kind: envinfo.INGRESS, }, }, - containerComponents: []versionsCommon.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: "container1", - Container: &versionsCommon.Container{ - Endpoints: []versionsCommon.Endpoint{ - { - Name: "example", - TargetPort: 8080, - Secure: false, - }, - { - Name: "example-1", - TargetPort: 9090, - Secure: false, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + { + Name: "example", + TargetPort: 8080, + Secure: false, + }, + { + Name: "example-1", + TargetPort: 9090, + Secure: false, + }, }, }, }, @@ -1005,20 +1007,22 @@ func TestPush(t *testing.T) { Kind: envinfo.INGRESS, }, }, - containerComponents: []versionsCommon.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: "container1", - Container: &versionsCommon.Container{ - Endpoints: []versionsCommon.Endpoint{ - { - Name: "example-local-0", - TargetPort: 8080, - Secure: false, - }, - { - Name: "example-local-1", - TargetPort: 9090, - Secure: false, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + { + Name: "example-local-0", + TargetPort: 8080, + Secure: false, + }, + { + Name: "example-local-1", + TargetPort: 9090, + Secure: false, + }, }, }, }, @@ -1080,20 +1084,22 @@ func TestPush(t *testing.T) { Kind: envinfo.INGRESS, }, }, - containerComponents: []versionsCommon.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: "container1", - Container: &versionsCommon.Container{ - Endpoints: []versionsCommon.Endpoint{ - { - Name: "example-0", - TargetPort: 8080, - Secure: false, - }, - { - Name: "example-1", - TargetPort: 9090, - Secure: false, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + { + Name: "example-0", + TargetPort: 8080, + Secure: false, + }, + { + Name: "example-1", + TargetPort: 9090, + Secure: false, + }, }, }, }, @@ -1120,20 +1126,22 @@ func TestPush(t *testing.T) { Kind: envinfo.INGRESS, }, }, - containerComponents: []versionsCommon.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: "container1", - Container: &versionsCommon.Container{ - Endpoints: []versionsCommon.Endpoint{ - { - Name: "example-local-0", - TargetPort: 8080, - Secure: false, - }, - { - Name: "example-local-1", - TargetPort: 9090, - Secure: false, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + { + Name: "example-local-0", + TargetPort: 8080, + Secure: false, + }, + { + Name: "example-local-1", + TargetPort: 9090, + Secure: false, + }, }, }, }, @@ -1190,15 +1198,17 @@ func TestPush(t *testing.T) { Kind: envinfo.INGRESS, }, }, - containerComponents: []versionsCommon.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: "container1", - Container: &versionsCommon.Container{ - Endpoints: []versionsCommon.Endpoint{ - { - Name: "example", - TargetPort: 8080, - Secure: true, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + { + Name: "example", + TargetPort: 8080, + Secure: true, + }, }, }, }, @@ -1234,15 +1244,17 @@ func TestPush(t *testing.T) { Kind: envinfo.ROUTE, }, }, - containerComponents: []versionsCommon.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: "container1", - Container: &versionsCommon.Container{ - Endpoints: []versionsCommon.Endpoint{ - { - Name: "example-local-0", - TargetPort: 8080, - Secure: false, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + { + Name: "example-local-0", + TargetPort: 8080, + Secure: false, + }, }, }, }, @@ -1325,15 +1337,17 @@ func TestPush(t *testing.T) { Kind: envinfo.ROUTE, }, }, - containerComponents: []versionsCommon.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: "container1", - Container: &versionsCommon.Container{ - Endpoints: []versionsCommon.Endpoint{ - { - Name: "example", - TargetPort: 8080, - Secure: true, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + { + Name: "example", + TargetPort: 8080, + Secure: true, + }, }, }, }, @@ -1366,15 +1380,17 @@ func TestPush(t *testing.T) { Kind: envinfo.INGRESS, }, }, - containerComponents: []versionsCommon.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: "container1", - Container: &versionsCommon.Container{ - Endpoints: []versionsCommon.Endpoint{ - { - Name: "example", - TargetPort: 8080, - Secure: true, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + { + Name: "example", + TargetPort: 8080, + Secure: true, + }, }, }, }, @@ -1409,15 +1425,17 @@ func TestPush(t *testing.T) { Kind: envinfo.INGRESS, }, }, - containerComponents: []versionsCommon.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: "container1", - Container: &versionsCommon.Container{ - Endpoints: []versionsCommon.Endpoint{ - { - Name: "example", - TargetPort: 8080, - Secure: true, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + { + Name: "example", + TargetPort: 8080, + Secure: true, + }, }, }, }, @@ -1451,16 +1469,18 @@ func TestPush(t *testing.T) { Kind: envinfo.INGRESS, }, }, - containerComponents: []versionsCommon.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: "container1", - Container: &versionsCommon.Container{ - Endpoints: []versionsCommon.Endpoint{ - { - Name: "example", - TargetPort: 8080, - Secure: true, - Exposure: versionsCommon.Internal, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + { + Name: "example", + TargetPort: 8080, + Secure: true, + Exposure: devfilev1.InternalEndpointExposure, + }, }, }, }, @@ -1482,16 +1502,18 @@ func TestPush(t *testing.T) { Kind: envinfo.INGRESS, }, }, - containerComponents: []versionsCommon.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: "container1", - Container: &versionsCommon.Container{ - Endpoints: []versionsCommon.Endpoint{ - { - Name: "example", - TargetPort: 8080, - Secure: true, - Exposure: versionsCommon.None, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + { + Name: "example", + TargetPort: 8080, + Secure: true, + Exposure: devfilev1.NoneEndpointExposure, + }, }, }, }, @@ -1512,16 +1534,18 @@ func TestPush(t *testing.T) { Kind: envinfo.ROUTE, }, }, - containerComponents: []versionsCommon.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: "container1", - Container: &versionsCommon.Container{ - Endpoints: []versionsCommon.Endpoint{ - { - Name: "example", - TargetPort: 8080, - Secure: true, - Exposure: versionsCommon.Internal, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + { + Name: "example", + TargetPort: 8080, + Secure: true, + Exposure: devfilev1.InternalEndpointExposure, + }, }, }, }, @@ -1542,16 +1566,18 @@ func TestPush(t *testing.T) { Kind: envinfo.ROUTE, }, }, - containerComponents: []versionsCommon.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: "container1", - Container: &versionsCommon.Container{ - Endpoints: []versionsCommon.Endpoint{ - { - Name: "example", - TargetPort: 8080, - Secure: true, - Exposure: versionsCommon.None, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + { + Name: "example", + TargetPort: 8080, + Secure: true, + Exposure: devfilev1.NoneEndpointExposure, + }, }, }, }, @@ -1567,15 +1593,17 @@ func TestPush(t *testing.T) { componentName: "nodejs", args: args{isRouteSupported: false}, existingEnvInfoURLs: []envinfo.EnvInfoURL{}, - containerComponents: []versionsCommon.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: "container1", - Container: &versionsCommon.Container{ - Endpoints: []versionsCommon.Endpoint{ - { - Name: "example", - TargetPort: 8080, - Secure: false, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + { + Name: "example", + TargetPort: 8080, + Secure: false, + }, }, }, }, @@ -1592,15 +1620,17 @@ func TestPush(t *testing.T) { applicationName: "app", args: args{isRouteSupported: true}, existingEnvInfoURLs: []envinfo.EnvInfoURL{}, - containerComponents: []versionsCommon.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: "container1", - Container: &versionsCommon.Container{ - Endpoints: []versionsCommon.Endpoint{ - { - Name: "example", - TargetPort: 8080, - Secure: false, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + { + Name: "example", + TargetPort: 8080, + Secure: false, + }, }, }, }, @@ -1635,15 +1665,17 @@ func TestPush(t *testing.T) { Kind: envinfo.INGRESS, }, }, - containerComponents: []versionsCommon.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: "container1", - Container: &versionsCommon.Container{ - Endpoints: []versionsCommon.Endpoint{ - { - Name: "example", - TargetPort: 8080, - Secure: false, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + { + Name: "example", + TargetPort: 8080, + Secure: false, + }, }, }, }, @@ -1673,16 +1705,18 @@ func TestPush(t *testing.T) { applicationName: "app", args: args{isRouteSupported: true}, existingEnvInfoURLs: []envinfo.EnvInfoURL{}, - containerComponents: []versionsCommon.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: "container1", - Container: &versionsCommon.Container{ - Endpoints: []versionsCommon.Endpoint{ - { - Name: "example", - TargetPort: 8080, - Secure: false, - Path: "/testpath", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + { + Name: "example", + TargetPort: 8080, + Secure: false, + Path: "/testpath", + }, }, }, }, @@ -1717,16 +1751,18 @@ func TestPush(t *testing.T) { Kind: envinfo.INGRESS, }, }, - containerComponents: []versionsCommon.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: "container1", - Container: &versionsCommon.Container{ - Endpoints: []versionsCommon.Endpoint{ - { - Name: "example", - TargetPort: 8080, - Secure: false, - Path: "/testpath", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + { + Name: "example", + TargetPort: 8080, + Secure: false, + Path: "/testpath", + }, }, }, }, @@ -2011,39 +2047,39 @@ func TestListIngressAndRoute(t *testing.T) { testURL5 := envinfo.EnvInfoURL{Name: "routeurl2", Kind: "route"} testURL6 := envinfo.EnvInfoURL{Name: "routeurl3", Port: 8080, Kind: "route"} - example1Endpoint := versionsCommon.Endpoint{ + example1Endpoint := devfilev1.Endpoint{ Name: "example-1", - Exposure: versionsCommon.Public, + Exposure: devfilev1.PublicEndpointExposure, TargetPort: 9090, - Protocol: versionsCommon.HTTP, + Protocol: devfilev1.HTTPEndpointProtocol, } - ingressurl3Endpoint := versionsCommon.Endpoint{ + ingressurl3Endpoint := devfilev1.Endpoint{ Name: "ingressurl3", - Exposure: versionsCommon.Public, + Exposure: devfilev1.PublicEndpointExposure, TargetPort: 8080, - Protocol: versionsCommon.HTTPS, + Protocol: devfilev1.HTTPSEndpointProtocol, Secure: true, } - exampleEndpoint := versionsCommon.Endpoint{ + exampleEndpoint := devfilev1.Endpoint{ Name: "example", - Exposure: versionsCommon.Public, + Exposure: devfilev1.PublicEndpointExposure, TargetPort: 8080, - Protocol: versionsCommon.HTTP, + Protocol: devfilev1.HTTPEndpointProtocol, } - routeurl2Endpoint := versionsCommon.Endpoint{ + routeurl2Endpoint := devfilev1.Endpoint{ Name: "routeurl2", - Exposure: versionsCommon.Public, + Exposure: devfilev1.PublicEndpointExposure, TargetPort: 8080, - Protocol: versionsCommon.HTTP, + Protocol: devfilev1.HTTPEndpointProtocol, } tests := []struct { name string component string envURLs []envinfo.EnvInfoURL - containerComponents []versionsCommon.DevfileComponent + containerComponents []devfilev1.Component routeSupported bool routeList *routev1.RouteList ingressList *extensionsv1.IngressList @@ -2053,12 +2089,14 @@ func TestListIngressAndRoute(t *testing.T) { name: "Should retrieve the URL list with both ingress and routes", component: componentName, envURLs: []envinfo.EnvInfoURL{testURL2, testURL3, testURL4, testURL5}, - containerComponents: []versionsCommon.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: containerName, - Container: &versionsCommon.Container{ - Endpoints: []versionsCommon.Endpoint{ - example1Endpoint, ingressurl3Endpoint, exampleEndpoint, routeurl2Endpoint, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + example1Endpoint, ingressurl3Endpoint, exampleEndpoint, routeurl2Endpoint, + }, }, }, }, @@ -2126,12 +2164,14 @@ func TestListIngressAndRoute(t *testing.T) { name: "Should retrieve only ingress URLs with routeSupported equals to false", component: componentName, envURLs: []envinfo.EnvInfoURL{testURL2, testURL3, testURL4, testURL5}, - containerComponents: []versionsCommon.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: containerName, - Container: &versionsCommon.Container{ - Endpoints: []versionsCommon.Endpoint{ - example1Endpoint, ingressurl3Endpoint, exampleEndpoint, routeurl2Endpoint, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + example1Endpoint, ingressurl3Endpoint, exampleEndpoint, routeurl2Endpoint, + }, }, }, }, @@ -2170,12 +2210,14 @@ func TestListIngressAndRoute(t *testing.T) { name: "Should retrieve only ingress URLs", component: componentName, envURLs: []envinfo.EnvInfoURL{testURL2, testURL3}, - containerComponents: []versionsCommon.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: containerName, - Container: &versionsCommon.Container{ - Endpoints: []versionsCommon.Endpoint{ - example1Endpoint, ingressurl3Endpoint, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + example1Endpoint, ingressurl3Endpoint, + }, }, }, }, @@ -2214,12 +2256,14 @@ func TestListIngressAndRoute(t *testing.T) { name: "Should retrieve only route URLs", component: componentName, envURLs: []envinfo.EnvInfoURL{testURL4, testURL5}, - containerComponents: []versionsCommon.DevfileComponent{ + containerComponents: []devfilev1.Component{ { Name: containerName, - Container: &versionsCommon.Container{ - Endpoints: []versionsCommon.Endpoint{ - exampleEndpoint, routeurl2Endpoint, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + exampleEndpoint, routeurl2Endpoint, + }, }, }, }, @@ -2339,38 +2383,38 @@ func TestGetIngressOrRoute(t *testing.T) { t.Log("Expected error since no physical env file to write") } fakecomponent := testingutil.GetFakeContainerComponent(containerName) - fakecomponent.Container.Endpoints = []versionsCommon.Endpoint{ + fakecomponent.Container.Endpoints = []devfilev1.Endpoint{ { Name: "ingressurl2", - Exposure: versionsCommon.Public, + Exposure: devfilev1.PublicEndpointExposure, TargetPort: 8080, - Protocol: versionsCommon.HTTP, + Protocol: devfilev1.HTTPEndpointProtocol, Path: "/", }, { Name: "ingressurl3", - Exposure: versionsCommon.Public, + Exposure: devfilev1.PublicEndpointExposure, TargetPort: 8080, - Protocol: versionsCommon.HTTP, + Protocol: devfilev1.HTTPEndpointProtocol, Secure: true, Path: "/", }, { Name: "example", - Exposure: versionsCommon.Public, + Exposure: devfilev1.PublicEndpointExposure, TargetPort: 8080, - Protocol: versionsCommon.HTTP, + Protocol: devfilev1.HTTPEndpointProtocol, Path: "/", }, { Name: "routeurl2", - Exposure: versionsCommon.Public, + Exposure: devfilev1.PublicEndpointExposure, TargetPort: 8080, - Protocol: versionsCommon.HTTP, + Protocol: devfilev1.HTTPEndpointProtocol, Path: "/", }, } - containerComponents := []versionsCommon.DevfileComponent{ + containerComponents := []devfilev1.Component{ fakecomponent, } @@ -2684,13 +2728,13 @@ func TestAddEndpointInDevfile(t *testing.T) { tests := []struct { name string devObj parser.DevfileObj - endpoint versionsCommon.Endpoint + endpoint devfilev1.Endpoint container string - wantComponents []versionsCommon.DevfileComponent + wantComponents []devfilev1.Component }{ { name: "Case 1: devfile has single container with existing endpoint", - endpoint: versionsCommon.Endpoint{ + endpoint: devfilev1.Endpoint{ Name: urlName, TargetPort: 8080, Secure: false, @@ -2699,15 +2743,19 @@ func TestAddEndpointInDevfile(t *testing.T) { devObj: parser.DevfileObj{ Ctx: devfileCtx.FakeContext(fs, parser.OutputDevfileYamlPath), Data: &testingutil.TestDevfileData{ - Components: []versionsCommon.DevfileComponent{ + Components: []devfilev1.Component{ { Name: "testcontainer1", - Container: &versionsCommon.Container{ - Image: "quay.io/nodejs-12", - Endpoints: []versionsCommon.Endpoint{ - { - Name: "port-3030", - TargetPort: 3000, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "quay.io/nodejs-12", + }, + Endpoints: []devfilev1.Endpoint{ + { + Name: "port-3030", + TargetPort: 3000, + }, }, }, }, @@ -2715,20 +2763,24 @@ func TestAddEndpointInDevfile(t *testing.T) { }, }, }, - wantComponents: []versionsCommon.DevfileComponent{ + wantComponents: []devfilev1.Component{ { Name: "testcontainer1", - Container: &versionsCommon.Container{ - Image: "quay.io/nodejs-12", - Endpoints: []versionsCommon.Endpoint{ - { - Name: "port-3030", - TargetPort: 3000, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "quay.io/nodejs-12", }, - { - Name: urlName, - TargetPort: 8080, - Secure: false, + Endpoints: []devfilev1.Endpoint{ + { + Name: "port-3030", + TargetPort: 3000, + }, + { + Name: urlName, + TargetPort: 8080, + Secure: false, + }, }, }, }, @@ -2737,7 +2789,7 @@ func TestAddEndpointInDevfile(t *testing.T) { }, { name: "Case 2: devfile has single container with no endpoint", - endpoint: versionsCommon.Endpoint{ + endpoint: devfilev1.Endpoint{ Name: urlName, TargetPort: 8080, Secure: false, @@ -2746,26 +2798,34 @@ func TestAddEndpointInDevfile(t *testing.T) { devObj: parser.DevfileObj{ Ctx: devfileCtx.FakeContext(fs, parser.OutputDevfileYamlPath), Data: &testingutil.TestDevfileData{ - Components: []versionsCommon.DevfileComponent{ + Components: []devfilev1.Component{ { Name: "testcontainer1", - Container: &versionsCommon.Container{ - Image: "quay.io/nodejs-12", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "quay.io/nodejs-12", + }, + }, }, }, }, }, }, - wantComponents: []versionsCommon.DevfileComponent{ + wantComponents: []devfilev1.Component{ { Name: "testcontainer1", - Container: &versionsCommon.Container{ - Image: "quay.io/nodejs-12", - Endpoints: []versionsCommon.Endpoint{ - { - Name: urlName, - TargetPort: 8080, - Secure: false, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "quay.io/nodejs-12", + }, + Endpoints: []devfilev1.Endpoint{ + { + Name: urlName, + TargetPort: 8080, + Secure: false, + }, }, }, }, @@ -2774,7 +2834,7 @@ func TestAddEndpointInDevfile(t *testing.T) { }, { name: "Case 3: devfile has multiple containers", - endpoint: versionsCommon.Endpoint{ + endpoint: devfilev1.Endpoint{ Name: urlName, TargetPort: 8080, Secure: false, @@ -2783,24 +2843,30 @@ func TestAddEndpointInDevfile(t *testing.T) { devObj: parser.DevfileObj{ Ctx: devfileCtx.FakeContext(fs, parser.OutputDevfileYamlPath), Data: &testingutil.TestDevfileData{ - Components: []versionsCommon.DevfileComponent{ + Components: []devfilev1.Component{ { Name: "testcontainer1", - Container: &versionsCommon.Container{ - Image: "quay.io/nodejs-12", + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "quay.io/nodejs-12", + }, + }, }, }, { Name: "testcontainer2", - Container: &versionsCommon.Container{ - Endpoints: []versionsCommon.Endpoint{ - { - Name: urlName2, - TargetPort: 9090, - Secure: true, - Path: "/testpath", - Exposure: versionsCommon.Internal, - Protocol: versionsCommon.HTTPS, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + { + Name: urlName2, + TargetPort: 9090, + Secure: true, + Path: "/testpath", + Exposure: devfilev1.InternalEndpointExposure, + Protocol: devfilev1.HTTPSEndpointProtocol, + }, }, }, }, @@ -2808,31 +2874,37 @@ func TestAddEndpointInDevfile(t *testing.T) { }, }, }, - wantComponents: []versionsCommon.DevfileComponent{ + wantComponents: []devfilev1.Component{ { Name: "testcontainer1", - Container: &versionsCommon.Container{ - Image: "quay.io/nodejs-12", - Endpoints: []versionsCommon.Endpoint{ - { - Name: urlName, - TargetPort: 8080, - Secure: false, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "quay.io/nodejs-12", + }, + Endpoints: []devfilev1.Endpoint{ + { + Name: urlName, + TargetPort: 8080, + Secure: false, + }, }, }, }, }, { Name: "testcontainer2", - Container: &versionsCommon.Container{ - Endpoints: []versionsCommon.Endpoint{ - { - Name: urlName2, - TargetPort: 9090, - Secure: true, - Path: "/testpath", - Exposure: versionsCommon.Internal, - Protocol: versionsCommon.HTTPS, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + { + Name: urlName2, + TargetPort: 9090, + Secure: true, + Path: "/testpath", + Exposure: devfilev1.InternalEndpointExposure, + Protocol: devfilev1.HTTPSEndpointProtocol, + }, }, }, }, @@ -2861,9 +2933,9 @@ func TestRemoveEndpointInDevfile(t *testing.T) { tests := []struct { name string devObj parser.DevfileObj - endpoint versionsCommon.Endpoint + endpoint devfilev1.Endpoint urlName string - wantComponents []versionsCommon.DevfileComponent + wantComponents []devfilev1.Component wantErr bool }{ { @@ -2872,20 +2944,24 @@ func TestRemoveEndpointInDevfile(t *testing.T) { devObj: parser.DevfileObj{ Ctx: devfileCtx.FakeContext(fs, parser.OutputDevfileYamlPath), Data: &testingutil.TestDevfileData{ - Components: []versionsCommon.DevfileComponent{ + Components: []devfilev1.Component{ { Name: "testcontainer1", - Container: &versionsCommon.Container{ - Image: "quay.io/nodejs-12", - Endpoints: []versionsCommon.Endpoint{ - { - Name: "port-3030", - TargetPort: 3000, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "quay.io/nodejs-12", }, - { - Name: urlName, - TargetPort: 8080, - Secure: false, + Endpoints: []devfilev1.Endpoint{ + { + Name: "port-3030", + TargetPort: 3000, + }, + { + Name: urlName, + TargetPort: 8080, + Secure: false, + }, }, }, }, @@ -2893,15 +2969,19 @@ func TestRemoveEndpointInDevfile(t *testing.T) { }, }, }, - wantComponents: []versionsCommon.DevfileComponent{ + wantComponents: []devfilev1.Component{ { Name: "testcontainer1", - Container: &versionsCommon.Container{ - Image: "quay.io/nodejs-12", - Endpoints: []versionsCommon.Endpoint{ - { - Name: "port-3030", - TargetPort: 3000, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "quay.io/nodejs-12", + }, + Endpoints: []devfilev1.Endpoint{ + { + Name: "port-3030", + TargetPort: 3000, + }, }, }, }, @@ -2915,16 +2995,20 @@ func TestRemoveEndpointInDevfile(t *testing.T) { devObj: parser.DevfileObj{ Ctx: devfileCtx.FakeContext(fs, parser.OutputDevfileYamlPath), Data: &testingutil.TestDevfileData{ - Components: []versionsCommon.DevfileComponent{ + Components: []devfilev1.Component{ { Name: "testcontainer1", - Container: &versionsCommon.Container{ - Image: "quay.io/nodejs-12", - Endpoints: []versionsCommon.Endpoint{ - { - Name: urlName, - TargetPort: 8080, - Secure: false, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "quay.io/nodejs-12", + }, + Endpoints: []devfilev1.Endpoint{ + { + Name: urlName, + TargetPort: 8080, + Secure: false, + }, }, }, }, @@ -2932,12 +3016,16 @@ func TestRemoveEndpointInDevfile(t *testing.T) { }, }, }, - wantComponents: []versionsCommon.DevfileComponent{ + wantComponents: []devfilev1.Component{ { Name: "testcontainer1", - Container: &versionsCommon.Container{ - Image: "quay.io/nodejs-12", - Endpoints: []versionsCommon.Endpoint{}, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "quay.io/nodejs-12", + }, + Endpoints: []devfilev1.Endpoint{}, + }, }, }, }, @@ -2949,31 +3037,37 @@ func TestRemoveEndpointInDevfile(t *testing.T) { devObj: parser.DevfileObj{ Ctx: devfileCtx.FakeContext(fs, parser.OutputDevfileYamlPath), Data: &testingutil.TestDevfileData{ - Components: []versionsCommon.DevfileComponent{ + Components: []devfilev1.Component{ { Name: "testcontainer1", - Container: &versionsCommon.Container{ - Image: "quay.io/nodejs-12", - Endpoints: []versionsCommon.Endpoint{ - { - Name: urlName, - TargetPort: 8080, - Secure: false, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "quay.io/nodejs-12", + }, + Endpoints: []devfilev1.Endpoint{ + { + Name: urlName, + TargetPort: 8080, + Secure: false, + }, }, }, }, }, { Name: "testcontainer2", - Container: &versionsCommon.Container{ - Endpoints: []versionsCommon.Endpoint{ - { - Name: urlName2, - TargetPort: 9090, - Secure: true, - Path: "/testpath", - Exposure: versionsCommon.Internal, - Protocol: versionsCommon.HTTPS, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + { + Name: urlName2, + TargetPort: 9090, + Secure: true, + Path: "/testpath", + Exposure: devfilev1.InternalEndpointExposure, + Protocol: devfilev1.HTTPSEndpointProtocol, + }, }, }, }, @@ -2981,25 +3075,31 @@ func TestRemoveEndpointInDevfile(t *testing.T) { }, }, }, - wantComponents: []versionsCommon.DevfileComponent{ + wantComponents: []devfilev1.Component{ { Name: "testcontainer1", - Container: &versionsCommon.Container{ - Image: "quay.io/nodejs-12", - Endpoints: []versionsCommon.Endpoint{}, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "quay.io/nodejs-12", + }, + Endpoints: []devfilev1.Endpoint{}, + }, }, }, { Name: "testcontainer2", - Container: &versionsCommon.Container{ - Endpoints: []versionsCommon.Endpoint{ - { - Name: urlName2, - TargetPort: 9090, - Secure: true, - Path: "/testpath", - Exposure: versionsCommon.Internal, - Protocol: versionsCommon.HTTPS, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Endpoints: []devfilev1.Endpoint{ + { + Name: urlName2, + TargetPort: 9090, + Secure: true, + Path: "/testpath", + Exposure: devfilev1.InternalEndpointExposure, + Protocol: devfilev1.HTTPSEndpointProtocol, + }, }, }, }, @@ -3013,16 +3113,20 @@ func TestRemoveEndpointInDevfile(t *testing.T) { devObj: parser.DevfileObj{ Ctx: devfileCtx.FakeContext(fs, parser.OutputDevfileYamlPath), Data: &testingutil.TestDevfileData{ - Components: []versionsCommon.DevfileComponent{ + Components: []devfilev1.Component{ { Name: "testcontainer1", - Container: &versionsCommon.Container{ - Image: "quay.io/nodejs-12", - Endpoints: []versionsCommon.Endpoint{ - { - Name: urlName, - TargetPort: 8080, - Secure: false, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "quay.io/nodejs-12", + }, + Endpoints: []devfilev1.Endpoint{ + { + Name: urlName, + TargetPort: 8080, + Secure: false, + }, }, }, }, @@ -3030,16 +3134,20 @@ func TestRemoveEndpointInDevfile(t *testing.T) { }, }, }, - wantComponents: []versionsCommon.DevfileComponent{ + wantComponents: []devfilev1.Component{ { Name: "testcontainer1", - Container: &versionsCommon.Container{ - Image: "quay.io/nodejs-12", - Endpoints: []versionsCommon.Endpoint{ - { - Name: urlName, - TargetPort: 8080, - Secure: false, + ComponentUnion: devfilev1.ComponentUnion{ + Container: &devfilev1.ContainerComponent{ + Container: devfilev1.Container{ + Image: "quay.io/nodejs-12", + }, + Endpoints: []devfilev1.Endpoint{ + { + Name: urlName, + TargetPort: 8080, + Secure: false, + }, }, }, }, diff --git a/tests/integration/component.go b/tests/integration/component.go index 11a62fff8..993e9c97a 100644 --- a/tests/integration/component.go +++ b/tests/integration/component.go @@ -64,7 +64,7 @@ func componentTests(args ...string) { helper.CmdShouldPass("odo", append(args, "create", "--s2i", "nodejs", "--project", commonVar.Project, componentName, "--ref", "master", "--git", "https://github.com/openshift/nodejs-ex")...) helper.ValidateLocalCmpExist(commonVar.Context, "Type,nodejs", "Name,"+componentName, "Application,app") helper.CmdShouldPass("odo", append(args, "push")...) - appName := helper.CmdShouldPass("odo", "app", "list") + appName := helper.CmdShouldPass("odo", "app", "list", "--project", commonVar.Project) Expect(appName).ToNot(BeEmpty()) // checking if application name is set to "app" diff --git a/tests/integration/devfile/cmd_devfile_push_test.go b/tests/integration/devfile/cmd_devfile_push_test.go index 292c2a4fe..d0e3ebc3b 100644 --- a/tests/integration/devfile/cmd_devfile_push_test.go +++ b/tests/integration/devfile/cmd_devfile_push_test.go @@ -786,7 +786,7 @@ var _ = Describe("odo devfile push command tests", func() { // Verify odo push failed output := helper.CmdShouldFail("odo", "push", "--context", commonVar.Context) - Expect(output).To(ContainSubstring("this Devfile version is not supported")) + Expect(output).To(ContainSubstring("unable to find schema for version \"1.0.0\"")) }) }) diff --git a/vendor/github.com/devfile/api/LICENSE b/vendor/github.com/devfile/api/LICENSE new file mode 100644 index 000000000..d3087e4c5 --- /dev/null +++ b/vendor/github.com/devfile/api/LICENSE @@ -0,0 +1,277 @@ +Eclipse Public License - v 2.0 + + THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE + PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION + OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + + a) in the case of the initial Contributor, the initial content + Distributed under this Agreement, and + + b) in the case of each subsequent Contributor: + i) changes to the Program, and + ii) additions to the Program; + where such changes and/or additions to the Program originate from + and are Distributed by that particular Contributor. A Contribution + "originates" from a Contributor if it was added to the Program by + such Contributor itself or anyone acting on such Contributor's behalf. + Contributions do not include changes or additions to the Program that + are not Modified Works. + +"Contributor" means any person or entity that Distributes the Program. + +"Licensed Patents" mean patent claims licensable by a Contributor which +are necessarily infringed by the use or sale of its Contribution alone +or when combined with the Program. + +"Program" means the Contributions Distributed in accordance with this +Agreement. + +"Recipient" means anyone who receives the Program under this Agreement +or any Secondary License (as applicable), including Contributors. + +"Derivative Works" shall mean any work, whether in Source Code or other +form, that is based on (or derived from) the Program and for which the +editorial revisions, annotations, elaborations, or other modifications +represent, as a whole, an original work of authorship. + +"Modified Works" shall mean any work in Source Code or other form that +results from an addition to, deletion from, or modification of the +contents of the Program, including, for purposes of clarity any new file +in Source Code form that contains any contents of the Program. Modified +Works shall not include works that contain only declarations, +interfaces, types, classes, structures, or files of the Program solely +in each case in order to link to, bind by name, or subclass the Program +or Modified Works thereof. + +"Distribute" means the acts of a) distributing or b) making available +in any manner that enables the transfer of a copy. + +"Source Code" means the form of a Program preferred for making +modifications, including but not limited to software source code, +documentation source, and configuration files. + +"Secondary License" means either the GNU General Public License, +Version 2.0, or any later versions of that license, including any +exceptions or additional permissions as identified by the initial +Contributor. + +2. GRANT OF RIGHTS + + a) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free copyright + license to reproduce, prepare Derivative Works of, publicly display, + publicly perform, Distribute and sublicense the Contribution of such + Contributor, if any, and such Derivative Works. + + b) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free patent + license under Licensed Patents to make, use, sell, offer to sell, + import and otherwise transfer the Contribution of such Contributor, + if any, in Source Code or other form. This patent license shall + apply to the combination of the Contribution and the Program if, at + the time the Contribution is added by the Contributor, such addition + of the Contribution causes such combination to be covered by the + Licensed Patents. The patent license shall not apply to any other + combinations which include the Contribution. No hardware per se is + licensed hereunder. + + c) Recipient understands that although each Contributor grants the + licenses to its Contributions set forth herein, no assurances are + provided by any Contributor that the Program does not infringe the + patent or other intellectual property rights of any other entity. + Each Contributor disclaims any liability to Recipient for claims + brought by any other entity based on infringement of intellectual + property rights or otherwise. As a condition to exercising the + rights and licenses granted hereunder, each Recipient hereby + assumes sole responsibility to secure any other intellectual + property rights needed, if any. For example, if a third party + patent license is required to allow Recipient to Distribute the + Program, it is Recipient's responsibility to acquire that license + before distributing the Program. + + d) Each Contributor represents that to its knowledge it has + sufficient copyright rights in its Contribution, if any, to grant + the copyright license set forth in this Agreement. + + e) Notwithstanding the terms of any Secondary License, no + Contributor makes additional grants to any Recipient (other than + those set forth in this Agreement) as a result of such Recipient's + receipt of the Program under the terms of a Secondary License + (if permitted under the terms of Section 3). + +3. REQUIREMENTS + +3.1 If a Contributor Distributes the Program in any form, then: + + a) the Program must also be made available as Source Code, in + accordance with section 3.2, and the Contributor must accompany + the Program with a statement that the Source Code for the Program + is available under this Agreement, and informs Recipients how to + obtain it in a reasonable manner on or through a medium customarily + used for software exchange; and + + b) the Contributor may Distribute the Program under a license + different than this Agreement, provided that such license: + i) effectively disclaims on behalf of all other Contributors all + warranties and conditions, express and implied, including + warranties or conditions of title and non-infringement, and + implied warranties or conditions of merchantability and fitness + for a particular purpose; + + ii) effectively excludes on behalf of all other Contributors all + liability for damages, including direct, indirect, special, + incidental and consequential damages, such as lost profits; + + iii) does not attempt to limit or alter the recipients' rights + in the Source Code under section 3.2; and + + iv) requires any subsequent distribution of the Program by any + party to be under a license that satisfies the requirements + of this section 3. + +3.2 When the Program is Distributed as Source Code: + + a) it must be made available under this Agreement, or if the + Program (i) is combined with other material in a separate file or + files made available under a Secondary License, and (ii) the initial + Contributor attached to the Source Code the notice described in + Exhibit A of this Agreement, then the Program may be made available + under the terms of such Secondary Licenses, and + + b) a copy of this Agreement must be included with each copy of + the Program. + +3.3 Contributors may not remove or alter any copyright, patent, +trademark, attribution notices, disclaimers of warranty, or limitations +of liability ("notices") contained within the Program from any copy of +the Program which they Distribute, provided that Contributors may add +their own appropriate notices. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities +with respect to end users, business partners and the like. While this +license is intended to facilitate the commercial use of the Program, +the Contributor who includes the Program in a commercial product +offering should do so in a manner which does not create potential +liability for other Contributors. Therefore, if a Contributor includes +the Program in a commercial product offering, such Contributor +("Commercial Contributor") hereby agrees to defend and indemnify every +other Contributor ("Indemnified Contributor") against any losses, +damages and costs (collectively "Losses") arising from claims, lawsuits +and other legal actions brought by a third party against the Indemnified +Contributor to the extent caused by the acts or omissions of such +Commercial Contributor in connection with its distribution of the Program +in a commercial product offering. The obligations in this section do not +apply to any claims or Losses relating to any actual or alleged +intellectual property infringement. In order to qualify, an Indemnified +Contributor must: a) promptly notify the Commercial Contributor in +writing of such claim, and b) allow the Commercial Contributor to control, +and cooperate with the Commercial Contributor in, the defense and any +related settlement negotiations. The Indemnified Contributor may +participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial +product offering, Product X. That Contributor is then a Commercial +Contributor. If that Commercial Contributor then makes performance +claims, or offers warranties related to Product X, those performance +claims and warranties are such Commercial Contributor's responsibility +alone. Under this section, the Commercial Contributor would have to +defend claims against the other Contributors related to those performance +claims and warranties, and if a court requires any other Contributor to +pay any damages as a result, the Commercial Contributor must pay +those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT +PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS" +BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR +IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF +TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR +PURPOSE. Each Recipient is solely responsible for determining the +appropriateness of using and distributing the Program and assumes all +risks associated with its exercise of rights under this Agreement, +including but not limited to the risks and costs of program errors, +compliance with applicable laws, damage to or loss of data, programs +or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT +PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS +SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST +PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE +EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under +applicable law, it shall not affect the validity or enforceability of +the remainder of the terms of this Agreement, and without further +action by the parties hereto, such provision shall be reformed to the +minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against any entity +(including a cross-claim or counterclaim in a lawsuit) alleging that the +Program itself (excluding combinations of the Program with other software +or hardware) infringes such Recipient's patent(s), then such Recipient's +rights granted under Section 2(b) shall terminate as of the date such +litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it +fails to comply with any of the material terms or conditions of this +Agreement and does not cure such failure in a reasonable period of +time after becoming aware of such noncompliance. If all Recipient's +rights under this Agreement terminate, Recipient agrees to cease use +and distribution of the Program as soon as reasonably practicable. +However, Recipient's obligations under this Agreement and any licenses +granted by Recipient relating to the Program shall continue and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, +but in order to avoid inconsistency the Agreement is copyrighted and +may only be modified in the following manner. The Agreement Steward +reserves the right to publish new versions (including revisions) of +this Agreement from time to time. No one other than the Agreement +Steward has the right to modify this Agreement. The Eclipse Foundation +is the initial Agreement Steward. The Eclipse Foundation may assign the +responsibility to serve as the Agreement Steward to a suitable separate +entity. Each new version of the Agreement will be given a distinguishing +version number. The Program (including Contributions) may always be +Distributed subject to the version of the Agreement under which it was +received. In addition, after a new version of the Agreement is published, +Contributor may elect to Distribute the Program (including its +Contributions) under the new version. + +Except as expressly stated in Sections 2(a) and 2(b) above, Recipient +receives no rights or licenses to the intellectual property of any +Contributor under this Agreement, whether expressly, by implication, +estoppel or otherwise. All rights in the Program not expressly granted +under this Agreement are reserved. Nothing in this Agreement is intended +to be enforceable by any entity that is not a Contributor or Recipient. +No third-party beneficiary rights are created under this Agreement. + +Exhibit A - Form of Secondary Licenses Notice + +"This Source Code may also be made available under the following +Secondary Licenses when the conditions for such availability set forth +in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), +version(s), and exceptions or additional permissions here}." + + Simply including a copy of this Agreement, including this Exhibit A + is not sufficient to license the Source Code under Secondary Licenses. + + If it is not possible or desirable to put the notice in a particular + file, then You may include the notice in a location (such as a LICENSE + file in a relevant directory) where a recipient would be likely to + look for such a notice. + + You may add additional accurate notices of copyright ownership. diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/WorkspacePodContribution.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/WorkspacePodContribution.go new file mode 100644 index 000000000..c85595ff4 --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/WorkspacePodContribution.go @@ -0,0 +1,31 @@ +package v1alpha2 + +import ( + corev1 "k8s.io/api/core/v1" +) + +type WorkspacePodContributions struct { + // +optional + // +patchMergeKey=name + // +patchStrategy=merge,retainKeys + Volumes []corev1.Volume `json:"volumes,omitempty" patchStrategy:"merge,retainKeys" patchMergeKey:"name" protobuf:"bytes,1,rep,name=volumes"` + // +patchMergeKey=name + // +patchStrategy=merge + InitContainers []corev1.Container `json:"initContainers,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,20,rep,name=initContainers"` + // +patchMergeKey=name + // +patchStrategy=merge + Containers []corev1.Container `json:"containers" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,2,rep,name=containers"` + // ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by the workspace Pod. + // If specified, these secrets will be passed to individual puller implementations for them to use. For example, + // in the case of docker, only DockerConfig type secrets are honored. + // More info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,15,rep,name=imagePullSecrets"` + // List of workspace-wide environment variables to set in all containers of the workspace POD. + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + CommonEnv []corev1.EnvVar `json:"env,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,7,rep,name=env"` +} diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/commands.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/commands.go new file mode 100644 index 000000000..aee3b619c --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/commands.go @@ -0,0 +1,218 @@ +package v1alpha2 + +import runtime "k8s.io/apimachinery/pkg/runtime" + +// CommandType describes the type of command. +// Only one of the following command type may be specified. +// +kubebuilder:validation:Enum=Exec;Apply;VscodeTask;VscodeLaunch;Composite;Custom +type CommandType string + +const ( + ExecCommandType CommandType = "Exec" + ApplyCommandType CommandType = "Apply" + VscodeTaskCommandType CommandType = "VscodeTask" + VscodeLaunchCommandType CommandType = "VscodeLaunch" + CompositeCommandType CommandType = "Composite" + CustomCommandType CommandType = "Custom" +) + +// CommandGroupKind describes the kind of command group. +// +kubebuilder:validation:Enum=build;run;test;debug +type CommandGroupKind string + +const ( + BuildCommandGroupKind CommandGroupKind = "build" + RunCommandGroupKind CommandGroupKind = "run" + TestCommandGroupKind CommandGroupKind = "test" + DebugCommandGroupKind CommandGroupKind = "debug" +) + +type CommandGroup struct { + // Kind of group the command is part of + Kind CommandGroupKind `json:"kind"` + + // +optional + // Identifies the default command for a given group kind + IsDefault bool `json:"isDefault,omitempty"` +} + +type BaseCommand struct { + // +optional + // Defines the group this command is part of + Group *CommandGroup `json:"group,omitempty"` + + // Optional map of free-form additional command attributes + Attributes map[string]string `json:"attributes,omitempty"` +} + +type LabeledCommand struct { + BaseCommand `json:",inline"` + + // +optional + // Optional label that provides a label for this command + // to be used in Editor UI menus for example + Label string `json:"label,omitempty"` +} + +type Command struct { + // Mandatory identifier that allows referencing + // this command in composite commands, from + // a parent, or in events. + Id string `json:"id"` + CommandUnion `json:",inline"` +} + +// +union +type CommandUnion struct { + // Type of workspace command + // +unionDiscriminator + // +optional + CommandType CommandType `json:"commandType,omitempty"` + + // CLI Command executed in an existing component container + // +optional + Exec *ExecCommand `json:"exec,omitempty"` + + // Command that consists in applying a given component definition, + // typically bound to a workspace event. + // + // For example, when an `apply` command is bound to a `preStart` event, + // and references a `container` component, it will start the container as a + // K8S initContainer in the workspace POD, unless the component has its + // `dedicatedPod` field set to `true`. + // + // When no `apply` command exist for a given component, + // it is assumed the component will be applied at workspace start + // by default. + // +optional + Apply *ApplyCommand `json:"apply,omitempty"` + + // Command providing the definition of a VsCode Task + // +optional + VscodeTask *VscodeConfigurationCommand `json:"vscodeTask,omitempty"` + + // Command providing the definition of a VsCode launch action + // +optional + VscodeLaunch *VscodeConfigurationCommand `json:"vscodeLaunch,omitempty"` + + // Composite command that allows executing several sub-commands + // either sequentially or concurrently + // +optional + Composite *CompositeCommand `json:"composite,omitempty"` + + // Custom command whose logic is implementation-dependant + // and should be provided by the user + // possibly through some dedicated plugin + // +optional + // +devfile:overrides:include:omit=true + Custom *CustomCommand `json:"custom,omitempty"` +} + +type ExecCommand struct { + LabeledCommand `json:",inline"` + + // The actual command-line string + // + // Special variables that can be used: + // + // - `$PROJECTS_ROOT`: A path where projects sources are mounted as defined by container component's sourceMapping. + // + // - `$PROJECT_SOURCE`: A path to a project source ($PROJECTS_ROOT/). If there are multiple projects, this will point to the directory of the first one. + CommandLine string `json:"commandLine"` + + // Describes component to which given action relates + // + Component string `json:"component"` + + // Working directory where the command should be executed + // + // Special variables that can be used: + // + // - `$PROJECTS_ROOT`: A path where projects sources are mounted as defined by container component's sourceMapping. + // + // - `$PROJECT_SOURCE`: A path to a project source ($PROJECTS_ROOT/). If there are multiple projects, this will point to the directory of the first one. + // +optional + WorkingDir string `json:"workingDir,omitempty"` + + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + // Optional list of environment variables that have to be set + // before running the command + Env []EnvVar `json:"env,omitempty" patchStrategy:"merge" patchMergeKey:"name"` + + // +optional + // Whether the command is capable to reload itself when source code changes. + // If set to `true` the command won't be restarted and it is expected to handle file changes on its own. + // + // Default value is `false` + HotReloadCapable bool `json:"hotReloadCapable,omitempty"` +} + +type ApplyCommand struct { + LabeledCommand `json:",inline"` + + // Describes component that will be applied + // + Component string `json:"component"` +} + +type CompositeCommand struct { + LabeledCommand `json:",inline"` + + // The commands that comprise this composite command + Commands []string `json:"commands,omitempty" patchStrategy:"replace"` + + // Indicates if the sub-commands should be executed concurrently + // +optional + Parallel bool `json:"parallel,omitempty"` +} + +// VscodeConfigurationCommandLocationType describes the type of +// the location the configuration is fetched from. +// Only one of the following component type may be specified. +// +kubebuilder:validation:Enum=Uri;Inlined +type VscodeConfigurationCommandLocationType string + +const ( + UriVscodeConfigurationCommandLocationType VscodeConfigurationCommandLocationType = "Uri" + InlinedVscodeConfigurationCommandLocationType VscodeConfigurationCommandLocationType = "Inlined" +) + +// +union +type VscodeConfigurationCommandLocation struct { + // Type of Vscode configuration command location + // + + // +unionDiscriminator + // +optional + LocationType VscodeConfigurationCommandLocationType `json:"locationType,omitempty"` + + // Location as an absolute of relative URI + // the VsCode configuration will be fetched from + // +optional + Uri string `json:"uri,omitempty"` + + // Inlined content of the VsCode configuration + // +optional + Inlined string `json:"inlined,omitempty"` +} + +type VscodeConfigurationCommand struct { + BaseCommand `json:",inline"` + VscodeConfigurationCommandLocation `json:",inline"` +} + +type CustomCommand struct { + LabeledCommand `json:",inline"` + + // Class of command that the associated implementation component + // should use to process this command with the appropriate logic + CommandClass string `json:"commandClass"` + + // Additional free-form configuration for this custom command + // that the implementation component will know how to use + // + // +kubebuilder:pruning:PreserveUnknownFields + // +kubebuilder:validation:EmbeddedResource + EmbeddedResource runtime.RawExtension `json:"embeddedResource"` +} diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/components.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/components.go new file mode 100644 index 000000000..39eeca7f0 --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/components.go @@ -0,0 +1,93 @@ +package v1alpha2 + +import runtime "k8s.io/apimachinery/pkg/runtime" + +// ComponentType describes the type of component. +// Only one of the following component type may be specified. +// +kubebuilder:validation:Enum=Container;Kubernetes;Openshift;Volume;Plugin;Custom +type ComponentType string + +const ( + ContainerComponentType ComponentType = "Container" + KubernetesComponentType ComponentType = "Kubernetes" + OpenshiftComponentType ComponentType = "Openshift" + PluginComponentType ComponentType = "Plugin" + VolumeComponentType ComponentType = "Volume" + CustomComponentType ComponentType = "Custom" +) + +// Workspace component: Anything that will bring additional features / tooling / behaviour / context +// to the workspace, in order to make working in it easier. +type BaseComponent struct { +} + +//+k8s:openapi-gen=true +type Component struct { + // Mandatory name that allows referencing the component + // from other elements (such as commands) or from an external + // devfile that may reference this component through a parent or a plugin. + Name string `json:"name"` + ComponentUnion `json:",inline"` +} + +// +union +type ComponentUnion struct { + // Type of component + // + // +unionDiscriminator + // +optional + ComponentType ComponentType `json:"componentType,omitempty"` + + // Allows adding and configuring workspace-related containers + // +optional + Container *ContainerComponent `json:"container,omitempty"` + + // Allows importing into the workspace the Kubernetes resources + // defined in a given manifest. For example this allows reusing the Kubernetes + // definitions used to deploy some runtime components in production. + // + // +optional + Kubernetes *KubernetesComponent `json:"kubernetes,omitempty"` + + // Allows importing into the workspace the OpenShift resources + // defined in a given manifest. For example this allows reusing the OpenShift + // definitions used to deploy some runtime components in production. + // + // +optional + Openshift *OpenshiftComponent `json:"openshift,omitempty"` + + // Allows specifying the definition of a volume + // shared by several other components + // +optional + Volume *VolumeComponent `json:"volume,omitempty"` + + // Allows importing a plugin. + // + // Plugins are mainly imported devfiles that contribute components, commands + // and events as a consistent single unit. They are defined in either YAML files + // following the devfile syntax, + // or as `DevWorkspaceTemplate` Kubernetes Custom Resources + // +optional + // +devfile:overrides:include:omitInPlugin=true + Plugin *PluginComponent `json:"plugin,omitempty"` + + // Custom component whose logic is implementation-dependant + // and should be provided by the user + // possibly through some dedicated controller + // +optional + // +devfile:overrides:include:omit=true + Custom *CustomComponent `json:"custom,omitempty"` +} + +type CustomComponent struct { + // Class of component that the associated implementation controller + // should use to process this command with the appropriate logic + ComponentClass string `json:"componentClass"` + + // Additional free-form configuration for this custom component + // that the implementation controller will know how to use + // + // +kubebuilder:pruning:PreserveUnknownFields + // +kubebuilder:validation:EmbeddedResource + EmbeddedResource runtime.RawExtension `json:"embeddedResource"` +} diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/containerComponent.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/containerComponent.go new file mode 100644 index 000000000..28b7dd201 --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/containerComponent.go @@ -0,0 +1,82 @@ +package v1alpha2 + +// Component that allows the developer to add a configured container into his workspace +type ContainerComponent struct { + BaseComponent `json:",inline"` + Container `json:",inline"` + Endpoints []Endpoint `json:"endpoints,omitempty" patchStrategy:"merge" patchMergeKey:"name"` +} + +type Container struct { + Image string `json:"image"` + + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + // Environment variables used in this container. + // + // The following variables are reserved and cannot be overridden via env: + // + // - `$PROJECTS_ROOT` + // + // - `$PROJECT_SOURCE` + Env []EnvVar `json:"env,omitempty" patchStrategy:"merge" patchMergeKey:"name"` + + // +optional + // List of volumes mounts that should be mounted is this container. + VolumeMounts []VolumeMount `json:"volumeMounts,omitempty" patchStrategy:"merge" patchMergeKey:"name"` + + // +optional + MemoryLimit string `json:"memoryLimit,omitempty"` + + // The command to run in the dockerimage component instead of the default one provided in the image. + // + // Defaults to an empty array, meaning use whatever is defined in the image. + // +optional + Command []string `json:"command,omitempty" patchStrategy:"replace"` + + // The arguments to supply to the command running the dockerimage component. The arguments are supplied either to the default command provided in the image or to the overridden command. + // + // Defaults to an empty array, meaning use whatever is defined in the image. + // +optional + Args []string `json:"args,omitempty" patchStrategy:"replace"` + + // Toggles whether or not the project source code should + // be mounted in the component. + // + // Defaults to true for all component types except plugins and components that set `dedicatedPod` to true. + // +optional + MountSources *bool `json:"mountSources,omitempty"` + + // Optional specification of the path in the container where + // project sources should be transferred/mounted when `mountSources` is `true`. + // When omitted, the default value of /projects is used. + // +optional + // +kubebuilder:default=/projects + SourceMapping string `json:"sourceMapping,omitempty"` + + // Specify if a container should run in its own separated pod, + // instead of running as part of the main development environment pod. + // + // Default value is `false` + // +optional + DedicatedPod bool `json:"dedicatedPod,omitempty"` +} + +type EnvVar struct { + Name string `json:"name" yaml:"name"` + Value string `json:"value" yaml:"value"` +} + +// Volume that should be mounted to a component container +type VolumeMount struct { + // The volume mount name is the name of an existing `Volume` component. + // If several containers mount the same volume name + // then they will reuse the same volume and will be able to access to the same files. + Name string `json:"name"` + + // The path in the component container where the volume should be mounted. + // If not path is mentioned, default path is the is `/`. + // +optional + Path string `json:"path,omitempty"` +} diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/devfile.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/devfile.go new file mode 100644 index 000000000..02ffc71fe --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/devfile.go @@ -0,0 +1,13 @@ +package v1alpha2 + +import ( + "github.com/devfile/api/pkg/devfile" +) + +// Devfile describes the structure of a cloud-native workspace and development environment. +// +devfile:jsonschema:generate:omitCustomUnionMembers=true +type Devfile struct { + devfile.DevfileHeader `json:",inline"` + + DevWorkspaceTemplateSpec `json:",inline"` +} diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/devworkspaceTemplateSpec.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/devworkspaceTemplateSpec.go new file mode 100644 index 000000000..96d10a508 --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/devworkspaceTemplateSpec.go @@ -0,0 +1,53 @@ +package v1alpha2 + +// Structure of the workspace. This is also the specification of a workspace template. +// +devfile:jsonschema:generate +type DevWorkspaceTemplateSpec struct { + // Parent workspace template + // +optional + Parent *Parent `json:"parent,omitempty"` + + DevWorkspaceTemplateSpecContent `json:",inline"` +} + +// +devfile:overrides:generate +type DevWorkspaceTemplateSpecContent struct { + // List of the workspace components, such as editor and plugins, + // user-provided containers, or other types of components + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + // +devfile:overrides:include:description=Overrides of components encapsulated in a parent devfile or a plugin. + // +devfile:toplevellist + Components []Component `json:"components,omitempty" patchStrategy:"merge" patchMergeKey:"name"` + + // Projects worked on in the workspace, containing names and sources locations + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + // +devfile:overrides:include:omitInPlugin=true,description=Overrides of projects encapsulated in a parent devfile. + // +devfile:toplevellist + Projects []Project `json:"projects,omitempty" patchStrategy:"merge" patchMergeKey:"name"` + + // StarterProjects is a project that can be used as a starting point when bootstrapping new projects + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + // +devfile:overrides:include:omitInPlugin=true,description=Overrides of starterProjects encapsulated in a parent devfile. + // +devfile:toplevellist + StarterProjects []StarterProject `json:"starterProjects,omitempty" patchStrategy:"merge" patchMergeKey:"name"` + + // Predefined, ready-to-use, workspace-related commands + // +optional + // +patchMergeKey=id + // +patchStrategy=merge + // +devfile:overrides:include:description=Overrides of commands encapsulated in a parent devfile or a plugin. + // +devfile:toplevellist + Commands []Command `json:"commands,omitempty" patchStrategy:"merge" patchMergeKey:"id"` + + // Bindings of commands to events. + // Each command is referred-to by its name. + // +optional + // +devfile:overrides:include:omit=true + Events *Events `json:"events,omitempty"` +} diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/devworkspace_types.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/devworkspace_types.go new file mode 100644 index 000000000..62ff4b0eb --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/devworkspace_types.go @@ -0,0 +1,91 @@ +package v1alpha2 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// DevWorkspaceSpec defines the desired state of DevWorkspace +type DevWorkspaceSpec struct { + Started bool `json:"started"` + RoutingClass string `json:"routingClass,omitempty"` + Template DevWorkspaceTemplateSpec `json:"template,omitempty"` +} + +// DevWorkspaceStatus defines the observed state of DevWorkspace +type DevWorkspaceStatus struct { + // Id of the workspace + WorkspaceId string `json:"workspaceId"` + // URL at which the Worksace Editor can be joined + IdeUrl string `json:"ideUrl,omitempty"` + Phase WorkspacePhase `json:"phase,omitempty"` + // Conditions represent the latest available observations of an object's state + Conditions []WorkspaceCondition `json:"conditions,omitempty"` +} + +type WorkspacePhase string + +// Valid workspace Statuses +const ( + WorkspaceStatusStarting WorkspacePhase = "Starting" + WorkspaceStatusRunning WorkspacePhase = "Running" + WorkspaceStatusStopped WorkspacePhase = "Stopped" + WorkspaceStatusStopping WorkspacePhase = "Stopping" + WorkspaceStatusFailed WorkspacePhase = "Failed" +) + +// WorkspaceCondition contains details for the current condition of this workspace. +type WorkspaceCondition struct { + // Type is the type of the condition. + Type WorkspaceConditionType `json:"type"` + // Phase is the status of the condition. + // Can be True, False, Unknown. + Status corev1.ConditionStatus `json:"status"` + // Last time the condition transitioned from one status to another. + LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"` + // Unique, one-word, CamelCase reason for the condition's last transition. + Reason string `json:"reason,omitempty"` + // Human-readable message indicating details about last transition. + Message string `json:"message,omitempty"` +} + +// Types of conditions reported by workspace +type WorkspaceConditionType string + +const ( + WorkspaceComponentsReady WorkspaceConditionType = "ComponentsReady" + WorkspaceRoutingReady WorkspaceConditionType = "RoutingReady" + WorkspaceServiceAccountReady WorkspaceConditionType = "ServiceAccountReady" + WorkspaceReady WorkspaceConditionType = "Ready" + WorkspaceFailedStart WorkspaceConditionType = "FailedStart" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// DevWorkspace is the Schema for the devworkspaces API +// +kubebuilder:subresource:status +// +kubebuilder:resource:path=devworkspaces,scope=Namespaced +// +kubebuilder:printcolumn:name="Workspace ID",type="string",JSONPath=".status.workspaceId",description="The workspace's unique id" +// +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase",description="The current workspace startup phase" +// +kubebuilder:printcolumn:name="URL",type="string",JSONPath=".status.ideUrl",description="Url endpoint for accessing workspace" +// +devfile:jsonschema:generate +type DevWorkspace struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec DevWorkspaceSpec `json:"spec,omitempty"` + Status DevWorkspaceStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// DevWorkspaceList contains a list of DevWorkspace +type DevWorkspaceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []DevWorkspace `json:"items"` +} + +func init() { + SchemeBuilder.Register(&DevWorkspace{}, &DevWorkspaceList{}) +} diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/devworkspacetemplate_types.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/devworkspacetemplate_types.go new file mode 100644 index 000000000..6b69e85dd --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/devworkspacetemplate_types.go @@ -0,0 +1,30 @@ +package v1alpha2 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// DevWorkspaceTemplate is the Schema for the devworkspacetemplates API +// +kubebuilder:resource:path=devworkspacetemplates,scope=Namespaced +// +devfile:jsonschema:generate +type DevWorkspaceTemplate struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec DevWorkspaceTemplateSpec `json:"spec,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// DevWorkspaceTemplateList contains a list of DevWorkspaceTemplate +type DevWorkspaceTemplateList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []DevWorkspaceTemplate `json:"items"` +} + +func init() { + SchemeBuilder.Register(&DevWorkspaceTemplate{}, &DevWorkspaceTemplateList{}) +} diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/doc.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/doc.go new file mode 100644 index 000000000..e243c3223 --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/doc.go @@ -0,0 +1,6 @@ +// Package v1alpha2 contains API Schema definitions for the org v1alpha2 API group +// +k8s:deepcopy-gen=package,register +// +k8s:openapi-gen=true +// +groupName=workspace.devfile.io +// +devfile:jsonschema:version=2.0.0-alpha2 +package v1alpha2 diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/endpoint.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/endpoint.go new file mode 100644 index 000000000..0f3d2991e --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/endpoint.go @@ -0,0 +1,106 @@ +package v1alpha2 + +// EndpointProtocol defines the application and transport protocols of the traffic that will go through this endpoint. +// Only one of the following protocols may be specified: http, ws, tcp, udp. +// +kubebuilder:validation:Enum=http;ws;tcp;udp +type EndpointProtocol string + +const ( + // Endpoint will have `http` traffic, typically on a TCP connection. + // It will be automaticaly promoted to `https` when the `secure` field is set to `true` + HTTPEndpointProtocol EndpointProtocol = "http" + // Endpoint will have `https` traffic, typically on a TCP connection + HTTPSEndpointProtocol EndpointProtocol = "https" + // Endpoint will have `ws` traffic, typically on a TCP connection + // It will be automaticaly promoted to `wss` when the `secure` field is set to `true` + WSEndpointProtocol EndpointProtocol = "ws" + // Endpoint will have `wss` traffic, typically on a TCP connection + WSSEndpointProtocol EndpointProtocol = "wss" + // Endpoint will have traffic on a TCP connection, + // without specifying an application protocol + TCPEndpointProtocol EndpointProtocol = "tcp" + // Endpoint will have traffic on an UDP connection, + // without specifying an application protocol + UDPEndpointProtocol EndpointProtocol = "udp" +) + +// EndpointExposure describes the way an endpoint is exposed on the network. +// Only one of the following exposures may be specified: public, internal, none. +// +kubebuilder:validation:Enum=public;internal;none +type EndpointExposure string + +const ( + // Endpoint will be exposed on the public network, typically through + // a K8S ingress or an OpenShift route + PublicEndpointExposure EndpointExposure = "public" + // Endpoint will be exposed internally outside of the main workspace POD, + // typically by K8S services, to be consumed by other elements running + // on the same cloud internal network. + InternalEndpointExposure EndpointExposure = "internal" + // Endpoint will not be exposed and will only be accessible + // inside the main workspace POD, on a local address. + NoneEndpointExposure EndpointExposure = "none" +) + +type Endpoint struct { + Name string `json:"name"` + + TargetPort int `json:"targetPort"` + + // Describes how the endpoint should be exposed on the network. + // + // - `public` means that the endpoint will be exposed on the public network, typically through + // a K8S ingress or an OpenShift route. + // + // - `internal` means that the endpoint will be exposed internally outside of the main workspace POD, + // typically by K8S services, to be consumed by other elements running + // on the same cloud internal network. + // + // - `none` means that the endpoint will not be exposed and will only be accessible + // inside the main workspace POD, on a local address. + // + // Default value is `public` + // +optional + // +kubebuilder:default=public + Exposure EndpointExposure `json:"exposure,omitempty"` + + // Describes the application and transport protocols of the traffic that will go through this endpoint. + // + // - `http`: Endpoint will have `http` traffic, typically on a TCP connection. + // It will be automaticaly promoted to `https` when the `secure` field is set to `true`. + // + // - `https`: Endpoint will have `https` traffic, typically on a TCP connection. + // + // - `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. + // It will be automaticaly promoted to `wss` when the `secure` field is set to `true`. + // + // - `wss`: Endpoint will have `wss` traffic, typically on a TCP connection. + // + // - `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol. + // + // - `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol. + // + // Default value is `http` + // +optional + // +kubebuilder:default=http + Protocol EndpointProtocol `json:"protocol,omitempty"` + + // Describes whether the endpoint should be secured and protected by some + // authentication process + // +optional + Secure bool `json:"secure,omitempty"` + + // Path of the endpoint URL + // +optional + Path string `json:"path,omitempty"` + + // Map of implementation-dependant string-based free-form attributes. + // + // Examples of Che-specific attributes: + // + // - cookiesAuthEnabled: "true" / "false", + // + // - type: "terminal" / "ide" / "ide-dev", + // +optional + Attributes map[string]string `json:"attributes,omitempty"` +} diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/events.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/events.go new file mode 100644 index 000000000..a12969939 --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/events.go @@ -0,0 +1,26 @@ +package v1alpha2 + +type Events struct { + WorkspaceEvents `json:",inline"` +} + +type WorkspaceEvents struct { + // Names of commands that should be executed before the workspace start. + // Kubernetes-wise, these commands would typically be executed in init containers of the workspace POD. + // +optional + PreStart []string `json:"preStart,omitempty"` + + // Names of commands that should be executed after the workspace is completely started. + // In the case of Che-Theia, these commands should be executed after all plugins and extensions have started, including project cloning. + // This means that those commands are not triggered until the user opens the IDE in his browser. + // +optional + PostStart []string `json:"postStart,omitempty"` + + // +optional + // Names of commands that should be executed before stopping the workspace. + PreStop []string `json:"preStop,omitempty"` + + // +optional + // Names of commands that should be executed after stopping the workspace. + PostStop []string `json:"postStop,omitempty"` +} diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/importReference.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/importReference.go new file mode 100644 index 000000000..a1b5bc88f --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/importReference.go @@ -0,0 +1,48 @@ +package v1alpha2 + +// ImportReferenceType describes the type of location +// from where the referenced template structure should be retrieved. +// Only one of the following parent locations may be specified. +// +kubebuilder:validation:Enum=Uri;Id;Kubernetes +type ImportReferenceType string + +const ( + UriImportReferenceType ImportReferenceType = "Uri" + IdImportReferenceType ImportReferenceType = "Id" + KubernetesImportReferenceType ImportReferenceType = "Kubernetes" +) + +// Location from where the an import reference is retrieved +// +union +type ImportReferenceUnion struct { + // type of location from where the referenced template structure should be retrieved + // + + // +unionDiscriminator + // +optional + ImportReferenceType ImportReferenceType `json:"importReferenceType,omitempty"` + + // Uri of a Devfile yaml file + // +optional + Uri string `json:"uri,omitempty"` + + // Id in a registry that contains a Devfile yaml file + // +optional + Id string `json:"id,omitempty"` + + // Reference to a Kubernetes CRD of type DevWorkspaceTemplate + // +optional + Kubernetes *KubernetesCustomResourceImportReference `json:"kubernetes,omitempty"` +} + +type KubernetesCustomResourceImportReference struct { + Name string `json:"name"` + + // +optional + Namespace string `json:"namespace,omitempty"` +} + +type ImportReference struct { + ImportReferenceUnion `json:",inline"` + // +optional + RegistryUrl string `json:"registryUrl,omitempty"` +} diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/keyed.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/keyed.go new file mode 100644 index 000000000..81182efc7 --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/keyed.go @@ -0,0 +1,51 @@ +package v1alpha2 + +// Keyed is expected to be implemented by the elements of the devfile top-level lists +// (such as Command, Component, Project, ...). +// +// The Keys of list objects will typically be used to merge the top-level lists +// according to strategic merge patch rules, during parent or plugin overriding. +// +k8s:deepcopy-gen=false +type Keyed interface { + // Key is a string that allows uniquely identifying the object, + // especially in the Devfile top-level lists that are map-like K8S-compatible lists. + Key() string +} + +// KeyedList is a list of object that are uniquely identified by a Key +// The devfile top-level list (such as Commands, Components, Projects, ...) +// are examples of such lists of Keyed objects +// +k8s:deepcopy-gen=false +type KeyedList []Keyed + +// GetKeys converts a KeyedList into a slice of string by calling Key() on each +// element in the list. +func (l KeyedList) GetKeys() []string { + var res []string + for _, keyed := range l { + res = append(res, keyed.Key()) + } + return res +} + +// TopLevelLists is a map that contains several Devfile top-level lists +// (such as `Commands`, `Components`, `Projects`, ...), available as `KeyedList`s. +// +// Each key of this map is the name of the field that contains the given top-level list: +// `Commands`, `Components`, etc... +// +k8s:deepcopy-gen=false +type TopLevelLists map[string]KeyedList + +// TopLevelListContainer is an interface that allows retrieving the devfile top-level lists +// from an object. +// Main implementor of this interface will be the `DevWorkspaceTemplateSpecContent`, which +// will return all its devfile top-level lists. +// +// But this will also be implemented by `Overrides` which may return less top-level lists +// the `DevWorkspaceTemplateSpecContent`, according to the top-level lists they can override. +// `PluginOverride` will not return the `Projects` and `StarterProjects` list, since plugins are +// not expected to override `projects` or `starterProjects` +// +k8s:deepcopy-gen=false +type TopLevelListContainer interface { + GetToplevelLists() TopLevelLists +} diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/keyed_implementations.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/keyed_implementations.go new file mode 100644 index 000000000..5c4703e83 --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/keyed_implementations.go @@ -0,0 +1,20 @@ +package v1alpha2 + +import ( + "reflect" +) + +func extractKeys(keyedList interface{}) []Keyed { + value := reflect.ValueOf(keyedList) + keys := make([]Keyed, 0, value.Len()) + for i := 0; i < value.Len(); i++ { + elem := value.Index(i) + if elem.CanInterface() { + i := elem.Interface() + if keyed, ok := i.(Keyed); ok { + keys = append(keys, keyed) + } + } + } + return keys +} diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/kubernetesLikeComponent.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/kubernetesLikeComponent.go new file mode 100644 index 000000000..02a18ed71 --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/kubernetesLikeComponent.go @@ -0,0 +1,45 @@ +package v1alpha2 + +// K8sLikeComponentLocationType describes the type of +// the location the configuration is fetched from. +// Only one of the following component type may be specified. +// +kubebuilder:validation:Enum=Uri;Inlined +type K8sLikeComponentLocationType string + +const ( + UriK8sLikeComponentLocationType K8sLikeComponentLocationType = "Uri" + InlinedK8sLikeComponentLocationType K8sLikeComponentLocationType = "Inlined" +) + +// +union +type K8sLikeComponentLocation struct { + // Type of Kubernetes-like location + // + + // +unionDiscriminator + // +optional + LocationType K8sLikeComponentLocationType `json:"locationType,omitempty"` + + // Location in a file fetched from a uri. + // +optional + Uri string `json:"uri,omitempty"` + + // Inlined manifest + // +optional + Inlined string `json:"inlined,omitempty"` +} + +type K8sLikeComponent struct { + BaseComponent `json:",inline"` + K8sLikeComponentLocation `json:",inline"` + Endpoints []Endpoint `json:"endpoints,omitempty" patchStrategy:"merge" patchMergeKey:"name"` +} + +// Component that allows partly importing Kubernetes resources into the workspace POD +type KubernetesComponent struct { + K8sLikeComponent `json:",inline"` +} + +// Component that allows partly importing Openshift resources into the workspace POD +type OpenshiftComponent struct { + K8sLikeComponent `json:",inline"` +} diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/overrideDirectives.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/overrideDirectives.go new file mode 100644 index 000000000..280ea367c --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/overrideDirectives.go @@ -0,0 +1,58 @@ +package v1alpha2 + +// +kubebuilder:validation:Enum=replace;delete +type OverridingPatchDirective string + +const ( + ReplaceOverridingDirective OverridingPatchDirective = "replace" + DeleteOverridingDirective OverridingPatchDirective = "delete" +) + +const ( + DeleteFromPrimitiveListOverridingPatchDirective OverridingPatchDirective = "replace" +) + +type OverrideDirective struct { + // Path of the element the directive should be applied on + // + // For the following path tree: + // + // ```json + // commands: + // - exec + // id: commandId + // ``` + // + // the path would be: `commands["commandId"]`. + Path string `json:"path"` + + // `$Patch` directlive as defined in + // https://github.com/kubernetes/community/blob/master/contributors/devel/sig-api-machinery/strategic-merge-patch.md#basic-patch-format + // + // This is an enumeration that allows the following values: + // + // - *replace*: indicates that the element matched by the `jsonPath` field should be replaced instead of being merged. + // + // - *delete*: indicates that the element matched by the `jsonPath` field should be deleted. + // + // +optional + Patch OverridingPatchDirective `json:"patch,omitempty"` + + // `DeleteFromPrimitiveList` directive as defined in + // https://github.com/kubernetes/community/blob/master/contributors/devel/sig-api-machinery/strategic-merge-patch.md#deletefromprimitivelist-directive + // + // This indicates that the elements in this list should be deleted from the original primitive list. + // The original primitive list is the element matched by the `jsonPath` field. + // +optional + DeleteFromPrimitiveList []string `json:"deleteFromPrimitiveList,omitempty"` + + // `SetElementOrder` directive as defined in + // https://github.com/kubernetes/community/blob/master/contributors/devel/sig-api-machinery/strategic-merge-patch.md#deletefromprimitivelist-directive + // + // This provides a way to specify the order of a list. The relative order specified in this directive will be retained. + // The list whose order is controller is the element matched by the `jsonPath` field. + // If the controller list is a list of objects, then the values in this list should be + // the merge keys of the objects to order. + // +optional + SetElementOrder []string `json:"setElementOrder,omitempty"` +} diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/overrides.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/overrides.go new file mode 100644 index 000000000..69ad5b6e3 --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/overrides.go @@ -0,0 +1,11 @@ +package v1alpha2 + +// +k8s:deepcopy-gen=false +type Overrides interface { + TopLevelListContainer + isOverride() +} + +// OverridesBase is used in the Overrides generator in order to provide a common base for the generated Overrides +// So please be careful when renaming +type OverridesBase struct{} diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/parent.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/parent.go new file mode 100644 index 000000000..69ebaa6b2 --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/parent.go @@ -0,0 +1,6 @@ +package v1alpha2 + +type Parent struct { + ImportReference `json:",inline"` + ParentOverrides `json:",inline"` +} diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/pluginComponents.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/pluginComponents.go new file mode 100644 index 000000000..68933dd71 --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/pluginComponents.go @@ -0,0 +1,7 @@ +package v1alpha2 + +type PluginComponent struct { + BaseComponent `json:",inline"` + ImportReference `json:",inline"` + PluginOverrides `json:",inline"` +} diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/projects.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/projects.go new file mode 100644 index 000000000..5c7a709c1 --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/projects.go @@ -0,0 +1,120 @@ +package v1alpha2 + +import runtime "k8s.io/apimachinery/pkg/runtime" + +type Project struct { + // Project name + Name string `json:"name"` + + // Path relative to the root of the projects to which this project should be cloned into. This is a unix-style relative path (i.e. uses forward slashes). The path is invalid if it is absolute or tries to escape the project root through the usage of '..'. If not specified, defaults to the project name. + // +optional + ClonePath string `json:"clonePath,omitempty"` + + // Populate the project sparsely with selected directories. + // +optional + SparseCheckoutDirs []string `json:"sparseCheckoutDirs,omitempty"` + + ProjectSource `json:",inline"` +} + +type StarterProject struct { + // Project name + Name string `json:"name"` + + // Description of a starter project + // +optional + Description string `json:"description,omitempty"` + + // Sub-directory from a starter project to be used as root for starter project. + // +optional + SubDir string `json:"subDir,omitempty"` + + ProjectSource `json:",inline"` +} + +// ProjectSourceType describes the type of Project sources. +// Only one of the following project sources may be specified. +// If none of the following policies is specified, the default one +// is AllowConcurrent. +// +kubebuilder:validation:Enum=Git;Github;Zip;Custom +type ProjectSourceType string + +const ( + GitProjectSourceType ProjectSourceType = "Git" + GitHubProjectSourceType ProjectSourceType = "Github" + ZipProjectSourceType ProjectSourceType = "Zip" + CustomProjectSourceType ProjectSourceType = "Custom" +) + +// +union +type ProjectSource struct { + // Type of project source + // + + // +unionDiscriminator + // +optional + SourceType ProjectSourceType `json:"sourceType,omitempty"` + + // Project's Git source + // +optional + Git *GitProjectSource `json:"git,omitempty"` + + // Project's GitHub source + // +optional + Github *GithubProjectSource `json:"github,omitempty"` + + // Project's Zip source + // +optional + Zip *ZipProjectSource `json:"zip,omitempty"` + + // Project's Custom source + // +optional + // +devfile:overrides:include:omit=true + Custom *CustomProjectSource `json:"custom,omitempty"` +} + +type CommonProjectSource struct { +} + +type CustomProjectSource struct { + ProjectSourceClass string `json:"projectSourceClass"` + // +kubebuilder:pruning:PreserveUnknownFields + // +kubebuilder:validation:EmbeddedResource + EmbeddedResource runtime.RawExtension `json:"embeddedResource"` +} + +type ZipProjectSource struct { + CommonProjectSource `json:",inline"` + + // Zip project's source location address. Should be file path of the archive, e.g. file://$FILE_PATH + // +required + Location string `json:"location,omitempty"` +} + +type GitLikeProjectSource struct { + CommonProjectSource `json:",inline"` + + // Defines from what the project should be checked out. Required if there are more than one remote configured + // +optional + CheckoutFrom *CheckoutFrom `json:"checkoutFrom,omitempty"` + + // The remotes map which should be initialized in the git project. Must have at least one remote configured + Remotes map[string]string `json:"remotes"` +} + +type CheckoutFrom struct { + // The revision to checkout from. Should be branch name, tag or commit id. + // Default branch is used if missing or specified revision is not found. + // +optional + Revision string `json:"revision,omitempty"` + // The remote name should be used as init. Required if there are more than one remote configured + // +optional + Remote string `json:"remote,omitempty"` +} + +type GitProjectSource struct { + GitLikeProjectSource `json:",inline"` +} + +type GithubProjectSource struct { + GitLikeProjectSource `json:",inline"` +} diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/register.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/register.go new file mode 100644 index 000000000..7e6965512 --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/register.go @@ -0,0 +1,19 @@ +// NOTE: Boilerplate only. Ignore this file. + +// Package v1alpha2 contains API Schema definitions for the org v1alpha2 API group +// +k8s:deepcopy-gen=package,register +// +groupName=workspace.devfile.io +package v1alpha2 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // SchemeGroupVersion is group version used to register these objects + SchemeGroupVersion = schema.GroupVersion{Group: "workspace.devfile.io", Version: "v1alpha2"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} +) diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/union.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/union.go new file mode 100644 index 000000000..34fb138c9 --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/union.go @@ -0,0 +1,21 @@ +package v1alpha2 + +// +k8s:deepcopy-gen=false + +// Union is an interface that allows managing structs defined as +// Kubernetes unions with discriminators, according to the following KEP: +// https://github.com/kubernetes/enhancements/blob/master/keps/sig-api-machinery/20190325-unions.md +type Union interface { + discriminator() *string + + // Normalize allows normalizing the union, according to the following rules: + // - When only one field of the union is set and no discriminator is set, set the discriminator according to the union value. + // - When several fields are set and a discrimnator is set, remove (== reset to zero value) all the values that do not match the discriminator. + // - When only one union value is set and it matches discriminator, just do nothing. + // - In other case, something is inconsistent or ambiguous: an error is thrown. + Normalize() error + + // Simplify allows removing the union discriminator, + // but only after normalizing it if necessary. + Simplify() +} diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/union_implementation.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/union_implementation.go new file mode 100644 index 000000000..d82ba4f26 --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/union_implementation.go @@ -0,0 +1,103 @@ +package v1alpha2 + +import ( + "errors" + "reflect" +) + +func visitUnion(union interface{}, visitor interface{}) (err error) { + visitorValue := reflect.ValueOf(visitor) + unionValue := reflect.ValueOf(union) + oneMemberPresent := false + typeOfVisitor := visitorValue.Type() + for i := 0; i < visitorValue.NumField(); i++ { + unionMemberToRead := typeOfVisitor.Field(i).Name + unionMember := unionValue.FieldByName(unionMemberToRead) + if !unionMember.IsZero() { + if oneMemberPresent { + err = errors.New("Only one element should be set in union: " + unionValue.Type().Name()) + return + } + oneMemberPresent = true + visitorFunction := visitorValue.Field(i) + if visitorFunction.IsNil() { + return + } + results := visitorFunction.Call([]reflect.Value{unionMember}) + if !results[0].IsNil() { + err = results[0].Interface().(error) + } + return + } + } + return +} + +func simplifyUnion(union Union, visitorType reflect.Type) { + normalizeUnion(union, visitorType) + *union.discriminator() = "" +} + +func normalizeUnion(union Union, visitorType reflect.Type) error { + err := updateDiscriminator(union, visitorType) + if err != nil { + return err + } + + err = cleanupValues(union, visitorType) + if err != nil { + return err + } + return nil +} + +func updateDiscriminator(union Union, visitorType reflect.Type) error { + unionValue := reflect.ValueOf(union) + + if union.discriminator() == nil { + return errors.New("Discriminator should not be 'nil' in union: " + unionValue.Type().Name()) + } + + if *union.discriminator() != "" { + // Nothing to do + return nil + } + + oneMemberPresent := false + for i := 0; i < visitorType.NumField(); i++ { + unionMemberToRead := visitorType.Field(i).Name + unionMember := unionValue.Elem().FieldByName(unionMemberToRead) + if !unionMember.IsZero() { + if oneMemberPresent { + return errors.New("Discriminator cannot be deduced from 2 values in union: " + unionValue.Type().Name()) + } + oneMemberPresent = true + *(union.discriminator()) = unionMemberToRead + } + } + return nil +} + +func cleanupValues(union Union, visitorType reflect.Type) error { + unionValue := reflect.ValueOf(union) + + if union.discriminator() == nil { + return errors.New("Discriminator should not be 'nil' in union: " + unionValue.Type().Name()) + } + + if *union.discriminator() == "" { + // Nothing to do + return errors.New("Values cannot be cleaned up without a discriminator in union: " + unionValue.Type().Name()) + } + + for i := 0; i < visitorType.NumField(); i++ { + unionMemberToRead := visitorType.Field(i).Name + unionMember := unionValue.Elem().FieldByName(unionMemberToRead) + if !unionMember.IsZero() { + if unionMemberToRead != *union.discriminator() { + unionMember.Set(reflect.Zero(unionMember.Type())) + } + } + } + return nil +} diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/volumeComponent.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/volumeComponent.go new file mode 100644 index 000000000..069238198 --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/volumeComponent.go @@ -0,0 +1,14 @@ +package v1alpha2 + +// Component that allows the developer to declare and configure a volume into his workspace +type VolumeComponent struct { + BaseComponent `json:",inline"` + Volume `json:",inline"` +} + +// Volume that should be mounted to a component container +type Volume struct { + // +optional + // Size of the volume + Size string `json:"size,omitempty"` +} diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/zz_generated.deepcopy.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/zz_generated.deepcopy.go new file mode 100644 index 000000000..741d2e935 --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/zz_generated.deepcopy.go @@ -0,0 +1,3056 @@ +// +build !ignore_autogenerated + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplyCommand) DeepCopyInto(out *ApplyCommand) { + *out = *in + in.LabeledCommand.DeepCopyInto(&out.LabeledCommand) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplyCommand. +func (in *ApplyCommand) DeepCopy() *ApplyCommand { + if in == nil { + return nil + } + out := new(ApplyCommand) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplyCommandParentOverride) DeepCopyInto(out *ApplyCommandParentOverride) { + *out = *in + in.LabeledCommandParentOverride.DeepCopyInto(&out.LabeledCommandParentOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplyCommandParentOverride. +func (in *ApplyCommandParentOverride) DeepCopy() *ApplyCommandParentOverride { + if in == nil { + return nil + } + out := new(ApplyCommandParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplyCommandPluginOverride) DeepCopyInto(out *ApplyCommandPluginOverride) { + *out = *in + in.LabeledCommandPluginOverride.DeepCopyInto(&out.LabeledCommandPluginOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplyCommandPluginOverride. +func (in *ApplyCommandPluginOverride) DeepCopy() *ApplyCommandPluginOverride { + if in == nil { + return nil + } + out := new(ApplyCommandPluginOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplyCommandPluginOverrideParentOverride) DeepCopyInto(out *ApplyCommandPluginOverrideParentOverride) { + *out = *in + in.LabeledCommandPluginOverrideParentOverride.DeepCopyInto(&out.LabeledCommandPluginOverrideParentOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplyCommandPluginOverrideParentOverride. +func (in *ApplyCommandPluginOverrideParentOverride) DeepCopy() *ApplyCommandPluginOverrideParentOverride { + if in == nil { + return nil + } + out := new(ApplyCommandPluginOverrideParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BaseCommand) DeepCopyInto(out *BaseCommand) { + *out = *in + if in.Group != nil { + in, out := &in.Group, &out.Group + *out = new(CommandGroup) + **out = **in + } + if in.Attributes != nil { + in, out := &in.Attributes, &out.Attributes + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BaseCommand. +func (in *BaseCommand) DeepCopy() *BaseCommand { + if in == nil { + return nil + } + out := new(BaseCommand) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BaseCommandParentOverride) DeepCopyInto(out *BaseCommandParentOverride) { + *out = *in + if in.Group != nil { + in, out := &in.Group, &out.Group + *out = new(CommandGroupParentOverride) + **out = **in + } + if in.Attributes != nil { + in, out := &in.Attributes, &out.Attributes + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BaseCommandParentOverride. +func (in *BaseCommandParentOverride) DeepCopy() *BaseCommandParentOverride { + if in == nil { + return nil + } + out := new(BaseCommandParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BaseCommandPluginOverride) DeepCopyInto(out *BaseCommandPluginOverride) { + *out = *in + if in.Group != nil { + in, out := &in.Group, &out.Group + *out = new(CommandGroupPluginOverride) + **out = **in + } + if in.Attributes != nil { + in, out := &in.Attributes, &out.Attributes + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BaseCommandPluginOverride. +func (in *BaseCommandPluginOverride) DeepCopy() *BaseCommandPluginOverride { + if in == nil { + return nil + } + out := new(BaseCommandPluginOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BaseCommandPluginOverrideParentOverride) DeepCopyInto(out *BaseCommandPluginOverrideParentOverride) { + *out = *in + if in.Group != nil { + in, out := &in.Group, &out.Group + *out = new(CommandGroupPluginOverrideParentOverride) + **out = **in + } + if in.Attributes != nil { + in, out := &in.Attributes, &out.Attributes + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BaseCommandPluginOverrideParentOverride. +func (in *BaseCommandPluginOverrideParentOverride) DeepCopy() *BaseCommandPluginOverrideParentOverride { + if in == nil { + return nil + } + out := new(BaseCommandPluginOverrideParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BaseComponent) DeepCopyInto(out *BaseComponent) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BaseComponent. +func (in *BaseComponent) DeepCopy() *BaseComponent { + if in == nil { + return nil + } + out := new(BaseComponent) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BaseComponentParentOverride) DeepCopyInto(out *BaseComponentParentOverride) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BaseComponentParentOverride. +func (in *BaseComponentParentOverride) DeepCopy() *BaseComponentParentOverride { + if in == nil { + return nil + } + out := new(BaseComponentParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BaseComponentPluginOverride) DeepCopyInto(out *BaseComponentPluginOverride) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BaseComponentPluginOverride. +func (in *BaseComponentPluginOverride) DeepCopy() *BaseComponentPluginOverride { + if in == nil { + return nil + } + out := new(BaseComponentPluginOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BaseComponentPluginOverrideParentOverride) DeepCopyInto(out *BaseComponentPluginOverrideParentOverride) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BaseComponentPluginOverrideParentOverride. +func (in *BaseComponentPluginOverrideParentOverride) DeepCopy() *BaseComponentPluginOverrideParentOverride { + if in == nil { + return nil + } + out := new(BaseComponentPluginOverrideParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CheckoutFrom) DeepCopyInto(out *CheckoutFrom) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CheckoutFrom. +func (in *CheckoutFrom) DeepCopy() *CheckoutFrom { + if in == nil { + return nil + } + out := new(CheckoutFrom) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CheckoutFromParentOverride) DeepCopyInto(out *CheckoutFromParentOverride) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CheckoutFromParentOverride. +func (in *CheckoutFromParentOverride) DeepCopy() *CheckoutFromParentOverride { + if in == nil { + return nil + } + out := new(CheckoutFromParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Command) DeepCopyInto(out *Command) { + *out = *in + in.CommandUnion.DeepCopyInto(&out.CommandUnion) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Command. +func (in *Command) DeepCopy() *Command { + if in == nil { + return nil + } + out := new(Command) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CommandGroup) DeepCopyInto(out *CommandGroup) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommandGroup. +func (in *CommandGroup) DeepCopy() *CommandGroup { + if in == nil { + return nil + } + out := new(CommandGroup) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CommandGroupParentOverride) DeepCopyInto(out *CommandGroupParentOverride) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommandGroupParentOverride. +func (in *CommandGroupParentOverride) DeepCopy() *CommandGroupParentOverride { + if in == nil { + return nil + } + out := new(CommandGroupParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CommandGroupPluginOverride) DeepCopyInto(out *CommandGroupPluginOverride) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommandGroupPluginOverride. +func (in *CommandGroupPluginOverride) DeepCopy() *CommandGroupPluginOverride { + if in == nil { + return nil + } + out := new(CommandGroupPluginOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CommandGroupPluginOverrideParentOverride) DeepCopyInto(out *CommandGroupPluginOverrideParentOverride) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommandGroupPluginOverrideParentOverride. +func (in *CommandGroupPluginOverrideParentOverride) DeepCopy() *CommandGroupPluginOverrideParentOverride { + if in == nil { + return nil + } + out := new(CommandGroupPluginOverrideParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CommandParentOverride) DeepCopyInto(out *CommandParentOverride) { + *out = *in + in.CommandUnionParentOverride.DeepCopyInto(&out.CommandUnionParentOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommandParentOverride. +func (in *CommandParentOverride) DeepCopy() *CommandParentOverride { + if in == nil { + return nil + } + out := new(CommandParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CommandPluginOverride) DeepCopyInto(out *CommandPluginOverride) { + *out = *in + in.CommandUnionPluginOverride.DeepCopyInto(&out.CommandUnionPluginOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommandPluginOverride. +func (in *CommandPluginOverride) DeepCopy() *CommandPluginOverride { + if in == nil { + return nil + } + out := new(CommandPluginOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CommandPluginOverrideParentOverride) DeepCopyInto(out *CommandPluginOverrideParentOverride) { + *out = *in + in.CommandUnionPluginOverrideParentOverride.DeepCopyInto(&out.CommandUnionPluginOverrideParentOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommandPluginOverrideParentOverride. +func (in *CommandPluginOverrideParentOverride) DeepCopy() *CommandPluginOverrideParentOverride { + if in == nil { + return nil + } + out := new(CommandPluginOverrideParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CommandUnion) DeepCopyInto(out *CommandUnion) { + *out = *in + if in.Exec != nil { + in, out := &in.Exec, &out.Exec + *out = new(ExecCommand) + (*in).DeepCopyInto(*out) + } + if in.Apply != nil { + in, out := &in.Apply, &out.Apply + *out = new(ApplyCommand) + (*in).DeepCopyInto(*out) + } + if in.VscodeTask != nil { + in, out := &in.VscodeTask, &out.VscodeTask + *out = new(VscodeConfigurationCommand) + (*in).DeepCopyInto(*out) + } + if in.VscodeLaunch != nil { + in, out := &in.VscodeLaunch, &out.VscodeLaunch + *out = new(VscodeConfigurationCommand) + (*in).DeepCopyInto(*out) + } + if in.Composite != nil { + in, out := &in.Composite, &out.Composite + *out = new(CompositeCommand) + (*in).DeepCopyInto(*out) + } + if in.Custom != nil { + in, out := &in.Custom, &out.Custom + *out = new(CustomCommand) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommandUnion. +func (in *CommandUnion) DeepCopy() *CommandUnion { + if in == nil { + return nil + } + out := new(CommandUnion) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CommandUnionParentOverride) DeepCopyInto(out *CommandUnionParentOverride) { + *out = *in + if in.Exec != nil { + in, out := &in.Exec, &out.Exec + *out = new(ExecCommandParentOverride) + (*in).DeepCopyInto(*out) + } + if in.Apply != nil { + in, out := &in.Apply, &out.Apply + *out = new(ApplyCommandParentOverride) + (*in).DeepCopyInto(*out) + } + if in.VscodeTask != nil { + in, out := &in.VscodeTask, &out.VscodeTask + *out = new(VscodeConfigurationCommandParentOverride) + (*in).DeepCopyInto(*out) + } + if in.VscodeLaunch != nil { + in, out := &in.VscodeLaunch, &out.VscodeLaunch + *out = new(VscodeConfigurationCommandParentOverride) + (*in).DeepCopyInto(*out) + } + if in.Composite != nil { + in, out := &in.Composite, &out.Composite + *out = new(CompositeCommandParentOverride) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommandUnionParentOverride. +func (in *CommandUnionParentOverride) DeepCopy() *CommandUnionParentOverride { + if in == nil { + return nil + } + out := new(CommandUnionParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CommandUnionPluginOverride) DeepCopyInto(out *CommandUnionPluginOverride) { + *out = *in + if in.Exec != nil { + in, out := &in.Exec, &out.Exec + *out = new(ExecCommandPluginOverride) + (*in).DeepCopyInto(*out) + } + if in.Apply != nil { + in, out := &in.Apply, &out.Apply + *out = new(ApplyCommandPluginOverride) + (*in).DeepCopyInto(*out) + } + if in.VscodeTask != nil { + in, out := &in.VscodeTask, &out.VscodeTask + *out = new(VscodeConfigurationCommandPluginOverride) + (*in).DeepCopyInto(*out) + } + if in.VscodeLaunch != nil { + in, out := &in.VscodeLaunch, &out.VscodeLaunch + *out = new(VscodeConfigurationCommandPluginOverride) + (*in).DeepCopyInto(*out) + } + if in.Composite != nil { + in, out := &in.Composite, &out.Composite + *out = new(CompositeCommandPluginOverride) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommandUnionPluginOverride. +func (in *CommandUnionPluginOverride) DeepCopy() *CommandUnionPluginOverride { + if in == nil { + return nil + } + out := new(CommandUnionPluginOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CommandUnionPluginOverrideParentOverride) DeepCopyInto(out *CommandUnionPluginOverrideParentOverride) { + *out = *in + if in.Exec != nil { + in, out := &in.Exec, &out.Exec + *out = new(ExecCommandPluginOverrideParentOverride) + (*in).DeepCopyInto(*out) + } + if in.Apply != nil { + in, out := &in.Apply, &out.Apply + *out = new(ApplyCommandPluginOverrideParentOverride) + (*in).DeepCopyInto(*out) + } + if in.VscodeTask != nil { + in, out := &in.VscodeTask, &out.VscodeTask + *out = new(VscodeConfigurationCommandPluginOverrideParentOverride) + (*in).DeepCopyInto(*out) + } + if in.VscodeLaunch != nil { + in, out := &in.VscodeLaunch, &out.VscodeLaunch + *out = new(VscodeConfigurationCommandPluginOverrideParentOverride) + (*in).DeepCopyInto(*out) + } + if in.Composite != nil { + in, out := &in.Composite, &out.Composite + *out = new(CompositeCommandPluginOverrideParentOverride) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommandUnionPluginOverrideParentOverride. +func (in *CommandUnionPluginOverrideParentOverride) DeepCopy() *CommandUnionPluginOverrideParentOverride { + if in == nil { + return nil + } + out := new(CommandUnionPluginOverrideParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CommonProjectSource) DeepCopyInto(out *CommonProjectSource) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommonProjectSource. +func (in *CommonProjectSource) DeepCopy() *CommonProjectSource { + if in == nil { + return nil + } + out := new(CommonProjectSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CommonProjectSourceParentOverride) DeepCopyInto(out *CommonProjectSourceParentOverride) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommonProjectSourceParentOverride. +func (in *CommonProjectSourceParentOverride) DeepCopy() *CommonProjectSourceParentOverride { + if in == nil { + return nil + } + out := new(CommonProjectSourceParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Component) DeepCopyInto(out *Component) { + *out = *in + in.ComponentUnion.DeepCopyInto(&out.ComponentUnion) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Component. +func (in *Component) DeepCopy() *Component { + if in == nil { + return nil + } + out := new(Component) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ComponentParentOverride) DeepCopyInto(out *ComponentParentOverride) { + *out = *in + in.ComponentUnionParentOverride.DeepCopyInto(&out.ComponentUnionParentOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ComponentParentOverride. +func (in *ComponentParentOverride) DeepCopy() *ComponentParentOverride { + if in == nil { + return nil + } + out := new(ComponentParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ComponentPluginOverride) DeepCopyInto(out *ComponentPluginOverride) { + *out = *in + in.ComponentUnionPluginOverride.DeepCopyInto(&out.ComponentUnionPluginOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ComponentPluginOverride. +func (in *ComponentPluginOverride) DeepCopy() *ComponentPluginOverride { + if in == nil { + return nil + } + out := new(ComponentPluginOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ComponentPluginOverrideParentOverride) DeepCopyInto(out *ComponentPluginOverrideParentOverride) { + *out = *in + in.ComponentUnionPluginOverrideParentOverride.DeepCopyInto(&out.ComponentUnionPluginOverrideParentOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ComponentPluginOverrideParentOverride. +func (in *ComponentPluginOverrideParentOverride) DeepCopy() *ComponentPluginOverrideParentOverride { + if in == nil { + return nil + } + out := new(ComponentPluginOverrideParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ComponentUnion) DeepCopyInto(out *ComponentUnion) { + *out = *in + if in.Container != nil { + in, out := &in.Container, &out.Container + *out = new(ContainerComponent) + (*in).DeepCopyInto(*out) + } + if in.Kubernetes != nil { + in, out := &in.Kubernetes, &out.Kubernetes + *out = new(KubernetesComponent) + (*in).DeepCopyInto(*out) + } + if in.Openshift != nil { + in, out := &in.Openshift, &out.Openshift + *out = new(OpenshiftComponent) + (*in).DeepCopyInto(*out) + } + if in.Volume != nil { + in, out := &in.Volume, &out.Volume + *out = new(VolumeComponent) + **out = **in + } + if in.Plugin != nil { + in, out := &in.Plugin, &out.Plugin + *out = new(PluginComponent) + (*in).DeepCopyInto(*out) + } + if in.Custom != nil { + in, out := &in.Custom, &out.Custom + *out = new(CustomComponent) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ComponentUnion. +func (in *ComponentUnion) DeepCopy() *ComponentUnion { + if in == nil { + return nil + } + out := new(ComponentUnion) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ComponentUnionParentOverride) DeepCopyInto(out *ComponentUnionParentOverride) { + *out = *in + if in.Container != nil { + in, out := &in.Container, &out.Container + *out = new(ContainerComponentParentOverride) + (*in).DeepCopyInto(*out) + } + if in.Kubernetes != nil { + in, out := &in.Kubernetes, &out.Kubernetes + *out = new(KubernetesComponentParentOverride) + (*in).DeepCopyInto(*out) + } + if in.Openshift != nil { + in, out := &in.Openshift, &out.Openshift + *out = new(OpenshiftComponentParentOverride) + (*in).DeepCopyInto(*out) + } + if in.Volume != nil { + in, out := &in.Volume, &out.Volume + *out = new(VolumeComponentParentOverride) + **out = **in + } + if in.Plugin != nil { + in, out := &in.Plugin, &out.Plugin + *out = new(PluginComponentParentOverride) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ComponentUnionParentOverride. +func (in *ComponentUnionParentOverride) DeepCopy() *ComponentUnionParentOverride { + if in == nil { + return nil + } + out := new(ComponentUnionParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ComponentUnionPluginOverride) DeepCopyInto(out *ComponentUnionPluginOverride) { + *out = *in + if in.Container != nil { + in, out := &in.Container, &out.Container + *out = new(ContainerComponentPluginOverride) + (*in).DeepCopyInto(*out) + } + if in.Kubernetes != nil { + in, out := &in.Kubernetes, &out.Kubernetes + *out = new(KubernetesComponentPluginOverride) + (*in).DeepCopyInto(*out) + } + if in.Openshift != nil { + in, out := &in.Openshift, &out.Openshift + *out = new(OpenshiftComponentPluginOverride) + (*in).DeepCopyInto(*out) + } + if in.Volume != nil { + in, out := &in.Volume, &out.Volume + *out = new(VolumeComponentPluginOverride) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ComponentUnionPluginOverride. +func (in *ComponentUnionPluginOverride) DeepCopy() *ComponentUnionPluginOverride { + if in == nil { + return nil + } + out := new(ComponentUnionPluginOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ComponentUnionPluginOverrideParentOverride) DeepCopyInto(out *ComponentUnionPluginOverrideParentOverride) { + *out = *in + if in.Container != nil { + in, out := &in.Container, &out.Container + *out = new(ContainerComponentPluginOverrideParentOverride) + (*in).DeepCopyInto(*out) + } + if in.Kubernetes != nil { + in, out := &in.Kubernetes, &out.Kubernetes + *out = new(KubernetesComponentPluginOverrideParentOverride) + (*in).DeepCopyInto(*out) + } + if in.Openshift != nil { + in, out := &in.Openshift, &out.Openshift + *out = new(OpenshiftComponentPluginOverrideParentOverride) + (*in).DeepCopyInto(*out) + } + if in.Volume != nil { + in, out := &in.Volume, &out.Volume + *out = new(VolumeComponentPluginOverrideParentOverride) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ComponentUnionPluginOverrideParentOverride. +func (in *ComponentUnionPluginOverrideParentOverride) DeepCopy() *ComponentUnionPluginOverrideParentOverride { + if in == nil { + return nil + } + out := new(ComponentUnionPluginOverrideParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CompositeCommand) DeepCopyInto(out *CompositeCommand) { + *out = *in + in.LabeledCommand.DeepCopyInto(&out.LabeledCommand) + if in.Commands != nil { + in, out := &in.Commands, &out.Commands + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CompositeCommand. +func (in *CompositeCommand) DeepCopy() *CompositeCommand { + if in == nil { + return nil + } + out := new(CompositeCommand) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CompositeCommandParentOverride) DeepCopyInto(out *CompositeCommandParentOverride) { + *out = *in + in.LabeledCommandParentOverride.DeepCopyInto(&out.LabeledCommandParentOverride) + if in.Commands != nil { + in, out := &in.Commands, &out.Commands + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CompositeCommandParentOverride. +func (in *CompositeCommandParentOverride) DeepCopy() *CompositeCommandParentOverride { + if in == nil { + return nil + } + out := new(CompositeCommandParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CompositeCommandPluginOverride) DeepCopyInto(out *CompositeCommandPluginOverride) { + *out = *in + in.LabeledCommandPluginOverride.DeepCopyInto(&out.LabeledCommandPluginOverride) + if in.Commands != nil { + in, out := &in.Commands, &out.Commands + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CompositeCommandPluginOverride. +func (in *CompositeCommandPluginOverride) DeepCopy() *CompositeCommandPluginOverride { + if in == nil { + return nil + } + out := new(CompositeCommandPluginOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CompositeCommandPluginOverrideParentOverride) DeepCopyInto(out *CompositeCommandPluginOverrideParentOverride) { + *out = *in + in.LabeledCommandPluginOverrideParentOverride.DeepCopyInto(&out.LabeledCommandPluginOverrideParentOverride) + if in.Commands != nil { + in, out := &in.Commands, &out.Commands + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CompositeCommandPluginOverrideParentOverride. +func (in *CompositeCommandPluginOverrideParentOverride) DeepCopy() *CompositeCommandPluginOverrideParentOverride { + if in == nil { + return nil + } + out := new(CompositeCommandPluginOverrideParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Container) DeepCopyInto(out *Container) { + *out = *in + if in.Env != nil { + in, out := &in.Env, &out.Env + *out = make([]EnvVar, len(*in)) + copy(*out, *in) + } + if in.VolumeMounts != nil { + in, out := &in.VolumeMounts, &out.VolumeMounts + *out = make([]VolumeMount, len(*in)) + copy(*out, *in) + } + if in.Command != nil { + in, out := &in.Command, &out.Command + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Args != nil { + in, out := &in.Args, &out.Args + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.MountSources != nil { + in, out := &in.MountSources, &out.MountSources + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Container. +func (in *Container) DeepCopy() *Container { + if in == nil { + return nil + } + out := new(Container) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerComponent) DeepCopyInto(out *ContainerComponent) { + *out = *in + out.BaseComponent = in.BaseComponent + in.Container.DeepCopyInto(&out.Container) + if in.Endpoints != nil { + in, out := &in.Endpoints, &out.Endpoints + *out = make([]Endpoint, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerComponent. +func (in *ContainerComponent) DeepCopy() *ContainerComponent { + if in == nil { + return nil + } + out := new(ContainerComponent) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerComponentParentOverride) DeepCopyInto(out *ContainerComponentParentOverride) { + *out = *in + out.BaseComponentParentOverride = in.BaseComponentParentOverride + in.ContainerParentOverride.DeepCopyInto(&out.ContainerParentOverride) + if in.Endpoints != nil { + in, out := &in.Endpoints, &out.Endpoints + *out = make([]EndpointParentOverride, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerComponentParentOverride. +func (in *ContainerComponentParentOverride) DeepCopy() *ContainerComponentParentOverride { + if in == nil { + return nil + } + out := new(ContainerComponentParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerComponentPluginOverride) DeepCopyInto(out *ContainerComponentPluginOverride) { + *out = *in + out.BaseComponentPluginOverride = in.BaseComponentPluginOverride + in.ContainerPluginOverride.DeepCopyInto(&out.ContainerPluginOverride) + if in.Endpoints != nil { + in, out := &in.Endpoints, &out.Endpoints + *out = make([]EndpointPluginOverride, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerComponentPluginOverride. +func (in *ContainerComponentPluginOverride) DeepCopy() *ContainerComponentPluginOverride { + if in == nil { + return nil + } + out := new(ContainerComponentPluginOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerComponentPluginOverrideParentOverride) DeepCopyInto(out *ContainerComponentPluginOverrideParentOverride) { + *out = *in + out.BaseComponentPluginOverrideParentOverride = in.BaseComponentPluginOverrideParentOverride + in.ContainerPluginOverrideParentOverride.DeepCopyInto(&out.ContainerPluginOverrideParentOverride) + if in.Endpoints != nil { + in, out := &in.Endpoints, &out.Endpoints + *out = make([]EndpointPluginOverrideParentOverride, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerComponentPluginOverrideParentOverride. +func (in *ContainerComponentPluginOverrideParentOverride) DeepCopy() *ContainerComponentPluginOverrideParentOverride { + if in == nil { + return nil + } + out := new(ContainerComponentPluginOverrideParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerParentOverride) DeepCopyInto(out *ContainerParentOverride) { + *out = *in + if in.Env != nil { + in, out := &in.Env, &out.Env + *out = make([]EnvVarParentOverride, len(*in)) + copy(*out, *in) + } + if in.VolumeMounts != nil { + in, out := &in.VolumeMounts, &out.VolumeMounts + *out = make([]VolumeMountParentOverride, len(*in)) + copy(*out, *in) + } + if in.Command != nil { + in, out := &in.Command, &out.Command + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Args != nil { + in, out := &in.Args, &out.Args + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.MountSources != nil { + in, out := &in.MountSources, &out.MountSources + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerParentOverride. +func (in *ContainerParentOverride) DeepCopy() *ContainerParentOverride { + if in == nil { + return nil + } + out := new(ContainerParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerPluginOverride) DeepCopyInto(out *ContainerPluginOverride) { + *out = *in + if in.Env != nil { + in, out := &in.Env, &out.Env + *out = make([]EnvVarPluginOverride, len(*in)) + copy(*out, *in) + } + if in.VolumeMounts != nil { + in, out := &in.VolumeMounts, &out.VolumeMounts + *out = make([]VolumeMountPluginOverride, len(*in)) + copy(*out, *in) + } + if in.Command != nil { + in, out := &in.Command, &out.Command + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Args != nil { + in, out := &in.Args, &out.Args + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.MountSources != nil { + in, out := &in.MountSources, &out.MountSources + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerPluginOverride. +func (in *ContainerPluginOverride) DeepCopy() *ContainerPluginOverride { + if in == nil { + return nil + } + out := new(ContainerPluginOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerPluginOverrideParentOverride) DeepCopyInto(out *ContainerPluginOverrideParentOverride) { + *out = *in + if in.Env != nil { + in, out := &in.Env, &out.Env + *out = make([]EnvVarPluginOverrideParentOverride, len(*in)) + copy(*out, *in) + } + if in.VolumeMounts != nil { + in, out := &in.VolumeMounts, &out.VolumeMounts + *out = make([]VolumeMountPluginOverrideParentOverride, len(*in)) + copy(*out, *in) + } + if in.Command != nil { + in, out := &in.Command, &out.Command + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Args != nil { + in, out := &in.Args, &out.Args + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.MountSources != nil { + in, out := &in.MountSources, &out.MountSources + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerPluginOverrideParentOverride. +func (in *ContainerPluginOverrideParentOverride) DeepCopy() *ContainerPluginOverrideParentOverride { + if in == nil { + return nil + } + out := new(ContainerPluginOverrideParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CustomCommand) DeepCopyInto(out *CustomCommand) { + *out = *in + in.LabeledCommand.DeepCopyInto(&out.LabeledCommand) + in.EmbeddedResource.DeepCopyInto(&out.EmbeddedResource) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomCommand. +func (in *CustomCommand) DeepCopy() *CustomCommand { + if in == nil { + return nil + } + out := new(CustomCommand) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CustomComponent) DeepCopyInto(out *CustomComponent) { + *out = *in + in.EmbeddedResource.DeepCopyInto(&out.EmbeddedResource) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomComponent. +func (in *CustomComponent) DeepCopy() *CustomComponent { + if in == nil { + return nil + } + out := new(CustomComponent) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CustomProjectSource) DeepCopyInto(out *CustomProjectSource) { + *out = *in + in.EmbeddedResource.DeepCopyInto(&out.EmbeddedResource) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomProjectSource. +func (in *CustomProjectSource) DeepCopy() *CustomProjectSource { + if in == nil { + return nil + } + out := new(CustomProjectSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DevWorkspace) DeepCopyInto(out *DevWorkspace) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DevWorkspace. +func (in *DevWorkspace) DeepCopy() *DevWorkspace { + if in == nil { + return nil + } + out := new(DevWorkspace) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DevWorkspace) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DevWorkspaceList) DeepCopyInto(out *DevWorkspaceList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]DevWorkspace, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DevWorkspaceList. +func (in *DevWorkspaceList) DeepCopy() *DevWorkspaceList { + if in == nil { + return nil + } + out := new(DevWorkspaceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DevWorkspaceList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DevWorkspaceSpec) DeepCopyInto(out *DevWorkspaceSpec) { + *out = *in + in.Template.DeepCopyInto(&out.Template) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DevWorkspaceSpec. +func (in *DevWorkspaceSpec) DeepCopy() *DevWorkspaceSpec { + if in == nil { + return nil + } + out := new(DevWorkspaceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DevWorkspaceStatus) DeepCopyInto(out *DevWorkspaceStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]WorkspaceCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DevWorkspaceStatus. +func (in *DevWorkspaceStatus) DeepCopy() *DevWorkspaceStatus { + if in == nil { + return nil + } + out := new(DevWorkspaceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DevWorkspaceTemplate) DeepCopyInto(out *DevWorkspaceTemplate) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DevWorkspaceTemplate. +func (in *DevWorkspaceTemplate) DeepCopy() *DevWorkspaceTemplate { + if in == nil { + return nil + } + out := new(DevWorkspaceTemplate) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DevWorkspaceTemplate) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DevWorkspaceTemplateList) DeepCopyInto(out *DevWorkspaceTemplateList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]DevWorkspaceTemplate, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DevWorkspaceTemplateList. +func (in *DevWorkspaceTemplateList) DeepCopy() *DevWorkspaceTemplateList { + if in == nil { + return nil + } + out := new(DevWorkspaceTemplateList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DevWorkspaceTemplateList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DevWorkspaceTemplateSpec) DeepCopyInto(out *DevWorkspaceTemplateSpec) { + *out = *in + if in.Parent != nil { + in, out := &in.Parent, &out.Parent + *out = new(Parent) + (*in).DeepCopyInto(*out) + } + in.DevWorkspaceTemplateSpecContent.DeepCopyInto(&out.DevWorkspaceTemplateSpecContent) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DevWorkspaceTemplateSpec. +func (in *DevWorkspaceTemplateSpec) DeepCopy() *DevWorkspaceTemplateSpec { + if in == nil { + return nil + } + out := new(DevWorkspaceTemplateSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DevWorkspaceTemplateSpecContent) DeepCopyInto(out *DevWorkspaceTemplateSpecContent) { + *out = *in + if in.Components != nil { + in, out := &in.Components, &out.Components + *out = make([]Component, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Projects != nil { + in, out := &in.Projects, &out.Projects + *out = make([]Project, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.StarterProjects != nil { + in, out := &in.StarterProjects, &out.StarterProjects + *out = make([]StarterProject, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Commands != nil { + in, out := &in.Commands, &out.Commands + *out = make([]Command, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Events != nil { + in, out := &in.Events, &out.Events + *out = new(Events) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DevWorkspaceTemplateSpecContent. +func (in *DevWorkspaceTemplateSpecContent) DeepCopy() *DevWorkspaceTemplateSpecContent { + if in == nil { + return nil + } + out := new(DevWorkspaceTemplateSpecContent) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Devfile) DeepCopyInto(out *Devfile) { + *out = *in + out.DevfileHeader = in.DevfileHeader + in.DevWorkspaceTemplateSpec.DeepCopyInto(&out.DevWorkspaceTemplateSpec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Devfile. +func (in *Devfile) DeepCopy() *Devfile { + if in == nil { + return nil + } + out := new(Devfile) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Endpoint) DeepCopyInto(out *Endpoint) { + *out = *in + if in.Attributes != nil { + in, out := &in.Attributes, &out.Attributes + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Endpoint. +func (in *Endpoint) DeepCopy() *Endpoint { + if in == nil { + return nil + } + out := new(Endpoint) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EndpointParentOverride) DeepCopyInto(out *EndpointParentOverride) { + *out = *in + if in.Attributes != nil { + in, out := &in.Attributes, &out.Attributes + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EndpointParentOverride. +func (in *EndpointParentOverride) DeepCopy() *EndpointParentOverride { + if in == nil { + return nil + } + out := new(EndpointParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EndpointPluginOverride) DeepCopyInto(out *EndpointPluginOverride) { + *out = *in + if in.Attributes != nil { + in, out := &in.Attributes, &out.Attributes + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EndpointPluginOverride. +func (in *EndpointPluginOverride) DeepCopy() *EndpointPluginOverride { + if in == nil { + return nil + } + out := new(EndpointPluginOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EndpointPluginOverrideParentOverride) DeepCopyInto(out *EndpointPluginOverrideParentOverride) { + *out = *in + if in.Attributes != nil { + in, out := &in.Attributes, &out.Attributes + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EndpointPluginOverrideParentOverride. +func (in *EndpointPluginOverrideParentOverride) DeepCopy() *EndpointPluginOverrideParentOverride { + if in == nil { + return nil + } + out := new(EndpointPluginOverrideParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EnvVar) DeepCopyInto(out *EnvVar) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvVar. +func (in *EnvVar) DeepCopy() *EnvVar { + if in == nil { + return nil + } + out := new(EnvVar) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EnvVarParentOverride) DeepCopyInto(out *EnvVarParentOverride) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvVarParentOverride. +func (in *EnvVarParentOverride) DeepCopy() *EnvVarParentOverride { + if in == nil { + return nil + } + out := new(EnvVarParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EnvVarPluginOverride) DeepCopyInto(out *EnvVarPluginOverride) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvVarPluginOverride. +func (in *EnvVarPluginOverride) DeepCopy() *EnvVarPluginOverride { + if in == nil { + return nil + } + out := new(EnvVarPluginOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EnvVarPluginOverrideParentOverride) DeepCopyInto(out *EnvVarPluginOverrideParentOverride) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvVarPluginOverrideParentOverride. +func (in *EnvVarPluginOverrideParentOverride) DeepCopy() *EnvVarPluginOverrideParentOverride { + if in == nil { + return nil + } + out := new(EnvVarPluginOverrideParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Events) DeepCopyInto(out *Events) { + *out = *in + in.WorkspaceEvents.DeepCopyInto(&out.WorkspaceEvents) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Events. +func (in *Events) DeepCopy() *Events { + if in == nil { + return nil + } + out := new(Events) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExecCommand) DeepCopyInto(out *ExecCommand) { + *out = *in + in.LabeledCommand.DeepCopyInto(&out.LabeledCommand) + if in.Env != nil { + in, out := &in.Env, &out.Env + *out = make([]EnvVar, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExecCommand. +func (in *ExecCommand) DeepCopy() *ExecCommand { + if in == nil { + return nil + } + out := new(ExecCommand) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExecCommandParentOverride) DeepCopyInto(out *ExecCommandParentOverride) { + *out = *in + in.LabeledCommandParentOverride.DeepCopyInto(&out.LabeledCommandParentOverride) + if in.Env != nil { + in, out := &in.Env, &out.Env + *out = make([]EnvVarParentOverride, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExecCommandParentOverride. +func (in *ExecCommandParentOverride) DeepCopy() *ExecCommandParentOverride { + if in == nil { + return nil + } + out := new(ExecCommandParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExecCommandPluginOverride) DeepCopyInto(out *ExecCommandPluginOverride) { + *out = *in + in.LabeledCommandPluginOverride.DeepCopyInto(&out.LabeledCommandPluginOverride) + if in.Env != nil { + in, out := &in.Env, &out.Env + *out = make([]EnvVarPluginOverride, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExecCommandPluginOverride. +func (in *ExecCommandPluginOverride) DeepCopy() *ExecCommandPluginOverride { + if in == nil { + return nil + } + out := new(ExecCommandPluginOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExecCommandPluginOverrideParentOverride) DeepCopyInto(out *ExecCommandPluginOverrideParentOverride) { + *out = *in + in.LabeledCommandPluginOverrideParentOverride.DeepCopyInto(&out.LabeledCommandPluginOverrideParentOverride) + if in.Env != nil { + in, out := &in.Env, &out.Env + *out = make([]EnvVarPluginOverrideParentOverride, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExecCommandPluginOverrideParentOverride. +func (in *ExecCommandPluginOverrideParentOverride) DeepCopy() *ExecCommandPluginOverrideParentOverride { + if in == nil { + return nil + } + out := new(ExecCommandPluginOverrideParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GitLikeProjectSource) DeepCopyInto(out *GitLikeProjectSource) { + *out = *in + out.CommonProjectSource = in.CommonProjectSource + if in.CheckoutFrom != nil { + in, out := &in.CheckoutFrom, &out.CheckoutFrom + *out = new(CheckoutFrom) + **out = **in + } + if in.Remotes != nil { + in, out := &in.Remotes, &out.Remotes + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitLikeProjectSource. +func (in *GitLikeProjectSource) DeepCopy() *GitLikeProjectSource { + if in == nil { + return nil + } + out := new(GitLikeProjectSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GitLikeProjectSourceParentOverride) DeepCopyInto(out *GitLikeProjectSourceParentOverride) { + *out = *in + out.CommonProjectSourceParentOverride = in.CommonProjectSourceParentOverride + if in.CheckoutFrom != nil { + in, out := &in.CheckoutFrom, &out.CheckoutFrom + *out = new(CheckoutFromParentOverride) + **out = **in + } + if in.Remotes != nil { + in, out := &in.Remotes, &out.Remotes + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitLikeProjectSourceParentOverride. +func (in *GitLikeProjectSourceParentOverride) DeepCopy() *GitLikeProjectSourceParentOverride { + if in == nil { + return nil + } + out := new(GitLikeProjectSourceParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GitProjectSource) DeepCopyInto(out *GitProjectSource) { + *out = *in + in.GitLikeProjectSource.DeepCopyInto(&out.GitLikeProjectSource) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitProjectSource. +func (in *GitProjectSource) DeepCopy() *GitProjectSource { + if in == nil { + return nil + } + out := new(GitProjectSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GitProjectSourceParentOverride) DeepCopyInto(out *GitProjectSourceParentOverride) { + *out = *in + in.GitLikeProjectSourceParentOverride.DeepCopyInto(&out.GitLikeProjectSourceParentOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitProjectSourceParentOverride. +func (in *GitProjectSourceParentOverride) DeepCopy() *GitProjectSourceParentOverride { + if in == nil { + return nil + } + out := new(GitProjectSourceParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GithubProjectSource) DeepCopyInto(out *GithubProjectSource) { + *out = *in + in.GitLikeProjectSource.DeepCopyInto(&out.GitLikeProjectSource) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GithubProjectSource. +func (in *GithubProjectSource) DeepCopy() *GithubProjectSource { + if in == nil { + return nil + } + out := new(GithubProjectSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GithubProjectSourceParentOverride) DeepCopyInto(out *GithubProjectSourceParentOverride) { + *out = *in + in.GitLikeProjectSourceParentOverride.DeepCopyInto(&out.GitLikeProjectSourceParentOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GithubProjectSourceParentOverride. +func (in *GithubProjectSourceParentOverride) DeepCopy() *GithubProjectSourceParentOverride { + if in == nil { + return nil + } + out := new(GithubProjectSourceParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ImportReference) DeepCopyInto(out *ImportReference) { + *out = *in + in.ImportReferenceUnion.DeepCopyInto(&out.ImportReferenceUnion) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImportReference. +func (in *ImportReference) DeepCopy() *ImportReference { + if in == nil { + return nil + } + out := new(ImportReference) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ImportReferenceParentOverride) DeepCopyInto(out *ImportReferenceParentOverride) { + *out = *in + in.ImportReferenceUnionParentOverride.DeepCopyInto(&out.ImportReferenceUnionParentOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImportReferenceParentOverride. +func (in *ImportReferenceParentOverride) DeepCopy() *ImportReferenceParentOverride { + if in == nil { + return nil + } + out := new(ImportReferenceParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ImportReferenceUnion) DeepCopyInto(out *ImportReferenceUnion) { + *out = *in + if in.Kubernetes != nil { + in, out := &in.Kubernetes, &out.Kubernetes + *out = new(KubernetesCustomResourceImportReference) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImportReferenceUnion. +func (in *ImportReferenceUnion) DeepCopy() *ImportReferenceUnion { + if in == nil { + return nil + } + out := new(ImportReferenceUnion) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ImportReferenceUnionParentOverride) DeepCopyInto(out *ImportReferenceUnionParentOverride) { + *out = *in + if in.Kubernetes != nil { + in, out := &in.Kubernetes, &out.Kubernetes + *out = new(KubernetesCustomResourceImportReferenceParentOverride) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImportReferenceUnionParentOverride. +func (in *ImportReferenceUnionParentOverride) DeepCopy() *ImportReferenceUnionParentOverride { + if in == nil { + return nil + } + out := new(ImportReferenceUnionParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *K8sLikeComponent) DeepCopyInto(out *K8sLikeComponent) { + *out = *in + out.BaseComponent = in.BaseComponent + out.K8sLikeComponentLocation = in.K8sLikeComponentLocation + if in.Endpoints != nil { + in, out := &in.Endpoints, &out.Endpoints + *out = make([]Endpoint, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new K8sLikeComponent. +func (in *K8sLikeComponent) DeepCopy() *K8sLikeComponent { + if in == nil { + return nil + } + out := new(K8sLikeComponent) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *K8sLikeComponentLocation) DeepCopyInto(out *K8sLikeComponentLocation) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new K8sLikeComponentLocation. +func (in *K8sLikeComponentLocation) DeepCopy() *K8sLikeComponentLocation { + if in == nil { + return nil + } + out := new(K8sLikeComponentLocation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *K8sLikeComponentLocationParentOverride) DeepCopyInto(out *K8sLikeComponentLocationParentOverride) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new K8sLikeComponentLocationParentOverride. +func (in *K8sLikeComponentLocationParentOverride) DeepCopy() *K8sLikeComponentLocationParentOverride { + if in == nil { + return nil + } + out := new(K8sLikeComponentLocationParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *K8sLikeComponentLocationPluginOverride) DeepCopyInto(out *K8sLikeComponentLocationPluginOverride) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new K8sLikeComponentLocationPluginOverride. +func (in *K8sLikeComponentLocationPluginOverride) DeepCopy() *K8sLikeComponentLocationPluginOverride { + if in == nil { + return nil + } + out := new(K8sLikeComponentLocationPluginOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *K8sLikeComponentLocationPluginOverrideParentOverride) DeepCopyInto(out *K8sLikeComponentLocationPluginOverrideParentOverride) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new K8sLikeComponentLocationPluginOverrideParentOverride. +func (in *K8sLikeComponentLocationPluginOverrideParentOverride) DeepCopy() *K8sLikeComponentLocationPluginOverrideParentOverride { + if in == nil { + return nil + } + out := new(K8sLikeComponentLocationPluginOverrideParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *K8sLikeComponentParentOverride) DeepCopyInto(out *K8sLikeComponentParentOverride) { + *out = *in + out.BaseComponentParentOverride = in.BaseComponentParentOverride + out.K8sLikeComponentLocationParentOverride = in.K8sLikeComponentLocationParentOverride + if in.Endpoints != nil { + in, out := &in.Endpoints, &out.Endpoints + *out = make([]EndpointParentOverride, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new K8sLikeComponentParentOverride. +func (in *K8sLikeComponentParentOverride) DeepCopy() *K8sLikeComponentParentOverride { + if in == nil { + return nil + } + out := new(K8sLikeComponentParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *K8sLikeComponentPluginOverride) DeepCopyInto(out *K8sLikeComponentPluginOverride) { + *out = *in + out.BaseComponentPluginOverride = in.BaseComponentPluginOverride + out.K8sLikeComponentLocationPluginOverride = in.K8sLikeComponentLocationPluginOverride + if in.Endpoints != nil { + in, out := &in.Endpoints, &out.Endpoints + *out = make([]EndpointPluginOverride, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new K8sLikeComponentPluginOverride. +func (in *K8sLikeComponentPluginOverride) DeepCopy() *K8sLikeComponentPluginOverride { + if in == nil { + return nil + } + out := new(K8sLikeComponentPluginOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *K8sLikeComponentPluginOverrideParentOverride) DeepCopyInto(out *K8sLikeComponentPluginOverrideParentOverride) { + *out = *in + out.BaseComponentPluginOverrideParentOverride = in.BaseComponentPluginOverrideParentOverride + out.K8sLikeComponentLocationPluginOverrideParentOverride = in.K8sLikeComponentLocationPluginOverrideParentOverride + if in.Endpoints != nil { + in, out := &in.Endpoints, &out.Endpoints + *out = make([]EndpointPluginOverrideParentOverride, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new K8sLikeComponentPluginOverrideParentOverride. +func (in *K8sLikeComponentPluginOverrideParentOverride) DeepCopy() *K8sLikeComponentPluginOverrideParentOverride { + if in == nil { + return nil + } + out := new(K8sLikeComponentPluginOverrideParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KubernetesComponent) DeepCopyInto(out *KubernetesComponent) { + *out = *in + in.K8sLikeComponent.DeepCopyInto(&out.K8sLikeComponent) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesComponent. +func (in *KubernetesComponent) DeepCopy() *KubernetesComponent { + if in == nil { + return nil + } + out := new(KubernetesComponent) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KubernetesComponentParentOverride) DeepCopyInto(out *KubernetesComponentParentOverride) { + *out = *in + in.K8sLikeComponentParentOverride.DeepCopyInto(&out.K8sLikeComponentParentOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesComponentParentOverride. +func (in *KubernetesComponentParentOverride) DeepCopy() *KubernetesComponentParentOverride { + if in == nil { + return nil + } + out := new(KubernetesComponentParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KubernetesComponentPluginOverride) DeepCopyInto(out *KubernetesComponentPluginOverride) { + *out = *in + in.K8sLikeComponentPluginOverride.DeepCopyInto(&out.K8sLikeComponentPluginOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesComponentPluginOverride. +func (in *KubernetesComponentPluginOverride) DeepCopy() *KubernetesComponentPluginOverride { + if in == nil { + return nil + } + out := new(KubernetesComponentPluginOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KubernetesComponentPluginOverrideParentOverride) DeepCopyInto(out *KubernetesComponentPluginOverrideParentOverride) { + *out = *in + in.K8sLikeComponentPluginOverrideParentOverride.DeepCopyInto(&out.K8sLikeComponentPluginOverrideParentOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesComponentPluginOverrideParentOverride. +func (in *KubernetesComponentPluginOverrideParentOverride) DeepCopy() *KubernetesComponentPluginOverrideParentOverride { + if in == nil { + return nil + } + out := new(KubernetesComponentPluginOverrideParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KubernetesCustomResourceImportReference) DeepCopyInto(out *KubernetesCustomResourceImportReference) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesCustomResourceImportReference. +func (in *KubernetesCustomResourceImportReference) DeepCopy() *KubernetesCustomResourceImportReference { + if in == nil { + return nil + } + out := new(KubernetesCustomResourceImportReference) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KubernetesCustomResourceImportReferenceParentOverride) DeepCopyInto(out *KubernetesCustomResourceImportReferenceParentOverride) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesCustomResourceImportReferenceParentOverride. +func (in *KubernetesCustomResourceImportReferenceParentOverride) DeepCopy() *KubernetesCustomResourceImportReferenceParentOverride { + if in == nil { + return nil + } + out := new(KubernetesCustomResourceImportReferenceParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LabeledCommand) DeepCopyInto(out *LabeledCommand) { + *out = *in + in.BaseCommand.DeepCopyInto(&out.BaseCommand) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LabeledCommand. +func (in *LabeledCommand) DeepCopy() *LabeledCommand { + if in == nil { + return nil + } + out := new(LabeledCommand) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LabeledCommandParentOverride) DeepCopyInto(out *LabeledCommandParentOverride) { + *out = *in + in.BaseCommandParentOverride.DeepCopyInto(&out.BaseCommandParentOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LabeledCommandParentOverride. +func (in *LabeledCommandParentOverride) DeepCopy() *LabeledCommandParentOverride { + if in == nil { + return nil + } + out := new(LabeledCommandParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LabeledCommandPluginOverride) DeepCopyInto(out *LabeledCommandPluginOverride) { + *out = *in + in.BaseCommandPluginOverride.DeepCopyInto(&out.BaseCommandPluginOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LabeledCommandPluginOverride. +func (in *LabeledCommandPluginOverride) DeepCopy() *LabeledCommandPluginOverride { + if in == nil { + return nil + } + out := new(LabeledCommandPluginOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LabeledCommandPluginOverrideParentOverride) DeepCopyInto(out *LabeledCommandPluginOverrideParentOverride) { + *out = *in + in.BaseCommandPluginOverrideParentOverride.DeepCopyInto(&out.BaseCommandPluginOverrideParentOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LabeledCommandPluginOverrideParentOverride. +func (in *LabeledCommandPluginOverrideParentOverride) DeepCopy() *LabeledCommandPluginOverrideParentOverride { + if in == nil { + return nil + } + out := new(LabeledCommandPluginOverrideParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OpenshiftComponent) DeepCopyInto(out *OpenshiftComponent) { + *out = *in + in.K8sLikeComponent.DeepCopyInto(&out.K8sLikeComponent) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenshiftComponent. +func (in *OpenshiftComponent) DeepCopy() *OpenshiftComponent { + if in == nil { + return nil + } + out := new(OpenshiftComponent) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OpenshiftComponentParentOverride) DeepCopyInto(out *OpenshiftComponentParentOverride) { + *out = *in + in.K8sLikeComponentParentOverride.DeepCopyInto(&out.K8sLikeComponentParentOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenshiftComponentParentOverride. +func (in *OpenshiftComponentParentOverride) DeepCopy() *OpenshiftComponentParentOverride { + if in == nil { + return nil + } + out := new(OpenshiftComponentParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OpenshiftComponentPluginOverride) DeepCopyInto(out *OpenshiftComponentPluginOverride) { + *out = *in + in.K8sLikeComponentPluginOverride.DeepCopyInto(&out.K8sLikeComponentPluginOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenshiftComponentPluginOverride. +func (in *OpenshiftComponentPluginOverride) DeepCopy() *OpenshiftComponentPluginOverride { + if in == nil { + return nil + } + out := new(OpenshiftComponentPluginOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OpenshiftComponentPluginOverrideParentOverride) DeepCopyInto(out *OpenshiftComponentPluginOverrideParentOverride) { + *out = *in + in.K8sLikeComponentPluginOverrideParentOverride.DeepCopyInto(&out.K8sLikeComponentPluginOverrideParentOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenshiftComponentPluginOverrideParentOverride. +func (in *OpenshiftComponentPluginOverrideParentOverride) DeepCopy() *OpenshiftComponentPluginOverrideParentOverride { + if in == nil { + return nil + } + out := new(OpenshiftComponentPluginOverrideParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OverrideDirective) DeepCopyInto(out *OverrideDirective) { + *out = *in + if in.DeleteFromPrimitiveList != nil { + in, out := &in.DeleteFromPrimitiveList, &out.DeleteFromPrimitiveList + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.SetElementOrder != nil { + in, out := &in.SetElementOrder, &out.SetElementOrder + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OverrideDirective. +func (in *OverrideDirective) DeepCopy() *OverrideDirective { + if in == nil { + return nil + } + out := new(OverrideDirective) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OverridesBase) DeepCopyInto(out *OverridesBase) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OverridesBase. +func (in *OverridesBase) DeepCopy() *OverridesBase { + if in == nil { + return nil + } + out := new(OverridesBase) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OverridesBaseParentOverride) DeepCopyInto(out *OverridesBaseParentOverride) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OverridesBaseParentOverride. +func (in *OverridesBaseParentOverride) DeepCopy() *OverridesBaseParentOverride { + if in == nil { + return nil + } + out := new(OverridesBaseParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Parent) DeepCopyInto(out *Parent) { + *out = *in + in.ImportReference.DeepCopyInto(&out.ImportReference) + in.ParentOverrides.DeepCopyInto(&out.ParentOverrides) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Parent. +func (in *Parent) DeepCopy() *Parent { + if in == nil { + return nil + } + out := new(Parent) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ParentOverrides) DeepCopyInto(out *ParentOverrides) { + *out = *in + out.OverridesBase = in.OverridesBase + if in.Components != nil { + in, out := &in.Components, &out.Components + *out = make([]ComponentParentOverride, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Projects != nil { + in, out := &in.Projects, &out.Projects + *out = make([]ProjectParentOverride, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.StarterProjects != nil { + in, out := &in.StarterProjects, &out.StarterProjects + *out = make([]StarterProjectParentOverride, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Commands != nil { + in, out := &in.Commands, &out.Commands + *out = make([]CommandParentOverride, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ParentOverrides. +func (in *ParentOverrides) DeepCopy() *ParentOverrides { + if in == nil { + return nil + } + out := new(ParentOverrides) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PluginComponent) DeepCopyInto(out *PluginComponent) { + *out = *in + out.BaseComponent = in.BaseComponent + in.ImportReference.DeepCopyInto(&out.ImportReference) + in.PluginOverrides.DeepCopyInto(&out.PluginOverrides) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginComponent. +func (in *PluginComponent) DeepCopy() *PluginComponent { + if in == nil { + return nil + } + out := new(PluginComponent) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PluginComponentParentOverride) DeepCopyInto(out *PluginComponentParentOverride) { + *out = *in + out.BaseComponentParentOverride = in.BaseComponentParentOverride + in.ImportReferenceParentOverride.DeepCopyInto(&out.ImportReferenceParentOverride) + in.PluginOverridesParentOverride.DeepCopyInto(&out.PluginOverridesParentOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginComponentParentOverride. +func (in *PluginComponentParentOverride) DeepCopy() *PluginComponentParentOverride { + if in == nil { + return nil + } + out := new(PluginComponentParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PluginOverrides) DeepCopyInto(out *PluginOverrides) { + *out = *in + out.OverridesBase = in.OverridesBase + if in.Components != nil { + in, out := &in.Components, &out.Components + *out = make([]ComponentPluginOverride, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Commands != nil { + in, out := &in.Commands, &out.Commands + *out = make([]CommandPluginOverride, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginOverrides. +func (in *PluginOverrides) DeepCopy() *PluginOverrides { + if in == nil { + return nil + } + out := new(PluginOverrides) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PluginOverridesParentOverride) DeepCopyInto(out *PluginOverridesParentOverride) { + *out = *in + out.OverridesBaseParentOverride = in.OverridesBaseParentOverride + if in.Components != nil { + in, out := &in.Components, &out.Components + *out = make([]ComponentPluginOverrideParentOverride, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Commands != nil { + in, out := &in.Commands, &out.Commands + *out = make([]CommandPluginOverrideParentOverride, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginOverridesParentOverride. +func (in *PluginOverridesParentOverride) DeepCopy() *PluginOverridesParentOverride { + if in == nil { + return nil + } + out := new(PluginOverridesParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Project) DeepCopyInto(out *Project) { + *out = *in + if in.SparseCheckoutDirs != nil { + in, out := &in.SparseCheckoutDirs, &out.SparseCheckoutDirs + *out = make([]string, len(*in)) + copy(*out, *in) + } + in.ProjectSource.DeepCopyInto(&out.ProjectSource) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Project. +func (in *Project) DeepCopy() *Project { + if in == nil { + return nil + } + out := new(Project) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProjectParentOverride) DeepCopyInto(out *ProjectParentOverride) { + *out = *in + if in.SparseCheckoutDirs != nil { + in, out := &in.SparseCheckoutDirs, &out.SparseCheckoutDirs + *out = make([]string, len(*in)) + copy(*out, *in) + } + in.ProjectSourceParentOverride.DeepCopyInto(&out.ProjectSourceParentOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProjectParentOverride. +func (in *ProjectParentOverride) DeepCopy() *ProjectParentOverride { + if in == nil { + return nil + } + out := new(ProjectParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProjectSource) DeepCopyInto(out *ProjectSource) { + *out = *in + if in.Git != nil { + in, out := &in.Git, &out.Git + *out = new(GitProjectSource) + (*in).DeepCopyInto(*out) + } + if in.Github != nil { + in, out := &in.Github, &out.Github + *out = new(GithubProjectSource) + (*in).DeepCopyInto(*out) + } + if in.Zip != nil { + in, out := &in.Zip, &out.Zip + *out = new(ZipProjectSource) + **out = **in + } + if in.Custom != nil { + in, out := &in.Custom, &out.Custom + *out = new(CustomProjectSource) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProjectSource. +func (in *ProjectSource) DeepCopy() *ProjectSource { + if in == nil { + return nil + } + out := new(ProjectSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProjectSourceParentOverride) DeepCopyInto(out *ProjectSourceParentOverride) { + *out = *in + if in.Git != nil { + in, out := &in.Git, &out.Git + *out = new(GitProjectSourceParentOverride) + (*in).DeepCopyInto(*out) + } + if in.Github != nil { + in, out := &in.Github, &out.Github + *out = new(GithubProjectSourceParentOverride) + (*in).DeepCopyInto(*out) + } + if in.Zip != nil { + in, out := &in.Zip, &out.Zip + *out = new(ZipProjectSourceParentOverride) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProjectSourceParentOverride. +func (in *ProjectSourceParentOverride) DeepCopy() *ProjectSourceParentOverride { + if in == nil { + return nil + } + out := new(ProjectSourceParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StarterProject) DeepCopyInto(out *StarterProject) { + *out = *in + in.ProjectSource.DeepCopyInto(&out.ProjectSource) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StarterProject. +func (in *StarterProject) DeepCopy() *StarterProject { + if in == nil { + return nil + } + out := new(StarterProject) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StarterProjectParentOverride) DeepCopyInto(out *StarterProjectParentOverride) { + *out = *in + in.ProjectSourceParentOverride.DeepCopyInto(&out.ProjectSourceParentOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StarterProjectParentOverride. +func (in *StarterProjectParentOverride) DeepCopy() *StarterProjectParentOverride { + if in == nil { + return nil + } + out := new(StarterProjectParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Volume) DeepCopyInto(out *Volume) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Volume. +func (in *Volume) DeepCopy() *Volume { + if in == nil { + return nil + } + out := new(Volume) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeComponent) DeepCopyInto(out *VolumeComponent) { + *out = *in + out.BaseComponent = in.BaseComponent + out.Volume = in.Volume +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeComponent. +func (in *VolumeComponent) DeepCopy() *VolumeComponent { + if in == nil { + return nil + } + out := new(VolumeComponent) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeComponentParentOverride) DeepCopyInto(out *VolumeComponentParentOverride) { + *out = *in + out.BaseComponentParentOverride = in.BaseComponentParentOverride + out.VolumeParentOverride = in.VolumeParentOverride +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeComponentParentOverride. +func (in *VolumeComponentParentOverride) DeepCopy() *VolumeComponentParentOverride { + if in == nil { + return nil + } + out := new(VolumeComponentParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeComponentPluginOverride) DeepCopyInto(out *VolumeComponentPluginOverride) { + *out = *in + out.BaseComponentPluginOverride = in.BaseComponentPluginOverride + out.VolumePluginOverride = in.VolumePluginOverride +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeComponentPluginOverride. +func (in *VolumeComponentPluginOverride) DeepCopy() *VolumeComponentPluginOverride { + if in == nil { + return nil + } + out := new(VolumeComponentPluginOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeComponentPluginOverrideParentOverride) DeepCopyInto(out *VolumeComponentPluginOverrideParentOverride) { + *out = *in + out.BaseComponentPluginOverrideParentOverride = in.BaseComponentPluginOverrideParentOverride + out.VolumePluginOverrideParentOverride = in.VolumePluginOverrideParentOverride +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeComponentPluginOverrideParentOverride. +func (in *VolumeComponentPluginOverrideParentOverride) DeepCopy() *VolumeComponentPluginOverrideParentOverride { + if in == nil { + return nil + } + out := new(VolumeComponentPluginOverrideParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeMount) DeepCopyInto(out *VolumeMount) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeMount. +func (in *VolumeMount) DeepCopy() *VolumeMount { + if in == nil { + return nil + } + out := new(VolumeMount) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeMountParentOverride) DeepCopyInto(out *VolumeMountParentOverride) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeMountParentOverride. +func (in *VolumeMountParentOverride) DeepCopy() *VolumeMountParentOverride { + if in == nil { + return nil + } + out := new(VolumeMountParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeMountPluginOverride) DeepCopyInto(out *VolumeMountPluginOverride) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeMountPluginOverride. +func (in *VolumeMountPluginOverride) DeepCopy() *VolumeMountPluginOverride { + if in == nil { + return nil + } + out := new(VolumeMountPluginOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeMountPluginOverrideParentOverride) DeepCopyInto(out *VolumeMountPluginOverrideParentOverride) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeMountPluginOverrideParentOverride. +func (in *VolumeMountPluginOverrideParentOverride) DeepCopy() *VolumeMountPluginOverrideParentOverride { + if in == nil { + return nil + } + out := new(VolumeMountPluginOverrideParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeParentOverride) DeepCopyInto(out *VolumeParentOverride) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeParentOverride. +func (in *VolumeParentOverride) DeepCopy() *VolumeParentOverride { + if in == nil { + return nil + } + out := new(VolumeParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumePluginOverride) DeepCopyInto(out *VolumePluginOverride) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumePluginOverride. +func (in *VolumePluginOverride) DeepCopy() *VolumePluginOverride { + if in == nil { + return nil + } + out := new(VolumePluginOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumePluginOverrideParentOverride) DeepCopyInto(out *VolumePluginOverrideParentOverride) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumePluginOverrideParentOverride. +func (in *VolumePluginOverrideParentOverride) DeepCopy() *VolumePluginOverrideParentOverride { + if in == nil { + return nil + } + out := new(VolumePluginOverrideParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VscodeConfigurationCommand) DeepCopyInto(out *VscodeConfigurationCommand) { + *out = *in + in.BaseCommand.DeepCopyInto(&out.BaseCommand) + out.VscodeConfigurationCommandLocation = in.VscodeConfigurationCommandLocation +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VscodeConfigurationCommand. +func (in *VscodeConfigurationCommand) DeepCopy() *VscodeConfigurationCommand { + if in == nil { + return nil + } + out := new(VscodeConfigurationCommand) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VscodeConfigurationCommandLocation) DeepCopyInto(out *VscodeConfigurationCommandLocation) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VscodeConfigurationCommandLocation. +func (in *VscodeConfigurationCommandLocation) DeepCopy() *VscodeConfigurationCommandLocation { + if in == nil { + return nil + } + out := new(VscodeConfigurationCommandLocation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VscodeConfigurationCommandLocationParentOverride) DeepCopyInto(out *VscodeConfigurationCommandLocationParentOverride) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VscodeConfigurationCommandLocationParentOverride. +func (in *VscodeConfigurationCommandLocationParentOverride) DeepCopy() *VscodeConfigurationCommandLocationParentOverride { + if in == nil { + return nil + } + out := new(VscodeConfigurationCommandLocationParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VscodeConfigurationCommandLocationPluginOverride) DeepCopyInto(out *VscodeConfigurationCommandLocationPluginOverride) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VscodeConfigurationCommandLocationPluginOverride. +func (in *VscodeConfigurationCommandLocationPluginOverride) DeepCopy() *VscodeConfigurationCommandLocationPluginOverride { + if in == nil { + return nil + } + out := new(VscodeConfigurationCommandLocationPluginOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VscodeConfigurationCommandLocationPluginOverrideParentOverride) DeepCopyInto(out *VscodeConfigurationCommandLocationPluginOverrideParentOverride) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VscodeConfigurationCommandLocationPluginOverrideParentOverride. +func (in *VscodeConfigurationCommandLocationPluginOverrideParentOverride) DeepCopy() *VscodeConfigurationCommandLocationPluginOverrideParentOverride { + if in == nil { + return nil + } + out := new(VscodeConfigurationCommandLocationPluginOverrideParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VscodeConfigurationCommandParentOverride) DeepCopyInto(out *VscodeConfigurationCommandParentOverride) { + *out = *in + in.BaseCommandParentOverride.DeepCopyInto(&out.BaseCommandParentOverride) + out.VscodeConfigurationCommandLocationParentOverride = in.VscodeConfigurationCommandLocationParentOverride +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VscodeConfigurationCommandParentOverride. +func (in *VscodeConfigurationCommandParentOverride) DeepCopy() *VscodeConfigurationCommandParentOverride { + if in == nil { + return nil + } + out := new(VscodeConfigurationCommandParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VscodeConfigurationCommandPluginOverride) DeepCopyInto(out *VscodeConfigurationCommandPluginOverride) { + *out = *in + in.BaseCommandPluginOverride.DeepCopyInto(&out.BaseCommandPluginOverride) + out.VscodeConfigurationCommandLocationPluginOverride = in.VscodeConfigurationCommandLocationPluginOverride +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VscodeConfigurationCommandPluginOverride. +func (in *VscodeConfigurationCommandPluginOverride) DeepCopy() *VscodeConfigurationCommandPluginOverride { + if in == nil { + return nil + } + out := new(VscodeConfigurationCommandPluginOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VscodeConfigurationCommandPluginOverrideParentOverride) DeepCopyInto(out *VscodeConfigurationCommandPluginOverrideParentOverride) { + *out = *in + in.BaseCommandPluginOverrideParentOverride.DeepCopyInto(&out.BaseCommandPluginOverrideParentOverride) + out.VscodeConfigurationCommandLocationPluginOverrideParentOverride = in.VscodeConfigurationCommandLocationPluginOverrideParentOverride +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VscodeConfigurationCommandPluginOverrideParentOverride. +func (in *VscodeConfigurationCommandPluginOverrideParentOverride) DeepCopy() *VscodeConfigurationCommandPluginOverrideParentOverride { + if in == nil { + return nil + } + out := new(VscodeConfigurationCommandPluginOverrideParentOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *WorkspaceCondition) DeepCopyInto(out *WorkspaceCondition) { + *out = *in + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkspaceCondition. +func (in *WorkspaceCondition) DeepCopy() *WorkspaceCondition { + if in == nil { + return nil + } + out := new(WorkspaceCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *WorkspaceEvents) DeepCopyInto(out *WorkspaceEvents) { + *out = *in + if in.PreStart != nil { + in, out := &in.PreStart, &out.PreStart + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.PostStart != nil { + in, out := &in.PostStart, &out.PostStart + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.PreStop != nil { + in, out := &in.PreStop, &out.PreStop + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.PostStop != nil { + in, out := &in.PostStop, &out.PostStop + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkspaceEvents. +func (in *WorkspaceEvents) DeepCopy() *WorkspaceEvents { + if in == nil { + return nil + } + out := new(WorkspaceEvents) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *WorkspacePodContributions) DeepCopyInto(out *WorkspacePodContributions) { + *out = *in + if in.Volumes != nil { + in, out := &in.Volumes, &out.Volumes + *out = make([]v1.Volume, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.InitContainers != nil { + in, out := &in.InitContainers, &out.InitContainers + *out = make([]v1.Container, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Containers != nil { + in, out := &in.Containers, &out.Containers + *out = make([]v1.Container, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ImagePullSecrets != nil { + in, out := &in.ImagePullSecrets, &out.ImagePullSecrets + *out = make([]v1.LocalObjectReference, len(*in)) + copy(*out, *in) + } + if in.CommonEnv != nil { + in, out := &in.CommonEnv, &out.CommonEnv + *out = make([]v1.EnvVar, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkspacePodContributions. +func (in *WorkspacePodContributions) DeepCopy() *WorkspacePodContributions { + if in == nil { + return nil + } + out := new(WorkspacePodContributions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ZipProjectSource) DeepCopyInto(out *ZipProjectSource) { + *out = *in + out.CommonProjectSource = in.CommonProjectSource +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZipProjectSource. +func (in *ZipProjectSource) DeepCopy() *ZipProjectSource { + if in == nil { + return nil + } + out := new(ZipProjectSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ZipProjectSourceParentOverride) DeepCopyInto(out *ZipProjectSourceParentOverride) { + *out = *in + out.CommonProjectSourceParentOverride = in.CommonProjectSourceParentOverride +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZipProjectSourceParentOverride. +func (in *ZipProjectSourceParentOverride) DeepCopy() *ZipProjectSourceParentOverride { + if in == nil { + return nil + } + out := new(ZipProjectSourceParentOverride) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/zz_generated.keyed_definitions.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/zz_generated.keyed_definitions.go new file mode 100644 index 000000000..27a85e013 --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/zz_generated.keyed_definitions.go @@ -0,0 +1,49 @@ +package v1alpha2 + +func (keyed Component) Key() string { + return keyed.Name +} + +func (keyed Project) Key() string { + return keyed.Name +} + +func (keyed StarterProject) Key() string { + return keyed.Name +} + +func (keyed Command) Key() string { + return keyed.Id +} + +func (keyed ComponentParentOverride) Key() string { + return keyed.Name +} + +func (keyed ProjectParentOverride) Key() string { + return keyed.Name +} + +func (keyed StarterProjectParentOverride) Key() string { + return keyed.Name +} + +func (keyed CommandParentOverride) Key() string { + return keyed.Id +} + +func (keyed ComponentPluginOverrideParentOverride) Key() string { + return keyed.Name +} + +func (keyed CommandPluginOverrideParentOverride) Key() string { + return keyed.Id +} + +func (keyed ComponentPluginOverride) Key() string { + return keyed.Name +} + +func (keyed CommandPluginOverride) Key() string { + return keyed.Id +} diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/zz_generated.parent_overrides.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/zz_generated.parent_overrides.go new file mode 100644 index 000000000..9dc2072ed --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/zz_generated.parent_overrides.go @@ -0,0 +1,1116 @@ +package v1alpha2 + +// +devfile:jsonschema:generate +type ParentOverrides struct { + OverridesBase `json:",inline"` + + // Overrides of components encapsulated in a parent devfile or a plugin. + // Overriding is done according to K8S strategic merge patch standard rules. + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + // +devfile:toplevellist + Components []ComponentParentOverride `json:"components,omitempty" patchStrategy:"merge" patchMergeKey:"name"` + + // Overrides of projects encapsulated in a parent devfile. + // Overriding is done according to K8S strategic merge patch standard rules. + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + // +devfile:toplevellist + Projects []ProjectParentOverride `json:"projects,omitempty" patchStrategy:"merge" patchMergeKey:"name"` + + // Overrides of starterProjects encapsulated in a parent devfile. + // Overriding is done according to K8S strategic merge patch standard rules. + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + // +devfile:toplevellist + StarterProjects []StarterProjectParentOverride `json:"starterProjects,omitempty" patchStrategy:"merge" patchMergeKey:"name"` + + // Overrides of commands encapsulated in a parent devfile or a plugin. + // Overriding is done according to K8S strategic merge patch standard rules. + // +optional + // +patchMergeKey=id + // +patchStrategy=merge + // +devfile:toplevellist + Commands []CommandParentOverride `json:"commands,omitempty" patchStrategy:"merge" patchMergeKey:"id"` +} + +//+k8s:openapi-gen=true +type ComponentParentOverride struct { + + // Mandatory name that allows referencing the component + // from other elements (such as commands) or from an external + // devfile that may reference this component through a parent or a plugin. + Name string `json:"name"` + ComponentUnionParentOverride `json:",inline"` +} + +type ProjectParentOverride struct { + + // Project name + Name string `json:"name"` + + // Path relative to the root of the projects to which this project should be cloned into. This is a unix-style relative path (i.e. uses forward slashes). The path is invalid if it is absolute or tries to escape the project root through the usage of '..'. If not specified, defaults to the project name. + // +optional + ClonePath string `json:"clonePath,omitempty"` + + // Populate the project sparsely with selected directories. + // +optional + SparseCheckoutDirs []string `json:"sparseCheckoutDirs,omitempty"` + + ProjectSourceParentOverride `json:",inline"` +} + +type StarterProjectParentOverride struct { + + // Project name + Name string `json:"name"` + + // Description of a starter project + // +optional + Description string `json:"description,omitempty"` + + // Sub-directory from a starter project to be used as root for starter project. + // +optional + SubDir string `json:"subDir,omitempty"` + + ProjectSourceParentOverride `json:",inline"` +} + +type CommandParentOverride struct { + + // Mandatory identifier that allows referencing + // this command in composite commands, from + // a parent, or in events. + Id string `json:"id"` + CommandUnionParentOverride `json:",inline"` +} + +// +union +type ComponentUnionParentOverride struct { + + // +kubebuilder:validation:Enum=Container;Kubernetes;Openshift;Volume;Plugin + // Type of component + // + // +unionDiscriminator + // +optional + ComponentType ComponentTypeParentOverride `json:"componentType,omitempty"` + + // Allows adding and configuring workspace-related containers + // +optional + Container *ContainerComponentParentOverride `json:"container,omitempty"` + + // Allows importing into the workspace the Kubernetes resources + // defined in a given manifest. For example this allows reusing the Kubernetes + // definitions used to deploy some runtime components in production. + // + // +optional + Kubernetes *KubernetesComponentParentOverride `json:"kubernetes,omitempty"` + + // Allows importing into the workspace the OpenShift resources + // defined in a given manifest. For example this allows reusing the OpenShift + // definitions used to deploy some runtime components in production. + // + // +optional + Openshift *OpenshiftComponentParentOverride `json:"openshift,omitempty"` + + // Allows specifying the definition of a volume + // shared by several other components + // +optional + Volume *VolumeComponentParentOverride `json:"volume,omitempty"` + + // Allows importing a plugin. + // + // Plugins are mainly imported devfiles that contribute components, commands + // and events as a consistent single unit. They are defined in either YAML files + // following the devfile syntax, + // or as `DevWorkspaceTemplate` Kubernetes Custom Resources + // +optional + // +devfile:overrides:include:omitInPlugin=true + Plugin *PluginComponentParentOverride `json:"plugin,omitempty"` +} + +// +union +type ProjectSourceParentOverride struct { + + // +kubebuilder:validation:Enum=Git;Github;Zip + // Type of project source + // + + // +unionDiscriminator + // +optional + SourceType ProjectSourceTypeParentOverride `json:"sourceType,omitempty"` + + // Project's Git source + // +optional + Git *GitProjectSourceParentOverride `json:"git,omitempty"` + + // Project's GitHub source + // +optional + Github *GithubProjectSourceParentOverride `json:"github,omitempty"` + + // Project's Zip source + // +optional + Zip *ZipProjectSourceParentOverride `json:"zip,omitempty"` +} + +// +union +type CommandUnionParentOverride struct { + + // +kubebuilder:validation:Enum=Exec;Apply;VscodeTask;VscodeLaunch;Composite + // Type of workspace command + // +unionDiscriminator + // +optional + CommandType CommandTypeParentOverride `json:"commandType,omitempty"` + + // CLI Command executed in an existing component container + // +optional + Exec *ExecCommandParentOverride `json:"exec,omitempty"` + + // Command that consists in applying a given component definition, + // typically bound to a workspace event. + // + // For example, when an `apply` command is bound to a `preStart` event, + // and references a `container` component, it will start the container as a + // K8S initContainer in the workspace POD, unless the component has its + // `dedicatedPod` field set to `true`. + // + // When no `apply` command exist for a given component, + // it is assumed the component will be applied at workspace start + // by default. + // +optional + Apply *ApplyCommandParentOverride `json:"apply,omitempty"` + + // Command providing the definition of a VsCode Task + // +optional + VscodeTask *VscodeConfigurationCommandParentOverride `json:"vscodeTask,omitempty"` + + // Command providing the definition of a VsCode launch action + // +optional + VscodeLaunch *VscodeConfigurationCommandParentOverride `json:"vscodeLaunch,omitempty"` + + // Composite command that allows executing several sub-commands + // either sequentially or concurrently + // +optional + Composite *CompositeCommandParentOverride `json:"composite,omitempty"` +} + +// ComponentType describes the type of component. +// Only one of the following component type may be specified. +type ComponentTypeParentOverride string + +// Component that allows the developer to add a configured container into his workspace +type ContainerComponentParentOverride struct { + BaseComponentParentOverride `json:",inline"` + ContainerParentOverride `json:",inline"` + Endpoints []EndpointParentOverride `json:"endpoints,omitempty" patchStrategy:"merge" patchMergeKey:"name"` +} + +// Component that allows partly importing Kubernetes resources into the workspace POD +type KubernetesComponentParentOverride struct { + K8sLikeComponentParentOverride `json:",inline"` +} + +// Component that allows partly importing Openshift resources into the workspace POD +type OpenshiftComponentParentOverride struct { + K8sLikeComponentParentOverride `json:",inline"` +} + +// Component that allows the developer to declare and configure a volume into his workspace +type VolumeComponentParentOverride struct { + BaseComponentParentOverride `json:",inline"` + VolumeParentOverride `json:",inline"` +} + +type PluginComponentParentOverride struct { + BaseComponentParentOverride `json:",inline"` + ImportReferenceParentOverride `json:",inline"` + PluginOverridesParentOverride `json:",inline"` +} + +// ProjectSourceType describes the type of Project sources. +// Only one of the following project sources may be specified. +// If none of the following policies is specified, the default one +// is AllowConcurrent. +type ProjectSourceTypeParentOverride string + +type GitProjectSourceParentOverride struct { + GitLikeProjectSourceParentOverride `json:",inline"` +} + +type GithubProjectSourceParentOverride struct { + GitLikeProjectSourceParentOverride `json:",inline"` +} + +type ZipProjectSourceParentOverride struct { + CommonProjectSourceParentOverride `json:",inline"` + + // Zip project's source location address. Should be file path of the archive, e.g. file://$FILE_PATH + // +required + Location string `json:"location,omitempty"` +} + +// CommandType describes the type of command. +// Only one of the following command type may be specified. +type CommandTypeParentOverride string + +type ExecCommandParentOverride struct { + LabeledCommandParentOverride `json:",inline"` + + // +optional + // The actual command-line string + // + // Special variables that can be used: + // + // - `$PROJECTS_ROOT`: A path where projects sources are mounted as defined by container component's sourceMapping. + // + // - `$PROJECT_SOURCE`: A path to a project source ($PROJECTS_ROOT/). If there are multiple projects, this will point to the directory of the first one. + CommandLine string `json:"commandLine,omitempty"` + + // +optional + // Describes component to which given action relates + // + Component string `json:"component,omitempty"` + + // Working directory where the command should be executed + // + // Special variables that can be used: + // + // - `$PROJECTS_ROOT`: A path where projects sources are mounted as defined by container component's sourceMapping. + // + // - `$PROJECT_SOURCE`: A path to a project source ($PROJECTS_ROOT/). If there are multiple projects, this will point to the directory of the first one. + // +optional + WorkingDir string `json:"workingDir,omitempty"` + + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + // Optional list of environment variables that have to be set + // before running the command + Env []EnvVarParentOverride `json:"env,omitempty" patchStrategy:"merge" patchMergeKey:"name"` + + // +optional + // Whether the command is capable to reload itself when source code changes. + // If set to `true` the command won't be restarted and it is expected to handle file changes on its own. + // + // Default value is `false` + HotReloadCapable bool `json:"hotReloadCapable,omitempty"` +} + +type ApplyCommandParentOverride struct { + LabeledCommandParentOverride `json:",inline"` + + // +optional + // Describes component that will be applied + // + Component string `json:"component,omitempty"` +} + +type VscodeConfigurationCommandParentOverride struct { + BaseCommandParentOverride `json:",inline"` + VscodeConfigurationCommandLocationParentOverride `json:",inline"` +} + +type CompositeCommandParentOverride struct { + LabeledCommandParentOverride `json:",inline"` + + // The commands that comprise this composite command + Commands []string `json:"commands,omitempty" patchStrategy:"replace"` + + // Indicates if the sub-commands should be executed concurrently + // +optional + Parallel bool `json:"parallel,omitempty"` +} + +// Workspace component: Anything that will bring additional features / tooling / behaviour / context +// to the workspace, in order to make working in it easier. +type BaseComponentParentOverride struct { +} + +type ContainerParentOverride struct { + // +optional + Image string `json:"image,omitempty"` + + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + // Environment variables used in this container. + // + // The following variables are reserved and cannot be overridden via env: + // + // - `$PROJECTS_ROOT` + // + // - `$PROJECT_SOURCE` + Env []EnvVarParentOverride `json:"env,omitempty" patchStrategy:"merge" patchMergeKey:"name"` + + // +optional + // List of volumes mounts that should be mounted is this container. + VolumeMounts []VolumeMountParentOverride `json:"volumeMounts,omitempty" patchStrategy:"merge" patchMergeKey:"name"` + + // +optional + MemoryLimit string `json:"memoryLimit,omitempty"` + + // The command to run in the dockerimage component instead of the default one provided in the image. + // + // Defaults to an empty array, meaning use whatever is defined in the image. + // +optional + Command []string `json:"command,omitempty" patchStrategy:"replace"` + + // The arguments to supply to the command running the dockerimage component. The arguments are supplied either to the default command provided in the image or to the overridden command. + // + // Defaults to an empty array, meaning use whatever is defined in the image. + // +optional + Args []string `json:"args,omitempty" patchStrategy:"replace"` + + // Toggles whether or not the project source code should + // be mounted in the component. + // + // Defaults to true for all component types except plugins and components that set `dedicatedPod` to true. + // +optional + MountSources *bool `json:"mountSources,omitempty"` + + // Optional specification of the path in the container where + // project sources should be transferred/mounted when `mountSources` is `true`. + // When omitted, the default value of /projects is used. + // +optional + SourceMapping string `json:"sourceMapping,omitempty"` + + // Specify if a container should run in its own separated pod, + // instead of running as part of the main development environment pod. + // + // Default value is `false` + // +optional + DedicatedPod bool `json:"dedicatedPod,omitempty"` +} + +type EndpointParentOverride struct { + Name string `json:"name"` + + // +optional + TargetPort int `json:"targetPort,omitempty"` + + // Describes how the endpoint should be exposed on the network. + // + // - `public` means that the endpoint will be exposed on the public network, typically through + // a K8S ingress or an OpenShift route. + // + // - `internal` means that the endpoint will be exposed internally outside of the main workspace POD, + // typically by K8S services, to be consumed by other elements running + // on the same cloud internal network. + // + // - `none` means that the endpoint will not be exposed and will only be accessible + // inside the main workspace POD, on a local address. + // + // Default value is `public` + // +optional + Exposure EndpointExposureParentOverride `json:"exposure,omitempty"` + + // Describes the application and transport protocols of the traffic that will go through this endpoint. + // + // - `http`: Endpoint will have `http` traffic, typically on a TCP connection. + // It will be automaticaly promoted to `https` when the `secure` field is set to `true`. + // + // - `https`: Endpoint will have `https` traffic, typically on a TCP connection. + // + // - `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. + // It will be automaticaly promoted to `wss` when the `secure` field is set to `true`. + // + // - `wss`: Endpoint will have `wss` traffic, typically on a TCP connection. + // + // - `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol. + // + // - `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol. + // + // Default value is `http` + // +optional + Protocol EndpointProtocolParentOverride `json:"protocol,omitempty"` + + // Describes whether the endpoint should be secured and protected by some + // authentication process + // +optional + Secure bool `json:"secure,omitempty"` + + // Path of the endpoint URL + // +optional + Path string `json:"path,omitempty"` + + // Map of implementation-dependant string-based free-form attributes. + // + // Examples of Che-specific attributes: + // + // - cookiesAuthEnabled: "true" / "false", + // + // - type: "terminal" / "ide" / "ide-dev", + // +optional + Attributes map[string]string `json:"attributes,omitempty"` +} + +type K8sLikeComponentParentOverride struct { + BaseComponentParentOverride `json:",inline"` + K8sLikeComponentLocationParentOverride `json:",inline"` + Endpoints []EndpointParentOverride `json:"endpoints,omitempty" patchStrategy:"merge" patchMergeKey:"name"` +} + +// Volume that should be mounted to a component container +type VolumeParentOverride struct { + + // +optional + // Size of the volume + Size string `json:"size,omitempty"` +} + +type ImportReferenceParentOverride struct { + ImportReferenceUnionParentOverride `json:",inline"` + + // +optional + RegistryUrl string `json:"registryUrl,omitempty"` +} + +type PluginOverridesParentOverride struct { + OverridesBaseParentOverride `json:",inline"` + + // Overrides of components encapsulated in a parent devfile or a plugin. + // Overriding is done according to K8S strategic merge patch standard rules. + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + // +devfile:toplevellist + Components []ComponentPluginOverrideParentOverride `json:"components,omitempty" patchStrategy:"merge" patchMergeKey:"name"` + + // Overrides of commands encapsulated in a parent devfile or a plugin. + // Overriding is done according to K8S strategic merge patch standard rules. + // +optional + // +patchMergeKey=id + // +patchStrategy=merge + // +devfile:toplevellist + Commands []CommandPluginOverrideParentOverride `json:"commands,omitempty" patchStrategy:"merge" patchMergeKey:"id"` +} + +type GitLikeProjectSourceParentOverride struct { + CommonProjectSourceParentOverride `json:",inline"` + + // Defines from what the project should be checked out. Required if there are more than one remote configured + // +optional + CheckoutFrom *CheckoutFromParentOverride `json:"checkoutFrom,omitempty"` + + // +optional + // The remotes map which should be initialized in the git project. Must have at least one remote configured + Remotes map[string]string `json:"remotes,omitempty"` +} + +type CommonProjectSourceParentOverride struct { +} + +type LabeledCommandParentOverride struct { + BaseCommandParentOverride `json:",inline"` + + // +optional + // Optional label that provides a label for this command + // to be used in Editor UI menus for example + Label string `json:"label,omitempty"` +} + +type EnvVarParentOverride struct { + Name string `json:"name" yaml:"name"` + // +optional + Value string `json:"value,omitempty" yaml:"value"` +} + +type BaseCommandParentOverride struct { + + // +optional + // Defines the group this command is part of + Group *CommandGroupParentOverride `json:"group,omitempty"` + + // Optional map of free-form additional command attributes + Attributes map[string]string `json:"attributes,omitempty"` +} + +// +union +type VscodeConfigurationCommandLocationParentOverride struct { + + // +kubebuilder:validation:Enum=Uri;Inlined + // Type of Vscode configuration command location + // + + // +unionDiscriminator + // +optional + LocationType VscodeConfigurationCommandLocationTypeParentOverride `json:"locationType,omitempty"` + + // Location as an absolute of relative URI + // the VsCode configuration will be fetched from + // +optional + Uri string `json:"uri,omitempty"` + + // Inlined content of the VsCode configuration + // +optional + Inlined string `json:"inlined,omitempty"` +} + +// Volume that should be mounted to a component container +type VolumeMountParentOverride struct { + + // The volume mount name is the name of an existing `Volume` component. + // If several containers mount the same volume name + // then they will reuse the same volume and will be able to access to the same files. + Name string `json:"name"` + + // The path in the component container where the volume should be mounted. + // If not path is mentioned, default path is the is `/`. + // +optional + Path string `json:"path,omitempty"` +} + +// EndpointExposure describes the way an endpoint is exposed on the network. +// Only one of the following exposures may be specified: public, internal, none. +// +kubebuilder:validation:Enum=public;internal;none +type EndpointExposureParentOverride string + +// EndpointProtocol defines the application and transport protocols of the traffic that will go through this endpoint. +// Only one of the following protocols may be specified: http, ws, tcp, udp. +// +kubebuilder:validation:Enum=http;ws;tcp;udp +type EndpointProtocolParentOverride string + +// +union +type K8sLikeComponentLocationParentOverride struct { + + // +kubebuilder:validation:Enum=Uri;Inlined + // Type of Kubernetes-like location + // + + // +unionDiscriminator + // +optional + LocationType K8sLikeComponentLocationTypeParentOverride `json:"locationType,omitempty"` + + // Location in a file fetched from a uri. + // +optional + Uri string `json:"uri,omitempty"` + + // Inlined manifest + // +optional + Inlined string `json:"inlined,omitempty"` +} + +// Location from where the an import reference is retrieved +// +union +type ImportReferenceUnionParentOverride struct { + + // +kubebuilder:validation:Enum=Uri;Id;Kubernetes + // type of location from where the referenced template structure should be retrieved + // + + // +unionDiscriminator + // +optional + ImportReferenceType ImportReferenceTypeParentOverride `json:"importReferenceType,omitempty"` + + // Uri of a Devfile yaml file + // +optional + Uri string `json:"uri,omitempty"` + + // Id in a registry that contains a Devfile yaml file + // +optional + Id string `json:"id,omitempty"` + + // Reference to a Kubernetes CRD of type DevWorkspaceTemplate + // +optional + Kubernetes *KubernetesCustomResourceImportReferenceParentOverride `json:"kubernetes,omitempty"` +} + +// OverridesBase is used in the Overrides generator in order to provide a common base for the generated Overrides +// So please be careful when renaming +type OverridesBaseParentOverride struct{} + +//+k8s:openapi-gen=true +type ComponentPluginOverrideParentOverride struct { + + // Mandatory name that allows referencing the component + // from other elements (such as commands) or from an external + // devfile that may reference this component through a parent or a plugin. + Name string `json:"name"` + ComponentUnionPluginOverrideParentOverride `json:",inline"` +} + +type CommandPluginOverrideParentOverride struct { + + // Mandatory identifier that allows referencing + // this command in composite commands, from + // a parent, or in events. + Id string `json:"id"` + CommandUnionPluginOverrideParentOverride `json:",inline"` +} + +type CheckoutFromParentOverride struct { + + // The revision to checkout from. Should be branch name, tag or commit id. + // Default branch is used if missing or specified revision is not found. + // +optional + Revision string `json:"revision,omitempty"` + + // The remote name should be used as init. Required if there are more than one remote configured + // +optional + Remote string `json:"remote,omitempty"` +} + +type CommandGroupParentOverride struct { + + // +optional + // Kind of group the command is part of + Kind CommandGroupKindParentOverride `json:"kind,omitempty"` + + // +optional + // Identifies the default command for a given group kind + IsDefault bool `json:"isDefault,omitempty"` +} + +// VscodeConfigurationCommandLocationType describes the type of +// the location the configuration is fetched from. +// Only one of the following component type may be specified. +type VscodeConfigurationCommandLocationTypeParentOverride string + +// K8sLikeComponentLocationType describes the type of +// the location the configuration is fetched from. +// Only one of the following component type may be specified. +type K8sLikeComponentLocationTypeParentOverride string + +// ImportReferenceType describes the type of location +// from where the referenced template structure should be retrieved. +// Only one of the following parent locations may be specified. +type ImportReferenceTypeParentOverride string + +type KubernetesCustomResourceImportReferenceParentOverride struct { + // +optional + Name string `json:"name,omitempty"` + + // +optional + Namespace string `json:"namespace,omitempty"` +} + +// +union +type ComponentUnionPluginOverrideParentOverride struct { + + // +kubebuilder:validation:Enum=Container;Kubernetes;Openshift;Volume + // Type of component + // + // +unionDiscriminator + // +optional + ComponentType ComponentTypePluginOverrideParentOverride `json:"componentType,omitempty"` + + // Allows adding and configuring workspace-related containers + // +optional + Container *ContainerComponentPluginOverrideParentOverride `json:"container,omitempty"` + + // Allows importing into the workspace the Kubernetes resources + // defined in a given manifest. For example this allows reusing the Kubernetes + // definitions used to deploy some runtime components in production. + // + // +optional + Kubernetes *KubernetesComponentPluginOverrideParentOverride `json:"kubernetes,omitempty"` + + // Allows importing into the workspace the OpenShift resources + // defined in a given manifest. For example this allows reusing the OpenShift + // definitions used to deploy some runtime components in production. + // + // +optional + Openshift *OpenshiftComponentPluginOverrideParentOverride `json:"openshift,omitempty"` + + // Allows specifying the definition of a volume + // shared by several other components + // +optional + Volume *VolumeComponentPluginOverrideParentOverride `json:"volume,omitempty"` +} + +// +union +type CommandUnionPluginOverrideParentOverride struct { + + // +kubebuilder:validation:Enum=Exec;Apply;VscodeTask;VscodeLaunch;Composite + // Type of workspace command + // +unionDiscriminator + // +optional + CommandType CommandTypePluginOverrideParentOverride `json:"commandType,omitempty"` + + // CLI Command executed in an existing component container + // +optional + Exec *ExecCommandPluginOverrideParentOverride `json:"exec,omitempty"` + + // Command that consists in applying a given component definition, + // typically bound to a workspace event. + // + // For example, when an `apply` command is bound to a `preStart` event, + // and references a `container` component, it will start the container as a + // K8S initContainer in the workspace POD, unless the component has its + // `dedicatedPod` field set to `true`. + // + // When no `apply` command exist for a given component, + // it is assumed the component will be applied at workspace start + // by default. + // +optional + Apply *ApplyCommandPluginOverrideParentOverride `json:"apply,omitempty"` + + // Command providing the definition of a VsCode Task + // +optional + VscodeTask *VscodeConfigurationCommandPluginOverrideParentOverride `json:"vscodeTask,omitempty"` + + // Command providing the definition of a VsCode launch action + // +optional + VscodeLaunch *VscodeConfigurationCommandPluginOverrideParentOverride `json:"vscodeLaunch,omitempty"` + + // Composite command that allows executing several sub-commands + // either sequentially or concurrently + // +optional + Composite *CompositeCommandPluginOverrideParentOverride `json:"composite,omitempty"` +} + +// CommandGroupKind describes the kind of command group. +// +kubebuilder:validation:Enum=build;run;test;debug +type CommandGroupKindParentOverride string + +// ComponentType describes the type of component. +// Only one of the following component type may be specified. +type ComponentTypePluginOverrideParentOverride string + +// Component that allows the developer to add a configured container into his workspace +type ContainerComponentPluginOverrideParentOverride struct { + BaseComponentPluginOverrideParentOverride `json:",inline"` + ContainerPluginOverrideParentOverride `json:",inline"` + Endpoints []EndpointPluginOverrideParentOverride `json:"endpoints,omitempty" patchStrategy:"merge" patchMergeKey:"name"` +} + +// Component that allows partly importing Kubernetes resources into the workspace POD +type KubernetesComponentPluginOverrideParentOverride struct { + K8sLikeComponentPluginOverrideParentOverride `json:",inline"` +} + +// Component that allows partly importing Openshift resources into the workspace POD +type OpenshiftComponentPluginOverrideParentOverride struct { + K8sLikeComponentPluginOverrideParentOverride `json:",inline"` +} + +// Component that allows the developer to declare and configure a volume into his workspace +type VolumeComponentPluginOverrideParentOverride struct { + BaseComponentPluginOverrideParentOverride `json:",inline"` + VolumePluginOverrideParentOverride `json:",inline"` +} + +// CommandType describes the type of command. +// Only one of the following command type may be specified. +type CommandTypePluginOverrideParentOverride string + +type ExecCommandPluginOverrideParentOverride struct { + LabeledCommandPluginOverrideParentOverride `json:",inline"` + + // +optional + // The actual command-line string + // + // Special variables that can be used: + // + // - `$PROJECTS_ROOT`: A path where projects sources are mounted as defined by container component's sourceMapping. + // + // - `$PROJECT_SOURCE`: A path to a project source ($PROJECTS_ROOT/). If there are multiple projects, this will point to the directory of the first one. + CommandLine string `json:"commandLine,omitempty"` + + // +optional + // Describes component to which given action relates + // + Component string `json:"component,omitempty"` + + // Working directory where the command should be executed + // + // Special variables that can be used: + // + // - `$PROJECTS_ROOT`: A path where projects sources are mounted as defined by container component's sourceMapping. + // + // - `$PROJECT_SOURCE`: A path to a project source ($PROJECTS_ROOT/). If there are multiple projects, this will point to the directory of the first one. + // +optional + WorkingDir string `json:"workingDir,omitempty"` + + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + // Optional list of environment variables that have to be set + // before running the command + Env []EnvVarPluginOverrideParentOverride `json:"env,omitempty" patchStrategy:"merge" patchMergeKey:"name"` + + // +optional + // Whether the command is capable to reload itself when source code changes. + // If set to `true` the command won't be restarted and it is expected to handle file changes on its own. + // + // Default value is `false` + HotReloadCapable bool `json:"hotReloadCapable,omitempty"` +} + +type ApplyCommandPluginOverrideParentOverride struct { + LabeledCommandPluginOverrideParentOverride `json:",inline"` + + // +optional + // Describes component that will be applied + // + Component string `json:"component,omitempty"` +} + +type VscodeConfigurationCommandPluginOverrideParentOverride struct { + BaseCommandPluginOverrideParentOverride `json:",inline"` + VscodeConfigurationCommandLocationPluginOverrideParentOverride `json:",inline"` +} + +type CompositeCommandPluginOverrideParentOverride struct { + LabeledCommandPluginOverrideParentOverride `json:",inline"` + + // The commands that comprise this composite command + Commands []string `json:"commands,omitempty" patchStrategy:"replace"` + + // Indicates if the sub-commands should be executed concurrently + // +optional + Parallel bool `json:"parallel,omitempty"` +} + +// Workspace component: Anything that will bring additional features / tooling / behaviour / context +// to the workspace, in order to make working in it easier. +type BaseComponentPluginOverrideParentOverride struct { +} + +type ContainerPluginOverrideParentOverride struct { + + // +optional + Image string `json:"image,omitempty"` + + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + // Environment variables used in this container. + // + // The following variables are reserved and cannot be overridden via env: + // + // - `$PROJECTS_ROOT` + // + // - `$PROJECT_SOURCE` + Env []EnvVarPluginOverrideParentOverride `json:"env,omitempty" patchStrategy:"merge" patchMergeKey:"name"` + + // +optional + // List of volumes mounts that should be mounted is this container. + VolumeMounts []VolumeMountPluginOverrideParentOverride `json:"volumeMounts,omitempty" patchStrategy:"merge" patchMergeKey:"name"` + + // +optional + MemoryLimit string `json:"memoryLimit,omitempty"` + + // The command to run in the dockerimage component instead of the default one provided in the image. + // + // Defaults to an empty array, meaning use whatever is defined in the image. + // +optional + Command []string `json:"command,omitempty" patchStrategy:"replace"` + + // The arguments to supply to the command running the dockerimage component. The arguments are supplied either to the default command provided in the image or to the overridden command. + // + // Defaults to an empty array, meaning use whatever is defined in the image. + // +optional + Args []string `json:"args,omitempty" patchStrategy:"replace"` + + // Toggles whether or not the project source code should + // be mounted in the component. + // + // Defaults to true for all component types except plugins and components that set `dedicatedPod` to true. + // +optional + MountSources *bool `json:"mountSources,omitempty"` + + // Optional specification of the path in the container where + // project sources should be transferred/mounted when `mountSources` is `true`. + // When omitted, the default value of /projects is used. + // +optional + SourceMapping string `json:"sourceMapping,omitempty"` + + // Specify if a container should run in its own separated pod, + // instead of running as part of the main development environment pod. + // + // Default value is `false` + // +optional + DedicatedPod bool `json:"dedicatedPod,omitempty"` +} + +type EndpointPluginOverrideParentOverride struct { + Name string `json:"name"` + + // +optional + TargetPort int `json:"targetPort,omitempty"` + + // Describes how the endpoint should be exposed on the network. + // + // - `public` means that the endpoint will be exposed on the public network, typically through + // a K8S ingress or an OpenShift route. + // + // - `internal` means that the endpoint will be exposed internally outside of the main workspace POD, + // typically by K8S services, to be consumed by other elements running + // on the same cloud internal network. + // + // - `none` means that the endpoint will not be exposed and will only be accessible + // inside the main workspace POD, on a local address. + // + // Default value is `public` + // +optional + Exposure EndpointExposurePluginOverrideParentOverride `json:"exposure,omitempty"` + + // Describes the application and transport protocols of the traffic that will go through this endpoint. + // + // - `http`: Endpoint will have `http` traffic, typically on a TCP connection. + // It will be automaticaly promoted to `https` when the `secure` field is set to `true`. + // + // - `https`: Endpoint will have `https` traffic, typically on a TCP connection. + // + // - `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. + // It will be automaticaly promoted to `wss` when the `secure` field is set to `true`. + // + // - `wss`: Endpoint will have `wss` traffic, typically on a TCP connection. + // + // - `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol. + // + // - `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol. + // + // Default value is `http` + // +optional + Protocol EndpointProtocolPluginOverrideParentOverride `json:"protocol,omitempty"` + + // Describes whether the endpoint should be secured and protected by some + // authentication process + // +optional + Secure bool `json:"secure,omitempty"` + + // Path of the endpoint URL + // +optional + Path string `json:"path,omitempty"` + + // Map of implementation-dependant string-based free-form attributes. + // + // Examples of Che-specific attributes: + // + // - cookiesAuthEnabled: "true" / "false", + // + // - type: "terminal" / "ide" / "ide-dev", + // +optional + Attributes map[string]string `json:"attributes,omitempty"` +} + +type K8sLikeComponentPluginOverrideParentOverride struct { + BaseComponentPluginOverrideParentOverride `json:",inline"` + K8sLikeComponentLocationPluginOverrideParentOverride `json:",inline"` + Endpoints []EndpointPluginOverrideParentOverride `json:"endpoints,omitempty" patchStrategy:"merge" patchMergeKey:"name"` +} + +// Volume that should be mounted to a component container +type VolumePluginOverrideParentOverride struct { + + // +optional + // Size of the volume + Size string `json:"size,omitempty"` +} + +type LabeledCommandPluginOverrideParentOverride struct { + BaseCommandPluginOverrideParentOverride `json:",inline"` + + // +optional + // Optional label that provides a label for this command + // to be used in Editor UI menus for example + Label string `json:"label,omitempty"` +} + +type EnvVarPluginOverrideParentOverride struct { + Name string `json:"name" yaml:"name"` + + // +optional + Value string `json:"value,omitempty" yaml:"value"` +} + +type BaseCommandPluginOverrideParentOverride struct { + + // +optional + // Defines the group this command is part of + Group *CommandGroupPluginOverrideParentOverride `json:"group,omitempty"` + + // Optional map of free-form additional command attributes + Attributes map[string]string `json:"attributes,omitempty"` +} + +// +union +type VscodeConfigurationCommandLocationPluginOverrideParentOverride struct { + + // +kubebuilder:validation:Enum=Uri;Inlined + // Type of Vscode configuration command location + // + + // +unionDiscriminator + // +optional + LocationType VscodeConfigurationCommandLocationTypePluginOverrideParentOverride `json:"locationType,omitempty"` + + // Location as an absolute of relative URI + // the VsCode configuration will be fetched from + // +optional + Uri string `json:"uri,omitempty"` + + // Inlined content of the VsCode configuration + // +optional + Inlined string `json:"inlined,omitempty"` +} + +// Volume that should be mounted to a component container +type VolumeMountPluginOverrideParentOverride struct { + + // The volume mount name is the name of an existing `Volume` component. + // If several containers mount the same volume name + // then they will reuse the same volume and will be able to access to the same files. + Name string `json:"name"` + + // The path in the component container where the volume should be mounted. + // If not path is mentioned, default path is the is `/`. + // +optional + Path string `json:"path,omitempty"` +} + +// EndpointExposure describes the way an endpoint is exposed on the network. +// Only one of the following exposures may be specified: public, internal, none. +// +kubebuilder:validation:Enum=public;internal;none +type EndpointExposurePluginOverrideParentOverride string + +// EndpointProtocol defines the application and transport protocols of the traffic that will go through this endpoint. +// Only one of the following protocols may be specified: http, ws, tcp, udp. +// +kubebuilder:validation:Enum=http;ws;tcp;udp +type EndpointProtocolPluginOverrideParentOverride string + +// +union +type K8sLikeComponentLocationPluginOverrideParentOverride struct { + + // +kubebuilder:validation:Enum=Uri;Inlined + // Type of Kubernetes-like location + // + + // +unionDiscriminator + // +optional + LocationType K8sLikeComponentLocationTypePluginOverrideParentOverride `json:"locationType,omitempty"` + + // Location in a file fetched from a uri. + // +optional + Uri string `json:"uri,omitempty"` + + // Inlined manifest + // +optional + Inlined string `json:"inlined,omitempty"` +} + +type CommandGroupPluginOverrideParentOverride struct { + + // +optional + // Kind of group the command is part of + Kind CommandGroupKindPluginOverrideParentOverride `json:"kind,omitempty"` + + // +optional + // Identifies the default command for a given group kind + IsDefault bool `json:"isDefault,omitempty"` +} + +// VscodeConfigurationCommandLocationType describes the type of +// the location the configuration is fetched from. +// Only one of the following component type may be specified. +type VscodeConfigurationCommandLocationTypePluginOverrideParentOverride string + +// K8sLikeComponentLocationType describes the type of +// the location the configuration is fetched from. +// Only one of the following component type may be specified. +type K8sLikeComponentLocationTypePluginOverrideParentOverride string + +// CommandGroupKind describes the kind of command group. +// +kubebuilder:validation:Enum=build;run;test;debug +type CommandGroupKindPluginOverrideParentOverride string + +func (overrides ParentOverrides) isOverride() {} diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/zz_generated.plugin_overrides.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/zz_generated.plugin_overrides.go new file mode 100644 index 000000000..d0c5f5b2a --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/zz_generated.plugin_overrides.go @@ -0,0 +1,467 @@ +package v1alpha2 + +// +devfile:jsonschema:generate +type PluginOverrides struct { + OverridesBase `json:",inline"` + + // Overrides of components encapsulated in a parent devfile or a plugin. + // Overriding is done according to K8S strategic merge patch standard rules. + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + // +devfile:toplevellist + Components []ComponentPluginOverride `json:"components,omitempty" patchStrategy:"merge" patchMergeKey:"name"` + + // Overrides of commands encapsulated in a parent devfile or a plugin. + // Overriding is done according to K8S strategic merge patch standard rules. + // +optional + // +patchMergeKey=id + // +patchStrategy=merge + // +devfile:toplevellist + Commands []CommandPluginOverride `json:"commands,omitempty" patchStrategy:"merge" patchMergeKey:"id"` +} + +//+k8s:openapi-gen=true +type ComponentPluginOverride struct { + + // Mandatory name that allows referencing the component + // from other elements (such as commands) or from an external + // devfile that may reference this component through a parent or a plugin. + Name string `json:"name"` + ComponentUnionPluginOverride `json:",inline"` +} + +type CommandPluginOverride struct { + + // Mandatory identifier that allows referencing + // this command in composite commands, from + // a parent, or in events. + Id string `json:"id"` + CommandUnionPluginOverride `json:",inline"` +} + +// +union +type ComponentUnionPluginOverride struct { + + // +kubebuilder:validation:Enum=Container;Kubernetes;Openshift;Volume + // Type of component + // + // +unionDiscriminator + // +optional + ComponentType ComponentTypePluginOverride `json:"componentType,omitempty"` + + // Allows adding and configuring workspace-related containers + // +optional + Container *ContainerComponentPluginOverride `json:"container,omitempty"` + + // Allows importing into the workspace the Kubernetes resources + // defined in a given manifest. For example this allows reusing the Kubernetes + // definitions used to deploy some runtime components in production. + // + // +optional + Kubernetes *KubernetesComponentPluginOverride `json:"kubernetes,omitempty"` + + // Allows importing into the workspace the OpenShift resources + // defined in a given manifest. For example this allows reusing the OpenShift + // definitions used to deploy some runtime components in production. + // + // +optional + Openshift *OpenshiftComponentPluginOverride `json:"openshift,omitempty"` + + // Allows specifying the definition of a volume + // shared by several other components + // +optional + Volume *VolumeComponentPluginOverride `json:"volume,omitempty"` +} + +// +union +type CommandUnionPluginOverride struct { + + // +kubebuilder:validation:Enum=Exec;Apply;VscodeTask;VscodeLaunch;Composite + // Type of workspace command + // +unionDiscriminator + // +optional + CommandType CommandTypePluginOverride `json:"commandType,omitempty"` + + // CLI Command executed in an existing component container + // +optional + Exec *ExecCommandPluginOverride `json:"exec,omitempty"` + + // Command that consists in applying a given component definition, + // typically bound to a workspace event. + // + // For example, when an `apply` command is bound to a `preStart` event, + // and references a `container` component, it will start the container as a + // K8S initContainer in the workspace POD, unless the component has its + // `dedicatedPod` field set to `true`. + // + // When no `apply` command exist for a given component, + // it is assumed the component will be applied at workspace start + // by default. + // +optional + Apply *ApplyCommandPluginOverride `json:"apply,omitempty"` + + // Command providing the definition of a VsCode Task + // +optional + VscodeTask *VscodeConfigurationCommandPluginOverride `json:"vscodeTask,omitempty"` + + // Command providing the definition of a VsCode launch action + // +optional + VscodeLaunch *VscodeConfigurationCommandPluginOverride `json:"vscodeLaunch,omitempty"` + + // Composite command that allows executing several sub-commands + // either sequentially or concurrently + // +optional + Composite *CompositeCommandPluginOverride `json:"composite,omitempty"` +} + +// ComponentType describes the type of component. +// Only one of the following component type may be specified. +type ComponentTypePluginOverride string + +// Component that allows the developer to add a configured container into his workspace +type ContainerComponentPluginOverride struct { + BaseComponentPluginOverride `json:",inline"` + ContainerPluginOverride `json:",inline"` + Endpoints []EndpointPluginOverride `json:"endpoints,omitempty" patchStrategy:"merge" patchMergeKey:"name"` +} + +// Component that allows partly importing Kubernetes resources into the workspace POD +type KubernetesComponentPluginOverride struct { + K8sLikeComponentPluginOverride `json:",inline"` +} + +// Component that allows partly importing Openshift resources into the workspace POD +type OpenshiftComponentPluginOverride struct { + K8sLikeComponentPluginOverride `json:",inline"` +} + +// Component that allows the developer to declare and configure a volume into his workspace +type VolumeComponentPluginOverride struct { + BaseComponentPluginOverride `json:",inline"` + VolumePluginOverride `json:",inline"` +} + +// CommandType describes the type of command. +// Only one of the following command type may be specified. +type CommandTypePluginOverride string + +type ExecCommandPluginOverride struct { + LabeledCommandPluginOverride `json:",inline"` + + // +optional + // The actual command-line string + // + // Special variables that can be used: + // + // - `$PROJECTS_ROOT`: A path where projects sources are mounted as defined by container component's sourceMapping. + // + // - `$PROJECT_SOURCE`: A path to a project source ($PROJECTS_ROOT/). If there are multiple projects, this will point to the directory of the first one. + CommandLine string `json:"commandLine,omitempty"` + + // +optional + // Describes component to which given action relates + // + Component string `json:"component,omitempty"` + + // Working directory where the command should be executed + // + // Special variables that can be used: + // + // - `$PROJECTS_ROOT`: A path where projects sources are mounted as defined by container component's sourceMapping. + // + // - `$PROJECT_SOURCE`: A path to a project source ($PROJECTS_ROOT/). If there are multiple projects, this will point to the directory of the first one. + // +optional + WorkingDir string `json:"workingDir,omitempty"` + + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + // Optional list of environment variables that have to be set + // before running the command + Env []EnvVarPluginOverride `json:"env,omitempty" patchStrategy:"merge" patchMergeKey:"name"` + + // +optional + // Whether the command is capable to reload itself when source code changes. + // If set to `true` the command won't be restarted and it is expected to handle file changes on its own. + // + // Default value is `false` + HotReloadCapable bool `json:"hotReloadCapable,omitempty"` +} + +type ApplyCommandPluginOverride struct { + LabeledCommandPluginOverride `json:",inline"` + + // +optional + // Describes component that will be applied + // + Component string `json:"component,omitempty"` +} + +type VscodeConfigurationCommandPluginOverride struct { + BaseCommandPluginOverride `json:",inline"` + VscodeConfigurationCommandLocationPluginOverride `json:",inline"` +} + +type CompositeCommandPluginOverride struct { + LabeledCommandPluginOverride `json:",inline"` + + // The commands that comprise this composite command + Commands []string `json:"commands,omitempty" patchStrategy:"replace"` + + // Indicates if the sub-commands should be executed concurrently + // +optional + Parallel bool `json:"parallel,omitempty"` +} + +// Workspace component: Anything that will bring additional features / tooling / behaviour / context +// to the workspace, in order to make working in it easier. +type BaseComponentPluginOverride struct { +} + +type ContainerPluginOverride struct { + // +optional + Image string `json:"image,omitempty"` + + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + // Environment variables used in this container. + // + // The following variables are reserved and cannot be overridden via env: + // + // - `$PROJECTS_ROOT` + // + // - `$PROJECT_SOURCE` + Env []EnvVarPluginOverride `json:"env,omitempty" patchStrategy:"merge" patchMergeKey:"name"` + + // +optional + // List of volumes mounts that should be mounted is this container. + VolumeMounts []VolumeMountPluginOverride `json:"volumeMounts,omitempty" patchStrategy:"merge" patchMergeKey:"name"` + + // +optional + MemoryLimit string `json:"memoryLimit,omitempty"` + + // The command to run in the dockerimage component instead of the default one provided in the image. + // + // Defaults to an empty array, meaning use whatever is defined in the image. + // +optional + Command []string `json:"command,omitempty" patchStrategy:"replace"` + + // The arguments to supply to the command running the dockerimage component. The arguments are supplied either to the default command provided in the image or to the overridden command. + // + // Defaults to an empty array, meaning use whatever is defined in the image. + // +optional + Args []string `json:"args,omitempty" patchStrategy:"replace"` + + // Toggles whether or not the project source code should + // be mounted in the component. + // + // Defaults to true for all component types except plugins and components that set `dedicatedPod` to true. + // +optional + MountSources *bool `json:"mountSources,omitempty"` + + // Optional specification of the path in the container where + // project sources should be transferred/mounted when `mountSources` is `true`. + // When omitted, the default value of /projects is used. + // +optional + SourceMapping string `json:"sourceMapping,omitempty"` + + // Specify if a container should run in its own separated pod, + // instead of running as part of the main development environment pod. + // + // Default value is `false` + // +optional + DedicatedPod bool `json:"dedicatedPod,omitempty"` +} + +type EndpointPluginOverride struct { + Name string `json:"name"` + + // +optional + TargetPort int `json:"targetPort,omitempty"` + + // Describes how the endpoint should be exposed on the network. + // + // - `public` means that the endpoint will be exposed on the public network, typically through + // a K8S ingress or an OpenShift route. + // + // - `internal` means that the endpoint will be exposed internally outside of the main workspace POD, + // typically by K8S services, to be consumed by other elements running + // on the same cloud internal network. + // + // - `none` means that the endpoint will not be exposed and will only be accessible + // inside the main workspace POD, on a local address. + // + // Default value is `public` + // +optional + Exposure EndpointExposurePluginOverride `json:"exposure,omitempty"` + + // Describes the application and transport protocols of the traffic that will go through this endpoint. + // + // - `http`: Endpoint will have `http` traffic, typically on a TCP connection. + // It will be automaticaly promoted to `https` when the `secure` field is set to `true`. + // + // - `https`: Endpoint will have `https` traffic, typically on a TCP connection. + // + // - `ws`: Endpoint will have `ws` traffic, typically on a TCP connection. + // It will be automaticaly promoted to `wss` when the `secure` field is set to `true`. + // + // - `wss`: Endpoint will have `wss` traffic, typically on a TCP connection. + // + // - `tcp`: Endpoint will have traffic on a TCP connection, without specifying an application protocol. + // + // - `udp`: Endpoint will have traffic on an UDP connection, without specifying an application protocol. + // + // Default value is `http` + // +optional + Protocol EndpointProtocolPluginOverride `json:"protocol,omitempty"` + + // Describes whether the endpoint should be secured and protected by some + // authentication process + // +optional + Secure bool `json:"secure,omitempty"` + + // Path of the endpoint URL + // +optional + Path string `json:"path,omitempty"` + + // Map of implementation-dependant string-based free-form attributes. + // + // Examples of Che-specific attributes: + // + // - cookiesAuthEnabled: "true" / "false", + // + // - type: "terminal" / "ide" / "ide-dev", + // +optional + Attributes map[string]string `json:"attributes,omitempty"` +} + +type K8sLikeComponentPluginOverride struct { + BaseComponentPluginOverride `json:",inline"` + K8sLikeComponentLocationPluginOverride `json:",inline"` + Endpoints []EndpointPluginOverride `json:"endpoints,omitempty" patchStrategy:"merge" patchMergeKey:"name"` +} + +// Volume that should be mounted to a component container +type VolumePluginOverride struct { + + // +optional + // Size of the volume + Size string `json:"size,omitempty"` +} + +type LabeledCommandPluginOverride struct { + BaseCommandPluginOverride `json:",inline"` + + // +optional + // Optional label that provides a label for this command + // to be used in Editor UI menus for example + Label string `json:"label,omitempty"` +} + +type EnvVarPluginOverride struct { + Name string `json:"name" yaml:"name"` + // +optional + Value string `json:"value,omitempty" yaml:"value"` +} + +type BaseCommandPluginOverride struct { + + // +optional + // Defines the group this command is part of + Group *CommandGroupPluginOverride `json:"group,omitempty"` + + // Optional map of free-form additional command attributes + Attributes map[string]string `json:"attributes,omitempty"` +} + +// +union +type VscodeConfigurationCommandLocationPluginOverride struct { + + // +kubebuilder:validation:Enum=Uri;Inlined + // Type of Vscode configuration command location + // + + // +unionDiscriminator + // +optional + LocationType VscodeConfigurationCommandLocationTypePluginOverride `json:"locationType,omitempty"` + + // Location as an absolute of relative URI + // the VsCode configuration will be fetched from + // +optional + Uri string `json:"uri,omitempty"` + + // Inlined content of the VsCode configuration + // +optional + Inlined string `json:"inlined,omitempty"` +} + +// Volume that should be mounted to a component container +type VolumeMountPluginOverride struct { + + // The volume mount name is the name of an existing `Volume` component. + // If several containers mount the same volume name + // then they will reuse the same volume and will be able to access to the same files. + Name string `json:"name"` + + // The path in the component container where the volume should be mounted. + // If not path is mentioned, default path is the is `/`. + // +optional + Path string `json:"path,omitempty"` +} + +// EndpointExposure describes the way an endpoint is exposed on the network. +// Only one of the following exposures may be specified: public, internal, none. +// +kubebuilder:validation:Enum=public;internal;none +type EndpointExposurePluginOverride string + +// EndpointProtocol defines the application and transport protocols of the traffic that will go through this endpoint. +// Only one of the following protocols may be specified: http, ws, tcp, udp. +// +kubebuilder:validation:Enum=http;ws;tcp;udp +type EndpointProtocolPluginOverride string + +// +union +type K8sLikeComponentLocationPluginOverride struct { + + // +kubebuilder:validation:Enum=Uri;Inlined + // Type of Kubernetes-like location + // + + // +unionDiscriminator + // +optional + LocationType K8sLikeComponentLocationTypePluginOverride `json:"locationType,omitempty"` + + // Location in a file fetched from a uri. + // +optional + Uri string `json:"uri,omitempty"` + + // Inlined manifest + // +optional + Inlined string `json:"inlined,omitempty"` +} + +type CommandGroupPluginOverride struct { + + // +optional + // Kind of group the command is part of + Kind CommandGroupKindPluginOverride `json:"kind,omitempty"` + + // +optional + // Identifies the default command for a given group kind + IsDefault bool `json:"isDefault,omitempty"` +} + +// VscodeConfigurationCommandLocationType describes the type of +// the location the configuration is fetched from. +// Only one of the following component type may be specified. +type VscodeConfigurationCommandLocationTypePluginOverride string + +// K8sLikeComponentLocationType describes the type of +// the location the configuration is fetched from. +// Only one of the following component type may be specified. +type K8sLikeComponentLocationTypePluginOverride string + +// CommandGroupKind describes the kind of command group. +// +kubebuilder:validation:Enum=build;run;test;debug +type CommandGroupKindPluginOverride string + +func (overrides PluginOverrides) isOverride() {} diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/zz_generated.toplevellistcontainer_definitions.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/zz_generated.toplevellistcontainer_definitions.go new file mode 100644 index 000000000..45be709ff --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/zz_generated.toplevellistcontainer_definitions.go @@ -0,0 +1,33 @@ +package v1alpha2 + +func (container DevWorkspaceTemplateSpecContent) GetToplevelLists() TopLevelLists { + return TopLevelLists{ + "Components": extractKeys(container.Components), + "Projects": extractKeys(container.Projects), + "StarterProjects": extractKeys(container.StarterProjects), + "Commands": extractKeys(container.Commands), + } +} + +func (container ParentOverrides) GetToplevelLists() TopLevelLists { + return TopLevelLists{ + "Components": extractKeys(container.Components), + "Projects": extractKeys(container.Projects), + "StarterProjects": extractKeys(container.StarterProjects), + "Commands": extractKeys(container.Commands), + } +} + +func (container PluginOverridesParentOverride) GetToplevelLists() TopLevelLists { + return TopLevelLists{ + "Components": extractKeys(container.Components), + "Commands": extractKeys(container.Commands), + } +} + +func (container PluginOverrides) GetToplevelLists() TopLevelLists { + return TopLevelLists{ + "Components": extractKeys(container.Components), + "Commands": extractKeys(container.Commands), + } +} diff --git a/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/zz_generated.union_definitions.go b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/zz_generated.union_definitions.go new file mode 100644 index 000000000..406ca523f --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/apis/workspaces/v1alpha2/zz_generated.union_definitions.go @@ -0,0 +1,454 @@ +package v1alpha2 + +import ( + "reflect" +) + +var commandUnion reflect.Type = reflect.TypeOf(CommandUnionVisitor{}) + +func (union CommandUnion) Visit(visitor CommandUnionVisitor) error { + return visitUnion(union, visitor) +} +func (union *CommandUnion) discriminator() *string { + return (*string)(&union.CommandType) +} +func (union *CommandUnion) Normalize() error { + return normalizeUnion(union, commandUnion) +} +func (union *CommandUnion) Simplify() { + simplifyUnion(union, commandUnion) +} + +// +k8s:deepcopy-gen=false +type CommandUnionVisitor struct { + Exec func(*ExecCommand) error + Apply func(*ApplyCommand) error + VscodeTask func(*VscodeConfigurationCommand) error + VscodeLaunch func(*VscodeConfigurationCommand) error + Composite func(*CompositeCommand) error + Custom func(*CustomCommand) error +} + +var vscodeConfigurationCommandLocation reflect.Type = reflect.TypeOf(VscodeConfigurationCommandLocationVisitor{}) + +func (union VscodeConfigurationCommandLocation) Visit(visitor VscodeConfigurationCommandLocationVisitor) error { + return visitUnion(union, visitor) +} +func (union *VscodeConfigurationCommandLocation) discriminator() *string { + return (*string)(&union.LocationType) +} +func (union *VscodeConfigurationCommandLocation) Normalize() error { + return normalizeUnion(union, vscodeConfigurationCommandLocation) +} +func (union *VscodeConfigurationCommandLocation) Simplify() { + simplifyUnion(union, vscodeConfigurationCommandLocation) +} + +// +k8s:deepcopy-gen=false +type VscodeConfigurationCommandLocationVisitor struct { + Uri func(string) error + Inlined func(string) error +} + +var componentUnion reflect.Type = reflect.TypeOf(ComponentUnionVisitor{}) + +func (union ComponentUnion) Visit(visitor ComponentUnionVisitor) error { + return visitUnion(union, visitor) +} +func (union *ComponentUnion) discriminator() *string { + return (*string)(&union.ComponentType) +} +func (union *ComponentUnion) Normalize() error { + return normalizeUnion(union, componentUnion) +} +func (union *ComponentUnion) Simplify() { + simplifyUnion(union, componentUnion) +} + +// +k8s:deepcopy-gen=false +type ComponentUnionVisitor struct { + Container func(*ContainerComponent) error + Kubernetes func(*KubernetesComponent) error + Openshift func(*OpenshiftComponent) error + Volume func(*VolumeComponent) error + Plugin func(*PluginComponent) error + Custom func(*CustomComponent) error +} + +var importReferenceUnion reflect.Type = reflect.TypeOf(ImportReferenceUnionVisitor{}) + +func (union ImportReferenceUnion) Visit(visitor ImportReferenceUnionVisitor) error { + return visitUnion(union, visitor) +} +func (union *ImportReferenceUnion) discriminator() *string { + return (*string)(&union.ImportReferenceType) +} +func (union *ImportReferenceUnion) Normalize() error { + return normalizeUnion(union, importReferenceUnion) +} +func (union *ImportReferenceUnion) Simplify() { + simplifyUnion(union, importReferenceUnion) +} + +// +k8s:deepcopy-gen=false +type ImportReferenceUnionVisitor struct { + Uri func(string) error + Id func(string) error + Kubernetes func(*KubernetesCustomResourceImportReference) error +} + +var k8sLikeComponentLocation reflect.Type = reflect.TypeOf(K8sLikeComponentLocationVisitor{}) + +func (union K8sLikeComponentLocation) Visit(visitor K8sLikeComponentLocationVisitor) error { + return visitUnion(union, visitor) +} +func (union *K8sLikeComponentLocation) discriminator() *string { + return (*string)(&union.LocationType) +} +func (union *K8sLikeComponentLocation) Normalize() error { + return normalizeUnion(union, k8sLikeComponentLocation) +} +func (union *K8sLikeComponentLocation) Simplify() { + simplifyUnion(union, k8sLikeComponentLocation) +} + +// +k8s:deepcopy-gen=false +type K8sLikeComponentLocationVisitor struct { + Uri func(string) error + Inlined func(string) error +} + +var projectSource reflect.Type = reflect.TypeOf(ProjectSourceVisitor{}) + +func (union ProjectSource) Visit(visitor ProjectSourceVisitor) error { + return visitUnion(union, visitor) +} +func (union *ProjectSource) discriminator() *string { + return (*string)(&union.SourceType) +} +func (union *ProjectSource) Normalize() error { + return normalizeUnion(union, projectSource) +} +func (union *ProjectSource) Simplify() { + simplifyUnion(union, projectSource) +} + +// +k8s:deepcopy-gen=false +type ProjectSourceVisitor struct { + Git func(*GitProjectSource) error + Github func(*GithubProjectSource) error + Zip func(*ZipProjectSource) error + Custom func(*CustomProjectSource) error +} + +var componentUnionParentOverride reflect.Type = reflect.TypeOf(ComponentUnionParentOverrideVisitor{}) + +func (union ComponentUnionParentOverride) Visit(visitor ComponentUnionParentOverrideVisitor) error { + return visitUnion(union, visitor) +} +func (union *ComponentUnionParentOverride) discriminator() *string { + return (*string)(&union.ComponentType) +} +func (union *ComponentUnionParentOverride) Normalize() error { + return normalizeUnion(union, componentUnionParentOverride) +} +func (union *ComponentUnionParentOverride) Simplify() { + simplifyUnion(union, componentUnionParentOverride) +} + +// +k8s:deepcopy-gen=false +type ComponentUnionParentOverrideVisitor struct { + Container func(*ContainerComponentParentOverride) error + Kubernetes func(*KubernetesComponentParentOverride) error + Openshift func(*OpenshiftComponentParentOverride) error + Volume func(*VolumeComponentParentOverride) error + Plugin func(*PluginComponentParentOverride) error +} + +var projectSourceParentOverride reflect.Type = reflect.TypeOf(ProjectSourceParentOverrideVisitor{}) + +func (union ProjectSourceParentOverride) Visit(visitor ProjectSourceParentOverrideVisitor) error { + return visitUnion(union, visitor) +} +func (union *ProjectSourceParentOverride) discriminator() *string { + return (*string)(&union.SourceType) +} +func (union *ProjectSourceParentOverride) Normalize() error { + return normalizeUnion(union, projectSourceParentOverride) +} +func (union *ProjectSourceParentOverride) Simplify() { + simplifyUnion(union, projectSourceParentOverride) +} + +// +k8s:deepcopy-gen=false +type ProjectSourceParentOverrideVisitor struct { + Git func(*GitProjectSourceParentOverride) error + Github func(*GithubProjectSourceParentOverride) error + Zip func(*ZipProjectSourceParentOverride) error +} + +var commandUnionParentOverride reflect.Type = reflect.TypeOf(CommandUnionParentOverrideVisitor{}) + +func (union CommandUnionParentOverride) Visit(visitor CommandUnionParentOverrideVisitor) error { + return visitUnion(union, visitor) +} +func (union *CommandUnionParentOverride) discriminator() *string { + return (*string)(&union.CommandType) +} +func (union *CommandUnionParentOverride) Normalize() error { + return normalizeUnion(union, commandUnionParentOverride) +} +func (union *CommandUnionParentOverride) Simplify() { + simplifyUnion(union, commandUnionParentOverride) +} + +// +k8s:deepcopy-gen=false +type CommandUnionParentOverrideVisitor struct { + Exec func(*ExecCommandParentOverride) error + Apply func(*ApplyCommandParentOverride) error + VscodeTask func(*VscodeConfigurationCommandParentOverride) error + VscodeLaunch func(*VscodeConfigurationCommandParentOverride) error + Composite func(*CompositeCommandParentOverride) error +} + +var vscodeConfigurationCommandLocationParentOverride reflect.Type = reflect.TypeOf(VscodeConfigurationCommandLocationParentOverrideVisitor{}) + +func (union VscodeConfigurationCommandLocationParentOverride) Visit(visitor VscodeConfigurationCommandLocationParentOverrideVisitor) error { + return visitUnion(union, visitor) +} +func (union *VscodeConfigurationCommandLocationParentOverride) discriminator() *string { + return (*string)(&union.LocationType) +} +func (union *VscodeConfigurationCommandLocationParentOverride) Normalize() error { + return normalizeUnion(union, vscodeConfigurationCommandLocationParentOverride) +} +func (union *VscodeConfigurationCommandLocationParentOverride) Simplify() { + simplifyUnion(union, vscodeConfigurationCommandLocationParentOverride) +} + +// +k8s:deepcopy-gen=false +type VscodeConfigurationCommandLocationParentOverrideVisitor struct { + Uri func(string) error + Inlined func(string) error +} + +var k8sLikeComponentLocationParentOverride reflect.Type = reflect.TypeOf(K8sLikeComponentLocationParentOverrideVisitor{}) + +func (union K8sLikeComponentLocationParentOverride) Visit(visitor K8sLikeComponentLocationParentOverrideVisitor) error { + return visitUnion(union, visitor) +} +func (union *K8sLikeComponentLocationParentOverride) discriminator() *string { + return (*string)(&union.LocationType) +} +func (union *K8sLikeComponentLocationParentOverride) Normalize() error { + return normalizeUnion(union, k8sLikeComponentLocationParentOverride) +} +func (union *K8sLikeComponentLocationParentOverride) Simplify() { + simplifyUnion(union, k8sLikeComponentLocationParentOverride) +} + +// +k8s:deepcopy-gen=false +type K8sLikeComponentLocationParentOverrideVisitor struct { + Uri func(string) error + Inlined func(string) error +} + +var importReferenceUnionParentOverride reflect.Type = reflect.TypeOf(ImportReferenceUnionParentOverrideVisitor{}) + +func (union ImportReferenceUnionParentOverride) Visit(visitor ImportReferenceUnionParentOverrideVisitor) error { + return visitUnion(union, visitor) +} +func (union *ImportReferenceUnionParentOverride) discriminator() *string { + return (*string)(&union.ImportReferenceType) +} +func (union *ImportReferenceUnionParentOverride) Normalize() error { + return normalizeUnion(union, importReferenceUnionParentOverride) +} +func (union *ImportReferenceUnionParentOverride) Simplify() { + simplifyUnion(union, importReferenceUnionParentOverride) +} + +// +k8s:deepcopy-gen=false +type ImportReferenceUnionParentOverrideVisitor struct { + Uri func(string) error + Id func(string) error + Kubernetes func(*KubernetesCustomResourceImportReferenceParentOverride) error +} + +var componentUnionPluginOverrideParentOverride reflect.Type = reflect.TypeOf(ComponentUnionPluginOverrideParentOverrideVisitor{}) + +func (union ComponentUnionPluginOverrideParentOverride) Visit(visitor ComponentUnionPluginOverrideParentOverrideVisitor) error { + return visitUnion(union, visitor) +} +func (union *ComponentUnionPluginOverrideParentOverride) discriminator() *string { + return (*string)(&union.ComponentType) +} +func (union *ComponentUnionPluginOverrideParentOverride) Normalize() error { + return normalizeUnion(union, componentUnionPluginOverrideParentOverride) +} +func (union *ComponentUnionPluginOverrideParentOverride) Simplify() { + simplifyUnion(union, componentUnionPluginOverrideParentOverride) +} + +// +k8s:deepcopy-gen=false +type ComponentUnionPluginOverrideParentOverrideVisitor struct { + Container func(*ContainerComponentPluginOverrideParentOverride) error + Kubernetes func(*KubernetesComponentPluginOverrideParentOverride) error + Openshift func(*OpenshiftComponentPluginOverrideParentOverride) error + Volume func(*VolumeComponentPluginOverrideParentOverride) error +} + +var commandUnionPluginOverrideParentOverride reflect.Type = reflect.TypeOf(CommandUnionPluginOverrideParentOverrideVisitor{}) + +func (union CommandUnionPluginOverrideParentOverride) Visit(visitor CommandUnionPluginOverrideParentOverrideVisitor) error { + return visitUnion(union, visitor) +} +func (union *CommandUnionPluginOverrideParentOverride) discriminator() *string { + return (*string)(&union.CommandType) +} +func (union *CommandUnionPluginOverrideParentOverride) Normalize() error { + return normalizeUnion(union, commandUnionPluginOverrideParentOverride) +} +func (union *CommandUnionPluginOverrideParentOverride) Simplify() { + simplifyUnion(union, commandUnionPluginOverrideParentOverride) +} + +// +k8s:deepcopy-gen=false +type CommandUnionPluginOverrideParentOverrideVisitor struct { + Exec func(*ExecCommandPluginOverrideParentOverride) error + Apply func(*ApplyCommandPluginOverrideParentOverride) error + VscodeTask func(*VscodeConfigurationCommandPluginOverrideParentOverride) error + VscodeLaunch func(*VscodeConfigurationCommandPluginOverrideParentOverride) error + Composite func(*CompositeCommandPluginOverrideParentOverride) error +} + +var vscodeConfigurationCommandLocationPluginOverrideParentOverride reflect.Type = reflect.TypeOf(VscodeConfigurationCommandLocationPluginOverrideParentOverrideVisitor{}) + +func (union VscodeConfigurationCommandLocationPluginOverrideParentOverride) Visit(visitor VscodeConfigurationCommandLocationPluginOverrideParentOverrideVisitor) error { + return visitUnion(union, visitor) +} +func (union *VscodeConfigurationCommandLocationPluginOverrideParentOverride) discriminator() *string { + return (*string)(&union.LocationType) +} +func (union *VscodeConfigurationCommandLocationPluginOverrideParentOverride) Normalize() error { + return normalizeUnion(union, vscodeConfigurationCommandLocationPluginOverrideParentOverride) +} +func (union *VscodeConfigurationCommandLocationPluginOverrideParentOverride) Simplify() { + simplifyUnion(union, vscodeConfigurationCommandLocationPluginOverrideParentOverride) +} + +// +k8s:deepcopy-gen=false +type VscodeConfigurationCommandLocationPluginOverrideParentOverrideVisitor struct { + Uri func(string) error + Inlined func(string) error +} + +var k8sLikeComponentLocationPluginOverrideParentOverride reflect.Type = reflect.TypeOf(K8sLikeComponentLocationPluginOverrideParentOverrideVisitor{}) + +func (union K8sLikeComponentLocationPluginOverrideParentOverride) Visit(visitor K8sLikeComponentLocationPluginOverrideParentOverrideVisitor) error { + return visitUnion(union, visitor) +} +func (union *K8sLikeComponentLocationPluginOverrideParentOverride) discriminator() *string { + return (*string)(&union.LocationType) +} +func (union *K8sLikeComponentLocationPluginOverrideParentOverride) Normalize() error { + return normalizeUnion(union, k8sLikeComponentLocationPluginOverrideParentOverride) +} +func (union *K8sLikeComponentLocationPluginOverrideParentOverride) Simplify() { + simplifyUnion(union, k8sLikeComponentLocationPluginOverrideParentOverride) +} + +// +k8s:deepcopy-gen=false +type K8sLikeComponentLocationPluginOverrideParentOverrideVisitor struct { + Uri func(string) error + Inlined func(string) error +} + +var componentUnionPluginOverride reflect.Type = reflect.TypeOf(ComponentUnionPluginOverrideVisitor{}) + +func (union ComponentUnionPluginOverride) Visit(visitor ComponentUnionPluginOverrideVisitor) error { + return visitUnion(union, visitor) +} +func (union *ComponentUnionPluginOverride) discriminator() *string { + return (*string)(&union.ComponentType) +} +func (union *ComponentUnionPluginOverride) Normalize() error { + return normalizeUnion(union, componentUnionPluginOverride) +} +func (union *ComponentUnionPluginOverride) Simplify() { + simplifyUnion(union, componentUnionPluginOverride) +} + +// +k8s:deepcopy-gen=false +type ComponentUnionPluginOverrideVisitor struct { + Container func(*ContainerComponentPluginOverride) error + Kubernetes func(*KubernetesComponentPluginOverride) error + Openshift func(*OpenshiftComponentPluginOverride) error + Volume func(*VolumeComponentPluginOverride) error +} + +var commandUnionPluginOverride reflect.Type = reflect.TypeOf(CommandUnionPluginOverrideVisitor{}) + +func (union CommandUnionPluginOverride) Visit(visitor CommandUnionPluginOverrideVisitor) error { + return visitUnion(union, visitor) +} +func (union *CommandUnionPluginOverride) discriminator() *string { + return (*string)(&union.CommandType) +} +func (union *CommandUnionPluginOverride) Normalize() error { + return normalizeUnion(union, commandUnionPluginOverride) +} +func (union *CommandUnionPluginOverride) Simplify() { + simplifyUnion(union, commandUnionPluginOverride) +} + +// +k8s:deepcopy-gen=false +type CommandUnionPluginOverrideVisitor struct { + Exec func(*ExecCommandPluginOverride) error + Apply func(*ApplyCommandPluginOverride) error + VscodeTask func(*VscodeConfigurationCommandPluginOverride) error + VscodeLaunch func(*VscodeConfigurationCommandPluginOverride) error + Composite func(*CompositeCommandPluginOverride) error +} + +var vscodeConfigurationCommandLocationPluginOverride reflect.Type = reflect.TypeOf(VscodeConfigurationCommandLocationPluginOverrideVisitor{}) + +func (union VscodeConfigurationCommandLocationPluginOverride) Visit(visitor VscodeConfigurationCommandLocationPluginOverrideVisitor) error { + return visitUnion(union, visitor) +} +func (union *VscodeConfigurationCommandLocationPluginOverride) discriminator() *string { + return (*string)(&union.LocationType) +} +func (union *VscodeConfigurationCommandLocationPluginOverride) Normalize() error { + return normalizeUnion(union, vscodeConfigurationCommandLocationPluginOverride) +} +func (union *VscodeConfigurationCommandLocationPluginOverride) Simplify() { + simplifyUnion(union, vscodeConfigurationCommandLocationPluginOverride) +} + +// +k8s:deepcopy-gen=false +type VscodeConfigurationCommandLocationPluginOverrideVisitor struct { + Uri func(string) error + Inlined func(string) error +} + +var k8sLikeComponentLocationPluginOverride reflect.Type = reflect.TypeOf(K8sLikeComponentLocationPluginOverrideVisitor{}) + +func (union K8sLikeComponentLocationPluginOverride) Visit(visitor K8sLikeComponentLocationPluginOverrideVisitor) error { + return visitUnion(union, visitor) +} +func (union *K8sLikeComponentLocationPluginOverride) discriminator() *string { + return (*string)(&union.LocationType) +} +func (union *K8sLikeComponentLocationPluginOverride) Normalize() error { + return normalizeUnion(union, k8sLikeComponentLocationPluginOverride) +} +func (union *K8sLikeComponentLocationPluginOverride) Simplify() { + simplifyUnion(union, k8sLikeComponentLocationPluginOverride) +} + +// +k8s:deepcopy-gen=false +type K8sLikeComponentLocationPluginOverrideVisitor struct { + Uri func(string) error + Inlined func(string) error +} diff --git a/vendor/github.com/devfile/api/pkg/devfile/header.go b/vendor/github.com/devfile/api/pkg/devfile/header.go new file mode 100644 index 000000000..1b7a458bc --- /dev/null +++ b/vendor/github.com/devfile/api/pkg/devfile/header.go @@ -0,0 +1,25 @@ +package devfile + +// DevfileHeader describes the structure of the devfile-specific top-level fields +// that are not part of the K8S API structures +type DevfileHeader struct { + // Devfile schema version + // +kubebuilder:validation:Pattern=^([2-9])\.([0-9]+)\.([0-9]+)(\-[0-9a-z-]+(\.[0-9a-z-]+)*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$ + SchemaVersion string `json:"schemaVersion"` + + // +kubebuilder:pruning:PreserveUnknownFields + // +optional + // Optional metadata + Metadata DevfileMetadata `json:"metadata,omitempty"` +} + +type DevfileMetadata struct { + // Optional devfile name + // +optional + Name string `json:"name,omitempty"` + + // Optional semver-compatible version + // +optional + // +kubebuilder:validation:Pattern=^([0-9]+)\.([0-9]+)\.([0-9]+)(\-[0-9a-z-]+(\.[0-9a-z-]+)*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$ + Version string `json:"version,omitempty"` +} diff --git a/vendor/github.com/devfile/library/LICENSE b/vendor/github.com/devfile/library/LICENSE new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/vendor/github.com/devfile/library/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/pkg/devfile/parse.go b/vendor/github.com/devfile/library/pkg/devfile/parse.go similarity index 74% rename from pkg/devfile/parse.go rename to vendor/github.com/devfile/library/pkg/devfile/parse.go index dba776f5d..dc732161c 100644 --- a/pkg/devfile/parse.go +++ b/vendor/github.com/devfile/library/pkg/devfile/parse.go @@ -1,13 +1,9 @@ package devfile import ( - "github.com/openshift/odo/pkg/devfile/parser" - "github.com/openshift/odo/pkg/devfile/validate" + "github.com/devfile/library/pkg/devfile/parser" ) -// This is the top level parse code which has validation code specific to odo hence it cannot be kept inside the -// devfile/parser package. That package is supposed to be independent of odo. - // ParseFromURLAndValidate func parses the devfile data from the url // and validates the devfile integrity with the schema // and validates the devfile data. @@ -21,7 +17,7 @@ func ParseFromURLAndValidate(url string) (d parser.DevfileObj, err error) { } // odo specific validation on devfile content - err = validate.ValidateDevfileData(d.Data) + // err = validate.ValidateDevfileData(d.Data) return d, err } @@ -38,7 +34,7 @@ func ParseFromDataAndValidate(data []byte) (d parser.DevfileObj, err error) { } // odo specific validation on devfile content - err = validate.ValidateDevfileData(d.Data) + // err = validate.ValidateDevfileData(d.Data) return d, err } @@ -55,8 +51,8 @@ func ParseAndValidate(path string) (d parser.DevfileObj, err error) { return d, err } - // validate the devfile content - err = validate.ValidateDevfileData(d.Data) + // odo specific validation on devfile content + // err = validate.ValidateDevfileData(d.Data) return d, err } diff --git a/vendor/github.com/devfile/library/pkg/devfile/parser/configurables.go b/vendor/github.com/devfile/library/pkg/devfile/parser/configurables.go new file mode 100644 index 000000000..ffae44729 --- /dev/null +++ b/vendor/github.com/devfile/library/pkg/devfile/parser/configurables.go @@ -0,0 +1,274 @@ +package parser + +import ( + "fmt" + "strconv" + "strings" + + v1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + corev1 "k8s.io/api/core/v1" +) + +const ( + Name = "Name" + Ports = "Ports" + Memory = "Memory" + PortsDescription = "Ports to be opened in all component containers" + MemoryDescription = "The Maximum memory all the component containers can consume" + NameDescription = "The name of the component" +) + +// SetMetadataName set metadata name in a devfile +func (d DevfileObj) SetMetadataName(name string) error { + metadata := d.Data.GetMetadata() + d.Data.SetMetadata(name, metadata.Version) + return d.WriteYamlDevfile() +} + +// AddEnvVars adds environment variables to all the components in a devfile +func (d DevfileObj) AddEnvVars(otherList []v1.EnvVar) error { + components := d.Data.GetComponents() + for _, component := range components { + if component.Container != nil { + component.Container.Env = Merge(component.Container.Env, otherList) + d.Data.UpdateComponent(component) + } + } + return d.WriteYamlDevfile() +} + +// RemoveEnvVars removes the environment variables which have the keys from all the components in a devfile +func (d DevfileObj) RemoveEnvVars(keys []string) (err error) { + components := d.Data.GetComponents() + for _, component := range components { + if component.Container != nil { + component.Container.Env, err = RemoveEnvVarsFromList(component.Container.Env, keys) + if err != nil { + return err + } + d.Data.UpdateComponent(component) + } + } + return d.WriteYamlDevfile() +} + +// SetPorts converts ports to endpoints, adds to a devfile +func (d DevfileObj) SetPorts(ports ...string) error { + components := d.Data.GetComponents() + endpoints, err := portsToEndpoints(ports...) + if err != nil { + return err + } + for _, component := range components { + if component.Container != nil { + component.Container.Endpoints = addEndpoints(component.Container.Endpoints, endpoints) + d.Data.UpdateComponent(component) + } + } + return d.WriteYamlDevfile() +} + +// RemovePorts removes all container endpoints from a devfile +func (d DevfileObj) RemovePorts() error { + components := d.Data.GetComponents() + for _, component := range components { + if component.Container != nil { + component.Container.Endpoints = []v1.Endpoint{} + d.Data.UpdateComponent(component) + } + } + return d.WriteYamlDevfile() +} + +// HasPorts checks if a devfile contains container endpoints +func (d DevfileObj) HasPorts() bool { + components := d.Data.GetComponents() + for _, component := range components { + if component.Container != nil { + if len(component.Container.Endpoints) > 0 { + return true + } + } + } + return false +} + +// SetMemory sets memoryLimit in devfile container +func (d DevfileObj) SetMemory(memory string) error { + components := d.Data.GetComponents() + for _, component := range components { + if component.Container != nil { + component.Container.MemoryLimit = memory + d.Data.UpdateComponent(component) + } + } + return d.WriteYamlDevfile() +} + +// GetMemory gets memoryLimit from devfile container +func (d DevfileObj) GetMemory() string { + components := d.Data.GetComponents() + for _, component := range components { + if component.Container != nil { + if component.Container.MemoryLimit != "" { + return component.Container.MemoryLimit + } + } + + } + return "" +} + +// GetMetadataName gets metadata name from a devfile +func (d DevfileObj) GetMetadataName() string { + return d.Data.GetMetadata().Name +} + +func portsToEndpoints(ports ...string) ([]v1.Endpoint, error) { + var endpoints []v1.Endpoint + conPorts, err := GetContainerPortsFromStrings(ports) + if err != nil { + return nil, err + } + for _, port := range conPorts { + + endpoint := v1.Endpoint{ + Name: fmt.Sprintf("port-%d-%s", port.ContainerPort, strings.ToLower(string(port.Protocol))), + TargetPort: int(port.ContainerPort), + Protocol: v1.EndpointProtocol(strings.ToLower(string(port.Protocol))), + } + endpoints = append(endpoints, endpoint) + } + return endpoints, nil + +} + +func addEndpoints(current []v1.Endpoint, other []v1.Endpoint) []v1.Endpoint { + newList := make([]v1.Endpoint, len(current)) + copy(newList, current) + for _, ep := range other { + present := false + + for _, presentep := range newList { + + protocol := presentep.Protocol + if protocol == "" { + // endpoint protocol default value is http + protocol = "http" + } + // if the target port and protocol match, we add a case where the protocol is not provided and hence we assume that to be "tcp" + if presentep.TargetPort == ep.TargetPort && (ep.Protocol == protocol) { + present = true + break + } + } + if !present { + newList = append(newList, ep) + } + } + + return newList +} + +// GetContainerPortsFromStrings generates ContainerPort values from the array of string port values +// ports is the array containing the string port values +func GetContainerPortsFromStrings(ports []string) ([]corev1.ContainerPort, error) { + var containerPorts []corev1.ContainerPort + for _, port := range ports { + splits := strings.Split(port, "/") + if len(splits) < 1 || len(splits) > 2 { + return nil, fmt.Errorf("unable to parse the port string %s", port) + } + + portNumberI64, err := strconv.ParseInt(splits[0], 10, 32) + if err != nil { + return nil, fmt.Errorf("invalid port number %s", splits[0]) + } + portNumber := int32(portNumberI64) + + var portProto corev1.Protocol + if len(splits) == 2 { + switch strings.ToUpper(splits[1]) { + case "TCP": + portProto = corev1.ProtocolTCP + case "UDP": + portProto = corev1.ProtocolUDP + default: + return nil, fmt.Errorf("invalid port protocol %s", splits[1]) + } + } else { + portProto = corev1.ProtocolTCP + } + + port := corev1.ContainerPort{ + Name: fmt.Sprintf("%d-%s", portNumber, strings.ToLower(string(portProto))), + ContainerPort: portNumber, + Protocol: portProto, + } + containerPorts = append(containerPorts, port) + } + return containerPorts, nil +} + +// RemoveEnvVarsFromList removes the env variables based on the keys provided +// and returns a new EnvVarList +func RemoveEnvVarsFromList(envVarList []v1.EnvVar, keys []string) ([]v1.EnvVar, error) { + // convert the envVarList map to an array to easily search for env var(s) + // to remove from the component + envVarListArray := []string{} + for _, env := range envVarList { + envVarListArray = append(envVarListArray, env.Name) + } + + // now check if the environment variable(s) requested for removal exists in + // the env vars set for the component by odo + for _, key := range keys { + if !InArray(envVarListArray, key) { + return nil, fmt.Errorf("unable to find environment variable %s in the component", key) + } + } + + // finally, let's remove the environment variables(s) requested by the user + newEnvVarList := []v1.EnvVar{} + for _, envVar := range envVarList { + // if the env is in the keys we skip it + if InArray(keys, envVar.Name) { + continue + } + newEnvVarList = append(newEnvVarList, envVar) + } + return newEnvVarList, nil +} + +// Merge merges the other EnvVarlist with keeping last value for duplicate EnvVars +// and returns a new EnvVarList +func Merge(original []v1.EnvVar, other []v1.EnvVar) []v1.EnvVar { + + var dedupNewEvl []v1.EnvVar + newEvl := append(original, other...) + uniqueMap := make(map[string]string) + // last value will be kept in case of duplicate env vars + for _, envVar := range newEvl { + uniqueMap[envVar.Name] = envVar.Value + } + + for key, value := range uniqueMap { + dedupNewEvl = append(dedupNewEvl, v1.EnvVar{ + Name: key, + Value: value, + }) + } + + return dedupNewEvl + +} + +// In checks if the value is in the array +func InArray(arr []string, value string) bool { + for _, item := range arr { + if item == value { + return true + } + } + return false +} diff --git a/pkg/devfile/parser/context/apiVersion.go b/vendor/github.com/devfile/library/pkg/devfile/parser/context/apiVersion.go similarity index 92% rename from pkg/devfile/parser/context/apiVersion.go rename to vendor/github.com/devfile/library/pkg/devfile/parser/context/apiVersion.go index 08ac745d4..425a51577 100644 --- a/pkg/devfile/parser/context/apiVersion.go +++ b/vendor/github.com/devfile/library/pkg/devfile/parser/context/apiVersion.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" - "github.com/openshift/odo/pkg/devfile/parser/data" + "github.com/devfile/library/pkg/devfile/parser/data" "github.com/pkg/errors" "k8s.io/klog" ) @@ -47,7 +47,7 @@ func (d *DevfileCtx) SetDevfileAPIVersion() error { // Successful d.apiVersion = apiVer - klog.V(2).Infof("devfile apiVersion: '%s'", d.apiVersion) + klog.V(4).Infof("devfile apiVersion: '%s'", d.apiVersion) return nil } diff --git a/pkg/devfile/parser/context/content.go b/vendor/github.com/devfile/library/pkg/devfile/parser/context/content.go similarity index 92% rename from pkg/devfile/parser/context/content.go rename to vendor/github.com/devfile/library/pkg/devfile/parser/context/content.go index 22aedc878..e9d817399 100644 --- a/pkg/devfile/parser/context/content.go +++ b/vendor/github.com/devfile/library/pkg/devfile/parser/context/content.go @@ -4,8 +4,7 @@ import ( "bytes" "unicode" - "github.com/openshift/odo/pkg/util" - + "github.com/devfile/library/pkg/util" "github.com/ghodss/yaml" "github.com/pkg/errors" "k8s.io/klog" @@ -31,7 +30,7 @@ func YAMLToJSON(data []byte) ([]byte, error) { } // Successful - klog.V(2).Infof("converted devfile YAML to JSON") + klog.V(4).Infof("converted devfile YAML to JSON") return data, nil } @@ -53,7 +52,7 @@ func (d *DevfileCtx) SetDevfileContent() error { var err error var data []byte if d.url != "" { - data, err = util.DownloadFileInMemory(util.HTTPRequestParams{URL: d.url}) + data, err = util.DownloadFileInMemory(d.url) if err != nil { return errors.Wrap(err, "error getting parent info from url") } diff --git a/pkg/devfile/parser/context/context.go b/vendor/github.com/devfile/library/pkg/devfile/parser/context/context.go similarity index 88% rename from pkg/devfile/parser/context/context.go rename to vendor/github.com/devfile/library/pkg/devfile/parser/context/context.go index 66ba02132..49448eb04 100644 --- a/pkg/devfile/parser/context/context.go +++ b/vendor/github.com/devfile/library/pkg/devfile/parser/context/context.go @@ -3,8 +3,8 @@ package parser import ( "net/url" - "github.com/openshift/odo/pkg/testingutil/filesystem" - "github.com/openshift/odo/pkg/util" + "github.com/devfile/library/pkg/testingutil/filesystem" + "github.com/devfile/library/pkg/util" "k8s.io/klog" ) @@ -30,14 +30,14 @@ type DevfileCtx struct { url string // filesystem for devfile - Fs filesystem.Filesystem + fs filesystem.Filesystem } // NewDevfileCtx returns a new DevfileCtx type object func NewDevfileCtx(path string) DevfileCtx { return DevfileCtx{ relPath: path, - Fs: filesystem.DefaultFs{}, + fs: filesystem.DefaultFs{}, } } @@ -63,10 +63,10 @@ func (d *DevfileCtx) populateDevfile() (err error) { // Populate fills the DevfileCtx struct with relevant context info func (d *DevfileCtx) Populate() (err error) { - err = d.SetAbsPath() - if err != nil { + if err := d.SetAbsPath(); err != nil { return err } + klog.V(4).Infof("absolute devfile path: '%s'", d.absPath) // Read and save devfile content if err := d.SetDevfileContent(); err != nil { @@ -75,18 +75,6 @@ func (d *DevfileCtx) Populate() (err error) { return d.populateDevfile() } -// SetAbsPath sets absolute file path for devfile -func (d *DevfileCtx) SetAbsPath() (err error) { - // Get devfile absolute path - if d.absPath, err = util.GetAbsPath(d.relPath); err != nil { - return err - } - klog.V(2).Infof("absolute devfile path: '%s'", d.absPath) - - return nil - -} - // PopulateFromURL fills the DevfileCtx struct with relevant context info func (d *DevfileCtx) PopulateFromURL() (err error) { @@ -117,3 +105,15 @@ func (d *DevfileCtx) Validate() error { func (d *DevfileCtx) GetAbsPath() string { return d.absPath } + +// SetAbsPath sets absolute file path for devfile +func (d *DevfileCtx) SetAbsPath() (err error) { + // Set devfile absolute path + if d.absPath, err = util.GetAbsPath(d.relPath); err != nil { + return err + } + klog.V(2).Infof("absolute devfile path: '%s'", d.absPath) + + return nil + +} diff --git a/pkg/devfile/parser/context/fake.go b/vendor/github.com/devfile/library/pkg/devfile/parser/context/fakecontext.go similarity index 63% rename from pkg/devfile/parser/context/fake.go rename to vendor/github.com/devfile/library/pkg/devfile/parser/context/fakecontext.go index 5c5b8769a..2db3c1bd8 100644 --- a/pkg/devfile/parser/context/fake.go +++ b/vendor/github.com/devfile/library/pkg/devfile/parser/context/fakecontext.go @@ -1,10 +1,10 @@ package parser -import "github.com/openshift/odo/pkg/testingutil/filesystem" +import "github.com/devfile/library/pkg/testingutil/filesystem" func FakeContext(fs filesystem.Filesystem, absPath string) DevfileCtx { return DevfileCtx{ - Fs: fs, + fs: fs, absPath: absPath, } } diff --git a/pkg/devfile/parser/context/fs.go b/vendor/github.com/devfile/library/pkg/devfile/parser/context/fs.go similarity index 59% rename from pkg/devfile/parser/context/fs.go rename to vendor/github.com/devfile/library/pkg/devfile/parser/context/fs.go index 75a3eb58d..d3992483a 100644 --- a/pkg/devfile/parser/context/fs.go +++ b/vendor/github.com/devfile/library/pkg/devfile/parser/context/fs.go @@ -1,8 +1,8 @@ package parser -import "github.com/openshift/odo/pkg/testingutil/filesystem" +import "github.com/devfile/library/pkg/testingutil/filesystem" // GetFs returns the filesystem object func (d *DevfileCtx) GetFs() filesystem.Filesystem { - return d.Fs + return d.fs } diff --git a/pkg/devfile/parser/context/schema.go b/vendor/github.com/devfile/library/pkg/devfile/parser/context/schema.go similarity index 90% rename from pkg/devfile/parser/context/schema.go rename to vendor/github.com/devfile/library/pkg/devfile/parser/context/schema.go index f9037b9e4..13326e96b 100644 --- a/pkg/devfile/parser/context/schema.go +++ b/vendor/github.com/devfile/library/pkg/devfile/parser/context/schema.go @@ -3,7 +3,7 @@ package parser import ( "fmt" - "github.com/openshift/odo/pkg/devfile/parser/data" + "github.com/devfile/library/pkg/devfile/parser/data" "github.com/pkg/errors" "github.com/xeipuuv/gojsonschema" "k8s.io/klog" @@ -23,7 +23,6 @@ func (d *DevfileCtx) SetDevfileJSONSchema() error { // ValidateDevfileSchema validate JSON schema of the provided devfile func (d *DevfileCtx) ValidateDevfileSchema() error { - var ( schemaLoader = gojsonschema.NewStringLoader(d.jsonSchema) documentLoader = gojsonschema.NewStringLoader(string(d.rawContent)) @@ -43,7 +42,7 @@ func (d *DevfileCtx) ValidateDevfileSchema() error { return fmt.Errorf(errMsg) } - // Success - klog.V(2).Info("validated devfile schema") + // Sucessful + klog.V(4).Info("validated devfile schema") return nil } diff --git a/pkg/devfile/parser/data/helper.go b/vendor/github.com/devfile/library/pkg/devfile/parser/data/helper.go similarity index 75% rename from pkg/devfile/parser/data/helper.go rename to vendor/github.com/devfile/library/pkg/devfile/parser/data/helper.go index 37c648b58..30c4a0dcf 100644 --- a/pkg/devfile/parser/data/helper.go +++ b/vendor/github.com/devfile/library/pkg/devfile/parser/data/helper.go @@ -3,6 +3,7 @@ package data import ( "fmt" "reflect" + "strings" "k8s.io/klog" ) @@ -31,9 +32,13 @@ func GetDevfileJSONSchema(version string) (string, error) { // Fetch json schema from the devfileApiVersionToJSONSchema map schema, ok := devfileApiVersionToJSONSchema[supportedApiVersion(version)] if !ok { - return "", fmt.Errorf("unable to find schema for apiVersion '%s', this Devfile version is not supported by odo", version) + var supportedVersions []string + for version := range devfileApiVersionToJSONSchema { + supportedVersions = append(supportedVersions, string(version)) + } + return "", fmt.Errorf("unable to find schema for version %q. The parser supports devfile schema for version %s", version, strings.Join(supportedVersions, ", ")) } - klog.V(2).Infof("devfile apiVersion '%s' is supported in odo", version) + klog.V(4).Infof("devfile apiVersion '%s' is supported in odo", version) // Successful return schema, nil diff --git a/vendor/github.com/devfile/library/pkg/devfile/parser/data/interface.go b/vendor/github.com/devfile/library/pkg/devfile/parser/data/interface.go new file mode 100644 index 000000000..84d0d8c08 --- /dev/null +++ b/vendor/github.com/devfile/library/pkg/devfile/parser/data/interface.go @@ -0,0 +1,47 @@ +package data + +import ( + v1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + devfilepkg "github.com/devfile/api/pkg/devfile" +) + +// DevfileData is an interface that defines functions for Devfile data operations +type DevfileData interface { + SetSchemaVersion(version string) + GetMetadata() devfilepkg.DevfileMetadata + SetMetadata(name, version string) + + // parent related methods + GetParent() *v1.Parent + SetParent(parent *v1.Parent) + + // event related methods + GetEvents() v1.Events + AddEvents(events v1.Events) error + UpdateEvents(postStart, postStop, preStart, preStop []string) + + // component related methods + GetComponents() []v1.Component + AddComponents(components []v1.Component) error + UpdateComponent(component v1.Component) + + // project related methods + GetProjects() []v1.Project + AddProjects(projects []v1.Project) error + UpdateProject(project v1.Project) + + // starter projects related commands + GetStarterProjects() []v1.StarterProject + AddStarterProjects(projects []v1.StarterProject) error + UpdateStarterProject(project v1.StarterProject) + + // command related methods + GetCommands() map[string]v1.Command + AddCommands(commands ...v1.Command) error + UpdateCommand(command v1.Command) + + // volume related methods + AddVolume(volume v1.Component, path string) error + DeleteVolume(name string) error + GetVolumeMountPath(name string) (string, error) +} diff --git a/pkg/devfile/parser/data/2.0.0/devfileJsonSchema200.go b/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/2.0.0/devfileJsonSchema200.go similarity index 99% rename from pkg/devfile/parser/data/2.0.0/devfileJsonSchema200.go rename to vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/2.0.0/devfileJsonSchema200.go index 669c58135..7aa2cfcc1 100644 --- a/pkg/devfile/parser/data/2.0.0/devfileJsonSchema200.go +++ b/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/2.0.0/devfileJsonSchema200.go @@ -3298,4 +3298,5 @@ const JsonSchema200 = `{ } }, "additionalProperties": false -}` +} +` diff --git a/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/commands.go b/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/commands.go new file mode 100644 index 000000000..f25c80623 --- /dev/null +++ b/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/commands.go @@ -0,0 +1,46 @@ +package v2 + +import ( + "strings" + + v1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + "github.com/devfile/library/pkg/devfile/parser/data/v2/common" +) + +// GetCommands returns the slice of Command objects parsed from the Devfile +func (d *DevfileV2) GetCommands() map[string]v1.Command { + + commands := make(map[string]v1.Command, len(d.Commands)) + + for _, command := range d.Commands { + command.Id = strings.ToLower(command.Id) + commands[command.Id] = command + } + + return commands +} + +// AddCommands adds the slice of Command objects to the Devfile's commands +// if a command is already defined, error out +func (d *DevfileV2) AddCommands(commands ...v1.Command) error { + commandsMap := d.GetCommands() + + for _, command := range commands { + if _, ok := commandsMap[command.Id]; !ok { + d.Commands = append(d.Commands, command) + } else { + return &common.FieldAlreadyExistError{Name: command.Id, Field: "command"} + } + } + return nil +} + +// UpdateCommand updates the command with the given id +func (d *DevfileV2) UpdateCommand(command v1.Command) { + for i := range d.Commands { + if strings.ToLower(d.Commands[i].Id) == strings.ToLower(command.Id) { + d.Commands[i] = command + d.Commands[i].Id = strings.ToLower(d.Commands[i].Id) + } + } +} diff --git a/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/common/command_helper.go b/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/common/command_helper.go new file mode 100644 index 000000000..3469cd731 --- /dev/null +++ b/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/common/command_helper.go @@ -0,0 +1,53 @@ +package common + +import ( + v1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" +) + +// GetGroup returns the group the command belongs to +func GetGroup(dc v1.Command) *v1.CommandGroup { + switch { + case dc.Composite != nil: + return dc.Composite.Group + case dc.Exec != nil: + return dc.Exec.Group + case dc.Apply != nil: + return dc.Apply.Group + case dc.VscodeLaunch != nil: + return dc.VscodeLaunch.Group + case dc.VscodeTask != nil: + return dc.VscodeTask.Group + case dc.Custom != nil: + return dc.Custom.Group + + default: + return nil + } +} + +// GetExecComponent returns the component of the exec command +func GetExecComponent(dc v1.Command) string { + if dc.Exec != nil { + return dc.Exec.Component + } + + return "" +} + +// GetExecCommandLine returns the command line of the exec command +func GetExecCommandLine(dc v1.Command) string { + if dc.Exec != nil { + return dc.Exec.CommandLine + } + + return "" +} + +// GetExecWorkingDir returns the working dir of the exec command +func GetExecWorkingDir(dc v1.Command) string { + if dc.Exec != nil { + return dc.Exec.WorkingDir + } + + return "" +} diff --git a/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/common/component_helper.go b/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/common/component_helper.go new file mode 100644 index 000000000..b225d2389 --- /dev/null +++ b/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/common/component_helper.go @@ -0,0 +1,38 @@ +package common + +import ( + "fmt" + + v1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" +) + +// IsContainer checks if the component is a container +func IsContainer(component v1.Component) bool { + return component.Container != nil +} + +// IsVolume checks if the component is a volume +func IsVolume(component v1.Component) bool { + return component.Volume != nil +} + +// GetComponentType returns the component type of a given component +func GetComponentType(component v1.Component) (v1.ComponentType, error) { + switch { + case component.Container != nil: + return v1.ContainerComponentType, nil + case component.Volume != nil: + return v1.VolumeComponentType, nil + case component.Plugin != nil: + return v1.PluginComponentType, nil + case component.Kubernetes != nil: + return v1.KubernetesComponentType, nil + case component.Openshift != nil: + return v1.OpenshiftComponentType, nil + case component.Custom != nil: + return v1.CustomComponentType, nil + + default: + return "", fmt.Errorf("unknown component type") + } +} diff --git a/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/common/errors.go b/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/common/errors.go new file mode 100644 index 000000000..ed5050ee0 --- /dev/null +++ b/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/common/errors.go @@ -0,0 +1,27 @@ +package common + +import "fmt" + +// FieldAlreadyExistError error returned if tried to add already exisitng field +type FieldAlreadyExistError struct { + // field which already exist + Field string + // field name + Name string +} + +func (e *FieldAlreadyExistError) Error() string { + return fmt.Sprintf("%s %s already exists in devfile", e.Field, e.Name) +} + +// FieldNotFoundError error returned if the field with the name is not found +type FieldNotFoundError struct { + // field which doesn't exist + Field string + // field name + Name string +} + +func (e *FieldNotFoundError) Error() string { + return fmt.Sprintf("%s %s is not found in the devfile", e.Field, e.Name) +} diff --git a/pkg/devfile/parser/data/common/project_helper.go b/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/common/project_helper.go similarity index 64% rename from pkg/devfile/parser/data/common/project_helper.go rename to vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/common/project_helper.go index c835cf0a9..3c5f49d01 100644 --- a/pkg/devfile/parser/data/common/project_helper.go +++ b/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/common/project_helper.go @@ -1,27 +1,32 @@ package common -import "fmt" +import ( + "fmt" + + v1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" +) // GetDefaultSource get information about primary source // returns 3 strings: remote name, remote URL, reference(revision) -func (ps GitLikeProjectSource) GetDefaultSource() (string, string, string, error) { +func GetDefaultSource(ps v1.GitLikeProjectSource) (remoteName string, remoteURL string, revision string, err error) { // get git checkout information // if there are multiple remotes we are ignoring them, as we don't need to setup git repository as it is defined here, // the only thing that we need is to download the content - var remoteName, remoteURL, revision string if ps.CheckoutFrom != nil && ps.CheckoutFrom.Revision != "" { revision = ps.CheckoutFrom.Revision } if len(ps.Remotes) > 1 { if ps.CheckoutFrom == nil { - return "", "", "", fmt.Errorf("there are multiple git remotes but no checkoutFrom information") + err = fmt.Errorf("there are multiple git remotes but no checkoutFrom information") + return "", "", "", err } remoteName = ps.CheckoutFrom.Remote if val, ok := ps.Remotes[remoteName]; ok { remoteURL = val } else { - return "", "", "", fmt.Errorf("checkoutFrom.Remote is not defined in Remotes") + err = fmt.Errorf("checkoutFrom.Remote is not defined in Remotes") + return "", "", "", err } } else { @@ -33,6 +38,6 @@ func (ps GitLikeProjectSource) GetDefaultSource() (string, string, string, error } - return remoteName, remoteURL, revision, nil + return remoteName, remoteURL, revision, err } diff --git a/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/components.go b/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/components.go new file mode 100644 index 000000000..15cc6b59f --- /dev/null +++ b/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/components.go @@ -0,0 +1,64 @@ +package v2 + +import ( + v1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + "github.com/devfile/library/pkg/devfile/parser/data/v2/common" +) + +// GetComponents returns the slice of Component objects parsed from the Devfile +func (d *DevfileV2) GetComponents() []v1.Component { + return d.Components +} + +// AddComponents adds the slice of Component objects to the devfile's components +// if a component is already defined, error out +func (d *DevfileV2) AddComponents(components []v1.Component) error { + + // different map for volume and container component as a volume and a container with same name + // can exist in devfile + containerMap := make(map[string]bool) + volumeMap := make(map[string]bool) + + for _, component := range d.Components { + if component.Volume != nil { + volumeMap[component.Name] = true + } + if component.Container != nil { + containerMap[component.Name] = true + } + } + + for _, component := range components { + + if component.Volume != nil { + if _, ok := volumeMap[component.Name]; !ok { + d.Components = append(d.Components, component) + } else { + return &common.FieldAlreadyExistError{Name: component.Name, Field: "component"} + } + } + + if component.Container != nil { + if _, ok := containerMap[component.Name]; !ok { + d.Components = append(d.Components, component) + } else { + return &common.FieldAlreadyExistError{Name: component.Name, Field: "component"} + } + } + } + return nil +} + +// UpdateComponent updates the component with the given name +func (d *DevfileV2) UpdateComponent(component v1.Component) { + index := -1 + for i := range d.Components { + if d.Components[i].Name == component.Name { + index = i + break + } + } + if index != -1 { + d.Components[index] = component + } +} diff --git a/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/events.go b/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/events.go new file mode 100644 index 000000000..04ea60ab3 --- /dev/null +++ b/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/events.go @@ -0,0 +1,65 @@ +package v2 + +import ( + v1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + "github.com/devfile/library/pkg/devfile/parser/data/v2/common" +) + +// GetEvents returns the Events Object parsed from devfile +func (d *DevfileV2) GetEvents() v1.Events { + if d.Events != nil { + return *d.Events + } + return v1.Events{} +} + +// AddEvents adds the Events Object to the devfile's events +// if the event is already defined in the devfile, error out +func (d *DevfileV2) AddEvents(events v1.Events) error { + if len(events.PreStop) > 0 { + if len(d.Events.PreStop) > 0 { + return &common.FieldAlreadyExistError{Field: "pre stop"} + } + d.Events.PreStop = events.PreStop + } + + if len(events.PreStart) > 0 { + if len(d.Events.PreStart) > 0 { + return &common.FieldAlreadyExistError{Field: "pre start"} + } + d.Events.PreStart = events.PreStart + } + + if len(events.PostStop) > 0 { + if len(d.Events.PostStop) > 0 { + return &common.FieldAlreadyExistError{Field: "post stop"} + } + d.Events.PostStop = events.PostStop + } + + if len(events.PostStart) > 0 { + if len(d.Events.PostStart) > 0 { + return &common.FieldAlreadyExistError{Field: "post start"} + } + d.Events.PostStart = events.PostStart + } + + return nil +} + +// UpdateEvents updates the devfile's events +// it only updates the events passed to it +func (d *DevfileV2) UpdateEvents(postStart, postStop, preStart, preStop []string) { + if len(postStart) != 0 { + d.Events.PostStart = postStart + } + if len(postStop) != 0 { + d.Events.PostStop = postStop + } + if len(preStart) != 0 { + d.Events.PreStart = preStart + } + if len(preStop) != 0 { + d.Events.PreStop = preStop + } +} diff --git a/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/header.go b/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/header.go new file mode 100644 index 000000000..3d44688c4 --- /dev/null +++ b/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/header.go @@ -0,0 +1,23 @@ +package v2 + +import ( + devfilepkg "github.com/devfile/api/pkg/devfile" +) + +//SetSchemaVersion sets devfile schema version +func (d *DevfileV2) SetSchemaVersion(version string) { + d.SchemaVersion = version +} + +// GetMetadata returns the DevfileMetadata Object parsed from devfile +func (d *DevfileV2) GetMetadata() devfilepkg.DevfileMetadata { + return d.Metadata +} + +// SetMetadata sets the metadata for devfile +func (d *DevfileV2) SetMetadata(name, version string) { + d.Metadata = devfilepkg.DevfileMetadata{ + Name: name, + Version: version, + } +} diff --git a/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/parent.go b/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/parent.go new file mode 100644 index 000000000..2e6f12428 --- /dev/null +++ b/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/parent.go @@ -0,0 +1,15 @@ +package v2 + +import ( + v1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" +) + +// GetParent returns the Parent object parsed from devfile +func (d *DevfileV2) GetParent() *v1.Parent { + return d.Parent +} + +// SetParent sets the parent for the devfile +func (d *DevfileV2) SetParent(parent *v1.Parent) { + d.Parent = parent +} diff --git a/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/projects.go b/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/projects.go new file mode 100644 index 000000000..1a13d6476 --- /dev/null +++ b/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/projects.go @@ -0,0 +1,72 @@ +package v2 + +import ( + "strings" + + v1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + "github.com/devfile/library/pkg/devfile/parser/data/v2/common" +) + +// GetProjects returns the Project Object parsed from devfile +func (d *DevfileV2) GetProjects() []v1.Project { + return d.Projects +} + +// AddProjects adss the slice of Devfile projects to the Devfile's project list +// if a project is already defined, error out +func (d *DevfileV2) AddProjects(projects []v1.Project) error { + projectsMap := make(map[string]bool) + for _, project := range d.Projects { + projectsMap[project.Name] = true + } + + for _, project := range projects { + if _, ok := projectsMap[project.Name]; !ok { + d.Projects = append(d.Projects, project) + } else { + return &common.FieldAlreadyExistError{Name: project.Name, Field: "project"} + } + } + return nil +} + +// UpdateProject updates the slice of Devfile projects parsed from the Devfile +func (d *DevfileV2) UpdateProject(project v1.Project) { + for i := range d.Projects { + if d.Projects[i].Name == strings.ToLower(project.Name) { + d.Projects[i] = project + } + } +} + +//GetStarterProjects returns the DevfileStarterProject parsed from devfile +func (d *DevfileV2) GetStarterProjects() []v1.StarterProject { + return d.StarterProjects +} + +// AddStarterProjects adds the slice of Devfile starter projects to the Devfile's starter project list +// if a starter project is already defined, error out +func (d *DevfileV2) AddStarterProjects(projects []v1.StarterProject) error { + projectsMap := make(map[string]bool) + for _, project := range d.StarterProjects { + projectsMap[project.Name] = true + } + + for _, project := range projects { + if _, ok := projectsMap[project.Name]; !ok { + d.StarterProjects = append(d.StarterProjects, project) + } else { + return &common.FieldAlreadyExistError{Name: project.Name, Field: "starterProject"} + } + } + return nil +} + +// UpdateStarterProject updates the slice of Devfile starter projects parsed from the Devfile +func (d *DevfileV2) UpdateStarterProject(project v1.StarterProject) { + for i := range d.StarterProjects { + if d.StarterProjects[i].Name == strings.ToLower(project.Name) { + d.StarterProjects[i] = project + } + } +} diff --git a/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/types.go b/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/types.go new file mode 100644 index 000000000..e7fdff4ed --- /dev/null +++ b/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/types.go @@ -0,0 +1,10 @@ +package v2 + +import ( + v1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" +) + +// DevfileV2 is the devfile go struct from devfile/api +type DevfileV2 struct { + v1.Devfile +} diff --git a/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/volumes.go b/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/volumes.go new file mode 100644 index 000000000..1f17e6ff4 --- /dev/null +++ b/vendor/github.com/devfile/library/pkg/devfile/parser/data/v2/volumes.go @@ -0,0 +1,106 @@ +package v2 + +import ( + "fmt" + "strings" + + v1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + "github.com/devfile/library/pkg/devfile/parser/data/v2/common" +) + +// AddVolume adds the volume to the devFile and mounts it to all the container components +func (d *DevfileV2) AddVolume(volumeComponent v1.Component, path string) error { + volumeExists := false + var pathErrorContainers []string + for _, component := range d.Components { + if component.Container != nil { + for _, volumeMount := range component.Container.VolumeMounts { + if volumeMount.Path == path { + var err = fmt.Errorf("another volume, %s, is mounted to the same path: %s, on the container: %s", volumeMount.Name, path, component.Name) + pathErrorContainers = append(pathErrorContainers, err.Error()) + } + } + component.Container.VolumeMounts = append(component.Container.VolumeMounts, v1.VolumeMount{ + Name: volumeComponent.Name, + Path: path, + }) + } else if component.Volume != nil && component.Name == volumeComponent.Name { + volumeExists = true + break + } + } + + if volumeExists { + return &common.FieldAlreadyExistError{ + Field: "volume", + Name: volumeComponent.Name, + } + } + + if len(pathErrorContainers) > 0 { + return fmt.Errorf("errors while creating volume:\n%s", strings.Join(pathErrorContainers, "\n")) + } + + d.Components = append(d.Components, volumeComponent) + + return nil +} + +// DeleteVolume removes the volume from the devFile and removes all the related volume mounts +func (d *DevfileV2) DeleteVolume(name string) error { + found := false + for i := len(d.Components) - 1; i >= 0; i-- { + if d.Components[i].Container != nil { + var tmp []v1.VolumeMount + for _, volumeMount := range d.Components[i].Container.VolumeMounts { + if volumeMount.Name != name { + tmp = append(tmp, volumeMount) + } + } + d.Components[i].Container.VolumeMounts = tmp + } else if d.Components[i].Volume != nil { + if d.Components[i].Name == name { + found = true + d.Components = append(d.Components[:i], d.Components[i+1:]...) + } + } + } + + if !found { + return &common.FieldNotFoundError{ + Field: "volume", + Name: name, + } + } + + return nil +} + +// GetVolumeMountPath gets the mount path of the required volume +func (d *DevfileV2) GetVolumeMountPath(name string) (string, error) { + volumeFound := false + mountFound := false + path := "" + + for _, component := range d.Components { + if component.Container != nil { + for _, volumeMount := range component.Container.VolumeMounts { + if volumeMount.Name == name { + mountFound = true + path = volumeMount.Path + } + } + } else if component.Volume != nil { + volumeFound = true + } + } + if volumeFound && mountFound { + return path, nil + } else if !mountFound && volumeFound { + return "", fmt.Errorf("volume not mounted to any component") + } + return "", &common.FieldNotFoundError{ + Field: "volume", + Name: "name", + } +} diff --git a/pkg/devfile/parser/data/versions.go b/vendor/github.com/devfile/library/pkg/devfile/parser/data/versions.go similarity index 83% rename from pkg/devfile/parser/data/versions.go rename to vendor/github.com/devfile/library/pkg/devfile/parser/data/versions.go index 1d44e4877..b0d48c783 100644 --- a/pkg/devfile/parser/data/versions.go +++ b/vendor/github.com/devfile/library/pkg/devfile/parser/data/versions.go @@ -3,7 +3,8 @@ package data import ( "reflect" - v200 "github.com/openshift/odo/pkg/devfile/parser/data/2.0.0" + v2 "github.com/devfile/library/pkg/devfile/parser/data/v2" + v200 "github.com/devfile/library/pkg/devfile/parser/data/v2/2.0.0" ) // SupportedApiVersions stores the supported devfile API versions @@ -22,8 +23,7 @@ var apiVersionToDevfileStruct map[supportedApiVersion]reflect.Type // Initializes a map of supported devfile api versions and devfile structs func init() { apiVersionToDevfileStruct = make(map[supportedApiVersion]reflect.Type) - apiVersionToDevfileStruct[APIVersion200] = reflect.TypeOf(v200.Devfile200{}) - + apiVersionToDevfileStruct[APIVersion200] = reflect.TypeOf(v2.DevfileV2{}) } // Map to store mappings between supported devfile API versions and respective devfile JSON schemas @@ -33,5 +33,4 @@ var devfileApiVersionToJSONSchema map[supportedApiVersion]string func init() { devfileApiVersionToJSONSchema = make(map[supportedApiVersion]string) devfileApiVersionToJSONSchema[APIVersion200] = v200.JsonSchema200 - } diff --git a/pkg/devfile/parser/types.go b/vendor/github.com/devfile/library/pkg/devfile/parser/devfileobj.go similarity index 62% rename from pkg/devfile/parser/types.go rename to vendor/github.com/devfile/library/pkg/devfile/parser/devfileobj.go index d4984acf1..13ccfa746 100644 --- a/pkg/devfile/parser/types.go +++ b/vendor/github.com/devfile/library/pkg/devfile/parser/devfileobj.go @@ -3,12 +3,11 @@ package parser import ( "encoding/json" "fmt" - "reflect" "strings" - devfileCtx "github.com/openshift/odo/pkg/devfile/parser/context" - "github.com/openshift/odo/pkg/devfile/parser/data" - "github.com/openshift/odo/pkg/devfile/parser/data/common" + v1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + devfileCtx "github.com/devfile/library/pkg/devfile/parser/context" + "github.com/devfile/library/pkg/devfile/parser/data" "github.com/pkg/errors" "k8s.io/apimachinery/pkg/util/strategicpatch" ) @@ -31,26 +30,31 @@ type DevfileObj struct { // OverrideComponents overrides the components of the parent devfile // overridePatch contains the patches to be applied to the parent's components -func (d DevfileObj) OverrideComponents(overridePatch []common.DevfileComponent) error { +func (d DevfileObj) OverrideComponents(overridePatch []v1.ComponentParentOverride) error { + // func (d DevfileObj) OverrideComponents(overridePatch interface{}) error { for _, patchComponent := range overridePatch { found := false for _, originalComponent := range d.Data.GetComponents() { if strings.ToLower(patchComponent.Name) == originalComponent.Name { found = true - var updatedContainer common.Container + var updatedComponent v1.ContainerComponent - merged, err := handleMerge(originalComponent.Container, patchComponent.Container, common.Container{}) + merged, err := handleMerge(originalComponent.Container, patchComponent.Container, v1.ContainerComponent{}) if err != nil { return err } - - err = json.Unmarshal(merged, &updatedContainer) + err = json.Unmarshal(merged, &updatedComponent) if err != nil { return errors.Wrap(err, "failed to unmarshal override components") } - d.Data.UpdateComponent(common.DevfileComponent{Name: patchComponent.Name, Container: &updatedContainer}) + d.Data.UpdateComponent(v1.Component{ + Name: patchComponent.Name, + ComponentUnion: v1.ComponentUnion{ + Container: &updatedComponent, + }, + }) } } if !found { @@ -62,34 +66,28 @@ func (d DevfileObj) OverrideComponents(overridePatch []common.DevfileComponent) // OverrideCommands overrides the commands of the parent devfile // overridePatch contains the patches to be applied to the parent's commands -func (d DevfileObj) OverrideCommands(overridePatch []common.DevfileCommand) (err error) { +func (d DevfileObj) OverrideCommands(overridePatch []v1.CommandParentOverride) (err error) { for _, patchCommand := range overridePatch { found := false - for _, originalCommand := range d.Data.GetCommands() { if strings.ToLower(patchCommand.Id) == originalCommand.Id { found = true - var devfileCommand common.DevfileCommand - if patchCommand.Exec != nil && originalCommand.Exec != nil { - var updatedExec common.Exec + var devfileCommand v1.Command - merged, err := handleMerge(originalCommand.Exec, patchCommand.Exec, common.Exec{}) + if patchCommand.Exec != nil && originalCommand.Exec != nil { + devfileCommand, err = overrideExecCommand(patchCommand, originalCommand) if err != nil { return err } - err = json.Unmarshal(merged, &updatedExec) - if err != nil { - return errors.Wrap(err, "failed to unmarshal override commands") - } - devfileCommand = common.DevfileCommand{Id: patchCommand.Id, Exec: &updatedExec} } else if patchCommand.Composite != nil && originalCommand.Composite != nil { devfileCommand, err = overrideCompositeCommand(patchCommand, originalCommand) if err != nil { return err } + // TODO: add other command types } else { // If the original command and patch command are different types, then we can't patch, so throw an error return fmt.Errorf("cannot overide command %q with a different type of command", originalCommand.Id) @@ -105,34 +103,60 @@ func (d DevfileObj) OverrideCommands(overridePatch []common.DevfileCommand) (err return nil } -// overrideCompositeCommand overrides the given parent composite command +// overrideCompositeCommand overrides the given parent composite commmand // patchCommand contains the patches to be applied to the parent's command -func overrideCompositeCommand(patchCommand common.DevfileCommand, originalCommand common.DevfileCommand) (common.DevfileCommand, error) { - var updatedComposite common.Composite +func overrideCompositeCommand(patchCommand v1.CommandParentOverride, originalCommand v1.Command) (v1.Command, error) { + var updatedComposite v1.CompositeCommand - merged, err := handleMerge(originalCommand.Composite, patchCommand.Composite, common.Composite{}) + merged, err := handleMerge(originalCommand.Composite, patchCommand.Composite, v1.CompositeCommand{}) if err != nil { - return common.DevfileCommand{}, err + return v1.Command{}, err } err = json.Unmarshal(merged, &updatedComposite) if err != nil { - return common.DevfileCommand{}, errors.Wrap(err, "failed to unmarshal override commands") + return v1.Command{}, errors.Wrap(err, "failed to unmarshal override commands") } - return common.DevfileCommand{Id: patchCommand.Id, Composite: &updatedComposite}, nil + return v1.Command{ + Id: patchCommand.Id, + CommandUnion: v1.CommandUnion{ + Composite: &updatedComposite, + }, + }, nil +} + +// overrideExecCommand overrides the given parent Exec commmand +// patchCommand contains the patches to be applied to the parent's command +func overrideExecCommand(patchCommand v1.CommandParentOverride, originalCommand v1.Command) (v1.Command, error) { + var updatedExec v1.ExecCommand + merged, err := handleMerge(originalCommand.Exec, patchCommand.Exec, v1.ExecCommand{}) + if err != nil { + return v1.Command{}, err + } + + err = json.Unmarshal(merged, &updatedExec) + if err != nil { + return v1.Command{}, errors.Wrap(err, "failed to unmarshal override commands") + } + return v1.Command{ + Id: patchCommand.Id, + CommandUnion: v1.CommandUnion{ + Exec: &updatedExec, + }, + }, nil } // OverrideProjects overrides the projects of the parent devfile // overridePatch contains the patches to be applied to the parent's projects -func (d DevfileObj) OverrideProjects(overridePatch []common.DevfileProject) error { +func (d DevfileObj) OverrideProjects(overridePatch []v1.ProjectParentOverride) error { for _, patchProject := range overridePatch { found := false for _, originalProject := range d.Data.GetProjects() { if strings.ToLower(patchProject.Name) == originalProject.Name { found = true - var updatedProject common.DevfileProject + var updatedProject v1.Project - merged, err := handleMerge(originalProject, patchProject, common.DevfileProject{}) + merged, err := handleMerge(originalProject, patchProject, v1.Project{}) if err != nil { return err } @@ -146,7 +170,7 @@ func (d DevfileObj) OverrideProjects(overridePatch []common.DevfileProject) erro } } if !found { - return fmt.Errorf("the project to override is not found in the parent") + return fmt.Errorf("the command to override is not found in the parent") } } return nil @@ -154,15 +178,15 @@ func (d DevfileObj) OverrideProjects(overridePatch []common.DevfileProject) erro // OverrideStarterProjects overrides the starter projects of the parent devfile // overridePatch contains the patches to be applied to the parent's starter projects -func (d DevfileObj) OverrideStarterProjects(overridePatch []common.DevfileStarterProject) error { +func (d DevfileObj) OverrideStarterProjects(overridePatch []v1.StarterProjectParentOverride) error { for _, patchProject := range overridePatch { found := false for _, originalProject := range d.Data.GetStarterProjects() { if strings.ToLower(patchProject.Name) == originalProject.Name { found = true - var updatedProject common.DevfileStarterProject + var updatedProject v1.StarterProject - merged, err := handleMerge(originalProject, patchProject, common.DevfileStarterProject{}) + merged, err := handleMerge(originalProject, patchProject, v1.StarterProject{}) if err != nil { return err } @@ -184,9 +208,9 @@ func (d DevfileObj) OverrideStarterProjects(overridePatch []common.DevfileStarte // handleMerge merges the patch to the original data // dataStruct is the type of the original and the patch data func handleMerge(original, patch, dataStruct interface{}) ([]byte, error) { - if reflect.TypeOf(original) != reflect.TypeOf(patch) { - return nil, fmt.Errorf("type of original and patch doesn't match") - } + // if reflect.TypeOf(original) != reflect.TypeOf(patch) { + // return nil, fmt.Errorf("type of original and patch doesn't match") + // } originalJson, err := json.Marshal(original) if err != nil { @@ -199,10 +223,8 @@ func handleMerge(original, patch, dataStruct interface{}) ([]byte, error) { } merged, err := strategicpatch.StrategicMergePatch(originalJson, patchJson, dataStruct) - if err != nil { return nil, err } - return merged, nil } diff --git a/pkg/devfile/parser/parse.go b/vendor/github.com/devfile/library/pkg/devfile/parser/parse.go similarity index 83% rename from pkg/devfile/parser/parse.go rename to vendor/github.com/devfile/library/pkg/devfile/parser/parse.go index 38b4d0e62..cb05af43d 100644 --- a/pkg/devfile/parser/parse.go +++ b/vendor/github.com/devfile/library/pkg/devfile/parser/parse.go @@ -3,13 +3,12 @@ package parser import ( "encoding/json" - devfileCtx "github.com/openshift/odo/pkg/devfile/parser/context" - parser "github.com/openshift/odo/pkg/devfile/parser/context" - "github.com/openshift/odo/pkg/devfile/parser/data" + devfileCtx "github.com/devfile/library/pkg/devfile/parser/context" + "github.com/devfile/library/pkg/devfile/parser/data" "reflect" - "github.com/openshift/odo/pkg/devfile/parser/data/common" + v1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" "github.com/pkg/errors" "k8s.io/klog" ) @@ -36,10 +35,12 @@ func parseDevfile(d DevfileObj) (DevfileObj, error) { return d, errors.Wrapf(err, "failed to decode devfile content") } - if !reflect.DeepEqual(d.Data.GetParent(), common.DevfileParent{}) && d.Data.GetParent().Uri != "" { - err = parseParent(d) - if err != nil { - return DevfileObj{}, err + if d.Data.GetParent() != nil { + if !reflect.DeepEqual(d.Data.GetParent(), &v1.Parent{}) && d.Data.GetParent().Uri != "" { + err = parseParent(d) + if err != nil { + return DevfileObj{}, err + } } } @@ -78,7 +79,7 @@ func ParseFromURL(url string) (d DevfileObj, err error) { // ParseFromData func parses and validates the devfile integrity. // Creates devfile context and runtime objects func ParseFromData(data []byte) (d DevfileObj, err error) { - d.Ctx = parser.DevfileCtx{} + d.Ctx = devfileCtx.DevfileCtx{} err = d.Ctx.SetDevfileContentFromBytes(data) if err != nil { return d, errors.Wrap(err, "failed to set devfile content from bytes") @@ -98,8 +99,7 @@ func parseParent(d DevfileObj) error { if err != nil { return err } - - klog.V(2).Infof("overriding data of devfile with URI: %v", parent.Uri) + klog.V(4).Infof("overriding data of devfile with URI: %v", parent.Uri) // override the parent's components, commands, projects and events err = parentData.OverrideComponents(d.Data.GetParent().Components) @@ -122,13 +122,13 @@ func parseParent(d DevfileObj) error { return err } - klog.V(2).Infof("adding data of devfile with URI: %v", parent.Uri) + klog.V(4).Infof("adding data of devfile with URI: %v", parent.Uri) - // since the parent's data has been overridden + // since the parent's data has been overriden // add the items back to the current devfile // error indicates that the item has been defined again in the current devfile commandsMap := parentData.Data.GetCommands() - commands := make([]common.DevfileCommand, 0, len(commandsMap)) + commands := make([]v1.Command, 0, len(commandsMap)) for _, command := range commandsMap { commands = append(commands, command) } diff --git a/pkg/devfile/parser/writer.go b/vendor/github.com/devfile/library/pkg/devfile/parser/writer.go similarity index 98% rename from pkg/devfile/parser/writer.go rename to vendor/github.com/devfile/library/pkg/devfile/parser/writer.go index 19d6487e3..e583b7749 100644 --- a/pkg/devfile/parser/writer.go +++ b/vendor/github.com/devfile/library/pkg/devfile/parser/writer.go @@ -3,7 +3,7 @@ package parser import ( "encoding/json" - "gopkg.in/yaml.v2" + "sigs.k8s.io/yaml" "github.com/pkg/errors" "k8s.io/klog" diff --git a/vendor/github.com/devfile/library/pkg/testingutil/filesystem/default_fs.go b/vendor/github.com/devfile/library/pkg/testingutil/filesystem/default_fs.go new file mode 100644 index 000000000..5e5b7101b --- /dev/null +++ b/vendor/github.com/devfile/library/pkg/testingutil/filesystem/default_fs.go @@ -0,0 +1,161 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + This package is a FORK of https://github.com/kubernetes/kubernetes/blob/master/pkg/util/filesystem/defaultfs.go + See above license +*/ + +package filesystem + +import ( + "io/ioutil" + "os" + "path/filepath" + "time" +) + +// DefaultFs implements Filesystem using same-named functions from "os" and "io/ioutil" +type DefaultFs struct{} + +var _ Filesystem = DefaultFs{} + +// Stat via os.Stat +func (DefaultFs) Stat(name string) (os.FileInfo, error) { + return os.Stat(name) +} + +// Create via os.Create +func (DefaultFs) Create(name string) (File, error) { + file, err := os.Create(name) + if err != nil { + return nil, err + } + return &defaultFile{file}, nil +} + +// Open via os.Open +func (DefaultFs) Open(name string) (File, error) { + file, err := os.Open(name) + if err != nil { + return nil, err + } + + return &defaultFile{file}, nil +} + +// OpenFile via os.OpenFile +func (DefaultFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) { + file, err := os.OpenFile(name, flag, perm) + if err != nil { + return nil, err + } + + return &defaultFile{file}, nil +} + +// Rename via os.Rename +func (DefaultFs) Rename(oldpath, newpath string) error { + return os.Rename(oldpath, newpath) +} + +// MkdirAll via os.MkdirAll +func (DefaultFs) MkdirAll(path string, perm os.FileMode) error { + return os.MkdirAll(path, perm) +} + +// Chtimes via os.Chtimes +func (DefaultFs) Chtimes(name string, atime time.Time, mtime time.Time) error { + return os.Chtimes(name, atime, mtime) +} + +// RemoveAll via os.RemoveAll +func (DefaultFs) RemoveAll(path string) error { + return os.RemoveAll(path) +} + +// Remove via os.RemoveAll +func (DefaultFs) Remove(name string) error { + return os.Remove(name) +} + +// ReadFile via ioutil.ReadFile +func (DefaultFs) ReadFile(filename string) ([]byte, error) { + return ioutil.ReadFile(filename) +} + +// WriteFile via ioutil.WriteFile +func (DefaultFs) WriteFile(filename string, data []byte, perm os.FileMode) error { + return ioutil.WriteFile(filename, data, perm) +} + +// TempDir via ioutil.TempDir +func (DefaultFs) TempDir(dir, prefix string) (string, error) { + return ioutil.TempDir(dir, prefix) +} + +// TempFile via ioutil.TempFile +func (DefaultFs) TempFile(dir, prefix string) (File, error) { + file, err := ioutil.TempFile(dir, prefix) + if err != nil { + return nil, err + } + return &defaultFile{file}, nil +} + +// ReadDir via ioutil.ReadDir +func (DefaultFs) ReadDir(dirname string) ([]os.FileInfo, error) { + return ioutil.ReadDir(dirname) +} + +// Walk via filepath.Walk +func (DefaultFs) Walk(root string, walkFn filepath.WalkFunc) error { + return filepath.Walk(root, walkFn) +} + +// defaultFile implements File using same-named functions from "os" +type defaultFile struct { + file *os.File +} + +// Name via os.File.Name +func (file *defaultFile) Name() string { + return file.file.Name() +} + +// Write via os.File.Write +func (file *defaultFile) Write(b []byte) (n int, err error) { + return file.file.Write(b) +} + +// WriteString via File.WriteString +func (file *defaultFile) WriteString(s string) (int, error) { + return file.file.WriteString(s) +} + +// Sync via os.File.Sync +func (file *defaultFile) Sync() error { + return file.file.Sync() +} + +// Close via os.File.Close +func (file *defaultFile) Close() error { + return file.file.Close() +} + +func (file *defaultFile) Readdir(n int) ([]os.FileInfo, error) { + return file.file.Readdir(n) +} diff --git a/vendor/github.com/devfile/library/pkg/testingutil/filesystem/fake_fs.go b/vendor/github.com/devfile/library/pkg/testingutil/filesystem/fake_fs.go new file mode 100644 index 000000000..85aafa86f --- /dev/null +++ b/vendor/github.com/devfile/library/pkg/testingutil/filesystem/fake_fs.go @@ -0,0 +1,165 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + This package is a FORK of https://github.com/kubernetes/kubernetes/blob/master/pkg/util/filesystem/fakefs.go + See above license +*/ + +package filesystem + +import ( + "os" + "path/filepath" + "time" + + "github.com/spf13/afero" +) + +// fakeFs is implemented in terms of afero +type fakeFs struct { + a afero.Afero +} + +// NewFakeFs returns a fake Filesystem that exists in-memory, useful for unit tests +func NewFakeFs() Filesystem { + return &fakeFs{a: afero.Afero{Fs: afero.NewMemMapFs()}} +} + +// Stat via afero.Fs.Stat +func (fs *fakeFs) Stat(name string) (os.FileInfo, error) { + return fs.a.Fs.Stat(name) +} + +// Create via afero.Fs.Create +func (fs *fakeFs) Create(name string) (File, error) { + file, err := fs.a.Fs.Create(name) + if err != nil { + return nil, err + } + return &fakeFile{file}, nil +} + +// Open via afero.Fs.Open +func (fs *fakeFs) Open(name string) (File, error) { + file, err := fs.a.Fs.Open(name) + if err != nil { + return nil, err + } + return &fakeFile{file}, nil +} + +// OpenFile via afero.Fs.OpenFile +func (fs *fakeFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) { + file, err := fs.a.Fs.OpenFile(name, flag, perm) + if err != nil { + return nil, err + } + return &fakeFile{file}, nil +} + +// Rename via afero.Fs.Rename +func (fs *fakeFs) Rename(oldpath, newpath string) error { + return fs.a.Fs.Rename(oldpath, newpath) +} + +// MkdirAll via afero.Fs.MkdirAll +func (fs *fakeFs) MkdirAll(path string, perm os.FileMode) error { + return fs.a.Fs.MkdirAll(path, perm) +} + +// Chtimes via afero.Fs.Chtimes +func (fs *fakeFs) Chtimes(name string, atime time.Time, mtime time.Time) error { + return fs.a.Fs.Chtimes(name, atime, mtime) +} + +// ReadFile via afero.ReadFile +func (fs *fakeFs) ReadFile(filename string) ([]byte, error) { + return fs.a.ReadFile(filename) +} + +// WriteFile via afero.WriteFile +func (fs *fakeFs) WriteFile(filename string, data []byte, perm os.FileMode) error { + return fs.a.WriteFile(filename, data, perm) +} + +// TempDir via afero.TempDir +func (fs *fakeFs) TempDir(dir, prefix string) (string, error) { + return fs.a.TempDir(dir, prefix) +} + +// TempFile via afero.TempFile +func (fs *fakeFs) TempFile(dir, prefix string) (File, error) { + file, err := fs.a.TempFile(dir, prefix) + if err != nil { + return nil, err + } + return &fakeFile{file}, nil +} + +// ReadDir via afero.ReadDir +func (fs *fakeFs) ReadDir(dirname string) ([]os.FileInfo, error) { + return fs.a.ReadDir(dirname) +} + +// Walk via afero.Walk +func (fs *fakeFs) Walk(root string, walkFn filepath.WalkFunc) error { + return fs.a.Walk(root, walkFn) +} + +// RemoveAll via afero.RemoveAll +func (fs *fakeFs) RemoveAll(path string) error { + return fs.a.RemoveAll(path) +} + +// Remove via afero.RemoveAll +func (fs *fakeFs) Remove(name string) error { + return fs.a.Remove(name) +} + +// fakeFile implements File; for use with fakeFs +type fakeFile struct { + file afero.File +} + +// Name via afero.File.Name +func (file *fakeFile) Name() string { + return file.file.Name() +} + +// Write via afero.File.Write +func (file *fakeFile) Write(b []byte) (n int, err error) { + return file.file.Write(b) +} + +// WriteString via afero.File.WriteString +func (file *fakeFile) WriteString(s string) (n int, err error) { + return file.file.WriteString(s) +} + +// Sync via afero.File.Sync +func (file *fakeFile) Sync() error { + return file.file.Sync() +} + +// Close via afero.File.Close +func (file *fakeFile) Close() error { + return file.file.Close() +} + +func (file *fakeFile) Readdir(n int) ([]os.FileInfo, error) { + return file.file.Readdir(n) +} diff --git a/vendor/github.com/devfile/library/pkg/testingutil/filesystem/filesystem.go b/vendor/github.com/devfile/library/pkg/testingutil/filesystem/filesystem.go new file mode 100644 index 000000000..aee6b16db --- /dev/null +++ b/vendor/github.com/devfile/library/pkg/testingutil/filesystem/filesystem.go @@ -0,0 +1,62 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* + This package is a FORK of https://github.com/kubernetes/kubernetes/blob/master/pkg/util/filesystem/filesystem.go + See above license +*/ + +package filesystem + +import ( + "os" + "path/filepath" + "time" +) + +// Filesystem is an interface that we can use to mock various filesystem operations +type Filesystem interface { + // from "os" + Stat(name string) (os.FileInfo, error) + Create(name string) (File, error) + Open(name string) (File, error) + OpenFile(name string, flag int, perm os.FileMode) (File, error) + Rename(oldpath, newpath string) error + MkdirAll(path string, perm os.FileMode) error + Chtimes(name string, atime time.Time, mtime time.Time) error + RemoveAll(path string) error + Remove(name string) error + + // from "io/ioutil" + ReadFile(filename string) ([]byte, error) + WriteFile(filename string, data []byte, perm os.FileMode) error + TempDir(dir, prefix string) (string, error) + TempFile(dir, prefix string) (File, error) + ReadDir(dirname string) ([]os.FileInfo, error) + Walk(root string, walkFn filepath.WalkFunc) error +} + +// File is an interface that we can use to mock various filesystem operations typically +// accessed through the File object from the "os" package +type File interface { + // for now, the only os.File methods used are those below, add more as necessary + Name() string + Write(b []byte) (n int, err error) + WriteString(s string) (n int, err error) + Sync() error + Close() error + Readdir(n int) ([]os.FileInfo, error) +} diff --git a/vendor/github.com/devfile/library/pkg/util/httpcache.go b/vendor/github.com/devfile/library/pkg/util/httpcache.go new file mode 100644 index 000000000..8c1406016 --- /dev/null +++ b/vendor/github.com/devfile/library/pkg/util/httpcache.go @@ -0,0 +1,29 @@ +package util + +import ( + "io/ioutil" + "os" + "path/filepath" + "time" + + "k8s.io/klog" +) + +// cleanHttpCache checks cacheDir and deletes all files that were modified more than cacheTime back +func cleanHttpCache(cacheDir string, cacheTime time.Duration) error { + cacheFiles, err := ioutil.ReadDir(cacheDir) + if err != nil { + return err + } + + for _, f := range cacheFiles { + if f.ModTime().Add(cacheTime).Before(time.Now()) { + klog.V(4).Infof("Removing cache file %s, because it is older than %s", f.Name(), cacheTime.String()) + err := os.Remove(filepath.Join(cacheDir, f.Name())) + if err != nil { + return err + } + } + } + return nil +} diff --git a/vendor/github.com/devfile/library/pkg/util/util.go b/vendor/github.com/devfile/library/pkg/util/util.go new file mode 100644 index 000000000..e8f4b2cdd --- /dev/null +++ b/vendor/github.com/devfile/library/pkg/util/util.go @@ -0,0 +1,1235 @@ +package util + +import ( + "archive/zip" + "bufio" + "bytes" + "crypto/rand" + "fmt" + "io" + "io/ioutil" + "math/big" + "net" + "net/http" + "net/url" + "os" + "os/exec" + "os/signal" + "os/user" + "path" + "path/filepath" + "regexp" + "runtime" + "sort" + "strconv" + "strings" + "syscall" + "time" + + "github.com/devfile/library/pkg/testingutil/filesystem" + "github.com/fatih/color" + "github.com/gobwas/glob" + "github.com/gregjones/httpcache" + "github.com/gregjones/httpcache/diskcache" + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + kvalidation "k8s.io/apimachinery/pkg/util/validation" + "k8s.io/klog" +) + +const ( + HTTPRequestTimeout = 30 * time.Second // HTTPRequestTimeout configures timeout of all HTTP requests + ResponseHeaderTimeout = 30 * time.Second // ResponseHeaderTimeout is the timeout to retrieve the server's response headers + ModeReadWriteFile = 0600 // default Permission for a file + CredentialPrefix = "odo-" // CredentialPrefix is the prefix of the credential that uses to access secure registry +) + +// httpCacheDir determines directory where odo will cache HTTP respones +var httpCacheDir = filepath.Join(os.TempDir(), "odohttpcache") + +var letterRunes = []rune("abcdefghijklmnopqrstuvwxyz") + +// 63 is the max length of a DeploymentConfig in Openshift and we also have to take into account +// that each component also gets a volume that uses the component name suffixed with -s2idata +const maxAllowedNamespacedStringLength = 63 - len("-s2idata") - 1 + +// This value can be provided to set a seperate directory for users 'homedir' resolution +// note for mocking purpose ONLY +var customHomeDir = os.Getenv("CUSTOM_HOMEDIR") + +const defaultGithubRef = "master" + +// ResourceRequirementInfo holds resource quantity before transformation into its appropriate form in container spec +type ResourceRequirementInfo struct { + ResourceType corev1.ResourceName + MinQty resource.Quantity + MaxQty resource.Quantity +} + +// HTTPRequestParams holds parameters of forming http request +type HTTPRequestParams struct { + URL string + Token string +} + +// DownloadParams holds parameters of forming file download request +type DownloadParams struct { + Request HTTPRequestParams + Filepath string +} + +// ConvertLabelsToSelector converts the given labels to selector +func ConvertLabelsToSelector(labels map[string]string) string { + var selector string + isFirst := true + for k, v := range labels { + if isFirst { + isFirst = false + if v == "" { + selector = selector + fmt.Sprintf("%v", k) + } else { + selector = fmt.Sprintf("%v=%v", k, v) + } + } else { + if v == "" { + selector = selector + fmt.Sprintf(",%v", k) + } else { + selector = selector + fmt.Sprintf(",%v=%v", k, v) + } + } + } + return selector +} + +// GenerateRandomString generates a random string of lower case characters of +// the given size +func GenerateRandomString(n int) string { + b := make([]rune, n) + + for i := range b { + // this error is ignored because it fails only when the 2nd arg of Int() is less then 0 + // which wont happen + n, _ := rand.Int(rand.Reader, big.NewInt(int64(len(letterRunes)))) + b[i] = letterRunes[n.Int64()] + } + return string(b) +} + +// In checks if the value is in the array +func In(arr []string, value string) bool { + for _, item := range arr { + if item == value { + return true + } + } + return false +} + +// NamespaceOpenShiftObject hyphenates applicationName and componentName +func NamespaceOpenShiftObject(componentName string, applicationName string) (string, error) { + + // Error if it's blank + if componentName == "" { + return "", errors.New("namespacing: component name cannot be blank") + } + + // Error if it's blank + if applicationName == "" { + return "", errors.New("namespacing: application name cannot be blank") + } + + // Return the hyphenated namespaced name + originalName := fmt.Sprintf("%s-%s", strings.Replace(componentName, "/", "-", -1), applicationName) + truncatedName := TruncateString(originalName, maxAllowedNamespacedStringLength) + if originalName != truncatedName { + klog.V(4).Infof("The combination of application %s and component %s was too long so the final name was truncated to %s", + applicationName, componentName, truncatedName) + } + return truncatedName, nil +} + +// ExtractComponentType returns only component type part from passed component type(default unqualified, fully qualified, versioned, etc...and their combinations) for use as component name +// Possible types of parameters: +// 1. "myproject/python:3.5" -- Return python +// 2. "python:3.5" -- Return python +// 3. nodejs -- Return nodejs +func ExtractComponentType(namespacedVersionedComponentType string) string { + s := strings.Split(namespacedVersionedComponentType, "/") + versionedString := s[0] + if len(s) == 2 { + versionedString = s[1] + } + s = strings.Split(versionedString, ":") + return s[0] +} + +// ParseComponentImageName returns +// 1. image name +// 2. component type i.e, builder image name +// 3. component name default value is component type else the user requested component name +// 4. component version which is by default latest else version passed with builder image name +func ParseComponentImageName(imageName string) (string, string, string, string) { + // We don't have to check it anymore, Args check made sure that args has at least one item + // and no more than two + + // "Default" values + componentImageName := imageName + componentType := imageName + componentName := ExtractComponentType(componentType) + componentVersion := "latest" + + // Check if componentType includes ":", if so, then we need to spit it into using versions + if strings.ContainsAny(componentImageName, ":") { + versionSplit := strings.Split(imageName, ":") + componentType = versionSplit[0] + componentName = ExtractComponentType(componentType) + componentVersion = versionSplit[1] + } + return componentImageName, componentType, componentName, componentVersion +} + +// WIN represent the windows OS +const WIN = "windows" + +// ReadFilePath Reads file path form URL file:///C:/path/to/file to C:\path\to\file +func ReadFilePath(u *url.URL, os string) string { + location := u.Path + if os == WIN { + location = strings.Replace(u.Path, "/", "\\", -1) + location = location[1:] + } + return location +} + +// GenFileURL Converts file path on windows to /C:/path/to/file to work in URL +func GenFileURL(location string, os ...string) string { + // param os is made variadic only for the purpose of UTs but need not be passed mandatorily + currOS := runtime.GOOS + if len(os) > 0 { + currOS = os[0] + } + urlPath := location + if currOS == WIN { + urlPath = "/" + strings.Replace(location, "\\", "/", -1) + } + return "file://" + urlPath +} + +// ConvertKeyValueStringToMap converts String Slice of Parameters to a Map[String]string +// Each value of the slice is expected to be in the key=value format +// Values that do not conform to this "spec", will be ignored +func ConvertKeyValueStringToMap(params []string) map[string]string { + result := make(map[string]string, len(params)) + for _, param := range params { + str := strings.Split(param, "=") + if len(str) != 2 { + klog.Fatalf("Parameter %s is not in the expected key=value format", param) + } else { + result[str[0]] = str[1] + } + } + return result +} + +// TruncateString truncates passed string to given length +// Note: if -1 is passed, the original string is returned +func TruncateString(str string, maxLen int) string { + if maxLen == -1 { + return str + } + if len(str) > maxLen { + return str[:maxLen] + } + return str +} + +// GetAbsPath returns absolute path from passed file path resolving even ~ to user home dir and any other such symbols that are only +// shell expanded can also be handled here +func GetAbsPath(path string) (string, error) { + // Only shell resolves `~` to home so handle it specially + var dir string + if strings.HasPrefix(path, "~") { + if len(customHomeDir) > 0 { + dir = customHomeDir + } else { + usr, err := user.Current() + if err != nil { + return path, errors.Wrapf(err, "unable to resolve %s to absolute path", path) + } + dir = usr.HomeDir + } + + if len(path) > 1 { + path = filepath.Join(dir, path[1:]) + } else { + path = dir + } + } + + path, err := filepath.Abs(path) + if err != nil { + return path, errors.Wrapf(err, "unable to resolve %s to absolute path", path) + } + return path, nil +} + +// GetRandomName returns a randomly generated name which can be used for naming odo and/or openshift entities +// prefix: Desired prefix part of the name +// prefixMaxLen: Desired maximum length of prefix part of random name; if -1 is passed, no limit on length will be enforced +// existList: List to verify that the returned name does not already exist +// retries: number of retries to try generating a unique name +// Returns: +// 1. randomname: is prefix-suffix, where: +// prefix: string passed as prefix or fetched current directory of length same as the passed prefixMaxLen +// suffix: 4 char random string +// 2. error: if requested number of retries also failed to generate unique name +func GetRandomName(prefix string, prefixMaxLen int, existList []string, retries int) (string, error) { + prefix = TruncateString(GetDNS1123Name(strings.ToLower(prefix)), prefixMaxLen) + name := fmt.Sprintf("%s-%s", prefix, GenerateRandomString(4)) + + //Create a map of existing names for efficient iteration to find if the newly generated name is same as any of the already existing ones + existingNames := make(map[string]bool) + for _, existingName := range existList { + existingNames[existingName] = true + } + + // check if generated name is already used in the existList + if _, ok := existingNames[name]; ok { + prevName := name + trial := 0 + // keep generating names until generated name is not unique. So, loop terminates when name is unique and hence for condition is false + for ok { + trial = trial + 1 + prevName = name + // Attempt unique name generation from prefix-suffix by concatenating prefix-suffix withrandom string of length 4 + prevName = fmt.Sprintf("%s-%s", prevName, GenerateRandomString(4)) + _, ok = existingNames[prevName] + if trial >= retries { + // Avoid infinite loops and fail after passed number of retries + return "", fmt.Errorf("failed to generate a unique name even after %d retrials", retries) + } + } + // If found to be unique, set name as generated name + name = prevName + } + // return name + return name, nil +} + +// GetDNS1123Name Converts passed string into DNS-1123 string +func GetDNS1123Name(str string) string { + nonAllowedCharsRegex := regexp.MustCompile(`[^a-zA-Z0-9_-]+`) + withReplacedChars := strings.Replace( + nonAllowedCharsRegex.ReplaceAllString(str, "-"), + "--", "-", -1) + return removeNonAlphaSuffix(removeNonAlphaPrefix(withReplacedChars)) +} + +func removeNonAlphaPrefix(input string) string { + regex := regexp.MustCompile("^[^a-zA-Z0-9]+(.*)$") + return regex.ReplaceAllString(input, "$1") +} + +func removeNonAlphaSuffix(input string) string { + suffixRegex := regexp.MustCompile("^(.*?)[^a-zA-Z0-9]+$") //regex that strips all trailing non alpha-numeric chars + matches := suffixRegex.FindStringSubmatch(input) + matchesLength := len(matches) + if matchesLength == 0 { + // in this case the string does not contain a non-alphanumeric suffix + return input + } else { + // in this case we return the smallest match which in the last element in the array + return matches[matchesLength-1] + } +} + +// SliceDifference returns the values of s2 that do not exist in s1 +func SliceDifference(s1 []string, s2 []string) []string { + mb := map[string]bool{} + for _, x := range s1 { + mb[x] = true + } + difference := []string{} + for _, x := range s2 { + if _, ok := mb[x]; !ok { + difference = append(difference, x) + } + } + return difference +} + +// OpenBrowser opens the URL within the users default browser +func OpenBrowser(url string) error { + var err error + + switch runtime.GOOS { + case "linux": + err = exec.Command("xdg-open", url).Start() + case "windows": + err = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start() + case "darwin": + err = exec.Command("open", url).Start() + default: + err = fmt.Errorf("unsupported platform") + } + if err != nil { + return err + } + + return nil +} + +// FetchResourceQuantity takes passed min, max and requested resource quantities and returns min and max resource requests +func FetchResourceQuantity(resourceType corev1.ResourceName, min string, max string, request string) (*ResourceRequirementInfo, error) { + if min == "" && max == "" && request == "" { + return nil, nil + } + // If minimum and maximum both are passed they carry highest priority + // Otherwise, use the request as min and max + var minResource resource.Quantity + var maxResource resource.Quantity + if min != "" { + resourceVal, err := resource.ParseQuantity(min) + if err != nil { + return nil, err + } + minResource = resourceVal + } + if max != "" { + resourceVal, err := resource.ParseQuantity(max) + if err != nil { + return nil, err + } + maxResource = resourceVal + } + if request != "" && (min == "" || max == "") { + resourceVal, err := resource.ParseQuantity(request) + if err != nil { + return nil, err + } + minResource = resourceVal + maxResource = resourceVal + } + return &ResourceRequirementInfo{ + ResourceType: resourceType, + MinQty: minResource, + MaxQty: maxResource, + }, nil +} + +// CheckPathExists checks if a path exists or not +func CheckPathExists(path string) bool { + if _, err := os.Stat(path); !os.IsNotExist(err) { + // path to file does exist + return true + } + klog.V(4).Infof("path %s doesn't exist, skipping it", path) + return false +} + +// GetHostWithPort parses provided url and returns string formated as +// host:port even if port was not specifically specified in the origin url. +// If port is not specified, standart port corresponding to url schema is provided. +// example: for url https://example.com function will return "example.com:443" +// for url https://example.com:8443 function will return "example:8443" +func GetHostWithPort(inputURL string) (string, error) { + u, err := url.Parse(inputURL) + if err != nil { + return "", errors.Wrapf(err, "error while getting port for url %s ", inputURL) + } + + port := u.Port() + address := u.Host + // if port is not specified try to detect it based on provided scheme + if port == "" { + portInt, err := net.LookupPort("tcp", u.Scheme) + if err != nil { + return "", errors.Wrapf(err, "error while getting port for url %s ", inputURL) + } + port = strconv.Itoa(portInt) + address = fmt.Sprintf("%s:%s", u.Host, port) + } + return address, nil +} + +// GetIgnoreRulesFromDirectory reads the .odoignore file, if present, and reads the rules from it +// if the .odoignore file is not found, then .gitignore is searched for the rules +// if both are not found, return empty array +// directory is the name of the directory to look into for either of the files +// rules is the array of rules (in string form) +func GetIgnoreRulesFromDirectory(directory string) ([]string, error) { + rules := []string{".git"} + // checking for presence of .odoignore file + pathIgnore := filepath.Join(directory, ".odoignore") + if _, err := os.Stat(pathIgnore); os.IsNotExist(err) || err != nil { + // .odoignore doesn't exist + // checking presence of .gitignore file + pathIgnore = filepath.Join(directory, ".gitignore") + if _, err := os.Stat(pathIgnore); os.IsNotExist(err) || err != nil { + // both doesn't exist, return empty array + return rules, nil + } + } + + file, err := os.Open(pathIgnore) + if err != nil { + return nil, err + } + + defer file.Close() // #nosec G307 + + scanner := bufio.NewReader(file) + for { + line, _, err := scanner.ReadLine() + if err != nil { + if err == io.EOF { + break + } + + return rules, err + } + spaceTrimmedLine := strings.TrimSpace(string(line)) + if len(spaceTrimmedLine) > 0 && !strings.HasPrefix(string(line), "#") && !strings.HasPrefix(string(line), ".git") { + rules = append(rules, string(line)) + } + } + + return rules, nil +} + +// GetAbsGlobExps converts the relative glob expressions into absolute glob expressions +// returns the absolute glob expressions +func GetAbsGlobExps(directory string, globExps []string) []string { + absGlobExps := []string{} + for _, globExp := range globExps { + // for glob matching with the library + // the relative paths in the glob expressions need to be converted to absolute paths + absGlobExps = append(absGlobExps, filepath.Join(directory, globExp)) + } + return absGlobExps +} + +// GetSortedKeys retrieves the alphabetically-sorted keys of the specified map +func GetSortedKeys(mapping map[string]string) []string { + keys := make([]string, len(mapping)) + + i := 0 + for k := range mapping { + keys[i] = k + i++ + } + + sort.Strings(keys) + + return keys +} + +// GetSplitValuesFromStr returns a slice containing the split string, using ',' as a separator +func GetSplitValuesFromStr(inputStr string) []string { + if len(inputStr) == 0 { + return []string{} + } + + result := strings.Split(inputStr, ",") + for i, value := range result { + result[i] = strings.TrimSpace(value) + } + return result +} + +// GetContainerPortsFromStrings generates ContainerPort values from the array of string port values +// ports is the array containing the string port values +func GetContainerPortsFromStrings(ports []string) ([]corev1.ContainerPort, error) { + var containerPorts []corev1.ContainerPort + for _, port := range ports { + splits := strings.Split(port, "/") + if len(splits) < 1 || len(splits) > 2 { + return nil, fmt.Errorf("unable to parse the port string %s", port) + } + + portNumberI64, err := strconv.ParseInt(splits[0], 10, 32) + if err != nil { + return nil, fmt.Errorf("invalid port number %s", splits[0]) + } + portNumber := int32(portNumberI64) + + var portProto corev1.Protocol + if len(splits) == 2 { + switch strings.ToUpper(splits[1]) { + case "TCP": + portProto = corev1.ProtocolTCP + case "UDP": + portProto = corev1.ProtocolUDP + default: + return nil, fmt.Errorf("invalid port protocol %s", splits[1]) + } + } else { + portProto = corev1.ProtocolTCP + } + + port := corev1.ContainerPort{ + Name: fmt.Sprintf("%d-%s", portNumber, strings.ToLower(string(portProto))), + ContainerPort: portNumber, + Protocol: portProto, + } + containerPorts = append(containerPorts, port) + } + return containerPorts, nil +} + +// IsGlobExpMatch compiles strToMatch against each of the passed globExps +// Parameters: +// strToMatch : a string for matching against the rules +// globExps : a list of glob patterns to match strToMatch with +// Returns: true if there is any match else false the error (if any) +// Notes: +// Source as well as glob expression to match is changed to forward +// slashes due to supporting Windows as well as support with the +// "github.com/gobwas/glob" library that we use. +func IsGlobExpMatch(strToMatch string, globExps []string) (bool, error) { + + // Replace all backslashes with forward slashes in order for + // glob / expression matching to work correctly with + // the "github.com/gobwas/glob" library + strToMatch = strings.Replace(strToMatch, "\\", "/", -1) + + for _, globExp := range globExps { + + // We replace backslashes with forward slashes for + // glob expression / matching support + globExp = strings.Replace(globExp, "\\", "/", -1) + + pattern, err := glob.Compile(globExp) + if err != nil { + return false, err + } + matched := pattern.Match(strToMatch) + if matched { + klog.V(4).Infof("ignoring path %s because of glob rule %s", strToMatch, globExp) + return true, nil + } + } + return false, nil +} + +// CheckOutputFlag returns true if specified output format is supported +func CheckOutputFlag(outputFlag string) bool { + if outputFlag == "json" || outputFlag == "" { + return true + } + return false +} + +// RemoveDuplicates goes through a string slice and removes all duplicates. +// Reference: https://siongui.github.io/2018/04/14/go-remove-duplicates-from-slice-or-array/ +func RemoveDuplicates(s []string) []string { + + // Make a map and go through each value to see if it's a duplicate or not + m := make(map[string]bool) + for _, item := range s { + if _, ok := m[item]; !ok { + m[item] = true + } + } + + // Append to the unique string + var result []string + for item := range m { + result = append(result, item) + } + return result +} + +// RemoveRelativePathFromFiles removes a specified path from a list of files +func RemoveRelativePathFromFiles(files []string, path string) ([]string, error) { + + removedRelativePathFiles := []string{} + for _, file := range files { + rel, err := filepath.Rel(path, file) + if err != nil { + return []string{}, err + } + removedRelativePathFiles = append(removedRelativePathFiles, rel) + } + + return removedRelativePathFiles, nil +} + +// DeletePath deletes a file/directory if it exists and doesn't throw error if it doesn't exist +func DeletePath(path string) error { + _, err := os.Stat(path) + + // reason for double negative is os.IsExist() would be blind to EMPTY FILE. + if !os.IsNotExist(err) { + return os.Remove(path) + } + return nil +} + +// HTTPGetFreePort gets a free port from the system +func HTTPGetFreePort() (int, error) { + listener, err := net.Listen("tcp", "localhost:0") + if err != nil { + return -1, err + } + freePort := listener.Addr().(*net.TCPAddr).Port + err = listener.Close() + if err != nil { + return -1, err + } + return freePort, nil +} + +// IsEmpty checks to see if a directory is empty +// shamelessly taken from: https://stackoverflow.com/questions/30697324/how-to-check-if-directory-on-path-is-empty +// this helps detect any edge cases where an empty directory is copied over +func IsEmpty(name string) (bool, error) { + f, err := os.Open(name) + if err != nil { + return false, err + } + defer f.Close() // #nosec G307 + + _, err = f.Readdirnames(1) // Or f.Readdir(1) + if err == io.EOF { + return true, nil + } + return false, err // Either not empty or error, suits both cases +} + +// GetRemoteFilesMarkedForDeletion returns the list of remote files marked for deletion +func GetRemoteFilesMarkedForDeletion(delSrcRelPaths []string, remoteFolder string) []string { + var rmPaths []string + for _, delRelPath := range delSrcRelPaths { + // since the paths inside the container are linux oriented + // so we convert the paths accordingly + rmPaths = append(rmPaths, filepath.ToSlash(filepath.Join(remoteFolder, delRelPath))) + } + return rmPaths +} + +// HTTPGetRequest gets resource contents given URL and token (if applicable) +// cacheFor determines how long the response should be cached (in minutes), 0 for no caching +func HTTPGetRequest(request HTTPRequestParams, cacheFor int) ([]byte, error) { + // Build http request + req, err := http.NewRequest("GET", request.URL, nil) + if err != nil { + return nil, err + } + if request.Token != "" { + bearer := "Bearer " + request.Token + req.Header.Add("Authorization", bearer) + } + + httpClient := &http.Client{ + Transport: &http.Transport{ + ResponseHeaderTimeout: ResponseHeaderTimeout, + }, + Timeout: HTTPRequestTimeout, + } + + klog.V(4).Infof("HTTPGetRequest: %s", req.URL.String()) + + if cacheFor > 0 { + // if there is an error during cache setup we show warning and continue without using cache + cacheError := false + httpCacheTime := time.Duration(cacheFor) * time.Minute + + // make sure that cache directory exists + err = os.MkdirAll(httpCacheDir, 0750) + if err != nil { + cacheError = true + klog.WarningDepth(4, "Unable to setup cache: ", err) + } + err = cleanHttpCache(httpCacheDir, httpCacheTime) + if err != nil { + cacheError = true + klog.WarningDepth(4, "Unable to clean up cache directory: ", err) + } + + if !cacheError { + httpClient.Transport = httpcache.NewTransport(diskcache.New(httpCacheDir)) + klog.V(4).Infof("Response will be cached in %s for %s", httpCacheDir, httpCacheTime) + } else { + klog.V(4).Info("Response won't be cached.") + } + } + + resp, err := httpClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.Header.Get(httpcache.XFromCache) != "" { + klog.V(4).Infof("Cached response used.") + } + + // We have a non 1xx / 2xx status, return an error + if (resp.StatusCode - 300) > 0 { + return nil, errors.Errorf("fail to retrive %s: %s", request.URL, http.StatusText(resp.StatusCode)) + } + + // Process http response + bytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + return bytes, err +} + +// FilterIgnores applies the glob rules on the filesChanged and filesDeleted and filters them +// returns the filtered results which match any of the glob rules +func FilterIgnores(filesChanged, filesDeleted, absIgnoreRules []string) (filesChangedFiltered, filesDeletedFiltered []string) { + for _, file := range filesChanged { + match, err := IsGlobExpMatch(file, absIgnoreRules) + if err != nil { + continue + } + if !match { + filesChangedFiltered = append(filesChangedFiltered, file) + } + } + + for _, file := range filesDeleted { + match, err := IsGlobExpMatch(file, absIgnoreRules) + if err != nil { + continue + } + if !match { + filesDeletedFiltered = append(filesDeletedFiltered, file) + } + } + return filesChangedFiltered, filesDeletedFiltered +} + +// IsValidProjectDir checks that the folder to download the project from devfile is +// either empty or only contains the devfile used. +func IsValidProjectDir(path string, devfilePath string) error { + files, err := ioutil.ReadDir(path) + if err != nil { + return err + } + + if len(files) > 1 { + return errors.Errorf("Folder %s is not empty. It can only contain the devfile used.", path) + } else if len(files) == 1 { + file := files[0] + if file.IsDir() { + return errors.Errorf("Folder %s is not empty. It contains a subfolder.", path) + } + fileName := files[0].Name() + devfilePath = strings.TrimPrefix(devfilePath, "./") + if fileName != devfilePath { + return errors.Errorf("Folder %s contains one element and it's not the devfile used.", path) + } + } + + return nil +} + +// Converts Git ssh remote to https +func ConvertGitSSHRemoteToHTTPS(remote string) string { + remote = strings.Replace(remote, ":", "/", 1) + remote = strings.Replace(remote, "git@", "https://", 1) + return remote +} + +// GetAndExtractZip downloads a zip file from a URL with a http prefix or +// takes an absolute path prefixed with file:// and extracts it to a destination. +// pathToUnzip specifies the path within the zip folder to extract +func GetAndExtractZip(zipURL string, destination string, pathToUnzip string) error { + if zipURL == "" { + return errors.Errorf("Empty zip url: %s", zipURL) + } + if !strings.Contains(zipURL, ".zip") { + return errors.Errorf("Invalid zip url: %s", zipURL) + } + + var pathToZip string + if strings.HasPrefix(zipURL, "file://") { + pathToZip = strings.TrimPrefix(zipURL, "file:/") + if runtime.GOOS == "windows" { + pathToZip = strings.Replace(pathToZip, "\\", "/", -1) + } + } else if strings.HasPrefix(zipURL, "http://") || strings.HasPrefix(zipURL, "https://") { + // Generate temporary zip file location + time := time.Now().Format(time.RFC3339) + time = strings.Replace(time, ":", "-", -1) // ":" is illegal char in windows + pathToZip = path.Join(os.TempDir(), "_"+time+".zip") + + params := DownloadParams{ + Request: HTTPRequestParams{ + URL: zipURL, + }, + Filepath: pathToZip, + } + err := DownloadFile(params) + if err != nil { + return err + } + + defer func() { + if err := DeletePath(pathToZip); err != nil { + klog.Errorf("Could not delete temporary directory for zip file. Error: %s", err) + } + }() + } else { + return errors.Errorf("Invalid Zip URL: %s . Should either be prefixed with file://, http:// or https://", zipURL) + } + + filenames, err := Unzip(pathToZip, destination, pathToUnzip) + if err != nil { + return err + } + + if len(filenames) == 0 { + return errors.New("no files were unzipped, ensure that the project repo is not empty or that sparseCheckoutDir has a valid path") + } + + return nil +} + +// Unzip will decompress a zip archive, moving specified files and folders +// within the zip file (parameter 1) to an output directory (parameter 2) +// Source: https://golangcode.com/unzip-files-in-go/ +// pathToUnzip (parameter 3) is the path within the zip folder to extract +func Unzip(src, dest, pathToUnzip string) ([]string, error) { + var filenames []string + + r, err := zip.OpenReader(src) + if err != nil { + return filenames, err + } + defer r.Close() + + // change path separator to correct character + pathToUnzip = filepath.FromSlash(pathToUnzip) + + // removes first slash of pathToUnzip if present + pathToUnzip = strings.TrimPrefix(pathToUnzip, string(os.PathSeparator)) + + for _, f := range r.File { + // Store filename/path for returning and using later on + index := strings.Index(f.Name, "/") + filename := filepath.FromSlash(f.Name[index+1:]) + if filename == "" { + continue + } + + // if sparseCheckoutDir has a pattern + match, err := filepath.Match(pathToUnzip, filename) + if err != nil { + return filenames, err + } + + // destination filepath before trim + fpath := filepath.Join(dest, filename) + + // used for pattern matching + fpathDir := filepath.Dir(fpath) + + // check for prefix or match + if strings.HasPrefix(filename, pathToUnzip) { + filename = strings.TrimPrefix(filename, pathToUnzip) + } else if !strings.HasPrefix(filename, pathToUnzip) && !match && !sliceContainsString(fpathDir, filenames) { + continue + } + // adds trailing slash to destination if needed as filepath.Join removes it + if (len(filename) == 1 && os.IsPathSeparator(filename[0])) || filename == "" { + fpath = dest + string(os.PathSeparator) + } else { + fpath = filepath.Join(dest, filename) + } + // Check for ZipSlip. More Info: http://bit.ly/2MsjAWE + if !strings.HasPrefix(fpath, filepath.Clean(dest)+string(os.PathSeparator)) { + return filenames, fmt.Errorf("%s: illegal file path", fpath) + } + + filenames = append(filenames, fpath) + + if f.FileInfo().IsDir() { + // Make Folder + if err = os.MkdirAll(fpath, os.ModePerm); err != nil { + return filenames, err + } + continue + } + + // Make File + if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil { + return filenames, err + } + + outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, ModeReadWriteFile) + if err != nil { + return filenames, err + } + + rc, err := f.Open() + if err != nil { + return filenames, err + } + + // limit the number of bytes copied from a file + // This is set to the limit of file size in Github + // which is 100MB + limited := io.LimitReader(rc, 100*1024*1024) + + _, err = io.Copy(outFile, limited) + + // Close the file without defer to close before next iteration of loop + outFile.Close() + rc.Close() + + if err != nil { + return filenames, err + } + } + return filenames, nil +} + +// DownloadFileWithCache downloads the file to the filepath given URL and token (if applicable) +// cacheFor determines how long the response should be cached (in minutes), 0 for no caching +func DownloadFileWithCache(params DownloadParams, cacheFor int) error { + // Get the data + data, err := HTTPGetRequest(params.Request, cacheFor) + if err != nil { + return err + } + + // Create the file + out, err := os.Create(params.Filepath) + if err != nil { + return err + } + defer out.Close() // #nosec G307 + + // Write the data to file + _, err = out.Write(data) + if err != nil { + return err + } + + return nil +} + +// DownloadFile downloads the file to the filepath given URL and token (if applicable) +func DownloadFile(params DownloadParams) error { + return DownloadFileWithCache(params, 0) +} + +// DownloadFileInMemory uses the url to download the file and return bytes +func DownloadFileInMemory(url string) ([]byte, error) { + var httpClient = &http.Client{Transport: &http.Transport{ + ResponseHeaderTimeout: ResponseHeaderTimeout, + }, Timeout: HTTPRequestTimeout} + resp, err := httpClient.Get(url) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + return ioutil.ReadAll(resp.Body) +} + +// ValidateK8sResourceName sanitizes kubernetes resource name with the following requirements: +// - Contain at most 63 characters +// - Contain only lowercase alphanumeric characters or ‘-’ +// - Start with an alphanumeric character +// - End with an alphanumeric character +// - Must not contain all numeric values +func ValidateK8sResourceName(key string, value string) error { + requirements := ` +- Contain at most 63 characters +- Contain only lowercase alphanumeric characters or ‘-’ +- Start with an alphanumeric character +- End with an alphanumeric character +- Must not contain all numeric values + ` + err1 := kvalidation.IsDNS1123Label(value) + _, err2 := strconv.ParseFloat(value, 64) + + if err1 != nil || err2 == nil { + return errors.Errorf("%s \"%s\" is not valid, %s should conform the following requirements: %s", key, value, key, requirements) + } + + return nil +} + +// CheckKubeConfigExist checks for existence of kubeconfig +func CheckKubeConfigExist() bool { + + var kubeconfig string + + if os.Getenv("KUBECONFIG") != "" { + kubeconfig = os.Getenv("KUBECONFIG") + } else { + home, _ := os.UserHomeDir() + kubeconfig = fmt.Sprintf("%s/.kube/config", home) + } + + if CheckPathExists(kubeconfig) { + return true + } + + return false +} + +// ValidateURL validates the URL +func ValidateURL(sourceURL string) error { + u, err := url.Parse(sourceURL) + if err != nil { + return err + } + + if len(u.Host) == 0 || len(u.Scheme) == 0 { + return errors.New("URL is invalid") + } + + return nil +} + +// ValidateFile validates the file +func ValidateFile(filePath string) error { + // Check if the file path exist + file, err := os.Stat(filePath) + if err != nil { + return err + } + + if file.IsDir() { + return errors.Errorf("%s exists but it's not a file", filePath) + } + + return nil +} + +// CopyFile copies file from source path to destination path +func CopyFile(srcPath string, dstPath string, info os.FileInfo) error { + // In order to avoid file overriding issue, do nothing if source path is equal to destination path + if PathEqual(srcPath, dstPath) { + return nil + } + // Check if the source file path exists + err := ValidateFile(srcPath) + if err != nil { + return err + } + + // Open source file + srcFile, err := os.Open(srcPath) + if err != nil { + return err + } + defer srcFile.Close() // #nosec G307 + + // Create destination file + dstFile, err := os.Create(dstPath) + if err != nil { + return err + } + defer dstFile.Close() // #nosec G307 + + // Ensure destination file has the same file mode with source file + err = os.Chmod(dstFile.Name(), info.Mode()) + if err != nil { + return err + } + + // Copy file + _, err = io.Copy(dstFile, srcFile) + if err != nil { + return err + } + + return nil +} + +// PathEqual compare the paths to determine if they are equal +func PathEqual(firstPath string, secondPath string) bool { + firstAbsPath, _ := GetAbsPath(firstPath) + secondAbsPath, _ := GetAbsPath(secondPath) + return firstAbsPath == secondAbsPath +} + +// sliceContainsString checks for existence of given string in given slice +func sliceContainsString(str string, slice []string) bool { + for _, b := range slice { + if b == str { + return true + } + } + return false +} + +// AddFileToIgnoreFile adds a file to the gitignore file. It only does that if the file doesn't exist +func AddFileToIgnoreFile(gitIgnoreFile, filename string) error { + return addFileToIgnoreFile(gitIgnoreFile, filename, filesystem.DefaultFs{}) +} + +func addFileToIgnoreFile(gitIgnoreFile, filename string, fs filesystem.Filesystem) error { + var data []byte + file, err := fs.OpenFile(gitIgnoreFile, os.O_APPEND|os.O_RDWR, ModeReadWriteFile) + if err != nil { + return errors.Wrap(err, "failed to open .gitignore file") + } + defer file.Close() + + if data, err = fs.ReadFile(gitIgnoreFile); err != nil { + return errors.Wrap(err, fmt.Sprintf("failed reading data from %v file", gitIgnoreFile)) + } + // check whether .odo/odo-file-index.json is already in the .gitignore file + if !strings.Contains(string(data), filename) { + if _, err := file.WriteString("\n" + filename); err != nil { + return errors.Wrapf(err, "failed to add %v to %v file", filepath.Base(filename), gitIgnoreFile) + } + } + return nil +} + +// DisplayLog displays logs to user stdout with some color formatting +func DisplayLog(followLog bool, rd io.ReadCloser, compName string) (err error) { + + defer rd.Close() + + // Copy to stdout (in yellow) + color.Set(color.FgYellow) + defer color.Unset() + + // If we are going to followLog, we'll be copying it to stdout + // else, we copy it to a buffer + if followLog { + + c := make(chan os.Signal) + signal.Notify(c, os.Interrupt, syscall.SIGTERM) + go func() { + <-c + color.Unset() + os.Exit(1) + }() + + if _, err = io.Copy(os.Stdout, rd); err != nil { + return errors.Wrapf(err, "error followLoging logs for %s", compName) + } + + } else { + + // Copy to buffer (we aren't going to be followLoging the logs..) + buf := new(bytes.Buffer) + _, err = io.Copy(buf, rd) + if err != nil { + return errors.Wrapf(err, "unable to copy followLog to buffer") + } + + // Copy to stdout + if _, err = io.Copy(os.Stdout, buf); err != nil { + return errors.Wrapf(err, "error copying logs to stdout") + } + + } + return + +} diff --git a/vendor/github.com/hashicorp/go-multierror/.travis.yml b/vendor/github.com/hashicorp/go-multierror/.travis.yml index 304a83595..24b80388f 100644 --- a/vendor/github.com/hashicorp/go-multierror/.travis.yml +++ b/vendor/github.com/hashicorp/go-multierror/.travis.yml @@ -9,4 +9,4 @@ branches: only: - master -script: make test testrace +script: env GO111MODULE=on make test testrace diff --git a/vendor/github.com/hashicorp/go-multierror/README.md b/vendor/github.com/hashicorp/go-multierror/README.md index ead5830f7..e92fa614c 100644 --- a/vendor/github.com/hashicorp/go-multierror/README.md +++ b/vendor/github.com/hashicorp/go-multierror/README.md @@ -14,9 +14,10 @@ be a list of errors. If the caller knows this, they can unwrap the list and access the errors. If the caller doesn't know, the error formats to a nice human-readable format. -`go-multierror` implements the -[errwrap](https://github.com/hashicorp/errwrap) interface so that it can -be used with that library, as well. +`go-multierror` is fully compatible with the Go standard library +[errors](https://golang.org/pkg/errors/) package, including the +functions `As`, `Is`, and `Unwrap`. This provides a standardized approach +for introspecting on error values. ## Installation and Docs @@ -81,6 +82,39 @@ if err := something(); err != nil { } ``` +You can also use the standard [`errors.Unwrap`](https://golang.org/pkg/errors/#Unwrap) +function. This will continue to unwrap into subsequent errors until none exist. + +**Extracting an error** + +The standard library [`errors.As`](https://golang.org/pkg/errors/#As) +function can be used directly with a multierror to extract a specific error: + +```go +// Assume err is a multierror value +err := somefunc() + +// We want to know if "err" has a "RichErrorType" in it and extract it. +var errRich RichErrorType +if errors.As(err, &errRich) { + // It has it, and now errRich is populated. +} +``` + +**Checking for an exact error value** + +Some errors are returned as exact errors such as the [`ErrNotExist`](https://golang.org/pkg/os/#pkg-variables) +error in the `os` package. You can check if this error is present by using +the standard [`errors.Is`](https://golang.org/pkg/errors/#Is) function. + +```go +// Assume err is a multierror value +err := somefunc() +if errors.Is(err, os.ErrNotExist) { + // err contains os.ErrNotExist +} +``` + **Returning a multierror only if there are errors** If you build a `multierror.Error`, you can use the `ErrorOrNil` function diff --git a/vendor/github.com/hashicorp/go-multierror/go.mod b/vendor/github.com/hashicorp/go-multierror/go.mod index 2534331d5..0afe8e6f9 100644 --- a/vendor/github.com/hashicorp/go-multierror/go.mod +++ b/vendor/github.com/hashicorp/go-multierror/go.mod @@ -1,3 +1,5 @@ module github.com/hashicorp/go-multierror +go 1.14 + require github.com/hashicorp/errwrap v1.0.0 diff --git a/vendor/github.com/hashicorp/go-multierror/go.sum b/vendor/github.com/hashicorp/go-multierror/go.sum index 85b1f8ff3..e8238e9ec 100644 --- a/vendor/github.com/hashicorp/go-multierror/go.sum +++ b/vendor/github.com/hashicorp/go-multierror/go.sum @@ -1,4 +1,2 @@ -github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce h1:prjrVgOk2Yg6w+PflHoszQNLTUh4kaByUcEWM/9uin4= -github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= diff --git a/vendor/github.com/hashicorp/go-multierror/group.go b/vendor/github.com/hashicorp/go-multierror/group.go new file mode 100644 index 000000000..9c29efb7f --- /dev/null +++ b/vendor/github.com/hashicorp/go-multierror/group.go @@ -0,0 +1,38 @@ +package multierror + +import "sync" + +// Group is a collection of goroutines which return errors that need to be +// coalesced. +type Group struct { + mutex sync.Mutex + err *Error + wg sync.WaitGroup +} + +// Go calls the given function in a new goroutine. +// +// If the function returns an error it is added to the group multierror which +// is returned by Wait. +func (g *Group) Go(f func() error) { + g.wg.Add(1) + + go func() { + defer g.wg.Done() + + if err := f(); err != nil { + g.mutex.Lock() + g.err = Append(g.err, err) + g.mutex.Unlock() + } + }() +} + +// Wait blocks until all function calls from the Go method have returned, then +// returns the multierror. +func (g *Group) Wait() *Error { + g.wg.Wait() + g.mutex.Lock() + defer g.mutex.Unlock() + return g.err +} diff --git a/vendor/github.com/hashicorp/go-multierror/multierror.go b/vendor/github.com/hashicorp/go-multierror/multierror.go index 89b1422d1..d05dd9269 100644 --- a/vendor/github.com/hashicorp/go-multierror/multierror.go +++ b/vendor/github.com/hashicorp/go-multierror/multierror.go @@ -1,6 +1,7 @@ package multierror import ( + "errors" "fmt" ) @@ -49,3 +50,69 @@ func (e *Error) GoString() string { func (e *Error) WrappedErrors() []error { return e.Errors } + +// Unwrap returns an error from Error (or nil if there are no errors). +// This error returned will further support Unwrap to get the next error, +// etc. The order will match the order of Errors in the multierror.Error +// at the time of calling. +// +// The resulting error supports errors.As/Is/Unwrap so you can continue +// to use the stdlib errors package to introspect further. +// +// This will perform a shallow copy of the errors slice. Any errors appended +// to this error after calling Unwrap will not be available until a new +// Unwrap is called on the multierror.Error. +func (e *Error) Unwrap() error { + // If we have no errors then we do nothing + if e == nil || len(e.Errors) == 0 { + return nil + } + + // If we have exactly one error, we can just return that directly. + if len(e.Errors) == 1 { + return e.Errors[0] + } + + // Shallow copy the slice + errs := make([]error, len(e.Errors)) + copy(errs, e.Errors) + return chain(errs) +} + +// chain implements the interfaces necessary for errors.Is/As/Unwrap to +// work in a deterministic way with multierror. A chain tracks a list of +// errors while accounting for the current represented error. This lets +// Is/As be meaningful. +// +// Unwrap returns the next error. In the cleanest form, Unwrap would return +// the wrapped error here but we can't do that if we want to properly +// get access to all the errors. Instead, users are recommended to use +// Is/As to get the correct error type out. +// +// Precondition: []error is non-empty (len > 0) +type chain []error + +// Error implements the error interface +func (e chain) Error() string { + return e[0].Error() +} + +// Unwrap implements errors.Unwrap by returning the next error in the +// chain or nil if there are no more errors. +func (e chain) Unwrap() error { + if len(e) == 1 { + return nil + } + + return e[1:] +} + +// As implements errors.As by attempting to map to the current value. +func (e chain) As(target interface{}) bool { + return errors.As(e[0], target) +} + +// Is implements errors.Is by comparing the current value directly. +func (e chain) Is(target error) bool { + return errors.Is(e[0], target) +} diff --git a/vendor/github.com/json-iterator/go/reflect_extension.go b/vendor/github.com/json-iterator/go/reflect_extension.go index e27e8d191..80320cd64 100644 --- a/vendor/github.com/json-iterator/go/reflect_extension.go +++ b/vendor/github.com/json-iterator/go/reflect_extension.go @@ -341,7 +341,7 @@ func describeStruct(ctx *ctx, typ reflect2.Type) *StructDescriptor { if ctx.onlyTaggedField && !hastag && !field.Anonymous() { continue } - if tag == "-" { + if tag == "-" || field.Name() == "_" { continue } tagParts := strings.Split(tag, ",") diff --git a/vendor/github.com/json-iterator/go/reflect_map.go b/vendor/github.com/json-iterator/go/reflect_map.go index 08e9a3912..9e2b623fe 100644 --- a/vendor/github.com/json-iterator/go/reflect_map.go +++ b/vendor/github.com/json-iterator/go/reflect_map.go @@ -290,16 +290,17 @@ func (encoder *sortKeysMapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { stream.WriteObjectStart() mapIter := encoder.mapType.UnsafeIterate(ptr) subStream := stream.cfg.BorrowStream(nil) + subStream.Attachment = stream.Attachment subIter := stream.cfg.BorrowIterator(nil) keyValues := encodedKeyValues{} for mapIter.HasNext() { - subStream.buf = make([]byte, 0, 64) key, elem := mapIter.UnsafeNext() + subStreamIndex := subStream.Buffered() encoder.keyEncoder.Encode(key, subStream) if subStream.Error != nil && subStream.Error != io.EOF && stream.Error == nil { stream.Error = subStream.Error } - encodedKey := subStream.Buffer() + encodedKey := subStream.Buffer()[subStreamIndex:] subIter.ResetBytes(encodedKey) decodedKey := subIter.ReadString() if stream.indention > 0 { @@ -310,7 +311,7 @@ func (encoder *sortKeysMapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { encoder.elemEncoder.Encode(elem, subStream) keyValues = append(keyValues, encodedKV{ key: decodedKey, - keyValue: subStream.Buffer(), + keyValue: subStream.Buffer()[subStreamIndex:], }) } sort.Sort(keyValues) @@ -320,6 +321,9 @@ func (encoder *sortKeysMapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { } stream.Write(keyValue.keyValue) } + if subStream.Error != nil && stream.Error == nil { + stream.Error = subStream.Error + } stream.WriteObjectEnd() stream.cfg.ReturnStream(subStream) stream.cfg.ReturnIterator(subIter) diff --git a/vendor/github.com/json-iterator/go/reflect_struct_encoder.go b/vendor/github.com/json-iterator/go/reflect_struct_encoder.go index d0759cf64..152e3ef5a 100644 --- a/vendor/github.com/json-iterator/go/reflect_struct_encoder.go +++ b/vendor/github.com/json-iterator/go/reflect_struct_encoder.go @@ -200,6 +200,7 @@ type stringModeStringEncoder struct { func (encoder *stringModeStringEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { tempStream := encoder.cfg.BorrowStream(nil) + tempStream.Attachment = stream.Attachment defer encoder.cfg.ReturnStream(tempStream) encoder.elemEncoder.Encode(ptr, tempStream) stream.WriteString(string(tempStream.Buffer())) diff --git a/vendor/github.com/stretchr/objx/.codeclimate.yml b/vendor/github.com/stretchr/objx/.codeclimate.yml deleted file mode 100644 index 559fa399c..000000000 --- a/vendor/github.com/stretchr/objx/.codeclimate.yml +++ /dev/null @@ -1,21 +0,0 @@ -engines: - gofmt: - enabled: true - golint: - enabled: true - govet: - enabled: true - -exclude_patterns: -- ".github/" -- "vendor/" -- "codegen/" -- "*.yml" -- ".*.yml" -- "*.md" -- "Gopkg.*" -- "doc.go" -- "type_specific_codegen_test.go" -- "type_specific_codegen.go" -- ".gitignore" -- "LICENSE" diff --git a/vendor/github.com/stretchr/objx/.gitignore b/vendor/github.com/stretchr/objx/.gitignore deleted file mode 100644 index ea58090bd..000000000 --- a/vendor/github.com/stretchr/objx/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -# Binaries for programs and plugins -*.exe -*.dll -*.so -*.dylib - -# Test binary, build with `go test -c` -*.test - -# Output of the go coverage tool, specifically when used with LiteIDE -*.out diff --git a/vendor/github.com/stretchr/objx/.travis.yml b/vendor/github.com/stretchr/objx/.travis.yml deleted file mode 100644 index cde6eb2af..000000000 --- a/vendor/github.com/stretchr/objx/.travis.yml +++ /dev/null @@ -1,30 +0,0 @@ -language: go -go: - - "1.10.x" - - "1.11.x" - - "1.12.x" - - master - -matrix: - allow_failures: - - go: master -fast_finish: true - -env: - global: - - CC_TEST_REPORTER_ID=68feaa3410049ce73e145287acbcdacc525087a30627f96f04e579e75bd71c00 - -before_script: - - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter - - chmod +x ./cc-test-reporter - - ./cc-test-reporter before-build - -install: - - curl -sL https://taskfile.dev/install.sh | sh - -script: - - diff -u <(echo -n) <(./bin/task lint) - - ./bin/task test-coverage - -after_script: - - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT diff --git a/vendor/github.com/stretchr/objx/LICENSE b/vendor/github.com/stretchr/objx/LICENSE deleted file mode 100644 index 44d4d9d5a..000000000 --- a/vendor/github.com/stretchr/objx/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License - -Copyright (c) 2014 Stretchr, Inc. -Copyright (c) 2017-2018 objx contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/stretchr/objx/README.md b/vendor/github.com/stretchr/objx/README.md deleted file mode 100644 index 246660b21..000000000 --- a/vendor/github.com/stretchr/objx/README.md +++ /dev/null @@ -1,80 +0,0 @@ -# Objx -[![Build Status](https://travis-ci.org/stretchr/objx.svg?branch=master)](https://travis-ci.org/stretchr/objx) -[![Go Report Card](https://goreportcard.com/badge/github.com/stretchr/objx)](https://goreportcard.com/report/github.com/stretchr/objx) -[![Maintainability](https://api.codeclimate.com/v1/badges/1d64bc6c8474c2074f2b/maintainability)](https://codeclimate.com/github/stretchr/objx/maintainability) -[![Test Coverage](https://api.codeclimate.com/v1/badges/1d64bc6c8474c2074f2b/test_coverage)](https://codeclimate.com/github/stretchr/objx/test_coverage) -[![Sourcegraph](https://sourcegraph.com/github.com/stretchr/objx/-/badge.svg)](https://sourcegraph.com/github.com/stretchr/objx) -[![GoDoc](https://godoc.org/github.com/stretchr/objx?status.svg)](https://godoc.org/github.com/stretchr/objx) - -Objx - Go package for dealing with maps, slices, JSON and other data. - -Get started: - -- Install Objx with [one line of code](#installation), or [update it with another](#staying-up-to-date) -- Check out the API Documentation http://godoc.org/github.com/stretchr/objx - -## Overview -Objx provides the `objx.Map` type, which is a `map[string]interface{}` that exposes a powerful `Get` method (among others) that allows you to easily and quickly get access to data within the map, without having to worry too much about type assertions, missing data, default values etc. - -### Pattern -Objx uses a preditable pattern to make access data from within `map[string]interface{}` easy. Call one of the `objx.` functions to create your `objx.Map` to get going: - - m, err := objx.FromJSON(json) - -NOTE: Any methods or functions with the `Must` prefix will panic if something goes wrong, the rest will be optimistic and try to figure things out without panicking. - -Use `Get` to access the value you're interested in. You can use dot and array -notation too: - - m.Get("places[0].latlng") - -Once you have sought the `Value` you're interested in, you can use the `Is*` methods to determine its type. - - if m.Get("code").IsStr() { // Your code... } - -Or you can just assume the type, and use one of the strong type methods to extract the real value: - - m.Get("code").Int() - -If there's no value there (or if it's the wrong type) then a default value will be returned, or you can be explicit about the default value. - - Get("code").Int(-1) - -If you're dealing with a slice of data as a value, Objx provides many useful methods for iterating, manipulating and selecting that data. You can find out more by exploring the index below. - -### Reading data -A simple example of how to use Objx: - - // Use MustFromJSON to make an objx.Map from some JSON - m := objx.MustFromJSON(`{"name": "Mat", "age": 30}`) - - // Get the details - name := m.Get("name").Str() - age := m.Get("age").Int() - - // Get their nickname (or use their name if they don't have one) - nickname := m.Get("nickname").Str(name) - -### Ranging -Since `objx.Map` is a `map[string]interface{}` you can treat it as such. For example, to `range` the data, do what you would expect: - - m := objx.MustFromJSON(json) - for key, value := range m { - // Your code... - } - -## Installation -To install Objx, use go get: - - go get github.com/stretchr/objx - -### Staying up to date -To update Objx to the latest version, run: - - go get -u github.com/stretchr/objx - -### Supported go versions -We support the lastest three major Go versions, which are 1.10, 1.11 and 1.12 at the moment. - -## Contributing -Please feel free to submit issues, fork the repository and send pull requests! diff --git a/vendor/github.com/stretchr/objx/Taskfile.yml b/vendor/github.com/stretchr/objx/Taskfile.yml deleted file mode 100644 index a749ac549..000000000 --- a/vendor/github.com/stretchr/objx/Taskfile.yml +++ /dev/null @@ -1,30 +0,0 @@ -version: '2' - -env: - GOFLAGS: -mod=vendor - -tasks: - default: - deps: [test] - - lint: - desc: Checks code style - cmds: - - gofmt -d -s *.go - - go vet ./... - silent: true - - lint-fix: - desc: Fixes code style - cmds: - - gofmt -w -s *.go - - test: - desc: Runs go tests - cmds: - - go test -race ./... - - test-coverage: - desc: Runs go tests and calucates test coverage - cmds: - - go test -race -coverprofile=c.out ./... diff --git a/vendor/github.com/stretchr/objx/accessors.go b/vendor/github.com/stretchr/objx/accessors.go deleted file mode 100644 index 676316281..000000000 --- a/vendor/github.com/stretchr/objx/accessors.go +++ /dev/null @@ -1,119 +0,0 @@ -package objx - -import ( - "regexp" - "strconv" - "strings" -) - -const ( - // PathSeparator is the character used to separate the elements - // of the keypath. - // - // For example, `location.address.city` - PathSeparator string = "." - - // arrayAccesRegexString is the regex used to extract the array number - // from the access path - arrayAccesRegexString = `^(.+)\[([0-9]+)\]$` -) - -// arrayAccesRegex is the compiled arrayAccesRegexString -var arrayAccesRegex = regexp.MustCompile(arrayAccesRegexString) - -// Get gets the value using the specified selector and -// returns it inside a new Obj object. -// -// If it cannot find the value, Get will return a nil -// value inside an instance of Obj. -// -// Get can only operate directly on map[string]interface{} and []interface. -// -// Example -// -// To access the title of the third chapter of the second book, do: -// -// o.Get("books[1].chapters[2].title") -func (m Map) Get(selector string) *Value { - rawObj := access(m, selector, nil, false) - return &Value{data: rawObj} -} - -// Set sets the value using the specified selector and -// returns the object on which Set was called. -// -// Set can only operate directly on map[string]interface{} and []interface -// -// Example -// -// To set the title of the third chapter of the second book, do: -// -// o.Set("books[1].chapters[2].title","Time to Go") -func (m Map) Set(selector string, value interface{}) Map { - access(m, selector, value, true) - return m -} - -// getIndex returns the index, which is hold in s by two braches. -// It also returns s withour the index part, e.g. name[1] will return (1, name). -// If no index is found, -1 is returned -func getIndex(s string) (int, string) { - arrayMatches := arrayAccesRegex.FindStringSubmatch(s) - if len(arrayMatches) > 0 { - // Get the key into the map - selector := arrayMatches[1] - // Get the index into the array at the key - // We know this cannt fail because arrayMatches[2] is an int for sure - index, _ := strconv.Atoi(arrayMatches[2]) - return index, selector - } - return -1, s -} - -// access accesses the object using the selector and performs the -// appropriate action. -func access(current interface{}, selector string, value interface{}, isSet bool) interface{} { - selSegs := strings.SplitN(selector, PathSeparator, 2) - thisSel := selSegs[0] - index := -1 - - if strings.Contains(thisSel, "[") { - index, thisSel = getIndex(thisSel) - } - - if curMap, ok := current.(Map); ok { - current = map[string]interface{}(curMap) - } - // get the object in question - switch current.(type) { - case map[string]interface{}: - curMSI := current.(map[string]interface{}) - if len(selSegs) <= 1 && isSet { - curMSI[thisSel] = value - return nil - } - - _, ok := curMSI[thisSel].(map[string]interface{}) - if (curMSI[thisSel] == nil || !ok) && index == -1 && isSet { - curMSI[thisSel] = map[string]interface{}{} - } - - current = curMSI[thisSel] - default: - current = nil - } - // do we need to access the item of an array? - if index > -1 { - if array, ok := current.([]interface{}); ok { - if index < len(array) { - current = array[index] - } else { - current = nil - } - } - } - if len(selSegs) > 1 { - current = access(current, selSegs[1], value, isSet) - } - return current -} diff --git a/vendor/github.com/stretchr/objx/conversions.go b/vendor/github.com/stretchr/objx/conversions.go deleted file mode 100644 index 080aa46e4..000000000 --- a/vendor/github.com/stretchr/objx/conversions.go +++ /dev/null @@ -1,280 +0,0 @@ -package objx - -import ( - "bytes" - "encoding/base64" - "encoding/json" - "errors" - "fmt" - "net/url" - "strconv" -) - -// SignatureSeparator is the character that is used to -// separate the Base64 string from the security signature. -const SignatureSeparator = "_" - -// URLValuesSliceKeySuffix is the character that is used to -// specify a suffic for slices parsed by URLValues. -// If the suffix is set to "[i]", then the index of the slice -// is used in place of i -// Ex: Suffix "[]" would have the form a[]=b&a[]=c -// OR Suffix "[i]" would have the form a[0]=b&a[1]=c -// OR Suffix "" would have the form a=b&a=c -var urlValuesSliceKeySuffix = "[]" - -const ( - URLValuesSliceKeySuffixEmpty = "" - URLValuesSliceKeySuffixArray = "[]" - URLValuesSliceKeySuffixIndex = "[i]" -) - -// SetURLValuesSliceKeySuffix sets the character that is used to -// specify a suffic for slices parsed by URLValues. -// If the suffix is set to "[i]", then the index of the slice -// is used in place of i -// Ex: Suffix "[]" would have the form a[]=b&a[]=c -// OR Suffix "[i]" would have the form a[0]=b&a[1]=c -// OR Suffix "" would have the form a=b&a=c -func SetURLValuesSliceKeySuffix(s string) error { - if s == URLValuesSliceKeySuffixEmpty || s == URLValuesSliceKeySuffixArray || s == URLValuesSliceKeySuffixIndex { - urlValuesSliceKeySuffix = s - return nil - } - - return errors.New("objx: Invalid URLValuesSliceKeySuffix provided.") -} - -// JSON converts the contained object to a JSON string -// representation -func (m Map) JSON() (string, error) { - for k, v := range m { - m[k] = cleanUp(v) - } - - result, err := json.Marshal(m) - if err != nil { - err = errors.New("objx: JSON encode failed with: " + err.Error()) - } - return string(result), err -} - -func cleanUpInterfaceArray(in []interface{}) []interface{} { - result := make([]interface{}, len(in)) - for i, v := range in { - result[i] = cleanUp(v) - } - return result -} - -func cleanUpInterfaceMap(in map[interface{}]interface{}) Map { - result := Map{} - for k, v := range in { - result[fmt.Sprintf("%v", k)] = cleanUp(v) - } - return result -} - -func cleanUpStringMap(in map[string]interface{}) Map { - result := Map{} - for k, v := range in { - result[k] = cleanUp(v) - } - return result -} - -func cleanUpMSIArray(in []map[string]interface{}) []Map { - result := make([]Map, len(in)) - for i, v := range in { - result[i] = cleanUpStringMap(v) - } - return result -} - -func cleanUpMapArray(in []Map) []Map { - result := make([]Map, len(in)) - for i, v := range in { - result[i] = cleanUpStringMap(v) - } - return result -} - -func cleanUp(v interface{}) interface{} { - switch v := v.(type) { - case []interface{}: - return cleanUpInterfaceArray(v) - case []map[string]interface{}: - return cleanUpMSIArray(v) - case map[interface{}]interface{}: - return cleanUpInterfaceMap(v) - case Map: - return cleanUpStringMap(v) - case []Map: - return cleanUpMapArray(v) - default: - return v - } -} - -// MustJSON converts the contained object to a JSON string -// representation and panics if there is an error -func (m Map) MustJSON() string { - result, err := m.JSON() - if err != nil { - panic(err.Error()) - } - return result -} - -// Base64 converts the contained object to a Base64 string -// representation of the JSON string representation -func (m Map) Base64() (string, error) { - var buf bytes.Buffer - - jsonData, err := m.JSON() - if err != nil { - return "", err - } - - encoder := base64.NewEncoder(base64.StdEncoding, &buf) - _, _ = encoder.Write([]byte(jsonData)) - _ = encoder.Close() - - return buf.String(), nil -} - -// MustBase64 converts the contained object to a Base64 string -// representation of the JSON string representation and panics -// if there is an error -func (m Map) MustBase64() string { - result, err := m.Base64() - if err != nil { - panic(err.Error()) - } - return result -} - -// SignedBase64 converts the contained object to a Base64 string -// representation of the JSON string representation and signs it -// using the provided key. -func (m Map) SignedBase64(key string) (string, error) { - base64, err := m.Base64() - if err != nil { - return "", err - } - - sig := HashWithKey(base64, key) - return base64 + SignatureSeparator + sig, nil -} - -// MustSignedBase64 converts the contained object to a Base64 string -// representation of the JSON string representation and signs it -// using the provided key and panics if there is an error -func (m Map) MustSignedBase64(key string) string { - result, err := m.SignedBase64(key) - if err != nil { - panic(err.Error()) - } - return result -} - -/* - URL Query - ------------------------------------------------ -*/ - -// URLValues creates a url.Values object from an Obj. This -// function requires that the wrapped object be a map[string]interface{} -func (m Map) URLValues() url.Values { - vals := make(url.Values) - - m.parseURLValues(m, vals, "") - - return vals -} - -func (m Map) parseURLValues(queryMap Map, vals url.Values, key string) { - useSliceIndex := false - if urlValuesSliceKeySuffix == "[i]" { - useSliceIndex = true - } - - for k, v := range queryMap { - val := &Value{data: v} - switch { - case val.IsObjxMap(): - if key == "" { - m.parseURLValues(val.ObjxMap(), vals, k) - } else { - m.parseURLValues(val.ObjxMap(), vals, key+"["+k+"]") - } - case val.IsObjxMapSlice(): - sliceKey := k - if key != "" { - sliceKey = key + "[" + k + "]" - } - - if useSliceIndex { - for i, sv := range val.MustObjxMapSlice() { - sk := sliceKey + "[" + strconv.FormatInt(int64(i), 10) + "]" - m.parseURLValues(sv, vals, sk) - } - } else { - sliceKey = sliceKey + urlValuesSliceKeySuffix - for _, sv := range val.MustObjxMapSlice() { - m.parseURLValues(sv, vals, sliceKey) - } - } - case val.IsMSISlice(): - sliceKey := k - if key != "" { - sliceKey = key + "[" + k + "]" - } - - if useSliceIndex { - for i, sv := range val.MustMSISlice() { - sk := sliceKey + "[" + strconv.FormatInt(int64(i), 10) + "]" - m.parseURLValues(New(sv), vals, sk) - } - } else { - sliceKey = sliceKey + urlValuesSliceKeySuffix - for _, sv := range val.MustMSISlice() { - m.parseURLValues(New(sv), vals, sliceKey) - } - } - case val.IsStrSlice(), val.IsBoolSlice(), - val.IsFloat32Slice(), val.IsFloat64Slice(), - val.IsIntSlice(), val.IsInt8Slice(), val.IsInt16Slice(), val.IsInt32Slice(), val.IsInt64Slice(), - val.IsUintSlice(), val.IsUint8Slice(), val.IsUint16Slice(), val.IsUint32Slice(), val.IsUint64Slice(): - - sliceKey := k - if key != "" { - sliceKey = key + "[" + k + "]" - } - - if useSliceIndex { - for i, sv := range val.StringSlice() { - sk := sliceKey + "[" + strconv.FormatInt(int64(i), 10) + "]" - vals.Set(sk, sv) - } - } else { - sliceKey = sliceKey + urlValuesSliceKeySuffix - vals[sliceKey] = val.StringSlice() - } - - default: - if key == "" { - vals.Set(k, val.String()) - } else { - vals.Set(key+"["+k+"]", val.String()) - } - } - } -} - -// URLQuery gets an encoded URL query representing the given -// Obj. This function requires that the wrapped object be a -// map[string]interface{} -func (m Map) URLQuery() (string, error) { - return m.URLValues().Encode(), nil -} diff --git a/vendor/github.com/stretchr/objx/doc.go b/vendor/github.com/stretchr/objx/doc.go deleted file mode 100644 index 6d6af1a83..000000000 --- a/vendor/github.com/stretchr/objx/doc.go +++ /dev/null @@ -1,66 +0,0 @@ -/* -Objx - Go package for dealing with maps, slices, JSON and other data. - -Overview - -Objx provides the `objx.Map` type, which is a `map[string]interface{}` that exposes -a powerful `Get` method (among others) that allows you to easily and quickly get -access to data within the map, without having to worry too much about type assertions, -missing data, default values etc. - -Pattern - -Objx uses a preditable pattern to make access data from within `map[string]interface{}` easy. -Call one of the `objx.` functions to create your `objx.Map` to get going: - - m, err := objx.FromJSON(json) - -NOTE: Any methods or functions with the `Must` prefix will panic if something goes wrong, -the rest will be optimistic and try to figure things out without panicking. - -Use `Get` to access the value you're interested in. You can use dot and array -notation too: - - m.Get("places[0].latlng") - -Once you have sought the `Value` you're interested in, you can use the `Is*` methods to determine its type. - - if m.Get("code").IsStr() { // Your code... } - -Or you can just assume the type, and use one of the strong type methods to extract the real value: - - m.Get("code").Int() - -If there's no value there (or if it's the wrong type) then a default value will be returned, -or you can be explicit about the default value. - - Get("code").Int(-1) - -If you're dealing with a slice of data as a value, Objx provides many useful methods for iterating, -manipulating and selecting that data. You can find out more by exploring the index below. - -Reading data - -A simple example of how to use Objx: - - // Use MustFromJSON to make an objx.Map from some JSON - m := objx.MustFromJSON(`{"name": "Mat", "age": 30}`) - - // Get the details - name := m.Get("name").Str() - age := m.Get("age").Int() - - // Get their nickname (or use their name if they don't have one) - nickname := m.Get("nickname").Str(name) - -Ranging - -Since `objx.Map` is a `map[string]interface{}` you can treat it as such. -For example, to `range` the data, do what you would expect: - - m := objx.MustFromJSON(json) - for key, value := range m { - // Your code... - } -*/ -package objx diff --git a/vendor/github.com/stretchr/objx/go.mod b/vendor/github.com/stretchr/objx/go.mod deleted file mode 100644 index 31ec5a7d9..000000000 --- a/vendor/github.com/stretchr/objx/go.mod +++ /dev/null @@ -1,8 +0,0 @@ -module github.com/stretchr/objx - -go 1.12 - -require ( - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/stretchr/testify v1.3.0 -) diff --git a/vendor/github.com/stretchr/objx/go.sum b/vendor/github.com/stretchr/objx/go.sum deleted file mode 100644 index 4f8984150..000000000 --- a/vendor/github.com/stretchr/objx/go.sum +++ /dev/null @@ -1,8 +0,0 @@ -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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= diff --git a/vendor/github.com/stretchr/objx/map.go b/vendor/github.com/stretchr/objx/map.go deleted file mode 100644 index 95149c06a..000000000 --- a/vendor/github.com/stretchr/objx/map.go +++ /dev/null @@ -1,228 +0,0 @@ -package objx - -import ( - "encoding/base64" - "encoding/json" - "errors" - "io/ioutil" - "net/url" - "strings" -) - -// MSIConvertable is an interface that defines methods for converting your -// custom types to a map[string]interface{} representation. -type MSIConvertable interface { - // MSI gets a map[string]interface{} (msi) representing the - // object. - MSI() map[string]interface{} -} - -// Map provides extended functionality for working with -// untyped data, in particular map[string]interface (msi). -type Map map[string]interface{} - -// Value returns the internal value instance -func (m Map) Value() *Value { - return &Value{data: m} -} - -// Nil represents a nil Map. -var Nil = New(nil) - -// New creates a new Map containing the map[string]interface{} in the data argument. -// If the data argument is not a map[string]interface, New attempts to call the -// MSI() method on the MSIConvertable interface to create one. -func New(data interface{}) Map { - if _, ok := data.(map[string]interface{}); !ok { - if converter, ok := data.(MSIConvertable); ok { - data = converter.MSI() - } else { - return nil - } - } - return Map(data.(map[string]interface{})) -} - -// MSI creates a map[string]interface{} and puts it inside a new Map. -// -// The arguments follow a key, value pattern. -// -// -// Returns nil if any key argument is non-string or if there are an odd number of arguments. -// -// Example -// -// To easily create Maps: -// -// m := objx.MSI("name", "Mat", "age", 29, "subobj", objx.MSI("active", true)) -// -// // creates an Map equivalent to -// m := objx.Map{"name": "Mat", "age": 29, "subobj": objx.Map{"active": true}} -func MSI(keyAndValuePairs ...interface{}) Map { - newMap := Map{} - keyAndValuePairsLen := len(keyAndValuePairs) - if keyAndValuePairsLen%2 != 0 { - return nil - } - for i := 0; i < keyAndValuePairsLen; i = i + 2 { - key := keyAndValuePairs[i] - value := keyAndValuePairs[i+1] - - // make sure the key is a string - keyString, keyStringOK := key.(string) - if !keyStringOK { - return nil - } - newMap[keyString] = value - } - return newMap -} - -// ****** Conversion Constructors - -// MustFromJSON creates a new Map containing the data specified in the -// jsonString. -// -// Panics if the JSON is invalid. -func MustFromJSON(jsonString string) Map { - o, err := FromJSON(jsonString) - if err != nil { - panic("objx: MustFromJSON failed with error: " + err.Error()) - } - return o -} - -// FromJSON creates a new Map containing the data specified in the -// jsonString. -// -// Returns an error if the JSON is invalid. -func FromJSON(jsonString string) (Map, error) { - var m Map - err := json.Unmarshal([]byte(jsonString), &m) - if err != nil { - return Nil, err - } - m.tryConvertFloat64() - return m, nil -} - -func (m Map) tryConvertFloat64() { - for k, v := range m { - switch v.(type) { - case float64: - f := v.(float64) - if float64(int(f)) == f { - m[k] = int(f) - } - case map[string]interface{}: - t := New(v) - t.tryConvertFloat64() - m[k] = t - case []interface{}: - m[k] = tryConvertFloat64InSlice(v.([]interface{})) - } - } -} - -func tryConvertFloat64InSlice(s []interface{}) []interface{} { - for k, v := range s { - switch v.(type) { - case float64: - f := v.(float64) - if float64(int(f)) == f { - s[k] = int(f) - } - case map[string]interface{}: - t := New(v) - t.tryConvertFloat64() - s[k] = t - case []interface{}: - s[k] = tryConvertFloat64InSlice(v.([]interface{})) - } - } - return s -} - -// FromBase64 creates a new Obj containing the data specified -// in the Base64 string. -// -// The string is an encoded JSON string returned by Base64 -func FromBase64(base64String string) (Map, error) { - decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(base64String)) - decoded, err := ioutil.ReadAll(decoder) - if err != nil { - return nil, err - } - return FromJSON(string(decoded)) -} - -// MustFromBase64 creates a new Obj containing the data specified -// in the Base64 string and panics if there is an error. -// -// The string is an encoded JSON string returned by Base64 -func MustFromBase64(base64String string) Map { - result, err := FromBase64(base64String) - if err != nil { - panic("objx: MustFromBase64 failed with error: " + err.Error()) - } - return result -} - -// FromSignedBase64 creates a new Obj containing the data specified -// in the Base64 string. -// -// The string is an encoded JSON string returned by SignedBase64 -func FromSignedBase64(base64String, key string) (Map, error) { - parts := strings.Split(base64String, SignatureSeparator) - if len(parts) != 2 { - return nil, errors.New("objx: Signed base64 string is malformed") - } - - sig := HashWithKey(parts[0], key) - if parts[1] != sig { - return nil, errors.New("objx: Signature for base64 data does not match") - } - return FromBase64(parts[0]) -} - -// MustFromSignedBase64 creates a new Obj containing the data specified -// in the Base64 string and panics if there is an error. -// -// The string is an encoded JSON string returned by Base64 -func MustFromSignedBase64(base64String, key string) Map { - result, err := FromSignedBase64(base64String, key) - if err != nil { - panic("objx: MustFromSignedBase64 failed with error: " + err.Error()) - } - return result -} - -// FromURLQuery generates a new Obj by parsing the specified -// query. -// -// For queries with multiple values, the first value is selected. -func FromURLQuery(query string) (Map, error) { - vals, err := url.ParseQuery(query) - if err != nil { - return nil, err - } - m := Map{} - for k, vals := range vals { - m[k] = vals[0] - } - return m, nil -} - -// MustFromURLQuery generates a new Obj by parsing the specified -// query. -// -// For queries with multiple values, the first value is selected. -// -// Panics if it encounters an error -func MustFromURLQuery(query string) Map { - o, err := FromURLQuery(query) - if err != nil { - panic("objx: MustFromURLQuery failed with error: " + err.Error()) - } - return o -} diff --git a/vendor/github.com/stretchr/objx/mutations.go b/vendor/github.com/stretchr/objx/mutations.go deleted file mode 100644 index c3400a3f7..000000000 --- a/vendor/github.com/stretchr/objx/mutations.go +++ /dev/null @@ -1,77 +0,0 @@ -package objx - -// Exclude returns a new Map with the keys in the specified []string -// excluded. -func (m Map) Exclude(exclude []string) Map { - excluded := make(Map) - for k, v := range m { - if !contains(exclude, k) { - excluded[k] = v - } - } - return excluded -} - -// Copy creates a shallow copy of the Obj. -func (m Map) Copy() Map { - copied := Map{} - for k, v := range m { - copied[k] = v - } - return copied -} - -// Merge blends the specified map with a copy of this map and returns the result. -// -// Keys that appear in both will be selected from the specified map. -// This method requires that the wrapped object be a map[string]interface{} -func (m Map) Merge(merge Map) Map { - return m.Copy().MergeHere(merge) -} - -// MergeHere blends the specified map with this map and returns the current map. -// -// Keys that appear in both will be selected from the specified map. The original map -// will be modified. This method requires that -// the wrapped object be a map[string]interface{} -func (m Map) MergeHere(merge Map) Map { - for k, v := range merge { - m[k] = v - } - return m -} - -// Transform builds a new Obj giving the transformer a chance -// to change the keys and values as it goes. This method requires that -// the wrapped object be a map[string]interface{} -func (m Map) Transform(transformer func(key string, value interface{}) (string, interface{})) Map { - newMap := Map{} - for k, v := range m { - modifiedKey, modifiedVal := transformer(k, v) - newMap[modifiedKey] = modifiedVal - } - return newMap -} - -// TransformKeys builds a new map using the specified key mapping. -// -// Unspecified keys will be unaltered. -// This method requires that the wrapped object be a map[string]interface{} -func (m Map) TransformKeys(mapping map[string]string) Map { - return m.Transform(func(key string, value interface{}) (string, interface{}) { - if newKey, ok := mapping[key]; ok { - return newKey, value - } - return key, value - }) -} - -// Checks if a string slice contains a string -func contains(s []string, e string) bool { - for _, a := range s { - if a == e { - return true - } - } - return false -} diff --git a/vendor/github.com/stretchr/objx/security.go b/vendor/github.com/stretchr/objx/security.go deleted file mode 100644 index 692be8e2a..000000000 --- a/vendor/github.com/stretchr/objx/security.go +++ /dev/null @@ -1,12 +0,0 @@ -package objx - -import ( - "crypto/sha1" - "encoding/hex" -) - -// HashWithKey hashes the specified string using the security key -func HashWithKey(data, key string) string { - d := sha1.Sum([]byte(data + ":" + key)) - return hex.EncodeToString(d[:]) -} diff --git a/vendor/github.com/stretchr/objx/tests.go b/vendor/github.com/stretchr/objx/tests.go deleted file mode 100644 index d9e0b479a..000000000 --- a/vendor/github.com/stretchr/objx/tests.go +++ /dev/null @@ -1,17 +0,0 @@ -package objx - -// Has gets whether there is something at the specified selector -// or not. -// -// If m is nil, Has will always return false. -func (m Map) Has(selector string) bool { - if m == nil { - return false - } - return !m.Get(selector).IsNil() -} - -// IsNil gets whether the data is nil or not. -func (v *Value) IsNil() bool { - return v == nil || v.data == nil -} diff --git a/vendor/github.com/stretchr/objx/type_specific.go b/vendor/github.com/stretchr/objx/type_specific.go deleted file mode 100644 index 80f88d9fa..000000000 --- a/vendor/github.com/stretchr/objx/type_specific.go +++ /dev/null @@ -1,346 +0,0 @@ -package objx - -/* - MSI (map[string]interface{} and []map[string]interface{}) -*/ - -// MSI gets the value as a map[string]interface{}, returns the optionalDefault -// value or a system default object if the value is the wrong type. -func (v *Value) MSI(optionalDefault ...map[string]interface{}) map[string]interface{} { - if s, ok := v.data.(map[string]interface{}); ok { - return s - } - if s, ok := v.data.(Map); ok { - return map[string]interface{}(s) - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return nil -} - -// MustMSI gets the value as a map[string]interface{}. -// -// Panics if the object is not a map[string]interface{}. -func (v *Value) MustMSI() map[string]interface{} { - if s, ok := v.data.(Map); ok { - return map[string]interface{}(s) - } - return v.data.(map[string]interface{}) -} - -// MSISlice gets the value as a []map[string]interface{}, returns the optionalDefault -// value or nil if the value is not a []map[string]interface{}. -func (v *Value) MSISlice(optionalDefault ...[]map[string]interface{}) []map[string]interface{} { - if s, ok := v.data.([]map[string]interface{}); ok { - return s - } - - s := v.ObjxMapSlice() - if s == nil { - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return nil - } - - result := make([]map[string]interface{}, len(s)) - for i := range s { - result[i] = s[i].Value().MSI() - } - return result -} - -// MustMSISlice gets the value as a []map[string]interface{}. -// -// Panics if the object is not a []map[string]interface{}. -func (v *Value) MustMSISlice() []map[string]interface{} { - if s := v.MSISlice(); s != nil { - return s - } - - return v.data.([]map[string]interface{}) -} - -// IsMSI gets whether the object contained is a map[string]interface{} or not. -func (v *Value) IsMSI() bool { - _, ok := v.data.(map[string]interface{}) - if !ok { - _, ok = v.data.(Map) - } - return ok -} - -// IsMSISlice gets whether the object contained is a []map[string]interface{} or not. -func (v *Value) IsMSISlice() bool { - _, ok := v.data.([]map[string]interface{}) - if !ok { - _, ok = v.data.([]Map) - if !ok { - s, ok := v.data.([]interface{}) - if ok { - for i := range s { - switch s[i].(type) { - case Map: - case map[string]interface{}: - default: - return false - } - } - return true - } - } - } - return ok -} - -// EachMSI calls the specified callback for each object -// in the []map[string]interface{}. -// -// Panics if the object is the wrong type. -func (v *Value) EachMSI(callback func(int, map[string]interface{}) bool) *Value { - for index, val := range v.MustMSISlice() { - carryon := callback(index, val) - if !carryon { - break - } - } - return v -} - -// WhereMSI uses the specified decider function to select items -// from the []map[string]interface{}. The object contained in the result will contain -// only the selected items. -func (v *Value) WhereMSI(decider func(int, map[string]interface{}) bool) *Value { - var selected []map[string]interface{} - v.EachMSI(func(index int, val map[string]interface{}) bool { - shouldSelect := decider(index, val) - if !shouldSelect { - selected = append(selected, val) - } - return true - }) - return &Value{data: selected} -} - -// GroupMSI uses the specified grouper function to group the items -// keyed by the return of the grouper. The object contained in the -// result will contain a map[string][]map[string]interface{}. -func (v *Value) GroupMSI(grouper func(int, map[string]interface{}) string) *Value { - groups := make(map[string][]map[string]interface{}) - v.EachMSI(func(index int, val map[string]interface{}) bool { - group := grouper(index, val) - if _, ok := groups[group]; !ok { - groups[group] = make([]map[string]interface{}, 0) - } - groups[group] = append(groups[group], val) - return true - }) - return &Value{data: groups} -} - -// ReplaceMSI uses the specified function to replace each map[string]interface{}s -// by iterating each item. The data in the returned result will be a -// []map[string]interface{} containing the replaced items. -func (v *Value) ReplaceMSI(replacer func(int, map[string]interface{}) map[string]interface{}) *Value { - arr := v.MustMSISlice() - replaced := make([]map[string]interface{}, len(arr)) - v.EachMSI(func(index int, val map[string]interface{}) bool { - replaced[index] = replacer(index, val) - return true - }) - return &Value{data: replaced} -} - -// CollectMSI uses the specified collector function to collect a value -// for each of the map[string]interface{}s in the slice. The data returned will be a -// []interface{}. -func (v *Value) CollectMSI(collector func(int, map[string]interface{}) interface{}) *Value { - arr := v.MustMSISlice() - collected := make([]interface{}, len(arr)) - v.EachMSI(func(index int, val map[string]interface{}) bool { - collected[index] = collector(index, val) - return true - }) - return &Value{data: collected} -} - -/* - ObjxMap ((Map) and [](Map)) -*/ - -// ObjxMap gets the value as a (Map), returns the optionalDefault -// value or a system default object if the value is the wrong type. -func (v *Value) ObjxMap(optionalDefault ...(Map)) Map { - if s, ok := v.data.((Map)); ok { - return s - } - if s, ok := v.data.(map[string]interface{}); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return New(nil) -} - -// MustObjxMap gets the value as a (Map). -// -// Panics if the object is not a (Map). -func (v *Value) MustObjxMap() Map { - if s, ok := v.data.(map[string]interface{}); ok { - return s - } - return v.data.((Map)) -} - -// ObjxMapSlice gets the value as a [](Map), returns the optionalDefault -// value or nil if the value is not a [](Map). -func (v *Value) ObjxMapSlice(optionalDefault ...[](Map)) [](Map) { - if s, ok := v.data.([]Map); ok { - return s - } - - if s, ok := v.data.([]map[string]interface{}); ok { - result := make([]Map, len(s)) - for i := range s { - result[i] = s[i] - } - return result - } - - s, ok := v.data.([]interface{}) - if !ok { - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return nil - } - - result := make([]Map, len(s)) - for i := range s { - switch s[i].(type) { - case Map: - result[i] = s[i].(Map) - case map[string]interface{}: - result[i] = New(s[i]) - default: - return nil - } - } - return result -} - -// MustObjxMapSlice gets the value as a [](Map). -// -// Panics if the object is not a [](Map). -func (v *Value) MustObjxMapSlice() [](Map) { - if s := v.ObjxMapSlice(); s != nil { - return s - } - return v.data.([](Map)) -} - -// IsObjxMap gets whether the object contained is a (Map) or not. -func (v *Value) IsObjxMap() bool { - _, ok := v.data.((Map)) - if !ok { - _, ok = v.data.(map[string]interface{}) - } - return ok -} - -// IsObjxMapSlice gets whether the object contained is a [](Map) or not. -func (v *Value) IsObjxMapSlice() bool { - _, ok := v.data.([](Map)) - if !ok { - _, ok = v.data.([]map[string]interface{}) - if !ok { - s, ok := v.data.([]interface{}) - if ok { - for i := range s { - switch s[i].(type) { - case Map: - case map[string]interface{}: - default: - return false - } - } - return true - } - } - } - - return ok -} - -// EachObjxMap calls the specified callback for each object -// in the [](Map). -// -// Panics if the object is the wrong type. -func (v *Value) EachObjxMap(callback func(int, Map) bool) *Value { - for index, val := range v.MustObjxMapSlice() { - carryon := callback(index, val) - if !carryon { - break - } - } - return v -} - -// WhereObjxMap uses the specified decider function to select items -// from the [](Map). The object contained in the result will contain -// only the selected items. -func (v *Value) WhereObjxMap(decider func(int, Map) bool) *Value { - var selected [](Map) - v.EachObjxMap(func(index int, val Map) bool { - shouldSelect := decider(index, val) - if !shouldSelect { - selected = append(selected, val) - } - return true - }) - return &Value{data: selected} -} - -// GroupObjxMap uses the specified grouper function to group the items -// keyed by the return of the grouper. The object contained in the -// result will contain a map[string][](Map). -func (v *Value) GroupObjxMap(grouper func(int, Map) string) *Value { - groups := make(map[string][](Map)) - v.EachObjxMap(func(index int, val Map) bool { - group := grouper(index, val) - if _, ok := groups[group]; !ok { - groups[group] = make([](Map), 0) - } - groups[group] = append(groups[group], val) - return true - }) - return &Value{data: groups} -} - -// ReplaceObjxMap uses the specified function to replace each (Map)s -// by iterating each item. The data in the returned result will be a -// [](Map) containing the replaced items. -func (v *Value) ReplaceObjxMap(replacer func(int, Map) Map) *Value { - arr := v.MustObjxMapSlice() - replaced := make([](Map), len(arr)) - v.EachObjxMap(func(index int, val Map) bool { - replaced[index] = replacer(index, val) - return true - }) - return &Value{data: replaced} -} - -// CollectObjxMap uses the specified collector function to collect a value -// for each of the (Map)s in the slice. The data returned will be a -// []interface{}. -func (v *Value) CollectObjxMap(collector func(int, Map) interface{}) *Value { - arr := v.MustObjxMapSlice() - collected := make([]interface{}, len(arr)) - v.EachObjxMap(func(index int, val Map) bool { - collected[index] = collector(index, val) - return true - }) - return &Value{data: collected} -} diff --git a/vendor/github.com/stretchr/objx/type_specific_codegen.go b/vendor/github.com/stretchr/objx/type_specific_codegen.go deleted file mode 100644 index 9859b407f..000000000 --- a/vendor/github.com/stretchr/objx/type_specific_codegen.go +++ /dev/null @@ -1,2251 +0,0 @@ -package objx - -/* - Inter (interface{} and []interface{}) -*/ - -// Inter gets the value as a interface{}, returns the optionalDefault -// value or a system default object if the value is the wrong type. -func (v *Value) Inter(optionalDefault ...interface{}) interface{} { - if s, ok := v.data.(interface{}); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return nil -} - -// MustInter gets the value as a interface{}. -// -// Panics if the object is not a interface{}. -func (v *Value) MustInter() interface{} { - return v.data.(interface{}) -} - -// InterSlice gets the value as a []interface{}, returns the optionalDefault -// value or nil if the value is not a []interface{}. -func (v *Value) InterSlice(optionalDefault ...[]interface{}) []interface{} { - if s, ok := v.data.([]interface{}); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return nil -} - -// MustInterSlice gets the value as a []interface{}. -// -// Panics if the object is not a []interface{}. -func (v *Value) MustInterSlice() []interface{} { - return v.data.([]interface{}) -} - -// IsInter gets whether the object contained is a interface{} or not. -func (v *Value) IsInter() bool { - _, ok := v.data.(interface{}) - return ok -} - -// IsInterSlice gets whether the object contained is a []interface{} or not. -func (v *Value) IsInterSlice() bool { - _, ok := v.data.([]interface{}) - return ok -} - -// EachInter calls the specified callback for each object -// in the []interface{}. -// -// Panics if the object is the wrong type. -func (v *Value) EachInter(callback func(int, interface{}) bool) *Value { - for index, val := range v.MustInterSlice() { - carryon := callback(index, val) - if !carryon { - break - } - } - return v -} - -// WhereInter uses the specified decider function to select items -// from the []interface{}. The object contained in the result will contain -// only the selected items. -func (v *Value) WhereInter(decider func(int, interface{}) bool) *Value { - var selected []interface{} - v.EachInter(func(index int, val interface{}) bool { - shouldSelect := decider(index, val) - if !shouldSelect { - selected = append(selected, val) - } - return true - }) - return &Value{data: selected} -} - -// GroupInter uses the specified grouper function to group the items -// keyed by the return of the grouper. The object contained in the -// result will contain a map[string][]interface{}. -func (v *Value) GroupInter(grouper func(int, interface{}) string) *Value { - groups := make(map[string][]interface{}) - v.EachInter(func(index int, val interface{}) bool { - group := grouper(index, val) - if _, ok := groups[group]; !ok { - groups[group] = make([]interface{}, 0) - } - groups[group] = append(groups[group], val) - return true - }) - return &Value{data: groups} -} - -// ReplaceInter uses the specified function to replace each interface{}s -// by iterating each item. The data in the returned result will be a -// []interface{} containing the replaced items. -func (v *Value) ReplaceInter(replacer func(int, interface{}) interface{}) *Value { - arr := v.MustInterSlice() - replaced := make([]interface{}, len(arr)) - v.EachInter(func(index int, val interface{}) bool { - replaced[index] = replacer(index, val) - return true - }) - return &Value{data: replaced} -} - -// CollectInter uses the specified collector function to collect a value -// for each of the interface{}s in the slice. The data returned will be a -// []interface{}. -func (v *Value) CollectInter(collector func(int, interface{}) interface{}) *Value { - arr := v.MustInterSlice() - collected := make([]interface{}, len(arr)) - v.EachInter(func(index int, val interface{}) bool { - collected[index] = collector(index, val) - return true - }) - return &Value{data: collected} -} - -/* - Bool (bool and []bool) -*/ - -// Bool gets the value as a bool, returns the optionalDefault -// value or a system default object if the value is the wrong type. -func (v *Value) Bool(optionalDefault ...bool) bool { - if s, ok := v.data.(bool); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return false -} - -// MustBool gets the value as a bool. -// -// Panics if the object is not a bool. -func (v *Value) MustBool() bool { - return v.data.(bool) -} - -// BoolSlice gets the value as a []bool, returns the optionalDefault -// value or nil if the value is not a []bool. -func (v *Value) BoolSlice(optionalDefault ...[]bool) []bool { - if s, ok := v.data.([]bool); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return nil -} - -// MustBoolSlice gets the value as a []bool. -// -// Panics if the object is not a []bool. -func (v *Value) MustBoolSlice() []bool { - return v.data.([]bool) -} - -// IsBool gets whether the object contained is a bool or not. -func (v *Value) IsBool() bool { - _, ok := v.data.(bool) - return ok -} - -// IsBoolSlice gets whether the object contained is a []bool or not. -func (v *Value) IsBoolSlice() bool { - _, ok := v.data.([]bool) - return ok -} - -// EachBool calls the specified callback for each object -// in the []bool. -// -// Panics if the object is the wrong type. -func (v *Value) EachBool(callback func(int, bool) bool) *Value { - for index, val := range v.MustBoolSlice() { - carryon := callback(index, val) - if !carryon { - break - } - } - return v -} - -// WhereBool uses the specified decider function to select items -// from the []bool. The object contained in the result will contain -// only the selected items. -func (v *Value) WhereBool(decider func(int, bool) bool) *Value { - var selected []bool - v.EachBool(func(index int, val bool) bool { - shouldSelect := decider(index, val) - if !shouldSelect { - selected = append(selected, val) - } - return true - }) - return &Value{data: selected} -} - -// GroupBool uses the specified grouper function to group the items -// keyed by the return of the grouper. The object contained in the -// result will contain a map[string][]bool. -func (v *Value) GroupBool(grouper func(int, bool) string) *Value { - groups := make(map[string][]bool) - v.EachBool(func(index int, val bool) bool { - group := grouper(index, val) - if _, ok := groups[group]; !ok { - groups[group] = make([]bool, 0) - } - groups[group] = append(groups[group], val) - return true - }) - return &Value{data: groups} -} - -// ReplaceBool uses the specified function to replace each bools -// by iterating each item. The data in the returned result will be a -// []bool containing the replaced items. -func (v *Value) ReplaceBool(replacer func(int, bool) bool) *Value { - arr := v.MustBoolSlice() - replaced := make([]bool, len(arr)) - v.EachBool(func(index int, val bool) bool { - replaced[index] = replacer(index, val) - return true - }) - return &Value{data: replaced} -} - -// CollectBool uses the specified collector function to collect a value -// for each of the bools in the slice. The data returned will be a -// []interface{}. -func (v *Value) CollectBool(collector func(int, bool) interface{}) *Value { - arr := v.MustBoolSlice() - collected := make([]interface{}, len(arr)) - v.EachBool(func(index int, val bool) bool { - collected[index] = collector(index, val) - return true - }) - return &Value{data: collected} -} - -/* - Str (string and []string) -*/ - -// Str gets the value as a string, returns the optionalDefault -// value or a system default object if the value is the wrong type. -func (v *Value) Str(optionalDefault ...string) string { - if s, ok := v.data.(string); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return "" -} - -// MustStr gets the value as a string. -// -// Panics if the object is not a string. -func (v *Value) MustStr() string { - return v.data.(string) -} - -// StrSlice gets the value as a []string, returns the optionalDefault -// value or nil if the value is not a []string. -func (v *Value) StrSlice(optionalDefault ...[]string) []string { - if s, ok := v.data.([]string); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return nil -} - -// MustStrSlice gets the value as a []string. -// -// Panics if the object is not a []string. -func (v *Value) MustStrSlice() []string { - return v.data.([]string) -} - -// IsStr gets whether the object contained is a string or not. -func (v *Value) IsStr() bool { - _, ok := v.data.(string) - return ok -} - -// IsStrSlice gets whether the object contained is a []string or not. -func (v *Value) IsStrSlice() bool { - _, ok := v.data.([]string) - return ok -} - -// EachStr calls the specified callback for each object -// in the []string. -// -// Panics if the object is the wrong type. -func (v *Value) EachStr(callback func(int, string) bool) *Value { - for index, val := range v.MustStrSlice() { - carryon := callback(index, val) - if !carryon { - break - } - } - return v -} - -// WhereStr uses the specified decider function to select items -// from the []string. The object contained in the result will contain -// only the selected items. -func (v *Value) WhereStr(decider func(int, string) bool) *Value { - var selected []string - v.EachStr(func(index int, val string) bool { - shouldSelect := decider(index, val) - if !shouldSelect { - selected = append(selected, val) - } - return true - }) - return &Value{data: selected} -} - -// GroupStr uses the specified grouper function to group the items -// keyed by the return of the grouper. The object contained in the -// result will contain a map[string][]string. -func (v *Value) GroupStr(grouper func(int, string) string) *Value { - groups := make(map[string][]string) - v.EachStr(func(index int, val string) bool { - group := grouper(index, val) - if _, ok := groups[group]; !ok { - groups[group] = make([]string, 0) - } - groups[group] = append(groups[group], val) - return true - }) - return &Value{data: groups} -} - -// ReplaceStr uses the specified function to replace each strings -// by iterating each item. The data in the returned result will be a -// []string containing the replaced items. -func (v *Value) ReplaceStr(replacer func(int, string) string) *Value { - arr := v.MustStrSlice() - replaced := make([]string, len(arr)) - v.EachStr(func(index int, val string) bool { - replaced[index] = replacer(index, val) - return true - }) - return &Value{data: replaced} -} - -// CollectStr uses the specified collector function to collect a value -// for each of the strings in the slice. The data returned will be a -// []interface{}. -func (v *Value) CollectStr(collector func(int, string) interface{}) *Value { - arr := v.MustStrSlice() - collected := make([]interface{}, len(arr)) - v.EachStr(func(index int, val string) bool { - collected[index] = collector(index, val) - return true - }) - return &Value{data: collected} -} - -/* - Int (int and []int) -*/ - -// Int gets the value as a int, returns the optionalDefault -// value or a system default object if the value is the wrong type. -func (v *Value) Int(optionalDefault ...int) int { - if s, ok := v.data.(int); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return 0 -} - -// MustInt gets the value as a int. -// -// Panics if the object is not a int. -func (v *Value) MustInt() int { - return v.data.(int) -} - -// IntSlice gets the value as a []int, returns the optionalDefault -// value or nil if the value is not a []int. -func (v *Value) IntSlice(optionalDefault ...[]int) []int { - if s, ok := v.data.([]int); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return nil -} - -// MustIntSlice gets the value as a []int. -// -// Panics if the object is not a []int. -func (v *Value) MustIntSlice() []int { - return v.data.([]int) -} - -// IsInt gets whether the object contained is a int or not. -func (v *Value) IsInt() bool { - _, ok := v.data.(int) - return ok -} - -// IsIntSlice gets whether the object contained is a []int or not. -func (v *Value) IsIntSlice() bool { - _, ok := v.data.([]int) - return ok -} - -// EachInt calls the specified callback for each object -// in the []int. -// -// Panics if the object is the wrong type. -func (v *Value) EachInt(callback func(int, int) bool) *Value { - for index, val := range v.MustIntSlice() { - carryon := callback(index, val) - if !carryon { - break - } - } - return v -} - -// WhereInt uses the specified decider function to select items -// from the []int. The object contained in the result will contain -// only the selected items. -func (v *Value) WhereInt(decider func(int, int) bool) *Value { - var selected []int - v.EachInt(func(index int, val int) bool { - shouldSelect := decider(index, val) - if !shouldSelect { - selected = append(selected, val) - } - return true - }) - return &Value{data: selected} -} - -// GroupInt uses the specified grouper function to group the items -// keyed by the return of the grouper. The object contained in the -// result will contain a map[string][]int. -func (v *Value) GroupInt(grouper func(int, int) string) *Value { - groups := make(map[string][]int) - v.EachInt(func(index int, val int) bool { - group := grouper(index, val) - if _, ok := groups[group]; !ok { - groups[group] = make([]int, 0) - } - groups[group] = append(groups[group], val) - return true - }) - return &Value{data: groups} -} - -// ReplaceInt uses the specified function to replace each ints -// by iterating each item. The data in the returned result will be a -// []int containing the replaced items. -func (v *Value) ReplaceInt(replacer func(int, int) int) *Value { - arr := v.MustIntSlice() - replaced := make([]int, len(arr)) - v.EachInt(func(index int, val int) bool { - replaced[index] = replacer(index, val) - return true - }) - return &Value{data: replaced} -} - -// CollectInt uses the specified collector function to collect a value -// for each of the ints in the slice. The data returned will be a -// []interface{}. -func (v *Value) CollectInt(collector func(int, int) interface{}) *Value { - arr := v.MustIntSlice() - collected := make([]interface{}, len(arr)) - v.EachInt(func(index int, val int) bool { - collected[index] = collector(index, val) - return true - }) - return &Value{data: collected} -} - -/* - Int8 (int8 and []int8) -*/ - -// Int8 gets the value as a int8, returns the optionalDefault -// value or a system default object if the value is the wrong type. -func (v *Value) Int8(optionalDefault ...int8) int8 { - if s, ok := v.data.(int8); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return 0 -} - -// MustInt8 gets the value as a int8. -// -// Panics if the object is not a int8. -func (v *Value) MustInt8() int8 { - return v.data.(int8) -} - -// Int8Slice gets the value as a []int8, returns the optionalDefault -// value or nil if the value is not a []int8. -func (v *Value) Int8Slice(optionalDefault ...[]int8) []int8 { - if s, ok := v.data.([]int8); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return nil -} - -// MustInt8Slice gets the value as a []int8. -// -// Panics if the object is not a []int8. -func (v *Value) MustInt8Slice() []int8 { - return v.data.([]int8) -} - -// IsInt8 gets whether the object contained is a int8 or not. -func (v *Value) IsInt8() bool { - _, ok := v.data.(int8) - return ok -} - -// IsInt8Slice gets whether the object contained is a []int8 or not. -func (v *Value) IsInt8Slice() bool { - _, ok := v.data.([]int8) - return ok -} - -// EachInt8 calls the specified callback for each object -// in the []int8. -// -// Panics if the object is the wrong type. -func (v *Value) EachInt8(callback func(int, int8) bool) *Value { - for index, val := range v.MustInt8Slice() { - carryon := callback(index, val) - if !carryon { - break - } - } - return v -} - -// WhereInt8 uses the specified decider function to select items -// from the []int8. The object contained in the result will contain -// only the selected items. -func (v *Value) WhereInt8(decider func(int, int8) bool) *Value { - var selected []int8 - v.EachInt8(func(index int, val int8) bool { - shouldSelect := decider(index, val) - if !shouldSelect { - selected = append(selected, val) - } - return true - }) - return &Value{data: selected} -} - -// GroupInt8 uses the specified grouper function to group the items -// keyed by the return of the grouper. The object contained in the -// result will contain a map[string][]int8. -func (v *Value) GroupInt8(grouper func(int, int8) string) *Value { - groups := make(map[string][]int8) - v.EachInt8(func(index int, val int8) bool { - group := grouper(index, val) - if _, ok := groups[group]; !ok { - groups[group] = make([]int8, 0) - } - groups[group] = append(groups[group], val) - return true - }) - return &Value{data: groups} -} - -// ReplaceInt8 uses the specified function to replace each int8s -// by iterating each item. The data in the returned result will be a -// []int8 containing the replaced items. -func (v *Value) ReplaceInt8(replacer func(int, int8) int8) *Value { - arr := v.MustInt8Slice() - replaced := make([]int8, len(arr)) - v.EachInt8(func(index int, val int8) bool { - replaced[index] = replacer(index, val) - return true - }) - return &Value{data: replaced} -} - -// CollectInt8 uses the specified collector function to collect a value -// for each of the int8s in the slice. The data returned will be a -// []interface{}. -func (v *Value) CollectInt8(collector func(int, int8) interface{}) *Value { - arr := v.MustInt8Slice() - collected := make([]interface{}, len(arr)) - v.EachInt8(func(index int, val int8) bool { - collected[index] = collector(index, val) - return true - }) - return &Value{data: collected} -} - -/* - Int16 (int16 and []int16) -*/ - -// Int16 gets the value as a int16, returns the optionalDefault -// value or a system default object if the value is the wrong type. -func (v *Value) Int16(optionalDefault ...int16) int16 { - if s, ok := v.data.(int16); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return 0 -} - -// MustInt16 gets the value as a int16. -// -// Panics if the object is not a int16. -func (v *Value) MustInt16() int16 { - return v.data.(int16) -} - -// Int16Slice gets the value as a []int16, returns the optionalDefault -// value or nil if the value is not a []int16. -func (v *Value) Int16Slice(optionalDefault ...[]int16) []int16 { - if s, ok := v.data.([]int16); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return nil -} - -// MustInt16Slice gets the value as a []int16. -// -// Panics if the object is not a []int16. -func (v *Value) MustInt16Slice() []int16 { - return v.data.([]int16) -} - -// IsInt16 gets whether the object contained is a int16 or not. -func (v *Value) IsInt16() bool { - _, ok := v.data.(int16) - return ok -} - -// IsInt16Slice gets whether the object contained is a []int16 or not. -func (v *Value) IsInt16Slice() bool { - _, ok := v.data.([]int16) - return ok -} - -// EachInt16 calls the specified callback for each object -// in the []int16. -// -// Panics if the object is the wrong type. -func (v *Value) EachInt16(callback func(int, int16) bool) *Value { - for index, val := range v.MustInt16Slice() { - carryon := callback(index, val) - if !carryon { - break - } - } - return v -} - -// WhereInt16 uses the specified decider function to select items -// from the []int16. The object contained in the result will contain -// only the selected items. -func (v *Value) WhereInt16(decider func(int, int16) bool) *Value { - var selected []int16 - v.EachInt16(func(index int, val int16) bool { - shouldSelect := decider(index, val) - if !shouldSelect { - selected = append(selected, val) - } - return true - }) - return &Value{data: selected} -} - -// GroupInt16 uses the specified grouper function to group the items -// keyed by the return of the grouper. The object contained in the -// result will contain a map[string][]int16. -func (v *Value) GroupInt16(grouper func(int, int16) string) *Value { - groups := make(map[string][]int16) - v.EachInt16(func(index int, val int16) bool { - group := grouper(index, val) - if _, ok := groups[group]; !ok { - groups[group] = make([]int16, 0) - } - groups[group] = append(groups[group], val) - return true - }) - return &Value{data: groups} -} - -// ReplaceInt16 uses the specified function to replace each int16s -// by iterating each item. The data in the returned result will be a -// []int16 containing the replaced items. -func (v *Value) ReplaceInt16(replacer func(int, int16) int16) *Value { - arr := v.MustInt16Slice() - replaced := make([]int16, len(arr)) - v.EachInt16(func(index int, val int16) bool { - replaced[index] = replacer(index, val) - return true - }) - return &Value{data: replaced} -} - -// CollectInt16 uses the specified collector function to collect a value -// for each of the int16s in the slice. The data returned will be a -// []interface{}. -func (v *Value) CollectInt16(collector func(int, int16) interface{}) *Value { - arr := v.MustInt16Slice() - collected := make([]interface{}, len(arr)) - v.EachInt16(func(index int, val int16) bool { - collected[index] = collector(index, val) - return true - }) - return &Value{data: collected} -} - -/* - Int32 (int32 and []int32) -*/ - -// Int32 gets the value as a int32, returns the optionalDefault -// value or a system default object if the value is the wrong type. -func (v *Value) Int32(optionalDefault ...int32) int32 { - if s, ok := v.data.(int32); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return 0 -} - -// MustInt32 gets the value as a int32. -// -// Panics if the object is not a int32. -func (v *Value) MustInt32() int32 { - return v.data.(int32) -} - -// Int32Slice gets the value as a []int32, returns the optionalDefault -// value or nil if the value is not a []int32. -func (v *Value) Int32Slice(optionalDefault ...[]int32) []int32 { - if s, ok := v.data.([]int32); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return nil -} - -// MustInt32Slice gets the value as a []int32. -// -// Panics if the object is not a []int32. -func (v *Value) MustInt32Slice() []int32 { - return v.data.([]int32) -} - -// IsInt32 gets whether the object contained is a int32 or not. -func (v *Value) IsInt32() bool { - _, ok := v.data.(int32) - return ok -} - -// IsInt32Slice gets whether the object contained is a []int32 or not. -func (v *Value) IsInt32Slice() bool { - _, ok := v.data.([]int32) - return ok -} - -// EachInt32 calls the specified callback for each object -// in the []int32. -// -// Panics if the object is the wrong type. -func (v *Value) EachInt32(callback func(int, int32) bool) *Value { - for index, val := range v.MustInt32Slice() { - carryon := callback(index, val) - if !carryon { - break - } - } - return v -} - -// WhereInt32 uses the specified decider function to select items -// from the []int32. The object contained in the result will contain -// only the selected items. -func (v *Value) WhereInt32(decider func(int, int32) bool) *Value { - var selected []int32 - v.EachInt32(func(index int, val int32) bool { - shouldSelect := decider(index, val) - if !shouldSelect { - selected = append(selected, val) - } - return true - }) - return &Value{data: selected} -} - -// GroupInt32 uses the specified grouper function to group the items -// keyed by the return of the grouper. The object contained in the -// result will contain a map[string][]int32. -func (v *Value) GroupInt32(grouper func(int, int32) string) *Value { - groups := make(map[string][]int32) - v.EachInt32(func(index int, val int32) bool { - group := grouper(index, val) - if _, ok := groups[group]; !ok { - groups[group] = make([]int32, 0) - } - groups[group] = append(groups[group], val) - return true - }) - return &Value{data: groups} -} - -// ReplaceInt32 uses the specified function to replace each int32s -// by iterating each item. The data in the returned result will be a -// []int32 containing the replaced items. -func (v *Value) ReplaceInt32(replacer func(int, int32) int32) *Value { - arr := v.MustInt32Slice() - replaced := make([]int32, len(arr)) - v.EachInt32(func(index int, val int32) bool { - replaced[index] = replacer(index, val) - return true - }) - return &Value{data: replaced} -} - -// CollectInt32 uses the specified collector function to collect a value -// for each of the int32s in the slice. The data returned will be a -// []interface{}. -func (v *Value) CollectInt32(collector func(int, int32) interface{}) *Value { - arr := v.MustInt32Slice() - collected := make([]interface{}, len(arr)) - v.EachInt32(func(index int, val int32) bool { - collected[index] = collector(index, val) - return true - }) - return &Value{data: collected} -} - -/* - Int64 (int64 and []int64) -*/ - -// Int64 gets the value as a int64, returns the optionalDefault -// value or a system default object if the value is the wrong type. -func (v *Value) Int64(optionalDefault ...int64) int64 { - if s, ok := v.data.(int64); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return 0 -} - -// MustInt64 gets the value as a int64. -// -// Panics if the object is not a int64. -func (v *Value) MustInt64() int64 { - return v.data.(int64) -} - -// Int64Slice gets the value as a []int64, returns the optionalDefault -// value or nil if the value is not a []int64. -func (v *Value) Int64Slice(optionalDefault ...[]int64) []int64 { - if s, ok := v.data.([]int64); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return nil -} - -// MustInt64Slice gets the value as a []int64. -// -// Panics if the object is not a []int64. -func (v *Value) MustInt64Slice() []int64 { - return v.data.([]int64) -} - -// IsInt64 gets whether the object contained is a int64 or not. -func (v *Value) IsInt64() bool { - _, ok := v.data.(int64) - return ok -} - -// IsInt64Slice gets whether the object contained is a []int64 or not. -func (v *Value) IsInt64Slice() bool { - _, ok := v.data.([]int64) - return ok -} - -// EachInt64 calls the specified callback for each object -// in the []int64. -// -// Panics if the object is the wrong type. -func (v *Value) EachInt64(callback func(int, int64) bool) *Value { - for index, val := range v.MustInt64Slice() { - carryon := callback(index, val) - if !carryon { - break - } - } - return v -} - -// WhereInt64 uses the specified decider function to select items -// from the []int64. The object contained in the result will contain -// only the selected items. -func (v *Value) WhereInt64(decider func(int, int64) bool) *Value { - var selected []int64 - v.EachInt64(func(index int, val int64) bool { - shouldSelect := decider(index, val) - if !shouldSelect { - selected = append(selected, val) - } - return true - }) - return &Value{data: selected} -} - -// GroupInt64 uses the specified grouper function to group the items -// keyed by the return of the grouper. The object contained in the -// result will contain a map[string][]int64. -func (v *Value) GroupInt64(grouper func(int, int64) string) *Value { - groups := make(map[string][]int64) - v.EachInt64(func(index int, val int64) bool { - group := grouper(index, val) - if _, ok := groups[group]; !ok { - groups[group] = make([]int64, 0) - } - groups[group] = append(groups[group], val) - return true - }) - return &Value{data: groups} -} - -// ReplaceInt64 uses the specified function to replace each int64s -// by iterating each item. The data in the returned result will be a -// []int64 containing the replaced items. -func (v *Value) ReplaceInt64(replacer func(int, int64) int64) *Value { - arr := v.MustInt64Slice() - replaced := make([]int64, len(arr)) - v.EachInt64(func(index int, val int64) bool { - replaced[index] = replacer(index, val) - return true - }) - return &Value{data: replaced} -} - -// CollectInt64 uses the specified collector function to collect a value -// for each of the int64s in the slice. The data returned will be a -// []interface{}. -func (v *Value) CollectInt64(collector func(int, int64) interface{}) *Value { - arr := v.MustInt64Slice() - collected := make([]interface{}, len(arr)) - v.EachInt64(func(index int, val int64) bool { - collected[index] = collector(index, val) - return true - }) - return &Value{data: collected} -} - -/* - Uint (uint and []uint) -*/ - -// Uint gets the value as a uint, returns the optionalDefault -// value or a system default object if the value is the wrong type. -func (v *Value) Uint(optionalDefault ...uint) uint { - if s, ok := v.data.(uint); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return 0 -} - -// MustUint gets the value as a uint. -// -// Panics if the object is not a uint. -func (v *Value) MustUint() uint { - return v.data.(uint) -} - -// UintSlice gets the value as a []uint, returns the optionalDefault -// value or nil if the value is not a []uint. -func (v *Value) UintSlice(optionalDefault ...[]uint) []uint { - if s, ok := v.data.([]uint); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return nil -} - -// MustUintSlice gets the value as a []uint. -// -// Panics if the object is not a []uint. -func (v *Value) MustUintSlice() []uint { - return v.data.([]uint) -} - -// IsUint gets whether the object contained is a uint or not. -func (v *Value) IsUint() bool { - _, ok := v.data.(uint) - return ok -} - -// IsUintSlice gets whether the object contained is a []uint or not. -func (v *Value) IsUintSlice() bool { - _, ok := v.data.([]uint) - return ok -} - -// EachUint calls the specified callback for each object -// in the []uint. -// -// Panics if the object is the wrong type. -func (v *Value) EachUint(callback func(int, uint) bool) *Value { - for index, val := range v.MustUintSlice() { - carryon := callback(index, val) - if !carryon { - break - } - } - return v -} - -// WhereUint uses the specified decider function to select items -// from the []uint. The object contained in the result will contain -// only the selected items. -func (v *Value) WhereUint(decider func(int, uint) bool) *Value { - var selected []uint - v.EachUint(func(index int, val uint) bool { - shouldSelect := decider(index, val) - if !shouldSelect { - selected = append(selected, val) - } - return true - }) - return &Value{data: selected} -} - -// GroupUint uses the specified grouper function to group the items -// keyed by the return of the grouper. The object contained in the -// result will contain a map[string][]uint. -func (v *Value) GroupUint(grouper func(int, uint) string) *Value { - groups := make(map[string][]uint) - v.EachUint(func(index int, val uint) bool { - group := grouper(index, val) - if _, ok := groups[group]; !ok { - groups[group] = make([]uint, 0) - } - groups[group] = append(groups[group], val) - return true - }) - return &Value{data: groups} -} - -// ReplaceUint uses the specified function to replace each uints -// by iterating each item. The data in the returned result will be a -// []uint containing the replaced items. -func (v *Value) ReplaceUint(replacer func(int, uint) uint) *Value { - arr := v.MustUintSlice() - replaced := make([]uint, len(arr)) - v.EachUint(func(index int, val uint) bool { - replaced[index] = replacer(index, val) - return true - }) - return &Value{data: replaced} -} - -// CollectUint uses the specified collector function to collect a value -// for each of the uints in the slice. The data returned will be a -// []interface{}. -func (v *Value) CollectUint(collector func(int, uint) interface{}) *Value { - arr := v.MustUintSlice() - collected := make([]interface{}, len(arr)) - v.EachUint(func(index int, val uint) bool { - collected[index] = collector(index, val) - return true - }) - return &Value{data: collected} -} - -/* - Uint8 (uint8 and []uint8) -*/ - -// Uint8 gets the value as a uint8, returns the optionalDefault -// value or a system default object if the value is the wrong type. -func (v *Value) Uint8(optionalDefault ...uint8) uint8 { - if s, ok := v.data.(uint8); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return 0 -} - -// MustUint8 gets the value as a uint8. -// -// Panics if the object is not a uint8. -func (v *Value) MustUint8() uint8 { - return v.data.(uint8) -} - -// Uint8Slice gets the value as a []uint8, returns the optionalDefault -// value or nil if the value is not a []uint8. -func (v *Value) Uint8Slice(optionalDefault ...[]uint8) []uint8 { - if s, ok := v.data.([]uint8); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return nil -} - -// MustUint8Slice gets the value as a []uint8. -// -// Panics if the object is not a []uint8. -func (v *Value) MustUint8Slice() []uint8 { - return v.data.([]uint8) -} - -// IsUint8 gets whether the object contained is a uint8 or not. -func (v *Value) IsUint8() bool { - _, ok := v.data.(uint8) - return ok -} - -// IsUint8Slice gets whether the object contained is a []uint8 or not. -func (v *Value) IsUint8Slice() bool { - _, ok := v.data.([]uint8) - return ok -} - -// EachUint8 calls the specified callback for each object -// in the []uint8. -// -// Panics if the object is the wrong type. -func (v *Value) EachUint8(callback func(int, uint8) bool) *Value { - for index, val := range v.MustUint8Slice() { - carryon := callback(index, val) - if !carryon { - break - } - } - return v -} - -// WhereUint8 uses the specified decider function to select items -// from the []uint8. The object contained in the result will contain -// only the selected items. -func (v *Value) WhereUint8(decider func(int, uint8) bool) *Value { - var selected []uint8 - v.EachUint8(func(index int, val uint8) bool { - shouldSelect := decider(index, val) - if !shouldSelect { - selected = append(selected, val) - } - return true - }) - return &Value{data: selected} -} - -// GroupUint8 uses the specified grouper function to group the items -// keyed by the return of the grouper. The object contained in the -// result will contain a map[string][]uint8. -func (v *Value) GroupUint8(grouper func(int, uint8) string) *Value { - groups := make(map[string][]uint8) - v.EachUint8(func(index int, val uint8) bool { - group := grouper(index, val) - if _, ok := groups[group]; !ok { - groups[group] = make([]uint8, 0) - } - groups[group] = append(groups[group], val) - return true - }) - return &Value{data: groups} -} - -// ReplaceUint8 uses the specified function to replace each uint8s -// by iterating each item. The data in the returned result will be a -// []uint8 containing the replaced items. -func (v *Value) ReplaceUint8(replacer func(int, uint8) uint8) *Value { - arr := v.MustUint8Slice() - replaced := make([]uint8, len(arr)) - v.EachUint8(func(index int, val uint8) bool { - replaced[index] = replacer(index, val) - return true - }) - return &Value{data: replaced} -} - -// CollectUint8 uses the specified collector function to collect a value -// for each of the uint8s in the slice. The data returned will be a -// []interface{}. -func (v *Value) CollectUint8(collector func(int, uint8) interface{}) *Value { - arr := v.MustUint8Slice() - collected := make([]interface{}, len(arr)) - v.EachUint8(func(index int, val uint8) bool { - collected[index] = collector(index, val) - return true - }) - return &Value{data: collected} -} - -/* - Uint16 (uint16 and []uint16) -*/ - -// Uint16 gets the value as a uint16, returns the optionalDefault -// value or a system default object if the value is the wrong type. -func (v *Value) Uint16(optionalDefault ...uint16) uint16 { - if s, ok := v.data.(uint16); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return 0 -} - -// MustUint16 gets the value as a uint16. -// -// Panics if the object is not a uint16. -func (v *Value) MustUint16() uint16 { - return v.data.(uint16) -} - -// Uint16Slice gets the value as a []uint16, returns the optionalDefault -// value or nil if the value is not a []uint16. -func (v *Value) Uint16Slice(optionalDefault ...[]uint16) []uint16 { - if s, ok := v.data.([]uint16); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return nil -} - -// MustUint16Slice gets the value as a []uint16. -// -// Panics if the object is not a []uint16. -func (v *Value) MustUint16Slice() []uint16 { - return v.data.([]uint16) -} - -// IsUint16 gets whether the object contained is a uint16 or not. -func (v *Value) IsUint16() bool { - _, ok := v.data.(uint16) - return ok -} - -// IsUint16Slice gets whether the object contained is a []uint16 or not. -func (v *Value) IsUint16Slice() bool { - _, ok := v.data.([]uint16) - return ok -} - -// EachUint16 calls the specified callback for each object -// in the []uint16. -// -// Panics if the object is the wrong type. -func (v *Value) EachUint16(callback func(int, uint16) bool) *Value { - for index, val := range v.MustUint16Slice() { - carryon := callback(index, val) - if !carryon { - break - } - } - return v -} - -// WhereUint16 uses the specified decider function to select items -// from the []uint16. The object contained in the result will contain -// only the selected items. -func (v *Value) WhereUint16(decider func(int, uint16) bool) *Value { - var selected []uint16 - v.EachUint16(func(index int, val uint16) bool { - shouldSelect := decider(index, val) - if !shouldSelect { - selected = append(selected, val) - } - return true - }) - return &Value{data: selected} -} - -// GroupUint16 uses the specified grouper function to group the items -// keyed by the return of the grouper. The object contained in the -// result will contain a map[string][]uint16. -func (v *Value) GroupUint16(grouper func(int, uint16) string) *Value { - groups := make(map[string][]uint16) - v.EachUint16(func(index int, val uint16) bool { - group := grouper(index, val) - if _, ok := groups[group]; !ok { - groups[group] = make([]uint16, 0) - } - groups[group] = append(groups[group], val) - return true - }) - return &Value{data: groups} -} - -// ReplaceUint16 uses the specified function to replace each uint16s -// by iterating each item. The data in the returned result will be a -// []uint16 containing the replaced items. -func (v *Value) ReplaceUint16(replacer func(int, uint16) uint16) *Value { - arr := v.MustUint16Slice() - replaced := make([]uint16, len(arr)) - v.EachUint16(func(index int, val uint16) bool { - replaced[index] = replacer(index, val) - return true - }) - return &Value{data: replaced} -} - -// CollectUint16 uses the specified collector function to collect a value -// for each of the uint16s in the slice. The data returned will be a -// []interface{}. -func (v *Value) CollectUint16(collector func(int, uint16) interface{}) *Value { - arr := v.MustUint16Slice() - collected := make([]interface{}, len(arr)) - v.EachUint16(func(index int, val uint16) bool { - collected[index] = collector(index, val) - return true - }) - return &Value{data: collected} -} - -/* - Uint32 (uint32 and []uint32) -*/ - -// Uint32 gets the value as a uint32, returns the optionalDefault -// value or a system default object if the value is the wrong type. -func (v *Value) Uint32(optionalDefault ...uint32) uint32 { - if s, ok := v.data.(uint32); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return 0 -} - -// MustUint32 gets the value as a uint32. -// -// Panics if the object is not a uint32. -func (v *Value) MustUint32() uint32 { - return v.data.(uint32) -} - -// Uint32Slice gets the value as a []uint32, returns the optionalDefault -// value or nil if the value is not a []uint32. -func (v *Value) Uint32Slice(optionalDefault ...[]uint32) []uint32 { - if s, ok := v.data.([]uint32); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return nil -} - -// MustUint32Slice gets the value as a []uint32. -// -// Panics if the object is not a []uint32. -func (v *Value) MustUint32Slice() []uint32 { - return v.data.([]uint32) -} - -// IsUint32 gets whether the object contained is a uint32 or not. -func (v *Value) IsUint32() bool { - _, ok := v.data.(uint32) - return ok -} - -// IsUint32Slice gets whether the object contained is a []uint32 or not. -func (v *Value) IsUint32Slice() bool { - _, ok := v.data.([]uint32) - return ok -} - -// EachUint32 calls the specified callback for each object -// in the []uint32. -// -// Panics if the object is the wrong type. -func (v *Value) EachUint32(callback func(int, uint32) bool) *Value { - for index, val := range v.MustUint32Slice() { - carryon := callback(index, val) - if !carryon { - break - } - } - return v -} - -// WhereUint32 uses the specified decider function to select items -// from the []uint32. The object contained in the result will contain -// only the selected items. -func (v *Value) WhereUint32(decider func(int, uint32) bool) *Value { - var selected []uint32 - v.EachUint32(func(index int, val uint32) bool { - shouldSelect := decider(index, val) - if !shouldSelect { - selected = append(selected, val) - } - return true - }) - return &Value{data: selected} -} - -// GroupUint32 uses the specified grouper function to group the items -// keyed by the return of the grouper. The object contained in the -// result will contain a map[string][]uint32. -func (v *Value) GroupUint32(grouper func(int, uint32) string) *Value { - groups := make(map[string][]uint32) - v.EachUint32(func(index int, val uint32) bool { - group := grouper(index, val) - if _, ok := groups[group]; !ok { - groups[group] = make([]uint32, 0) - } - groups[group] = append(groups[group], val) - return true - }) - return &Value{data: groups} -} - -// ReplaceUint32 uses the specified function to replace each uint32s -// by iterating each item. The data in the returned result will be a -// []uint32 containing the replaced items. -func (v *Value) ReplaceUint32(replacer func(int, uint32) uint32) *Value { - arr := v.MustUint32Slice() - replaced := make([]uint32, len(arr)) - v.EachUint32(func(index int, val uint32) bool { - replaced[index] = replacer(index, val) - return true - }) - return &Value{data: replaced} -} - -// CollectUint32 uses the specified collector function to collect a value -// for each of the uint32s in the slice. The data returned will be a -// []interface{}. -func (v *Value) CollectUint32(collector func(int, uint32) interface{}) *Value { - arr := v.MustUint32Slice() - collected := make([]interface{}, len(arr)) - v.EachUint32(func(index int, val uint32) bool { - collected[index] = collector(index, val) - return true - }) - return &Value{data: collected} -} - -/* - Uint64 (uint64 and []uint64) -*/ - -// Uint64 gets the value as a uint64, returns the optionalDefault -// value or a system default object if the value is the wrong type. -func (v *Value) Uint64(optionalDefault ...uint64) uint64 { - if s, ok := v.data.(uint64); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return 0 -} - -// MustUint64 gets the value as a uint64. -// -// Panics if the object is not a uint64. -func (v *Value) MustUint64() uint64 { - return v.data.(uint64) -} - -// Uint64Slice gets the value as a []uint64, returns the optionalDefault -// value or nil if the value is not a []uint64. -func (v *Value) Uint64Slice(optionalDefault ...[]uint64) []uint64 { - if s, ok := v.data.([]uint64); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return nil -} - -// MustUint64Slice gets the value as a []uint64. -// -// Panics if the object is not a []uint64. -func (v *Value) MustUint64Slice() []uint64 { - return v.data.([]uint64) -} - -// IsUint64 gets whether the object contained is a uint64 or not. -func (v *Value) IsUint64() bool { - _, ok := v.data.(uint64) - return ok -} - -// IsUint64Slice gets whether the object contained is a []uint64 or not. -func (v *Value) IsUint64Slice() bool { - _, ok := v.data.([]uint64) - return ok -} - -// EachUint64 calls the specified callback for each object -// in the []uint64. -// -// Panics if the object is the wrong type. -func (v *Value) EachUint64(callback func(int, uint64) bool) *Value { - for index, val := range v.MustUint64Slice() { - carryon := callback(index, val) - if !carryon { - break - } - } - return v -} - -// WhereUint64 uses the specified decider function to select items -// from the []uint64. The object contained in the result will contain -// only the selected items. -func (v *Value) WhereUint64(decider func(int, uint64) bool) *Value { - var selected []uint64 - v.EachUint64(func(index int, val uint64) bool { - shouldSelect := decider(index, val) - if !shouldSelect { - selected = append(selected, val) - } - return true - }) - return &Value{data: selected} -} - -// GroupUint64 uses the specified grouper function to group the items -// keyed by the return of the grouper. The object contained in the -// result will contain a map[string][]uint64. -func (v *Value) GroupUint64(grouper func(int, uint64) string) *Value { - groups := make(map[string][]uint64) - v.EachUint64(func(index int, val uint64) bool { - group := grouper(index, val) - if _, ok := groups[group]; !ok { - groups[group] = make([]uint64, 0) - } - groups[group] = append(groups[group], val) - return true - }) - return &Value{data: groups} -} - -// ReplaceUint64 uses the specified function to replace each uint64s -// by iterating each item. The data in the returned result will be a -// []uint64 containing the replaced items. -func (v *Value) ReplaceUint64(replacer func(int, uint64) uint64) *Value { - arr := v.MustUint64Slice() - replaced := make([]uint64, len(arr)) - v.EachUint64(func(index int, val uint64) bool { - replaced[index] = replacer(index, val) - return true - }) - return &Value{data: replaced} -} - -// CollectUint64 uses the specified collector function to collect a value -// for each of the uint64s in the slice. The data returned will be a -// []interface{}. -func (v *Value) CollectUint64(collector func(int, uint64) interface{}) *Value { - arr := v.MustUint64Slice() - collected := make([]interface{}, len(arr)) - v.EachUint64(func(index int, val uint64) bool { - collected[index] = collector(index, val) - return true - }) - return &Value{data: collected} -} - -/* - Uintptr (uintptr and []uintptr) -*/ - -// Uintptr gets the value as a uintptr, returns the optionalDefault -// value or a system default object if the value is the wrong type. -func (v *Value) Uintptr(optionalDefault ...uintptr) uintptr { - if s, ok := v.data.(uintptr); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return 0 -} - -// MustUintptr gets the value as a uintptr. -// -// Panics if the object is not a uintptr. -func (v *Value) MustUintptr() uintptr { - return v.data.(uintptr) -} - -// UintptrSlice gets the value as a []uintptr, returns the optionalDefault -// value or nil if the value is not a []uintptr. -func (v *Value) UintptrSlice(optionalDefault ...[]uintptr) []uintptr { - if s, ok := v.data.([]uintptr); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return nil -} - -// MustUintptrSlice gets the value as a []uintptr. -// -// Panics if the object is not a []uintptr. -func (v *Value) MustUintptrSlice() []uintptr { - return v.data.([]uintptr) -} - -// IsUintptr gets whether the object contained is a uintptr or not. -func (v *Value) IsUintptr() bool { - _, ok := v.data.(uintptr) - return ok -} - -// IsUintptrSlice gets whether the object contained is a []uintptr or not. -func (v *Value) IsUintptrSlice() bool { - _, ok := v.data.([]uintptr) - return ok -} - -// EachUintptr calls the specified callback for each object -// in the []uintptr. -// -// Panics if the object is the wrong type. -func (v *Value) EachUintptr(callback func(int, uintptr) bool) *Value { - for index, val := range v.MustUintptrSlice() { - carryon := callback(index, val) - if !carryon { - break - } - } - return v -} - -// WhereUintptr uses the specified decider function to select items -// from the []uintptr. The object contained in the result will contain -// only the selected items. -func (v *Value) WhereUintptr(decider func(int, uintptr) bool) *Value { - var selected []uintptr - v.EachUintptr(func(index int, val uintptr) bool { - shouldSelect := decider(index, val) - if !shouldSelect { - selected = append(selected, val) - } - return true - }) - return &Value{data: selected} -} - -// GroupUintptr uses the specified grouper function to group the items -// keyed by the return of the grouper. The object contained in the -// result will contain a map[string][]uintptr. -func (v *Value) GroupUintptr(grouper func(int, uintptr) string) *Value { - groups := make(map[string][]uintptr) - v.EachUintptr(func(index int, val uintptr) bool { - group := grouper(index, val) - if _, ok := groups[group]; !ok { - groups[group] = make([]uintptr, 0) - } - groups[group] = append(groups[group], val) - return true - }) - return &Value{data: groups} -} - -// ReplaceUintptr uses the specified function to replace each uintptrs -// by iterating each item. The data in the returned result will be a -// []uintptr containing the replaced items. -func (v *Value) ReplaceUintptr(replacer func(int, uintptr) uintptr) *Value { - arr := v.MustUintptrSlice() - replaced := make([]uintptr, len(arr)) - v.EachUintptr(func(index int, val uintptr) bool { - replaced[index] = replacer(index, val) - return true - }) - return &Value{data: replaced} -} - -// CollectUintptr uses the specified collector function to collect a value -// for each of the uintptrs in the slice. The data returned will be a -// []interface{}. -func (v *Value) CollectUintptr(collector func(int, uintptr) interface{}) *Value { - arr := v.MustUintptrSlice() - collected := make([]interface{}, len(arr)) - v.EachUintptr(func(index int, val uintptr) bool { - collected[index] = collector(index, val) - return true - }) - return &Value{data: collected} -} - -/* - Float32 (float32 and []float32) -*/ - -// Float32 gets the value as a float32, returns the optionalDefault -// value or a system default object if the value is the wrong type. -func (v *Value) Float32(optionalDefault ...float32) float32 { - if s, ok := v.data.(float32); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return 0 -} - -// MustFloat32 gets the value as a float32. -// -// Panics if the object is not a float32. -func (v *Value) MustFloat32() float32 { - return v.data.(float32) -} - -// Float32Slice gets the value as a []float32, returns the optionalDefault -// value or nil if the value is not a []float32. -func (v *Value) Float32Slice(optionalDefault ...[]float32) []float32 { - if s, ok := v.data.([]float32); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return nil -} - -// MustFloat32Slice gets the value as a []float32. -// -// Panics if the object is not a []float32. -func (v *Value) MustFloat32Slice() []float32 { - return v.data.([]float32) -} - -// IsFloat32 gets whether the object contained is a float32 or not. -func (v *Value) IsFloat32() bool { - _, ok := v.data.(float32) - return ok -} - -// IsFloat32Slice gets whether the object contained is a []float32 or not. -func (v *Value) IsFloat32Slice() bool { - _, ok := v.data.([]float32) - return ok -} - -// EachFloat32 calls the specified callback for each object -// in the []float32. -// -// Panics if the object is the wrong type. -func (v *Value) EachFloat32(callback func(int, float32) bool) *Value { - for index, val := range v.MustFloat32Slice() { - carryon := callback(index, val) - if !carryon { - break - } - } - return v -} - -// WhereFloat32 uses the specified decider function to select items -// from the []float32. The object contained in the result will contain -// only the selected items. -func (v *Value) WhereFloat32(decider func(int, float32) bool) *Value { - var selected []float32 - v.EachFloat32(func(index int, val float32) bool { - shouldSelect := decider(index, val) - if !shouldSelect { - selected = append(selected, val) - } - return true - }) - return &Value{data: selected} -} - -// GroupFloat32 uses the specified grouper function to group the items -// keyed by the return of the grouper. The object contained in the -// result will contain a map[string][]float32. -func (v *Value) GroupFloat32(grouper func(int, float32) string) *Value { - groups := make(map[string][]float32) - v.EachFloat32(func(index int, val float32) bool { - group := grouper(index, val) - if _, ok := groups[group]; !ok { - groups[group] = make([]float32, 0) - } - groups[group] = append(groups[group], val) - return true - }) - return &Value{data: groups} -} - -// ReplaceFloat32 uses the specified function to replace each float32s -// by iterating each item. The data in the returned result will be a -// []float32 containing the replaced items. -func (v *Value) ReplaceFloat32(replacer func(int, float32) float32) *Value { - arr := v.MustFloat32Slice() - replaced := make([]float32, len(arr)) - v.EachFloat32(func(index int, val float32) bool { - replaced[index] = replacer(index, val) - return true - }) - return &Value{data: replaced} -} - -// CollectFloat32 uses the specified collector function to collect a value -// for each of the float32s in the slice. The data returned will be a -// []interface{}. -func (v *Value) CollectFloat32(collector func(int, float32) interface{}) *Value { - arr := v.MustFloat32Slice() - collected := make([]interface{}, len(arr)) - v.EachFloat32(func(index int, val float32) bool { - collected[index] = collector(index, val) - return true - }) - return &Value{data: collected} -} - -/* - Float64 (float64 and []float64) -*/ - -// Float64 gets the value as a float64, returns the optionalDefault -// value or a system default object if the value is the wrong type. -func (v *Value) Float64(optionalDefault ...float64) float64 { - if s, ok := v.data.(float64); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return 0 -} - -// MustFloat64 gets the value as a float64. -// -// Panics if the object is not a float64. -func (v *Value) MustFloat64() float64 { - return v.data.(float64) -} - -// Float64Slice gets the value as a []float64, returns the optionalDefault -// value or nil if the value is not a []float64. -func (v *Value) Float64Slice(optionalDefault ...[]float64) []float64 { - if s, ok := v.data.([]float64); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return nil -} - -// MustFloat64Slice gets the value as a []float64. -// -// Panics if the object is not a []float64. -func (v *Value) MustFloat64Slice() []float64 { - return v.data.([]float64) -} - -// IsFloat64 gets whether the object contained is a float64 or not. -func (v *Value) IsFloat64() bool { - _, ok := v.data.(float64) - return ok -} - -// IsFloat64Slice gets whether the object contained is a []float64 or not. -func (v *Value) IsFloat64Slice() bool { - _, ok := v.data.([]float64) - return ok -} - -// EachFloat64 calls the specified callback for each object -// in the []float64. -// -// Panics if the object is the wrong type. -func (v *Value) EachFloat64(callback func(int, float64) bool) *Value { - for index, val := range v.MustFloat64Slice() { - carryon := callback(index, val) - if !carryon { - break - } - } - return v -} - -// WhereFloat64 uses the specified decider function to select items -// from the []float64. The object contained in the result will contain -// only the selected items. -func (v *Value) WhereFloat64(decider func(int, float64) bool) *Value { - var selected []float64 - v.EachFloat64(func(index int, val float64) bool { - shouldSelect := decider(index, val) - if !shouldSelect { - selected = append(selected, val) - } - return true - }) - return &Value{data: selected} -} - -// GroupFloat64 uses the specified grouper function to group the items -// keyed by the return of the grouper. The object contained in the -// result will contain a map[string][]float64. -func (v *Value) GroupFloat64(grouper func(int, float64) string) *Value { - groups := make(map[string][]float64) - v.EachFloat64(func(index int, val float64) bool { - group := grouper(index, val) - if _, ok := groups[group]; !ok { - groups[group] = make([]float64, 0) - } - groups[group] = append(groups[group], val) - return true - }) - return &Value{data: groups} -} - -// ReplaceFloat64 uses the specified function to replace each float64s -// by iterating each item. The data in the returned result will be a -// []float64 containing the replaced items. -func (v *Value) ReplaceFloat64(replacer func(int, float64) float64) *Value { - arr := v.MustFloat64Slice() - replaced := make([]float64, len(arr)) - v.EachFloat64(func(index int, val float64) bool { - replaced[index] = replacer(index, val) - return true - }) - return &Value{data: replaced} -} - -// CollectFloat64 uses the specified collector function to collect a value -// for each of the float64s in the slice. The data returned will be a -// []interface{}. -func (v *Value) CollectFloat64(collector func(int, float64) interface{}) *Value { - arr := v.MustFloat64Slice() - collected := make([]interface{}, len(arr)) - v.EachFloat64(func(index int, val float64) bool { - collected[index] = collector(index, val) - return true - }) - return &Value{data: collected} -} - -/* - Complex64 (complex64 and []complex64) -*/ - -// Complex64 gets the value as a complex64, returns the optionalDefault -// value or a system default object if the value is the wrong type. -func (v *Value) Complex64(optionalDefault ...complex64) complex64 { - if s, ok := v.data.(complex64); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return 0 -} - -// MustComplex64 gets the value as a complex64. -// -// Panics if the object is not a complex64. -func (v *Value) MustComplex64() complex64 { - return v.data.(complex64) -} - -// Complex64Slice gets the value as a []complex64, returns the optionalDefault -// value or nil if the value is not a []complex64. -func (v *Value) Complex64Slice(optionalDefault ...[]complex64) []complex64 { - if s, ok := v.data.([]complex64); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return nil -} - -// MustComplex64Slice gets the value as a []complex64. -// -// Panics if the object is not a []complex64. -func (v *Value) MustComplex64Slice() []complex64 { - return v.data.([]complex64) -} - -// IsComplex64 gets whether the object contained is a complex64 or not. -func (v *Value) IsComplex64() bool { - _, ok := v.data.(complex64) - return ok -} - -// IsComplex64Slice gets whether the object contained is a []complex64 or not. -func (v *Value) IsComplex64Slice() bool { - _, ok := v.data.([]complex64) - return ok -} - -// EachComplex64 calls the specified callback for each object -// in the []complex64. -// -// Panics if the object is the wrong type. -func (v *Value) EachComplex64(callback func(int, complex64) bool) *Value { - for index, val := range v.MustComplex64Slice() { - carryon := callback(index, val) - if !carryon { - break - } - } - return v -} - -// WhereComplex64 uses the specified decider function to select items -// from the []complex64. The object contained in the result will contain -// only the selected items. -func (v *Value) WhereComplex64(decider func(int, complex64) bool) *Value { - var selected []complex64 - v.EachComplex64(func(index int, val complex64) bool { - shouldSelect := decider(index, val) - if !shouldSelect { - selected = append(selected, val) - } - return true - }) - return &Value{data: selected} -} - -// GroupComplex64 uses the specified grouper function to group the items -// keyed by the return of the grouper. The object contained in the -// result will contain a map[string][]complex64. -func (v *Value) GroupComplex64(grouper func(int, complex64) string) *Value { - groups := make(map[string][]complex64) - v.EachComplex64(func(index int, val complex64) bool { - group := grouper(index, val) - if _, ok := groups[group]; !ok { - groups[group] = make([]complex64, 0) - } - groups[group] = append(groups[group], val) - return true - }) - return &Value{data: groups} -} - -// ReplaceComplex64 uses the specified function to replace each complex64s -// by iterating each item. The data in the returned result will be a -// []complex64 containing the replaced items. -func (v *Value) ReplaceComplex64(replacer func(int, complex64) complex64) *Value { - arr := v.MustComplex64Slice() - replaced := make([]complex64, len(arr)) - v.EachComplex64(func(index int, val complex64) bool { - replaced[index] = replacer(index, val) - return true - }) - return &Value{data: replaced} -} - -// CollectComplex64 uses the specified collector function to collect a value -// for each of the complex64s in the slice. The data returned will be a -// []interface{}. -func (v *Value) CollectComplex64(collector func(int, complex64) interface{}) *Value { - arr := v.MustComplex64Slice() - collected := make([]interface{}, len(arr)) - v.EachComplex64(func(index int, val complex64) bool { - collected[index] = collector(index, val) - return true - }) - return &Value{data: collected} -} - -/* - Complex128 (complex128 and []complex128) -*/ - -// Complex128 gets the value as a complex128, returns the optionalDefault -// value or a system default object if the value is the wrong type. -func (v *Value) Complex128(optionalDefault ...complex128) complex128 { - if s, ok := v.data.(complex128); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return 0 -} - -// MustComplex128 gets the value as a complex128. -// -// Panics if the object is not a complex128. -func (v *Value) MustComplex128() complex128 { - return v.data.(complex128) -} - -// Complex128Slice gets the value as a []complex128, returns the optionalDefault -// value or nil if the value is not a []complex128. -func (v *Value) Complex128Slice(optionalDefault ...[]complex128) []complex128 { - if s, ok := v.data.([]complex128); ok { - return s - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - return nil -} - -// MustComplex128Slice gets the value as a []complex128. -// -// Panics if the object is not a []complex128. -func (v *Value) MustComplex128Slice() []complex128 { - return v.data.([]complex128) -} - -// IsComplex128 gets whether the object contained is a complex128 or not. -func (v *Value) IsComplex128() bool { - _, ok := v.data.(complex128) - return ok -} - -// IsComplex128Slice gets whether the object contained is a []complex128 or not. -func (v *Value) IsComplex128Slice() bool { - _, ok := v.data.([]complex128) - return ok -} - -// EachComplex128 calls the specified callback for each object -// in the []complex128. -// -// Panics if the object is the wrong type. -func (v *Value) EachComplex128(callback func(int, complex128) bool) *Value { - for index, val := range v.MustComplex128Slice() { - carryon := callback(index, val) - if !carryon { - break - } - } - return v -} - -// WhereComplex128 uses the specified decider function to select items -// from the []complex128. The object contained in the result will contain -// only the selected items. -func (v *Value) WhereComplex128(decider func(int, complex128) bool) *Value { - var selected []complex128 - v.EachComplex128(func(index int, val complex128) bool { - shouldSelect := decider(index, val) - if !shouldSelect { - selected = append(selected, val) - } - return true - }) - return &Value{data: selected} -} - -// GroupComplex128 uses the specified grouper function to group the items -// keyed by the return of the grouper. The object contained in the -// result will contain a map[string][]complex128. -func (v *Value) GroupComplex128(grouper func(int, complex128) string) *Value { - groups := make(map[string][]complex128) - v.EachComplex128(func(index int, val complex128) bool { - group := grouper(index, val) - if _, ok := groups[group]; !ok { - groups[group] = make([]complex128, 0) - } - groups[group] = append(groups[group], val) - return true - }) - return &Value{data: groups} -} - -// ReplaceComplex128 uses the specified function to replace each complex128s -// by iterating each item. The data in the returned result will be a -// []complex128 containing the replaced items. -func (v *Value) ReplaceComplex128(replacer func(int, complex128) complex128) *Value { - arr := v.MustComplex128Slice() - replaced := make([]complex128, len(arr)) - v.EachComplex128(func(index int, val complex128) bool { - replaced[index] = replacer(index, val) - return true - }) - return &Value{data: replaced} -} - -// CollectComplex128 uses the specified collector function to collect a value -// for each of the complex128s in the slice. The data returned will be a -// []interface{}. -func (v *Value) CollectComplex128(collector func(int, complex128) interface{}) *Value { - arr := v.MustComplex128Slice() - collected := make([]interface{}, len(arr)) - v.EachComplex128(func(index int, val complex128) bool { - collected[index] = collector(index, val) - return true - }) - return &Value{data: collected} -} diff --git a/vendor/github.com/stretchr/objx/value.go b/vendor/github.com/stretchr/objx/value.go deleted file mode 100644 index 4e5f9b77e..000000000 --- a/vendor/github.com/stretchr/objx/value.go +++ /dev/null @@ -1,159 +0,0 @@ -package objx - -import ( - "fmt" - "strconv" -) - -// Value provides methods for extracting interface{} data in various -// types. -type Value struct { - // data contains the raw data being managed by this Value - data interface{} -} - -// Data returns the raw data contained by this Value -func (v *Value) Data() interface{} { - return v.data -} - -// String returns the value always as a string -func (v *Value) String() string { - switch { - case v.IsNil(): - return "" - case v.IsStr(): - return v.Str() - case v.IsBool(): - return strconv.FormatBool(v.Bool()) - case v.IsFloat32(): - return strconv.FormatFloat(float64(v.Float32()), 'f', -1, 32) - case v.IsFloat64(): - return strconv.FormatFloat(v.Float64(), 'f', -1, 64) - case v.IsInt(): - return strconv.FormatInt(int64(v.Int()), 10) - case v.IsInt8(): - return strconv.FormatInt(int64(v.Int8()), 10) - case v.IsInt16(): - return strconv.FormatInt(int64(v.Int16()), 10) - case v.IsInt32(): - return strconv.FormatInt(int64(v.Int32()), 10) - case v.IsInt64(): - return strconv.FormatInt(v.Int64(), 10) - case v.IsUint(): - return strconv.FormatUint(uint64(v.Uint()), 10) - case v.IsUint8(): - return strconv.FormatUint(uint64(v.Uint8()), 10) - case v.IsUint16(): - return strconv.FormatUint(uint64(v.Uint16()), 10) - case v.IsUint32(): - return strconv.FormatUint(uint64(v.Uint32()), 10) - case v.IsUint64(): - return strconv.FormatUint(v.Uint64(), 10) - } - return fmt.Sprintf("%#v", v.Data()) -} - -// StringSlice returns the value always as a []string -func (v *Value) StringSlice(optionalDefault ...[]string) []string { - switch { - case v.IsStrSlice(): - return v.MustStrSlice() - case v.IsBoolSlice(): - slice := v.MustBoolSlice() - vals := make([]string, len(slice)) - for i, iv := range slice { - vals[i] = strconv.FormatBool(iv) - } - return vals - case v.IsFloat32Slice(): - slice := v.MustFloat32Slice() - vals := make([]string, len(slice)) - for i, iv := range slice { - vals[i] = strconv.FormatFloat(float64(iv), 'f', -1, 32) - } - return vals - case v.IsFloat64Slice(): - slice := v.MustFloat64Slice() - vals := make([]string, len(slice)) - for i, iv := range slice { - vals[i] = strconv.FormatFloat(iv, 'f', -1, 64) - } - return vals - case v.IsIntSlice(): - slice := v.MustIntSlice() - vals := make([]string, len(slice)) - for i, iv := range slice { - vals[i] = strconv.FormatInt(int64(iv), 10) - } - return vals - case v.IsInt8Slice(): - slice := v.MustInt8Slice() - vals := make([]string, len(slice)) - for i, iv := range slice { - vals[i] = strconv.FormatInt(int64(iv), 10) - } - return vals - case v.IsInt16Slice(): - slice := v.MustInt16Slice() - vals := make([]string, len(slice)) - for i, iv := range slice { - vals[i] = strconv.FormatInt(int64(iv), 10) - } - return vals - case v.IsInt32Slice(): - slice := v.MustInt32Slice() - vals := make([]string, len(slice)) - for i, iv := range slice { - vals[i] = strconv.FormatInt(int64(iv), 10) - } - return vals - case v.IsInt64Slice(): - slice := v.MustInt64Slice() - vals := make([]string, len(slice)) - for i, iv := range slice { - vals[i] = strconv.FormatInt(iv, 10) - } - return vals - case v.IsUintSlice(): - slice := v.MustUintSlice() - vals := make([]string, len(slice)) - for i, iv := range slice { - vals[i] = strconv.FormatUint(uint64(iv), 10) - } - return vals - case v.IsUint8Slice(): - slice := v.MustUint8Slice() - vals := make([]string, len(slice)) - for i, iv := range slice { - vals[i] = strconv.FormatUint(uint64(iv), 10) - } - return vals - case v.IsUint16Slice(): - slice := v.MustUint16Slice() - vals := make([]string, len(slice)) - for i, iv := range slice { - vals[i] = strconv.FormatUint(uint64(iv), 10) - } - return vals - case v.IsUint32Slice(): - slice := v.MustUint32Slice() - vals := make([]string, len(slice)) - for i, iv := range slice { - vals[i] = strconv.FormatUint(uint64(iv), 10) - } - return vals - case v.IsUint64Slice(): - slice := v.MustUint64Slice() - vals := make([]string, len(slice)) - for i, iv := range slice { - vals[i] = strconv.FormatUint(iv, 10) - } - return vals - } - if len(optionalDefault) == 1 { - return optionalDefault[0] - } - - return []string{} -} diff --git a/vendor/github.com/stretchr/testify/mock/doc.go b/vendor/github.com/stretchr/testify/mock/doc.go deleted file mode 100644 index 7324128ef..000000000 --- a/vendor/github.com/stretchr/testify/mock/doc.go +++ /dev/null @@ -1,44 +0,0 @@ -// Package mock provides a system by which it is possible to mock your objects -// and verify calls are happening as expected. -// -// Example Usage -// -// The mock package provides an object, Mock, that tracks activity on another object. It is usually -// embedded into a test object as shown below: -// -// type MyTestObject struct { -// // add a Mock object instance -// mock.Mock -// -// // other fields go here as normal -// } -// -// When implementing the methods of an interface, you wire your functions up -// to call the Mock.Called(args...) method, and return the appropriate values. -// -// For example, to mock a method that saves the name and age of a person and returns -// the year of their birth or an error, you might write this: -// -// func (o *MyTestObject) SavePersonDetails(firstname, lastname string, age int) (int, error) { -// args := o.Called(firstname, lastname, age) -// return args.Int(0), args.Error(1) -// } -// -// The Int, Error and Bool methods are examples of strongly typed getters that take the argument -// index position. Given this argument list: -// -// (12, true, "Something") -// -// You could read them out strongly typed like this: -// -// args.Int(0) -// args.Bool(1) -// args.String(2) -// -// For objects of your own type, use the generic Arguments.Get(index) method and make a type assertion: -// -// return args.Get(0).(*MyObject), args.Get(1).(*AnotherObjectOfMine) -// -// This may cause a panic if the object you are getting is nil (the type assertion will fail), in those -// cases you should check for nil first. -package mock diff --git a/vendor/github.com/stretchr/testify/mock/mock.go b/vendor/github.com/stretchr/testify/mock/mock.go deleted file mode 100644 index c6df4485a..000000000 --- a/vendor/github.com/stretchr/testify/mock/mock.go +++ /dev/null @@ -1,981 +0,0 @@ -package mock - -import ( - "errors" - "fmt" - "reflect" - "regexp" - "runtime" - "strings" - "sync" - "time" - - "github.com/davecgh/go-spew/spew" - "github.com/pmezard/go-difflib/difflib" - "github.com/stretchr/objx" - "github.com/stretchr/testify/assert" -) - -// TestingT is an interface wrapper around *testing.T -type TestingT interface { - Logf(format string, args ...interface{}) - Errorf(format string, args ...interface{}) - FailNow() -} - -/* - Call -*/ - -// Call represents a method call and is used for setting expectations, -// as well as recording activity. -type Call struct { - Parent *Mock - - // The name of the method that was or will be called. - Method string - - // Holds the arguments of the method. - Arguments Arguments - - // Holds the arguments that should be returned when - // this method is called. - ReturnArguments Arguments - - // Holds the caller info for the On() call - callerInfo []string - - // The number of times to return the return arguments when setting - // expectations. 0 means to always return the value. - Repeatability int - - // Amount of times this call has been called - totalCalls int - - // Call to this method can be optional - optional bool - - // Holds a channel that will be used to block the Return until it either - // receives a message or is closed. nil means it returns immediately. - WaitFor <-chan time.Time - - waitTime time.Duration - - // Holds a handler used to manipulate arguments content that are passed by - // reference. It's useful when mocking methods such as unmarshalers or - // decoders. - RunFn func(Arguments) - - // PanicMsg holds msg to be used to mock panic on the function call - // if the PanicMsg is set to a non nil string the function call will panic - // irrespective of other settings - PanicMsg *string -} - -func newCall(parent *Mock, methodName string, callerInfo []string, methodArguments ...interface{}) *Call { - return &Call{ - Parent: parent, - Method: methodName, - Arguments: methodArguments, - ReturnArguments: make([]interface{}, 0), - callerInfo: callerInfo, - Repeatability: 0, - WaitFor: nil, - RunFn: nil, - PanicMsg: nil, - } -} - -func (c *Call) lock() { - c.Parent.mutex.Lock() -} - -func (c *Call) unlock() { - c.Parent.mutex.Unlock() -} - -// Return specifies the return arguments for the expectation. -// -// Mock.On("DoSomething").Return(errors.New("failed")) -func (c *Call) Return(returnArguments ...interface{}) *Call { - c.lock() - defer c.unlock() - - c.ReturnArguments = returnArguments - - return c -} - -// Panic specifies if the functon call should fail and the panic message -// -// Mock.On("DoSomething").Panic("test panic") -func (c *Call) Panic(msg string) *Call { - c.lock() - defer c.unlock() - - c.PanicMsg = &msg - - return c -} - -// Once indicates that that the mock should only return the value once. -// -// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Once() -func (c *Call) Once() *Call { - return c.Times(1) -} - -// Twice indicates that that the mock should only return the value twice. -// -// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Twice() -func (c *Call) Twice() *Call { - return c.Times(2) -} - -// Times indicates that that the mock should only return the indicated number -// of times. -// -// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Times(5) -func (c *Call) Times(i int) *Call { - c.lock() - defer c.unlock() - c.Repeatability = i - return c -} - -// WaitUntil sets the channel that will block the mock's return until its closed -// or a message is received. -// -// Mock.On("MyMethod", arg1, arg2).WaitUntil(time.After(time.Second)) -func (c *Call) WaitUntil(w <-chan time.Time) *Call { - c.lock() - defer c.unlock() - c.WaitFor = w - return c -} - -// After sets how long to block until the call returns -// -// Mock.On("MyMethod", arg1, arg2).After(time.Second) -func (c *Call) After(d time.Duration) *Call { - c.lock() - defer c.unlock() - c.waitTime = d - return c -} - -// Run sets a handler to be called before returning. It can be used when -// mocking a method (such as an unmarshaler) that takes a pointer to a struct and -// sets properties in such struct -// -// Mock.On("Unmarshal", AnythingOfType("*map[string]interface{}")).Return().Run(func(args Arguments) { -// arg := args.Get(0).(*map[string]interface{}) -// arg["foo"] = "bar" -// }) -func (c *Call) Run(fn func(args Arguments)) *Call { - c.lock() - defer c.unlock() - c.RunFn = fn - return c -} - -// Maybe allows the method call to be optional. Not calling an optional method -// will not cause an error while asserting expectations -func (c *Call) Maybe() *Call { - c.lock() - defer c.unlock() - c.optional = true - return c -} - -// On chains a new expectation description onto the mocked interface. This -// allows syntax like. -// -// Mock. -// On("MyMethod", 1).Return(nil). -// On("MyOtherMethod", 'a', 'b', 'c').Return(errors.New("Some Error")) -//go:noinline -func (c *Call) On(methodName string, arguments ...interface{}) *Call { - return c.Parent.On(methodName, arguments...) -} - -// Mock is the workhorse used to track activity on another object. -// For an example of its usage, refer to the "Example Usage" section at the top -// of this document. -type Mock struct { - // Represents the calls that are expected of - // an object. - ExpectedCalls []*Call - - // Holds the calls that were made to this mocked object. - Calls []Call - - // test is An optional variable that holds the test struct, to be used when an - // invalid mock call was made. - test TestingT - - // TestData holds any data that might be useful for testing. Testify ignores - // this data completely allowing you to do whatever you like with it. - testData objx.Map - - mutex sync.Mutex -} - -// TestData holds any data that might be useful for testing. Testify ignores -// this data completely allowing you to do whatever you like with it. -func (m *Mock) TestData() objx.Map { - - if m.testData == nil { - m.testData = make(objx.Map) - } - - return m.testData -} - -/* - Setting expectations -*/ - -// Test sets the test struct variable of the mock object -func (m *Mock) Test(t TestingT) { - m.mutex.Lock() - defer m.mutex.Unlock() - m.test = t -} - -// fail fails the current test with the given formatted format and args. -// In case that a test was defined, it uses the test APIs for failing a test, -// otherwise it uses panic. -func (m *Mock) fail(format string, args ...interface{}) { - m.mutex.Lock() - defer m.mutex.Unlock() - - if m.test == nil { - panic(fmt.Sprintf(format, args...)) - } - m.test.Errorf(format, args...) - m.test.FailNow() -} - -// On starts a description of an expectation of the specified method -// being called. -// -// Mock.On("MyMethod", arg1, arg2) -func (m *Mock) On(methodName string, arguments ...interface{}) *Call { - for _, arg := range arguments { - if v := reflect.ValueOf(arg); v.Kind() == reflect.Func { - panic(fmt.Sprintf("cannot use Func in expectations. Use mock.AnythingOfType(\"%T\")", arg)) - } - } - - m.mutex.Lock() - defer m.mutex.Unlock() - c := newCall(m, methodName, assert.CallerInfo(), arguments...) - m.ExpectedCalls = append(m.ExpectedCalls, c) - return c -} - -// /* -// Recording and responding to activity -// */ - -func (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, *Call) { - var expectedCall *Call - - for i, call := range m.ExpectedCalls { - if call.Method == method { - _, diffCount := call.Arguments.Diff(arguments) - if diffCount == 0 { - expectedCall = call - if call.Repeatability > -1 { - return i, call - } - } - } - } - - return -1, expectedCall -} - -func (m *Mock) findClosestCall(method string, arguments ...interface{}) (*Call, string) { - var diffCount int - var closestCall *Call - var err string - - for _, call := range m.expectedCalls() { - if call.Method == method { - - errInfo, tempDiffCount := call.Arguments.Diff(arguments) - if tempDiffCount < diffCount || diffCount == 0 { - diffCount = tempDiffCount - closestCall = call - err = errInfo - } - - } - } - - return closestCall, err -} - -func callString(method string, arguments Arguments, includeArgumentValues bool) string { - - var argValsString string - if includeArgumentValues { - var argVals []string - for argIndex, arg := range arguments { - argVals = append(argVals, fmt.Sprintf("%d: %#v", argIndex, arg)) - } - argValsString = fmt.Sprintf("\n\t\t%s", strings.Join(argVals, "\n\t\t")) - } - - return fmt.Sprintf("%s(%s)%s", method, arguments.String(), argValsString) -} - -// Called tells the mock object that a method has been called, and gets an array -// of arguments to return. Panics if the call is unexpected (i.e. not preceded by -// appropriate .On .Return() calls) -// If Call.WaitFor is set, blocks until the channel is closed or receives a message. -func (m *Mock) Called(arguments ...interface{}) Arguments { - // get the calling function's name - pc, _, _, ok := runtime.Caller(1) - if !ok { - panic("Couldn't get the caller information") - } - functionPath := runtime.FuncForPC(pc).Name() - //Next four lines are required to use GCCGO function naming conventions. - //For Ex: github_com_docker_libkv_store_mock.WatchTree.pN39_github_com_docker_libkv_store_mock.Mock - //uses interface information unlike golang github.com/docker/libkv/store/mock.(*Mock).WatchTree - //With GCCGO we need to remove interface information starting from pN
. - re := regexp.MustCompile("\\.pN\\d+_") - if re.MatchString(functionPath) { - functionPath = re.Split(functionPath, -1)[0] - } - parts := strings.Split(functionPath, ".") - functionName := parts[len(parts)-1] - return m.MethodCalled(functionName, arguments...) -} - -// MethodCalled tells the mock object that the given method has been called, and gets -// an array of arguments to return. Panics if the call is unexpected (i.e. not preceded -// by appropriate .On .Return() calls) -// If Call.WaitFor is set, blocks until the channel is closed or receives a message. -func (m *Mock) MethodCalled(methodName string, arguments ...interface{}) Arguments { - m.mutex.Lock() - //TODO: could combine expected and closes in single loop - found, call := m.findExpectedCall(methodName, arguments...) - - if found < 0 { - // expected call found but it has already been called with repeatable times - if call != nil { - m.mutex.Unlock() - m.fail("\nassert: mock: The method has been called over %d times.\n\tEither do one more Mock.On(\"%s\").Return(...), or remove extra call.\n\tThis call was unexpected:\n\t\t%s\n\tat: %s", call.totalCalls, methodName, callString(methodName, arguments, true), assert.CallerInfo()) - } - // we have to fail here - because we don't know what to do - // as the return arguments. This is because: - // - // a) this is a totally unexpected call to this method, - // b) the arguments are not what was expected, or - // c) the developer has forgotten to add an accompanying On...Return pair. - closestCall, mismatch := m.findClosestCall(methodName, arguments...) - m.mutex.Unlock() - - if closestCall != nil { - m.fail("\n\nmock: Unexpected Method Call\n-----------------------------\n\n%s\n\nThe closest call I have is: \n\n%s\n\n%s\nDiff: %s", - callString(methodName, arguments, true), - callString(methodName, closestCall.Arguments, true), - diffArguments(closestCall.Arguments, arguments), - strings.TrimSpace(mismatch), - ) - } else { - m.fail("\nassert: mock: I don't know what to return because the method call was unexpected.\n\tEither do Mock.On(\"%s\").Return(...) first, or remove the %s() call.\n\tThis method was unexpected:\n\t\t%s\n\tat: %s", methodName, methodName, callString(methodName, arguments, true), assert.CallerInfo()) - } - } - - if call.Repeatability == 1 { - call.Repeatability = -1 - } else if call.Repeatability > 1 { - call.Repeatability-- - } - call.totalCalls++ - - // add the call - m.Calls = append(m.Calls, *newCall(m, methodName, assert.CallerInfo(), arguments...)) - m.mutex.Unlock() - - // block if specified - if call.WaitFor != nil { - <-call.WaitFor - } else { - time.Sleep(call.waitTime) - } - - m.mutex.Lock() - panicMsg := call.PanicMsg - m.mutex.Unlock() - if panicMsg != nil { - panic(*panicMsg) - } - - m.mutex.Lock() - runFn := call.RunFn - m.mutex.Unlock() - - if runFn != nil { - runFn(arguments) - } - - m.mutex.Lock() - returnArgs := call.ReturnArguments - m.mutex.Unlock() - - return returnArgs -} - -/* - Assertions -*/ - -type assertExpectationser interface { - AssertExpectations(TestingT) bool -} - -// AssertExpectationsForObjects asserts that everything specified with On and Return -// of the specified objects was in fact called as expected. -// -// Calls may have occurred in any order. -func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - for _, obj := range testObjects { - if m, ok := obj.(Mock); ok { - t.Logf("Deprecated mock.AssertExpectationsForObjects(myMock.Mock) use mock.AssertExpectationsForObjects(myMock)") - obj = &m - } - m := obj.(assertExpectationser) - if !m.AssertExpectations(t) { - t.Logf("Expectations didn't match for Mock: %+v", reflect.TypeOf(m)) - return false - } - } - return true -} - -// AssertExpectations asserts that everything specified with On and Return was -// in fact called as expected. Calls may have occurred in any order. -func (m *Mock) AssertExpectations(t TestingT) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - m.mutex.Lock() - defer m.mutex.Unlock() - var somethingMissing bool - var failedExpectations int - - // iterate through each expectation - expectedCalls := m.expectedCalls() - for _, expectedCall := range expectedCalls { - if !expectedCall.optional && !m.methodWasCalled(expectedCall.Method, expectedCall.Arguments) && expectedCall.totalCalls == 0 { - somethingMissing = true - failedExpectations++ - t.Logf("FAIL:\t%s(%s)\n\t\tat: %s", expectedCall.Method, expectedCall.Arguments.String(), expectedCall.callerInfo) - } else { - if expectedCall.Repeatability > 0 { - somethingMissing = true - failedExpectations++ - t.Logf("FAIL:\t%s(%s)\n\t\tat: %s", expectedCall.Method, expectedCall.Arguments.String(), expectedCall.callerInfo) - } else { - t.Logf("PASS:\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String()) - } - } - } - - if somethingMissing { - t.Errorf("FAIL: %d out of %d expectation(s) were met.\n\tThe code you are testing needs to make %d more call(s).\n\tat: %s", len(expectedCalls)-failedExpectations, len(expectedCalls), failedExpectations, assert.CallerInfo()) - } - - return !somethingMissing -} - -// AssertNumberOfCalls asserts that the method was called expectedCalls times. -func (m *Mock) AssertNumberOfCalls(t TestingT, methodName string, expectedCalls int) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - m.mutex.Lock() - defer m.mutex.Unlock() - var actualCalls int - for _, call := range m.calls() { - if call.Method == methodName { - actualCalls++ - } - } - return assert.Equal(t, expectedCalls, actualCalls, fmt.Sprintf("Expected number of calls (%d) does not match the actual number of calls (%d).", expectedCalls, actualCalls)) -} - -// AssertCalled asserts that the method was called. -// It can produce a false result when an argument is a pointer type and the underlying value changed after calling the mocked method. -func (m *Mock) AssertCalled(t TestingT, methodName string, arguments ...interface{}) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - m.mutex.Lock() - defer m.mutex.Unlock() - if !m.methodWasCalled(methodName, arguments) { - var calledWithArgs []string - for _, call := range m.calls() { - calledWithArgs = append(calledWithArgs, fmt.Sprintf("%v", call.Arguments)) - } - if len(calledWithArgs) == 0 { - return assert.Fail(t, "Should have called with given arguments", - fmt.Sprintf("Expected %q to have been called with:\n%v\nbut no actual calls happened", methodName, arguments)) - } - return assert.Fail(t, "Should have called with given arguments", - fmt.Sprintf("Expected %q to have been called with:\n%v\nbut actual calls were:\n %v", methodName, arguments, strings.Join(calledWithArgs, "\n"))) - } - return true -} - -// AssertNotCalled asserts that the method was not called. -// It can produce a false result when an argument is a pointer type and the underlying value changed after calling the mocked method. -func (m *Mock) AssertNotCalled(t TestingT, methodName string, arguments ...interface{}) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - m.mutex.Lock() - defer m.mutex.Unlock() - if m.methodWasCalled(methodName, arguments) { - return assert.Fail(t, "Should not have called with given arguments", - fmt.Sprintf("Expected %q to not have been called with:\n%v\nbut actually it was.", methodName, arguments)) - } - return true -} - -// IsMethodCallable checking that the method can be called -// If the method was called more than `Repeatability` return false -func (m *Mock) IsMethodCallable(t TestingT, methodName string, arguments ...interface{}) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - m.mutex.Lock() - defer m.mutex.Unlock() - - for _, v := range m.ExpectedCalls { - if v.Method != methodName { - continue - } - if len(arguments) != len(v.Arguments) { - continue - } - if v.Repeatability < v.totalCalls { - continue - } - if isArgsEqual(v.Arguments, arguments) { - return true - } - } - return false -} - -// isArgsEqual compares arguments -func isArgsEqual(expected Arguments, args []interface{}) bool { - if len(expected) != len(args) { - return false - } - for i, v := range args { - if !reflect.DeepEqual(expected[i], v) { - return false - } - } - return true -} - -func (m *Mock) methodWasCalled(methodName string, expected []interface{}) bool { - for _, call := range m.calls() { - if call.Method == methodName { - - _, differences := Arguments(expected).Diff(call.Arguments) - - if differences == 0 { - // found the expected call - return true - } - - } - } - // we didn't find the expected call - return false -} - -func (m *Mock) expectedCalls() []*Call { - return append([]*Call{}, m.ExpectedCalls...) -} - -func (m *Mock) calls() []Call { - return append([]Call{}, m.Calls...) -} - -/* - Arguments -*/ - -// Arguments holds an array of method arguments or return values. -type Arguments []interface{} - -const ( - // Anything is used in Diff and Assert when the argument being tested - // shouldn't be taken into consideration. - Anything = "mock.Anything" -) - -// AnythingOfTypeArgument is a string that contains the type of an argument -// for use when type checking. Used in Diff and Assert. -type AnythingOfTypeArgument string - -// AnythingOfType returns an AnythingOfTypeArgument object containing the -// name of the type to check for. Used in Diff and Assert. -// -// For example: -// Assert(t, AnythingOfType("string"), AnythingOfType("int")) -func AnythingOfType(t string) AnythingOfTypeArgument { - return AnythingOfTypeArgument(t) -} - -// IsTypeArgument is a struct that contains the type of an argument -// for use when type checking. This is an alternative to AnythingOfType. -// Used in Diff and Assert. -type IsTypeArgument struct { - t interface{} -} - -// IsType returns an IsTypeArgument object containing the type to check for. -// You can provide a zero-value of the type to check. This is an -// alternative to AnythingOfType. Used in Diff and Assert. -// -// For example: -// Assert(t, IsType(""), IsType(0)) -func IsType(t interface{}) *IsTypeArgument { - return &IsTypeArgument{t: t} -} - -// argumentMatcher performs custom argument matching, returning whether or -// not the argument is matched by the expectation fixture function. -type argumentMatcher struct { - // fn is a function which accepts one argument, and returns a bool. - fn reflect.Value -} - -func (f argumentMatcher) Matches(argument interface{}) bool { - expectType := f.fn.Type().In(0) - expectTypeNilSupported := false - switch expectType.Kind() { - case reflect.Interface, reflect.Chan, reflect.Func, reflect.Map, reflect.Slice, reflect.Ptr: - expectTypeNilSupported = true - } - - argType := reflect.TypeOf(argument) - var arg reflect.Value - if argType == nil { - arg = reflect.New(expectType).Elem() - } else { - arg = reflect.ValueOf(argument) - } - - if argType == nil && !expectTypeNilSupported { - panic(errors.New("attempting to call matcher with nil for non-nil expected type")) - } - if argType == nil || argType.AssignableTo(expectType) { - result := f.fn.Call([]reflect.Value{arg}) - return result[0].Bool() - } - return false -} - -func (f argumentMatcher) String() string { - return fmt.Sprintf("func(%s) bool", f.fn.Type().In(0).Name()) -} - -// MatchedBy can be used to match a mock call based on only certain properties -// from a complex struct or some calculation. It takes a function that will be -// evaluated with the called argument and will return true when there's a match -// and false otherwise. -// -// Example: -// m.On("Do", MatchedBy(func(req *http.Request) bool { return req.Host == "example.com" })) -// -// |fn|, must be a function accepting a single argument (of the expected type) -// which returns a bool. If |fn| doesn't match the required signature, -// MatchedBy() panics. -func MatchedBy(fn interface{}) argumentMatcher { - fnType := reflect.TypeOf(fn) - - if fnType.Kind() != reflect.Func { - panic(fmt.Sprintf("assert: arguments: %s is not a func", fn)) - } - if fnType.NumIn() != 1 { - panic(fmt.Sprintf("assert: arguments: %s does not take exactly one argument", fn)) - } - if fnType.NumOut() != 1 || fnType.Out(0).Kind() != reflect.Bool { - panic(fmt.Sprintf("assert: arguments: %s does not return a bool", fn)) - } - - return argumentMatcher{fn: reflect.ValueOf(fn)} -} - -// Get Returns the argument at the specified index. -func (args Arguments) Get(index int) interface{} { - if index+1 > len(args) { - panic(fmt.Sprintf("assert: arguments: Cannot call Get(%d) because there are %d argument(s).", index, len(args))) - } - return args[index] -} - -// Is gets whether the objects match the arguments specified. -func (args Arguments) Is(objects ...interface{}) bool { - for i, obj := range args { - if obj != objects[i] { - return false - } - } - return true -} - -// Diff gets a string describing the differences between the arguments -// and the specified objects. -// -// Returns the diff string and number of differences found. -func (args Arguments) Diff(objects []interface{}) (string, int) { - //TODO: could return string as error and nil for No difference - - var output = "\n" - var differences int - - var maxArgCount = len(args) - if len(objects) > maxArgCount { - maxArgCount = len(objects) - } - - for i := 0; i < maxArgCount; i++ { - var actual, expected interface{} - var actualFmt, expectedFmt string - - if len(objects) <= i { - actual = "(Missing)" - actualFmt = "(Missing)" - } else { - actual = objects[i] - actualFmt = fmt.Sprintf("(%[1]T=%[1]v)", actual) - } - - if len(args) <= i { - expected = "(Missing)" - expectedFmt = "(Missing)" - } else { - expected = args[i] - expectedFmt = fmt.Sprintf("(%[1]T=%[1]v)", expected) - } - - if matcher, ok := expected.(argumentMatcher); ok { - if matcher.Matches(actual) { - output = fmt.Sprintf("%s\t%d: PASS: %s matched by %s\n", output, i, actualFmt, matcher) - } else { - differences++ - output = fmt.Sprintf("%s\t%d: FAIL: %s not matched by %s\n", output, i, actualFmt, matcher) - } - } else if reflect.TypeOf(expected) == reflect.TypeOf((*AnythingOfTypeArgument)(nil)).Elem() { - - // type checking - if reflect.TypeOf(actual).Name() != string(expected.(AnythingOfTypeArgument)) && reflect.TypeOf(actual).String() != string(expected.(AnythingOfTypeArgument)) { - // not match - differences++ - output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, expected, reflect.TypeOf(actual).Name(), actualFmt) - } - - } else if reflect.TypeOf(expected) == reflect.TypeOf((*IsTypeArgument)(nil)) { - t := expected.(*IsTypeArgument).t - if reflect.TypeOf(t) != reflect.TypeOf(actual) { - differences++ - output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, reflect.TypeOf(t).Name(), reflect.TypeOf(actual).Name(), actualFmt) - } - } else { - - // normal checking - - if assert.ObjectsAreEqual(expected, Anything) || assert.ObjectsAreEqual(actual, Anything) || assert.ObjectsAreEqual(actual, expected) { - // match - output = fmt.Sprintf("%s\t%d: PASS: %s == %s\n", output, i, actualFmt, expectedFmt) - } else { - // not match - differences++ - output = fmt.Sprintf("%s\t%d: FAIL: %s != %s\n", output, i, actualFmt, expectedFmt) - } - } - - } - - if differences == 0 { - return "No differences.", differences - } - - return output, differences - -} - -// Assert compares the arguments with the specified objects and fails if -// they do not exactly match. -func (args Arguments) Assert(t TestingT, objects ...interface{}) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - - // get the differences - diff, diffCount := args.Diff(objects) - - if diffCount == 0 { - return true - } - - // there are differences... report them... - t.Logf(diff) - t.Errorf("%sArguments do not match.", assert.CallerInfo()) - - return false - -} - -// String gets the argument at the specified index. Panics if there is no argument, or -// if the argument is of the wrong type. -// -// If no index is provided, String() returns a complete string representation -// of the arguments. -func (args Arguments) String(indexOrNil ...int) string { - - if len(indexOrNil) == 0 { - // normal String() method - return a string representation of the args - var argsStr []string - for _, arg := range args { - argsStr = append(argsStr, fmt.Sprintf("%T", arg)) // handles nil nicely - } - return strings.Join(argsStr, ",") - } else if len(indexOrNil) == 1 { - // Index has been specified - get the argument at that index - var index = indexOrNil[0] - var s string - var ok bool - if s, ok = args.Get(index).(string); !ok { - panic(fmt.Sprintf("assert: arguments: String(%d) failed because object wasn't correct type: %s", index, args.Get(index))) - } - return s - } - - panic(fmt.Sprintf("assert: arguments: Wrong number of arguments passed to String. Must be 0 or 1, not %d", len(indexOrNil))) - -} - -// Int gets the argument at the specified index. Panics if there is no argument, or -// if the argument is of the wrong type. -func (args Arguments) Int(index int) int { - var s int - var ok bool - if s, ok = args.Get(index).(int); !ok { - panic(fmt.Sprintf("assert: arguments: Int(%d) failed because object wasn't correct type: %v", index, args.Get(index))) - } - return s -} - -// Error gets the argument at the specified index. Panics if there is no argument, or -// if the argument is of the wrong type. -func (args Arguments) Error(index int) error { - obj := args.Get(index) - var s error - var ok bool - if obj == nil { - return nil - } - if s, ok = obj.(error); !ok { - panic(fmt.Sprintf("assert: arguments: Error(%d) failed because object wasn't correct type: %v", index, args.Get(index))) - } - return s -} - -// Bool gets the argument at the specified index. Panics if there is no argument, or -// if the argument is of the wrong type. -func (args Arguments) Bool(index int) bool { - var s bool - var ok bool - if s, ok = args.Get(index).(bool); !ok { - panic(fmt.Sprintf("assert: arguments: Bool(%d) failed because object wasn't correct type: %v", index, args.Get(index))) - } - return s -} - -func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) { - t := reflect.TypeOf(v) - k := t.Kind() - - if k == reflect.Ptr { - t = t.Elem() - k = t.Kind() - } - return t, k -} - -func diffArguments(expected Arguments, actual Arguments) string { - if len(expected) != len(actual) { - return fmt.Sprintf("Provided %v arguments, mocked for %v arguments", len(expected), len(actual)) - } - - for x := range expected { - if diffString := diff(expected[x], actual[x]); diffString != "" { - return fmt.Sprintf("Difference found in argument %v:\n\n%s", x, diffString) - } - } - - return "" -} - -// diff returns a diff of both values as long as both are of the same type and -// are a struct, map, slice or array. Otherwise it returns an empty string. -func diff(expected interface{}, actual interface{}) string { - if expected == nil || actual == nil { - return "" - } - - et, ek := typeAndKind(expected) - at, _ := typeAndKind(actual) - - if et != at { - return "" - } - - if ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array { - return "" - } - - e := spewConfig.Sdump(expected) - a := spewConfig.Sdump(actual) - - diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ - A: difflib.SplitLines(e), - B: difflib.SplitLines(a), - FromFile: "Expected", - FromDate: "", - ToFile: "Actual", - ToDate: "", - Context: 1, - }) - - return diff -} - -var spewConfig = spew.ConfigState{ - Indent: " ", - DisablePointerAddresses: true, - DisableCapacities: true, - SortKeys: true, -} - -type tHelper interface { - Helper() -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 1ae4c2530..8cffd191f 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -46,6 +46,19 @@ github.com/containerd/containerd/errdefs github.com/danieljoos/wincred # github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew/spew +# github.com/devfile/api v0.0.0-20201103130402-29b8738e196e +github.com/devfile/api/pkg/apis/workspaces/v1alpha2 +github.com/devfile/api/pkg/devfile +# github.com/devfile/library v0.0.0-20201112211805-e68d67cf4204 +github.com/devfile/library/pkg/devfile +github.com/devfile/library/pkg/devfile/parser +github.com/devfile/library/pkg/devfile/parser/context +github.com/devfile/library/pkg/devfile/parser/data +github.com/devfile/library/pkg/devfile/parser/data/v2 +github.com/devfile/library/pkg/devfile/parser/data/v2/2.0.0 +github.com/devfile/library/pkg/devfile/parser/data/v2/common +github.com/devfile/library/pkg/testingutil/filesystem +github.com/devfile/library/pkg/util # github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/dgrijalva/jwt-go # github.com/docker/distribution v2.7.1+incompatible @@ -216,7 +229,7 @@ github.com/gregjones/httpcache github.com/gregjones/httpcache/diskcache # github.com/hashicorp/errwrap v1.0.0 github.com/hashicorp/errwrap -# github.com/hashicorp/go-multierror v1.0.0 +# github.com/hashicorp/go-multierror v1.1.0 github.com/hashicorp/go-multierror # github.com/hashicorp/golang-lru v0.5.3 github.com/hashicorp/golang-lru @@ -229,7 +242,7 @@ github.com/imdario/mergo github.com/inconshreveable/mousetrap # github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 github.com/jbenet/go-context/io -# github.com/json-iterator/go v1.1.8 +# github.com/json-iterator/go v1.1.9 github.com/json-iterator/go # github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/kballard/go-shellquote @@ -435,11 +448,8 @@ github.com/spf13/afero/mem github.com/spf13/cobra # github.com/spf13/pflag v1.0.5 github.com/spf13/pflag -# github.com/stretchr/objx v0.2.0 -github.com/stretchr/objx # github.com/stretchr/testify v1.6.1 github.com/stretchr/testify/assert -github.com/stretchr/testify/mock github.com/stretchr/testify/require # github.com/xanzy/ssh-agent v0.2.1 github.com/xanzy/ssh-agent