Compare commits

...

2 Commits

Author SHA1 Message Date
Amit Singh 2a31930c4b
Chore: imports workflow crd from pkg repo (#6954)
CodeQL / Analyze (go) (push) Has been cancelled Details
Definition-Lint / definition-doc (push) Has been cancelled Details
E2E MultiCluster Test / detect-noop (push) Has been cancelled Details
E2E Test / detect-noop (push) Has been cancelled Details
Go / detect-noop (push) Has been cancelled Details
license / Check for unapproved licenses (push) Has been cancelled Details
Registry / Build and Push Vela Images (push) Has been cancelled Details
Unit-Test / detect-noop (push) Has been cancelled Details
Webhook Upgrade Validation / webhook-upgrade-check (push) Has been cancelled Details
Scorecards supply-chain security / Scorecards analysis (push) Has been cancelled Details
E2E MultiCluster Test / e2e-multi-cluster-tests (v1.31.9) (push) Has been cancelled Details
E2E Test / e2e-tests (v1.31) (push) Has been cancelled Details
Go / staticcheck (push) Has been cancelled Details
Go / lint (push) Has been cancelled Details
Go / check-diff (push) Has been cancelled Details
Go / check-windows (push) Has been cancelled Details
Go / check-core-image-build (push) Has been cancelled Details
Go / check-cli-image-build (push) Has been cancelled Details
Registry / Generate and Push Provenance to GCHR (${{ needs.publish-vela-images.outputs.vela_cli_digest }}, ${{ needs.publish-vela-images.outputs.vela_cli_image }}, Vela CLI Image) (push) Has been cancelled Details
Registry / Generate and Push Provenance to GCHR (${{ needs.publish-vela-images.outputs.vela_core_digest }}, ${{ needs.publish-vela-images.outputs.vela_core_image }}, Vela Core Image) (push) Has been cancelled Details
Registry / Generate and Push Provenance to DockerHub (${{ needs.publish-vela-images.outputs.vela_cli_digest }}, ${{ needs.publish-vela-images.outputs.vela_cli_dockerhub_image }}, Vela CLI Image) (push) Has been cancelled Details
Registry / Generate and Push Provenance to DockerHub (${{ needs.publish-vela-images.outputs.vela_core_digest }}, ${{ needs.publish-vela-images.outputs.vela_core_dockerhub_image }}, Vela Core Image) (push) Has been cancelled Details
Unit-Test / unit-tests (push) Has been cancelled Details
* chore: adds logic to pull workflow crd from pkg repo

Signed-off-by: Amit Singh <singhamitch@outlook.com>
Signed-off-by: Ayush <ayushshyamkumar888@gmail.com>
Co-authored-by: Ayush Kumar <ayushshyamkumar888@gmail.com>

* feat: introduce GetIteratorLabel utility function and refactor label retrieval in CUE processing

Signed-off-by: Ayush <ayushshyamkumar888@gmail.com>
Co-authored-by: Vishal Kumar <vishal210893@gmail.com>

* feat: refactor FromCUE method to use GetIteratorLabel utility for improved label retrieval

Signed-off-by: Ayush <ayushshyamkumar888@gmail.com>
Co-authored-by: Ayush Kumar <ayushshyamkumar888@gmail.com>

* feat: remove unused imports and optimize list concatenation in template files

Signed-off-by: Ayush <ayushshyamkumar888@gmail.com>
Co-authored-by: Vishal Kumar <vishal210893@gmail.com>

* refactor: standardize import formatting across multiple YAML and Go files

Signed-off-by: Ayush <ayushshyamkumar888@gmail.com>
Co-authored-by: Vishal Kumar <vishal210893@gmail.com>
Signed-off-by: Ayush <ayushshyamkumar888@gmail.com>

* refactor: import statements in multiple YAML templates for consistency

- Removed unnecessary parentheses around import statements in various CUE templates.
- Ensured a consistent import style across all templates in the vela-core chart.

Signed-off-by: Ayush <ayushshyamkumar888@gmail.com>

* feat: add disk space cleanup steps before and after cross-build in Go workflow

Signed-off-by: Ayush <ayushshyamkumar888@gmail.com>

* refactor: update check-diff target to depend on build for improved consistency

Signed-off-by: Ayush <ayushshyamkumar888@gmail.com>

* refactor: update reviewable target to include build for improved consistency in check-diff

Signed-off-by: Ayush <ayushshyamkumar888@gmail.com>

---------

Signed-off-by: Amit Singh <singhamitch@outlook.com>
Signed-off-by: Ayush <ayushshyamkumar888@gmail.com>
Co-authored-by: Ayush Kumar <ayushshyamkumar888@gmail.com>
Co-authored-by: Vishal Kumar <vishal210893@gmail.com>
2025-11-06 18:56:04 -08:00
Brian Kane 8e3749f970
Fix: Fix issue with imports/packages in status validations (#6963)
Signed-off-by: Brian Kane <briankane1@gmail.com>
2025-11-06 15:23:08 -08:00
18 changed files with 375 additions and 54 deletions

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

33
pkg/oam/util/cue.go Normal file
View File

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

View File

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

View File

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