Skip to content

Commit

Permalink
Add support for OCI registries to helm_push (#113)
Browse files Browse the repository at this point in the history
  • Loading branch information
abrisco authored Nov 2, 2024
1 parent 8009822 commit 9b166ff
Show file tree
Hide file tree
Showing 9 changed files with 280 additions and 65 deletions.
2 changes: 1 addition & 1 deletion MODULE.bazel.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 20 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,28 +191,35 @@ Rules for creating Helm chart packages.
## helm_push

<pre>
helm_push(<a href="#helm_push-name">name</a>, <a href="#helm_push-include_images">include_images</a>, <a href="#helm_push-package">package</a>, <a href="#helm_push-registry_url">registry_url</a>)
helm_push(<a href="#helm_push-name">name</a>, <a href="#helm_push-env">env</a>, <a href="#helm_push-include_images">include_images</a>, <a href="#helm_push-login_url">login_url</a>, <a href="#helm_push-package">package</a>, <a href="#helm_push-registry_url">registry_url</a>)
</pre>

Produce an executable for performing a helm push to a registry.

Before performing `helm push` the executable produced will conditionally perform [`helm registry login`](https://helm.sh/docs/helm/helm_registry_login/)
if the following environment variables are defined:
- `HELM_REGISTRY_USERNAME`: The value of `--username`.
- `HELM_REGISTRY_PASSWORD`/`HELM_REGISTRY_PASSWORD_FILE`: The value of `--password` or a file containing the `--password` value.

**ATTRIBUTES**


| Name | Description | Type | Mandatory | Default |
| :------------- | :------------- | :------------- | :------------- | :------------- |
| <a id="helm_push-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
| <a id="helm_push-env"></a>env | Environment variables to set when running this target. | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | optional | `{}` |
| <a id="helm_push-include_images"></a>include_images | If True, images depended on by `package` will be pushed as well. | Boolean | optional | `False` |
| <a id="helm_push-login_url"></a>login_url | The URL of the registry to use for `helm login`. E.g. `my.registry.io` | String | optional | `""` |
| <a id="helm_push-package"></a>package | The helm package to push to the registry. | <a href="https://bazel.build/concepts/labels">Label</a> | required | |
| <a id="helm_push-registry_url"></a>registry_url | The URL of the registry. | String | required | |
| <a id="helm_push-registry_url"></a>registry_url | The registry URL at which to push the helm chart to. E.g. `oci://my.registry.io/chart-name` | String | required | |


<a id="helm_push_images"></a>

## helm_push_images

<pre>
helm_push_images(<a href="#helm_push_images-name">name</a>, <a href="#helm_push_images-package">package</a>)
helm_push_images(<a href="#helm_push_images-name">name</a>, <a href="#helm_push_images-env">env</a>, <a href="#helm_push_images-package">package</a>)
</pre>

Produce an executable for pushing all oci images used by a helm chart.
Expand All @@ -223,6 +230,7 @@ Produce an executable for pushing all oci images used by a helm chart.
| Name | Description | Type | Mandatory | Default |
| :------------- | :------------- | :------------- | :------------- | :------------- |
| <a id="helm_push_images-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
| <a id="helm_push_images-env"></a>env | Environment variables to set when running this target. | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | optional | `{}` |
| <a id="helm_push_images-package"></a>package | The helm package to upload images from. | <a href="https://bazel.build/concepts/labels">Label</a> | required | |


Expand All @@ -231,20 +239,27 @@ Produce an executable for pushing all oci images used by a helm chart.
## helm_push_registry

<pre>
helm_push_registry(<a href="#helm_push_registry-name">name</a>, <a href="#helm_push_registry-include_images">include_images</a>, <a href="#helm_push_registry-package">package</a>, <a href="#helm_push_registry-registry_url">registry_url</a>)
helm_push_registry(<a href="#helm_push_registry-name">name</a>, <a href="#helm_push_registry-env">env</a>, <a href="#helm_push_registry-include_images">include_images</a>, <a href="#helm_push_registry-login_url">login_url</a>, <a href="#helm_push_registry-package">package</a>, <a href="#helm_push_registry-registry_url">registry_url</a>)
</pre>

Produce an executable for performing a helm push to a registry.

Before performing `helm push` the executable produced will conditionally perform [`helm registry login`](https://helm.sh/docs/helm/helm_registry_login/)
if the following environment variables are defined:
- `HELM_REGISTRY_USERNAME`: The value of `--username`.
- `HELM_REGISTRY_PASSWORD`/`HELM_REGISTRY_PASSWORD_FILE`: The value of `--password` or a file containing the `--password` value.

**ATTRIBUTES**


| Name | Description | Type | Mandatory | Default |
| :------------- | :------------- | :------------- | :------------- | :------------- |
| <a id="helm_push_registry-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
| <a id="helm_push_registry-env"></a>env | Environment variables to set when running this target. | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | optional | `{}` |
| <a id="helm_push_registry-include_images"></a>include_images | If True, images depended on by `package` will be pushed as well. | Boolean | optional | `False` |
| <a id="helm_push_registry-login_url"></a>login_url | The URL of the registry to use for `helm login`. E.g. `my.registry.io` | String | optional | `""` |
| <a id="helm_push_registry-package"></a>package | The helm package to push to the registry. | <a href="https://bazel.build/concepts/labels">Label</a> | required | |
| <a id="helm_push_registry-registry_url"></a>registry_url | The URL of the registry. | String | required | |
| <a id="helm_push_registry-registry_url"></a>registry_url | The registry URL at which to push the helm chart to. E.g. `oci://my.registry.io/chart-name` | String | required | |


<a id="helm_toolchain"></a>
Expand Down
1 change: 0 additions & 1 deletion helm/private/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ filegroup(
srcs = glob(["**/*.bzl"]) + [
"//helm/private/packager:bzl_srcs",
"//helm/private/pusher:bzl_srcs",
"//helm/private/registrar:bzl_srcs",
"//helm/private/runner:bzl_srcs",
"//helm/private/stamp:bzl_srcs",
],
Expand Down
92 changes: 65 additions & 27 deletions helm/private/helm_registry.bzl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Helm rules"""

load("//helm:providers.bzl", "HelmPackageInfo")
load(":helm_utils.bzl", "rlocationpath")

def _get_image_push_commands(ctx, pkg_info):
image_pushers = []
Expand All @@ -9,79 +10,108 @@ def _get_image_push_commands(ctx, pkg_info):
image_pushers.append(image[DefaultInfo].files_to_run.executable)
image_runfiles.append(image[DefaultInfo].default_runfiles)

if image_pushers:
image_commands = "\n".join([pusher.short_path for pusher in image_pushers])
else:
image_commands = "echo 'No OCI images to push for Helm chart.'"

runfiles = ctx.runfiles(files = image_pushers)
for ir in image_runfiles:
runfiles = runfiles.merge(ir)
return image_commands, runfiles
return image_pushers, runfiles

def _helm_push_impl(ctx):
toolchain = ctx.toolchains[Label("//helm:toolchain_type")]

if toolchain.helm.basename.endswith(".exe"):
registrar = ctx.actions.declare_file(ctx.label.name + ".bat")
registrar = ctx.actions.declare_file(ctx.label.name + ".exe")
else:
registrar = ctx.actions.declare_file(ctx.label.name + ".sh")
registrar = ctx.actions.declare_file(ctx.label.name)

ctx.actions.symlink(
target_file = ctx.executable._registrar,
output = registrar,
is_executable = True,
)

registry_url = ctx.attr.registry_url
pkg_info = ctx.attr.package[HelmPackageInfo]

image_commands = ""
args = ctx.actions.args()
args.set_param_file_format("multiline")
args.add("-helm", rlocationpath(toolchain.helm, ctx.workspace_name))
args.add("-chart", rlocationpath(pkg_info.chart, ctx.workspace_name))
args.add("-registry_url", ctx.attr.registry_url)

if ctx.attr.login_url:
args.add("-login_url", ctx.attr.login_url)

image_runfiles = ctx.runfiles()
if ctx.attr.include_images:
image_commands, image_runfiles = _get_image_push_commands(
image_pushers, image_runfiles = _get_image_push_commands(
ctx = ctx,
pkg_info = pkg_info,
)

ctx.actions.expand_template(
template = ctx.file._registrar,
output = registrar,
substitutions = {
"{chart}": pkg_info.chart.short_path,
"{helm}": toolchain.helm.short_path,
"{image_pushers}": image_commands,
"{registry_url}": registry_url,
},
is_executable = True,
if image_pushers:
args.add("-image_pusher", ",".join([rlocationpath(p, ctx.workspace_name) for p in image_pushers]))

args_file = ctx.actions.declare_file("{}.args.txt".format(ctx.label.name))
ctx.actions.write(
output = args_file,
content = args,
)

runfiles = ctx.runfiles([registrar, toolchain.helm, pkg_info.chart]).merge(image_runfiles)
runfiles = ctx.runfiles([
registrar,
args_file,
toolchain.helm,
pkg_info.chart,
]).merge(image_runfiles)

return [
DefaultInfo(
files = depset([registrar]),
runfiles = runfiles,
executable = registrar,
),
RunEnvironmentInfo(
environment = ctx.attr.env | {
"HELM_PUSH_ARGS_FILE": rlocationpath(args_file, ctx.workspace_name),
},
),
]

helm_push = rule(
doc = "Produce an executable for performing a helm push to a registry.",
doc = """\
Produce an executable for performing a helm push to a registry.
Before performing `helm push` the executable produced will conditionally perform [`helm registry login`](https://helm.sh/docs/helm/helm_registry_login/)
if the following environment variables are defined:
- `HELM_REGISTRY_USERNAME`: The value of `--username`.
- `HELM_REGISTRY_PASSWORD`/`HELM_REGISTRY_PASSWORD_FILE`: The value of `--password` or a file containing the `--password` value.
""",
implementation = _helm_push_impl,
executable = True,
attrs = {
"env": attr.string_dict(
doc = "Environment variables to set when running this target.",
),
"include_images": attr.bool(
doc = "If True, images depended on by `package` will be pushed as well.",
default = False,
),
"login_url": attr.string(
doc = "The URL of the registry to use for `helm login`. E.g. `my.registry.io`",
),
"package": attr.label(
doc = "The helm package to push to the registry.",
providers = [HelmPackageInfo],
mandatory = True,
),
"registry_url": attr.string(
doc = "The URL of the registry.",
doc = "The registry URL at which to push the helm chart to. E.g. `oci://my.registry.io/chart-name`",
mandatory = True,
),
"_registrar": attr.label(
doc = "A process wrapper to use for performing `helm registry and helm push`.",
allow_single_file = True,
default = Label("//helm/private/registrar:template"),
executable = True,
cfg = "exec",
default = Label("//helm/private/registrar"),
),
},
toolchains = [
Expand All @@ -99,11 +129,13 @@ def _helm_push_images_impl(ctx):

pkg_info = ctx.attr.package[HelmPackageInfo]

image_commands, image_runfiles = _get_image_push_commands(
image_pushers, image_runfiles = _get_image_push_commands(
ctx = ctx,
pkg_info = pkg_info,
)

image_commands = "\n".join([file.short_path for file in image_pushers])

ctx.actions.expand_template(
template = ctx.file._pusher,
output = pusher,
Expand All @@ -121,13 +153,19 @@ def _helm_push_images_impl(ctx):
runfiles = runfiles,
executable = pusher,
),
RunEnvironmentInfo(
environment = ctx.attr.env,
),
]

helm_push_images = rule(
doc = "Produce an executable for pushing all oci images used by a helm chart.",
implementation = _helm_push_images_impl,
executable = True,
attrs = {
"env": attr.string_dict(
doc = "Environment variables to set when running this target.",
),
"package": attr.label(
doc = "The helm package to upload images from.",
providers = [HelmPackageInfo],
Expand Down
29 changes: 8 additions & 21 deletions helm/private/registrar/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,23 +1,10 @@
package(default_visibility = ["//visibility:public"])
load("@io_bazel_rules_go//go:def.bzl", "go_binary")

exports_files([
"helm_registry.bat.template",
"helm_registry.sh.template",
])

alias(
name = "template",
actual = select({
"@platforms//os:windows": ":helm_registry.bat.template",
"//conditions:default": ":helm_registry.sh.template",
}),
)

filegroup(
name = "bzl_srcs",
srcs = glob(
["**/*.bzl"],
allow_empty = True,
),
visibility = ["//:__subpackages__"],
go_binary(
name = "registrar",
srcs = ["registrar.go"],
visibility = ["//visibility:public"],
deps = [
"@io_bazel_rules_go//go/runfiles",
],
)
4 changes: 0 additions & 4 deletions helm/private/registrar/helm_registry.bat.template

This file was deleted.

6 changes: 0 additions & 6 deletions helm/private/registrar/helm_registry.sh.template

This file was deleted.

Loading

0 comments on commit 9b166ff

Please sign in to comment.