mirror of https://github.com/kubevela/kubevela.git
Compare commits
2 Commits
089f657b0c
...
2a31930c4b
| Author | SHA1 | Date |
|---|---|---|
|
|
2a31930c4b | |
|
|
8e3749f970 |
|
|
@ -97,6 +97,21 @@ jobs:
|
|||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Free Disk Space
|
||||
run: |
|
||||
echo "Disk space before cleanup:"
|
||||
df -h
|
||||
|
||||
# Remove unnecessary software to free up disk space
|
||||
sudo rm -rf /usr/share/dotnet
|
||||
sudo rm -rf /usr/local/lib/android
|
||||
sudo rm -rf /opt/ghc
|
||||
sudo rm -rf /opt/hostedtoolcache/CodeQL
|
||||
sudo docker image prune --all --force
|
||||
|
||||
echo "Disk space after cleanup:"
|
||||
df -h
|
||||
|
||||
- name: Setup Env
|
||||
uses: ./.github/actions/env-setup
|
||||
|
||||
|
|
@ -111,6 +126,24 @@ jobs:
|
|||
- name: Run cross-build
|
||||
run: make cross-build
|
||||
|
||||
- name: Free Disk Space After Cross-Build
|
||||
run: |
|
||||
echo "Disk space before cleanup:"
|
||||
df -h
|
||||
|
||||
# Remove cross-build artifacts to free up space
|
||||
# (make build will rebuild binaries for current platform)
|
||||
rm -rf _bin
|
||||
|
||||
# Clean Go build cache and test cache
|
||||
go clean -cache -testcache
|
||||
|
||||
# Remove Docker build cache
|
||||
sudo docker builder prune --all --force || true
|
||||
|
||||
echo "Disk space after cleanup:"
|
||||
df -h
|
||||
|
||||
- name: Check Diff
|
||||
run: |
|
||||
export PATH=$(pwd)/bin/:$PATH
|
||||
|
|
|
|||
6
Makefile
6
Makefile
|
|
@ -64,8 +64,8 @@ lint: golangci
|
|||
@GOLANGCILINT=$(GOLANGCILINT) ./hack/utils/golangci-lint-wrapper.sh
|
||||
|
||||
## reviewable: Run the reviewable
|
||||
reviewable: manifests fmt vet lint staticcheck helm-doc-gen sdk_fmt
|
||||
go mod tidy
|
||||
## Run make build to compile vela binary before running this target to ensure all generated definitions are up to date.
|
||||
reviewable: build manifests fmt vet lint staticcheck helm-doc-gen sdk_fmt
|
||||
|
||||
# check-diff: Execute auto-gen code commands and ensure branch is clean.
|
||||
check-diff: reviewable
|
||||
|
|
@ -103,7 +103,7 @@ manager:
|
|||
$(GOBUILD_ENV) go build -o bin/manager -a -ldflags $(LDFLAGS) ./cmd/core/main.go
|
||||
|
||||
## manifests: Generate manifests e.g. CRD, RBAC etc.
|
||||
manifests: installcue kustomize
|
||||
manifests: tidy installcue kustomize sync-crds
|
||||
go generate $(foreach t,pkg apis,./$(t)/...)
|
||||
# TODO(yangsoon): kustomize will merge all CRD into a whole file, it may not work if we want patch more than one CRD in this way
|
||||
$(KUSTOMIZE) build config/crd -o config/crd/base/core.oam.dev_applications.yaml
|
||||
|
|
|
|||
|
|
@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
|||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.9.0
|
||||
creationTimestamp: null
|
||||
controller-gen.kubebuilder.io/version: v0.16.5
|
||||
name: workflows.core.oam.dev
|
||||
spec:
|
||||
group: core.oam.dev
|
||||
|
|
@ -23,14 +22,19 @@ spec:
|
|||
description: Workflow is the Schema for the workflow API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
|
|
@ -59,6 +63,7 @@ spec:
|
|||
inputs:
|
||||
description: Inputs is the inputs of the step
|
||||
items:
|
||||
description: InputItem defines an input variable of WorkflowStep
|
||||
properties:
|
||||
from:
|
||||
type: string
|
||||
|
|
@ -66,7 +71,6 @@ spec:
|
|||
type: string
|
||||
required:
|
||||
- from
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
|
|
@ -75,12 +79,18 @@ spec:
|
|||
alias:
|
||||
type: string
|
||||
type: object
|
||||
mode:
|
||||
description: Mode is only valid for sub steps, it defines the mode
|
||||
of the sub steps
|
||||
nullable: true
|
||||
type: string
|
||||
name:
|
||||
description: Name is the unique name of the workflow step.
|
||||
type: string
|
||||
outputs:
|
||||
description: Outputs is the outputs of the step
|
||||
items:
|
||||
description: OutputItem defines an output variable of WorkflowStep
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
|
|
@ -110,6 +120,7 @@ spec:
|
|||
inputs:
|
||||
description: Inputs is the inputs of the step
|
||||
items:
|
||||
description: InputItem defines an input variable of WorkflowStep
|
||||
properties:
|
||||
from:
|
||||
type: string
|
||||
|
|
@ -117,7 +128,6 @@ spec:
|
|||
type: string
|
||||
required:
|
||||
- from
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
|
|
@ -132,6 +142,7 @@ spec:
|
|||
outputs:
|
||||
description: Outputs is the outputs of the step
|
||||
items:
|
||||
description: OutputItem defines an output variable of WorkflowStep
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
|
|
@ -153,7 +164,6 @@ spec:
|
|||
description: Type is the type of the workflow step.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
|
|
@ -164,7 +174,6 @@ spec:
|
|||
description: Type is the type of the workflow step.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
|
|
|
|||
6
go.mod
6
go.mod
|
|
@ -37,8 +37,8 @@ require (
|
|||
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174
|
||||
github.com/imdario/mergo v0.3.16
|
||||
github.com/jeremywohl/flatten/v2 v2.0.0-20211013061545-07e4a09fb8e4
|
||||
github.com/kubevela/pkg v1.9.3-0.20251007211343-a91fd1f290c6
|
||||
github.com/kubevela/workflow v0.6.3-0.20251007211423-415593c3cee0
|
||||
github.com/kubevela/pkg v1.9.3-0.20251015050342-14cd204ff6fc
|
||||
github.com/kubevela/workflow v0.6.3-0.20250717221743-56b80cee4121
|
||||
github.com/kyokomi/emoji v2.2.4+incompatible
|
||||
github.com/magiconair/properties v1.8.7
|
||||
github.com/mattn/go-runewidth v0.0.15
|
||||
|
|
@ -280,7 +280,7 @@ require (
|
|||
golang.org/x/net v0.42.0 // indirect
|
||||
golang.org/x/sys v0.34.0 // indirect
|
||||
golang.org/x/time v0.10.0 // indirect
|
||||
golang.org/x/tools/go/expect v0.1.0-deprecated // indirect
|
||||
golang.org/x/tools/go/expect v0.1.1-deprecated // indirect
|
||||
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect
|
||||
|
|
|
|||
12
go.sum
12
go.sum
|
|
@ -476,10 +476,10 @@ github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
|||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kubevela/pkg v1.9.3-0.20251007211343-a91fd1f290c6 h1:7REKNm1RC8pcvkYKyTD+mRMWp10+Jdkv/YqL/LE6VSE=
|
||||
github.com/kubevela/pkg v1.9.3-0.20251007211343-a91fd1f290c6/go.mod h1:P5FmkdwbXKt42LOhR0oMfMiQffYYKie9s2mLDJaPzjc=
|
||||
github.com/kubevela/workflow v0.6.3-0.20251007211423-415593c3cee0 h1:23CTZ0d7/KOB1TH52E+dvzKkp5vCMcrqGyyGLOelb9c=
|
||||
github.com/kubevela/workflow v0.6.3-0.20251007211423-415593c3cee0/go.mod h1:8mZrIj+6Oe08ikz/IpvGFTB/WzP2stwb8G6M01TCqac=
|
||||
github.com/kubevela/pkg v1.9.3-0.20251015050342-14cd204ff6fc h1:nuXTUQRQDJORMopbRD1fV4iwKT43MWgvMERM9YnrSPk=
|
||||
github.com/kubevela/pkg v1.9.3-0.20251015050342-14cd204ff6fc/go.mod h1:EmM4VIyU7KxDmPBq9hG4GpSZbGwiM76/W/8paLBk8wY=
|
||||
github.com/kubevela/workflow v0.6.3-0.20250717221743-56b80cee4121 h1:clU2P7FyrhLm1l/xviiLO1Cen00ZI01oOfPxAOoMi0w=
|
||||
github.com/kubevela/workflow v0.6.3-0.20250717221743-56b80cee4121/go.mod h1:79KSLzfgBnJboWgxy5P/1GCc2ZUOLEYlF+vS4xQ3FNo=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/kyokomi/emoji v2.2.4+incompatible h1:np0woGKwx9LiHAQmwZx79Oc0rHpNw3o+3evou4BEPv4=
|
||||
|
|
@ -968,8 +968,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
|||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0=
|
||||
golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
|
||||
golang.org/x/tools/go/expect v0.1.0-deprecated h1:jY2C5HGYR5lqex3gEniOQL0r7Dq5+VGVgY1nudX5lXY=
|
||||
golang.org/x/tools/go/expect v0.1.0-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY=
|
||||
golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM=
|
||||
golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY=
|
||||
golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM=
|
||||
golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGNv1ib0J382/DPCRS/BPnsGebyM1Gj5VSDpG8=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
|
|
|||
|
|
@ -47,4 +47,7 @@ VELA_CLI_IMAGE ?= oamdev/vela-cli:latest
|
|||
VELA_CORE_TEST_IMAGE ?= vela-core-test:$(GIT_COMMIT)
|
||||
VELA_APISERVER_IMAGE ?= apiserver:latest
|
||||
RUNTIME_CLUSTER_CONFIG ?= /tmp/worker.client.kubeconfig
|
||||
RUNTIME_CLUSTER_NAME ?= worker
|
||||
RUNTIME_CLUSTER_NAME ?= worker
|
||||
|
||||
COMMON_CRD_FILES = \
|
||||
core.oam.dev_workflows.yaml
|
||||
|
|
@ -98,3 +98,17 @@ endif
|
|||
envtest: $(ENVTEST) ## Download envtest-setup locally if necessary.
|
||||
$(ENVTEST): $(LOCALBIN)
|
||||
GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest
|
||||
|
||||
.PHONY: tidy
|
||||
tidy:
|
||||
go mod tidy
|
||||
|
||||
.PHONY: sync-crds
|
||||
PKG_MODULE = github.com/kubevela/pkg # fetch common crds from the pkg repo instead of generating locally
|
||||
sync-crds: ## Copy CRD from pinned module version in go.mod
|
||||
@moddir=$$(go list -m -f '{{.Dir}}' $(PKG_MODULE) 2>/dev/null); \
|
||||
mkdir -p config/crd/base; \
|
||||
for file in $(COMMON_CRD_FILES); do \
|
||||
src="$$moddir/crds/$$file"; \
|
||||
cp -f "$$src" "config/crd/base/"; \
|
||||
done
|
||||
|
|
@ -30,6 +30,7 @@ import (
|
|||
"github.com/kubevela/workflow/pkg/cue/model/value"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/builtin/registry"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
|
@ -152,7 +153,7 @@ func parseHeaders(obj cue.Value, label string) (http.Header, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h.Add(iter.Selector().Unquoted(), str)
|
||||
h.Add(util.GetIteratorLabel(*iter), str)
|
||||
}
|
||||
return h, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import (
|
|||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/cue/process"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
)
|
||||
|
||||
// ErrParameterNotExist represents the parameter field is not exist in CUE template
|
||||
|
|
@ -47,9 +48,8 @@ func GetParameters(templateStr string) ([]types.Parameter, error) {
|
|||
if iter.Selector().IsDefinition() {
|
||||
continue
|
||||
}
|
||||
name := GetSelectorLabel(iter.Selector())
|
||||
var param = types.Parameter{
|
||||
Name: name,
|
||||
Name: util.GetIteratorLabel(*iter),
|
||||
Required: !iter.IsOptional(),
|
||||
}
|
||||
val := iter.Value()
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
velacue "github.com/oam-dev/kubevela/pkg/cue"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -145,8 +145,7 @@ func getStatusMap(templateContext map[string]interface{}, statusFields string, p
|
|||
return templateContext, nil, errors.WithMessage(err, "get context fields")
|
||||
}
|
||||
for iter.Next() {
|
||||
label := velacue.GetSelectorLabel(iter.Selector())
|
||||
contextLabels = append(contextLabels, label)
|
||||
contextLabels = append(contextLabels, util.GetIteratorLabel(*iter))
|
||||
}
|
||||
|
||||
cueBuffer := runtimeContextBuff + "\n" + statusFields
|
||||
|
|
@ -163,7 +162,7 @@ func getStatusMap(templateContext map[string]interface{}, statusFields string, p
|
|||
|
||||
outer:
|
||||
for iter.Next() {
|
||||
label := velacue.GetSelectorLabel(iter.Selector())
|
||||
label := util.GetIteratorLabel(*iter)
|
||||
|
||||
if len(label) >= 32 {
|
||||
klog.Warningf("status.details field label %s is too long, skipping", label)
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ import (
|
|||
"github.com/kubevela/workflow/pkg/cue/model/value"
|
||||
"github.com/kubevela/workflow/pkg/cue/process"
|
||||
|
||||
velacue "github.com/oam-dev/kubevela/pkg/cue"
|
||||
velaprocess "github.com/oam-dev/kubevela/pkg/cue/process"
|
||||
"github.com/oam-dev/kubevela/pkg/cue/task"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
|
|
@ -140,7 +139,7 @@ func (wd *workloadDef) Complete(ctx process.Context, abstractTemplate string, pa
|
|||
continue
|
||||
}
|
||||
other, err := model.NewOther(iter.Value())
|
||||
name := velacue.GetSelectorLabel(iter.Selector())
|
||||
name := util.GetIteratorLabel(*iter)
|
||||
if err != nil {
|
||||
return errors.WithMessagef(err, "invalid outputs(%s) of workload %s", name, wd.name)
|
||||
}
|
||||
|
|
@ -273,7 +272,7 @@ func (td *traitDef) Complete(ctx process.Context, abstractTemplate string, param
|
|||
continue
|
||||
}
|
||||
other, err := model.NewOther(iter.Value())
|
||||
name := velacue.GetSelectorLabel(iter.Selector())
|
||||
name := util.GetIteratorLabel(*iter)
|
||||
if err != nil {
|
||||
return errors.WithMessagef(err, "invalid outputs(resource=%s) of trait %s", name, td.name)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ import (
|
|||
"strings"
|
||||
|
||||
"cuelang.org/go/cue/ast"
|
||||
"cuelang.org/go/cue/parser"
|
||||
"cuelang.org/go/cue/token"
|
||||
)
|
||||
|
||||
|
|
@ -111,14 +110,15 @@ func unmarshalField[T ast.Node](field *ast.Field, key string, validator func(T)
|
|||
}
|
||||
|
||||
unquoted := strings.TrimSpace(TrimCueRawString(basicLit.Value))
|
||||
expr, err := parser.ParseExpr("-", WrapCueStruct(unquoted))
|
||||
if err != nil {
|
||||
return fmt.Errorf("unexpected error re-parsing validated %s string: %w", key, err)
|
||||
|
||||
structLit, hasImports, hasPackage, parseErr := ParseCueContent(unquoted)
|
||||
if parseErr != nil {
|
||||
return fmt.Errorf("unexpected error re-parsing validated %s string: %w", key, parseErr)
|
||||
}
|
||||
|
||||
structLit, ok := expr.(*ast.StructLit)
|
||||
if !ok {
|
||||
return fmt.Errorf("expected struct after validation in field %s", key)
|
||||
if hasImports || hasPackage {
|
||||
// Keep as string literal to preserve imports/package
|
||||
return nil
|
||||
}
|
||||
|
||||
statusField.Value = structLit
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import (
|
|||
"cuelang.org/go/cue/ast"
|
||||
"cuelang.org/go/cue/format"
|
||||
"cuelang.org/go/cue/parser"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
|
@ -176,6 +177,50 @@ func TestMarshalAndUnmarshalMetadata(t *testing.T) {
|
|||
`,
|
||||
expectContains: "$local",
|
||||
},
|
||||
{
|
||||
name: "status details with import statement should work",
|
||||
input: `
|
||||
attributes: {
|
||||
status: {
|
||||
details: #"""
|
||||
import "strconv"
|
||||
replicas: strconv.Atoi(context.output.status.replicas)
|
||||
"""#
|
||||
}
|
||||
}
|
||||
`,
|
||||
expectContains: "import \"strconv\"",
|
||||
},
|
||||
{
|
||||
name: "status details with package declaration",
|
||||
input: `
|
||||
attributes: {
|
||||
status: {
|
||||
details: #"""
|
||||
package status
|
||||
|
||||
ready: true
|
||||
phase: "Running"
|
||||
"""#
|
||||
}
|
||||
}
|
||||
`,
|
||||
expectContains: "package status",
|
||||
},
|
||||
{
|
||||
name: "status details with import cannot bypass validation",
|
||||
input: `
|
||||
attributes: {
|
||||
status: {
|
||||
details: #"""
|
||||
import "strings"
|
||||
data: { nested: "structure" }
|
||||
"""#
|
||||
}
|
||||
}
|
||||
`,
|
||||
expectMarshalErr: "unsupported expression type",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
|
@ -379,6 +424,21 @@ func TestMarshalAndUnmarshalHealthPolicy(t *testing.T) {
|
|||
`,
|
||||
expectContains: "isHealth",
|
||||
},
|
||||
{
|
||||
name: "healthPolicy with package declaration",
|
||||
input: `
|
||||
attributes: {
|
||||
status: {
|
||||
healthPolicy: #"""
|
||||
package health
|
||||
|
||||
isHealth: context.output.status.phase == "Running"
|
||||
"""#
|
||||
}
|
||||
}
|
||||
`,
|
||||
expectContains: "package health",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
|
@ -610,6 +670,96 @@ func TestMarshalAndUnmarshalCustomStatus(t *testing.T) {
|
|||
`,
|
||||
expectContains: "message",
|
||||
},
|
||||
{
|
||||
name: "customStatus with import statement should work",
|
||||
input: `
|
||||
attributes: {
|
||||
status: {
|
||||
customStatus: #"""
|
||||
import "strings"
|
||||
message: strings.Join(["hello", "world"], ",")
|
||||
"""#
|
||||
}
|
||||
}
|
||||
`,
|
||||
expectContains: "import \"strings\"",
|
||||
},
|
||||
{
|
||||
name: "customStatus with multiple imports",
|
||||
input: `
|
||||
attributes: {
|
||||
status: {
|
||||
customStatus: #"""
|
||||
import "strings"
|
||||
import "strconv"
|
||||
count: strconv.Atoi("42")
|
||||
message: strings.Join(["Count", strconv.FormatInt(count, 10)], ": ")
|
||||
"""#
|
||||
}
|
||||
}
|
||||
`,
|
||||
expectContains: "import \"strconv\"",
|
||||
},
|
||||
{
|
||||
name: "customStatus with import alias",
|
||||
input: `
|
||||
attributes: {
|
||||
status: {
|
||||
customStatus: #"""
|
||||
import str "strings"
|
||||
message: str.ToUpper(str.Join(["hello", "world"], " "))
|
||||
"""#
|
||||
}
|
||||
}
|
||||
`,
|
||||
expectContains: "import str \"strings\"",
|
||||
},
|
||||
{
|
||||
name: "customStatus with package declaration",
|
||||
input: `
|
||||
attributes: {
|
||||
status: {
|
||||
customStatus: #"""
|
||||
package mytest
|
||||
|
||||
message: "Package test"
|
||||
"""#
|
||||
}
|
||||
}
|
||||
`,
|
||||
expectContains: "package mytest",
|
||||
},
|
||||
{
|
||||
name: "customStatus with package and imports",
|
||||
input: `
|
||||
attributes: {
|
||||
status: {
|
||||
customStatus: #"""
|
||||
package mytest
|
||||
|
||||
import "strings"
|
||||
|
||||
message: strings.ToUpper("hello world")
|
||||
"""#
|
||||
}
|
||||
}
|
||||
`,
|
||||
expectContains: "package mytest",
|
||||
},
|
||||
{
|
||||
name: "customStatus with import still requires message field",
|
||||
input: `
|
||||
attributes: {
|
||||
status: {
|
||||
customStatus: #"""
|
||||
import "strings"
|
||||
someOtherField: "value"
|
||||
"""#
|
||||
}
|
||||
}
|
||||
`,
|
||||
expectMarshalErr: "customStatus must contain a 'message' field",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
|
@ -951,6 +1101,57 @@ func TestCustomStatusEdgeCases(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestMixedFieldsWithAndWithoutImports(t *testing.T) {
|
||||
input := `
|
||||
attributes: {
|
||||
status: {
|
||||
healthPolicy: #"""
|
||||
isHealth: context.output.status.phase == "Running"
|
||||
"""#
|
||||
customStatus: #"""
|
||||
import "strings"
|
||||
message: strings.ToLower(context.output.status.phase)
|
||||
"""#
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
file, err := parser.ParseFile("-", input)
|
||||
require.NoError(t, err)
|
||||
|
||||
var rootField *ast.Field
|
||||
for _, decl := range file.Decls {
|
||||
if f, ok := decl.(*ast.Field); ok {
|
||||
rootField = f
|
||||
break
|
||||
}
|
||||
}
|
||||
require.NotNil(t, rootField)
|
||||
|
||||
// Encode (struct -> string)
|
||||
err = EncodeMetadata(rootField)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Decode (string -> struct/string based on imports)
|
||||
err = DecodeMetadata(rootField)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Check healthPolicy (no imports) - should be decoded to struct
|
||||
healthField, ok := GetFieldByPath(rootField, "attributes.status.healthPolicy")
|
||||
require.True(t, ok)
|
||||
_, isStruct := healthField.Value.(*ast.StructLit)
|
||||
assert.True(t, isStruct, "healthPolicy without imports should be decoded to struct")
|
||||
|
||||
// Check customStatus (has imports) - should remain as string
|
||||
customField, ok := GetFieldByPath(rootField, "attributes.status.customStatus")
|
||||
require.True(t, ok)
|
||||
basicLit, isString := customField.Value.(*ast.BasicLit)
|
||||
assert.True(t, isString, "customStatus with imports should remain as string")
|
||||
if isString {
|
||||
assert.Contains(t, basicLit.Value, "import \"strings\"")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBackwardCompatibility(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
|
|
|||
|
|
@ -152,18 +152,15 @@ func ValidateCueStringLiteral[T ast.Node](lit *ast.BasicLit, validator func(T) e
|
|||
return nil
|
||||
}
|
||||
|
||||
wrapped := WrapCueStruct(raw)
|
||||
|
||||
expr, err := parser.ParseExpr("-", wrapped)
|
||||
structLit, _, _, err := ParseCueContent(raw)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid cue content in string literal: %w", err)
|
||||
}
|
||||
|
||||
node, ok := expr.(T)
|
||||
node, ok := ast.Node(structLit).(T)
|
||||
if !ok {
|
||||
return fmt.Errorf("parsed expression is not of expected type %T", *new(T))
|
||||
}
|
||||
|
||||
return validator(node)
|
||||
}
|
||||
|
||||
|
|
@ -197,6 +194,36 @@ func WrapCueStruct(s string) string {
|
|||
return fmt.Sprintf("{\n%s\n}", s)
|
||||
}
|
||||
|
||||
// ParseCueContent parses CUE content and extracts struct fields, skipping imports/packages
|
||||
func ParseCueContent(content string) (*ast.StructLit, bool, bool, error) {
|
||||
if strings.TrimSpace(content) == "" {
|
||||
return &ast.StructLit{Elts: []ast.Decl{}}, false, false, nil
|
||||
}
|
||||
|
||||
file, err := parser.ParseFile("-", content)
|
||||
if err != nil {
|
||||
return nil, false, false, err
|
||||
}
|
||||
|
||||
hasImports := len(file.Imports) > 0
|
||||
hasPackage := file.PackageName() != ""
|
||||
|
||||
structLit := &ast.StructLit{
|
||||
Elts: []ast.Decl{},
|
||||
}
|
||||
|
||||
for _, decl := range file.Decls {
|
||||
switch decl.(type) {
|
||||
case *ast.ImportDecl, *ast.Package:
|
||||
// Skip imports and package declarations
|
||||
default:
|
||||
structLit.Elts = append(structLit.Elts, decl)
|
||||
}
|
||||
}
|
||||
|
||||
return structLit, hasImports, hasPackage, nil
|
||||
}
|
||||
|
||||
// FindAndValidateField searches for a field at the top level or within top-level if statements
|
||||
func FindAndValidateField(sl *ast.StructLit, fieldName string, validator fieldValidator) (found bool, err error) {
|
||||
// First check top-level fields
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ import (
|
|||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
velacue "github.com/oam-dev/kubevela/pkg/cue"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
"github.com/oam-dev/kubevela/pkg/utils"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/filters"
|
||||
"github.com/oam-dev/kubevela/pkg/workflow/providers"
|
||||
|
|
@ -292,7 +293,7 @@ func (def *Definition) FromCUE(val *cue.Value, templateString string) error {
|
|||
return err
|
||||
}
|
||||
for fields.Next() {
|
||||
definitionName := fields.Label()
|
||||
definitionName := util.GetIteratorLabel(*fields)
|
||||
v := fields.Value()
|
||||
if nameFlag {
|
||||
return fmt.Errorf("duplicated definition name found, %s and %s", def.GetName(), definitionName)
|
||||
|
|
@ -304,7 +305,7 @@ func (def *Definition) FromCUE(val *cue.Value, templateString string) error {
|
|||
return err
|
||||
}
|
||||
for _fields.Next() {
|
||||
_key := _fields.Label()
|
||||
_key := util.GetIteratorLabel(*_fields)
|
||||
_value := _fields.Value()
|
||||
switch _key {
|
||||
case "type":
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
Copyright 2021 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import "cuelang.org/go/cue"
|
||||
|
||||
// GetIteratorLabel returns the label string from a CUE iterator using the
|
||||
// non-deprecated Selector API. It handles both string labels and other label types.
|
||||
func GetIteratorLabel(iter cue.Iterator) string {
|
||||
selector := iter.Selector()
|
||||
|
||||
// If it's a quoted string, unquote it safely
|
||||
if selector.IsString() && selector.LabelType() == cue.StringLabel {
|
||||
return selector.Unquoted()
|
||||
}
|
||||
|
||||
// For other label types, use the string representation
|
||||
return selector.String()
|
||||
}
|
||||
|
|
@ -40,6 +40,7 @@ import (
|
|||
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/appfile/dryrun"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
)
|
||||
|
|
@ -322,7 +323,7 @@ func (d *debugOpts) separateBySteps(v cue.Value, ioStreams cmdutil.IOStreams) er
|
|||
if it.Value().IncompleteKind() == cue.BottomKind {
|
||||
break
|
||||
}
|
||||
fieldName := it.Selector().String()
|
||||
fieldName := util.GetIteratorLabel(*it)
|
||||
fieldList = append(fieldList, fieldName)
|
||||
fieldMap[fieldName] = it.Value()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ import (
|
|||
"cuelang.org/go/cue/cuecontext"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
velacue "github.com/oam-dev/kubevela/pkg/cue"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
)
|
||||
|
||||
// GenerateProvidersMarkdown generates markdown documentation for providers.
|
||||
|
|
@ -101,9 +101,9 @@ func GenerateProviderMarkdown(provider io.Reader, w io.Writer) error {
|
|||
pkg = t
|
||||
}
|
||||
|
||||
// header - handle both string and non-string selectors
|
||||
selectorStr := velacue.GetSelectorLabel(iter.Selector())
|
||||
fmt.Fprintf(docs, "## %s\n", selectorStr)
|
||||
// header
|
||||
label := util.GetIteratorLabel(*iter)
|
||||
fmt.Fprintf(docs, "## %s\n", label)
|
||||
|
||||
doc, _, err := ref.parseParameters("", item.LookupPath(cue.ParsePath(paramsKey)), "*Params*", 0, true)
|
||||
if err != nil {
|
||||
|
|
|
|||
Loading…
Reference in New Issue