Compare commits

...

2 Commits

Author SHA1 Message Date
Jeff McCune
a533d4e7d9 testutil: update v1alpha6 platform1 fixture to use struct for components 2025-05-22 17:26:40 -07:00
Jeff McCune
f6c06df979 v1alpha6: define top level platform schema (#435) 2025-05-22 15:29:41 -07:00
22 changed files with 253 additions and 13 deletions

View File

@@ -1,13 +1,18 @@
{
"permissions": {
"allow": [
"Bash(cd:*)",
"Bash(make:*)",
"Bash(holos:*)",
"Bash(cue:*)",
"Bash(grep:*)",
"Bash(cd:*)",
"Bash(mkdir:*)",
"Bash(find:*)",
"Bash(echo:*)",
"Bash(head:*)",
"Bash(git commit:*)",
"Bash(git add:*)",
"Bash(make:*)"
"Bash(git add:*)"
],
"deny": []
}
}
}

View File

@@ -308,6 +308,7 @@
"sysfs",
"systemconnect",
"tablewriter",
"taskset",
"templatable",
"testscript",
"testutil",

View File

@@ -113,3 +113,4 @@ Component: #Helm & {
- Test fixtures: `/internal/testutil/fixtures/`
- Core schemas: `/api/core/` (Abstraction over low level data pipeline tasks)
- Author schemas: `/api/author/` (User facing abstractions over core Schemas)
- Task planning documents are located in the `/tasks/` directory

View File

