diff --git a/helm-java/src/main/java/com/marcnuri/helm/TemplateCommand.java b/helm-java/src/main/java/com/marcnuri/helm/TemplateCommand.java index db28447..ff80eb6 100644 --- a/helm-java/src/main/java/com/marcnuri/helm/TemplateCommand.java +++ b/helm-java/src/main/java/com/marcnuri/helm/TemplateCommand.java @@ -29,6 +29,7 @@ * @author Marc Nuri * @author Andres F. Vallecilla * @author Antonio Fernandez Alhambra + * @author Shubham Mohole */ public class TemplateCommand extends HelmCommand { @@ -50,6 +51,8 @@ public class TemplateCommand extends HelmCommand { private Path keyring; private boolean debug; private Path repositoryConfig; + private Path outputDir; + private boolean useReleaseName; public TemplateCommand(HelmLib helmLib) { this(helmLib, null); @@ -83,7 +86,9 @@ public String call() { toInt(plainHttp), toString(keyring), toInt(debug), - toString(repositoryConfig) + toString(repositoryConfig), + toString(outputDir), + toInt(useReleaseName) ))).out; } @@ -299,4 +304,25 @@ public TemplateCommand withRepositoryConfig(Path repositoryConfig) { return this; } + /** + * Write rendered manifests to separate files in the specified directory. + * + * @param outputDir the directory for rendered manifest files. + * @return this {@link TemplateCommand} instance. + */ + public TemplateCommand withOutputDir(Path outputDir) { + this.outputDir = outputDir; + return this; + } + + /** + * Include the release name in the output directory path. + * + * @return this {@link TemplateCommand} instance. + */ + public TemplateCommand useReleaseName() { + this.useReleaseName = true; + return this; + } + } diff --git a/helm-java/src/test/java/com/marcnuri/helm/HelmTemplateTest.java b/helm-java/src/test/java/com/marcnuri/helm/HelmTemplateTest.java index a115b24..4d8b678 100644 --- a/helm-java/src/test/java/com/marcnuri/helm/HelmTemplateTest.java +++ b/helm-java/src/test/java/com/marcnuri/helm/HelmTemplateTest.java @@ -35,6 +35,7 @@ * @author Marc Nuri * @author Andres F. Vallecilla * @author Antonio Fernandez Alhambra + * @author Shubham Mohole */ class HelmTemplateTest { @@ -64,6 +65,36 @@ void withName() { .contains("name: the-name-local-chart-test"); } + @Test + void withOutputDir() throws IOException { + final Path outputDir = tempDir.resolve("rendered"); + helm.template().withOutputDir(outputDir).call(); + + final Path deployment = outputDir.resolve("local-chart-test/templates/deployment.yaml"); + final Path service = outputDir.resolve("local-chart-test/templates/service.yaml"); + assertThat(deployment) + .exists() + .content(StandardCharsets.UTF_8) + .contains("name: release-name-local-chart-test"); + assertThat(service).exists(); + } + + @Test + void withOutputDirAndReleaseName() throws IOException { + final Path outputDir = tempDir.resolve("rendered-with-release"); + helm.template() + .withName("the-name") + .withOutputDir(outputDir) + .useReleaseName() + .call(); + + final Path deployment = outputDir.resolve("the-name/local-chart-test/templates/deployment.yaml"); + assertThat(deployment) + .exists() + .content(StandardCharsets.UTF_8) + .contains("name: the-name-local-chart-test"); + } + @Test void withValues() { final String result = helm.template() diff --git a/lib/api/src/main/java/com/marcnuri/helm/jni/TemplateOptions.java b/lib/api/src/main/java/com/marcnuri/helm/jni/TemplateOptions.java index ce68fae..22961ad 100644 --- a/lib/api/src/main/java/com/marcnuri/helm/jni/TemplateOptions.java +++ b/lib/api/src/main/java/com/marcnuri/helm/jni/TemplateOptions.java @@ -22,6 +22,7 @@ * @author Marc Nuri * @author Andres F. Vallecilla * @author Antonio Fernandez Alhambra + * @author Shubham Mohole */ @Structure.FieldOrder({ "name", @@ -41,7 +42,9 @@ "plainHttp", "keyring", "debug", - "repositoryConfig" + "repositoryConfig", + "outputDir", + "useReleaseName" }) public class TemplateOptions extends Structure { public String name; @@ -62,6 +65,8 @@ public class TemplateOptions extends Structure { public String keyring; public int debug; public String repositoryConfig; + public String outputDir; + public int useReleaseName; public TemplateOptions( String name, @@ -81,7 +86,9 @@ public TemplateOptions( int plainHttp, String keyring, int debug, - String repositoryConfig + String repositoryConfig, + String outputDir, + int useReleaseName ) { this.name = name; this.version = version; @@ -101,5 +108,7 @@ public TemplateOptions( this.keyring = keyring; this.debug = debug; this.repositoryConfig = repositoryConfig; + this.outputDir = outputDir; + this.useReleaseName = useReleaseName; } } diff --git a/native/internal/helm/install.go b/native/internal/helm/install.go index 6cafe64..eff3cf8 100644 --- a/native/internal/helm/install.go +++ b/native/internal/helm/install.go @@ -67,6 +67,8 @@ type InstallOptions struct { // For testing purposes only, prevents connecting to Kubernetes (happens even with DryRun=true and DryRunOption=client) ClientOnly bool RepositoryConfig string + OutputDir string + UseReleaseName bool } type installOutputs struct { @@ -144,6 +146,8 @@ func install(options *InstallOptions) (*release.Release, *installOutputs, error) client.Wait = options.Wait client.Timeout = options.Timeout client.ClientOnly = options.ClientOnly + client.OutputDir = options.OutputDir + client.UseReleaseName = options.UseReleaseName client.CertFile = options.CertFile client.KeyFile = options.KeyFile client.CaFile = options.CaFile diff --git a/native/internal/helm/template.go b/native/internal/helm/template.go index 57758b6..babcaa5 100644 --- a/native/internal/helm/template.go +++ b/native/internal/helm/template.go @@ -36,6 +36,8 @@ type TemplateOptions struct { ValuesFiles string Debug bool RepositoryConfig string + OutputDir string + UseReleaseName bool } func Template(options *TemplateOptions) (string, error) { @@ -61,6 +63,8 @@ func Template(options *TemplateOptions) (string, error) { ValuesFiles: options.ValuesFiles, Debug: options.Debug, RepositoryConfig: options.RepositoryConfig, + OutputDir: options.OutputDir, + UseReleaseName: options.UseReleaseName, }) if err != nil && !options.Debug { diff --git a/native/internal/helm/template_test.go b/native/internal/helm/template_test.go index 6b275ee..7d25c3b 100644 --- a/native/internal/helm/template_test.go +++ b/native/internal/helm/template_test.go @@ -19,6 +19,7 @@ package helm import ( "helm.sh/helm/v3/pkg/chartutil" "os" + "path/filepath" "strings" "testing" ) @@ -55,6 +56,46 @@ func TestTemplateFromLocal(t *testing.T) { return } }) + t.Run("with output directory", func(t *testing.T) { + outputDir := t.TempDir() + _, err := Template(&TemplateOptions{ + Chart: create, + OutputDir: outputDir, + }) + if err != nil { + t.Errorf("Expected template to succeed, got %s", err) + return + } + manifest, err := os.ReadFile(filepath.Join(outputDir, "chart-for-template-tests", "templates", "deployment.yaml")) + if err != nil { + t.Errorf("Expected deployment manifest to be written, got %s", err) + return + } + if !strings.Contains(string(manifest), "name: release-name-chart-for-template-tests") { + t.Errorf("Expected deployment manifest to contain rendered release name, got %s", manifest) + } + }) + t.Run("with release name in output directory", func(t *testing.T) { + outputDir := t.TempDir() + _, err := Template(&TemplateOptions{ + Name: "the-name", + Chart: create, + OutputDir: outputDir, + UseReleaseName: true, + }) + if err != nil { + t.Errorf("Expected template to succeed, got %s", err) + return + } + manifest, err := os.ReadFile(filepath.Join(outputDir, "the-name", "chart-for-template-tests", "templates", "deployment.yaml")) + if err != nil { + t.Errorf("Expected deployment manifest to be written under the release name, got %s", err) + return + } + if !strings.Contains(string(manifest), "name: the-name-chart-for-template-tests") { + t.Errorf("Expected deployment manifest to contain rendered release name, got %s", manifest) + } + }) t.Run("with invalid values", func(t *testing.T) { manifests, err := Template(&TemplateOptions{ Chart: create, diff --git a/native/main.go b/native/main.go index 183fe9a..54bd362 100644 --- a/native/main.go +++ b/native/main.go @@ -193,6 +193,8 @@ struct TemplateOptions { char* keyring; int debug; char* repositoryConfig; + char* outputDir; + int useReleaseName; }; struct TestOptions { @@ -702,6 +704,8 @@ func Template(options *C.struct_TemplateOptions) C.Result { }, Debug: options.debug == 1, RepositoryConfig: C.GoString(options.repositoryConfig), + OutputDir: C.GoString(options.outputDir), + UseReleaseName: options.useReleaseName == 1, }) }) }