Skip to content

Commit

Permalink
Add an aspect to figure out the repository name of container images (#43
Browse files Browse the repository at this point in the history
)

Co-authored-by: Andre Brisco <[email protected]>
  • Loading branch information
freeformstu and abrisco authored Jan 18, 2024
1 parent 493c9a0 commit 166b9fd
Show file tree
Hide file tree
Showing 7 changed files with 404 additions and 249 deletions.
2 changes: 1 addition & 1 deletion MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ bazel_dep(name = "platforms", version = "0.0.5")
bazel_dep(name = "bazel_skylib", version = "1.4.2")
bazel_dep(name = "stardoc", version = "0.6.2", repo_name = "io_bazel_stardoc")
bazel_dep(name = "rules_go", version = "0.39.1", repo_name = "io_bazel_rules_go")
bazel_dep(name = "rules_oci", version = "1.2.0")
bazel_dep(name = "rules_oci", version = "1.6.0")

# This is unfortunately requried by `rules_oci`.
bazel_dep(name = "aspect_bazel_lib", version = "1.34.0")
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ A rule for performing `helm lint` on a helm package
helm_package(<a href="#helm_package-name">name</a>, <a href="#helm_package-deps">deps</a>, <a href="#helm_package-chart">chart</a>, <a href="#helm_package-chart_json">chart_json</a>, <a href="#helm_package-images">images</a>, <a href="#helm_package-stamp">stamp</a>, <a href="#helm_package-templates">templates</a>, <a href="#helm_package-values">values</a>, <a href="#helm_package-values_json">values_json</a>)
</pre>


Rules for creating Helm chart packages.

**ATTRIBUTES**

