Start HTTP server to replace Devfile Registry server in the tests (#7154)

This commit is contained in:
Armel Soro
2023-12-01 10:35:15 +01:00
committed by GitHub
parent 172c57d0eb
commit 15f663f12a
104 changed files with 6721 additions and 54 deletions

View File

@@ -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}

View File

@@ -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/

View File

@@ -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.

View File

@@ -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
```

View File

@@ -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
```

View File

@@ -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.

View File

@@ -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.

2
go.mod
View File

@@ -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

View File

@@ -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)

View File

@@ -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")
}

View File

@@ -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) {

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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}"

View File

@@ -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.

View File

@@ -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"
]
}
]
}
]

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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:<x.y.z>, 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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, its a Python module that lets you develop web applications easily.
Its has a small and easy-to-extend core: its a microframework that doesnt 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

View File

@@ -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, its a Python module that lets you develop web applications easily.
Its has a small and easy-to-extend core: its a microframework that doesnt 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

View File

@@ -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

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,12 @@
FROM registry.access.redhat.com/ubi9/go-toolset:1.19.13-4.1697647145
COPY go.mod ./
RUN go mod download
COPY *.go ./
RUN go build -o ./main
EXPOSE 8081
CMD [ "./main" , "-p=8081"]

View File

@@ -0,0 +1,41 @@
kind: Service
apiVersion: v1
metadata:
name: my-go-svc
spec:
ports:
- name: http-8081
port: 8081
protocol: TCP
targetPort: 8081
selector:
app: go-app
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: my-go
spec:
replicas: 1
selector:
matchLabels:
app: go-app
template:
metadata:
labels:
app: go-app
spec:
containers:
- name: my-go
image: go-image:latest
ports:
- name: http
containerPort: 8081
protocol: TCP
resources:
requests:
memory: "10Mi"
cpu: "10m"
limits:
memory: "100Mi"
cpu: "100m"

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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:<x.y.z>, 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

View File

@@ -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

View File

@@ -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

View File

@@ -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" ]

View File

@@ -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"

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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, its a Python module that lets you develop web applications easily.
Its has a small and easy-to-extend core: its a microframework that doesnt 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

View File

@@ -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, its a Python module that lets you develop web applications easily.
Its has a small and easy-to-extend core: its a microframework that doesnt 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

View File

@@ -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" ]

View File

@@ -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"

View File

@@ -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

View File

@@ -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))

View File

@@ -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))

View File

@@ -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

View File

@@ -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))

0
vendor/github.com/felixge/httpsnoop/.gitignore generated vendored Normal file
View File

6
vendor/github.com/felixge/httpsnoop/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,6 @@
language: go
go:
- 1.6
- 1.7
- 1.8

19
vendor/github.com/felixge/httpsnoop/LICENSE.txt generated vendored Normal file
View File

@@ -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.

10
vendor/github.com/felixge/httpsnoop/Makefile generated vendored Normal file
View File

@@ -0,0 +1,10 @@
.PHONY: ci generate clean
ci: clean generate
go test -v ./...
generate:
go generate .
clean:
rm -rf *_generated*.go

95
vendor/github.com/felixge/httpsnoop/README.md generated vendored Normal file
View File

@@ -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

86
vendor/github.com/felixge/httpsnoop/capture_metrics.go generated vendored Normal file
View File

@@ -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)
}

10
vendor/github.com/felixge/httpsnoop/docs.go generated vendored Normal file
View File

@@ -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

View File

@@ -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
}
}

View File

@@ -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
}
}

22
vendor/github.com/gorilla/handlers/LICENSE generated vendored Normal file
View File

@@ -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.

56
vendor/github.com/gorilla/handlers/README.md generated vendored Normal file
View File

@@ -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.

74
vendor/github.com/gorilla/handlers/canonical.go generated vendored Normal file
View File

@@ -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
}

143
vendor/github.com/gorilla/handlers/compress.go generated vendored Normal file
View File

@@ -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)
})
}

355
vendor/github.com/gorilla/handlers/cors.go generated vendored Normal file
View File

@@ -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
}

9
vendor/github.com/gorilla/handlers/doc.go generated vendored Normal file
View File

@@ -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

147
vendor/github.com/gorilla/handlers/handlers.go generated vendored Normal file
View File

@@ -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)
})
}

Some files were not shown because too many files have changed in this diff Show More