diff --git a/README.md b/README.md
index b3a9eac..6ddba69 100755
--- a/README.md
+++ b/README.md
@@ -165,37 +165,6 @@ A rule for performing `helm lint` on a helm package
| chart | The helm package to run linting on. | Label | required | |
-
-
-## helm_package
-
-
-load("@rules_helm//helm:defs.bzl", "helm_package")
-
-helm_package(name, deps, chart, chart_json, crds, images, stamp, substitutions, templates, values,
- values_json)
-
-
-Rules for creating Helm chart packages.
-
-**ATTRIBUTES**
-
-
-| Name | Description | Type | Mandatory | Default |
-| :------------- | :------------- | :------------- | :------------- | :------------- |
-| name | A unique name for this target. | Name | required | |
-| deps | Other helm packages this package depends on. | List of labels | optional | `[]` |
-| chart | The `Chart.yaml` file of the helm chart | Label | optional | `None` |
-| chart_json | The `Chart.yaml` file of the helm chart as a json object | String | optional | `""` |
-| crds | All crds associated with the current helm chart. E.g., the `./crds` directory | List of labels | optional | `[]` |
-| images | A list of [oci_push](https://github.com/bazel-contrib/rules_oci/blob/main/docs/push.md#oci_push_rule-remote_tags) targets. | List of labels | optional | `[]` |
-| stamp | Whether to encode build information into the helm actions. Possible values:
- `stamp = 1`: Always stamp the build information into the helm actions, even in [--nostamp](https://docs.bazel.build/versions/main/user-manual.html#flag--stamp) builds. This setting should be avoided, since it potentially kills remote caching for the target and any downstream actions that depend on it.
- `stamp = 0`: Always replace build information by constant values. This gives good build result caching.
- `stamp = -1`: Embedding of build information is controlled by the [--[no]stamp](https://docs.bazel.build/versions/main/user-manual.html#flag--stamp) flag.
Stamped targets are not rebuilt unless their dependencies change. | Integer | optional | `-1` |
-| substitutions | A dictionary of substitutions to apply to the `values.yaml` file. | Dictionary: String -> String | optional | `{}` |
-| templates | All templates associated with the current helm chart. E.g., the `./templates` directory | List of labels | optional | `[]` |
-| values | The `values.yaml` file for the current package. | Label | optional | `None` |
-| values_json | The `values.yaml` file for the current package as a json object. | String | optional | `""` |
-
-
## helm_plugin
@@ -451,8 +420,8 @@ str: A json encoded string which represents `Chart.yaml` contents.
load("@rules_helm//helm:defs.bzl", "helm_chart")
-helm_chart(name, chart, chart_json, crds, values, values_json, substitutions, templates, images,
- deps, install_name, registry_url, login_url, helm_opts, install_opts, upgrade_opts,
+helm_chart(name, chart, chart_json, crds, values, values_json, substitutions, templates, files,
+ images, deps, install_name, registry_url, login_url, helm_opts, install_opts, upgrade_opts,
uninstall_opts, data, stamp, **kwargs)
@@ -482,6 +451,7 @@ Rules for producing a helm package and some convenience targets.
| values_json | The json encoded contents of `values.yaml`. | `None` |
| substitutions | A dictionary of substitutions to apply to `values.yaml`. | `{}` |
| templates | A list of template files to include in the package. | `None` |
+| files | A a map with lists of files to be copied to their respective folders within the helm chart. | `{}` |
| images | A list of [oci_push](https://github.com/bazel-contrib/rules_oci/blob/main/docs/push.md#oci_push_rule-remote_tags) targets | `[]` |
| deps | A list of helm package dependencies. | `None` |
| install_name | The `helm install` name to use. `name` will be used if unset. | `None` |
@@ -496,6 +466,39 @@ Rules for producing a helm package and some convenience targets.
| kwargs | Additional keyword arguments for `helm_package`. | none |
+
+
+## helm_package
+
+
+load("@rules_helm//helm:defs.bzl", "helm_package")
+
+helm_package(name, chart, chart_json, crds, values, values_json, substitutions, templates, files,
+ images, deps, stamp, **kwargs)
+
+
+Rules for creating Helm chart packages.
+
+**PARAMETERS**
+
+
+| Name | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| name | The name of the target | none |
+| chart | "The `Chart.yaml` file of the helm chart" | `None` |
+| chart_json | "The `Chart.yaml` file of the helm chart as a json object" | `None` |
+| crds | All crds associated with the current helm chart. E.g., the `./crds` directory | `None` |
+| values | The `values.yaml` file for the current package. | `None` |
+| values_json | The `values.yaml` file for the current package as a json object. | `None` |
+| substitutions | A dictionary of substitutions to apply to the `values.yaml` file. | `{}` |
+| templates | All templates associated with the current helm chart. E.g., the `./templates` directory | `None` |
+| files | Additional files to be added to the chart specified as a map from string to list of labels. | `{}` |
+| images | A list of [oci_push](https://github.com/bazel-contrib/rules_oci/blob/main/docs/push.md#oci_push_rule-remote_tags) targets | `[]` |
+| deps | Other helm packages this package depends on. | `None` |
+| stamp | Whether to encode build information into the helm actions. Possible values:
- `stamp = 1`: Always stamp the build information into the helm actions, even in [--nostamp](https://docs.bazel.build/versions/main/user-manual.html#flag--stamp) builds. This setting should be avoided, since it potentially kills remote caching for the target and any downstream actions that depend on it.
- `stamp = 0`: Always replace build information by constant values. This gives good build result caching.
- `stamp = -1`: Embedding of build information is controlled by the [--[no]stamp](https://docs.bazel.build/versions/main/user-manual.html#flag--stamp) flag.
Stamped targets are not rebuilt unless their dependencies change. | `None` |
+| kwargs | Additional keyword arguments. | none |
+
+
## helm_register_toolchains
diff --git a/helm/private/helm.bzl b/helm/private/helm.bzl
index 926d072..82dd743 100644
--- a/helm/private/helm.bzl
+++ b/helm/private/helm.bzl
@@ -13,6 +13,7 @@ def helm_chart(
values_json = None,
substitutions = {},
templates = None,
+ files = {},
images = [],
deps = None,
install_name = None,
@@ -46,6 +47,7 @@ def helm_chart(
values_json (str, optional): The json encoded contents of `values.yaml`.
substitutions (dict, optional): A dictionary of substitutions to apply to `values.yaml`.
templates (list, optional): A list of template files to include in the package.
+ files (map[string, list[label]], optional): A a map with lists of files to be copied to their respective folders within the helm chart.
images (list, optional): A list of [oci_push](https://github.com/bazel-contrib/rules_oci/blob/main/docs/push.md#oci_push_rule-remote_tags) targets
deps (list, optional): A list of helm package dependencies.
install_name (str, optional): The `helm install` name to use. `name` will be used if unset.
@@ -74,6 +76,7 @@ def helm_chart(
deps = deps,
images = images,
templates = templates,
+ files = files,
values = values,
values_json = values_json,
substitutions = substitutions,
diff --git a/helm/private/helm_package.bzl b/helm/private/helm_package.bzl
index 6b3995a..1e4cd8f 100644
--- a/helm/private/helm_package.bzl
+++ b/helm/private/helm_package.bzl
@@ -109,6 +109,10 @@ def _helm_package_impl(ctx):
)
args.add("-templates_manifest", templates_manifest)
+ for ln in ctx.attr.files:
+ fmt = "%s=" + ctx.attr.files[ln]
+ args.add_all(ln.files, before_each = "-add_files", format_each = fmt, uniquify = True)
+
crds_manifest = ctx.actions.declare_file("{}/crds_manifest.json".format(ctx.label.name))
ctx.actions.write(
output = crds_manifest,
@@ -180,7 +184,7 @@ def _helm_package_impl(ctx):
executable = ctx.executable._packager,
outputs = [output, metadata_output],
inputs = depset(
- ctx.files.templates + ctx.files.crds + stamps + image_inputs + deps + [
+ ctx.files.templates + ctx.files.files + ctx.files.crds + stamps + image_inputs + deps + [
chart_yaml,
values_yaml,
templates_manifest,
@@ -208,7 +212,77 @@ def _helm_package_impl(ctx):
),
]
-helm_package = rule(
+def helm_package(
+ name,
+ chart = None,
+ chart_json = None,
+ crds = None,
+ values = None,
+ values_json = None,
+ substitutions = {},
+ templates = None,
+ files = {},
+ images = [],
+ deps = None,
+ stamp = None,
+ **kwargs):
+ """Rules for creating Helm chart packages.
+
+ Args:
+ name: The name of the target
+ chart: "The `Chart.yaml` file of the helm chart"
+ chart_json: "The `Chart.yaml` file of the helm chart as a json object"
+ crds: All crds associated with the current helm chart. E.g., the `./crds` directory
+ values (str, optional): The `values.yaml` file for the current package.
+ values_json: The `values.yaml` file for the current package as a json object.
+ substitutions: A dictionary of substitutions to apply to the `values.yaml` file.
+ templates: All templates associated with the current helm chart. E.g., the `./templates` directory
+ files: Additional files to be added to the chart specified as a map from string to list of labels.
+ images: A list of [oci_push](https://github.com/bazel-contrib/rules_oci/blob/main/docs/push.md#oci_push_rule-remote_tags) targets
+ deps: Other helm packages this package depends on.
+ stamp: Whether to encode build information into the helm actions. Possible values:
+
+ - `stamp = 1`: Always stamp the build information into the helm actions, even in \
+ [--nostamp](https://docs.bazel.build/versions/main/user-manual.html#flag--stamp) builds. \
+ This setting should be avoided, since it potentially kills remote caching for the target and \
+ any downstream actions that depend on it.
+
+ - `stamp = 0`: Always replace build information by constant values. This gives good build result caching.
+
+ - `stamp = -1`: Embedding of build information is controlled by the \
+ [--[no]stamp](https://docs.bazel.build/versions/main/user-manual.html#flag--stamp) flag.
+
+ Stamped targets are not rebuilt unless their dependencies change.
+ **kwargs (dict): Additional keyword arguments.
+ """
+
+ # We wrap this in a macro so that we can provide a better API for the `files` attribute
+ # If https://github.com/bazelbuild/bazel/issues/7989 ever gets implemented we can remove the macro
+ filegroups = {}
+ for folder, folder_files in files.items():
+ native.filegroup(
+ name = "{}_filegroup".format(folder),
+ srcs = folder_files,
+ )
+ filegroups[":{}_filegroup".format(folder)] = folder
+
+ _helm_package(
+ name = name,
+ chart = chart,
+ chart_json = chart_json,
+ crds = crds,
+ deps = deps,
+ images = images,
+ templates = templates,
+ files = filegroups,
+ values = values,
+ values_json = values_json,
+ substitutions = substitutions,
+ stamp = stamp,
+ **kwargs
+ )
+
+_helm_package = rule(
implementation = _helm_package_impl,
doc = "Rules for creating Helm chart packages.",
attrs = {
@@ -228,6 +302,11 @@ helm_package = rule(
doc = "Other helm packages this package depends on.",
providers = [HelmPackageInfo],
),
+ "files": attr.label_keyed_string_dict(
+ doc = "Additional files to be added to the chart specified as a map from string to list of labels.",
+ allow_empty = True,
+ allow_files = True,
+ ),
"images": attr.label_list(
doc = """\
A list of \
diff --git a/helm/private/packager/packager.go b/helm/private/packager/packager.go
index 871a2d4..a7574c6 100644
--- a/helm/private/packager/packager.go
+++ b/helm/private/packager/packager.go
@@ -69,6 +69,35 @@ type HelmDependency struct {
Alias string `yaml:"alias,omitempty"`
}
+type addFile struct {
+ src string
+ dst string
+}
+
+func (r addFile) String() string {
+ return fmt.Sprintf("%s=%s", r.src, r.dst)
+}
+
+type addFiles []addFile
+
+func (c *addFiles) String() string {
+ return fmt.Sprintf("%v", *c)
+}
+
+func (c *addFiles) Set(s string) error {
+ split := strings.SplitN(s, "=", 2)
+ if len(split) != 2 {
+ return fmt.Errorf("parse addFile from %q", s)
+ }
+ src := split[0]
+ if len(src) == 0 {
+ return fmt.Errorf("empty src in %q", s)
+ }
+ dst := split[1]
+ *c = append(*c, addFile{src: src, dst: dst})
+ return nil
+}
+
type HelmChart struct {
ApiVersion string `yaml:"apiVersion"`
Name string `yaml:"name"`
@@ -89,6 +118,7 @@ type HelmChart struct {
type Arguments struct {
TemplatesManifest string
+ AddFiles addFiles
CrdsManifest string
Chart string
Values string
@@ -108,6 +138,7 @@ func parseArgs() Arguments {
var args Arguments
flag.StringVar(&args.TemplatesManifest, "templates_manifest", "", "A helm file containing a list of all helm template files.")
+ flag.Var(&args.AddFiles, "add_files", "Additional files to be added to the chart")
flag.StringVar(&args.CrdsManifest, "crds_manifest", "", "A helm file containing a list of all helm crd files.")
flag.StringVar(&args.Chart, "chart", "", "The helm `chart.yaml` file.")
flag.StringVar(&args.Values, "values", "", "The helm `values.yaml` file.")
@@ -428,7 +459,67 @@ func copyFile(source string, dest string) error {
return nil
}
-func installHelmContent(workingDir string, stampedChartContent string, stampedValuesContent string, templatesManifest string, crdsManifest string, depsManifest string) error {
+func copyFileToDir(src string, dir string) error {
+ srcFile, err := os.Open(src)
+ if err != nil {
+ return fmt.Errorf("open %s: %w", src, err)
+ }
+ defer srcFile.Close()
+
+ err = os.MkdirAll(dir, 0700)
+ if err != nil && !os.IsExist(err) {
+ return fmt.Errorf("make dirs %s: %w", dir, err)
+ }
+
+ dst := filepath.Join(dir, filepath.Base(src))
+
+ dstFile, err := os.Create(dst)
+ if err != nil {
+ return fmt.Errorf("create %s: %w", dst, err)
+ }
+
+ _, err = io.Copy(dstFile, srcFile)
+ if errClose := dstFile.Close(); errClose != nil && err == nil {
+ err = errClose
+ }
+ return err
+}
+
+func copyDir(src string, dst string) error {
+ var err error
+ var fds []os.DirEntry
+
+ if _, err = os.Stat(src); err != nil {
+ return fmt.Errorf("file stat: %w", err)
+ }
+
+ if err = os.MkdirAll(dst, 0700); err != nil {
+ if !os.IsExist(err) {
+ return fmt.Errorf("make dirs: %w", err)
+ }
+ }
+
+ if fds, err = os.ReadDir(src); err != nil {
+ return fmt.Errorf("read dir: %w", err)
+ }
+ for _, fd := range fds {
+ srcfp := filepath.Join(src, fd.Name())
+ dstfp := filepath.Join(dst, fd.Name())
+
+ if fd.IsDir() {
+ if err = copyDir(srcfp, dstfp); err != nil {
+ return fmt.Errorf("copy dir: %w", err)
+ }
+ } else {
+ if err = copyFile(srcfp, dstfp); err != nil {
+ return fmt.Errorf("copy file: %w", err)
+ }
+ }
+ }
+ return nil
+}
+
+func installHelmContent(workingDir string, stampedChartContent string, stampedValuesContent string, templatesManifest string, addFiles addFiles, crdsManifest string, depsManifest string) error {
err := os.MkdirAll(workingDir, 0700)
if err != nil {
return fmt.Errorf("Error creating working directory %s: %w", workingDir, err)
@@ -635,6 +726,23 @@ func installHelmContent(workingDir string, stampedChartContent string, stampedVa
}
}
+ // Copy all additional files
+ for _, addFile := range addFiles {
+ dst := filepath.Join(workingDir, addFile.dst)
+ srcStat, err := os.Stat(addFile.src)
+ if err != nil {
+ return fmt.Errorf("stat: %w", err)
+ }
+ if srcStat.IsDir() {
+ err = copyDir(addFile.src, dst)
+ } else {
+ err = copyFileToDir(addFile.src, dst)
+ }
+ if err != nil {
+ return fmt.Errorf("copy %s to %s: %w", addFile.src, dst, err)
+ }
+ }
+
// Copy over any dependency chart files
if len(depsManifest) > 0 {
manifestContent, err := os.ReadFile(depsManifest)
@@ -801,7 +909,7 @@ func main() {
// Create a directory in which to run helm package
tmpPath := filepath.Join(dir, chart.Name)
- err = installHelmContent(tmpPath, stampedChartContent, stampedValuesContent, args.TemplatesManifest, args.CrdsManifest, args.DepsManifest)
+ err = installHelmContent(tmpPath, stampedChartContent, stampedValuesContent, args.TemplatesManifest, args.AddFiles, args.CrdsManifest, args.DepsManifest)
if err != nil {
log.Fatal(err)
}
diff --git a/tests/simple/BUILD.bazel b/tests/simple/BUILD.bazel
index 6c584c6..88b61ac 100644
--- a/tests/simple/BUILD.bazel
+++ b/tests/simple/BUILD.bazel
@@ -1,8 +1,26 @@
load("//helm:defs.bzl", "helm_chart", "helm_lint_test", "helm_template_test")
+genrule(
+ name = "generated",
+ outs = ["generated_file"],
+ cmd = "echo 'generated file' > $@",
+)
+
helm_chart(
name = "simple",
chart = "Chart.yaml",
+ files = {
+ "": [
+ "other_files/file1",
+ "other_files/file2",
+ ":generated",
+ ],
+ "folder1": [
+ "other_files/file1",
+ "other_files/file2",
+ ":generated",
+ ],
+ },
registry_url = "oci://localhost/helm-registry",
values = "values.yaml",
)
diff --git a/tests/simple/other_files/file1 b/tests/simple/other_files/file1
new file mode 100644
index 0000000..f81fce0
--- /dev/null
+++ b/tests/simple/other_files/file1
@@ -0,0 +1 @@
+this is a file
diff --git a/tests/simple/other_files/file2 b/tests/simple/other_files/file2
new file mode 100644
index 0000000..77d8517
--- /dev/null
+++ b/tests/simple/other_files/file2
@@ -0,0 +1 @@
+This is another file