diff --git a/ci/paperless-ngx/test-values.yaml b/ci/paperless-ngx/test-values.yaml index 3769628..383ab65 100644 --- a/ci/paperless-ngx/test-values.yaml +++ b/ci/paperless-ngx/test-values.yaml @@ -9,5 +9,12 @@ ingress: # apply - there is no cert-manager in the CI cluster. clusterIssuer: ci +paperless: + files: + # Regression guard for issue #61: a childless "barcodes:" key is YAML null. + # It must fall back to the chart defaults (barcodes enabled, "PATCHT") and + # neither erase them nor break rendering. + barcodes: + # smbConnection and oidc stay disabled (defaults): the SMB CSI driver and a # real OIDC login flow are out of scope for the CI install-test. diff --git a/paperless-ngx/Chart.yaml b/paperless-ngx/Chart.yaml index d87db47..9386978 100644 --- a/paperless-ngx/Chart.yaml +++ b/paperless-ngx/Chart.yaml @@ -5,7 +5,7 @@ icon: https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/dev/src-ui/s type: application -version: 10.0.0+up3.0.5 +version: 11.0.0+up3.0.5 appVersion: 3.0.5 diff --git a/paperless-ngx/templates/_helpers.tpl b/paperless-ngx/templates/_helpers.tpl index b4029b9..48aecea 100644 --- a/paperless-ngx/templates/_helpers.tpl +++ b/paperless-ngx/templates/_helpers.tpl @@ -114,3 +114,78 @@ template-chart is the reference implementation. 1 {{- end -}} {{- end -}} + +{{/* +Merge a user-supplied values sub-tree onto a dict of chart defaults so that a +null / empty override falls back to the defaults instead of erasing them. + +Input: dict "defaults" "given" "path" . Output: YAML of the merged dict (consume +it with fromYaml). + +Why this exists (issue #61): Helm merges values maps recursively, but an +override key written without children — e.g. a leftover + + barcodes: + +after deleting its last remaining sub-key — is YAML null and replaces the +whole default sub-tree. The chart then renders with no barcode settings at +all. This helper defines the opposite semantics: an empty block means "chart +defaults apply". + +Rules: + - a nil "given" is treated as an empty dict (all defaults apply). + - a key whose override value is null keeps the default (nulls never delete). + - a key present in both as a map is merged recursively, so a partially + filled block only overrides the keys it actually sets. + - a scalar override for a key the defaults define as a map is rejected with + a message naming the values path, instead of failing later with a template + field error. + - any other set value wins as given, including an explicit false or 0 — + Helm's "default" and sprig's "mergeOverwrite" would both swallow those + zero values, hence the explicit kindIs "invalid" nil check. + - keys only present in the override are passed through unchanged. +*/}} +{{- define "paperless-ngx.defaultedDict" -}} +{{- $defaults := .defaults | default dict -}} +{{- $given := .given -}} +{{- $path := .path | default "value" -}} +{{- if kindIs "invalid" $given -}} +{{- $given = dict -}} +{{- end -}} +{{- if not (kindIs "map" $given) -}} +{{- fail (printf "%s must be a mapping or null, got %s (%v)" $path (kindOf $given) $given) -}} +{{- end -}} +{{- $out := deepCopy $defaults -}} +{{- range $key, $value := $given -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $default := index $defaults $key -}} +{{- if and (kindIs "map" $value) (kindIs "map" $default) -}} +{{- $_ := set $out $key (fromYaml (include "paperless-ngx.defaultedDict" (dict "defaults" $default "given" $value "path" (printf "%s.%s" $path $key)))) -}} +{{- else if kindIs "map" $default -}} +{{- fail (printf "%s.%s must be a mapping or null, got %s (%v)" $path $key (kindOf $value) $value) -}} +{{- else -}} +{{- $_ := set $out $key $value -}} +{{- end -}} +{{- end -}} +{{- end -}} +{{- toYaml $out -}} +{{- end -}} + +{{/* +The effective barcode settings, rendered as YAML (consume with fromYaml). + +Input: .Values.paperless.files.barcodes (may be nil, empty or partial). + +The defaults below MUST stay in sync with the barcodes block in values.yaml, +which stays the documented, user-facing place for them; this copy is only the +fallback for the case where an override has erased the block. +*/}} +{{- define "paperless-ngx.barcodes" -}} +{{- $defaults := dict + "enabled" true + "barcodeString" "PATCHT" + "retainBarcodePage" false + "asn" (dict "enabled" true) -}} +{{- include "paperless-ngx.defaultedDict" (dict "defaults" $defaults "given" . "path" "paperless.files.barcodes") -}} +{{- end -}} diff --git a/paperless-ngx/templates/paperless-server.sfs.yaml b/paperless-ngx/templates/paperless-server.sfs.yaml index 06a6d9f..d100978 100644 --- a/paperless-ngx/templates/paperless-server.sfs.yaml +++ b/paperless-ngx/templates/paperless-server.sfs.yaml @@ -1,3 +1,8 @@ +{{- /* +Barcode settings, defended against a null / empty "barcodes:" override: +an empty block falls back to the chart defaults (issue #61). +*/ -}} +{{- $barcodes := fromYaml (include "paperless-ngx.barcodes" .Values.paperless.files.barcodes) -}} apiVersion: apps/v1 kind: StatefulSet metadata: @@ -137,13 +142,13 @@ spec: - name: PAPERLESS_URL value: "https://{{ .Values.ingress.domain }}" - name: PAPERLESS_CONSUMER_ENABLE_ASN_BARCODE - value: "{{ .Values.paperless.files.barcodes.asn.enabled }}" + value: "{{ $barcodes.asn.enabled }}" - name: PAPERLESS_CONSUMER_ENABLE_BARCODES - value: "{{ .Values.paperless.files.barcodes.enabled }}" + value: "{{ $barcodes.enabled }}" - name: PAPERLESS_CONSUMER_BARCODE_STRING - value: "{{ .Values.paperless.files.barcodes.barcodeString }}" + value: "{{ $barcodes.barcodeString }}" - name: PAPERLESS_CONSUMER_BARCODE_RETAIN_SPLIT_PAGES - value: "{{ .Values.paperless.files.barcodes.retainBarcodePage }}" + value: "{{ $barcodes.retainBarcodePage }}" - name: PAPERLESS_CONSUMER_DELETE_DUPLICATES value: "{{ .Values.paperless.files.deleteDuplicates }}" {{- if .Values.paperless.files.tikaGotenberg.enabled }} diff --git a/paperless-ngx/values.yaml b/paperless-ngx/values.yaml index 08ae837..dcc0851 100644 --- a/paperless-ngx/values.yaml +++ b/paperless-ngx/values.yaml @@ -48,6 +48,13 @@ paperless: # The barcode scanner backend is no longer configurable: paperless-ngx 3.0 # removed pyzbar and PAPERLESS_CONSUMER_BARCODE_SCANNER; zxing-cpp is the # only backend now. + # + # An empty or null "barcodes:" block in an override means "the defaults + # below apply" — the chart merges the block onto these defaults instead of + # letting a childless key erase them (issue #61; the fallback copy lives in + # the paperless-ngx.barcodes helper and is kept in sync with this block). + # To switch barcode handling off, set barcodes.enabled: false explicitly; + # deleting the sub-keys does not disable it. barcodes: enabled: true barcodeString: "PATCHT"