Skip to content

Add Helm-compatible include template function#282

Open
lack wants to merge 1 commit into
openshift:mainfrom
lack:feature/template-include-function
Open

Add Helm-compatible include template function#282
lack wants to merge 1 commit into
openshift:mainfrom
lack:feature/template-include-function

Conversation

@lack

@lack lack commented Jul 14, 2026

Copy link
Copy Markdown
Member

What

Add the include template function, matching Helm's semantics. Unlike Go's built-in {{template}} action which writes directly to the output, {{include}} executes a named template and returns its result as a string. This allows the output to be piped through other template functions like indent, upper, nindent, etc.

Why

The include function is one of the most commonly used Helm template functions. Reference authors coming from Helm expect it to be available, and it enables cleaner template composition — defining reusable snippets (e.g. standard labels, annotations) in _helpers.tpl files and including them with post-processing.

Without include, authors are limited to Go's {{template}} which cannot be piped:

{{/* This works but cannot be indented */}}
{{ template "mychart.labels" . }}

{{/* This is what Helm users expect */}}
{{ include "mychart.labels" . | indent 4 }}

How

The implementation follows the same pattern Helm uses in pkg/engine/engine.go:

  • A placeholder include is registered in FuncMap() so templates can parse without error
  • After parsing, InitInclude() late-binds the real implementation as a closure over the parsed *template.Template, enabling it to call ExecuteTemplate()
  • A recursion guard (max 1000 depth, matching Helm) prevents infinite loops from self-including templates

The function was not imported directly from Helm's engine package because that would pull in the entire chart rendering pipeline (chart loading, Kubernetes client, values handling, etc.) as a dependency. The actual include implementation is ~25 lines.

Testing

  • Unit tests (funcmap_include_test.go): basic include, data passing, piping through upper/indent, nested includes, missing template error, recursion guard
  • Integration test (TestCompareRun/Include_Function): end-to-end test with a _helpers.tpl defining labels and a ConfigMap template using {{ include "mychart.labels" . | indent 4 }}

Summary by CodeRabbit

  • New Features
    • Added Helm-style include support for templates, enabling named partial reuse, passing data context, and using included output with built-in template functions.
    • Added protection against infinite self-referential includes via an enforced recursion limit.
    • Missing included templates now surface clear execution errors.
  • Tests
    • Expanded coverage for basic, nested, formatted/piped includes, missing-template errors, and recursion-guard behavior, including updated fixtures.
  • Documentation
    • Updated the config guide to document include, including usage examples and the recursion-guard behavior.

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: f180522a-9f25-46ac-a886-520b78172101

📥 Commits

Reviewing files that changed from the base of the PR and between 534afab and fac4630.

📒 Files selected for processing (12)
  • docs/reference-config-guide-v1.md
  • docs/reference-config-guide-v2.md
  • pkg/compare/compare_test.go
  • pkg/compare/funcmap.go
  • pkg/compare/funcmap_include_test.go
  • pkg/compare/parsing.go
  • pkg/compare/testdata/IncludeFunction/liveout.golden
  • pkg/compare/testdata/IncludeFunction/localout.golden
  • pkg/compare/testdata/IncludeFunction/reference/_helpers.tpl
  • pkg/compare/testdata/IncludeFunction/reference/cm.yaml
  • pkg/compare/testdata/IncludeFunction/reference/metadata.yaml
  • pkg/compare/testdata/IncludeFunction/resources/cm.yaml
🚧 Files skipped from review as they are similar to previous changes (9)
  • pkg/compare/testdata/IncludeFunction/localout.golden
  • pkg/compare/testdata/IncludeFunction/liveout.golden
  • pkg/compare/testdata/IncludeFunction/resources/cm.yaml
  • pkg/compare/parsing.go
  • docs/reference-config-guide-v1.md
  • docs/reference-config-guide-v2.md
  • pkg/compare/funcmap_include_test.go
  • pkg/compare/funcmap.go
  • pkg/compare/compare_test.go

Walkthrough

Changes

The PR adds Helm-like late-bound include support with recursion protection, initializes it during template parsing, and adds unit, comparison-fixture, and documentation coverage.

Template Include Support

Layer / File(s) Summary
Include runtime and binding
pkg/compare/funcmap.go
Registers an include placeholder, binds the implementation after parsing, executes named templates, and limits nested includes.
Parser wiring and runtime validation
pkg/compare/parsing.go, pkg/compare/funcmap_include_test.go, pkg/compare/compare_test.go, pkg/compare/testdata/IncludeFunction/...
Initializes include functions on parsed templates and tests rendering, pipelines, nesting, missing templates, recursion errors, and comparison outputs.
Comparison fixtures and documentation
pkg/compare/testdata/IncludeFunction/..., docs/reference-config-guide-v1.md, docs/reference-config-guide-v2.md
Adds included label templates, manifests, metadata, expected outputs, and documentation for the include function.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant TemplateParser
  participant InitInclude
  participant includeFun
  participant NamedTemplate
  TemplateParser->>InitInclude: initialize parsed template
  InitInclude->>includeFun: bind include function
  includeFun->>NamedTemplate: execute referenced template
  NamedTemplate-->>includeFun: return rendered content or error
