Skip to content

cap-operator-plugin generates invalid semver versions incompatible with cap-operator #91

@yotamsonn

Description

@yotamsonn

Description

The cap-operator-plugin uses {{ .Release.Revision }} as the spec.version for CAPApplicationVersion resources. Helm release revisions are plain integers (1, 2, 3, ...), which are not valid semantic versions.

The CAP Operator requires valid semver (MAJOR.MINOR.PATCH) for version comparison logic (golang.org/x/mod/semver). When given non-semver versions, the operator silently fails to identify newer versions, and automatic tenant upgrades never trigger.

Related issue: sap/cap-operator#XXX

Location

During cds build, the CapOperatorBuildPlugin (lib/build.js) generates Helm templates by calling helper functions in lib/util.js. The invalid version originates in the writeCAPApplicationVersionCommonCRO function:

// lib/util.js - writeCAPApplicationVersionCommonCRO()
' version: "{{ .Release.Revision }}"',

This is called by both getCAPOpCroYaml() and getConfigurableCapOpCroYaml(), meaning all chart modes (default, with-templates, and with-configurable-templates) are affected.

The resource name helper in getHelperTpl() also uses the revision directly:

// lib/util.js - getHelperTpl()
'{{- define "capApplicationVersionName" -}}',
'{{ printf "%s-%d" (include "appName" $) (.Release.Revision) }}',
'{{- end -}}',

Steps to Reproduce

  1. Create a CAP project with cds add cap-operator
  2. Run cds build — generates Helm chart templates containing version: "{{ .Release.Revision }}"
  3. Deploy with helm install → creates CAV with spec.version: "1"
  4. Deploy again with helm upgrade → creates CAV with spec.version: "2"
  5. Both versions reach Ready state
  6. Expected: Tenant is automatically upgraded to version "2"
  7. Actual: Tenant remains on version "1" — the operator's semver.Compare("v2", "v1") returns 0 (both invalid) so it never identifies "2" as newer

No error or warning is shown. Everything appears healthy (CAV is Ready, CAPApplication is Consistent).

Suggested Fix

Make the version configurable through values.yaml with a valid semver default that falls back to the Helm release revision.

In lib/util.js, update writeCAPApplicationVersionCommonCRO:

// From:
' version: "{{ .Release.Revision }}"',

// To:
' version: "{{ .Values.app.version | default (printf "%d.0.0" .Release.Revision) }}"',

In the generated values.yaml (via values.yaml.hbs), add an optional version field under app:

app:
  # version: "1.2.3"   # Optional: override with your own semver (e.g., from CI/CD pipeline)

This way:

  • By default (no user override): produces "1.0.0", "2.0.0", "3.0.0" etc. — valid semver derived from the Helm revision
  • With user override: users can set app.version to their own semver (e.g., from a CI/CD pipeline variable, git tag, or package.json version) via values.yaml or --set app.version=1.2.3

The capApplicationVersionName helper in getHelperTpl() should also use this value for consistency:

// From:
'{{ printf "%s-%d" (include "appName" $) (.Release.Revision) }}',

// To:
'{{ printf "%s-%s" (include "appName" $) (.Values.app.version | default (printf "%d.0.0" .Release.Revision) | replace "." "-") }}',

Impact

  • All users deploying with the default cap-operator-plugin templates are affected
  • Automatic tenant version upgrades silently do not work
  • No error or warning is shown — users have no indication anything is wrong until they notice tenants are not being upgraded
  • Version cleanup monitoring (if enabled) is also affected by the same semver comparison issue

Metadata

Metadata

Assignees

No one assigned

    Labels

    invalidThis doesn't seem right

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions