From 6285c32a6075e6e06f9bd81c359ff14b1e62e0fd Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Thu, 30 Nov 2023 22:41:25 +0100 Subject: [PATCH 1/4] Make tests start an HTTP server service Devfile artifacts This allows us to remove the dependency on a Devfile Registry server. We no longer want to have a long-running cluster to which a Devfile registry is deployed. And relying on the public staging registry makes those tests sometimes fail, due to the frequency of updates and changes that break our tests. Now, an HTTP Server instance is started on a random ports and serves the OCI artifacts for the stacks that are useful for our tests. Note that this will now be the default behavior, unless the DEVFILE_REGISTRY env var is explicitly set. This allows us to also update the stacks at our own pace. The process for updating is as follows: 1- update the stacks folder under tests/helper/registry_server/testdata/registry 2- run 'generate-test-registry-build' to regenerate the Devfile Index and OCI archives for stack extra-files 3- Commit and push the changes --- Makefile | 8 + go.mod | 2 + tests/helper/helper_generic.go | 37 +- tests/helper/helper_registry.go | 10 +- tests/helper/registry_server/mock_registry.go | 516 ++++++++++++ .../testdata/build-registry.sh | 20 + .../testdata/registry-build/README.md | 6 + .../testdata/registry-build/index.json | 737 ++++++++++++++++++ .../stacks/dotnet50/devfile.yaml | 56 ++ .../stacks/dotnet60/devfile.yaml | 56 ++ .../stacks/go/1.0.2/devfile.yaml | 53 ++ .../stacks/go/1.2.0/devfile.yaml | 76 ++ .../stacks/go/2.2.0/archive.tar | Bin 0 -> 608 bytes .../stacks/go/2.2.0/devfile.yaml | 103 +++ .../registry-build/stacks/go/stack.yaml | 11 + .../stacks/java-maven/1.2.0/devfile.yaml | 63 ++ .../stacks/java-maven/1.3.0/devfile.yaml | 63 ++ .../stacks/java-maven/stack.yaml | 9 + .../stacks/java-openliberty/devfile.yaml | 103 +++ .../stacks/java-springboot/1.3.0/devfile.yaml | 65 ++ .../stacks/java-springboot/2.1.0/archive.tar | Bin 0 -> 881 bytes .../stacks/java-springboot/2.1.0/devfile.yaml | 92 +++ .../stacks/java-springboot/stack.yaml | 10 + .../stacks/java-vertx/devfile.yaml | 138 ++++ .../stacks/nodejs-angular/2.0.2/devfile.yaml | 50 ++ .../stacks/nodejs-angular/2.1.0/devfile.yaml | 50 ++ .../stacks/nodejs-angular/2.2.0/devfile.yaml | 50 ++ .../stacks/nodejs-angular/stack.yaml | 13 + .../stacks/nodejs-react/2.0.2/devfile.yaml | 47 ++ .../stacks/nodejs-react/2.2.0/devfile.yaml | 47 ++ .../stacks/nodejs-react/stack.yaml | 10 + .../stacks/nodejs/2.1.1/devfile.yaml | 67 ++ .../stacks/nodejs/2.2.0/devfile.yaml | 67 ++ .../registry-build/stacks/nodejs/stack.yaml | 8 + .../stacks/python/2.1.0/devfile.yaml | 62 ++ .../stacks/python/3.0.0/archive.tar | Bin 0 -> 741 bytes .../stacks/python/3.0.0/devfile.yaml | 89 +++ .../registry-build/stacks/python/stack.yaml | 9 + .../testdata/registry/README.md | 6 + .../registry/stacks/dotnet50/devfile.yaml | 56 ++ .../registry/stacks/dotnet60/devfile.yaml | 56 ++ .../registry/stacks/go/1.0.2/devfile.yaml | 53 ++ .../registry/stacks/go/1.2.0/devfile.yaml | 76 ++ .../registry/stacks/go/2.2.0/devfile.yaml | 103 +++ .../stacks/go/2.2.0/docker/Dockerfile | 12 + .../stacks/go/2.2.0/kubernetes/deploy.yaml | 41 + .../testdata/registry/stacks/go/stack.yaml | 11 + .../stacks/java-maven/1.2.0/devfile.yaml | 63 ++ .../stacks/java-maven/1.3.0/devfile.yaml | 63 ++ .../registry/stacks/java-maven/stack.yaml | 9 + .../stacks/java-openliberty/devfile.yaml | 103 +++ .../stacks/java-springboot/1.3.0/devfile.yaml | 65 ++ .../stacks/java-springboot/2.1.0/devfile.yaml | 92 +++ .../java-springboot/2.1.0/docker/Dockerfile | 27 + .../2.1.0/kubernetes/deploy.yaml | 41 + .../stacks/java-springboot/stack.yaml | 10 + .../registry/stacks/java-vertx/devfile.yaml | 138 ++++ .../stacks/nodejs-angular/2.0.2/devfile.yaml | 50 ++ .../stacks/nodejs-angular/2.1.0/devfile.yaml | 50 ++ .../stacks/nodejs-angular/2.2.0/devfile.yaml | 50 ++ .../registry/stacks/nodejs-angular/stack.yaml | 13 + .../stacks/nodejs-react/2.0.2/devfile.yaml | 47 ++ .../stacks/nodejs-react/2.2.0/devfile.yaml | 47 ++ .../registry/stacks/nodejs-react/stack.yaml | 10 + .../registry/stacks/nodejs/2.1.1/devfile.yaml | 67 ++ .../registry/stacks/nodejs/2.2.0/devfile.yaml | 67 ++ .../registry/stacks/nodejs/stack.yaml | 8 + .../registry/stacks/python/2.1.0/devfile.yaml | 62 ++ .../registry/stacks/python/3.0.0/devfile.yaml | 89 +++ .../stacks/python/3.0.0/docker/Dockerfile | 20 + .../python/3.0.0/kubernetes/deploy.yaml | 41 + .../registry/stacks/python/stack.yaml | 9 + .../github.com/felixge/httpsnoop/.gitignore | 0 .../github.com/felixge/httpsnoop/.travis.yml | 6 + .../github.com/felixge/httpsnoop/LICENSE.txt | 19 + vendor/github.com/felixge/httpsnoop/Makefile | 10 + vendor/github.com/felixge/httpsnoop/README.md | 95 +++ .../felixge/httpsnoop/capture_metrics.go | 86 ++ vendor/github.com/felixge/httpsnoop/docs.go | 10 + .../httpsnoop/wrap_generated_gteq_1.8.go | 436 +++++++++++ .../httpsnoop/wrap_generated_lt_1.8.go | 278 +++++++ vendor/github.com/gorilla/handlers/LICENSE | 22 + vendor/github.com/gorilla/handlers/README.md | 56 ++ .../github.com/gorilla/handlers/canonical.go | 74 ++ .../github.com/gorilla/handlers/compress.go | 143 ++++ vendor/github.com/gorilla/handlers/cors.go | 355 +++++++++ vendor/github.com/gorilla/handlers/doc.go | 9 + .../github.com/gorilla/handlers/handlers.go | 147 ++++ vendor/github.com/gorilla/handlers/logging.go | 244 ++++++ .../gorilla/handlers/proxy_headers.go | 120 +++ .../github.com/gorilla/handlers/recovery.go | 96 +++ vendor/modules.txt | 6 + 92 files changed, 6658 insertions(+), 12 deletions(-) create mode 100644 tests/helper/registry_server/mock_registry.go create mode 100644 tests/helper/registry_server/testdata/build-registry.sh create mode 100644 tests/helper/registry_server/testdata/registry-build/README.md create mode 100644 tests/helper/registry_server/testdata/registry-build/index.json create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/dotnet50/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/dotnet60/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/go/1.0.2/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/go/1.2.0/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/go/2.2.0/archive.tar create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/go/2.2.0/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/go/stack.yaml create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/java-maven/1.2.0/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/java-maven/1.3.0/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/java-maven/stack.yaml create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/java-openliberty/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/java-springboot/1.3.0/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/java-springboot/2.1.0/archive.tar create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/java-springboot/2.1.0/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/java-springboot/stack.yaml create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/java-vertx/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/nodejs-angular/2.0.2/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/nodejs-angular/2.1.0/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/nodejs-angular/2.2.0/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/nodejs-angular/stack.yaml create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/nodejs-react/2.0.2/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/nodejs-react/2.2.0/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/nodejs-react/stack.yaml create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/nodejs/2.1.1/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/nodejs/2.2.0/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/nodejs/stack.yaml create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/python/2.1.0/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/python/3.0.0/archive.tar create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/python/3.0.0/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry-build/stacks/python/stack.yaml create mode 100644 tests/helper/registry_server/testdata/registry/README.md create mode 100644 tests/helper/registry_server/testdata/registry/stacks/dotnet50/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry/stacks/dotnet60/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry/stacks/go/1.0.2/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry/stacks/go/1.2.0/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry/stacks/go/2.2.0/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry/stacks/go/2.2.0/docker/Dockerfile create mode 100644 tests/helper/registry_server/testdata/registry/stacks/go/2.2.0/kubernetes/deploy.yaml create mode 100644 tests/helper/registry_server/testdata/registry/stacks/go/stack.yaml create mode 100644 tests/helper/registry_server/testdata/registry/stacks/java-maven/1.2.0/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry/stacks/java-maven/1.3.0/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry/stacks/java-maven/stack.yaml create mode 100644 tests/helper/registry_server/testdata/registry/stacks/java-openliberty/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry/stacks/java-springboot/1.3.0/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry/stacks/java-springboot/2.1.0/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry/stacks/java-springboot/2.1.0/docker/Dockerfile create mode 100644 tests/helper/registry_server/testdata/registry/stacks/java-springboot/2.1.0/kubernetes/deploy.yaml create mode 100644 tests/helper/registry_server/testdata/registry/stacks/java-springboot/stack.yaml create mode 100644 tests/helper/registry_server/testdata/registry/stacks/java-vertx/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry/stacks/nodejs-angular/2.0.2/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry/stacks/nodejs-angular/2.1.0/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry/stacks/nodejs-angular/2.2.0/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry/stacks/nodejs-angular/stack.yaml create mode 100644 tests/helper/registry_server/testdata/registry/stacks/nodejs-react/2.0.2/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry/stacks/nodejs-react/2.2.0/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry/stacks/nodejs-react/stack.yaml create mode 100644 tests/helper/registry_server/testdata/registry/stacks/nodejs/2.1.1/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry/stacks/nodejs/2.2.0/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry/stacks/nodejs/stack.yaml create mode 100644 tests/helper/registry_server/testdata/registry/stacks/python/2.1.0/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry/stacks/python/3.0.0/devfile.yaml create mode 100644 tests/helper/registry_server/testdata/registry/stacks/python/3.0.0/docker/Dockerfile create mode 100644 tests/helper/registry_server/testdata/registry/stacks/python/3.0.0/kubernetes/deploy.yaml create mode 100644 tests/helper/registry_server/testdata/registry/stacks/python/stack.yaml create mode 100644 vendor/github.com/felixge/httpsnoop/.gitignore create mode 100644 vendor/github.com/felixge/httpsnoop/.travis.yml create mode 100644 vendor/github.com/felixge/httpsnoop/LICENSE.txt create mode 100644 vendor/github.com/felixge/httpsnoop/Makefile create mode 100644 vendor/github.com/felixge/httpsnoop/README.md create mode 100644 vendor/github.com/felixge/httpsnoop/capture_metrics.go create mode 100644 vendor/github.com/felixge/httpsnoop/docs.go create mode 100644 vendor/github.com/felixge/httpsnoop/wrap_generated_gteq_1.8.go create mode 100644 vendor/github.com/felixge/httpsnoop/wrap_generated_lt_1.8.go create mode 100644 vendor/github.com/gorilla/handlers/LICENSE create mode 100644 vendor/github.com/gorilla/handlers/README.md create mode 100644 vendor/github.com/gorilla/handlers/canonical.go create mode 100644 vendor/github.com/gorilla/handlers/compress.go create mode 100644 vendor/github.com/gorilla/handlers/cors.go create mode 100644 vendor/github.com/gorilla/handlers/doc.go create mode 100644 vendor/github.com/gorilla/handlers/handlers.go create mode 100644 vendor/github.com/gorilla/handlers/logging.go create mode 100644 vendor/github.com/gorilla/handlers/proxy_headers.go create mode 100644 vendor/github.com/gorilla/handlers/recovery.go diff --git a/Makefile b/Makefile index 91ee99d89ea..3ba3e640de4 100644 --- a/Makefile +++ b/Makefile @@ -274,3 +274,11 @@ generate-api: generate-apiserver generate-apifront ## Generate code based on odo .PHONY: copy-swagger-ui copy-swagger-ui: ./scripts/copy-swagger-ui.sh + +generate-test-registry-build: ## Rebuild the local registry artifacts. Only for testing + mkdir -p "${PWD}"/tests/helper/registry_server/testdata/registry-build + rm -rf "${PWD}"/tests/helper/registry_server/testdata/registry-build/* + podman container run --rm \ + -v "${PWD}"/tests/helper/registry_server/testdata:/code \ + -t docker.io/golang:1.19 \ + bash /code/build-registry.sh /code/registry/ /code/registry-build/ diff --git a/go.mod b/go.mod index 5fdce62ae15..35135356dd1 100644 --- a/go.mod +++ b/go.mod @@ -23,6 +23,7 @@ require ( github.com/go-openapi/spec v0.20.8 github.com/golang/mock v1.6.0 github.com/google/go-cmp v0.5.9 + github.com/gorilla/handlers v1.5.1 github.com/gorilla/mux v1.8.0 github.com/jedib0t/go-pretty/v6 v6.4.7 github.com/kubernetes-sigs/service-catalog v0.3.1 @@ -110,6 +111,7 @@ require ( github.com/evanphx/json-patch v4.12.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect + github.com/felixge/httpsnoop v1.0.3 // indirect github.com/go-errors/errors v1.0.1 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.4.1 // indirect diff --git a/tests/helper/helper_generic.go b/tests/helper/helper_generic.go index 543b23b93fa..35502409a3a 100644 --- a/tests/helper/helper_generic.go +++ b/tests/helper/helper_generic.go @@ -22,6 +22,7 @@ import ( envcontext "github.com/redhat-developer/odo/pkg/config/context" "github.com/redhat-developer/odo/pkg/preference" "github.com/redhat-developer/odo/pkg/segment" + "github.com/redhat-developer/odo/tests/helper/registry_server" dfutil "github.com/devfile/library/v2/pkg/util" @@ -179,6 +180,8 @@ type CommonVar struct { // original values to get restored after the test is done OriginalWorkingDirectory string OriginalKubeconfig string + registryServer RegistryServer + registryUrl string // Ginkgo test realted testFileName string testCase string @@ -256,7 +259,7 @@ func CommonBeforeEach() CommonVar { // Use ephemeral volumes (emptyDir) in tests to make test faster err = cfg.SetConfiguration(preference.EphemeralSetting, "true") Expect(err).To(BeNil()) - SetDefaultDevfileRegistryAsStaging() + SetDefaultDevfileRegistry(&commonVar) return commonVar } @@ -299,6 +302,15 @@ func CommonAfterEach(commonVar CommonVar) { } } + if commonVar.registryServer != nil { + err = commonVar.registryServer.Stop() + if err != nil { + fmt.Fprintf(GinkgoWriter, "[warn] failed to stop mock registry server at %q: %v\n", commonVar.registryServer.GetUrl(), err) + } + commonVar.registryServer = nil + commonVar.registryUrl = "" + } + if commonVar.Project != "" && commonVar.CliRunner.HasNamespaceProject(commonVar.Project) { // delete the random project/namespace created in CommonBeforeEach commonVar.CliRunner.DeleteNamespaceProject(commonVar.Project, false) @@ -394,20 +406,23 @@ type ResourceInfo struct { Namespace string } -func SetDefaultDevfileRegistryAsStaging() { +func SetDefaultDevfileRegistry(commonVar *CommonVar) { + commonVar.registryUrl = os.Getenv("DEVFILE_REGISTRY") + if commonVar.registryUrl == "" { + commonVar.registryServer = registry_server.NewMockRegistryServer() + var err error + commonVar.registryUrl, err = commonVar.registryServer.Start() + Expect(err).ShouldNot(HaveOccurred()) + } + fmt.Printf("Using Devfile Registry URL at: %q\n", commonVar.registryUrl) + const registryName string = "DefaultDevfileRegistry" Cmd("odo", "preference", "remove", "registry", registryName, "-f").ShouldPass() - Cmd("odo", "preference", "add", "registry", registryName, GetDevfileRegistryURL()).ShouldPass() + Cmd("odo", "preference", "add", "registry", registryName, commonVar.registryUrl).ShouldPass() } -func GetDevfileRegistryURL() string { - registryURL := "https://registry.stage.devfile.io" - customReg := os.Getenv("DEVFILE_REGISTRY") - if customReg != "" { - registryURL = customReg - } - fmt.Printf("Using Devfile Registry URL at: %q\n", registryURL) - return registryURL +func (c CommonVar) GetDevfileRegistryURL() string { + return c.registryUrl } func GetOdoVersion() (version string, gitCommit string) { diff --git a/tests/helper/helper_registry.go b/tests/helper/helper_registry.go index c2a092463fc..997a836ffd8 100644 --- a/tests/helper/helper_registry.go +++ b/tests/helper/helper_registry.go @@ -6,6 +6,7 @@ import ( "net/http" "net/url" "regexp" + "strings" . "github.com/onsi/ginkgo/v2" @@ -26,7 +27,7 @@ func NewRegistry(url string) Registry { } func (o Registry) GetIndex() ([]api.DevfileStack, error) { - url, err := url.JoinPath(o.url, "v2index") + url, err := url.JoinPath(strings.TrimSuffix(o.url, "/"), "/v2index") if err != nil { return nil, err } @@ -82,3 +83,10 @@ func GetVersions(registryName string, stackName string) []string { func HasAtLeastTwoVersions(registryName string, stackName string) bool { return len(GetVersions(registryName, stackName)) >= 2 } + +type RegistryServer interface { + Start() (url string, err error) + Stop() error + IsStarted() bool + GetUrl() string +} diff --git a/tests/helper/registry_server/mock_registry.go b/tests/helper/registry_server/mock_registry.go new file mode 100644 index 00000000000..83175cbab67 --- /dev/null +++ b/tests/helper/registry_server/mock_registry.go @@ -0,0 +1,516 @@ +package registry_server + +import ( + "encoding/json" + "errors" + "fmt" + "io" + "io/fs" + "log" + "net/http" + "net/http/httptest" + "os" + "path" + "path/filepath" + "reflect" + "runtime" + "strings" + + "github.com/gorilla/handlers" + "github.com/gorilla/mux" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/opencontainers/go-digest" + "github.com/opencontainers/image-spec/specs-go" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" +) + +const ( + _singleStackVersionName = "___SINGLE_VERSION__" +) + +// MockRegistryServer is an implementation of a Devfile Registry Server, +// inspired by the own Devfile Registry tests at https://github.com/devfile/registry-support/blob/main/index/server/pkg/server/endpoint_test.go. +type MockRegistryServer struct { + started bool + server *httptest.Server +} + +// DevfileStack is the main struct for devfile stack +type DevfileStack struct { + Name string `json:"name"` + Versions []DevfileStackVersion `json:"versions,omitempty"` +} + +type DevfileStackVersion struct { + Version string `json:"version,omitempty"` + IsDefault bool `json:"default"` + SchemaVersion string `json:"schemaVersion,omitempty"` + StarterProjects []string `json:"starterProjects"` +} + +var manifests map[string]map[string]ocispec.Manifest + +func init() { + manifests = make(map[string]map[string]ocispec.Manifest) + stackRoot := filepath.Join(getRegistryBasePath(), "stacks") + _, err := os.Stat(stackRoot) + if err != nil && errors.Is(err, fs.ErrNotExist) { + log.Fatalf("file not found: %v - reason: %s. Did you run 'make generate-test-registry-build'?", stackRoot, err) + } + + listFilesInDir := func(p string, excludeIf func(f os.FileInfo) bool) (res []string, err error) { + file, err := os.Open(p) + if err != nil { + return nil, err + } + defer file.Close() + files, err := file.Readdir(0) + if err != nil { + return nil, err + } + for _, f := range files { + if excludeIf != nil && excludeIf(f) { + continue + } + res = append(res, f.Name()) + } + return res, nil + } + + newManifest := func() ocispec.Manifest { + return ocispec.Manifest{ + Versioned: specs.Versioned{SchemaVersion: 2}, + Config: ocispec.Descriptor{ + MediaType: "application/vnd.devfileio.devfile.config.v2+json", + }, + } + } + + buildLayerForFile := func(fpath string) (layer ocispec.Descriptor, err error) { + stat, err := os.Stat(fpath) + if err != nil { + return ocispec.Descriptor{}, err + } + + dgest, err := digestFile(fpath) + if err != nil { + return ocispec.Descriptor{}, err + } + layer.Digest = digest.Digest(dgest) + + f := filepath.Base(filepath.Clean(fpath)) + if f == "devfile.yaml" { + layer.MediaType = "application/vnd.devfileio.devfile.layer.v1" + } else if strings.HasSuffix(f, ".tar") { + layer.MediaType = "application/x-tar" + } + + layer.Size = stat.Size() + layer.Annotations = map[string]string{ + "org.opencontainers.image.title": f, + } + return layer, nil + } + + excludeIfDirFn := func(f os.FileInfo) bool { + return f.IsDir() + } + excludeIfNotDirFn := func(f os.FileInfo) bool { + return !f.IsDir() + } + + dirsInStacksRoot, err := listFilesInDir(stackRoot, excludeIfNotDirFn) + if err != nil { + log.Fatalf(err.Error()) + } + for _, f := range dirsInStacksRoot { + manifests[f] = make(map[string]ocispec.Manifest) + versionList, err := listFilesInDir(filepath.Join(stackRoot, f), excludeIfNotDirFn) + if err != nil { + log.Fatalf(err.Error()) + } + if len(versionList) == 0 { + // Possible stack with single unnamed version + stackFiles, err := listFilesInDir(filepath.Join(stackRoot, f), excludeIfDirFn) + if err != nil { + log.Fatalf(err.Error()) + } + manifest := newManifest() + for _, vf := range stackFiles { + layer, err := buildLayerForFile(filepath.Join(stackRoot, f, vf)) + if err != nil { + log.Fatalf(err.Error()) + } + manifest.Layers = append(manifest.Layers, layer) + } + manifests[f][_singleStackVersionName] = manifest + continue + } + for _, v := range versionList { + versionFiles, err := listFilesInDir(filepath.Join(stackRoot, f, v), excludeIfDirFn) + if err != nil { + log.Fatalf(err.Error()) + } + manifest := newManifest() + for _, vf := range versionFiles { + layer, err := buildLayerForFile(filepath.Join(stackRoot, f, v, vf)) + if err != nil { + log.Fatalf(err.Error()) + } + manifest.Layers = append(manifest.Layers, layer) + } + manifests[f][v] = manifest + } + } +} + +func NewMockRegistryServer() *MockRegistryServer { + r := mux.NewRouter() + m := MockRegistryServer{ + server: httptest.NewUnstartedServer(handlers.LoggingHandler(GinkgoWriter, r)), + } + + m.setupRoutes(r) + return &m +} + +func (m *MockRegistryServer) Start() (url string, err error) { + m.server.Start() + m.started = true + fmt.Fprintln(GinkgoWriter, "Mock Devfile Registry server started and available at", m.server.URL) + return m.server.URL, nil +} + +func (m *MockRegistryServer) Stop() error { + m.server.Close() + m.started = false + return nil +} + +func (m *MockRegistryServer) GetUrl() string { + return m.server.URL +} + +func (m *MockRegistryServer) IsStarted() bool { + return m.started +} + +func notFoundManifest(res http.ResponseWriter, req *http.Request, tag string) { + var data string + if req.Method == http.MethodGet { + data = fmt.Sprintf(` +{ + "code": "MANIFEST_UNKNOWN", + "message": "manifest unknown", + "detail": { + "tag": %s + } +} +`, tag) + } + res.WriteHeader(http.StatusNotFound) + _, err := res.Write([]byte(data)) + if err != nil { + fmt.Fprintln(GinkgoWriter, "[warn] failed to write response; cause:", err) + } +} + +// notFound custom handler for anything not found +func notFound(res http.ResponseWriter, req *http.Request, data string) { + res.WriteHeader(http.StatusNotFound) + _, err := res.Write([]byte(data)) + if err != nil { + fmt.Fprintln(GinkgoWriter, "[warn] failed to write response; cause:", err) + } +} + +func internalServerError(res http.ResponseWriter, req *http.Request, data string) { + res.WriteHeader(http.StatusInternalServerError) + _, err := res.Write([]byte(fmt.Sprintf(`{"detail": %q}`, data))) + if err != nil { + fmt.Fprintln(GinkgoWriter, "[warn] failed to write response; cause:", err) + } +} + +// setupRoutes setups the routing, based on the OpenAPI Schema defined at: +// https://github.com/devfile/registry-support/blob/main/index/server/openapi.yaml +func (m *MockRegistryServer) setupRoutes(r *mux.Router) { + r.HandleFunc("/v2index", serveV2Index).Methods(http.MethodGet) + r.HandleFunc("/v2/devfile-catalog/{stack}/manifests/{ref}", serveManifests).Methods(http.MethodGet, http.MethodHead) + r.HandleFunc("/v2/devfile-catalog/{stack}/blobs/{digest}", serveBlobs).Methods(http.MethodGet) + r.HandleFunc("/devfiles/{stack}", m.serveDevfileDefaultVersion).Methods(http.MethodGet) + r.HandleFunc("/devfiles/{stack}/{version}", m.serveDevfileAtVersion).Methods(http.MethodGet) +} + +func getRegistryBasePath() string { + _, filename, _, _ := runtime.Caller(1) + return filepath.Join(path.Dir(filename), "testdata", "registry-build") +} + +func serveV2Index(res http.ResponseWriter, req *http.Request) { + index := filepath.Join(getRegistryBasePath(), "index.json") + d, err := os.ReadFile(index) + if err != nil { + internalServerError(res, req, err.Error()) + return + } + _, err = res.Write(d) + if err != nil { + fmt.Fprintln(GinkgoWriter, "[warn] failed to write response; cause:", err) + } +} + +func serveManifests(res http.ResponseWriter, req *http.Request) { + vars := mux.Vars(req) + stack := vars["stack"] + ref := vars["ref"] + var ( + stackManifest ocispec.Manifest + found bool + bytes []byte + err error + ) + + if strings.HasPrefix(ref, "sha256:") { + var stackManifests map[string]ocispec.Manifest + stackManifests, found = manifests[stack] + if !found { + notFoundManifest(res, req, ref) + return + } + found = false + var dgst string + for _, manifest := range stackManifests { + dgst, err = digestEntity(manifest) + if err != nil { + internalServerError(res, req, "") + return + } + if reflect.DeepEqual(ref, dgst) { + stackManifest = manifest + found = true + break + } + } + if !found { + notFoundManifest(res, req, ref) + return + } + } else { + stackManifest, found = manifests[stack][ref] + if !found { + // Possible single unnamed version + stackManifest, found = manifests[stack][_singleStackVersionName] + if !found { + notFoundManifest(res, req, ref) + return + } + } + } + + var j []byte + if j, err = json.MarshalIndent(stackManifest, " ", " "); err != nil { + fmt.Fprintln(GinkgoWriter, "[debug] stackManifest:", stackManifest) + } else { + fmt.Fprintln(GinkgoWriter, "[debug] stackManifest:", string(j)) + } + + if req.Method == http.MethodGet { + bytes, err = json.Marshal(stackManifest) + if err != nil { + internalServerError(res, req, err.Error()) + return + } + } + + res.Header().Set("Content-Type", ocispec.MediaTypeImageManifest) + res.WriteHeader(http.StatusOK) + _, err = res.Write(bytes) + if err != nil { + fmt.Fprintln(GinkgoWriter, "[warn] failed to write response; cause:", err) + } +} + +func serveBlobs(res http.ResponseWriter, req *http.Request) { + vars := mux.Vars(req) + stack := vars["stack"] + sDigest := vars["digest"] + stackRoot := filepath.Join(getRegistryBasePath(), "stacks", stack) + var ( + blobPath string + found bool + err error + ) + + found = false + err = filepath.WalkDir(stackRoot, func(path string, d fs.DirEntry, err error) error { + var fdgst string + + if err != nil { + return err + } + + if found || d.IsDir() { + return nil + } + + fdgst, err = digestFile(path) + if err != nil { + return err + } + if reflect.DeepEqual(sDigest, fdgst) { + blobPath = path + found = true + } + + return nil + }) + if err != nil || !found { + notFound(res, req, "") + return + } + + file, err := os.Open(blobPath) + Expect(err).ShouldNot(HaveOccurred()) + defer file.Close() + + bytes, err := io.ReadAll(file) + Expect(err).ShouldNot(HaveOccurred()) + + res.WriteHeader(http.StatusOK) + res.Header().Set("Content-Type", http.DetectContentType(bytes)) + _, err = res.Write(bytes) + if err != nil { + fmt.Fprintln(GinkgoWriter, "[warn] failed to write response; cause:", err) + } +} + +func (m *MockRegistryServer) serveDevfileDefaultVersion(res http.ResponseWriter, req *http.Request) { + vars := mux.Vars(req) + stack := vars["stack"] + + defaultVersion, internalErr, err := findStackDefaultVersion(stack) + if err != nil { + if internalErr { + internalServerError(res, req, "") + } else { + notFound(res, req, "") + } + return + } + + http.Redirect(res, req, fmt.Sprintf("%s/devfiles/%s/%s", m.GetUrl(), stack, defaultVersion), http.StatusSeeOther) +} + +func findStackDefaultVersion(stack string) (string, bool, error) { + index, err := parseIndex() + if index == nil { + return "", true, err + } + for _, d := range index { + if d.Name != stack { + continue + } + for _, v := range d.Versions { + if v.IsDefault { + return v.Version, false, nil + } + } + } + return "", false, fmt.Errorf("default version not found for %q", stack) +} + +func parseIndex() ([]DevfileStack, error) { + // find the default version + index := filepath.Join(getRegistryBasePath(), "index.json") + d, err := os.ReadFile(index) + if err != nil { + return nil, err + } + + var objmap []DevfileStack + err = json.Unmarshal(d, &objmap) + if err != nil { + return nil, err + } + return objmap, nil +} + +func (m *MockRegistryServer) serveDevfileAtVersion(res http.ResponseWriter, req *http.Request) { + vars := mux.Vars(req) + stack := vars["stack"] + version := vars["version"] + + // find layer for this version and redirect to the blob download URL + manifestByVersionMap, ok := manifests[stack] + if !ok { + notFound(res, req, "") + return + } + manifest, ok := manifestByVersionMap[version] + if ok { + // find blob with devfile + for _, layer := range manifest.Layers { + if layer.Annotations["org.opencontainers.image.title"] == "devfile.yaml" { + http.Redirect(res, req, fmt.Sprintf("%s/v2/devfile-catalog/%s/blobs/%s", m.GetUrl(), stack, layer.Digest), http.StatusSeeOther) + return + } + } + notFound(res, req, "devfile.yaml not found") + return + } + + // find if devfile has a single version that matches the default version in index + defaultVersion, internalErr, err := findStackDefaultVersion(stack) + if err != nil { + if internalErr { + internalServerError(res, req, "") + } else { + notFound(res, req, "") + } + return + } + if defaultVersion != version { + notFound(res, req, "default version for this stack is:"+defaultVersion) + return + } + manifest, ok = manifestByVersionMap[defaultVersion] + if ok { + // find blob with devfile + for _, layer := range manifest.Layers { + if layer.Annotations["org.opencontainers.image.title"] == "devfile.yaml" { + http.Redirect(res, req, fmt.Sprintf("%s/v2/devfile-catalog/%s/blobs/%s", m.GetUrl(), stack, layer.Digest), http.StatusSeeOther) + return + } + } + notFound(res, req, "devfile.yaml not found") + return + } +} + +// digestEntity generates sha256 digest of any entity type +func digestEntity(e interface{}) (string, error) { + bytes, err := json.Marshal(e) + if err != nil { + return "", err + } + + return digest.FromBytes(bytes).String(), nil +} + +// digestFile generates sha256 digest from file contents +func digestFile(filepath string) (string, error) { + file, err := os.Open(filepath) + if err != nil { + return "", err + } + defer file.Close() + + dgst, err := digest.FromReader(file) + if err != nil { + return "", err + } + + return dgst.String(), nil +} diff --git a/tests/helper/registry_server/testdata/build-registry.sh b/tests/helper/registry_server/testdata/build-registry.sh new file mode 100644 index 00000000000..ee229aa9df5 --- /dev/null +++ b/tests/helper/registry_server/testdata/build-registry.sh @@ -0,0 +1,20 @@ +#/bin/bash + +set -eo pipefail + +if [ "$#" -lt 2 ]; then + echo "Wrong number of arguments. Usage: ./build-registry.sh /path/to/registry/dir /path/to/empty/build/dir" + exit 1 +fi + +registryDir=$1 +outputDir=$2 + +TEMPDIR=$(mktemp -d) +( + cd ${TEMPDIR} && + git clone -b deterministic_stack_tar_archives_in_build_script --depth 1 --single-branch https://github.com/rm3l/devfile-registry-support . +) + +bash "${TEMPDIR}"/build-tools/build.sh "$registryDir" "$outputDir" +rm -rf "${TEMPDIR}" diff --git a/tests/helper/registry_server/testdata/registry-build/README.md b/tests/helper/registry_server/testdata/registry-build/README.md new file mode 100644 index 00000000000..e9b2126ed57 --- /dev/null +++ b/tests/helper/registry_server/testdata/registry-build/README.md @@ -0,0 +1,6 @@ +This folder is used to generate and serve artifacts by a Devfile Registry started only for testing. + +To update, simply copy the relevant files from an existing folder from an existing registry stacks folder (see https://github.com/devfile/registry/tree/main/stacks) +to this folder. +Then, and anytime a change is made to the source `registry/stacks` folder, you need to run 'make generate-test-registry-build' +to regenerate the `registry-build` folder with the artifacts that will be served for the tests. \ No newline at end of file diff --git a/tests/helper/registry_server/testdata/registry-build/index.json b/tests/helper/registry_server/testdata/registry-build/index.json new file mode 100644 index 00000000000..3d06c82805d --- /dev/null +++ b/tests/helper/registry_server/testdata/registry-build/index.json @@ -0,0 +1,737 @@ +[ + { + "name": "dotnet50", + "displayName": ".NET 5.0", + "description": ".NET 5.0 application", + "type": "stack", + "tags": [ + ".NET", + ".NET 5.0" + ], + "icon": "https://github.com/dotnet/brand/raw/main/logo/dotnet-logo.png", + "projectType": "dotnet", + "language": ".NET", + "versions": [ + { + "version": "1.0.3", + "schemaVersion": "2.1.0", + "default": true, + "description": ".NET 5.0 application", + "tags": [ + ".NET", + ".NET 5.0" + ], + "icon": "https://github.com/dotnet/brand/raw/main/logo/dotnet-logo.png", + "links": { + "self": "devfile-catalog/dotnet50:1.0.3" + }, + "commandGroups": { + "build": true, + "debug": false, + "deploy": false, + "run": true, + "test": false + }, + "resources": [ + "devfile.yaml" + ], + "starterProjects": [ + "dotnet50-example" + ] + } + ] + }, + { + "name": "dotnet60", + "displayName": ".NET 6.0", + "description": ".NET 6.0 application", + "type": "stack", + "tags": [ + ".NET", + ".NET 6.0" + ], + "icon": "https://github.com/dotnet/brand/raw/main/logo/dotnet-logo.png", + "projectType": "dotnet", + "language": ".NET", + "versions": [ + { + "version": "1.0.2", + "schemaVersion": "2.1.0", + "default": true, + "description": ".NET 6.0 application", + "tags": [ + ".NET", + ".NET 6.0" + ], + "icon": "https://github.com/dotnet/brand/raw/main/logo/dotnet-logo.png", + "links": { + "self": "devfile-catalog/dotnet60:1.0.2" + }, + "commandGroups": { + "build": true, + "debug": false, + "deploy": false, + "run": true, + "test": false + }, + "resources": [ + "devfile.yaml" + ], + "starterProjects": [ + "dotnet60-example" + ] + } + ] + }, + { + "name": "go", + "displayName": "Go Runtime", + "description": "Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.", + "type": "stack", + "tags": [ + "Go", + "Deprecated" + ], + "icon": "https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/golang.svg", + "projectType": "Go", + "language": "Go", + "provider": "Red Hat", + "versions": [ + { + "version": "2.2.0", + "schemaVersion": "2.2.0", + "description": "Go (version 1.19.x) is an open source programming language that makes it easy to build simple, reliable, and efficient software.", + "tags": [ + "Go" + ], + "icon": "https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/golang.svg", + "links": { + "self": "devfile-catalog/go:2.2.0" + }, + "commandGroups": { + "build": true, + "debug": true, + "deploy": true, + "run": true, + "test": false + }, + "resources": [ + "archive.tar", + "devfile.yaml" + ], + "starterProjects": [ + "go-starter" + ] + }, + { + "version": "1.2.0", + "schemaVersion": "2.1.0", + "default": true, + "description": "Go (version 1.19.x) is an open source programming language that makes it easy to build simple, reliable, and efficient software.", + "tags": [ + "Go" + ], + "icon": "https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/golang.svg", + "links": { + "self": "devfile-catalog/go:1.2.0" + }, + "commandGroups": { + "build": true, + "debug": true, + "deploy": false, + "run": true, + "test": false + }, + "resources": [ + "devfile.yaml" + ], + "starterProjects": [ + "go-starter" + ] + }, + { + "version": "1.0.2", + "schemaVersion": "2.1.0", + "description": "Go (version 1.18.x) is an open source programming language that makes it easy to build simple, reliable, and efficient software.", + "tags": [ + "Go", + "Deprecated" + ], + "icon": "https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/golang.svg", + "links": { + "self": "devfile-catalog/go:1.0.2" + }, + "commandGroups": { + "build": true, + "debug": false, + "deploy": false, + "run": true, + "test": false + }, + "resources": [ + "devfile.yaml" + ], + "starterProjects": [ + "go-starter" + ] + } + ] + }, + { + "name": "java-maven", + "displayName": "Maven Java", + "description": "Java application based on Maven and OpenJDK", + "type": "stack", + "tags": [ + "Java", + "Maven" + ], + "icon": "https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/java-maven.jpg", + "projectType": "Maven", + "language": "Java", + "versions": [ + { + "version": "1.3.0", + "schemaVersion": "2.1.0", + "default": true, + "description": "Java application based on Maven 3.6 and OpenJDK 17", + "tags": [ + "Java", + "Maven" + ], + "icon": "https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/java-maven.jpg", + "links": { + "self": "devfile-catalog/java-maven:1.3.0" + }, + "commandGroups": { + "build": true, + "debug": true, + "deploy": false, + "run": true, + "test": false + }, + "resources": [ + "devfile.yaml" + ], + "starterProjects": [ + "springbootproject" + ] + }, + { + "version": "1.2.0", + "schemaVersion": "2.1.0", + "description": "Java application based on Maven 3.6 and OpenJDK 11", + "tags": [ + "Java", + "Maven" + ], + "icon": "https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/java-maven.jpg", + "links": { + "self": "devfile-catalog/java-maven:1.2.0" + }, + "commandGroups": { + "build": true, + "debug": true, + "deploy": false, + "run": true, + "test": false + }, + "resources": [ + "devfile.yaml" + ], + "starterProjects": [ + "springbootproject" + ] + } + ] + }, + { + "name": "java-openliberty", + "displayName": "Open Liberty Maven", + "description": "Java application based on Java 11 and Maven 3.8, using the Open Liberty runtime 22.0.0.1", + "type": "stack", + "tags": [ + "Java", + "Maven" + ], + "architectures": [ + "amd64", + "ppc64le", + "s390x" + ], + "icon": "https://raw.githubusercontent.com/OpenLiberty/logos/7fbb132949b9b2589e18c8d5665c1b107028a21d/logomark/svg/OL_logomark.svg", + "projectType": "Open Liberty", + "language": "Java", + "versions": [ + { + "version": "0.9.0", + "schemaVersion": "2.1.0", + "default": true, + "description": "Java application based on Java 11 and Maven 3.8, using the Open Liberty runtime 22.0.0.1", + "tags": [ + "Java", + "Maven" + ], + "architectures": [ + "amd64", + "ppc64le", + "s390x" + ], + "icon": "https://raw.githubusercontent.com/OpenLiberty/logos/7fbb132949b9b2589e18c8d5665c1b107028a21d/logomark/svg/OL_logomark.svg", + "links": { + "self": "devfile-catalog/java-openliberty:0.9.0" + }, + "commandGroups": { + "build": false, + "debug": true, + "deploy": false, + "run": true, + "test": true + }, + "resources": [ + "devfile.yaml" + ], + "starterProjects": [ + "rest" + ] + } + ] + }, + { + "name": "java-springboot", + "displayName": "Spring Boot", + "description": "Spring Boot using Java", + "type": "stack", + "tags": [ + "Java", + "Spring" + ], + "icon": "https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/spring.svg", + "projectType": "springboot", + "language": "Java", + "versions": [ + { + "version": "2.1.0", + "schemaVersion": "2.2.0", + "description": "Java application using Spring Boot® and OpenJDK 11", + "tags": [ + "Java", + "Spring" + ], + "icon": "https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/spring.svg", + "links": { + "self": "devfile-catalog/java-springboot:2.1.0" + }, + "commandGroups": { + "build": true, + "debug": true, + "deploy": true, + "run": true, + "test": false + }, + "resources": [ + "archive.tar", + "devfile.yaml" + ], + "starterProjects": [ + "springbootproject" + ] + }, + { + "version": "1.3.0", + "schemaVersion": "2.1.0", + "default": true, + "description": "Java application using Spring Boot® and OpenJDK 11", + "tags": [ + "Java", + "Spring" + ], + "icon": "https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/spring.svg", + "links": { + "self": "devfile-catalog/java-springboot:1.3.0" + }, + "commandGroups": { + "build": true, + "debug": true, + "deploy": false, + "run": true, + "test": false + }, + "resources": [ + "devfile.yaml" + ], + "starterProjects": [ + "springbootproject" + ] + } + ] + }, + { + "name": "java-vertx", + "displayName": "Vert.x Java", + "description": "Java application using Vert.x and OpenJDK 11", + "type": "stack", + "tags": [ + "Java", + "Vert.x" + ], + "icon": "https://raw.githubusercontent.com/vertx-web-site/vertx-logo/master/vertx-logo.svg", + "projectType": "Vert.x", + "language": "Java", + "versions": [ + { + "version": "1.2.0", + "schemaVersion": "2.1.0", + "default": true, + "description": "Java application using Vert.x and OpenJDK 11", + "tags": [ + "Java", + "Vert.x" + ], + "icon": "https://raw.githubusercontent.com/vertx-web-site/vertx-logo/master/vertx-logo.svg", + "links": { + "self": "devfile-catalog/java-vertx:1.2.0" + }, + "commandGroups": { + "build": true, + "debug": true, + "deploy": false, + "run": true, + "test": false + }, + "resources": [ + "devfile.yaml" + ], + "starterProjects": [ + "vertx-http-example", + "vertx-istio-circuit-breaker-booster", + "vertx-istio-routing-booster", + "vertx-secured-http-example-redhat", + "vertx-crud-example-redhat", + "vertx-istio-security-booster", + "vertx-crud-example", + "vertx-circuit-breaker-example", + "vertx-configmap-example", + "vertx-circuit-breaker-example-redhat", + "vertx-cache-example-redhat", + "vertx-cache-example", + "vertx-secured-http-example", + "vertx-health-checks-example-redhat", + "vertx-http-example-redhat", + "vertx-health-checks-example", + "vertx-configmap-example-redhat", + "vertx-messaging-work-queue-booster", + "vertx-istio-distributed-tracing-booster" + ] + } + ] + }, + { + "name": "nodejs", + "displayName": "Node.js Runtime", + "description": "Node.js application", + "type": "stack", + "tags": [ + "Node.js", + "Express", + "ubi8" + ], + "icon": "https://nodejs.org/static/images/logos/nodejs-new-pantone-black.svg", + "projectType": "Node.js", + "language": "JavaScript", + "versions": [ + { + "version": "2.2.0", + "schemaVersion": "2.1.0", + "description": "Node.js 18 application", + "tags": [ + "Node.js", + "Express", + "ubi8" + ], + "icon": "https://nodejs.org/static/images/logos/nodejs-new-pantone-black.svg", + "links": { + "self": "devfile-catalog/nodejs:2.2.0" + }, + "commandGroups": { + "build": true, + "debug": true, + "deploy": false, + "run": true, + "test": true + }, + "resources": [ + "devfile.yaml" + ], + "starterProjects": [ + "nodejs-starter" + ] + }, + { + "version": "2.1.1", + "schemaVersion": "2.1.0", + "default": true, + "description": "Node.js 16 application", + "tags": [ + "Node.js", + "Express", + "ubi8" + ], + "icon": "https://nodejs.org/static/images/logos/nodejs-new-pantone-black.svg", + "links": { + "self": "devfile-catalog/nodejs:2.1.1" + }, + "commandGroups": { + "build": true, + "debug": true, + "deploy": false, + "run": true, + "test": true + }, + "resources": [ + "devfile.yaml" + ], + "starterProjects": [ + "nodejs-starter" + ] + } + ] + }, + { + "name": "nodejs-angular", + "displayName": "Angular", + "description": "Angular is a development platform, built on TypeScript. As a platform, Angular includes: A component-based framework for building scalable web applications A collection of well-integrated libraries that cover a wide variety of features, including routing, forms management, client-server communication, and more A suite of developer tools to help you develop, build, test, and update your code", + "type": "stack", + "tags": [ + "Node.js", + "Angular" + ], + "icon": "https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/angular.svg", + "projectType": "Angular", + "language": "TypeScript", + "provider": "Red Hat", + "versions": [ + { + "version": "2.2.0", + "schemaVersion": "2.2.0", + "description": "Angular is a development platform, built on TypeScript. As a platform, Angular includes: A component-based framework for building scalable web applications A collection of well-integrated libraries that cover a wide variety of features, including routing, forms management, client-server communication, and more A suite of developer tools to help you develop, build, test, and update your code", + "tags": [ + "Node.js", + "Angular" + ], + "icon": "https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/angular.svg", + "links": { + "self": "devfile-catalog/nodejs-angular:2.2.0" + }, + "commandGroups": { + "build": true, + "debug": false, + "deploy": false, + "run": true, + "test": false + }, + "resources": [ + "devfile.yaml" + ], + "starterProjects": [ + "nodejs-angular-starter" + ] + }, + { + "version": "2.1.0", + "schemaVersion": "2.1.0", + "description": "Angular is a development platform, built on TypeScript. As a platform, Angular includes: A component-based framework for building scalable web applications A collection of well-integrated libraries that cover a wide variety of features, including routing, forms management, client-server communication, and more A suite of developer tools to help you develop, build, test, and update your code", + "tags": [ + "Node.js", + "Angular" + ], + "icon": "https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/angular.svg", + "links": { + "self": "devfile-catalog/nodejs-angular:2.1.0" + }, + "commandGroups": { + "build": true, + "debug": false, + "deploy": false, + "run": true, + "test": false + }, + "resources": [ + "devfile.yaml" + ], + "starterProjects": [ + "nodejs-angular-starter" + ] + }, + { + "version": "2.0.2", + "schemaVersion": "2.1.0", + "default": true, + "description": "Angular is a development platform, built on TypeScript. As a platform, Angular includes: A component-based framework for building scalable web applications A collection of well-integrated libraries that cover a wide variety of features, including routing, forms management, client-server communication, and more A suite of developer tools to help you develop, build, test, and update your code", + "tags": [ + "Node.js", + "Angular" + ], + "icon": "https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/angular.svg", + "links": { + "self": "devfile-catalog/nodejs-angular:2.0.2" + }, + "commandGroups": { + "build": true, + "debug": false, + "deploy": false, + "run": true, + "test": false + }, + "resources": [ + "devfile.yaml" + ], + "starterProjects": [ + "nodejs-angular-starter" + ] + } + ] + }, + { + "name": "nodejs-react", + "displayName": "React", + "description": "React is a free and open-source front-end JavaScript library for building user interfaces based on UI components. It is maintained by Meta and a community of individual developers and companies.", + "type": "stack", + "tags": [ + "Node.js", + "React" + ], + "icon": "https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/react.svg", + "projectType": "React", + "language": "TypeScript", + "provider": "Red Hat", + "versions": [ + { + "version": "2.2.0", + "schemaVersion": "2.2.0", + "description": "React is a free and open-source front-end JavaScript library for building user interfaces based on UI components. It is maintained by Meta and a community of individual developers and companies.", + "tags": [ + "Node.js", + "React" + ], + "icon": "https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/react.svg", + "links": { + "self": "devfile-catalog/nodejs-react:2.2.0" + }, + "commandGroups": { + "build": true, + "debug": false, + "deploy": false, + "run": true, + "test": false + }, + "resources": [ + "devfile.yaml" + ], + "starterProjects": [ + "nodejs-react-starter" + ] + }, + { + "version": "2.0.2", + "schemaVersion": "2.1.0", + "default": true, + "description": "React is a free and open-source front-end JavaScript library for building user interfaces based on UI components. It is maintained by Meta and a community of individual developers and companies.", + "tags": [ + "Node.js", + "React" + ], + "icon": "https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/react.svg", + "links": { + "self": "devfile-catalog/nodejs-react:2.0.2" + }, + "commandGroups": { + "build": true, + "debug": false, + "deploy": false, + "run": true, + "test": false + }, + "resources": [ + "devfile.yaml" + ], + "starterProjects": [ + "nodejs-react-starter" + ] + } + ] + }, + { + "name": "python", + "displayName": "Python", + "description": "Python is an interpreted, object-oriented, high-level programming language with dynamic semantics. Its high-level built in data structures, combined with dynamic typing and dynamic binding, make it very attractive for Rapid Application Development, as well as for use as a scripting or glue language to connect existing components together.", + "type": "stack", + "tags": [ + "Python", + "Pip", + "Flask" + ], + "icon": "https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/python.svg", + "projectType": "Python", + "language": "Python", + "provider": "Red Hat", + "versions": [ + { + "version": "3.0.0", + "schemaVersion": "2.2.0", + "description": "Python (version 3.9.x) is an interpreted, object-oriented, high-level programming language with dynamic semantics. Its high-level built in data structures, combined with dynamic typing and dynamic binding, make it very attractive for Rapid Application Development, as well as for use as a scripting or glue language to connect existing components together.", + "tags": [ + "Python", + "Pip", + "Flask" + ], + "icon": "https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/python.svg", + "links": { + "self": "devfile-catalog/python:3.0.0" + }, + "commandGroups": { + "build": true, + "debug": true, + "deploy": true, + "run": true, + "test": false + }, + "resources": [ + "archive.tar", + "devfile.yaml" + ], + "starterProjects": [ + "flask-example" + ] + }, + { + "version": "2.1.0", + "schemaVersion": "2.1.0", + "default": true, + "description": "Python (version 3.9.x) is an interpreted, object-oriented, high-level programming language with dynamic semantics. Its high-level built in data structures, combined with dynamic typing and dynamic binding, make it very attractive for Rapid Application Development, as well as for use as a scripting or glue language to connect existing components together.", + "tags": [ + "Python", + "Pip", + "Flask" + ], + "icon": "https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/python.svg", + "links": { + "self": "devfile-catalog/python:2.1.0" + }, + "commandGroups": { + "build": true, + "debug": true, + "deploy": false, + "run": true, + "test": false + }, + "resources": [ + "devfile.yaml" + ], + "starterProjects": [ + "flask-example" + ] + } + ] + } +] \ No newline at end of file diff --git a/tests/helper/registry_server/testdata/registry-build/stacks/dotnet50/devfile.yaml b/tests/helper/registry_server/testdata/registry-build/stacks/dotnet50/devfile.yaml new file mode 100644 index 00000000000..4c893f80ec1 --- /dev/null +++ b/tests/helper/registry_server/testdata/registry-build/stacks/dotnet50/devfile.yaml @@ -0,0 +1,56 @@ +schemaVersion: 2.1.0 +metadata: + name: dotnet50 + displayName: .NET 5.0 + description: .NET 5.0 application + icon: https://github.com/dotnet/brand/raw/main/logo/dotnet-logo.png + tags: + - .NET + - .NET 5.0 + projectType: dotnet + language: .NET + version: 1.0.3 +starterProjects: + - name: dotnet50-example + git: + checkoutFrom: + remote: origin + revision: dotnet-5.0 + remotes: + origin: https://github.com/redhat-developer/s2i-dotnetcore-ex + subDir: app +components: + - name: dotnet + container: + image: registry.access.redhat.com/ubi8/dotnet-50:5.0-39 + args: ["tail", "-f", "/dev/null"] + mountSources: true + env: + - name: CONFIGURATION + value: Debug + - name: STARTUP_PROJECT + value: app.csproj + - name: ASPNETCORE_ENVIRONMENT + value: Development + - name: ASPNETCORE_URLS + value: http://*:8080 + endpoints: + - name: http-dotnet50 + targetPort: 8080 +commands: + - id: build + exec: + workingDir: ${PROJECT_SOURCE} + commandLine: kill $(pidof dotnet); dotnet build -c $CONFIGURATION $STARTUP_PROJECT /p:UseSharedCompilation=false + component: dotnet + group: + isDefault: true + kind: build + - id: run + exec: + workingDir: ${PROJECT_SOURCE} + commandLine: dotnet run -c $CONFIGURATION --no-build --project $STARTUP_PROJECT --no-launch-profile + component: dotnet + group: + isDefault: true + kind: run diff --git a/tests/helper/registry_server/testdata/registry-build/stacks/dotnet60/devfile.yaml b/tests/helper/registry_server/testdata/registry-build/stacks/dotnet60/devfile.yaml new file mode 100644 index 00000000000..0c9467342df --- /dev/null +++ b/tests/helper/registry_server/testdata/registry-build/stacks/dotnet60/devfile.yaml @@ -0,0 +1,56 @@ +schemaVersion: 2.1.0 +metadata: + name: dotnet60 + displayName: .NET 6.0 + description: .NET 6.0 application + icon: https://github.com/dotnet/brand/raw/main/logo/dotnet-logo.png + tags: + - .NET + - .NET 6.0 + projectType: dotnet + language: .NET + version: 1.0.2 +starterProjects: + - name: dotnet60-example + git: + checkoutFrom: + remote: origin + revision: dotnet-6.0 + remotes: + origin: https://github.com/redhat-developer/s2i-dotnetcore-ex + subDir: app +components: + - name: dotnet + container: + image: registry.access.redhat.com/ubi8/dotnet-60:6.0-43 + args: ["tail", "-f", "/dev/null"] + mountSources: true + env: + - name: CONFIGURATION + value: Debug + - name: STARTUP_PROJECT + value: app.csproj + - name: ASPNETCORE_ENVIRONMENT + value: Development + - name: ASPNETCORE_URLS + value: http://*:8080 + endpoints: + - name: http-dotnet60 + targetPort: 8080 +commands: + - id: build + exec: + workingDir: ${PROJECT_SOURCE} + commandLine: kill $(pidof dotnet); dotnet build -c $CONFIGURATION $STARTUP_PROJECT /p:UseSharedCompilation=false + component: dotnet + group: + isDefault: true + kind: build + - id: run + exec: + workingDir: ${PROJECT_SOURCE} + commandLine: dotnet run -c $CONFIGURATION --no-build --project $STARTUP_PROJECT --no-launch-profile + component: dotnet + group: + isDefault: true + kind: run diff --git a/tests/helper/registry_server/testdata/registry-build/stacks/go/1.0.2/devfile.yaml b/tests/helper/registry_server/testdata/registry-build/stacks/go/1.0.2/devfile.yaml new file mode 100644 index 00000000000..cdd1b9a9240 --- /dev/null +++ b/tests/helper/registry_server/testdata/registry-build/stacks/go/1.0.2/devfile.yaml @@ -0,0 +1,53 @@ +schemaVersion: 2.1.0 +metadata: + name: go + displayName: Go Runtime + description: Go (version 1.18.x) is an open source programming language that makes it easy to build simple, reliable, and efficient software. + icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/golang.svg + tags: + - Go + - Deprecated + projectType: Go + language: Go + provider: Red Hat + version: 1.0.2 +starterProjects: + - name: go-starter + description: A Go project with a simple HTTP server + git: + checkoutFrom: + revision: main + remotes: + origin: https://github.com/devfile-samples/devfile-stack-go.git +components: + - container: + endpoints: + - name: http-go + targetPort: 8080 + image: registry.access.redhat.com/ubi9/go-toolset:1.18.10-4 + args: ["tail", "-f", "/dev/null"] + memoryLimit: 1024Mi + mountSources: true + name: runtime +commands: + - exec: + env: + - name: GOPATH + value: ${PROJECT_SOURCE}/.go + - name: GOCACHE + value: ${PROJECT_SOURCE}/.cache + commandLine: go build main.go + component: runtime + group: + isDefault: true + kind: build + workingDir: ${PROJECT_SOURCE} + id: build + - exec: + commandLine: ./main + component: runtime + group: + isDefault: true + kind: run + workingDir: ${PROJECT_SOURCE} + id: run diff --git a/tests/helper/registry_server/testdata/registry-build/stacks/go/1.2.0/devfile.yaml b/tests/helper/registry_server/testdata/registry-build/stacks/go/1.2.0/devfile.yaml new file mode 100644 index 00000000000..fe0ca80d2cf --- /dev/null +++ b/tests/helper/registry_server/testdata/registry-build/stacks/go/1.2.0/devfile.yaml @@ -0,0 +1,76 @@ +schemaVersion: 2.1.0 +metadata: + name: go + displayName: Go Runtime + description: Go (version 1.19.x) is an open source programming language that makes it easy to build simple, reliable, and efficient software. + icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/golang.svg + tags: + - Go + projectType: Go + language: Go + provider: Red Hat + version: 1.2.0 +starterProjects: + - name: go-starter + description: A Go project with a simple HTTP server + git: + checkoutFrom: + revision: main + remotes: + origin: https://github.com/devfile-samples/devfile-stack-go.git +components: + - container: + endpoints: + - name: http-go + targetPort: 8080 + - exposure: none + name: debug + targetPort: 5858 + image: registry.access.redhat.com/ubi9/go-toolset:1.19.13-4.1697647145 + args: ["tail", "-f", "/dev/null"] + env: + - name: DEBUG_PORT + value: '5858' + memoryLimit: 1024Mi + mountSources: true + name: runtime +commands: + - exec: + env: + - name: GOPATH + value: ${PROJECT_SOURCE}/.go + - name: GOCACHE + value: ${PROJECT_SOURCE}/.cache + commandLine: go build main.go + component: runtime + group: + isDefault: true + kind: build + workingDir: ${PROJECT_SOURCE} + id: build + - exec: + commandLine: ./main + component: runtime + group: + isDefault: true + kind: run + workingDir: ${PROJECT_SOURCE} + id: run + + - exec: + commandLine: | + GOPATH=${PROJECT_SOURCE}/.go \ + GOCACHE=${PROJECT_SOURCE}/.cache \ + dlv \ + --listen=127.0.0.1:${DEBUG_PORT} \ + --only-same-user=false \ + --headless=true \ + --api-version=2 \ + --accept-multiclient \ + debug --continue main.go + component: runtime + group: + isDefault: true + kind: debug + workingDir: ${PROJECT_SOURCE} + id: debug diff --git a/tests/helper/registry_server/testdata/registry-build/stacks/go/2.2.0/archive.tar b/tests/helper/registry_server/testdata/registry-build/stacks/go/2.2.0/archive.tar new file mode 100644 index 0000000000000000000000000000000000000000..081f5c254d1090d6cf5edbe006b9eb936b706085 GIT binary patch literal 608 zcmV-m0-yaKiwFP!000001MQYkZ__Xk$NQX5aq1%?N!_OH7Kx{AJTX>nfIx@`H#s_M zaU5)CsNWtt?MjnvosiZ}!2MpFoX>av%L7&xZmaWgu)ad4T`i z|F@SH=b&*RjMdACXBiq3Y0R&=jWQ+UdM=LRg$k`wg+ZILh#g046ebay98V|7lqKUJ zIJua8frW~s${~t_%a8Bf9r(Lk{VWT`^L5Uv$i-d8UCO)`MGm2lNiNDDIQu-ixH^NQ z!4Y#y&QIYh^jC9zcn$rqdgG`1--4HZasLQWd{fU+muS)K>kRnw{eL*1{r@nu{Lir} z)G}IfSv+TtC-#3f8cjO>C&NKP`~M-h5oMmj73y1&VZbZ#3AGWbOyQOV5-rcU-4Qwo}#s~yVf;ZOYmf>wC;#=>VM~lEy1usNWQ?P((1}9Fm@|p z%aLv^?@ViAtM#nw(x%=6Zh15sRcrT$q1{X4kJ<_9ME(1bN-tCBv%$IOcU4q%Gb7s* ug^*%rr5&Ywt(X3~2!bF8f*=TjAP9mW2!bF8f*=Uuu>1lIW)GSGC;$LYRW+>u literal 0 HcmV?d00001 diff --git a/tests/helper/registry_server/testdata/registry-build/stacks/go/2.2.0/devfile.yaml b/tests/helper/registry_server/testdata/registry-build/stacks/go/2.2.0/devfile.yaml new file mode 100644 index 00000000000..69ec50aa619 --- /dev/null +++ b/tests/helper/registry_server/testdata/registry-build/stacks/go/2.2.0/devfile.yaml @@ -0,0 +1,103 @@ +schemaVersion: 2.2.0 +metadata: + name: go + displayName: Go Runtime + description: Go (version 1.19.x) is an open source programming language that makes it easy to build simple, reliable, and efficient software. + icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/golang.svg + tags: + - Go + projectType: Go + language: Go + provider: Red Hat + version: 2.2.0 +starterProjects: + - name: go-starter + description: A Go project with a simple HTTP server + git: + checkoutFrom: + revision: main + remotes: + origin: https://github.com/devfile-samples/devfile-stack-go.git +components: + - name: build + image: + imageName: go-image:latest + dockerfile: + uri: docker/Dockerfile + buildContext: . + rootRequired: false + - name: deploy + kubernetes: + uri: kubernetes/deploy.yaml + endpoints: + - name: http-8081 + targetPort: 8081 + - container: + endpoints: + - name: http-go + targetPort: 8080 + - exposure: none + name: debug + targetPort: 5858 + image: registry.access.redhat.com/ubi9/go-toolset:1.19.13-4.1697647145 + args: ['tail', '-f', '/dev/null'] + env: + - name: DEBUG_PORT + value: '5858' + memoryLimit: 1024Mi + mountSources: true + name: runtime +commands: + - id: build-image + apply: + component: build + - id: deployk8s + apply: + component: deploy + - id: deploy + composite: + commands: + - build-image + - deployk8s + group: + kind: deploy + isDefault: true + - exec: + env: + - name: GOPATH + value: ${PROJECT_SOURCE}/.go + - name: GOCACHE + value: ${PROJECT_SOURCE}/.cache + commandLine: go build main.go + component: runtime + group: + isDefault: true + kind: build + workingDir: ${PROJECT_SOURCE} + id: build + - exec: + commandLine: ./main + component: runtime + group: + isDefault: true + kind: run + workingDir: ${PROJECT_SOURCE} + id: run + + - exec: + commandLine: | + GOPATH=${PROJECT_SOURCE}/.go \ + GOCACHE=${PROJECT_SOURCE}/.cache \ + dlv \ + --listen=127.0.0.1:${DEBUG_PORT} \ + --only-same-user=false \ + --headless=true \ + --api-version=2 \ + --accept-multiclient \ + debug --continue main.go + component: runtime + group: + isDefault: true + kind: debug + workingDir: ${PROJECT_SOURCE} + id: debug diff --git a/tests/helper/registry_server/testdata/registry-build/stacks/go/stack.yaml b/tests/helper/registry_server/testdata/registry-build/stacks/go/stack.yaml new file mode 100644 index 00000000000..40c227dfc1b --- /dev/null +++ b/tests/helper/registry_server/testdata/registry-build/stacks/go/stack.yaml @@ -0,0 +1,11 @@ +name: go +description: 'Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.' +displayName: Go Runtime +icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/golang.svg +versions: + - version: 1.0.2 + # 1.2.0: debug command via dlv & go 1.19 + - version: 1.2.0 + default: true # should have one and only one default version + # 2.2.0: debug command via dlv & go 1.19 + - version: 2.2.0 \ No newline at end of file diff --git a/tests/helper/registry_server/testdata/registry-build/stacks/java-maven/1.2.0/devfile.yaml b/tests/helper/registry_server/testdata/registry-build/stacks/java-maven/1.2.0/devfile.yaml new file mode 100644 index 00000000000..e0ce61565d3 --- /dev/null +++ b/tests/helper/registry_server/testdata/registry-build/stacks/java-maven/1.2.0/devfile.yaml @@ -0,0 +1,63 @@ +schemaVersion: 2.1.0 +metadata: + name: java-maven + displayName: Maven Java + description: Java application based on Maven 3.6 and OpenJDK 11 + icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/java-maven.jpg + tags: + - Java + - Maven + projectType: Maven + language: Java + version: 1.2.0 +starterProjects: + - name: springbootproject + git: + remotes: + origin: 'https://github.com/odo-devfiles/springboot-ex.git' +components: + - name: tools + container: + image: registry.access.redhat.com/ubi8/openjdk-11:1.17-9 + command: ["tail", "-f", "/dev/null"] + memoryLimit: 512Mi + mountSources: true + endpoints: + - name: http-maven + targetPort: 8080 + - exposure: none + name: debug + targetPort: 5858 + volumeMounts: + - name: m2 + path: /home/user/.m2 + env: + - name: DEBUG_PORT + value: '5858' + - name: m2 + volume: {} +commands: + - id: mvn-package + exec: + component: tools + workingDir: ${PROJECT_SOURCE} + commandLine: 'mvn -Dmaven.repo.local=/home/user/.m2/repository package' + group: + kind: build + isDefault: true + - id: run + exec: + component: tools + workingDir: ${PROJECT_SOURCE} + commandLine: 'java -jar target/*.jar' + group: + kind: run + isDefault: true + - id: debug + exec: + component: tools + workingDir: ${PROJECT_SOURCE} + commandLine: 'java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=${DEBUG_PORT},suspend=n -jar target/*.jar' + group: + kind: debug + isDefault: true diff --git a/tests/helper/registry_server/testdata/registry-build/stacks/java-maven/1.3.0/devfile.yaml b/tests/helper/registry_server/testdata/registry-build/stacks/java-maven/1.3.0/devfile.yaml new file mode 100644 index 00000000000..3d993da2139 --- /dev/null +++ b/tests/helper/registry_server/testdata/registry-build/stacks/java-maven/1.3.0/devfile.yaml @@ -0,0 +1,63 @@ +schemaVersion: 2.1.0 +metadata: + name: java-maven + displayName: Maven Java + description: Java application based on Maven 3.6 and OpenJDK 17 + icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/java-maven.jpg + tags: + - Java + - Maven + projectType: Maven + language: Java + version: 1.3.0 +starterProjects: + - name: springbootproject + git: + remotes: + origin: 'https://github.com/odo-devfiles/springboot-ex.git' +components: + - name: tools + container: + image: registry.access.redhat.com/ubi9/openjdk-17:1.17-1 + command: ["tail", "-f", "/dev/null"] + memoryLimit: 512Mi + mountSources: true + endpoints: + - name: http-maven + targetPort: 8080 + - exposure: none + name: debug + targetPort: 5858 + volumeMounts: + - name: m2 + path: /home/user/.m2 + env: + - name: DEBUG_PORT + value: '5858' + - name: m2 + volume: {} +commands: + - id: mvn-package + exec: + component: tools + workingDir: ${PROJECT_SOURCE} + commandLine: 'mvn -Dmaven.repo.local=/home/user/.m2/repository package' + group: + kind: build + isDefault: true + - id: run + exec: + component: tools + workingDir: ${PROJECT_SOURCE} + commandLine: 'java -jar target/*.jar' + group: + kind: run + isDefault: true + - id: debug + exec: + component: tools + workingDir: ${PROJECT_SOURCE} + commandLine: 'java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=${DEBUG_PORT},suspend=n -jar target/*.jar' + group: + kind: debug + isDefault: true diff --git a/tests/helper/registry_server/testdata/registry-build/stacks/java-maven/stack.yaml b/tests/helper/registry_server/testdata/registry-build/stacks/java-maven/stack.yaml new file mode 100644 index 00000000000..decbeab1f6e --- /dev/null +++ b/tests/helper/registry_server/testdata/registry-build/stacks/java-maven/stack.yaml @@ -0,0 +1,9 @@ +name: java-maven +description: 'Java application based on Maven and OpenJDK' +displayName: Maven Java +icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/java-maven.jpg +versions: + - version: 1.2.0 + # 1.3.0: with JDK 17 + - version: 1.3.0 + default: true # should have one and only one default version diff --git a/tests/helper/registry_server/testdata/registry-build/stacks/java-openliberty/devfile.yaml b/tests/helper/registry_server/testdata/registry-build/stacks/java-openliberty/devfile.yaml new file mode 100644 index 00000000000..9651343bd00 --- /dev/null +++ b/tests/helper/registry_server/testdata/registry-build/stacks/java-openliberty/devfile.yaml @@ -0,0 +1,103 @@ +# Copyright (c) 2021,2022 IBM Corporation and others +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# 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. + +schemaVersion: 2.1.0 +metadata: + name: java-openliberty + displayName: Open Liberty Maven + description: Java application based on Java 11 and Maven 3.8, using the Open Liberty runtime 22.0.0.1 + icon: https://raw.githubusercontent.com/OpenLiberty/logos/7fbb132949b9b2589e18c8d5665c1b107028a21d/logomark/svg/OL_logomark.svg + tags: + - Java + - Maven + architectures: + - amd64 + - ppc64le + - s390x + projectType: Open Liberty + language: Java + version: 0.9.0 + alpha.build-dockerfile: https://github.com/OpenLiberty/devfile-stack/releases/download/open-liberty-maven-0.8.1/Dockerfile + alpha.deployment-manifest: https://github.com/OpenLiberty/devfile-stack/releases/download/open-liberty-maven-0.8.1/app-deploy.yaml +starterProjects: + - name: rest + git: + remotes: + origin: https://github.com/OpenLiberty/devfile-stack-starters.git +variables: + # Liberty runtime version. Minimum recommended: 21.0.0.9 + liberty-version: '22.0.0.1' + liberty-plugin-version: '3.5.1' + mvn-cmd: 'mvn' +components: + - name: dev + container: + # In the original upstream of this devfile, the image used is openliberty/devfile-stack:, which is built from the repository: https://github.com/OpenLiberty/devfile-stack + image: icr.io/appcafe/open-liberty-devfile-stack:{{liberty-version}} + args: ['tail', '-f', '/dev/null'] + memoryLimit: 768Mi + mountSources: true + endpoints: + - exposure: public + path: / + name: http-openlib + targetPort: 9080 + protocol: http + - exposure: none + name: debug + targetPort: 5858 + env: + - name: DEBUG_PORT + value: '5858' +commands: + - id: run + exec: + component: dev + commandLine: echo "run command "; {{mvn-cmd}} -DinstallDirectory=/opt/ol/wlp -Ddebug=false -DhotTests=true -DcompileWait=3 io.openliberty.tools:liberty-maven-plugin:{{liberty-plugin-version}}:dev + workingDir: ${PROJECT_SOURCE} + hotReloadCapable: true + group: + kind: run + isDefault: true + - id: run-test-off + exec: + component: dev + commandLine: echo "run-test-off command "; {{mvn-cmd}} -DinstallDirectory=/opt/ol/wlp -Ddebug=false io.openliberty.tools:liberty-maven-plugin:{{liberty-plugin-version}}:dev + workingDir: ${PROJECT_SOURCE} + hotReloadCapable: true + group: + kind: run + isDefault: false + - id: debug + exec: + component: dev + commandLine: echo "debug command "; {{mvn-cmd}} -DinstallDirectory=/opt/ol/wlp -DdebugPort=${DEBUG_PORT} io.openliberty.tools:liberty-maven-plugin:{{liberty-plugin-version}}:dev -Dliberty.env.WLP_DEBUG_REMOTE=y + workingDir: ${PROJECT_SOURCE} + hotReloadCapable: true + group: + kind: debug + isDefault: true + - id: test + # The 'test' command requires an already active container. Multi-module apps require compilation prior to test processing. + exec: + component: dev + commandLine: echo "test command "; {{mvn-cmd}} compiler:compile failsafe:integration-test failsafe:verify + workingDir: ${PROJECT_SOURCE} + hotReloadCapable: true + group: + kind: test + isDefault: true diff --git a/tests/helper/registry_server/testdata/registry-build/stacks/java-springboot/1.3.0/devfile.yaml b/tests/helper/registry_server/testdata/registry-build/stacks/java-springboot/1.3.0/devfile.yaml new file mode 100644 index 00000000000..e1789c841e4 --- /dev/null +++ b/tests/helper/registry_server/testdata/registry-build/stacks/java-springboot/1.3.0/devfile.yaml @@ -0,0 +1,65 @@ +schemaVersion: 2.1.0 +metadata: + name: java-springboot + displayName: Spring Boot® + description: Java application using Spring Boot® and OpenJDK 11 + icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/spring.svg + tags: + - Java + - Spring + projectType: springboot + language: Java + version: 1.3.0 + globalMemoryLimit: 2674Mi +starterProjects: + - name: springbootproject + git: + remotes: + origin: "https://github.com/odo-devfiles/springboot-ex.git" +components: + - name: tools + container: + image: registry.access.redhat.com/ubi9/openjdk-17:1.17-1 + command: ["tail", "-f", "/dev/null"] + memoryLimit: 768Mi + mountSources: true + endpoints: + - name: http-springboot + targetPort: 8080 + - exposure: none + name: debug + targetPort: 5858 + volumeMounts: + - name: m2 + path: /home/user/.m2 + env: + - name: DEBUG_PORT + value: "5858" + - name: m2 + volume: + size: 3Gi +commands: + - id: build + exec: + component: tools + workingDir: ${PROJECT_SOURCE} + commandLine: "mvn clean -Dmaven.repo.local=/home/user/.m2/repository package -Dmaven.test.skip=true" + group: + kind: build + isDefault: true + - id: run + exec: + component: tools + workingDir: ${PROJECT_SOURCE} + commandLine: "mvn -Dmaven.repo.local=/home/user/.m2/repository spring-boot:run" + group: + kind: run + isDefault: true + - id: debug + exec: + component: tools + workingDir: ${PROJECT_SOURCE} + commandLine: "java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=${DEBUG_PORT},suspend=n -jar target/*.jar" + group: + kind: debug + isDefault: true diff --git a/tests/helper/registry_server/testdata/registry-build/stacks/java-springboot/2.1.0/archive.tar b/tests/helper/registry_server/testdata/registry-build/stacks/java-springboot/2.1.0/archive.tar new file mode 100644 index 0000000000000000000000000000000000000000..8beb05ce484473fcb2b9b1cc3c6b8cf267e775c4 GIT binary patch literal 881 zcmV-%1CIP3iwFP!000001MQY=Z`(Ey$Mc$>;^4j=^^iDCCLk}`Cc}!Yv0-};MbQ_u zbha6bqDoTk{Ow0lnqxbO(*jAmVf+D!Wb%0YACKZOiVK-9QN>5kM`AfUJ@rq^{`2m8 znx@C;5u84wrVWiYOaUAzDa|3f$NK-HME~Uf(m!Ur#3!G_CG};$|4{zZlb8Ly{GX)h z*%2g9uH+v6=lOqOAunLE;2LhX0N7uR#sYW+QWdDcNSHRfEPz2SE5mr@8W+rfYAS8t z5XQCQ)f`^ig#uRBCC{1RvLep^Yd_Xmalz&YpSf9NzNg)OopU;aJKGVc0qtE+t>;)X zQI|*y6cQrRYRAf{@a}KLHQEl@nZwyo4wNbZw1)HKJk8v{2iz0CHb0F9@8DCz))AL+ zfh#8|7Hox8b`qUODU~%=H^q{sXH=J55c0=h^vmVj5yUlin<@V>-ipgEoZ$kqk~vT9oRrR#6c-_*dYVF+f3*32gs!^>_MYUAs!ujpNNAkVDxqlN;ylkeZDzuq>t~C$gzftA?_%NptU3uD{FrO;nz zbOv{&2xjuduWX8C7x@8oHZrvL3tL9Jv0EY><&K+!j;xGMoMUtC*&0kAjte&U>)72n z+UBm_-&$|wcYhX_=ber%QN#V5Z~Wbpdxt_T8)dI0yK^c0)L21#t!^2GRO<|S>3Q;w z_x5Gfjq6IpZil_A@dK_-k^`=sukZck1_FUVAP@)y0)apv5C{YUfj}S-2;9%#Q_U>t H04M+eACJPS literal 0 HcmV?d00001 diff --git a/tests/helper/registry_server/testdata/registry-build/stacks/java-springboot/2.1.0/devfile.yaml b/tests/helper/registry_server/testdata/registry-build/stacks/java-springboot/2.1.0/devfile.yaml new file mode 100644 index 00000000000..25a849dcd3d --- /dev/null +++ b/tests/helper/registry_server/testdata/registry-build/stacks/java-springboot/2.1.0/devfile.yaml @@ -0,0 +1,92 @@ +schemaVersion: 2.2.0 +metadata: + name: java-springboot + displayName: Spring Boot® + description: Java application using Spring Boot® and OpenJDK 11 + icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/spring.svg + tags: + - Java + - Spring + projectType: springboot + language: Java + version: 2.1.0 + globalMemoryLimit: 2674Mi +starterProjects: + - name: springbootproject + git: + remotes: + origin: "https://github.com/odo-devfiles/springboot-ex.git" +components: + - name: tools + container: + image: registry.access.redhat.com/ubi9/openjdk-17:1.17-1 + command: ['tail', '-f', '/dev/null'] + memoryLimit: 768Mi + mountSources: true + endpoints: + - name: http-springboot + targetPort: 8080 + - exposure: none + name: debug + targetPort: 5858 + volumeMounts: + - name: m2 + path: /home/user/.m2 + env: + - name: DEBUG_PORT + value: "5858" + - name: m2 + volume: + size: 3Gi + - name: build + image: + imageName: java-springboot-image:latest + dockerfile: + uri: docker/Dockerfile + buildContext: . + rootRequired: false + - name: deploy + kubernetes: + uri: kubernetes/deploy.yaml + endpoints: + - name: http-8081 + targetPort: 8081 +commands: + - id: build + exec: + component: tools + workingDir: ${PROJECT_SOURCE} + commandLine: 'mvn clean -Dmaven.repo.local=/home/user/.m2/repository package -Dmaven.test.skip=true' + group: + kind: build + isDefault: true + - id: run + exec: + component: tools + workingDir: ${PROJECT_SOURCE} + commandLine: 'mvn -Dmaven.repo.local=/home/user/.m2/repository spring-boot:run' + group: + kind: run + isDefault: true + - id: debug + exec: + component: tools + workingDir: ${PROJECT_SOURCE} + commandLine: 'java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=${DEBUG_PORT},suspend=n -jar target/*.jar' + group: + kind: debug + isDefault: true + - id: build-image + apply: + component: build + - id: deployk8s + apply: + component: deploy + - id: deploy + composite: + commands: + - build-image + - deployk8s + group: + kind: deploy + isDefault: true diff --git a/tests/helper/registry_server/testdata/registry-build/stacks/java-springboot/stack.yaml b/tests/helper/registry_server/testdata/registry-build/stacks/java-springboot/stack.yaml new file mode 100644 index 00000000000..5f7de7269d2 --- /dev/null +++ b/tests/helper/registry_server/testdata/registry-build/stacks/java-springboot/stack.yaml @@ -0,0 +1,10 @@ +name: java-springboot +description: Spring Boot using Java +displayName: Spring Boot +icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/spring.svg +versions: + # 1.3.0: with JDK 17 + - version: 1.3.0 + default: true # should have one and only one default version + # 2.1.0: with JDK 17 + - version: 2.1.0 diff --git a/tests/helper/registry_server/testdata/registry-build/stacks/java-vertx/devfile.yaml b/tests/helper/registry_server/testdata/registry-build/stacks/java-vertx/devfile.yaml new file mode 100644 index 00000000000..776787a29c0 --- /dev/null +++ b/tests/helper/registry_server/testdata/registry-build/stacks/java-vertx/devfile.yaml @@ -0,0 +1,138 @@ +schemaVersion: 2.1.0 +metadata: + name: java-vertx + displayName: Vert.x Java + description: Java application using Vert.x and OpenJDK 11 + icon: https://raw.githubusercontent.com/vertx-web-site/vertx-logo/master/vertx-logo.svg + tags: + - Java + - Vert.x + projectType: Vert.x + language: Java + version: 1.2.0 +starterProjects: + - name: vertx-http-example + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-http-example + - name: vertx-istio-circuit-breaker-booster + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-istio-circuit-breaker-booster + - name: vertx-istio-routing-booster + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-istio-routing-booster + - name: vertx-secured-http-example-redhat + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-secured-http-example-redhat + - name: vertx-crud-example-redhat + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-crud-example-redhat + - name: vertx-istio-security-booster + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-istio-security-booster + - name: vertx-crud-example + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-crud-example + - name: vertx-circuit-breaker-example + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-circuit-breaker-example + - name: vertx-configmap-example + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-configmap-example + - name: vertx-circuit-breaker-example-redhat + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-circuit-breaker-example-redhat + - name: vertx-cache-example-redhat + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-cache-example-redhat + - name: vertx-cache-example + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-cache-example + - name: vertx-secured-http-example + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-secured-http-example + - name: vertx-health-checks-example-redhat + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-health-checks-example-redhat + - name: vertx-http-example-redhat + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-http-example-redhat + - name: vertx-health-checks-example + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-health-checks-example + - name: vertx-configmap-example-redhat + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-configmap-example-redhat + - name: vertx-messaging-work-queue-booster + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-messaging-work-queue-booster + - name: vertx-istio-distributed-tracing-booster + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-istio-distributed-tracing-booster +components: + - name: runtime + container: + endpoints: + - exposure: public + path: / + name: http-vertx + targetPort: 8080 + protocol: http + - exposure: none + name: debug + targetPort: 5858 + image: quay.io/eclipse/che-java11-maven:7.37.2 + memoryLimit: 512Mi + mountSources: true + volumeMounts: + - name: m2 + path: /home/user/.m2 + env: + - name: DEBUG_PORT + value: '5858' + - name: m2 + volume: + size: 3Gi +commands: + - id: mvn-package + exec: + commandLine: mvn package -Dmaven.test.skip=true + component: runtime + workingDir: ${PROJECT_SOURCE} + group: + isDefault: true + kind: build + - id: run + exec: + commandLine: mvn io.reactiverse:vertx-maven-plugin:run + component: runtime + workingDir: ${PROJECT_SOURCE} + group: + isDefault: true + kind: run + - id: debug + exec: + commandLine: mvn io.reactiverse:vertx-maven-plugin:debug -Ddebug.port=${DEBUG_PORT} + component: runtime + workingDir: ${PROJECT_SOURCE} + group: + isDefault: true + kind: debug diff --git a/tests/helper/registry_server/testdata/registry-build/stacks/nodejs-angular/2.0.2/devfile.yaml b/tests/helper/registry_server/testdata/registry-build/stacks/nodejs-angular/2.0.2/devfile.yaml new file mode 100644 index 00000000000..10a4d8a1865 --- /dev/null +++ b/tests/helper/registry_server/testdata/registry-build/stacks/nodejs-angular/2.0.2/devfile.yaml @@ -0,0 +1,50 @@ +schemaVersion: 2.1.0 +metadata: + name: nodejs-angular + displayName: Angular + description: "Angular is a development platform, built on TypeScript. As a platform, Angular includes: + A component-based framework for building scalable web applications + A collection of well-integrated libraries that cover a wide variety of features, including routing, forms management, client-server communication, and more + A suite of developer tools to help you develop, build, test, and update your code" + icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/angular.svg + tags: + - Node.js + - Angular + projectType: Angular + language: TypeScript + provider: Red Hat + version: 2.0.2 +starterProjects: + - name: nodejs-angular-starter + git: + checkoutFrom: + revision: main + remotes: + origin: https://github.com/devfile-samples/devfile-stack-nodejs-angular.git +components: + - container: + endpoints: + - name: http-angular + targetPort: 4200 + image: registry.access.redhat.com/ubi8/nodejs-16:1-139 + args: ["tail", "-f", "/dev/null"] + memoryLimit: 1024Mi + name: runtime +commands: + - exec: + commandLine: npm install + component: runtime + group: + isDefault: true + kind: build + workingDir: ${PROJECT_SOURCE} + id: install + - exec: + commandLine: npm run start + component: runtime + group: + isDefault: true + kind: run + hotReloadCapable: true + workingDir: ${PROJECT_SOURCE} + id: run diff --git a/tests/helper/registry_server/testdata/registry-build/stacks/nodejs-angular/2.1.0/devfile.yaml b/tests/helper/registry_server/testdata/registry-build/stacks/nodejs-angular/2.1.0/devfile.yaml new file mode 100644 index 00000000000..eb55fc88773 --- /dev/null +++ b/tests/helper/registry_server/testdata/registry-build/stacks/nodejs-angular/2.1.0/devfile.yaml @@ -0,0 +1,50 @@ +schemaVersion: 2.1.0 +metadata: + name: nodejs-angular + displayName: Angular + description: "Angular is a development platform, built on TypeScript. As a platform, Angular includes: + A component-based framework for building scalable web applications + A collection of well-integrated libraries that cover a wide variety of features, including routing, forms management, client-server communication, and more + A suite of developer tools to help you develop, build, test, and update your code" + icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/angular.svg + tags: + - Node.js + - Angular + projectType: Angular + language: TypeScript + provider: Red Hat + version: 2.1.0 +starterProjects: + - name: nodejs-angular-starter + git: + checkoutFrom: + revision: main + remotes: + origin: https://github.com/devfile-samples/devfile-stack-nodejs-angular.git +components: + - container: + endpoints: + - name: http-angular + targetPort: 4200 + image: registry.access.redhat.com/ubi8/nodejs-18:1-81 + args: ["tail", "-f", "/dev/null"] + memoryLimit: 1024Mi + name: runtime +commands: + - exec: + commandLine: npm install + component: runtime + group: + isDefault: true + kind: build + workingDir: ${PROJECT_SOURCE} + id: install + - exec: + commandLine: npm run start + component: runtime + group: + isDefault: true + kind: run + hotReloadCapable: true + workingDir: ${PROJECT_SOURCE} + id: run diff --git a/tests/helper/registry_server/testdata/registry-build/stacks/nodejs-angular/2.2.0/devfile.yaml b/tests/helper/registry_server/testdata/registry-build/stacks/nodejs-angular/2.2.0/devfile.yaml new file mode 100644 index 00000000000..549ec6c2f61 --- /dev/null +++ b/tests/helper/registry_server/testdata/registry-build/stacks/nodejs-angular/2.2.0/devfile.yaml @@ -0,0 +1,50 @@ +schemaVersion: 2.2.0 +metadata: + name: nodejs-angular + displayName: Angular + description: "Angular is a development platform, built on TypeScript. As a platform, Angular includes: + A component-based framework for building scalable web applications + A collection of well-integrated libraries that cover a wide variety of features, including routing, forms management, client-server communication, and more + A suite of developer tools to help you develop, build, test, and update your code" + icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/angular.svg + tags: + - Node.js + - Angular + projectType: Angular + language: TypeScript + provider: Red Hat + version: 2.2.0 +starterProjects: + - name: nodejs-angular-starter + git: + checkoutFrom: + revision: main + remotes: + origin: https://github.com/devfile-samples/devfile-stack-nodejs-angular.git +components: + - container: + endpoints: + - name: http-angular + targetPort: 4200 + image: registry.access.redhat.com/ubi8/nodejs-18:1-81 + args: ["tail", "-f", "/dev/null"] + memoryLimit: 1024Mi + name: runtime +commands: + - exec: + commandLine: npm install + component: runtime + group: + isDefault: true + kind: build + workingDir: ${PROJECT_SOURCE} + id: install + - exec: + commandLine: npm run start + component: runtime + group: + isDefault: true + kind: run + hotReloadCapable: true + workingDir: ${PROJECT_SOURCE} + id: run diff --git a/tests/helper/registry_server/testdata/registry-build/stacks/nodejs-angular/stack.yaml b/tests/helper/registry_server/testdata/registry-build/stacks/nodejs-angular/stack.yaml new file mode 100644 index 00000000000..75e4f7ef31f --- /dev/null +++ b/tests/helper/registry_server/testdata/registry-build/stacks/nodejs-angular/stack.yaml @@ -0,0 +1,13 @@ +name: nodejs-angular +description: + "Angular is a development platform, built on TypeScript. As a platform, Angular includes: + A component-based framework for building scalable web applications + A collection of well-integrated libraries that cover a wide variety of features, including routing, forms management, client-server communication, and more + A suite of developer tools to help you develop, build, test, and update your code" +displayName: Angular +icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/angular.svg +versions: + - version: 2.0.2 + default: true # should have one and only one default version + - version: 2.1.0 + - version: 2.2.0 diff --git a/tests/helper/registry_server/testdata/registry-build/stacks/nodejs-react/2.0.2/devfile.yaml b/tests/helper/registry_server/testdata/registry-build/stacks/nodejs-react/2.0.2/devfile.yaml new file mode 100644 index 00000000000..fd6a73c9b7c --- /dev/null +++ b/tests/helper/registry_server/testdata/registry-build/stacks/nodejs-react/2.0.2/devfile.yaml @@ -0,0 +1,47 @@ +schemaVersion: 2.1.0 +metadata: + name: nodejs-react + displayName: React + description: "React is a free and open-source front-end JavaScript library for building user interfaces based on UI components. + It is maintained by Meta and a community of individual developers and companies." + icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/react.svg + tags: + - Node.js + - React + projectType: React + language: TypeScript + provider: Red Hat + version: 2.0.2 +starterProjects: + - name: nodejs-react-starter + git: + checkoutFrom: + revision: main + remotes: + origin: https://github.com/devfile-samples/devfile-stacks-nodejs-react.git +components: + - container: + endpoints: + - name: http-react + targetPort: 3000 + image: registry.access.redhat.com/ubi8/nodejs-16:1-139 + args: ['tail', '-f', '/dev/null'] + memoryLimit: 1024Mi + name: runtime +commands: + - exec: + commandLine: npm install + component: runtime + group: + isDefault: true + kind: build + workingDir: ${PROJECT_SOURCE} + id: install + - exec: + commandLine: npm run dev + component: runtime + group: + isDefault: true + kind: run + workingDir: ${PROJECT_SOURCE} + id: run diff --git a/tests/helper/registry_server/testdata/registry-build/stacks/nodejs-react/2.2.0/devfile.yaml b/tests/helper/registry_server/testdata/registry-build/stacks/nodejs-react/2.2.0/devfile.yaml new file mode 100644 index 00000000000..707e8748a25 --- /dev/null +++ b/tests/helper/registry_server/testdata/registry-build/stacks/nodejs-react/2.2.0/devfile.yaml @@ -0,0 +1,47 @@ +schemaVersion: 2.2.0 +metadata: + name: nodejs-react + displayName: React + description: "React is a free and open-source front-end JavaScript library for building user interfaces based on UI components. + It is maintained by Meta and a community of individual developers and companies." + icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/react.svg + tags: + - Node.js + - React + projectType: React + language: TypeScript + provider: Red Hat + version: 2.2.0 +starterProjects: + - name: nodejs-react-starter + git: + checkoutFrom: + revision: main + remotes: + origin: https://github.com/devfile-samples/devfile-stacks-nodejs-react.git +components: + - container: + endpoints: + - name: http-react + targetPort: 3000 + image: registry.access.redhat.com/ubi8/nodejs-18:1-81 + args: ['tail', '-f', '/dev/null'] + memoryLimit: 1024Mi + name: runtime +commands: + - exec: + commandLine: npm install + component: runtime + group: + isDefault: true + kind: build + workingDir: ${PROJECT_SOURCE} + id: install + - exec: + commandLine: npm run dev + component: runtime + group: + isDefault: true + kind: run + workingDir: ${PROJECT_SOURCE} + id: run diff --git a/tests/helper/registry_server/testdata/registry-build/stacks/nodejs-react/stack.yaml b/tests/helper/registry_server/testdata/registry-build/stacks/nodejs-react/stack.yaml new file mode 100644 index 00000000000..d974646c380 --- /dev/null +++ b/tests/helper/registry_server/testdata/registry-build/stacks/nodejs-react/stack.yaml @@ -0,0 +1,10 @@ +name: nodejs-react +description: + 'React is a free and open-source front-end JavaScript library for building user interfaces based on UI components. + It is maintained by Meta and a community of individual developers and companies.' +displayName: React +icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/react.svg +versions: + - version: 2.0.2 + default: true # should have one and only one default version + - version: 2.2.0 diff --git a/tests/helper/registry_server/testdata/registry-build/stacks/nodejs/2.1.1/devfile.yaml b/tests/helper/registry_server/testdata/registry-build/stacks/nodejs/2.1.1/devfile.yaml new file mode 100644 index 00000000000..75c4f5f31ef --- /dev/null +++ b/tests/helper/registry_server/testdata/registry-build/stacks/nodejs/2.1.1/devfile.yaml @@ -0,0 +1,67 @@ +schemaVersion: 2.1.0 +metadata: + name: nodejs + displayName: Node.js Runtime + description: Node.js 16 application + icon: https://nodejs.org/static/images/logos/nodejs-new-pantone-black.svg + tags: + - Node.js + - Express + - ubi8 + projectType: Node.js + language: JavaScript + version: 2.1.1 +starterProjects: + - name: nodejs-starter + git: + remotes: + origin: 'https://github.com/odo-devfiles/nodejs-ex.git' +components: + - name: runtime + container: + image: registry.access.redhat.com/ubi8/nodejs-16:latest + args: ['tail', '-f', '/dev/null'] + memoryLimit: 1024Mi + mountSources: true + env: + - name: DEBUG_PORT + value: '5858' + endpoints: + - name: http-node + targetPort: 3000 + - exposure: none + name: debug + targetPort: 5858 +commands: + - id: install + exec: + component: runtime + commandLine: npm install + workingDir: ${PROJECT_SOURCE} + group: + kind: build + isDefault: true + - id: run + exec: + component: runtime + commandLine: npm start + workingDir: ${PROJECT_SOURCE} + group: + kind: run + isDefault: true + - id: debug + exec: + component: runtime + commandLine: npm run debug + workingDir: ${PROJECT_SOURCE} + group: + kind: debug + isDefault: true + - id: test + exec: + component: runtime + commandLine: npm test + workingDir: ${PROJECT_SOURCE} + group: + kind: test + isDefault: true diff --git a/tests/helper/registry_server/testdata/registry-build/stacks/nodejs/2.2.0/devfile.yaml b/tests/helper/registry_server/testdata/registry-build/stacks/nodejs/2.2.0/devfile.yaml new file mode 100644 index 00000000000..d8fa1f897ab --- /dev/null +++ b/tests/helper/registry_server/testdata/registry-build/stacks/nodejs/2.2.0/devfile.yaml @@ -0,0 +1,67 @@ +schemaVersion: 2.1.0 +metadata: + name: nodejs + displayName: Node.js Runtime + description: Node.js 18 application + icon: https://nodejs.org/static/images/logos/nodejs-new-pantone-black.svg + tags: + - Node.js + - Express + - ubi8 + projectType: Node.js + language: JavaScript + version: 2.2.0 +starterProjects: + - name: nodejs-starter + git: + remotes: + origin: 'https://github.com/odo-devfiles/nodejs-ex.git' +components: + - name: runtime + container: + image: registry.access.redhat.com/ubi8/nodejs-18:1-32 + args: ['tail', '-f', '/dev/null'] + memoryLimit: 1024Mi + mountSources: true + env: + - name: DEBUG_PORT + value: '5858' + endpoints: + - name: http-node + targetPort: 3000 + - exposure: none + name: debug + targetPort: 5858 +commands: + - id: install + exec: + component: runtime + commandLine: npm install + workingDir: ${PROJECT_SOURCE} + group: + kind: build + isDefault: true + - id: run + exec: + component: runtime + commandLine: npm start + workingDir: ${PROJECT_SOURCE} + group: + kind: run + isDefault: true + - id: debug + exec: + component: runtime + commandLine: npm run debug + workingDir: ${PROJECT_SOURCE} + group: + kind: debug + isDefault: true + - id: test + exec: + component: runtime + commandLine: npm test + workingDir: ${PROJECT_SOURCE} + group: + kind: test + isDefault: true diff --git a/tests/helper/registry_server/testdata/registry-build/stacks/nodejs/stack.yaml b/tests/helper/registry_server/testdata/registry-build/stacks/nodejs/stack.yaml new file mode 100644 index 00000000000..7435813ce8d --- /dev/null +++ b/tests/helper/registry_server/testdata/registry-build/stacks/nodejs/stack.yaml @@ -0,0 +1,8 @@ +name: nodejs +description: 'Node.js application' +displayName: Node.js Runtime +icon: https://nodejs.org/static/images/logos/nodejs-new-pantone-black.svg +versions: + - version: 2.1.1 + default: true # should have one and only one default version + - version: 2.2.0 diff --git a/tests/helper/registry_server/testdata/registry-build/stacks/python/2.1.0/devfile.yaml b/tests/helper/registry_server/testdata/registry-build/stacks/python/2.1.0/devfile.yaml new file mode 100644 index 00000000000..fa0fba8d2ec --- /dev/null +++ b/tests/helper/registry_server/testdata/registry-build/stacks/python/2.1.0/devfile.yaml @@ -0,0 +1,62 @@ +schemaVersion: 2.1.0 +metadata: + name: python + displayName: Python + description: "Python (version 3.9.x) is an interpreted, object-oriented, high-level programming language with dynamic semantics. + Its high-level built in data structures, combined with dynamic typing and dynamic binding, make it very attractive for Rapid Application Development, as well as for use as a scripting or glue language to connect existing components together." + icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/python.svg + tags: + - Python + - Pip + - Flask + projectType: Python + language: Python + provider: Red Hat + version: 2.1.0 +starterProjects: + - name: flask-example + description: + 'Flask is a web framework, it’s a Python module that lets you develop web applications easily. + It’s has a small and easy-to-extend core: it’s a microframework that doesn’t include an ORM (Object Relational Manager) or such features.' + git: + remotes: + origin: https://github.com/devfile-samples/python-ex +components: + - name: py + container: + image: registry.access.redhat.com/ubi9/python-39:1-153.1699551718 + args: ['tail', '-f', '/dev/null'] + mountSources: true + endpoints: + - name: http-python + targetPort: 8080 + - exposure: none + name: debug + targetPort: 5858 + env: + - name: DEBUG_PORT + value: '5858' +commands: + - id: pip-install-requirements + exec: + commandLine: pip install -r requirements.txt + workingDir: ${PROJECT_SOURCE} + group: + kind: build + isDefault: true + component: py + - id: run-app + exec: + commandLine: 'python app.py' + workingDir: ${PROJECT_SOURCE} + component: py + group: + kind: run + isDefault: true + - id: debug-py + exec: + commandLine: 'pip install debugpy && python -m debugpy --listen 0.0.0.0:${DEBUG_PORT} app.py' + workingDir: ${PROJECT_SOURCE} + component: py + group: + kind: debug diff --git a/tests/helper/registry_server/testdata/registry-build/stacks/python/3.0.0/archive.tar b/tests/helper/registry_server/testdata/registry-build/stacks/python/3.0.0/archive.tar new file mode 100644 index 0000000000000000000000000000000000000000..dc5c647e344299e0452d5d6b8e1ae53dfea95e4a GIT binary patch literal 741 zcmVvhPlqKIAXWW7nFWP+QkN~RP_S{UAJkPCf70G zHL*S0X_tRLJ5WY|(M>9yrun&vV;>*C&TEbd!j$7XBE!b+hzy6FPW3dbKG)lE9Jk^I zbatp|L7_B~01e5x-WK=N_&-YU=zp(zjA=%meGO~s!T$a){XguqSNw0st*8Ofvn$!a zfA0V3uzv}XOsLYb3=qadsX&r+igbW^9u~LsI25Ixa^|;>lMHF1wCBBow!J5kwD60lAXBtsPr1!o*Jnx+iArz8-H9^YG?{ZOAaVZgmrG#Nh6xd@7ns3hR zb^C*lX3yUW(~}dXRiM9X2yD7DW{yLa0b*q>qc?na1%e8rY8K$jwG1^mR<;=cKCWIf zj!_0m;-w94*B8tLjRe7T{FpP(5lihvSyZ2U@o~VOV(oP=d+-UGGryX9&0 zG}T)8Re^^J8, which is built from the repository: https://github.com/OpenLiberty/devfile-stack + image: icr.io/appcafe/open-liberty-devfile-stack:{{liberty-version}} + args: ['tail', '-f', '/dev/null'] + memoryLimit: 768Mi + mountSources: true + endpoints: + - exposure: public + path: / + name: http-openlib + targetPort: 9080 + protocol: http + - exposure: none + name: debug + targetPort: 5858 + env: + - name: DEBUG_PORT + value: '5858' +commands: + - id: run + exec: + component: dev + commandLine: echo "run command "; {{mvn-cmd}} -DinstallDirectory=/opt/ol/wlp -Ddebug=false -DhotTests=true -DcompileWait=3 io.openliberty.tools:liberty-maven-plugin:{{liberty-plugin-version}}:dev + workingDir: ${PROJECT_SOURCE} + hotReloadCapable: true + group: + kind: run + isDefault: true + - id: run-test-off + exec: + component: dev + commandLine: echo "run-test-off command "; {{mvn-cmd}} -DinstallDirectory=/opt/ol/wlp -Ddebug=false io.openliberty.tools:liberty-maven-plugin:{{liberty-plugin-version}}:dev + workingDir: ${PROJECT_SOURCE} + hotReloadCapable: true + group: + kind: run + isDefault: false + - id: debug + exec: + component: dev + commandLine: echo "debug command "; {{mvn-cmd}} -DinstallDirectory=/opt/ol/wlp -DdebugPort=${DEBUG_PORT} io.openliberty.tools:liberty-maven-plugin:{{liberty-plugin-version}}:dev -Dliberty.env.WLP_DEBUG_REMOTE=y + workingDir: ${PROJECT_SOURCE} + hotReloadCapable: true + group: + kind: debug + isDefault: true + - id: test + # The 'test' command requires an already active container. Multi-module apps require compilation prior to test processing. + exec: + component: dev + commandLine: echo "test command "; {{mvn-cmd}} compiler:compile failsafe:integration-test failsafe:verify + workingDir: ${PROJECT_SOURCE} + hotReloadCapable: true + group: + kind: test + isDefault: true diff --git a/tests/helper/registry_server/testdata/registry/stacks/java-springboot/1.3.0/devfile.yaml b/tests/helper/registry_server/testdata/registry/stacks/java-springboot/1.3.0/devfile.yaml new file mode 100644 index 00000000000..e1789c841e4 --- /dev/null +++ b/tests/helper/registry_server/testdata/registry/stacks/java-springboot/1.3.0/devfile.yaml @@ -0,0 +1,65 @@ +schemaVersion: 2.1.0 +metadata: + name: java-springboot + displayName: Spring Boot® + description: Java application using Spring Boot® and OpenJDK 11 + icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/spring.svg + tags: + - Java + - Spring + projectType: springboot + language: Java + version: 1.3.0 + globalMemoryLimit: 2674Mi +starterProjects: + - name: springbootproject + git: + remotes: + origin: "https://github.com/odo-devfiles/springboot-ex.git" +components: + - name: tools + container: + image: registry.access.redhat.com/ubi9/openjdk-17:1.17-1 + command: ["tail", "-f", "/dev/null"] + memoryLimit: 768Mi + mountSources: true + endpoints: + - name: http-springboot + targetPort: 8080 + - exposure: none + name: debug + targetPort: 5858 + volumeMounts: + - name: m2 + path: /home/user/.m2 + env: + - name: DEBUG_PORT + value: "5858" + - name: m2 + volume: + size: 3Gi +commands: + - id: build + exec: + component: tools + workingDir: ${PROJECT_SOURCE} + commandLine: "mvn clean -Dmaven.repo.local=/home/user/.m2/repository package -Dmaven.test.skip=true" + group: + kind: build + isDefault: true + - id: run + exec: + component: tools + workingDir: ${PROJECT_SOURCE} + commandLine: "mvn -Dmaven.repo.local=/home/user/.m2/repository spring-boot:run" + group: + kind: run + isDefault: true + - id: debug + exec: + component: tools + workingDir: ${PROJECT_SOURCE} + commandLine: "java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=${DEBUG_PORT},suspend=n -jar target/*.jar" + group: + kind: debug + isDefault: true diff --git a/tests/helper/registry_server/testdata/registry/stacks/java-springboot/2.1.0/devfile.yaml b/tests/helper/registry_server/testdata/registry/stacks/java-springboot/2.1.0/devfile.yaml new file mode 100644 index 00000000000..25a849dcd3d --- /dev/null +++ b/tests/helper/registry_server/testdata/registry/stacks/java-springboot/2.1.0/devfile.yaml @@ -0,0 +1,92 @@ +schemaVersion: 2.2.0 +metadata: + name: java-springboot + displayName: Spring Boot® + description: Java application using Spring Boot® and OpenJDK 11 + icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/spring.svg + tags: + - Java + - Spring + projectType: springboot + language: Java + version: 2.1.0 + globalMemoryLimit: 2674Mi +starterProjects: + - name: springbootproject + git: + remotes: + origin: "https://github.com/odo-devfiles/springboot-ex.git" +components: + - name: tools + container: + image: registry.access.redhat.com/ubi9/openjdk-17:1.17-1 + command: ['tail', '-f', '/dev/null'] + memoryLimit: 768Mi + mountSources: true + endpoints: + - name: http-springboot + targetPort: 8080 + - exposure: none + name: debug + targetPort: 5858 + volumeMounts: + - name: m2 + path: /home/user/.m2 + env: + - name: DEBUG_PORT + value: "5858" + - name: m2 + volume: + size: 3Gi + - name: build + image: + imageName: java-springboot-image:latest + dockerfile: + uri: docker/Dockerfile + buildContext: . + rootRequired: false + - name: deploy + kubernetes: + uri: kubernetes/deploy.yaml + endpoints: + - name: http-8081 + targetPort: 8081 +commands: + - id: build + exec: + component: tools + workingDir: ${PROJECT_SOURCE} + commandLine: 'mvn clean -Dmaven.repo.local=/home/user/.m2/repository package -Dmaven.test.skip=true' + group: + kind: build + isDefault: true + - id: run + exec: + component: tools + workingDir: ${PROJECT_SOURCE} + commandLine: 'mvn -Dmaven.repo.local=/home/user/.m2/repository spring-boot:run' + group: + kind: run + isDefault: true + - id: debug + exec: + component: tools + workingDir: ${PROJECT_SOURCE} + commandLine: 'java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=${DEBUG_PORT},suspend=n -jar target/*.jar' + group: + kind: debug + isDefault: true + - id: build-image + apply: + component: build + - id: deployk8s + apply: + component: deploy + - id: deploy + composite: + commands: + - build-image + - deployk8s + group: + kind: deploy + isDefault: true diff --git a/tests/helper/registry_server/testdata/registry/stacks/java-springboot/2.1.0/docker/Dockerfile b/tests/helper/registry_server/testdata/registry/stacks/java-springboot/2.1.0/docker/Dockerfile new file mode 100644 index 00000000000..ee91d95e376 --- /dev/null +++ b/tests/helper/registry_server/testdata/registry/stacks/java-springboot/2.1.0/docker/Dockerfile @@ -0,0 +1,27 @@ +#### +# This Dockerfile is used in order to build a container that runs the Spring Boot application +# +# Build the image with: +# +# docker build -f docker/Dockerfile -t springboot/sample-demo . +# +# Then run the container using: +# +# docker run -i --rm -p 8081:8081 springboot/sample-demo +#### +FROM quay.io/devfile/maven:3.8.1-openjdk-17-slim + +WORKDIR /build + +# Build dependency offline to streamline build +COPY pom.xml . +RUN mvn dependency:go-offline + +COPY src src +RUN mvn package -Dmaven.test.skip=true + +FROM registry.access.redhat.com/ubi9/openjdk-17-runtime:latest +COPY --from=0 /build/target/demo-0.0.1-SNAPSHOT.jar /app/target/demo-0.0.1-SNAPSHOT.jar + +EXPOSE 8081 +ENTRYPOINT [ "java", "-jar", "/app/target/demo-0.0.1-SNAPSHOT.jar", "--server.port=8081" ] diff --git a/tests/helper/registry_server/testdata/registry/stacks/java-springboot/2.1.0/kubernetes/deploy.yaml b/tests/helper/registry_server/testdata/registry/stacks/java-springboot/2.1.0/kubernetes/deploy.yaml new file mode 100644 index 00000000000..0878b82b7cf --- /dev/null +++ b/tests/helper/registry_server/testdata/registry/stacks/java-springboot/2.1.0/kubernetes/deploy.yaml @@ -0,0 +1,41 @@ +kind: Service +apiVersion: v1 +metadata: + name: my-java-springboot-svc +spec: + ports: + - name: http-8081 + port: 8081 + protocol: TCP + targetPort: 8081 + selector: + app: java-springboot-app +--- +kind: Deployment +apiVersion: apps/v1 +metadata: + name: my-java-springboot +spec: + replicas: 1 + selector: + matchLabels: + app: java-springboot-app + template: + metadata: + labels: + app: java-springboot-app + spec: + containers: + - name: my-java-springboot + image: java-springboot-image:latest + ports: + - name: http + containerPort: 8081 + protocol: TCP + resources: + requests: + memory: "180Mi" + cpu: "10m" + limits: + memory: "300Mi" + cpu: "100m" diff --git a/tests/helper/registry_server/testdata/registry/stacks/java-springboot/stack.yaml b/tests/helper/registry_server/testdata/registry/stacks/java-springboot/stack.yaml new file mode 100644 index 00000000000..5f7de7269d2 --- /dev/null +++ b/tests/helper/registry_server/testdata/registry/stacks/java-springboot/stack.yaml @@ -0,0 +1,10 @@ +name: java-springboot +description: Spring Boot using Java +displayName: Spring Boot +icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/spring.svg +versions: + # 1.3.0: with JDK 17 + - version: 1.3.0 + default: true # should have one and only one default version + # 2.1.0: with JDK 17 + - version: 2.1.0 diff --git a/tests/helper/registry_server/testdata/registry/stacks/java-vertx/devfile.yaml b/tests/helper/registry_server/testdata/registry/stacks/java-vertx/devfile.yaml new file mode 100644 index 00000000000..776787a29c0 --- /dev/null +++ b/tests/helper/registry_server/testdata/registry/stacks/java-vertx/devfile.yaml @@ -0,0 +1,138 @@ +schemaVersion: 2.1.0 +metadata: + name: java-vertx + displayName: Vert.x Java + description: Java application using Vert.x and OpenJDK 11 + icon: https://raw.githubusercontent.com/vertx-web-site/vertx-logo/master/vertx-logo.svg + tags: + - Java + - Vert.x + projectType: Vert.x + language: Java + version: 1.2.0 +starterProjects: + - name: vertx-http-example + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-http-example + - name: vertx-istio-circuit-breaker-booster + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-istio-circuit-breaker-booster + - name: vertx-istio-routing-booster + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-istio-routing-booster + - name: vertx-secured-http-example-redhat + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-secured-http-example-redhat + - name: vertx-crud-example-redhat + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-crud-example-redhat + - name: vertx-istio-security-booster + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-istio-security-booster + - name: vertx-crud-example + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-crud-example + - name: vertx-circuit-breaker-example + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-circuit-breaker-example + - name: vertx-configmap-example + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-configmap-example + - name: vertx-circuit-breaker-example-redhat + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-circuit-breaker-example-redhat + - name: vertx-cache-example-redhat + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-cache-example-redhat + - name: vertx-cache-example + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-cache-example + - name: vertx-secured-http-example + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-secured-http-example + - name: vertx-health-checks-example-redhat + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-health-checks-example-redhat + - name: vertx-http-example-redhat + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-http-example-redhat + - name: vertx-health-checks-example + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-health-checks-example + - name: vertx-configmap-example-redhat + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-configmap-example-redhat + - name: vertx-messaging-work-queue-booster + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-messaging-work-queue-booster + - name: vertx-istio-distributed-tracing-booster + git: + remotes: + origin: https://github.com/openshift-vertx-examples/vertx-istio-distributed-tracing-booster +components: + - name: runtime + container: + endpoints: + - exposure: public + path: / + name: http-vertx + targetPort: 8080 + protocol: http + - exposure: none + name: debug + targetPort: 5858 + image: quay.io/eclipse/che-java11-maven:7.37.2 + memoryLimit: 512Mi + mountSources: true + volumeMounts: + - name: m2 + path: /home/user/.m2 + env: + - name: DEBUG_PORT + value: '5858' + - name: m2 + volume: + size: 3Gi +commands: + - id: mvn-package + exec: + commandLine: mvn package -Dmaven.test.skip=true + component: runtime + workingDir: ${PROJECT_SOURCE} + group: + isDefault: true + kind: build + - id: run + exec: + commandLine: mvn io.reactiverse:vertx-maven-plugin:run + component: runtime + workingDir: ${PROJECT_SOURCE} + group: + isDefault: true + kind: run + - id: debug + exec: + commandLine: mvn io.reactiverse:vertx-maven-plugin:debug -Ddebug.port=${DEBUG_PORT} + component: runtime + workingDir: ${PROJECT_SOURCE} + group: + isDefault: true + kind: debug diff --git a/tests/helper/registry_server/testdata/registry/stacks/nodejs-angular/2.0.2/devfile.yaml b/tests/helper/registry_server/testdata/registry/stacks/nodejs-angular/2.0.2/devfile.yaml new file mode 100644 index 00000000000..10a4d8a1865 --- /dev/null +++ b/tests/helper/registry_server/testdata/registry/stacks/nodejs-angular/2.0.2/devfile.yaml @@ -0,0 +1,50 @@ +schemaVersion: 2.1.0 +metadata: + name: nodejs-angular + displayName: Angular + description: "Angular is a development platform, built on TypeScript. As a platform, Angular includes: + A component-based framework for building scalable web applications + A collection of well-integrated libraries that cover a wide variety of features, including routing, forms management, client-server communication, and more + A suite of developer tools to help you develop, build, test, and update your code" + icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/angular.svg + tags: + - Node.js + - Angular + projectType: Angular + language: TypeScript + provider: Red Hat + version: 2.0.2 +starterProjects: + - name: nodejs-angular-starter + git: + checkoutFrom: + revision: main + remotes: + origin: https://github.com/devfile-samples/devfile-stack-nodejs-angular.git +components: + - container: + endpoints: + - name: http-angular + targetPort: 4200 + image: registry.access.redhat.com/ubi8/nodejs-16:1-139 + args: ["tail", "-f", "/dev/null"] + memoryLimit: 1024Mi + name: runtime +commands: + - exec: + commandLine: npm install + component: runtime + group: + isDefault: true + kind: build + workingDir: ${PROJECT_SOURCE} + id: install + - exec: + commandLine: npm run start + component: runtime + group: + isDefault: true + kind: run + hotReloadCapable: true + workingDir: ${PROJECT_SOURCE} + id: run diff --git a/tests/helper/registry_server/testdata/registry/stacks/nodejs-angular/2.1.0/devfile.yaml b/tests/helper/registry_server/testdata/registry/stacks/nodejs-angular/2.1.0/devfile.yaml new file mode 100644 index 00000000000..eb55fc88773 --- /dev/null +++ b/tests/helper/registry_server/testdata/registry/stacks/nodejs-angular/2.1.0/devfile.yaml @@ -0,0 +1,50 @@ +schemaVersion: 2.1.0 +metadata: + name: nodejs-angular + displayName: Angular + description: "Angular is a development platform, built on TypeScript. As a platform, Angular includes: + A component-based framework for building scalable web applications + A collection of well-integrated libraries that cover a wide variety of features, including routing, forms management, client-server communication, and more + A suite of developer tools to help you develop, build, test, and update your code" + icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/angular.svg + tags: + - Node.js + - Angular + projectType: Angular + language: TypeScript + provider: Red Hat + version: 2.1.0 +starterProjects: + - name: nodejs-angular-starter + git: + checkoutFrom: + revision: main + remotes: + origin: https://github.com/devfile-samples/devfile-stack-nodejs-angular.git +components: + - container: + endpoints: + - name: http-angular + targetPort: 4200 + image: registry.access.redhat.com/ubi8/nodejs-18:1-81 + args: ["tail", "-f", "/dev/null"] + memoryLimit: 1024Mi + name: runtime +commands: + - exec: + commandLine: npm install + component: runtime + group: + isDefault: true + kind: build + workingDir: ${PROJECT_SOURCE} + id: install + - exec: + commandLine: npm run start + component: runtime + group: + isDefault: true + kind: run + hotReloadCapable: true + workingDir: ${PROJECT_SOURCE} + id: run diff --git a/tests/helper/registry_server/testdata/registry/stacks/nodejs-angular/2.2.0/devfile.yaml b/tests/helper/registry_server/testdata/registry/stacks/nodejs-angular/2.2.0/devfile.yaml new file mode 100644 index 00000000000..549ec6c2f61 --- /dev/null +++ b/tests/helper/registry_server/testdata/registry/stacks/nodejs-angular/2.2.0/devfile.yaml @@ -0,0 +1,50 @@ +schemaVersion: 2.2.0 +metadata: + name: nodejs-angular + displayName: Angular + description: "Angular is a development platform, built on TypeScript. As a platform, Angular includes: + A component-based framework for building scalable web applications + A collection of well-integrated libraries that cover a wide variety of features, including routing, forms management, client-server communication, and more + A suite of developer tools to help you develop, build, test, and update your code" + icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/angular.svg + tags: + - Node.js + - Angular + projectType: Angular + language: TypeScript + provider: Red Hat + version: 2.2.0 +starterProjects: + - name: nodejs-angular-starter + git: + checkoutFrom: + revision: main + remotes: + origin: https://github.com/devfile-samples/devfile-stack-nodejs-angular.git +components: + - container: + endpoints: + - name: http-angular + targetPort: 4200 + image: registry.access.redhat.com/ubi8/nodejs-18:1-81 + args: ["tail", "-f", "/dev/null"] + memoryLimit: 1024Mi + name: runtime +commands: + - exec: + commandLine: npm install + component: runtime + group: + isDefault: true + kind: build + workingDir: ${PROJECT_SOURCE} + id: install + - exec: + commandLine: npm run start + component: runtime + group: + isDefault: true + kind: run + hotReloadCapable: true + workingDir: ${PROJECT_SOURCE} + id: run diff --git a/tests/helper/registry_server/testdata/registry/stacks/nodejs-angular/stack.yaml b/tests/helper/registry_server/testdata/registry/stacks/nodejs-angular/stack.yaml new file mode 100644 index 00000000000..75e4f7ef31f --- /dev/null +++ b/tests/helper/registry_server/testdata/registry/stacks/nodejs-angular/stack.yaml @@ -0,0 +1,13 @@ +name: nodejs-angular +description: + "Angular is a development platform, built on TypeScript. As a platform, Angular includes: + A component-based framework for building scalable web applications + A collection of well-integrated libraries that cover a wide variety of features, including routing, forms management, client-server communication, and more + A suite of developer tools to help you develop, build, test, and update your code" +displayName: Angular +icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/angular.svg +versions: + - version: 2.0.2 + default: true # should have one and only one default version + - version: 2.1.0 + - version: 2.2.0 diff --git a/tests/helper/registry_server/testdata/registry/stacks/nodejs-react/2.0.2/devfile.yaml b/tests/helper/registry_server/testdata/registry/stacks/nodejs-react/2.0.2/devfile.yaml new file mode 100644 index 00000000000..fd6a73c9b7c --- /dev/null +++ b/tests/helper/registry_server/testdata/registry/stacks/nodejs-react/2.0.2/devfile.yaml @@ -0,0 +1,47 @@ +schemaVersion: 2.1.0 +metadata: + name: nodejs-react + displayName: React + description: "React is a free and open-source front-end JavaScript library for building user interfaces based on UI components. + It is maintained by Meta and a community of individual developers and companies." + icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/react.svg + tags: + - Node.js + - React + projectType: React + language: TypeScript + provider: Red Hat + version: 2.0.2 +starterProjects: + - name: nodejs-react-starter + git: + checkoutFrom: + revision: main + remotes: + origin: https://github.com/devfile-samples/devfile-stacks-nodejs-react.git +components: + - container: + endpoints: + - name: http-react + targetPort: 3000 + image: registry.access.redhat.com/ubi8/nodejs-16:1-139 + args: ['tail', '-f', '/dev/null'] + memoryLimit: 1024Mi + name: runtime +commands: + - exec: + commandLine: npm install + component: runtime + group: + isDefault: true + kind: build + workingDir: ${PROJECT_SOURCE} + id: install + - exec: + commandLine: npm run dev + component: runtime + group: + isDefault: true + kind: run + workingDir: ${PROJECT_SOURCE} + id: run diff --git a/tests/helper/registry_server/testdata/registry/stacks/nodejs-react/2.2.0/devfile.yaml b/tests/helper/registry_server/testdata/registry/stacks/nodejs-react/2.2.0/devfile.yaml new file mode 100644 index 00000000000..707e8748a25 --- /dev/null +++ b/tests/helper/registry_server/testdata/registry/stacks/nodejs-react/2.2.0/devfile.yaml @@ -0,0 +1,47 @@ +schemaVersion: 2.2.0 +metadata: + name: nodejs-react + displayName: React + description: "React is a free and open-source front-end JavaScript library for building user interfaces based on UI components. + It is maintained by Meta and a community of individual developers and companies." + icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/react.svg + tags: + - Node.js + - React + projectType: React + language: TypeScript + provider: Red Hat + version: 2.2.0 +starterProjects: + - name: nodejs-react-starter + git: + checkoutFrom: + revision: main + remotes: + origin: https://github.com/devfile-samples/devfile-stacks-nodejs-react.git +components: + - container: + endpoints: + - name: http-react + targetPort: 3000 + image: registry.access.redhat.com/ubi8/nodejs-18:1-81 + args: ['tail', '-f', '/dev/null'] + memoryLimit: 1024Mi + name: runtime +commands: + - exec: + commandLine: npm install + component: runtime + group: + isDefault: true + kind: build + workingDir: ${PROJECT_SOURCE} + id: install + - exec: + commandLine: npm run dev + component: runtime + group: + isDefault: true + kind: run + workingDir: ${PROJECT_SOURCE} + id: run diff --git a/tests/helper/registry_server/testdata/registry/stacks/nodejs-react/stack.yaml b/tests/helper/registry_server/testdata/registry/stacks/nodejs-react/stack.yaml new file mode 100644 index 00000000000..d974646c380 --- /dev/null +++ b/tests/helper/registry_server/testdata/registry/stacks/nodejs-react/stack.yaml @@ -0,0 +1,10 @@ +name: nodejs-react +description: + 'React is a free and open-source front-end JavaScript library for building user interfaces based on UI components. + It is maintained by Meta and a community of individual developers and companies.' +displayName: React +icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/react.svg +versions: + - version: 2.0.2 + default: true # should have one and only one default version + - version: 2.2.0 diff --git a/tests/helper/registry_server/testdata/registry/stacks/nodejs/2.1.1/devfile.yaml b/tests/helper/registry_server/testdata/registry/stacks/nodejs/2.1.1/devfile.yaml new file mode 100644 index 00000000000..75c4f5f31ef --- /dev/null +++ b/tests/helper/registry_server/testdata/registry/stacks/nodejs/2.1.1/devfile.yaml @@ -0,0 +1,67 @@ +schemaVersion: 2.1.0 +metadata: + name: nodejs + displayName: Node.js Runtime + description: Node.js 16 application + icon: https://nodejs.org/static/images/logos/nodejs-new-pantone-black.svg + tags: + - Node.js + - Express + - ubi8 + projectType: Node.js + language: JavaScript + version: 2.1.1 +starterProjects: + - name: nodejs-starter + git: + remotes: + origin: 'https://github.com/odo-devfiles/nodejs-ex.git' +components: + - name: runtime + container: + image: registry.access.redhat.com/ubi8/nodejs-16:latest + args: ['tail', '-f', '/dev/null'] + memoryLimit: 1024Mi + mountSources: true + env: + - name: DEBUG_PORT + value: '5858' + endpoints: + - name: http-node + targetPort: 3000 + - exposure: none + name: debug + targetPort: 5858 +commands: + - id: install + exec: + component: runtime + commandLine: npm install + workingDir: ${PROJECT_SOURCE} + group: + kind: build + isDefault: true + - id: run + exec: + component: runtime + commandLine: npm start + workingDir: ${PROJECT_SOURCE} + group: + kind: run + isDefault: true + - id: debug + exec: + component: runtime + commandLine: npm run debug + workingDir: ${PROJECT_SOURCE} + group: + kind: debug + isDefault: true + - id: test + exec: + component: runtime + commandLine: npm test + workingDir: ${PROJECT_SOURCE} + group: + kind: test + isDefault: true diff --git a/tests/helper/registry_server/testdata/registry/stacks/nodejs/2.2.0/devfile.yaml b/tests/helper/registry_server/testdata/registry/stacks/nodejs/2.2.0/devfile.yaml new file mode 100644 index 00000000000..d8fa1f897ab --- /dev/null +++ b/tests/helper/registry_server/testdata/registry/stacks/nodejs/2.2.0/devfile.yaml @@ -0,0 +1,67 @@ +schemaVersion: 2.1.0 +metadata: + name: nodejs + displayName: Node.js Runtime + description: Node.js 18 application + icon: https://nodejs.org/static/images/logos/nodejs-new-pantone-black.svg + tags: + - Node.js + - Express + - ubi8 + projectType: Node.js + language: JavaScript + version: 2.2.0 +starterProjects: + - name: nodejs-starter + git: + remotes: + origin: 'https://github.com/odo-devfiles/nodejs-ex.git' +components: + - name: runtime + container: + image: registry.access.redhat.com/ubi8/nodejs-18:1-32 + args: ['tail', '-f', '/dev/null'] + memoryLimit: 1024Mi + mountSources: true + env: + - name: DEBUG_PORT + value: '5858' + endpoints: + - name: http-node + targetPort: 3000 + - exposure: none + name: debug + targetPort: 5858 +commands: + - id: install + exec: + component: runtime + commandLine: npm install + workingDir: ${PROJECT_SOURCE} + group: + kind: build + isDefault: true + - id: run + exec: + component: runtime + commandLine: npm start + workingDir: ${PROJECT_SOURCE} + group: + kind: run + isDefault: true + - id: debug + exec: + component: runtime + commandLine: npm run debug + workingDir: ${PROJECT_SOURCE} + group: + kind: debug + isDefault: true + - id: test + exec: + component: runtime + commandLine: npm test + workingDir: ${PROJECT_SOURCE} + group: + kind: test + isDefault: true diff --git a/tests/helper/registry_server/testdata/registry/stacks/nodejs/stack.yaml b/tests/helper/registry_server/testdata/registry/stacks/nodejs/stack.yaml new file mode 100644 index 00000000000..7435813ce8d --- /dev/null +++ b/tests/helper/registry_server/testdata/registry/stacks/nodejs/stack.yaml @@ -0,0 +1,8 @@ +name: nodejs +description: 'Node.js application' +displayName: Node.js Runtime +icon: https://nodejs.org/static/images/logos/nodejs-new-pantone-black.svg +versions: + - version: 2.1.1 + default: true # should have one and only one default version + - version: 2.2.0 diff --git a/tests/helper/registry_server/testdata/registry/stacks/python/2.1.0/devfile.yaml b/tests/helper/registry_server/testdata/registry/stacks/python/2.1.0/devfile.yaml new file mode 100644 index 00000000000..fa0fba8d2ec --- /dev/null +++ b/tests/helper/registry_server/testdata/registry/stacks/python/2.1.0/devfile.yaml @@ -0,0 +1,62 @@ +schemaVersion: 2.1.0 +metadata: + name: python + displayName: Python + description: "Python (version 3.9.x) is an interpreted, object-oriented, high-level programming language with dynamic semantics. + Its high-level built in data structures, combined with dynamic typing and dynamic binding, make it very attractive for Rapid Application Development, as well as for use as a scripting or glue language to connect existing components together." + icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/python.svg + tags: + - Python + - Pip + - Flask + projectType: Python + language: Python + provider: Red Hat + version: 2.1.0 +starterProjects: + - name: flask-example + description: + 'Flask is a web framework, it’s a Python module that lets you develop web applications easily. + It’s has a small and easy-to-extend core: it’s a microframework that doesn’t include an ORM (Object Relational Manager) or such features.' + git: + remotes: + origin: https://github.com/devfile-samples/python-ex +components: + - name: py + container: + image: registry.access.redhat.com/ubi9/python-39:1-153.1699551718 + args: ['tail', '-f', '/dev/null'] + mountSources: true + endpoints: + - name: http-python + targetPort: 8080 + - exposure: none + name: debug + targetPort: 5858 + env: + - name: DEBUG_PORT + value: '5858' +commands: + - id: pip-install-requirements + exec: + commandLine: pip install -r requirements.txt + workingDir: ${PROJECT_SOURCE} + group: + kind: build + isDefault: true + component: py + - id: run-app + exec: + commandLine: 'python app.py' + workingDir: ${PROJECT_SOURCE} + component: py + group: + kind: run + isDefault: true + - id: debug-py + exec: + commandLine: 'pip install debugpy && python -m debugpy --listen 0.0.0.0:${DEBUG_PORT} app.py' + workingDir: ${PROJECT_SOURCE} + component: py + group: + kind: debug diff --git a/tests/helper/registry_server/testdata/registry/stacks/python/3.0.0/devfile.yaml b/tests/helper/registry_server/testdata/registry/stacks/python/3.0.0/devfile.yaml new file mode 100644 index 00000000000..0fd6702c558 --- /dev/null +++ b/tests/helper/registry_server/testdata/registry/stacks/python/3.0.0/devfile.yaml @@ -0,0 +1,89 @@ +schemaVersion: 2.2.0 +metadata: + name: python + displayName: Python + description: "Python (version 3.9.x) is an interpreted, object-oriented, high-level programming language with dynamic semantics. + Its high-level built in data structures, combined with dynamic typing and dynamic binding, make it very attractive for Rapid Application Development, as well as for use as a scripting or glue language to connect existing components together." + icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/python.svg + tags: + - Python + - Pip + - Flask + projectType: Python + language: Python + provider: Red Hat + version: 3.0.0 +starterProjects: + - name: flask-example + description: + 'Flask is a web framework, it’s a Python module that lets you develop web applications easily. + It’s has a small and easy-to-extend core: it’s a microframework that doesn’t include an ORM (Object Relational Manager) or such features.' + git: + remotes: + origin: https://github.com/devfile-samples/python-ex +components: + - name: py + container: + image: registry.access.redhat.com/ubi9/python-39:1-153.1699551718 + args: ['tail', '-f', '/dev/null'] + mountSources: true + endpoints: + - name: http-python + targetPort: 8080 + - exposure: none + name: debug + targetPort: 5858 + env: + - name: DEBUG_PORT + value: '5858' + - name: build + image: + imageName: python-image:latest + dockerfile: + uri: docker/Dockerfile + buildContext: . + rootRequired: false + - name: deploy + kubernetes: + uri: kubernetes/deploy.yaml + endpoints: + - name: http-8081 + targetPort: 8081 +commands: + - id: pip-install-requirements + exec: + commandLine: pip install -r requirements.txt + workingDir: ${PROJECT_SOURCE} + group: + kind: build + isDefault: true + component: py + - id: run-app + exec: + commandLine: 'python app.py' + workingDir: ${PROJECT_SOURCE} + component: py + group: + kind: run + isDefault: true + - id: debug-py + exec: + commandLine: 'pip install debugpy && python -m debugpy --listen 0.0.0.0:${DEBUG_PORT} app.py' + workingDir: ${PROJECT_SOURCE} + component: py + group: + kind: debug + - id: build-image + apply: + component: build + - id: deployk8s + apply: + component: deploy + - id: deploy + composite: + commands: + - build-image + - deployk8s + group: + kind: deploy + isDefault: true diff --git a/tests/helper/registry_server/testdata/registry/stacks/python/3.0.0/docker/Dockerfile b/tests/helper/registry_server/testdata/registry/stacks/python/3.0.0/docker/Dockerfile new file mode 100644 index 00000000000..f2e07bfa7bd --- /dev/null +++ b/tests/helper/registry_server/testdata/registry/stacks/python/3.0.0/docker/Dockerfile @@ -0,0 +1,20 @@ +FROM registry.access.redhat.com/ubi9/python-39:latest + +# By default, listen on port 8081 +EXPOSE 8081/tcp +ENV FLASK_PORT=8081 + +# Set the working directory in the container +WORKDIR /projects + +# Copy the dependencies file to the working directory +COPY requirements.txt . + +# Install any dependencies +RUN pip install -r requirements.txt + +# Copy the content of the local src directory to the working directory +COPY . . + +# Specify the command to run on container start +CMD [ "python", "./app.py" ] diff --git a/tests/helper/registry_server/testdata/registry/stacks/python/3.0.0/kubernetes/deploy.yaml b/tests/helper/registry_server/testdata/registry/stacks/python/3.0.0/kubernetes/deploy.yaml new file mode 100644 index 00000000000..e981eee3599 --- /dev/null +++ b/tests/helper/registry_server/testdata/registry/stacks/python/3.0.0/kubernetes/deploy.yaml @@ -0,0 +1,41 @@ +kind: Service +apiVersion: v1 +metadata: + name: my-python +spec: + ports: + - name: http-8081 + port: 8081 + protocol: TCP + targetPort: 8081 + selector: + app: python-app +--- +kind: Deployment +apiVersion: apps/v1 +metadata: + name: my-python +spec: + replicas: 1 + selector: + matchLabels: + app: python-app + template: + metadata: + labels: + app: python-app + spec: + containers: + - name: my-python + image: python-image:latest + ports: + - name: http + containerPort: 8081 + protocol: TCP + resources: + requests: + memory: "50Mi" + cpu: "10m" + limits: + memory: "100Mi" + cpu: "100m" diff --git a/tests/helper/registry_server/testdata/registry/stacks/python/stack.yaml b/tests/helper/registry_server/testdata/registry/stacks/python/stack.yaml new file mode 100644 index 00000000000..1bce9f73eb8 --- /dev/null +++ b/tests/helper/registry_server/testdata/registry/stacks/python/stack.yaml @@ -0,0 +1,9 @@ +name: python +description: 'Python is an interpreted, object-oriented, high-level programming language with dynamic semantics. + Its high-level built in data structures, combined with dynamic typing and dynamic binding, make it very attractive for Rapid Application Development, as well as for use as a scripting or glue language to connect existing components together.' +displayName: Python +icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/python.svg +versions: + - version: 2.1.0 + default: true # should have one and only one default version + - version: 3.0.0 diff --git a/vendor/github.com/felixge/httpsnoop/.gitignore b/vendor/github.com/felixge/httpsnoop/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/vendor/github.com/felixge/httpsnoop/.travis.yml b/vendor/github.com/felixge/httpsnoop/.travis.yml new file mode 100644 index 00000000000..bfc421200d0 --- /dev/null +++ b/vendor/github.com/felixge/httpsnoop/.travis.yml @@ -0,0 +1,6 @@ +language: go + +go: + - 1.6 + - 1.7 + - 1.8 diff --git a/vendor/github.com/felixge/httpsnoop/LICENSE.txt b/vendor/github.com/felixge/httpsnoop/LICENSE.txt new file mode 100644 index 00000000000..e028b46a9b0 --- /dev/null +++ b/vendor/github.com/felixge/httpsnoop/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (c) 2016 Felix Geisendörfer (felix@debuggable.com) + + 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/felixge/httpsnoop/Makefile b/vendor/github.com/felixge/httpsnoop/Makefile new file mode 100644 index 00000000000..2d84889aed7 --- /dev/null +++ b/vendor/github.com/felixge/httpsnoop/Makefile @@ -0,0 +1,10 @@ +.PHONY: ci generate clean + +ci: clean generate + go test -v ./... + +generate: + go generate . + +clean: + rm -rf *_generated*.go diff --git a/vendor/github.com/felixge/httpsnoop/README.md b/vendor/github.com/felixge/httpsnoop/README.md new file mode 100644 index 00000000000..ddcecd13e73 --- /dev/null +++ b/vendor/github.com/felixge/httpsnoop/README.md @@ -0,0 +1,95 @@ +# httpsnoop + +Package httpsnoop provides an easy way to capture http related metrics (i.e. +response time, bytes written, and http status code) from your application's +http.Handlers. + +Doing this requires non-trivial wrapping of the http.ResponseWriter interface, +which is also exposed for users interested in a more low-level API. + +[![GoDoc](https://godoc.org/github.com/felixge/httpsnoop?status.svg)](https://godoc.org/github.com/felixge/httpsnoop) +[![Build Status](https://travis-ci.org/felixge/httpsnoop.svg?branch=master)](https://travis-ci.org/felixge/httpsnoop) + +## Usage Example + +```go +// myH is your app's http handler, perhaps a http.ServeMux or similar. +var myH http.Handler +// wrappedH wraps myH in order to log every request. +wrappedH := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + m := httpsnoop.CaptureMetrics(myH, w, r) + log.Printf( + "%s %s (code=%d dt=%s written=%d)", + r.Method, + r.URL, + m.Code, + m.Duration, + m.Written, + ) +}) +http.ListenAndServe(":8080", wrappedH) +``` + +## Why this package exists + +Instrumenting an application's http.Handler is surprisingly difficult. + +However if you google for e.g. "capture ResponseWriter status code" you'll find +lots of advise and code examples that suggest it to be a fairly trivial +undertaking. Unfortunately everything I've seen so far has a high chance of +breaking your application. + +The main problem is that a `http.ResponseWriter` often implements additional +interfaces such as `http.Flusher`, `http.CloseNotifier`, `http.Hijacker`, `http.Pusher`, and +`io.ReaderFrom`. So the naive approach of just wrapping `http.ResponseWriter` +in your own struct that also implements the `http.ResponseWriter` interface +will hide the additional interfaces mentioned above. This has a high change of +introducing subtle bugs into any non-trivial application. + +Another approach I've seen people take is to return a struct that implements +all of the interfaces above. However, that's also problematic, because it's +difficult to fake some of these interfaces behaviors when the underlying +`http.ResponseWriter` doesn't have an implementation. It's also dangerous, +because an application may choose to operate differently, merely because it +detects the presence of these additional interfaces. + +This package solves this problem by checking which additional interfaces a +`http.ResponseWriter` implements, returning a wrapped version implementing the +exact same set of interfaces. + +Additionally this package properly handles edge cases such as `WriteHeader` not +being called, or called more than once, as well as concurrent calls to +`http.ResponseWriter` methods, and even calls happening after the wrapped +`ServeHTTP` has already returned. + +Unfortunately this package is not perfect either. It's possible that it is +still missing some interfaces provided by the go core (let me know if you find +one), and it won't work for applications adding their own interfaces into the +mix. You can however use `httpsnoop.Unwrap(w)` to access the underlying +`http.ResponseWriter` and type-assert the result to its other interfaces. + +However, hopefully the explanation above has sufficiently scared you of rolling +your own solution to this problem. httpsnoop may still break your application, +but at least it tries to avoid it as much as possible. + +Anyway, the real problem here is that smuggling additional interfaces inside +`http.ResponseWriter` is a problematic design choice, but it probably goes as +deep as the Go language specification itself. But that's okay, I still prefer +Go over the alternatives ;). + +## Performance + +``` +BenchmarkBaseline-8 20000 94912 ns/op +BenchmarkCaptureMetrics-8 20000 95461 ns/op +``` + +As you can see, using `CaptureMetrics` on a vanilla http.Handler introduces an +overhead of ~500 ns per http request on my machine. However, the margin of +error appears to be larger than that, therefor it should be reasonable to +assume that the overhead introduced by `CaptureMetrics` is absolutely +negligible. + +## License + +MIT diff --git a/vendor/github.com/felixge/httpsnoop/capture_metrics.go b/vendor/github.com/felixge/httpsnoop/capture_metrics.go new file mode 100644 index 00000000000..b77cc7c0095 --- /dev/null +++ b/vendor/github.com/felixge/httpsnoop/capture_metrics.go @@ -0,0 +1,86 @@ +package httpsnoop + +import ( + "io" + "net/http" + "time" +) + +// Metrics holds metrics captured from CaptureMetrics. +type Metrics struct { + // Code is the first http response code passed to the WriteHeader func of + // the ResponseWriter. If no such call is made, a default code of 200 is + // assumed instead. + Code int + // Duration is the time it took to execute the handler. + Duration time.Duration + // Written is the number of bytes successfully written by the Write or + // ReadFrom function of the ResponseWriter. ResponseWriters may also write + // data to their underlaying connection directly (e.g. headers), but those + // are not tracked. Therefor the number of Written bytes will usually match + // the size of the response body. + Written int64 +} + +// CaptureMetrics wraps the given hnd, executes it with the given w and r, and +// returns the metrics it captured from it. +func CaptureMetrics(hnd http.Handler, w http.ResponseWriter, r *http.Request) Metrics { + return CaptureMetricsFn(w, func(ww http.ResponseWriter) { + hnd.ServeHTTP(ww, r) + }) +} + +// CaptureMetricsFn wraps w and calls fn with the wrapped w and returns the +// resulting metrics. This is very similar to CaptureMetrics (which is just +// sugar on top of this func), but is a more usable interface if your +// application doesn't use the Go http.Handler interface. +func CaptureMetricsFn(w http.ResponseWriter, fn func(http.ResponseWriter)) Metrics { + m := Metrics{Code: http.StatusOK} + m.CaptureMetrics(w, fn) + return m +} + +// CaptureMetrics wraps w and calls fn with the wrapped w and updates +// Metrics m with the resulting metrics. This is similar to CaptureMetricsFn, +// but allows one to customize starting Metrics object. +func (m *Metrics) CaptureMetrics(w http.ResponseWriter, fn func(http.ResponseWriter)) { + var ( + start = time.Now() + headerWritten bool + hooks = Hooks{ + WriteHeader: func(next WriteHeaderFunc) WriteHeaderFunc { + return func(code int) { + next(code) + + if !headerWritten { + m.Code = code + headerWritten = true + } + } + }, + + Write: func(next WriteFunc) WriteFunc { + return func(p []byte) (int, error) { + n, err := next(p) + + m.Written += int64(n) + headerWritten = true + return n, err + } + }, + + ReadFrom: func(next ReadFromFunc) ReadFromFunc { + return func(src io.Reader) (int64, error) { + n, err := next(src) + + headerWritten = true + m.Written += n + return n, err + } + }, + } + ) + + fn(Wrap(w, hooks)) + m.Duration += time.Since(start) +} diff --git a/vendor/github.com/felixge/httpsnoop/docs.go b/vendor/github.com/felixge/httpsnoop/docs.go new file mode 100644 index 00000000000..203c35b3c6d --- /dev/null +++ b/vendor/github.com/felixge/httpsnoop/docs.go @@ -0,0 +1,10 @@ +// Package httpsnoop provides an easy way to capture http related metrics (i.e. +// response time, bytes written, and http status code) from your application's +// http.Handlers. +// +// Doing this requires non-trivial wrapping of the http.ResponseWriter +// interface, which is also exposed for users interested in a more low-level +// API. +package httpsnoop + +//go:generate go run codegen/main.go diff --git a/vendor/github.com/felixge/httpsnoop/wrap_generated_gteq_1.8.go b/vendor/github.com/felixge/httpsnoop/wrap_generated_gteq_1.8.go new file mode 100644 index 00000000000..31cbdfb8ef0 --- /dev/null +++ b/vendor/github.com/felixge/httpsnoop/wrap_generated_gteq_1.8.go @@ -0,0 +1,436 @@ +// +build go1.8 +// Code generated by "httpsnoop/codegen"; DO NOT EDIT + +package httpsnoop + +import ( + "bufio" + "io" + "net" + "net/http" +) + +// HeaderFunc is part of the http.ResponseWriter interface. +type HeaderFunc func() http.Header + +// WriteHeaderFunc is part of the http.ResponseWriter interface. +type WriteHeaderFunc func(code int) + +// WriteFunc is part of the http.ResponseWriter interface. +type WriteFunc func(b []byte) (int, error) + +// FlushFunc is part of the http.Flusher interface. +type FlushFunc func() + +// CloseNotifyFunc is part of the http.CloseNotifier interface. +type CloseNotifyFunc func() <-chan bool + +// HijackFunc is part of the http.Hijacker interface. +type HijackFunc func() (net.Conn, *bufio.ReadWriter, error) + +// ReadFromFunc is part of the io.ReaderFrom interface. +type ReadFromFunc func(src io.Reader) (int64, error) + +// PushFunc is part of the http.Pusher interface. +type PushFunc func(target string, opts *http.PushOptions) error + +// Hooks defines a set of method interceptors for methods included in +// http.ResponseWriter as well as some others. You can think of them as +// middleware for the function calls they target. See Wrap for more details. +type Hooks struct { + Header func(HeaderFunc) HeaderFunc + WriteHeader func(WriteHeaderFunc) WriteHeaderFunc + Write func(WriteFunc) WriteFunc + Flush func(FlushFunc) FlushFunc + CloseNotify func(CloseNotifyFunc) CloseNotifyFunc + Hijack func(HijackFunc) HijackFunc + ReadFrom func(ReadFromFunc) ReadFromFunc + Push func(PushFunc) PushFunc +} + +// Wrap returns a wrapped version of w that provides the exact same interface +// as w. Specifically if w implements any combination of: +// +// - http.Flusher +// - http.CloseNotifier +// - http.Hijacker +// - io.ReaderFrom +// - http.Pusher +// +// The wrapped version will implement the exact same combination. If no hooks +// are set, the wrapped version also behaves exactly as w. Hooks targeting +// methods not supported by w are ignored. Any other hooks will intercept the +// method they target and may modify the call's arguments and/or return values. +// The CaptureMetrics implementation serves as a working example for how the +// hooks can be used. +func Wrap(w http.ResponseWriter, hooks Hooks) http.ResponseWriter { + rw := &rw{w: w, h: hooks} + _, i0 := w.(http.Flusher) + _, i1 := w.(http.CloseNotifier) + _, i2 := w.(http.Hijacker) + _, i3 := w.(io.ReaderFrom) + _, i4 := w.(http.Pusher) + switch { + // combination 1/32 + case !i0 && !i1 && !i2 && !i3 && !i4: + return struct { + Unwrapper + http.ResponseWriter + }{rw, rw} + // combination 2/32 + case !i0 && !i1 && !i2 && !i3 && i4: + return struct { + Unwrapper + http.ResponseWriter + http.Pusher + }{rw, rw, rw} + // combination 3/32 + case !i0 && !i1 && !i2 && i3 && !i4: + return struct { + Unwrapper + http.ResponseWriter + io.ReaderFrom + }{rw, rw, rw} + // combination 4/32 + case !i0 && !i1 && !i2 && i3 && i4: + return struct { + Unwrapper + http.ResponseWriter + io.ReaderFrom + http.Pusher + }{rw, rw, rw, rw} + // combination 5/32 + case !i0 && !i1 && i2 && !i3 && !i4: + return struct { + Unwrapper + http.ResponseWriter + http.Hijacker + }{rw, rw, rw} + // combination 6/32 + case !i0 && !i1 && i2 && !i3 && i4: + return struct { + Unwrapper + http.ResponseWriter + http.Hijacker + http.Pusher + }{rw, rw, rw, rw} + // combination 7/32 + case !i0 && !i1 && i2 && i3 && !i4: + return struct { + Unwrapper + http.ResponseWriter + http.Hijacker + io.ReaderFrom + }{rw, rw, rw, rw} + // combination 8/32 + case !i0 && !i1 && i2 && i3 && i4: + return struct { + Unwrapper + http.ResponseWriter + http.Hijacker + io.ReaderFrom + http.Pusher + }{rw, rw, rw, rw, rw} + // combination 9/32 + case !i0 && i1 && !i2 && !i3 && !i4: + return struct { + Unwrapper + http.ResponseWriter + http.CloseNotifier + }{rw, rw, rw} + // combination 10/32 + case !i0 && i1 && !i2 && !i3 && i4: + return struct { + Unwrapper + http.ResponseWriter + http.CloseNotifier + http.Pusher + }{rw, rw, rw, rw} + // combination 11/32 + case !i0 && i1 && !i2 && i3 && !i4: + return struct { + Unwrapper + http.ResponseWriter + http.CloseNotifier + io.ReaderFrom + }{rw, rw, rw, rw} + // combination 12/32 + case !i0 && i1 && !i2 && i3 && i4: + return struct { + Unwrapper + http.ResponseWriter + http.CloseNotifier + io.ReaderFrom + http.Pusher + }{rw, rw, rw, rw, rw} + // combination 13/32 + case !i0 && i1 && i2 && !i3 && !i4: + return struct { + Unwrapper + http.ResponseWriter + http.CloseNotifier + http.Hijacker + }{rw, rw, rw, rw} + // combination 14/32 + case !i0 && i1 && i2 && !i3 && i4: + return struct { + Unwrapper + http.ResponseWriter + http.CloseNotifier + http.Hijacker + http.Pusher + }{rw, rw, rw, rw, rw} + // combination 15/32 + case !i0 && i1 && i2 && i3 && !i4: + return struct { + Unwrapper + http.ResponseWriter + http.CloseNotifier + http.Hijacker + io.ReaderFrom + }{rw, rw, rw, rw, rw} + // combination 16/32 + case !i0 && i1 && i2 && i3 && i4: + return struct { + Unwrapper + http.ResponseWriter + http.CloseNotifier + http.Hijacker + io.ReaderFrom + http.Pusher + }{rw, rw, rw, rw, rw, rw} + // combination 17/32 + case i0 && !i1 && !i2 && !i3 && !i4: + return struct { + Unwrapper + http.ResponseWriter + http.Flusher + }{rw, rw, rw} + // combination 18/32 + case i0 && !i1 && !i2 && !i3 && i4: + return struct { + Unwrapper + http.ResponseWriter + http.Flusher + http.Pusher + }{rw, rw, rw, rw} + // combination 19/32 + case i0 && !i1 && !i2 && i3 && !i4: + return struct { + Unwrapper + http.ResponseWriter + http.Flusher + io.ReaderFrom + }{rw, rw, rw, rw} + // combination 20/32 + case i0 && !i1 && !i2 && i3 && i4: + return struct { + Unwrapper + http.ResponseWriter + http.Flusher + io.ReaderFrom + http.Pusher + }{rw, rw, rw, rw, rw} + // combination 21/32 + case i0 && !i1 && i2 && !i3 && !i4: + return struct { + Unwrapper + http.ResponseWriter + http.Flusher + http.Hijacker + }{rw, rw, rw, rw} + // combination 22/32 + case i0 && !i1 && i2 && !i3 && i4: + return struct { + Unwrapper + http.ResponseWriter + http.Flusher + http.Hijacker + http.Pusher + }{rw, rw, rw, rw, rw} + // combination 23/32 + case i0 && !i1 && i2 && i3 && !i4: + return struct { + Unwrapper + http.ResponseWriter + http.Flusher + http.Hijacker + io.ReaderFrom + }{rw, rw, rw, rw, rw} + // combination 24/32 + case i0 && !i1 && i2 && i3 && i4: + return struct { + Unwrapper + http.ResponseWriter + http.Flusher + http.Hijacker + io.ReaderFrom + http.Pusher + }{rw, rw, rw, rw, rw, rw} + // combination 25/32 + case i0 && i1 && !i2 && !i3 && !i4: + return struct { + Unwrapper + http.ResponseWriter + http.Flusher + http.CloseNotifier + }{rw, rw, rw, rw} + // combination 26/32 + case i0 && i1 && !i2 && !i3 && i4: + return struct { + Unwrapper + http.ResponseWriter + http.Flusher + http.CloseNotifier + http.Pusher + }{rw, rw, rw, rw, rw} + // combination 27/32 + case i0 && i1 && !i2 && i3 && !i4: + return struct { + Unwrapper + http.ResponseWriter + http.Flusher + http.CloseNotifier + io.ReaderFrom + }{rw, rw, rw, rw, rw} + // combination 28/32 + case i0 && i1 && !i2 && i3 && i4: + return struct { + Unwrapper + http.ResponseWriter + http.Flusher + http.CloseNotifier + io.ReaderFrom + http.Pusher + }{rw, rw, rw, rw, rw, rw} + // combination 29/32 + case i0 && i1 && i2 && !i3 && !i4: + return struct { + Unwrapper + http.ResponseWriter + http.Flusher + http.CloseNotifier + http.Hijacker + }{rw, rw, rw, rw, rw} + // combination 30/32 + case i0 && i1 && i2 && !i3 && i4: + return struct { + Unwrapper + http.ResponseWriter + http.Flusher + http.CloseNotifier + http.Hijacker + http.Pusher + }{rw, rw, rw, rw, rw, rw} + // combination 31/32 + case i0 && i1 && i2 && i3 && !i4: + return struct { + Unwrapper + http.ResponseWriter + http.Flusher + http.CloseNotifier + http.Hijacker + io.ReaderFrom + }{rw, rw, rw, rw, rw, rw} + // combination 32/32 + case i0 && i1 && i2 && i3 && i4: + return struct { + Unwrapper + http.ResponseWriter + http.Flusher + http.CloseNotifier + http.Hijacker + io.ReaderFrom + http.Pusher + }{rw, rw, rw, rw, rw, rw, rw} + } + panic("unreachable") +} + +type rw struct { + w http.ResponseWriter + h Hooks +} + +func (w *rw) Unwrap() http.ResponseWriter { + return w.w +} + +func (w *rw) Header() http.Header { + f := w.w.(http.ResponseWriter).Header + if w.h.Header != nil { + f = w.h.Header(f) + } + return f() +} + +func (w *rw) WriteHeader(code int) { + f := w.w.(http.ResponseWriter).WriteHeader + if w.h.WriteHeader != nil { + f = w.h.WriteHeader(f) + } + f(code) +} + +func (w *rw) Write(b []byte) (int, error) { + f := w.w.(http.ResponseWriter).Write + if w.h.Write != nil { + f = w.h.Write(f) + } + return f(b) +} + +func (w *rw) Flush() { + f := w.w.(http.Flusher).Flush + if w.h.Flush != nil { + f = w.h.Flush(f) + } + f() +} + +func (w *rw) CloseNotify() <-chan bool { + f := w.w.(http.CloseNotifier).CloseNotify + if w.h.CloseNotify != nil { + f = w.h.CloseNotify(f) + } + return f() +} + +func (w *rw) Hijack() (net.Conn, *bufio.ReadWriter, error) { + f := w.w.(http.Hijacker).Hijack + if w.h.Hijack != nil { + f = w.h.Hijack(f) + } + return f() +} + +func (w *rw) ReadFrom(src io.Reader) (int64, error) { + f := w.w.(io.ReaderFrom).ReadFrom + if w.h.ReadFrom != nil { + f = w.h.ReadFrom(f) + } + return f(src) +} + +func (w *rw) Push(target string, opts *http.PushOptions) error { + f := w.w.(http.Pusher).Push + if w.h.Push != nil { + f = w.h.Push(f) + } + return f(target, opts) +} + +type Unwrapper interface { + Unwrap() http.ResponseWriter +} + +// Unwrap returns the underlying http.ResponseWriter from within zero or more +// layers of httpsnoop wrappers. +func Unwrap(w http.ResponseWriter) http.ResponseWriter { + if rw, ok := w.(Unwrapper); ok { + // recurse until rw.Unwrap() returns a non-Unwrapper + return Unwrap(rw.Unwrap()) + } else { + return w + } +} diff --git a/vendor/github.com/felixge/httpsnoop/wrap_generated_lt_1.8.go b/vendor/github.com/felixge/httpsnoop/wrap_generated_lt_1.8.go new file mode 100644 index 00000000000..ab99c07c7a1 --- /dev/null +++ b/vendor/github.com/felixge/httpsnoop/wrap_generated_lt_1.8.go @@ -0,0 +1,278 @@ +// +build !go1.8 +// Code generated by "httpsnoop/codegen"; DO NOT EDIT + +package httpsnoop + +import ( + "bufio" + "io" + "net" + "net/http" +) + +// HeaderFunc is part of the http.ResponseWriter interface. +type HeaderFunc func() http.Header + +// WriteHeaderFunc is part of the http.ResponseWriter interface. +type WriteHeaderFunc func(code int) + +// WriteFunc is part of the http.ResponseWriter interface. +type WriteFunc func(b []byte) (int, error) + +// FlushFunc is part of the http.Flusher interface. +type FlushFunc func() + +// CloseNotifyFunc is part of the http.CloseNotifier interface. +type CloseNotifyFunc func() <-chan bool + +// HijackFunc is part of the http.Hijacker interface. +type HijackFunc func() (net.Conn, *bufio.ReadWriter, error) + +// ReadFromFunc is part of the io.ReaderFrom interface. +type ReadFromFunc func(src io.Reader) (int64, error) + +// Hooks defines a set of method interceptors for methods included in +// http.ResponseWriter as well as some others. You can think of them as +// middleware for the function calls they target. See Wrap for more details. +type Hooks struct { + Header func(HeaderFunc) HeaderFunc + WriteHeader func(WriteHeaderFunc) WriteHeaderFunc + Write func(WriteFunc) WriteFunc + Flush func(FlushFunc) FlushFunc + CloseNotify func(CloseNotifyFunc) CloseNotifyFunc + Hijack func(HijackFunc) HijackFunc + ReadFrom func(ReadFromFunc) ReadFromFunc +} + +// Wrap returns a wrapped version of w that provides the exact same interface +// as w. Specifically if w implements any combination of: +// +// - http.Flusher +// - http.CloseNotifier +// - http.Hijacker +// - io.ReaderFrom +// +// The wrapped version will implement the exact same combination. If no hooks +// are set, the wrapped version also behaves exactly as w. Hooks targeting +// methods not supported by w are ignored. Any other hooks will intercept the +// method they target and may modify the call's arguments and/or return values. +// The CaptureMetrics implementation serves as a working example for how the +// hooks can be used. +func Wrap(w http.ResponseWriter, hooks Hooks) http.ResponseWriter { + rw := &rw{w: w, h: hooks} + _, i0 := w.(http.Flusher) + _, i1 := w.(http.CloseNotifier) + _, i2 := w.(http.Hijacker) + _, i3 := w.(io.ReaderFrom) + switch { + // combination 1/16 + case !i0 && !i1 && !i2 && !i3: + return struct { + Unwrapper + http.ResponseWriter + }{rw, rw} + // combination 2/16 + case !i0 && !i1 && !i2 && i3: + return struct { + Unwrapper + http.ResponseWriter + io.ReaderFrom + }{rw, rw, rw} + // combination 3/16 + case !i0 && !i1 && i2 && !i3: + return struct { + Unwrapper + http.ResponseWriter + http.Hijacker + }{rw, rw, rw} + // combination 4/16 + case !i0 && !i1 && i2 && i3: + return struct { + Unwrapper + http.ResponseWriter + http.Hijacker + io.ReaderFrom + }{rw, rw, rw, rw} + // combination 5/16 + case !i0 && i1 && !i2 && !i3: + return struct { + Unwrapper + http.ResponseWriter + http.CloseNotifier + }{rw, rw, rw} + // combination 6/16 + case !i0 && i1 && !i2 && i3: + return struct { + Unwrapper + http.ResponseWriter + http.CloseNotifier + io.ReaderFrom + }{rw, rw, rw, rw} + // combination 7/16 + case !i0 && i1 && i2 && !i3: + return struct { + Unwrapper + http.ResponseWriter + http.CloseNotifier + http.Hijacker + }{rw, rw, rw, rw} + // combination 8/16 + case !i0 && i1 && i2 && i3: + return struct { + Unwrapper + http.ResponseWriter + http.CloseNotifier + http.Hijacker + io.ReaderFrom + }{rw, rw, rw, rw, rw} + // combination 9/16 + case i0 && !i1 && !i2 && !i3: + return struct { + Unwrapper + http.ResponseWriter + http.Flusher + }{rw, rw, rw} + // combination 10/16 + case i0 && !i1 && !i2 && i3: + return struct { + Unwrapper + http.ResponseWriter + http.Flusher + io.ReaderFrom + }{rw, rw, rw, rw} + // combination 11/16 + case i0 && !i1 && i2 && !i3: + return struct { + Unwrapper + http.ResponseWriter + http.Flusher + http.Hijacker + }{rw, rw, rw, rw} + // combination 12/16 + case i0 && !i1 && i2 && i3: + return struct { + Unwrapper + http.ResponseWriter + http.Flusher + http.Hijacker + io.ReaderFrom + }{rw, rw, rw, rw, rw} + // combination 13/16 + case i0 && i1 && !i2 && !i3: + return struct { + Unwrapper + http.ResponseWriter + http.Flusher + http.CloseNotifier + }{rw, rw, rw, rw} + // combination 14/16 + case i0 && i1 && !i2 && i3: + return struct { + Unwrapper + http.ResponseWriter + http.Flusher + http.CloseNotifier + io.ReaderFrom + }{rw, rw, rw, rw, rw} + // combination 15/16 + case i0 && i1 && i2 && !i3: + return struct { + Unwrapper + http.ResponseWriter + http.Flusher + http.CloseNotifier + http.Hijacker + }{rw, rw, rw, rw, rw} + // combination 16/16 + case i0 && i1 && i2 && i3: + return struct { + Unwrapper + http.ResponseWriter + http.Flusher + http.CloseNotifier + http.Hijacker + io.ReaderFrom + }{rw, rw, rw, rw, rw, rw} + } + panic("unreachable") +} + +type rw struct { + w http.ResponseWriter + h Hooks +} + +func (w *rw) Unwrap() http.ResponseWriter { + return w.w +} + +func (w *rw) Header() http.Header { + f := w.w.(http.ResponseWriter).Header + if w.h.Header != nil { + f = w.h.Header(f) + } + return f() +} + +func (w *rw) WriteHeader(code int) { + f := w.w.(http.ResponseWriter).WriteHeader + if w.h.WriteHeader != nil { + f = w.h.WriteHeader(f) + } + f(code) +} + +func (w *rw) Write(b []byte) (int, error) { + f := w.w.(http.ResponseWriter).Write + if w.h.Write != nil { + f = w.h.Write(f) + } + return f(b) +} + +func (w *rw) Flush() { + f := w.w.(http.Flusher).Flush + if w.h.Flush != nil { + f = w.h.Flush(f) + } + f() +} + +func (w *rw) CloseNotify() <-chan bool { + f := w.w.(http.CloseNotifier).CloseNotify + if w.h.CloseNotify != nil { + f = w.h.CloseNotify(f) + } + return f() +} + +func (w *rw) Hijack() (net.Conn, *bufio.ReadWriter, error) { + f := w.w.(http.Hijacker).Hijack + if w.h.Hijack != nil { + f = w.h.Hijack(f) + } + return f() +} + +func (w *rw) ReadFrom(src io.Reader) (int64, error) { + f := w.w.(io.ReaderFrom).ReadFrom + if w.h.ReadFrom != nil { + f = w.h.ReadFrom(f) + } + return f(src) +} + +type Unwrapper interface { + Unwrap() http.ResponseWriter +} + +// Unwrap returns the underlying http.ResponseWriter from within zero or more +// layers of httpsnoop wrappers. +func Unwrap(w http.ResponseWriter) http.ResponseWriter { + if rw, ok := w.(Unwrapper); ok { + // recurse until rw.Unwrap() returns a non-Unwrapper + return Unwrap(rw.Unwrap()) + } else { + return w + } +} diff --git a/vendor/github.com/gorilla/handlers/LICENSE b/vendor/github.com/gorilla/handlers/LICENSE new file mode 100644 index 00000000000..66ea3c8ae71 --- /dev/null +++ b/vendor/github.com/gorilla/handlers/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2013 The Gorilla Handlers Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/gorilla/handlers/README.md b/vendor/github.com/gorilla/handlers/README.md new file mode 100644 index 00000000000..6eba66bf302 --- /dev/null +++ b/vendor/github.com/gorilla/handlers/README.md @@ -0,0 +1,56 @@ +gorilla/handlers +================ +[![GoDoc](https://godoc.org/github.com/gorilla/handlers?status.svg)](https://godoc.org/github.com/gorilla/handlers) +[![CircleCI](https://circleci.com/gh/gorilla/handlers.svg?style=svg)](https://circleci.com/gh/gorilla/handlers) +[![Sourcegraph](https://sourcegraph.com/github.com/gorilla/handlers/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/handlers?badge) + + +Package handlers is a collection of handlers (aka "HTTP middleware") for use +with Go's `net/http` package (or any framework supporting `http.Handler`), including: + +* [**LoggingHandler**](https://godoc.org/github.com/gorilla/handlers#LoggingHandler) for logging HTTP requests in the Apache [Common Log + Format](http://httpd.apache.org/docs/2.2/logs.html#common). +* [**CombinedLoggingHandler**](https://godoc.org/github.com/gorilla/handlers#CombinedLoggingHandler) for logging HTTP requests in the Apache [Combined Log + Format](http://httpd.apache.org/docs/2.2/logs.html#combined) commonly used by + both Apache and nginx. +* [**CompressHandler**](https://godoc.org/github.com/gorilla/handlers#CompressHandler) for gzipping responses. +* [**ContentTypeHandler**](https://godoc.org/github.com/gorilla/handlers#ContentTypeHandler) for validating requests against a list of accepted + content types. +* [**MethodHandler**](https://godoc.org/github.com/gorilla/handlers#MethodHandler) for matching HTTP methods against handlers in a + `map[string]http.Handler` +* [**ProxyHeaders**](https://godoc.org/github.com/gorilla/handlers#ProxyHeaders) for populating `r.RemoteAddr` and `r.URL.Scheme` based on the + `X-Forwarded-For`, `X-Real-IP`, `X-Forwarded-Proto` and RFC7239 `Forwarded` + headers when running a Go server behind a HTTP reverse proxy. +* [**CanonicalHost**](https://godoc.org/github.com/gorilla/handlers#CanonicalHost) for re-directing to the preferred host when handling multiple + domains (i.e. multiple CNAME aliases). +* [**RecoveryHandler**](https://godoc.org/github.com/gorilla/handlers#RecoveryHandler) for recovering from unexpected panics. + +Other handlers are documented [on the Gorilla +website](https://www.gorillatoolkit.org/pkg/handlers). + +## Example + +A simple example using `handlers.LoggingHandler` and `handlers.CompressHandler`: + +```go +import ( + "net/http" + "github.com/gorilla/handlers" +) + +func main() { + r := http.NewServeMux() + + // Only log requests to our admin dashboard to stdout + r.Handle("/admin", handlers.LoggingHandler(os.Stdout, http.HandlerFunc(ShowAdminDashboard))) + r.HandleFunc("/", ShowIndex) + + // Wrap our server with our gzip handler to gzip compress all responses. + http.ListenAndServe(":8000", handlers.CompressHandler(r)) +} +``` + +## License + +BSD licensed. See the included LICENSE file for details. + diff --git a/vendor/github.com/gorilla/handlers/canonical.go b/vendor/github.com/gorilla/handlers/canonical.go new file mode 100644 index 00000000000..8437fefc1ef --- /dev/null +++ b/vendor/github.com/gorilla/handlers/canonical.go @@ -0,0 +1,74 @@ +package handlers + +import ( + "net/http" + "net/url" + "strings" +) + +type canonical struct { + h http.Handler + domain string + code int +} + +// CanonicalHost is HTTP middleware that re-directs requests to the canonical +// domain. It accepts a domain and a status code (e.g. 301 or 302) and +// re-directs clients to this domain. The existing request path is maintained. +// +// Note: If the provided domain is considered invalid by url.Parse or otherwise +// returns an empty scheme or host, clients are not re-directed. +// +// Example: +// +// r := mux.NewRouter() +// canonical := handlers.CanonicalHost("http://www.gorillatoolkit.org", 302) +// r.HandleFunc("/route", YourHandler) +// +// log.Fatal(http.ListenAndServe(":7000", canonical(r))) +// +func CanonicalHost(domain string, code int) func(h http.Handler) http.Handler { + fn := func(h http.Handler) http.Handler { + return canonical{h, domain, code} + } + + return fn +} + +func (c canonical) ServeHTTP(w http.ResponseWriter, r *http.Request) { + dest, err := url.Parse(c.domain) + if err != nil { + // Call the next handler if the provided domain fails to parse. + c.h.ServeHTTP(w, r) + return + } + + if dest.Scheme == "" || dest.Host == "" { + // Call the next handler if the scheme or host are empty. + // Note that url.Parse won't fail on in this case. + c.h.ServeHTTP(w, r) + return + } + + if !strings.EqualFold(cleanHost(r.Host), dest.Host) { + // Re-build the destination URL + dest := dest.Scheme + "://" + dest.Host + r.URL.Path + if r.URL.RawQuery != "" { + dest += "?" + r.URL.RawQuery + } + http.Redirect(w, r, dest, c.code) + return + } + + c.h.ServeHTTP(w, r) +} + +// cleanHost cleans invalid Host headers by stripping anything after '/' or ' '. +// This is backported from Go 1.5 (in response to issue #11206) and attempts to +// mitigate malformed Host headers that do not match the format in RFC7230. +func cleanHost(in string) string { + if i := strings.IndexAny(in, " /"); i != -1 { + return in[:i] + } + return in +} diff --git a/vendor/github.com/gorilla/handlers/compress.go b/vendor/github.com/gorilla/handlers/compress.go new file mode 100644 index 00000000000..1e95f1ccbfa --- /dev/null +++ b/vendor/github.com/gorilla/handlers/compress.go @@ -0,0 +1,143 @@ +// Copyright 2013 The Gorilla Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package handlers + +import ( + "compress/flate" + "compress/gzip" + "io" + "net/http" + "strings" + + "github.com/felixge/httpsnoop" +) + +const acceptEncoding string = "Accept-Encoding" + +type compressResponseWriter struct { + compressor io.Writer + w http.ResponseWriter +} + +func (cw *compressResponseWriter) WriteHeader(c int) { + cw.w.Header().Del("Content-Length") + cw.w.WriteHeader(c) +} + +func (cw *compressResponseWriter) Write(b []byte) (int, error) { + h := cw.w.Header() + if h.Get("Content-Type") == "" { + h.Set("Content-Type", http.DetectContentType(b)) + } + h.Del("Content-Length") + + return cw.compressor.Write(b) +} + +func (cw *compressResponseWriter) ReadFrom(r io.Reader) (int64, error) { + return io.Copy(cw.compressor, r) +} + +type flusher interface { + Flush() error +} + +func (w *compressResponseWriter) Flush() { + // Flush compressed data if compressor supports it. + if f, ok := w.compressor.(flusher); ok { + f.Flush() + } + // Flush HTTP response. + if f, ok := w.w.(http.Flusher); ok { + f.Flush() + } +} + +// CompressHandler gzip compresses HTTP responses for clients that support it +// via the 'Accept-Encoding' header. +// +// Compressing TLS traffic may leak the page contents to an attacker if the +// page contains user input: http://security.stackexchange.com/a/102015/12208 +func CompressHandler(h http.Handler) http.Handler { + return CompressHandlerLevel(h, gzip.DefaultCompression) +} + +// CompressHandlerLevel gzip compresses HTTP responses with specified compression level +// for clients that support it via the 'Accept-Encoding' header. +// +// The compression level should be gzip.DefaultCompression, gzip.NoCompression, +// or any integer value between gzip.BestSpeed and gzip.BestCompression inclusive. +// gzip.DefaultCompression is used in case of invalid compression level. +func CompressHandlerLevel(h http.Handler, level int) http.Handler { + if level < gzip.DefaultCompression || level > gzip.BestCompression { + level = gzip.DefaultCompression + } + + const ( + gzipEncoding = "gzip" + flateEncoding = "deflate" + ) + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // detect what encoding to use + var encoding string + for _, curEnc := range strings.Split(r.Header.Get(acceptEncoding), ",") { + curEnc = strings.TrimSpace(curEnc) + if curEnc == gzipEncoding || curEnc == flateEncoding { + encoding = curEnc + break + } + } + + // always add Accept-Encoding to Vary to prevent intermediate caches corruption + w.Header().Add("Vary", acceptEncoding) + + // if we weren't able to identify an encoding we're familiar with, pass on the + // request to the handler and return + if encoding == "" { + h.ServeHTTP(w, r) + return + } + + if r.Header.Get("Upgrade") != "" { + h.ServeHTTP(w, r) + return + } + + // wrap the ResponseWriter with the writer for the chosen encoding + var encWriter io.WriteCloser + if encoding == gzipEncoding { + encWriter, _ = gzip.NewWriterLevel(w, level) + } else if encoding == flateEncoding { + encWriter, _ = flate.NewWriter(w, level) + } + defer encWriter.Close() + + w.Header().Set("Content-Encoding", encoding) + r.Header.Del(acceptEncoding) + + cw := &compressResponseWriter{ + w: w, + compressor: encWriter, + } + + w = httpsnoop.Wrap(w, httpsnoop.Hooks{ + Write: func(httpsnoop.WriteFunc) httpsnoop.WriteFunc { + return cw.Write + }, + WriteHeader: func(httpsnoop.WriteHeaderFunc) httpsnoop.WriteHeaderFunc { + return cw.WriteHeader + }, + Flush: func(httpsnoop.FlushFunc) httpsnoop.FlushFunc { + return cw.Flush + }, + ReadFrom: func(rff httpsnoop.ReadFromFunc) httpsnoop.ReadFromFunc { + return cw.ReadFrom + }, + }) + + h.ServeHTTP(w, r) + }) +} diff --git a/vendor/github.com/gorilla/handlers/cors.go b/vendor/github.com/gorilla/handlers/cors.go new file mode 100644 index 00000000000..0dcdffb3d32 --- /dev/null +++ b/vendor/github.com/gorilla/handlers/cors.go @@ -0,0 +1,355 @@ +package handlers + +import ( + "net/http" + "strconv" + "strings" +) + +// CORSOption represents a functional option for configuring the CORS middleware. +type CORSOption func(*cors) error + +type cors struct { + h http.Handler + allowedHeaders []string + allowedMethods []string + allowedOrigins []string + allowedOriginValidator OriginValidator + exposedHeaders []string + maxAge int + ignoreOptions bool + allowCredentials bool + optionStatusCode int +} + +// OriginValidator takes an origin string and returns whether or not that origin is allowed. +type OriginValidator func(string) bool + +var ( + defaultCorsOptionStatusCode = 200 + defaultCorsMethods = []string{"GET", "HEAD", "POST"} + defaultCorsHeaders = []string{"Accept", "Accept-Language", "Content-Language", "Origin"} + // (WebKit/Safari v9 sends the Origin header by default in AJAX requests) +) + +const ( + corsOptionMethod string = "OPTIONS" + corsAllowOriginHeader string = "Access-Control-Allow-Origin" + corsExposeHeadersHeader string = "Access-Control-Expose-Headers" + corsMaxAgeHeader string = "Access-Control-Max-Age" + corsAllowMethodsHeader string = "Access-Control-Allow-Methods" + corsAllowHeadersHeader string = "Access-Control-Allow-Headers" + corsAllowCredentialsHeader string = "Access-Control-Allow-Credentials" + corsRequestMethodHeader string = "Access-Control-Request-Method" + corsRequestHeadersHeader string = "Access-Control-Request-Headers" + corsOriginHeader string = "Origin" + corsVaryHeader string = "Vary" + corsOriginMatchAll string = "*" +) + +func (ch *cors) ServeHTTP(w http.ResponseWriter, r *http.Request) { + origin := r.Header.Get(corsOriginHeader) + if !ch.isOriginAllowed(origin) { + if r.Method != corsOptionMethod || ch.ignoreOptions { + ch.h.ServeHTTP(w, r) + } + + return + } + + if r.Method == corsOptionMethod { + if ch.ignoreOptions { + ch.h.ServeHTTP(w, r) + return + } + + if _, ok := r.Header[corsRequestMethodHeader]; !ok { + w.WriteHeader(http.StatusBadRequest) + return + } + + method := r.Header.Get(corsRequestMethodHeader) + if !ch.isMatch(method, ch.allowedMethods) { + w.WriteHeader(http.StatusMethodNotAllowed) + return + } + + requestHeaders := strings.Split(r.Header.Get(corsRequestHeadersHeader), ",") + allowedHeaders := []string{} + for _, v := range requestHeaders { + canonicalHeader := http.CanonicalHeaderKey(strings.TrimSpace(v)) + if canonicalHeader == "" || ch.isMatch(canonicalHeader, defaultCorsHeaders) { + continue + } + + if !ch.isMatch(canonicalHeader, ch.allowedHeaders) { + w.WriteHeader(http.StatusForbidden) + return + } + + allowedHeaders = append(allowedHeaders, canonicalHeader) + } + + if len(allowedHeaders) > 0 { + w.Header().Set(corsAllowHeadersHeader, strings.Join(allowedHeaders, ",")) + } + + if ch.maxAge > 0 { + w.Header().Set(corsMaxAgeHeader, strconv.Itoa(ch.maxAge)) + } + + if !ch.isMatch(method, defaultCorsMethods) { + w.Header().Set(corsAllowMethodsHeader, method) + } + } else { + if len(ch.exposedHeaders) > 0 { + w.Header().Set(corsExposeHeadersHeader, strings.Join(ch.exposedHeaders, ",")) + } + } + + if ch.allowCredentials { + w.Header().Set(corsAllowCredentialsHeader, "true") + } + + if len(ch.allowedOrigins) > 1 { + w.Header().Set(corsVaryHeader, corsOriginHeader) + } + + returnOrigin := origin + if ch.allowedOriginValidator == nil && len(ch.allowedOrigins) == 0 { + returnOrigin = "*" + } else { + for _, o := range ch.allowedOrigins { + // A configuration of * is different than explicitly setting an allowed + // origin. Returning arbitrary origin headers in an access control allow + // origin header is unsafe and is not required by any use case. + if o == corsOriginMatchAll { + returnOrigin = "*" + break + } + } + } + w.Header().Set(corsAllowOriginHeader, returnOrigin) + + if r.Method == corsOptionMethod { + w.WriteHeader(ch.optionStatusCode) + return + } + ch.h.ServeHTTP(w, r) +} + +// CORS provides Cross-Origin Resource Sharing middleware. +// Example: +// +// import ( +// "net/http" +// +// "github.com/gorilla/handlers" +// "github.com/gorilla/mux" +// ) +// +// func main() { +// r := mux.NewRouter() +// r.HandleFunc("/users", UserEndpoint) +// r.HandleFunc("/projects", ProjectEndpoint) +// +// // Apply the CORS middleware to our top-level router, with the defaults. +// http.ListenAndServe(":8000", handlers.CORS()(r)) +// } +// +func CORS(opts ...CORSOption) func(http.Handler) http.Handler { + return func(h http.Handler) http.Handler { + ch := parseCORSOptions(opts...) + ch.h = h + return ch + } +} + +func parseCORSOptions(opts ...CORSOption) *cors { + ch := &cors{ + allowedMethods: defaultCorsMethods, + allowedHeaders: defaultCorsHeaders, + allowedOrigins: []string{}, + optionStatusCode: defaultCorsOptionStatusCode, + } + + for _, option := range opts { + option(ch) + } + + return ch +} + +// +// Functional options for configuring CORS. +// + +// AllowedHeaders adds the provided headers to the list of allowed headers in a +// CORS request. +// This is an append operation so the headers Accept, Accept-Language, +// and Content-Language are always allowed. +// Content-Type must be explicitly declared if accepting Content-Types other than +// application/x-www-form-urlencoded, multipart/form-data, or text/plain. +func AllowedHeaders(headers []string) CORSOption { + return func(ch *cors) error { + for _, v := range headers { + normalizedHeader := http.CanonicalHeaderKey(strings.TrimSpace(v)) + if normalizedHeader == "" { + continue + } + + if !ch.isMatch(normalizedHeader, ch.allowedHeaders) { + ch.allowedHeaders = append(ch.allowedHeaders, normalizedHeader) + } + } + + return nil + } +} + +// AllowedMethods can be used to explicitly allow methods in the +// Access-Control-Allow-Methods header. +// This is a replacement operation so you must also +// pass GET, HEAD, and POST if you wish to support those methods. +func AllowedMethods(methods []string) CORSOption { + return func(ch *cors) error { + ch.allowedMethods = []string{} + for _, v := range methods { + normalizedMethod := strings.ToUpper(strings.TrimSpace(v)) + if normalizedMethod == "" { + continue + } + + if !ch.isMatch(normalizedMethod, ch.allowedMethods) { + ch.allowedMethods = append(ch.allowedMethods, normalizedMethod) + } + } + + return nil + } +} + +// AllowedOrigins sets the allowed origins for CORS requests, as used in the +// 'Allow-Access-Control-Origin' HTTP header. +// Note: Passing in a []string{"*"} will allow any domain. +func AllowedOrigins(origins []string) CORSOption { + return func(ch *cors) error { + for _, v := range origins { + if v == corsOriginMatchAll { + ch.allowedOrigins = []string{corsOriginMatchAll} + return nil + } + } + + ch.allowedOrigins = origins + return nil + } +} + +// AllowedOriginValidator sets a function for evaluating allowed origins in CORS requests, represented by the +// 'Allow-Access-Control-Origin' HTTP header. +func AllowedOriginValidator(fn OriginValidator) CORSOption { + return func(ch *cors) error { + ch.allowedOriginValidator = fn + return nil + } +} + +// OptionStatusCode sets a custom status code on the OPTIONS requests. +// Default behaviour sets it to 200 to reflect best practices. This is option is not mandatory +// and can be used if you need a custom status code (i.e 204). +// +// More informations on the spec: +// https://fetch.spec.whatwg.org/#cors-preflight-fetch +func OptionStatusCode(code int) CORSOption { + return func(ch *cors) error { + ch.optionStatusCode = code + return nil + } +} + +// ExposedHeaders can be used to specify headers that are available +// and will not be stripped out by the user-agent. +func ExposedHeaders(headers []string) CORSOption { + return func(ch *cors) error { + ch.exposedHeaders = []string{} + for _, v := range headers { + normalizedHeader := http.CanonicalHeaderKey(strings.TrimSpace(v)) + if normalizedHeader == "" { + continue + } + + if !ch.isMatch(normalizedHeader, ch.exposedHeaders) { + ch.exposedHeaders = append(ch.exposedHeaders, normalizedHeader) + } + } + + return nil + } +} + +// MaxAge determines the maximum age (in seconds) between preflight requests. A +// maximum of 10 minutes is allowed. An age above this value will default to 10 +// minutes. +func MaxAge(age int) CORSOption { + return func(ch *cors) error { + // Maximum of 10 minutes. + if age > 600 { + age = 600 + } + + ch.maxAge = age + return nil + } +} + +// IgnoreOptions causes the CORS middleware to ignore OPTIONS requests, instead +// passing them through to the next handler. This is useful when your application +// or framework has a pre-existing mechanism for responding to OPTIONS requests. +func IgnoreOptions() CORSOption { + return func(ch *cors) error { + ch.ignoreOptions = true + return nil + } +} + +// AllowCredentials can be used to specify that the user agent may pass +// authentication details along with the request. +func AllowCredentials() CORSOption { + return func(ch *cors) error { + ch.allowCredentials = true + return nil + } +} + +func (ch *cors) isOriginAllowed(origin string) bool { + if origin == "" { + return false + } + + if ch.allowedOriginValidator != nil { + return ch.allowedOriginValidator(origin) + } + + if len(ch.allowedOrigins) == 0 { + return true + } + + for _, allowedOrigin := range ch.allowedOrigins { + if allowedOrigin == origin || allowedOrigin == corsOriginMatchAll { + return true + } + } + + return false +} + +func (ch *cors) isMatch(needle string, haystack []string) bool { + for _, v := range haystack { + if v == needle { + return true + } + } + + return false +} diff --git a/vendor/github.com/gorilla/handlers/doc.go b/vendor/github.com/gorilla/handlers/doc.go new file mode 100644 index 00000000000..944e5a8ae99 --- /dev/null +++ b/vendor/github.com/gorilla/handlers/doc.go @@ -0,0 +1,9 @@ +/* +Package handlers is a collection of handlers (aka "HTTP middleware") for use +with Go's net/http package (or any framework supporting http.Handler). + +The package includes handlers for logging in standardised formats, compressing +HTTP responses, validating content types and other useful tools for manipulating +requests and responses. +*/ +package handlers diff --git a/vendor/github.com/gorilla/handlers/handlers.go b/vendor/github.com/gorilla/handlers/handlers.go new file mode 100644 index 00000000000..0509482ad7a --- /dev/null +++ b/vendor/github.com/gorilla/handlers/handlers.go @@ -0,0 +1,147 @@ +// Copyright 2013 The Gorilla Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package handlers + +import ( + "bufio" + "fmt" + "net" + "net/http" + "sort" + "strings" +) + +// MethodHandler is an http.Handler that dispatches to a handler whose key in the +// MethodHandler's map matches the name of the HTTP request's method, eg: GET +// +// If the request's method is OPTIONS and OPTIONS is not a key in the map then +// the handler responds with a status of 200 and sets the Allow header to a +// comma-separated list of available methods. +// +// If the request's method doesn't match any of its keys the handler responds +// with a status of HTTP 405 "Method Not Allowed" and sets the Allow header to a +// comma-separated list of available methods. +type MethodHandler map[string]http.Handler + +func (h MethodHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { + if handler, ok := h[req.Method]; ok { + handler.ServeHTTP(w, req) + } else { + allow := []string{} + for k := range h { + allow = append(allow, k) + } + sort.Strings(allow) + w.Header().Set("Allow", strings.Join(allow, ", ")) + if req.Method == "OPTIONS" { + w.WriteHeader(http.StatusOK) + } else { + http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) + } + } +} + +// responseLogger is wrapper of http.ResponseWriter that keeps track of its HTTP +// status code and body size +type responseLogger struct { + w http.ResponseWriter + status int + size int +} + +func (l *responseLogger) Write(b []byte) (int, error) { + size, err := l.w.Write(b) + l.size += size + return size, err +} + +func (l *responseLogger) WriteHeader(s int) { + l.w.WriteHeader(s) + l.status = s +} + +func (l *responseLogger) Status() int { + return l.status +} + +func (l *responseLogger) Size() int { + return l.size +} + +func (l *responseLogger) Hijack() (net.Conn, *bufio.ReadWriter, error) { + conn, rw, err := l.w.(http.Hijacker).Hijack() + if err == nil && l.status == 0 { + // The status will be StatusSwitchingProtocols if there was no error and + // WriteHeader has not been called yet + l.status = http.StatusSwitchingProtocols + } + return conn, rw, err +} + +// isContentType validates the Content-Type header matches the supplied +// contentType. That is, its type and subtype match. +func isContentType(h http.Header, contentType string) bool { + ct := h.Get("Content-Type") + if i := strings.IndexRune(ct, ';'); i != -1 { + ct = ct[0:i] + } + return ct == contentType +} + +// ContentTypeHandler wraps and returns a http.Handler, validating the request +// content type is compatible with the contentTypes list. It writes a HTTP 415 +// error if that fails. +// +// Only PUT, POST, and PATCH requests are considered. +func ContentTypeHandler(h http.Handler, contentTypes ...string) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if !(r.Method == "PUT" || r.Method == "POST" || r.Method == "PATCH") { + h.ServeHTTP(w, r) + return + } + + for _, ct := range contentTypes { + if isContentType(r.Header, ct) { + h.ServeHTTP(w, r) + return + } + } + http.Error(w, fmt.Sprintf("Unsupported content type %q; expected one of %q", r.Header.Get("Content-Type"), contentTypes), http.StatusUnsupportedMediaType) + }) +} + +const ( + // HTTPMethodOverrideHeader is a commonly used + // http header to override a request method. + HTTPMethodOverrideHeader = "X-HTTP-Method-Override" + // HTTPMethodOverrideFormKey is a commonly used + // HTML form key to override a request method. + HTTPMethodOverrideFormKey = "_method" +) + +// HTTPMethodOverrideHandler wraps and returns a http.Handler which checks for +// the X-HTTP-Method-Override header or the _method form key, and overrides (if +// valid) request.Method with its value. +// +// This is especially useful for HTTP clients that don't support many http verbs. +// It isn't secure to override e.g a GET to a POST, so only POST requests are +// considered. Likewise, the override method can only be a "write" method: PUT, +// PATCH or DELETE. +// +// Form method takes precedence over header method. +func HTTPMethodOverrideHandler(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method == "POST" { + om := r.FormValue(HTTPMethodOverrideFormKey) + if om == "" { + om = r.Header.Get(HTTPMethodOverrideHeader) + } + if om == "PUT" || om == "PATCH" || om == "DELETE" { + r.Method = om + } + } + h.ServeHTTP(w, r) + }) +} diff --git a/vendor/github.com/gorilla/handlers/logging.go b/vendor/github.com/gorilla/handlers/logging.go new file mode 100644 index 00000000000..228465eba00 --- /dev/null +++ b/vendor/github.com/gorilla/handlers/logging.go @@ -0,0 +1,244 @@ +// Copyright 2013 The Gorilla Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package handlers + +import ( + "io" + "net" + "net/http" + "net/url" + "strconv" + "time" + "unicode/utf8" + + "github.com/felixge/httpsnoop" +) + +// Logging + +// LogFormatterParams is the structure any formatter will be handed when time to log comes +type LogFormatterParams struct { + Request *http.Request + URL url.URL + TimeStamp time.Time + StatusCode int + Size int +} + +// LogFormatter gives the signature of the formatter function passed to CustomLoggingHandler +type LogFormatter func(writer io.Writer, params LogFormatterParams) + +// loggingHandler is the http.Handler implementation for LoggingHandlerTo and its +// friends + +type loggingHandler struct { + writer io.Writer + handler http.Handler + formatter LogFormatter +} + +func (h loggingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { + t := time.Now() + logger, w := makeLogger(w) + url := *req.URL + + h.handler.ServeHTTP(w, req) + if req.MultipartForm != nil { + req.MultipartForm.RemoveAll() + } + + params := LogFormatterParams{ + Request: req, + URL: url, + TimeStamp: t, + StatusCode: logger.Status(), + Size: logger.Size(), + } + + h.formatter(h.writer, params) +} + +func makeLogger(w http.ResponseWriter) (*responseLogger, http.ResponseWriter) { + logger := &responseLogger{w: w, status: http.StatusOK} + return logger, httpsnoop.Wrap(w, httpsnoop.Hooks{ + Write: func(httpsnoop.WriteFunc) httpsnoop.WriteFunc { + return logger.Write + }, + WriteHeader: func(httpsnoop.WriteHeaderFunc) httpsnoop.WriteHeaderFunc { + return logger.WriteHeader + }, + }) +} + +const lowerhex = "0123456789abcdef" + +func appendQuoted(buf []byte, s string) []byte { + var runeTmp [utf8.UTFMax]byte + for width := 0; len(s) > 0; s = s[width:] { + r := rune(s[0]) + width = 1 + if r >= utf8.RuneSelf { + r, width = utf8.DecodeRuneInString(s) + } + if width == 1 && r == utf8.RuneError { + buf = append(buf, `\x`...) + buf = append(buf, lowerhex[s[0]>>4]) + buf = append(buf, lowerhex[s[0]&0xF]) + continue + } + if r == rune('"') || r == '\\' { // always backslashed + buf = append(buf, '\\') + buf = append(buf, byte(r)) + continue + } + if strconv.IsPrint(r) { + n := utf8.EncodeRune(runeTmp[:], r) + buf = append(buf, runeTmp[:n]...) + continue + } + switch r { + case '\a': + buf = append(buf, `\a`...) + case '\b': + buf = append(buf, `\b`...) + case '\f': + buf = append(buf, `\f`...) + case '\n': + buf = append(buf, `\n`...) + case '\r': + buf = append(buf, `\r`...) + case '\t': + buf = append(buf, `\t`...) + case '\v': + buf = append(buf, `\v`...) + default: + switch { + case r < ' ': + buf = append(buf, `\x`...) + buf = append(buf, lowerhex[s[0]>>4]) + buf = append(buf, lowerhex[s[0]&0xF]) + case r > utf8.MaxRune: + r = 0xFFFD + fallthrough + case r < 0x10000: + buf = append(buf, `\u`...) + for s := 12; s >= 0; s -= 4 { + buf = append(buf, lowerhex[r>>uint(s)&0xF]) + } + default: + buf = append(buf, `\U`...) + for s := 28; s >= 0; s -= 4 { + buf = append(buf, lowerhex[r>>uint(s)&0xF]) + } + } + } + } + return buf +} + +// buildCommonLogLine builds a log entry for req in Apache Common Log Format. +// ts is the timestamp with which the entry should be logged. +// status and size are used to provide the response HTTP status and size. +func buildCommonLogLine(req *http.Request, url url.URL, ts time.Time, status int, size int) []byte { + username := "-" + if url.User != nil { + if name := url.User.Username(); name != "" { + username = name + } + } + + host, _, err := net.SplitHostPort(req.RemoteAddr) + if err != nil { + host = req.RemoteAddr + } + + uri := req.RequestURI + + // Requests using the CONNECT method over HTTP/2.0 must use + // the authority field (aka r.Host) to identify the target. + // Refer: https://httpwg.github.io/specs/rfc7540.html#CONNECT + if req.ProtoMajor == 2 && req.Method == "CONNECT" { + uri = req.Host + } + if uri == "" { + uri = url.RequestURI() + } + + buf := make([]byte, 0, 3*(len(host)+len(username)+len(req.Method)+len(uri)+len(req.Proto)+50)/2) + buf = append(buf, host...) + buf = append(buf, " - "...) + buf = append(buf, username...) + buf = append(buf, " ["...) + buf = append(buf, ts.Format("02/Jan/2006:15:04:05 -0700")...) + buf = append(buf, `] "`...) + buf = append(buf, req.Method...) + buf = append(buf, " "...) + buf = appendQuoted(buf, uri) + buf = append(buf, " "...) + buf = append(buf, req.Proto...) + buf = append(buf, `" `...) + buf = append(buf, strconv.Itoa(status)...) + buf = append(buf, " "...) + buf = append(buf, strconv.Itoa(size)...) + return buf +} + +// writeLog writes a log entry for req to w in Apache Common Log Format. +// ts is the timestamp with which the entry should be logged. +// status and size are used to provide the response HTTP status and size. +func writeLog(writer io.Writer, params LogFormatterParams) { + buf := buildCommonLogLine(params.Request, params.URL, params.TimeStamp, params.StatusCode, params.Size) + buf = append(buf, '\n') + writer.Write(buf) +} + +// writeCombinedLog writes a log entry for req to w in Apache Combined Log Format. +// ts is the timestamp with which the entry should be logged. +// status and size are used to provide the response HTTP status and size. +func writeCombinedLog(writer io.Writer, params LogFormatterParams) { + buf := buildCommonLogLine(params.Request, params.URL, params.TimeStamp, params.StatusCode, params.Size) + buf = append(buf, ` "`...) + buf = appendQuoted(buf, params.Request.Referer()) + buf = append(buf, `" "`...) + buf = appendQuoted(buf, params.Request.UserAgent()) + buf = append(buf, '"', '\n') + writer.Write(buf) +} + +// CombinedLoggingHandler return a http.Handler that wraps h and logs requests to out in +// Apache Combined Log Format. +// +// See http://httpd.apache.org/docs/2.2/logs.html#combined for a description of this format. +// +// LoggingHandler always sets the ident field of the log to - +func CombinedLoggingHandler(out io.Writer, h http.Handler) http.Handler { + return loggingHandler{out, h, writeCombinedLog} +} + +// LoggingHandler return a http.Handler that wraps h and logs requests to out in +// Apache Common Log Format (CLF). +// +// See http://httpd.apache.org/docs/2.2/logs.html#common for a description of this format. +// +// LoggingHandler always sets the ident field of the log to - +// +// Example: +// +// r := mux.NewRouter() +// r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { +// w.Write([]byte("This is a catch-all route")) +// }) +// loggedRouter := handlers.LoggingHandler(os.Stdout, r) +// http.ListenAndServe(":1123", loggedRouter) +// +func LoggingHandler(out io.Writer, h http.Handler) http.Handler { + return loggingHandler{out, h, writeLog} +} + +// CustomLoggingHandler provides a way to supply a custom log formatter +// while taking advantage of the mechanisms in this package +func CustomLoggingHandler(out io.Writer, h http.Handler, f LogFormatter) http.Handler { + return loggingHandler{out, h, f} +} diff --git a/vendor/github.com/gorilla/handlers/proxy_headers.go b/vendor/github.com/gorilla/handlers/proxy_headers.go new file mode 100644 index 00000000000..ed939dcef5d --- /dev/null +++ b/vendor/github.com/gorilla/handlers/proxy_headers.go @@ -0,0 +1,120 @@ +package handlers + +import ( + "net/http" + "regexp" + "strings" +) + +var ( + // De-facto standard header keys. + xForwardedFor = http.CanonicalHeaderKey("X-Forwarded-For") + xForwardedHost = http.CanonicalHeaderKey("X-Forwarded-Host") + xForwardedProto = http.CanonicalHeaderKey("X-Forwarded-Proto") + xForwardedScheme = http.CanonicalHeaderKey("X-Forwarded-Scheme") + xRealIP = http.CanonicalHeaderKey("X-Real-IP") +) + +var ( + // RFC7239 defines a new "Forwarded: " header designed to replace the + // existing use of X-Forwarded-* headers. + // e.g. Forwarded: for=192.0.2.60;proto=https;by=203.0.113.43 + forwarded = http.CanonicalHeaderKey("Forwarded") + // Allows for a sub-match of the first value after 'for=' to the next + // comma, semi-colon or space. The match is case-insensitive. + forRegex = regexp.MustCompile(`(?i)(?:for=)([^(;|,| )]+)`) + // Allows for a sub-match for the first instance of scheme (http|https) + // prefixed by 'proto='. The match is case-insensitive. + protoRegex = regexp.MustCompile(`(?i)(?:proto=)(https|http)`) +) + +// ProxyHeaders inspects common reverse proxy headers and sets the corresponding +// fields in the HTTP request struct. These are X-Forwarded-For and X-Real-IP +// for the remote (client) IP address, X-Forwarded-Proto or X-Forwarded-Scheme +// for the scheme (http|https), X-Forwarded-Host for the host and the RFC7239 +// Forwarded header, which may include both client IPs and schemes. +// +// NOTE: This middleware should only be used when behind a reverse +// proxy like nginx, HAProxy or Apache. Reverse proxies that don't (or are +// configured not to) strip these headers from client requests, or where these +// headers are accepted "as is" from a remote client (e.g. when Go is not behind +// a proxy), can manifest as a vulnerability if your application uses these +// headers for validating the 'trustworthiness' of a request. +func ProxyHeaders(h http.Handler) http.Handler { + fn := func(w http.ResponseWriter, r *http.Request) { + // Set the remote IP with the value passed from the proxy. + if fwd := getIP(r); fwd != "" { + r.RemoteAddr = fwd + } + + // Set the scheme (proto) with the value passed from the proxy. + if scheme := getScheme(r); scheme != "" { + r.URL.Scheme = scheme + } + // Set the host with the value passed by the proxy + if r.Header.Get(xForwardedHost) != "" { + r.Host = r.Header.Get(xForwardedHost) + } + // Call the next handler in the chain. + h.ServeHTTP(w, r) + } + + return http.HandlerFunc(fn) +} + +// getIP retrieves the IP from the X-Forwarded-For, X-Real-IP and RFC7239 +// Forwarded headers (in that order). +func getIP(r *http.Request) string { + var addr string + + if fwd := r.Header.Get(xForwardedFor); fwd != "" { + // Only grab the first (client) address. Note that '192.168.0.1, + // 10.1.1.1' is a valid key for X-Forwarded-For where addresses after + // the first may represent forwarding proxies earlier in the chain. + s := strings.Index(fwd, ", ") + if s == -1 { + s = len(fwd) + } + addr = fwd[:s] + } else if fwd := r.Header.Get(xRealIP); fwd != "" { + // X-Real-IP should only contain one IP address (the client making the + // request). + addr = fwd + } else if fwd := r.Header.Get(forwarded); fwd != "" { + // match should contain at least two elements if the protocol was + // specified in the Forwarded header. The first element will always be + // the 'for=' capture, which we ignore. In the case of multiple IP + // addresses (for=8.8.8.8, 8.8.4.4,172.16.1.20 is valid) we only + // extract the first, which should be the client IP. + if match := forRegex.FindStringSubmatch(fwd); len(match) > 1 { + // IPv6 addresses in Forwarded headers are quoted-strings. We strip + // these quotes. + addr = strings.Trim(match[1], `"`) + } + } + + return addr +} + +// getScheme retrieves the scheme from the X-Forwarded-Proto and RFC7239 +// Forwarded headers (in that order). +func getScheme(r *http.Request) string { + var scheme string + + // Retrieve the scheme from X-Forwarded-Proto. + if proto := r.Header.Get(xForwardedProto); proto != "" { + scheme = strings.ToLower(proto) + } else if proto = r.Header.Get(xForwardedScheme); proto != "" { + scheme = strings.ToLower(proto) + } else if proto = r.Header.Get(forwarded); proto != "" { + // match should contain at least two elements if the protocol was + // specified in the Forwarded header. The first element will always be + // the 'proto=' capture, which we ignore. In the case of multiple proto + // parameters (invalid) we only extract the first. + if match := protoRegex.FindStringSubmatch(proto); len(match) > 1 { + scheme = strings.ToLower(match[1]) + } + } + + return scheme +} diff --git a/vendor/github.com/gorilla/handlers/recovery.go b/vendor/github.com/gorilla/handlers/recovery.go new file mode 100644 index 00000000000..4c4c1d9c6ce --- /dev/null +++ b/vendor/github.com/gorilla/handlers/recovery.go @@ -0,0 +1,96 @@ +package handlers + +import ( + "log" + "net/http" + "runtime/debug" +) + +// RecoveryHandlerLogger is an interface used by the recovering handler to print logs. +type RecoveryHandlerLogger interface { + Println(...interface{}) +} + +type recoveryHandler struct { + handler http.Handler + logger RecoveryHandlerLogger + printStack bool +} + +// RecoveryOption provides a functional approach to define +// configuration for a handler; such as setting the logging +// whether or not to print stack traces on panic. +type RecoveryOption func(http.Handler) + +func parseRecoveryOptions(h http.Handler, opts ...RecoveryOption) http.Handler { + for _, option := range opts { + option(h) + } + + return h +} + +// RecoveryHandler is HTTP middleware that recovers from a panic, +// logs the panic, writes http.StatusInternalServerError, and +// continues to the next handler. +// +// Example: +// +// r := mux.NewRouter() +// r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { +// panic("Unexpected error!") +// }) +// +// http.ListenAndServe(":1123", handlers.RecoveryHandler()(r)) +func RecoveryHandler(opts ...RecoveryOption) func(h http.Handler) http.Handler { + return func(h http.Handler) http.Handler { + r := &recoveryHandler{handler: h} + return parseRecoveryOptions(r, opts...) + } +} + +// RecoveryLogger is a functional option to override +// the default logger +func RecoveryLogger(logger RecoveryHandlerLogger) RecoveryOption { + return func(h http.Handler) { + r := h.(*recoveryHandler) + r.logger = logger + } +} + +// PrintRecoveryStack is a functional option to enable +// or disable printing stack traces on panic. +func PrintRecoveryStack(print bool) RecoveryOption { + return func(h http.Handler) { + r := h.(*recoveryHandler) + r.printStack = print + } +} + +func (h recoveryHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { + defer func() { + if err := recover(); err != nil { + w.WriteHeader(http.StatusInternalServerError) + h.log(err) + } + }() + + h.handler.ServeHTTP(w, req) +} + +func (h recoveryHandler) log(v ...interface{}) { + if h.logger != nil { + h.logger.Println(v...) + } else { + log.Println(v...) + } + + if h.printStack { + stack := string(debug.Stack()) + if h.logger != nil { + h.logger.Println(stack) + } else { + log.Println(stack) + } + } +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 55bf1731e41..fc214e384eb 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -283,6 +283,9 @@ github.com/exponent-io/jsonpath # github.com/fatih/color v1.15.0 ## explicit; go 1.17 github.com/fatih/color +# github.com/felixge/httpsnoop v1.0.3 +## explicit; go 1.13 +github.com/felixge/httpsnoop # github.com/feloy/devfile-lifecycle v0.0.0-20230703133341-1c1589018778 ## explicit; go 1.19 github.com/feloy/devfile-lifecycle/pkg/dftools @@ -449,6 +452,9 @@ github.com/google/uuid # github.com/gookit/color v1.5.4 ## explicit; go 1.18 github.com/gookit/color +# github.com/gorilla/handlers v1.5.1 +## explicit; go 1.14 +github.com/gorilla/handlers # github.com/gorilla/mux v1.8.0 ## explicit; go 1.12 github.com/gorilla/mux From c435c93b1d18a2bdde8d8f8fe8282236d1c41b78 Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Thu, 30 Nov 2023 22:44:14 +0100 Subject: [PATCH 2/4] Fix integration tests with the updates stacks --- tests/integration/cmd_devfile_init_test.go | 6 +++--- tests/integration/cmd_devfile_registry_test.go | 16 ++++++---------- tests/integration/cmd_pref_config_test.go | 2 +- tests/integration/interactive_init_test.go | 4 ++-- 4 files changed, 12 insertions(+), 16 deletions(-) diff --git a/tests/integration/cmd_devfile_init_test.go b/tests/integration/cmd_devfile_init_test.go index 324778dc5a8..1b44a0a7723 100644 --- a/tests/integration/cmd_devfile_init_test.go +++ b/tests/integration/cmd_devfile_init_test.go @@ -156,7 +156,7 @@ var _ = Describe("odo devfile init command tests", func() { helper.JsonPathContentIs(stdout, "devfilePath", filepath.Join(commonVar.Context, "devfile.yaml")) helper.JsonPathContentIs(stdout, "devfileData.devfile.metadata.name", compName) helper.JsonPathContentIs(stdout, "devfileData.supportedOdoFeatures.dev", "true") - helper.JsonPathContentIs(stdout, "devfileData.supportedOdoFeatures.debug", "false") + helper.JsonPathContentIs(stdout, "devfileData.supportedOdoFeatures.debug", "true") helper.JsonPathContentIs(stdout, "devfileData.supportedOdoFeatures.deploy", "false") helper.JsonPathContentIs(stdout, "managedBy", "odo") }) @@ -173,7 +173,7 @@ var _ = Describe("odo devfile init command tests", func() { title: "to download the latest version", devfileVersion: "latest", checkVersion: func(metadataVersion string) { - reg := helper.NewRegistry(helper.GetDevfileRegistryURL()) + reg := helper.NewRegistry(commonVar.GetDevfileRegistryURL()) stack, err := reg.GetStack(devfileName) Expect(err).ToNot(HaveOccurred()) Expect(len(stack.Versions)).ToNot(BeZero()) @@ -604,7 +604,7 @@ spec: devfileRegistries: - name: ns-devfile-reg url: %q -`, helper.GetDevfileRegistryURL())) +`, commonVar.GetDevfileRegistryURL())) Expect(err).ToNot(HaveOccurred()) command := commonVar.CliRunner.Run("-n", commonVar.Project, "apply", "-f", manifestFilePath) Expect(command.ExitCode()).To(BeEquivalentTo(0)) diff --git a/tests/integration/cmd_devfile_registry_test.go b/tests/integration/cmd_devfile_registry_test.go index 10930700b15..e079fc3f5e2 100644 --- a/tests/integration/cmd_devfile_registry_test.go +++ b/tests/integration/cmd_devfile_registry_test.go @@ -35,9 +35,6 @@ var _ = Describe("odo devfile registry command tests", func() { const registryName string = "RegistryName" - // Use staging OCI-based registry for tests to avoid overload - addRegistryURL := helper.GetDevfileRegistryURL() - It("Should list all default registries", func() { output := helper.Cmd("odo", "preference", "view").ShouldPass().Out() helper.MatchAllInOutput(output, []string{"DefaultDevfileRegistry"}) @@ -165,12 +162,12 @@ var _ = Describe("odo devfile registry command tests", func() { When("adding a registry", func() { BeforeEach(func() { - helper.Cmd("odo", "preference", "add", "registry", registryName, addRegistryURL).ShouldPass() + helper.Cmd("odo", "preference", "add", "registry", registryName, commonVar.GetDevfileRegistryURL()).ShouldPass() }) It("should list newly added registry", func() { output := helper.Cmd("odo", "preference", "view").ShouldPass().Out() - helper.MatchAllInOutput(output, []string{registryName, addRegistryURL}) + helper.MatchAllInOutput(output, []string{registryName, commonVar.GetDevfileRegistryURL()}) }) It("should pass, when doing odo init with --devfile-registry flag", func() { @@ -179,7 +176,7 @@ var _ = Describe("odo devfile registry command tests", func() { }) It("should fail, when adding same registry", func() { - helper.Cmd("odo", "preference", "add", "registry", registryName, addRegistryURL).ShouldFail() + helper.Cmd("odo", "preference", "add", "registry", registryName, commonVar.GetDevfileRegistryURL()).ShouldFail() }) It("should successfully delete registry", func() { @@ -197,11 +194,10 @@ var _ = Describe("odo devfile registry command tests", func() { output := helper.Cmd("odo", "preference", "view", "-o", "json").ShouldPass().Out() Expect(helper.IsJSON(output)).To(BeTrue()) helper.JsonPathContentIs(output, "registries.0.name", registryName) - helper.JsonPathContentIs(output, "registries.0.url", addRegistryURL) + helper.JsonPathContentIs(output, "registries.0.url", commonVar.GetDevfileRegistryURL()) helper.JsonPathContentIs(output, "registries.1.name", "DefaultDevfileRegistry") - helper.JsonPathContentIs(output, "registries.1.url", addRegistryURL) // as we are using its updated in case of Proxy + helper.JsonPathContentIs(output, "registries.1.url", commonVar.GetDevfileRegistryURL()) // as we are using its updated in case of Proxy }) - }) }) @@ -235,7 +231,7 @@ spec: devfileRegistries: - name: ns-devfile-reg url: %q -`, helper.GetDevfileRegistryURL())) +`, commonVar.GetDevfileRegistryURL())) Expect(err).ToNot(HaveOccurred()) command := commonVar.CliRunner.Run("-n", commonVar.Project, "apply", "-f", manifestFilePath) Expect(command.ExitCode()).To(BeEquivalentTo(0)) diff --git a/tests/integration/cmd_pref_config_test.go b/tests/integration/cmd_pref_config_test.go index ca5f5a5b9b8..ded0d9923c3 100644 --- a/tests/integration/cmd_pref_config_test.go +++ b/tests/integration/cmd_pref_config_test.go @@ -391,7 +391,7 @@ OdoSettings: BeforeEach(func() { manifestFilePath := filepath.Join(commonVar.ConfigDir, "devfileRegistryListCR.yaml") - registryURL = helper.GetDevfileRegistryURL() + registryURL = commonVar.GetDevfileRegistryURL() // NOTE: Use reachable URLs as we might be on a cluster with the registry operator installed, which would perform validations. err := helper.CreateFileWithContent(manifestFilePath, fmt.Sprintf(` apiVersion: registry.devfile.io/v1alpha1 diff --git a/tests/integration/interactive_init_test.go b/tests/integration/interactive_init_test.go index aeb796291a3..8fd67c459e5 100644 --- a/tests/integration/interactive_init_test.go +++ b/tests/integration/interactive_init_test.go @@ -271,7 +271,7 @@ var _ = Describe("odo init interactive command tests", func() { command := []string{"odo", "init"} starter := "go-starter" componentName := "my-go-app" - devfileVersion := "2.0.0" + devfileVersion := "2.2.0" output, err := helper.RunInteractive(command, nil, func(ctx helper.InteractiveContext) { @@ -728,7 +728,7 @@ spec: devfileRegistries: - name: %s url: %q -`, devfileRegistryName, helper.GetDevfileRegistryURL())) +`, devfileRegistryName, commonVar.GetDevfileRegistryURL())) Expect(err).ToNot(HaveOccurred()) command := commonVar.CliRunner.Run("-n", commonVar.Project, "apply", "-f", manifestFilePath) Expect(command.ExitCode()).To(BeEquivalentTo(0)) From 63e6740d675594e30e72f9730ccbe2cb2ffddbe9 Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Thu, 30 Nov 2023 22:45:26 +0100 Subject: [PATCH 3/4] Fix doc-automation tests The registry URL is now by default. --- .../docs-mdx/init/devfile_from_url_output.mdx | 4 +- .../docs-mdx/init/registry_list_output.mdx | 4 +- .../docs-mdx/init/registry_output.mdx | 2 +- .../init/versioned_devfile_output.mdx | 4 +- .../docs-mdx/go/go_odo_init_output.mdx | 8 ++-- .../doc_command_reference_init_test.go | 42 +++++++++++++------ tests/helper/helper_documentation.go | 5 +++ 7 files changed, 46 insertions(+), 23 deletions(-) diff --git a/docs/website/docs/command-reference/docs-mdx/init/devfile_from_url_output.mdx b/docs/website/docs/command-reference/docs-mdx/init/devfile_from_url_output.mdx index 37eafdb1f45..19375af0f74 100644 --- a/docs/website/docs/command-reference/docs-mdx/init/devfile_from_url_output.mdx +++ b/docs/website/docs/command-reference/docs-mdx/init/devfile_from_url_output.mdx @@ -1,12 +1,12 @@ ```console -$ odo init --devfile-path https://registry.devfile.io/devfiles/nodejs-angular --name my-nodejs-app --starter nodejs-angular-starter +$ odo init --devfile-path https://registry.stage.devfile.io/devfiles/nodejs-angular --name my-nodejs-app --starter nodejs-angular-starter __ / \__ Initializing a new component \__/ \ / \__/ odo version: v3.15.0 \__/ - ✓ Downloading devfile from "https://registry.devfile.io/devfiles/nodejs-angular" [1s] + ✓ Downloading devfile from "https://registry.stage.devfile.io/devfiles/nodejs-angular" [1s] ✓ Downloading starter project "nodejs-angular-starter" [958ms] Your new component 'my-nodejs-app' is ready in the current directory. diff --git a/docs/website/docs/command-reference/docs-mdx/init/registry_list_output.mdx b/docs/website/docs/command-reference/docs-mdx/init/registry_list_output.mdx index 1b550e716c6..1c6a66a656e 100644 --- a/docs/website/docs/command-reference/docs-mdx/init/registry_list_output.mdx +++ b/docs/website/docs/command-reference/docs-mdx/init/registry_list_output.mdx @@ -1,6 +1,6 @@ ```console $ odo registry --devfile nodejs-react NAME REGISTRY DESCRIPTION ARCHITECTURES VERSIONS - nodejs-react StagingRegistry React is a free and open-source front-en... 2.0.2, 2.1.0, 2.2.0 - nodejs-react DefaultDevfileRegistry React is a free and open-source front-en... 2.0.2, 2.1.0, 2.2.0 + nodejs-react StagingRegistry React is a free and open-source front-en... 2.0.2, 2.2.0 + nodejs-react DefaultDevfileRegistry React is a free and open-source front-en... 2.0.2, 2.2.0 ``` \ No newline at end of file diff --git a/docs/website/docs/command-reference/docs-mdx/init/registry_output.mdx b/docs/website/docs/command-reference/docs-mdx/init/registry_output.mdx index 81039500161..eb404a01fd5 100644 --- a/docs/website/docs/command-reference/docs-mdx/init/registry_output.mdx +++ b/docs/website/docs/command-reference/docs-mdx/init/registry_output.mdx @@ -5,5 +5,5 @@ $ odo preference view Devfile registries: NAME URL SECURE StagingRegistry https://registry.stage.devfile.io No - DefaultDevfileRegistry https://registry.devfile.io No + DefaultDevfileRegistry https://registry.stage.devfile.io No ``` \ No newline at end of file diff --git a/docs/website/docs/command-reference/docs-mdx/init/versioned_devfile_output.mdx b/docs/website/docs/command-reference/docs-mdx/init/versioned_devfile_output.mdx index 774528e5e20..12d1d3cd1f7 100644 --- a/docs/website/docs/command-reference/docs-mdx/init/versioned_devfile_output.mdx +++ b/docs/website/docs/command-reference/docs-mdx/init/versioned_devfile_output.mdx @@ -1,12 +1,12 @@ ```console -$ odo init --devfile go --name my-go-app --devfile-version 2.0.0 +$ odo init --devfile go --name my-go-app --devfile-version 2.2.0 __ / \__ Initializing a new component \__/ \ / \__/ odo version: v3.15.0 \__/ - ✓ Downloading devfile "go:2.0.0" [3s] + ✓ Downloading devfile "go:2.2.0" [3s] Your new component 'my-go-app' is ready in the current directory. To start editing your component, use 'odo dev' and open this folder in your favorite IDE. diff --git a/docs/website/docs/user-guides/quickstart/docs-mdx/go/go_odo_init_output.mdx b/docs/website/docs/user-guides/quickstart/docs-mdx/go/go_odo_init_output.mdx index 8c47a17c9ba..1465eebd8cc 100644 --- a/docs/website/docs/user-guides/quickstart/docs-mdx/go/go_odo_init_output.mdx +++ b/docs/website/docs/user-guides/quickstart/docs-mdx/go/go_odo_init_output.mdx @@ -13,20 +13,22 @@ Supported architectures: all Language: Go Project type: Go Application ports: 8080 -The devfile "go:1.0.2" from the registry "DefaultDevfileRegistry" will be downloaded. +The devfile "go:1.2.0" from the registry "DefaultDevfileRegistry" will be downloaded. ? Is this correct? Yes - ✓ Downloading devfile "go:1.0.2" from registry "DefaultDevfileRegistry" [3s] + ✓ Downloading devfile "go:1.2.0" from registry "DefaultDevfileRegistry" [3s] ↪ Container Configuration "runtime": OPEN PORTS: - 8080 + - 5858 ENVIRONMENT VARIABLES: + - DEBUG_PORT = 5858 ? Select container for which you want to change configuration? NONE - configuration is correct ? Enter component name: my-go-app You can automate this command by executing: - odo init --name my-go-app --devfile go --devfile-registry DefaultDevfileRegistry --devfile-version 1.0.2 + odo init --name my-go-app --devfile go --devfile-registry DefaultDevfileRegistry --devfile-version 1.2.0 Your new component 'my-go-app' is ready in the current directory. To start editing your component, use 'odo dev' and open this folder in your favorite IDE. diff --git a/tests/documentation/command-reference/doc_command_reference_init_test.go b/tests/documentation/command-reference/doc_command_reference_init_test.go index 310f27a891b..db5dc17ddcf 100644 --- a/tests/documentation/command-reference/doc_command_reference_init_test.go +++ b/tests/documentation/command-reference/doc_command_reference_init_test.go @@ -104,7 +104,7 @@ var _ = Describe("doc command reference odo init", Label(helper.LabelNoCluster), Context("Non Interactive Mode", func() { It("Fetch Devfile of a specific version", func() { - args := []string{"init", "--devfile", "go", "--name", "my-go-app", "--devfile-version", "2.0.0"} + args := []string{"init", "--devfile", "go", "--name", "my-go-app", "--devfile-version", "2.2.0"} out := helper.Cmd("odo", args...).ShouldPass().Out() got := fmt.Sprintf(outputStringFormat, strings.Join(args, " "), helper.StripSpinner(out)) got = helper.StripGitCommitFromVersion(got) @@ -126,10 +126,11 @@ var _ = Describe("doc command reference odo init", Label(helper.LabelNoCluster), }) It("Fetch Devfile from a URL", func() { - args := []string{"init", "--devfile-path", "https://registry.devfile.io/devfiles/nodejs-angular", "--name", "my-nodejs-app", "--starter", "nodejs-angular-starter"} + args := []string{"init", "--devfile-path", fmt.Sprintf("%s/devfiles/nodejs-angular", commonVar.GetDevfileRegistryURL()), "--name", "my-nodejs-app", "--starter", "nodejs-angular-starter"} out := helper.Cmd("odo", args...).ShouldPass().Out() got := fmt.Sprintf(outputStringFormat, strings.Join(args, " "), helper.StripSpinner(out)) got = helper.StripGitCommitFromVersion(got) + got = helper.ReplaceRegistryUrl(commonVar, got) file := "devfile_from_url_output.mdx" want := helper.GetMDXContent(filepath.Join(commonPath, file)) diff := cmp.Diff(want, got) @@ -139,21 +140,19 @@ var _ = Describe("doc command reference odo init", Label(helper.LabelNoCluster), Context("fetching devfile from a registry", func() { When("setting up the registry", func() { const ( - defaultReg = "DefaultDevfileRegistry" - defaultRegURL = "https://registry.devfile.io" - stagingReg = "StagingRegistry" - stagingRegURL = "https://registry.stage.devfile.io" + defaultReg = "DefaultDevfileRegistry" + stagingReg = "StagingRegistry" ) BeforeEach(func() { helper.Cmd("odo", "preference", "remove", "registry", defaultReg, "-f").ShouldPass() - helper.Cmd("odo", "preference", "add", "registry", defaultReg, defaultRegURL).ShouldPass() - - helper.Cmd("odo", "preference", "add", "registry", stagingReg, stagingRegURL).ShouldPass() + devfileRegistryURL := commonVar.GetDevfileRegistryURL() + helper.Cmd("odo", "preference", "add", "registry", defaultReg, devfileRegistryURL).ShouldPass() + helper.Cmd("odo", "preference", "add", "registry", stagingReg, devfileRegistryURL).ShouldPass() }) AfterEach(func() { helper.Cmd("odo", "preference", "remove", "registry", stagingReg, "-f").ShouldPass() - helper.SetDefaultDevfileRegistryAsStaging() + helper.SetDefaultDevfileRegistry(&commonVar) }) removePreferenceKeys := func(docString string) string { @@ -165,10 +164,26 @@ var _ = Describe("doc command reference odo init", Label(helper.LabelNoCluster), got := helper.StripAnsi(out) got = removePreferenceKeys(got) got = fmt.Sprintf(outputStringFormat, strings.Join(args, " "), helper.StripSpinner(got)) + got = helper.ReplaceRegistryUrl(commonVar, got) file := "registry_output.mdx" want := helper.GetMDXContent(filepath.Join(commonPath, file)) - diff := cmp.Diff(want, got) - Expect(diff).To(BeEmpty(), file) + want = helper.ReplaceRegistryUrl(commonVar, want) + wantLines, err := helper.ExtractLines(want) + Expect(err).ShouldNot(HaveOccurred()) + gotLines, err := helper.ExtractLines(got) + Expect(err).ShouldNot(HaveOccurred()) + Expect(gotLines).ShouldNot(BeEmpty()) + Expect(gotLines).Should(HaveLen(len(wantLines)), + fmt.Sprintf("%s: unexpected number of lines:\n==want:\n%s\n\n==got:\n%s", file, want, got)) + for i, line := range wantLines { + if strings.Contains(line, "SECURE") { + continue + } + wantFields := strings.Fields(line) + gotFields := strings.Fields(gotLines[i]) + Expect(gotFields).Should(HaveExactElements(wantFields), + fmt.Sprintf("%s: mismatch at line %d:\n==want line:\n%s\n\n==got line:\n%s", file, i, line, gotLines[i])) + } } It("Fetch Devfile from a specific registry of the list", func() { @@ -219,10 +234,11 @@ var _ = Describe("doc command reference odo init", Label(helper.LabelNoCluster), }) It("Fetch Devfile from a URL", func() { - args := []string{"init", "--devfile-path", "https://registry.devfile.io/devfiles/nodejs-angular", "--name", "my-nodejs-app", "--starter", "nodejs-angular-starter"} + args := []string{"init", "--devfile-path", fmt.Sprintf("%s/devfiles/nodejs-angular", commonVar.GetDevfileRegistryURL()), "--name", "my-nodejs-app", "--starter", "nodejs-angular-starter"} out := helper.Cmd("odo", args...).ShouldPass().Out() got := fmt.Sprintf(outputStringFormat, strings.Join(args, " "), helper.StripSpinner(out)) got = helper.StripGitCommitFromVersion(got) + got = helper.ReplaceRegistryUrl(commonVar, got) file := "devfile_from_url_output.mdx" want := helper.GetMDXContent(filepath.Join(commonPath, file)) diff := cmp.Diff(want, got) diff --git a/tests/helper/helper_documentation.go b/tests/helper/helper_documentation.go index e8f5edbfb34..fbf069ccd97 100644 --- a/tests/helper/helper_documentation.go +++ b/tests/helper/helper_documentation.go @@ -154,3 +154,8 @@ func ReplaceAllForwardedPorts(docString string, cmdEndpointsMap map[string]strin } return } + +// ReplaceRegistryUrl replaces the registry URL used for testing by a more static one +func ReplaceRegistryUrl(commonVar CommonVar, docString string) string { + return strings.ReplaceAll(docString, commonVar.GetDevfileRegistryURL(), "https://registry.stage.devfile.io") +} From 5250cdf85e1cc3fa9d93d4bcdf144a4fdea753c6 Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Thu, 30 Nov 2023 22:46:52 +0100 Subject: [PATCH 4/4] Fix Windows tests script For some reason, "scp" was not able to find the destination folder. --- .ibm/pipelines/windows-test.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.ibm/pipelines/windows-test.sh b/.ibm/pipelines/windows-test.sh index df035e6ef3c..cc04bc8e3db 100755 --- a/.ibm/pipelines/windows-test.sh +++ b/.ibm/pipelines/windows-test.sh @@ -14,11 +14,13 @@ TEST_NAME="Windows Tests (OCP)" export REPO=${REPO:-"https://github.com/redhat-developer/odo"} #copy test script inside /tmp/ -sshpass -p $WINDOWS_PASSWORD scp -o StrictHostKeyChecking=no ./.ibm/pipelines/windows-test-script.ps1 Administrator@$WINDOWS_IP:/tmp/windows-test-script.ps1 +sshpass -p $WINDOWS_PASSWORD scp -o StrictHostKeyChecking=no powershell "New-Item -ItemType Directory -Force -Path C:\tmp -ErrorAction SilentlyContinue" + +sshpass -p $WINDOWS_PASSWORD scp -o StrictHostKeyChecking=no ./.ibm/pipelines/windows-test-script.ps1 Administrator@$WINDOWS_IP:C:\tmp\windows-test-script.ps1 #execute test from the test script export TEST_EXEC_NODES=${TEST_EXEC_NODES:-"16"} -sshpass -p $WINDOWS_PASSWORD ssh Administrator@$WINDOWS_IP -o StrictHostKeyChecking=no powershell /tmp/windows-test-script.ps1 "${GIT_PR_NUMBER}" "${BUILD_NUMBER}" "${API_KEY_QE}" "${IBM_OPENSHIFT_ENDPOINT}" "${LOGFILE}" "${REPO}" "${CLUSTER_ID}" "${TEST_EXEC_NODES}" "${SKIP_SERVICE_BINDING_TESTS}" +sshpass -p $WINDOWS_PASSWORD ssh Administrator@$WINDOWS_IP -o StrictHostKeyChecking=no powershell C:\tmp\windows-test-script.ps1 "${GIT_PR_NUMBER}" "${BUILD_NUMBER}" "${API_KEY_QE}" "${IBM_OPENSHIFT_ENDPOINT}" "${LOGFILE}" "${REPO}" "${CLUSTER_ID}" "${TEST_EXEC_NODES}" "${SKIP_SERVICE_BINDING_TESTS}" RESULT=$? echo "RESULT: $RESULT" @@ -36,6 +38,6 @@ save_results "/tmp/test-integration.xml" "${LOGFILE}" "${TEST_NAME}" "${BUILD_NU save_results "/tmp/test-e2e.xml" "${LOGFILE}" "${TEST_NAME}" "${BUILD_NUMBER}" # cleanup -sshpass -p $WINDOWS_PASSWORD ssh Administrator@$WINDOWS_IP -o StrictHostKeyChecking=no rm -rf /tmp/windows-test-script.ps1 +sshpass -p $WINDOWS_PASSWORD ssh Administrator@$WINDOWS_IP -o StrictHostKeyChecking=no rm -rf C:\tmp\windows-test-script.ps1 exit ${RESULT}