Expand All @@ -155,7 +155,7 @@ helm_package(<a href="#helm_package-name">name</a>, <a href="#helm_package-deps"
| <a id="helm_package-deps"></a>deps | Other helm packages this package depends on. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="helm_package-chart"></a>chart | The `Chart.yaml` file of the helm chart | <a href="https://bazel.build/concepts/labels">Label</a> | optional | `None` |
| <a id="helm_package-chart_json"></a>chart_json | A json encoded string to use as the `Chart.yaml` file of the helm chart | String | optional | `""` |
| <a id="helm_package-images"></a>images | [@rules_oci//oci:defs.bzl%oci_push](https://github.com/bazel-contrib/rules_oci/blob/main/docs/push.md#oci_push_rule-remote_tags) targets. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="helm_package-images"></a>images | A list of [oci_push](https://github.com/bazel-contrib/rules_oci/blob/main/docs/push.md#oci_push_rule-remote_tags) targets. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="helm_package-stamp"></a>stamp | Whether to encode build information into the helm actions. Possible values:<br><br>- `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.<br><br>- `stamp = 0`: Always replace build information by constant values. This gives good build result caching.<br><br>- `stamp = -1`: Embedding of build information is controlled by the [--[no]stamp](https://docs.bazel.build/versions/main/user-manual.html#flag--stamp) flag.<br><br>Stamped targets are not rebuilt unless their dependencies change. | Integer | optional | `-1` |
| <a id="helm_package-templates"></a>templates | All templates associated with the current helm chart. E.g., the `./templates` directory | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="helm_package-values"></a>values | The `values.yaml` file for the current package. This attribute is mutally exclusive with `values_json`. | <a href="https://bazel.build/concepts/labels">Label</a> | optional | `None` |
Expand Down
6 changes: 3 additions & 3 deletions WORKSPACE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

http_archive(
name = "rules_oci",
sha256 = "176e601d21d1151efd88b6b027a24e782493c5d623d8c6211c7767f306d655c8",
strip_prefix = "rules_oci-1.2.0",
url = "https://github.com/bazel-contrib/rules_oci/releases/download/v1.2.0/rules_oci-v1.2.0.tar.gz",
sha256 = "58b7a175ee90c12583afeca388523adf6a4e5a0528f330b41c302b91a4d6fc06",
strip_prefix = "rules_oci-1.6.0",
url = "https://github.com/bazel-contrib/rules_oci/releases/download/v1.6.0/rules_oci-v1.6.0.tar.gz",
)

load("@rules_oci//oci:dependencies.bzl", "rules_oci_dependencies")
Expand Down
106 changes: 78 additions & 28 deletions helm/private/helm_package.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,48 @@
load("//helm:providers.bzl", "HelmPackageInfo")
load("//helm/private:helm_utils.bzl", "is_stamping_enabled")

OciPushRepositoryInfo = provider(
doc = "Repository and image information for a given oci_push target",
fields = {
"image_root": "File: The directory containing the image files for the oci_push target",
"repository_file": "File: The file containing the repository path for the oci_push target",
},
)

def _oci_push_repository_aspect_impl(target, ctx):
if hasattr(ctx.rule.attr, "repository") and ctx.rule.attr.repository:
output = ctx.actions.declare_file("{}.rules_helm.repository.txt".format(target.label.name))
ctx.actions.write(
output = output,
content = ctx.rule.attr.repository,
)
elif hasattr(ctx.rule.file, "repository_file") and ctx.rule.file.repository_file:
output = ctx.rule.file.repository_file
else:
fail("oci_push target {} must have a `repository` attribute or a `repository_file` file".format(
target.label,
))

if not hasattr(ctx.rule.file, "image"):
fail("oci_push target {} must have an `image` attribute".format(
target.label,
))

return [OciPushRepositoryInfo(
repository_file = output,
image_root = ctx.rule.file.image,
)]

# This aspect exists because rules_oci seems reluctant to create a provider
# that cleanly publishes this information but for the helm rules, it's
# absolutely necessary that an image's repository and digest are knowable.
# If rules_oci decides to define their own provider for this (which they should)
# then this should be deleted in favor of that.
_oci_push_repository_aspect = aspect(
doc = "Provides the repository and image_root for a given oci_push target",
implementation = _oci_push_repository_aspect_impl,
)

def _render_json_to_yaml(ctx, name, inline_content):
target_file = ctx.actions.declare_file("{}/{}.yaml".format(
name,
Expand Down Expand Up @@ -91,34 +133,38 @@ def _helm_package_impl(ctx):

# Create documents for each image the package depends on
image_inputs = []
if ctx.attr.images:
single_image_manifests = []
for image in ctx.attr.images:
single_image_manifest = ctx.actions.declare_file("{}/{}".format(
ctx.label.name,
str(image.label).strip("@").replace("/", "_").replace(":", "_") + ".image_manifest",
))
push_info = image[DefaultInfo]
ctx.actions.write(
output = single_image_manifest,
content = json.encode_indent(
struct(
label = str(image.label),
paths = [manifest.path for manifest in push_info.default_runfiles.files.to_list()],
),
),
)
image_inputs.extend(push_info.default_runfiles.files.to_list())
single_image_manifests.append(single_image_manifest)

image_manifest = ctx.actions.declare_file("{}/image_manifest.json".format(ctx.label.name))
single_image_manifests = []
for image in ctx.attr.images:
image_inputs.extend([
image[OciPushRepositoryInfo].repository_file,
image[OciPushRepositoryInfo].image_root,
])
single_image_manifest = ctx.actions.declare_file("{}/{}".format(
ctx.label.name,
str(image.label).strip("@").replace("/", "_").replace(":", "_") + ".image_manifest",
))
push_info = image[DefaultInfo]
ctx.actions.write(
output = image_manifest,
content = json.encode_indent([manifest.path for manifest in single_image_manifests], indent = " " * 4),
output = single_image_manifest,
content = json.encode_indent(
struct(
label = str(image.label),
repository_path = image[OciPushRepositoryInfo].repository_file.path,
image_root_path = image[OciPushRepositoryInfo].image_root.path,
),
),
)
image_inputs.append(image_manifest)
image_inputs.extend(single_image_manifests)
args.add("-image_manifest", image_manifest)
image_inputs.extend(push_info.default_runfiles.files.to_list())
single_image_manifests.append(single_image_manifest)

image_manifest = ctx.actions.declare_file("{}/image_manifest.json".format(ctx.label.name))
ctx.actions.write(
output = image_manifest,
content = json.encode_indent([manifest.path for manifest in single_image_manifests], indent = " " * 4),
)
image_inputs.append(image_manifest)
image_inputs.extend(single_image_manifests)
args.add("-image_manifest", image_manifest)
stamps = []
if is_stamping_enabled(ctx.attr):
args.add("-volatile_status_file", ctx.version_file)
Expand Down Expand Up @@ -155,7 +201,7 @@ def _helm_package_impl(ctx):

helm_package = rule(
implementation = _helm_package_impl,
doc = "",
doc = "Rules for creating Helm chart packages.",
attrs = {
"chart": attr.label(
doc = "The `Chart.yaml` file of the helm chart",
Expand All @@ -169,7 +215,11 @@ helm_package = rule(
providers = [HelmPackageInfo],
),
"images": attr.label_list(
doc = "[@rules_oci//oci:defs.bzl%oci_push](https://github.com/bazel-contrib/rules_oci/blob/main/docs/push.md#oci_push_rule-remote_tags) targets.",
doc = """\
A list of \
[oci_push](https://github.com/bazel-contrib/rules_oci/blob/main/docs/push.md#oci_push_rule-remote_tags) \
targets.""",
aspects = [_oci_push_repository_aspect],
),
"stamp": attr.int(
doc = """\
Expand Down
6 changes: 6 additions & 0 deletions helm/private/json_to_yaml/json_to_yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"flag"
"log"
"os"
"path"

"gopkg.in/yaml.v3"
)
Expand All @@ -31,6 +32,11 @@ func main() {
log.Fatal(err)
}

err = os.MkdirAll(path.Dir(*output), 0755)
if err != nil {
log.Fatal(err)
}

err = os.WriteFile(*output, []byte(yaml_content), 0644)
if err != nil {
log.Fatal(err)
Expand Down
Loading

0 comments on commit 166b9fd

Please sign in to comment.