@@ -382,6 +382,10 @@ type Command struct {
IsStdoutOutput bool `json:"isStdoutOutput,omitempty" yaml:"isStdoutOutput,omitempty"`
}
// NameLabel indicates a field name matching the name of the value. Usually the
// name or metadata.name field of the struct value.
type NameLabel string
// InternalLabel is an arbitrary unique identifier internal to holos itself.
// The holos cli is expected to never write a InternalLabel value to rendered
// output files, therefore use a InternalLabel when the identifier must be
@@ -426,7 +430,7 @@ type Platform struct {
// PlatformSpec represents the platform specification.
type PlatformSpec struct {
// Components represents a collection of holos components to manage.
Components []Component `json:"components" yaml:"components"`
Components map[NameLabel]Component `json:"components" yaml:"components" cue:"{[NAME=string]: name: NAME}"`
}
// Component represents the complete context necessary to produce a [BuildPlan]

View File

@@ -37,6 +37,7 @@ Package core contains schemas for a [Platform](<#Platform>) and [BuildPlan](<#Bu
- [type Kustomization](<#Kustomization>)
- [type Kustomize](<#Kustomize>)
- [type Metadata](<#Metadata>)
- [type NameLabel](<#NameLabel>)
- [type Platform](<#Platform>)
- [type PlatformSpec](<#PlatformSpec>)
- [type Repository](<#Repository>)
@@ -478,6 +479,15 @@ type Metadata struct {
}
```
<a name="NameLabel"></a>
## type NameLabel {#NameLabel}
NameLabel indicates a field name matching the name of the value. Usually the name or metadata.name field of the struct value.
```go
type NameLabel string
```
<a name="Platform"></a>
## type Platform {#Platform}
@@ -511,7 +521,7 @@ PlatformSpec represents the platform specification.
```go
type PlatformSpec struct {
// Components represents a collection of holos components to manage.
Components []Component `json:"components" yaml:"components"`
Components map[NameLabel]Component `json:"components" yaml:"components" cue:"{[NAME=string]: name: NAME}"`
}
```

View File

@@ -66,7 +66,7 @@ func TestShowAlpha6(t *testing.T) {
t.Run("BuildPlans", func(t *testing.T) {
t.Run("EmptyPlatform", func(t *testing.T) {
platformDir := filepath.Join(tempDir, "platform")
platformDir := filepath.Join(tempDir, "fixtures", "v1alpha6", "empty-platform")
h := newHarness()
err := h.Run(ctx, "buildplans", platformDir)
require.NoError(t, err)

View File

@@ -400,6 +400,10 @@ package core
isStdoutOutput?: bool @go(IsStdoutOutput)
}
// NameLabel indicates a field name matching the name of the value. Usually the
// name or metadata.name field of the struct value.
#NameLabel: string
// InternalLabel is an arbitrary unique identifier internal to holos itself.
// The holos cli is expected to never write a InternalLabel value to rendered
// output files, therefore use a InternalLabel when the identifier must be
@@ -448,7 +452,7 @@ package core
// PlatformSpec represents the platform specification.
#PlatformSpec: {
// Components represents a collection of holos components to manage.
components: [...#Component] @go(Components,[]Component)
components: {[string]: #Component} & {[NAME=string]: name: NAME} @go(Components,map[NameLabel]Component)
}
// Component represents the complete context necessary to produce a [BuildPlan]

View File

@@ -10,7 +10,7 @@ import (
components: _
resource: {
metadata: "name": name
spec: "components": [for x in components {x}]
spec: "components": components
}
}

View File

@@ -0,0 +1,10 @@
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
vendor/
node_modules/
tmp/

View File

@@ -0,0 +1,30 @@
package holos
// This component produces a TaskSet at the top level holos field
// The TaskSet structure is to be defined
holos: {
metadata: name: "taskset-example"
// TaskSet structure placeholder - to be defined
// This will represent the new v1alpha6 TaskSet that replaces BuildPlan
taskSet: {
// Example structure for discussion
tasks: {
// Tasks as a struct instead of list for better composition
generateManifests: {
type: "generator"
// Additional fields to be defined
}
transformManifests: {
type: "transformer"
dependsOn: ["generateManifests"]
// Additional fields to be defined
}
validateManifests: {
type: "validator"
dependsOn: ["transformManifests"]
// Additional fields to be defined
}
}
}
}

View File

@@ -0,0 +1,6 @@
@extern(embed)
package holos
import "github.com/holos-run/holos/api/core/v1alpha6:core"
holos: core.#Component @embed(file=typemeta.yaml)

View File

@@ -0,0 +1,2 @@
kind: Component
apiVersion: v1alpha6

View File

@@ -0,0 +1,17 @@
package holos
platform: spec: components: {
TaskSet1: {
name: "TaskSet1"
path: "components/taskset"
// Parameters to pass into the component.
parameters: index: "1"
// In v1alpha5 "component" was ambiguous. We disambiguate in v1alpha6 by
// naming the output of a platform component an "instance"
labels: "app.holos.run/component.instance": name
// The component the instance is derived from.
labels: "app.holos.run/component.path": path
}
}
holos: platform

View File

@@ -0,0 +1,6 @@
@extern(embed)
package holos
import "github.com/holos-run/holos/api/core/v1alpha6:core"
holos: core.#Platform @embed(file=typemeta.yaml)

View File

@@ -0,0 +1,2 @@
kind: Platform
apiVersion: v1alpha6

View File

@@ -0,0 +1,49 @@
package holos
import (
corev1 "k8s.io/api/core/v1"
appsv1 "k8s.io/api/apps/v1"
rbacv1 "k8s.io/api/rbac/v1"
batchv1 "k8s.io/api/batch/v1"
ci "cert-manager.io/clusterissuer/v1"
rgv1 "gateway.networking.k8s.io/referencegrant/v1beta1"
certv1 "cert-manager.io/certificate/v1"
hrv1 "gateway.networking.k8s.io/httproute/v1"
gwv1 "gateway.networking.k8s.io/gateway/v1"
ap "argoproj.io/appproject/v1alpha1"
es "external-secrets.io/externalsecret/v1beta1"
ss "external-secrets.io/secretstore/v1beta1"
)
#Resources: {
[Kind=string]: [InternalLabel=string]: {
kind: Kind
metadata: name: string | *InternalLabel
}
AppProject?: [_]: ap.#AppProject
Certificate?: [_]: certv1.#Certificate
ClusterIssuer?: [_]: ci.#ClusterIssuer
ClusterRole?: [_]: rbacv1.#ClusterRole
ClusterRoleBinding?: [_]: rbacv1.#ClusterRoleBinding
ConfigMap?: [_]: corev1.#ConfigMap
CronJob?: [_]: batchv1.#CronJob
Deployment?: [_]: appsv1.#Deployment
ExternalSecret?: [_]: es.#ExternalSecret
HTTPRoute?: [_]: hrv1.#HTTPRoute
Job?: [_]: batchv1.#Job
Namespace?: [_]: corev1.#Namespace
ReferenceGrant?: [_]: rgv1.#ReferenceGrant
Role?: [_]: rbacv1.#Role
RoleBinding?: [_]: rbacv1.#RoleBinding
Secret?: [_]: corev1.#Secret
SecretStore?: [_]: ss.#SecretStore
Service?: [_]: corev1.#Service
ServiceAccount?: [_]: corev1.#ServiceAccount
StatefulSet?: [_]: appsv1.#StatefulSet
Gateway?: [_]: gwv1.#Gateway & {
spec: gatewayClassName: string | *"istio"
}
}

View File

@@ -0,0 +1,37 @@
package holos
import "github.com/holos-run/holos/api/author/v1alpha6:author"
#ComponentConfig: author.#ComponentConfig & {
Name: _Tags.component.name
Path: _Tags.component.path
Resources: #Resources
// labels is an optional field, guard references to it.
if _Tags.component.labels != _|_ {
Labels: _Tags.component.labels
}
// annotations is an optional field, guard references to it.
if _Tags.component.annotations != _|_ {
Annotations: _Tags.component.annotations
}
}
// https://holos.run/docs/api/author/v1alpha6/#Kubernetes
#Kubernetes: close({
#ComponentConfig
author.#Kubernetes
})
// https://holos.run/docs/api/author/v1alpha6/#Kustomize
#Kustomize: close({
#ComponentConfig
author.#Kustomize
})
// https://holos.run/docs/api/author/v1alpha6/#Helm
#Helm: close({
#ComponentConfig
author.#Helm
})

View File

@@ -0,0 +1,34 @@
package holos
import (
"encoding/json"
"github.com/holos-run/holos/api/core/v1alpha6:core"
)
// Note: tags should have a reasonable default value for cue export.
_Tags: {
// Standardized parameters
component: core.#Component & {
name: string | *"no-name" @tag(holos_component_name, type=string)
path: string | *"no-path" @tag(holos_component_path, type=string)
_labels_json: string | *"" @tag(holos_component_labels, type=string)
_labels: {}
if _labels_json != "" {
_labels: json.Unmarshal(_labels_json)
}
for k, v in _labels {
labels: (k): v
}
_annotations_json: string | *"" @tag(holos_component_annotations, type=string)
_annotations: {}
if _annotations_json != "" {
_annotations: json.Unmarshal(_annotations_json)
}
for k, v in _annotations {
annotations: (k): v
}
}
}

View File

@@ -0,0 +1,14 @@
package holos
import "github.com/holos-run/holos/api/author/v1alpha6:author"
// holos represents the field holos render platform evaluates, the resource
// field of the author.#Platform definition constructed from a components
// struct.
holos: platform.resource
platform: author.#Platform & {
components: {
// Empty platform with no components
}
}

View File

@@ -0,0 +1,6 @@
@extern(embed)
package holos
import "github.com/holos-run/holos/api/core/v1alpha6:core"
holos: core.#Platform @embed(file=typemeta.yaml)

View File

@@ -0,0 +1,2 @@
kind: Platform
apiVersion: v1alpha6

View File

@@ -7,8 +7,8 @@ holos: {
"name": "default"
}
"spec": {
"components": [
{
"components": {
"slice": {
"annotations": {
"app.holos.run/description": "slice command transformer"
}
@@ -20,7 +20,7 @@ holos: {
"outputBaseDir": "outputBaseDir"
}
"path": "fixtures/v1alpha6/components/slice"
},
]
}
}
}
}