Loading

Suggested reviewers: pixelsoccupied, natifridman

🚥 Pre-merge checks | ✅ 14 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (14 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding a Helm-compatible include template function.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed All added test titles are static and deterministic; no generated values or run-to-run varying data appears in titles.
Test Structure And Quality ✅ Passed The new tests are table-driven, single-purpose subtests with explicit failure messages; there are no cluster resources, Eventually calls, or cleanup issues to flag.
Microshift Test Compatibility ✅ Passed The new test is a plain testing.T case, not Ginkgo e2e, and the fixture only uses a core ConfigMap/template include—no MicroShift-unsupported OpenShift APIs.
Single Node Openshift (Sno) Test Compatibility ✅ Passed PASS: The added Include Function coverage is a standard Go test, not Ginkgo e2e, and it only exercises template rendering—no multi-node or HA assumptions.
Topology-Aware Scheduling Compatibility ✅ Passed PR only adds template include support, tests, docs, and fixtures; no deployment/operator/controller scheduling logic or topology constraints were modified.
Ote Binary Stdout Contract ✅ Passed Touched files add library/test code only; no main/init/TestMain/suite hooks or stdout prints were introduced.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed No new Ginkgo e2e tests were added; the new tests are plain Go unit/integration tests and the IncludeFunction fixtures contain no IPv4 or external-network assumptions.
No-Weak-Crypto ✅ Passed Reviewed all modified files; no MD5/SHA1/DES/RC4/3DES/Blowfish/ECB, custom crypto, or secret/token comparisons were added.
Container-Privileges ✅ Passed Touched manifests are ConfigMaps/metadata only; no privileged, hostPID/Network/IPC, SYS_ADMIN, or allowPrivilegeEscalation settings were added.
No-Sensitive-Data-In-Logs ✅ Passed The PR adds include support and tests, but no new logging statements or sensitive identifiers appear in the changed lines.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions
The command is terminated due to an error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions


Comment @coderabbitai help to get the list of available commands.

@openshift-ci

openshift-ci Bot commented Jul 14, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign marsik for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/reference-config-guide-v1.md`:
- Line 87: Update the Helm compatibility statement near “behavior” in the
documentation to limit the claim to the implemented Helm-style helpers: include,
toYaml, toJson, fromYaml, fromJson, lookupCR, lookupCRs, and doNotMatch, instead
of claiming support for all custom Helm functions.

In `@docs/reference-config-guide-v2.md`:
- Around line 285-287: Align the documented recursion limit with the guard in
funcmap.go: either change the recursionMaxNums comparison to enforce a true
maximum of 1000 active includes, or update this guide and its related tests to
state and verify the current 1001-include behavior. Keep the documentation,
implementation, and tests consistent.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 0fa5b6e5-1eec-44c9-85e6-8f40be6028e0

📥 Commits

Reviewing files that changed from the base of the PR and between a2c20d3 and 534afab.

📒 Files selected for processing (2)
  • docs/reference-config-guide-v1.md
  • docs/reference-config-guide-v2.md

Comment thread docs/reference-config-guide-v1.md Outdated
Comment thread docs/reference-config-guide-v2.md Outdated
Add the "include" template function, matching Helm's semantics.
Unlike Go's built-in {{template}} action which writes directly to
the output, {{include}} executes a named template and returns its
result as a string. This allows the output to be piped through other
template functions like indent, upper, nindent, etc.

The implementation follows Helm's approach:
- A placeholder include is registered in FuncMap() so templates parse
  without error
- After parsing, InitInclude() binds the real implementation as a
  closure over the parsed *template.Template
- A recursion guard prevents infinite loops from templates that
  include themselves

Example usage in reference templates:
  {{- define "mychart.labels" -}}
  app: my-app
  chart: my-chart
  {{- end -}}

  metadata:
    labels:
  {{ include "mychart.labels" . | indent 4 }}

Assisted-by: Claude Opus 4.6 and pi.dev
Signed-off-by: Jim Ramsay <jramsay@redhat.com>
@lack lack force-pushed the feature/template-include-function branch from 534afab to fac4630 Compare July 14, 2026 07:19
@openshift-ci

openshift-ci Bot commented Jul 14, 2026

Copy link
Copy Markdown

@lack: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant