Skip to content

Commit

Permalink
Feature: Deployment scopes field and filter (#237)
Browse files Browse the repository at this point in the history
* deployment scopes field

Signed-off-by: Michael Valdron <mvaldron@redhat.com>

* deployment scopes validation

Signed-off-by: Michael Valdron <mvaldron@redhat.com>

* stack version deployment scopes

Signed-off-by: Michael Valdron <mvaldron@redhat.com>

* deployment scope validation test cases

Signed-off-by: Michael Valdron <mvaldron@redhat.com>

* deployment scopes and filter added to openapi spec

Signed-off-by: Michael Valdron <mvaldron@redhat.com>

* update index/generator to include deployment scope schema field

Signed-off-by: Michael Valdron <mvaldron@redhat.com>

* add deployment scopes parameter from openapi spec

Signed-off-by: Michael Valdron <mvaldron@redhat.com>

* deployment scope filter logic and test cases

Signed-off-by: Michael Valdron <mvaldron@redhat.com>

* fix naming convention of filter parameter name constants

Signed-off-by: Michael Valdron <mvaldron@redhat.com>

* add deployment scopes parameter to RESTful API docs

Signed-off-by: Michael Valdron <mvaldron@redhat.com>

* bump index/generator revision for registry library

Signed-off-by: Michael Valdron <mvaldron@redhat.com>

* go mod index server

Signed-off-by: Michael Valdron <mvaldron@redhat.com>

* bump index/generator revision for integration test suite

Signed-off-by: Michael Valdron <mvaldron@redhat.com>

---------

Signed-off-by: Michael Valdron <mvaldron@redhat.com>
  • Loading branch information
michael-valdron committed Apr 30, 2024
1 parent cca4c9a commit f77b0bf
Show file tree
Hide file tree
Showing 22 changed files with 992 additions and 265 deletions.
48 changes: 48 additions & 0 deletions index/generator/library/library.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,35 @@ func (e *IconUrlBrokenError) Error() string {
return fmt.Sprintf("Devfile %s has broken or not existing icon\n", e.devfile)
}

// InvalidDeploymentScopes error type for when deploymentScopes contains any incorrect kinds
type InvalidDeploymentScopes struct {
devfile string
deploymentScopeKind schema.DeploymentScopeKind
}

func (e *InvalidDeploymentScopes) Error() string {
return fmt.Sprintf("Deployment scope %s is incorrect for devfile %s, can only be '%s' or '%s'\n",
e.deploymentScopeKind, e.devfile, schema.InnerloopKind, schema.OuterloopKind)
}

// TooManyDeploymentScopes error type for when there are deploymentScopes set at once
type TooManyDeploymentScopes struct {
devfile string
}

func (e *TooManyDeploymentScopes) Error() string {
deploymentScopeKinds := []any{
schema.InnerloopKind,
schema.OuterloopKind,
}
params := []any{
e.devfile,
}
params = append(params, len(deploymentScopeKinds))
params = append(params, deploymentScopeKinds...)
return fmt.Sprintf("Devfile %s has too many deployment scopes, can only be %s at most, '%s' or '%s'\n", params...)
}

// GenerateIndexStruct parses registry then generates index struct according to the schema
func GenerateIndexStruct(registryDirPath string, force bool) ([]schema.Schema, error) {
// Parse devfile registry then populate index struct
Expand Down Expand Up @@ -193,6 +222,25 @@ func validateIndexComponent(indexComponent schema.Schema, componentType schema.D
if len(indexComponent.Architectures) == 0 {
return &MissingArchError{devfile: indexComponent.Name}
}
if len(indexComponent.DeploymentScopes) > 2 {
return &TooManyDeploymentScopes{devfile: indexComponent.Name}
}
for kind := range indexComponent.DeploymentScopes {
if kind != schema.InnerloopKind && kind != schema.OuterloopKind {
return &InvalidDeploymentScopes{devfile: indexComponent.Name, deploymentScopeKind: kind}
}
}
for _, version := range indexComponent.Versions {
if len(version.DeploymentScopes) > 2 {
return &TooManyDeploymentScopes{devfile: indexComponent.Name}
}

for kind := range version.DeploymentScopes {
if kind != schema.InnerloopKind && kind != schema.OuterloopKind {
return &InvalidDeploymentScopes{devfile: indexComponent.Name, deploymentScopeKind: kind}
}
}
}

return nil
}
Expand Down
126 changes: 126 additions & 0 deletions index/generator/library/library_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ func TestValidateIndexComponent(t *testing.T) {
schemaVersionEmptyErr := ".*schema version is empty.*"
multipleVersionErr := ".*has multiple default versions.*"
iconUrlBrokenErr := ".*has broken or not existing icon.*"
invalidDeploymentScopeErr := ".*Deployment scope \\S+ is incorrect for devfile \\S+.*"
tooManyDeploymentScopesErr := ".*has too many deployment scopes.*"

tests := []struct {
name string
Expand Down Expand Up @@ -530,6 +532,130 @@ func TestValidateIndexComponent(t *testing.T) {
schema.StackDevfileType,
&iconUrlBrokenErr,
},
{
name: "Case 23: deployment scope has invalid kind",
indexComponent: schema.Schema{
Name: "java-maven",
Icon: "https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/java-maven.jpg",
Provider: "Red Hat",
SupportUrl: "https://devfile.io",
Architectures: []string{
"amd64",
},
Versions: []schema.Version{
{
Version: "1.0.0",
SchemaVersion: "2.0.0",
Default: true,
Links: map[string]string{
"self": "devfile-catalog/java-maven:latest",
},
Resources: []string{
"devfile.yaml",
},
},
},
DeploymentScopes: map[schema.DeploymentScopeKind]bool{
"foo": true,
},
},
componentType: schema.StackDevfileType,
wantErr: &invalidDeploymentScopeErr,
},
{
name: "Case 24: deployment scope has invalid kind",
indexComponent: schema.Schema{
Name: "java-maven",
Icon: "https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/java-maven.jpg",
Provider: "Red Hat",
SupportUrl: "https://devfile.io",
Architectures: []string{
"amd64",
},
Versions: []schema.Version{
{
Version: "1.0.0",
SchemaVersion: "2.0.0",
Default: true,
Links: map[string]string{
"self": "devfile-catalog/java-maven:latest",
},
Resources: []string{
"devfile.yaml",
},
},
},
DeploymentScopes: map[schema.DeploymentScopeKind]bool{
schema.InnerloopKind: true,
schema.OuterloopKind: false,
"foo": false,
},
},
componentType: schema.StackDevfileType,
wantErr: &tooManyDeploymentScopesErr,
},
{
name: "Case 25: version deployment scope has invalid kind",
indexComponent: schema.Schema{
Name: "java-maven",
Icon: "https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/java-maven.jpg",
Provider: "Red Hat",
SupportUrl: "https://devfile.io",
Architectures: []string{
"amd64",
},
Versions: []schema.Version{
{
Version: "1.0.0",
SchemaVersion: "2.0.0",
Default: true,
Links: map[string]string{
"self": "devfile-catalog/java-maven:latest",
},
Resources: []string{
"devfile.yaml",
},
DeploymentScopes: map[schema.DeploymentScopeKind]bool{
"foo": true,
},
},
},
},
componentType: schema.StackDevfileType,
wantErr: &invalidDeploymentScopeErr,
},
{
name: "Case 26: version deployment scope has invalid kind",
indexComponent: schema.Schema{
Name: "java-maven",
Icon: "https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/java-maven.jpg",
Provider: "Red Hat",
SupportUrl: "https://devfile.io",
Architectures: []string{
"amd64",
},
Versions: []schema.Version{
{
Version: "1.0.0",
SchemaVersion: "2.0.0",
Default: true,
Links: map[string]string{
"self": "devfile-catalog/java-maven:latest",
},
Resources: []string{
"devfile.yaml",
},
DeploymentScopes: map[schema.DeploymentScopeKind]bool{
schema.InnerloopKind: true,
schema.OuterloopKind: false,
"foo": false,
},
},
},
},
componentType: schema.StackDevfileType,
wantErr: &tooManyDeploymentScopesErr,
},
}

for _, tt := range tests {
Expand Down
75 changes: 43 additions & 32 deletions index/generator/schema/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ projectType: string - The project framework that is used in the devfile
language: string - The project language that is used in the devfile
links: map[string]string - Links related to the devfile
commandGroups: map[CommandGroupKind]bool - The command groups that are used in the devfile
deploymentScopes: map[DeploymentScopeKind]bool - The deployment scope that are detected in the devfile
resources: []string - The file resources that compose a devfile stack.
starterProjects: string[] - The project templates that can be used in the devfile
git: *git - The information of remote repositories
Expand All @@ -139,26 +140,27 @@ versions: []Version - The list of stack versions information

// Schema is the index file schema
type Schema struct {
Name string `yaml:"name,omitempty" json:"name,omitempty"`
Version string `yaml:"version,omitempty" json:"version,omitempty"`
Attributes map[string]apiext.JSON `yaml:"attributes,omitempty" json:"attributes,omitempty"`
DisplayName string `yaml:"displayName,omitempty" json:"displayName,omitempty"`
Description string `yaml:"description,omitempty" json:"description,omitempty"`
Type DevfileType `yaml:"type,omitempty" json:"type,omitempty"`
Tags []string `yaml:"tags,omitempty" json:"tags,omitempty"`
Architectures []string `yaml:"architectures,omitempty" json:"architectures,omitempty"`
Icon string `yaml:"icon,omitempty" json:"icon,omitempty"`
GlobalMemoryLimit string `yaml:"globalMemoryLimit,omitempty" json:"globalMemoryLimit,omitempty"`
ProjectType string `yaml:"projectType,omitempty" json:"projectType,omitempty"`
Language string `yaml:"language,omitempty" json:"language,omitempty"`
Links map[string]string `yaml:"links,omitempty" json:"links,omitempty"`
CommandGroups map[CommandGroupKind]bool `yaml:"commandGroups,omitempty" json:"commandGroups,omitempty"`
Resources []string `yaml:"resources,omitempty" json:"resources,omitempty"`
StarterProjects []string `yaml:"starterProjects,omitempty" json:"starterProjects,omitempty"`
Git *Git `yaml:"git,omitempty" json:"git,omitempty"`
Provider string `yaml:"provider,omitempty" json:"provider,omitempty"`
SupportUrl string `yaml:"supportUrl,omitempty" json:"supportUrl,omitempty"`
Versions []Version `yaml:"versions,omitempty" json:"versions,omitempty"`
Name string `yaml:"name,omitempty" json:"name,omitempty"`
Version string `yaml:"version,omitempty" json:"version,omitempty"`
Attributes map[string]apiext.JSON `yaml:"attributes,omitempty" json:"attributes,omitempty"`
DisplayName string `yaml:"displayName,omitempty" json:"displayName,omitempty"`
Description string `yaml:"description,omitempty" json:"description,omitempty"`
Type DevfileType `yaml:"type,omitempty" json:"type,omitempty"`
Tags []string `yaml:"tags,omitempty" json:"tags,omitempty"`
Architectures []string `yaml:"architectures,omitempty" json:"architectures,omitempty"`
Icon string `yaml:"icon,omitempty" json:"icon,omitempty"`
GlobalMemoryLimit string `yaml:"globalMemoryLimit,omitempty" json:"globalMemoryLimit,omitempty"`
ProjectType string `yaml:"projectType,omitempty" json:"projectType,omitempty"`
Language string `yaml:"language,omitempty" json:"language,omitempty"`
Links map[string]string `yaml:"links,omitempty" json:"links,omitempty"`
CommandGroups map[CommandGroupKind]bool `yaml:"commandGroups,omitempty" json:"commandGroups,omitempty"`
DeploymentScopes map[DeploymentScopeKind]bool `yaml:"deploymentScopes,omitempty" json:"deploymentScopes,omitempty"`
Resources []string `yaml:"resources,omitempty" json:"resources,omitempty"`
StarterProjects []string `yaml:"starterProjects,omitempty" json:"starterProjects,omitempty"`
Git *Git `yaml:"git,omitempty" json:"git,omitempty"`
Provider string `yaml:"provider,omitempty" json:"provider,omitempty"`
SupportUrl string `yaml:"supportUrl,omitempty" json:"supportUrl,omitempty"`
Versions []Version `yaml:"versions,omitempty" json:"versions,omitempty"`
}

// DevfileType describes the type of devfile
Expand All @@ -183,6 +185,14 @@ const (
DeployCommandGroupKind CommandGroupKind = "deploy"
)

// DeploymentScopeKind describes the kind of deployment scope
type DeploymentScopeKind string

const (
InnerloopKind DeploymentScopeKind = "innerloop"
OuterloopKind DeploymentScopeKind = "outerloop"
)

// StarterProject is the devfile starter project
type StarterProject struct {
Name string `yaml:"name,omitempty" json:"name,omitempty"`
Expand Down Expand Up @@ -241,16 +251,17 @@ type StackInfo struct {

// Version stores the information for each stack version
type Version struct {
Version string `yaml:"version,omitempty" json:"version,omitempty"`
SchemaVersion string `yaml:"schemaVersion,omitempty" json:"schemaVersion,omitempty"`
Default bool `yaml:"default,omitempty" json:"default,omitempty"`
Git *Git `yaml:"git,omitempty" json:"git,omitempty"`
Description string `yaml:"description,omitempty" json:"description,omitempty"`
Tags []string `yaml:"tags,omitempty" json:"tags,omitempty"`
Architectures []string `yaml:"architectures,omitempty" json:"architectures,omitempty"`
Icon string `yaml:"icon,omitempty" json:"icon,omitempty"`
Links map[string]string `yaml:"links,omitempty" json:"links,omitempty"`
CommandGroups map[CommandGroupKind]bool `yaml:"commandGroups,omitempty" json:"commandGroups,omitempty"`
Resources []string `yaml:"resources,omitempty" json:"resources,omitempty"`
StarterProjects []string `yaml:"starterProjects,omitempty" json:"starterProjects,omitempty"`
Version string `yaml:"version,omitempty" json:"version,omitempty"`
SchemaVersion string `yaml:"schemaVersion,omitempty" json:"schemaVersion,omitempty"`
Default bool `yaml:"default,omitempty" json:"default,omitempty"`
Git *Git `yaml:"git,omitempty" json:"git,omitempty"`
Description string `yaml:"description,omitempty" json:"description,omitempty"`
Tags []string `yaml:"tags,omitempty" json:"tags,omitempty"`
Architectures []string `yaml:"architectures,omitempty" json:"architectures,omitempty"`
Icon string `yaml:"icon,omitempty" json:"icon,omitempty"`
Links map[string]string `yaml:"links,omitempty" json:"links,omitempty"`
CommandGroups map[CommandGroupKind]bool `yaml:"commandGroups,omitempty" json:"commandGroups,omitempty"`
DeploymentScopes map[DeploymentScopeKind]bool `yaml:"deploymentScopes,omitempty" json:"deploymentScopes,omitempty"`
Resources []string `yaml:"resources,omitempty" json:"resources,omitempty"`
StarterProjects []string `yaml:"starterProjects,omitempty" json:"starterProjects,omitempty"`
}
1 change: 1 addition & 0 deletions index/server/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ require (
go.opentelemetry.io/otel v1.24.0 // indirect
go.opentelemetry.io/otel/metric v1.24.0 // indirect
go.opentelemetry.io/otel/trace v1.24.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/mod v0.16.0 // indirect
Expand Down
3 changes: 2 additions & 1 deletion index/server/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,8 @@ go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGX
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU=
Expand Down
22 changes: 22 additions & 0 deletions index/server/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ paths:
- $ref: '#/components/parameters/linkNamesParam'
- $ref: '#/components/parameters/linksParam'
- $ref: '#/components/parameters/commandGroupsParam'
- $ref: '#/components/parameters/deploymentScopesParam'
- $ref: '#/components/parameters/gitRemoteNamesParam'
- $ref: '#/components/parameters/gitRemotesParam'
- $ref: '#/components/parameters/gitUrlParam'
Expand Down Expand Up @@ -339,6 +340,7 @@ paths:
- $ref: '#/components/parameters/linkNamesParam'
- $ref: '#/components/parameters/linksParam'
- $ref: '#/components/parameters/commandGroupsParam'
- $ref: '#/components/parameters/deploymentScopesParam'
- $ref: '#/components/parameters/gitRemoteNamesParam'
- $ref: '#/components/parameters/gitRemotesParam'
- $ref: '#/components/parameters/gitUrlParam'
Expand Down Expand Up @@ -860,6 +862,8 @@ components:
$ref: '#/components/schemas/Links'
commandGroups:
$ref: '#/components/schemas/CommandGroups'
deploymentScopes:
$ref: '#/components/schemas/DeploymentScopes'
gitRemoteNames:
$ref: '#/components/schemas/GitRemoteNames'
gitRemotes:
Expand Down Expand Up @@ -979,6 +983,15 @@ components:
- test
- debug
- deploy
DeploymentScopes:
description: List of deployment scopes that are detected in the devfile
type: array
uniqueItems: true
items:
type: string
enum:
- innerloop
- outerloop
GitRemoteName:
description: Git repository remote name
type: string
Expand Down Expand Up @@ -1167,6 +1180,15 @@ components:
groups
schema:
$ref: '#/components/schemas/CommandGroups'
deploymentScopesParam:
name: deploymentScopes
in: query
required: false
description: |-
Collection of search strings to filter stacks by their present deployment
scopes
schema:
$ref: '#/components/schemas/DeploymentScopes'
gitRemoteNamesParam:
name: gitRemoteNames
in: query
Expand Down
Loading

0 comments on commit f77b0bf

Please sign in to comment.