-
-
Notifications
You must be signed in to change notification settings - Fork 159
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
360 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
<!-- Generated with Stardoc: http://skydoc.bazel.build --> | ||
|
||
Implementation details for the push rule | ||
|
||
<a id="#oci_push"></a> | ||
|
||
## oci_push | ||
|
||
<pre> | ||
oci_push(<a href="#oci_push-name">name</a>, <a href="#oci_push-default_tags">default_tags</a>, <a href="#oci_push-image">image</a>, <a href="#oci_push-repository">repository</a>) | ||
</pre> | ||
|
||
Push an oci_image or oci_image_index to a remote registry. | ||
|
||
Pushing and tagging are performed sequentially which MAY lead to non-atomic pushes if one the following events occur; | ||
|
||
- Remote registry rejects a tag due to various reasons. eg: forbidden characters, existing tags | ||
- Remote registry closes the connection during the tagging | ||
- Local network outages | ||
|
||
In order to avoid incomplete pushes oci_push will push the image by its digest and then apply the `default_tags` sequentially at | ||
the remote registry. | ||
|
||
Any failure during pushing or tagging will be reported with non-zero exit code cause remaining steps to be skipped. | ||
|
||
|
||
Push an oci_image to docker registry with latest tag | ||
|
||
```starlark | ||
oci_image(name = "image") | ||
|
||
oci_push( | ||
image = ":image", | ||
repository = "index.docker.io/<ORG>/image", | ||
default_tags = ["latest"] | ||
) | ||
``` | ||
|
||
Push an oci_image_index to github container registry with a semver tag | ||
|
||
```starlark | ||
oci_image(name = "app_linux_arm64") | ||
|
||
oci_image(name = "app_linux_amd64") | ||
|
||
oci_image(name = "app_windows_amd64") | ||
|
||
oci_image_index( | ||
name = "app_image", | ||
images = [ | ||
":app_linux_arm64", | ||
":app_linux_amd64", | ||
":app_windows_amd64", | ||
] | ||
) | ||
|
||
oci_push( | ||
image = ":app_image", | ||
repository = "ghcr.io/<OWNER>/image", | ||
default_tags = ["0.0.0"] | ||
) | ||
``` | ||
|
||
Ideally the semver information is gathered from a vcs, like git, instead of being hardcoded to the BUILD files. | ||
However, due to nature of BUILD files being static, one has to use `-t|--tag` flag to pass the tag at runtime instead of using `default_tags`. eg. `bazel run //target:push -- --tag $(git tag)` | ||
|
||
Similary, the `repository` attribute can be overridden at runtime with the `-r|--repository` flag. eg. `bazel run //target:push -- --repository index.docker.io/<ORG>/image` | ||
|
||
|
||
**ATTRIBUTES** | ||
|
||
|
||
| Name | Description | Type | Mandatory | Default | | ||
| :------------- | :------------- | :------------- | :------------- | :------------- | | ||
| <a id="oci_push-name"></a>name | A unique name for this target. | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required | | | ||
| <a id="oci_push-default_tags"></a>default_tags | List of tags to apply to the image at remote registry. | List of strings | optional | [] | | ||
| <a id="oci_push-image"></a>image | Label to an oci_image or oci_image_index | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | optional | None | | ||
| <a id="oci_push-repository"></a>repository | Repository URL where the image will be signed at. eg: index.docker.io/<user>/image. digests and tags are disallowed. | String | required | | | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
load("//oci:defs.bzl", "oci_image", "oci_image_index", "oci_push") | ||
|
||
oci_image( | ||
name = "image", | ||
architecture = "amd64", | ||
entrypoint = ["/fail"], | ||
os = "linux", | ||
) | ||
|
||
oci_push( | ||
name = "push_image", | ||
image = ":image", | ||
repository = "index.docker.io/<ORG>/image", | ||
default_tags = ["latest"] | ||
) | ||
|
||
oci_push( | ||
name = "push_image_wo_tags", | ||
image = ":image", | ||
repository = "index.docker.io/<ORG>/image" | ||
) | ||
|
||
oci_image_index( | ||
name = "image_index", | ||
images = [ | ||
":image" | ||
] | ||
) | ||
|
||
oci_push( | ||
name = "push_image_index", | ||
image = ":image_index", | ||
repository = "index.docker.io/<ORG>/image", | ||
default_tags = ["nightly"] | ||
) | ||
|
||
|
||
sh_test( | ||
name = "test", | ||
srcs = ["test.bash"], | ||
args = [ | ||
"$(CRANE_BIN)", | ||
"$(LAUNCHER)", | ||
"$(location :push_image)", | ||
"$(location :push_image_index)", | ||
"$(location :push_image_wo_tags)" | ||
], | ||
data = [ | ||
":push_image", | ||
":push_image_index", | ||
":push_image_wo_tags", | ||
"@oci_crane_toolchains//:current_toolchain", | ||
"@oci_zot_toolchains//:current_toolchain", | ||
], | ||
toolchains = [ | ||
"@oci_crane_toolchains//:current_toolchain", | ||
"@oci_zot_toolchains//:current_toolchain", | ||
], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
#!/usr/bin/env bash | ||
set -o pipefail -o errexit -o nounset | ||
|
||
readonly CRANE="$1" | ||
readonly REGISTRY_LAUNCHER="$2" | ||
|
||
# Launch a registry instance at a random port | ||
source "${REGISTRY_LAUNCHER}" | ||
start_registry $TEST_TMPDIR $TEST_TMPDIR/output.log | ||
echo "Registry is running at ${REGISTRY}" | ||
|
||
|
||
readonly PUSH_IMAGE="$3" | ||
readonly PUSH_IMAGE_INDEX="$4" | ||
readonly PUSH_IMAGE_WO_TAGS="$5" | ||
|
||
|
||
# should push image with default tags | ||
REPOSITORY="${REGISTRY}/local" | ||
"${PUSH_IMAGE}" --repository "${REPOSITORY}" | ||
"${CRANE}" digest "$REPOSITORY:latest" | ||
|
||
# should push image_index with default tags | ||
REPOSITORY="${REGISTRY}/local-index" | ||
"${PUSH_IMAGE_INDEX}" --repository "${REPOSITORY}" | ||
"${CRANE}" digest "$REPOSITORY:nightly" | ||
|
||
|
||
# should push image without default tags | ||
REPOSITORY="${REGISTRY}/local-wo-tags" | ||
"${PUSH_IMAGE_WO_TAGS}" --repository "${REPOSITORY}" | ||
TAGS=$("${CRANE}" ls "$REPOSITORY") | ||
if [ -n "${TAGS}" ]; then | ||
echo "image is not supposed to have any tags but got" | ||
echo "${TAGS}" | ||
exit 1 | ||
fi | ||
|
||
# should push image with the --tag flag. | ||
REPOSITORY="${REGISTRY}/local-flag-tag" | ||
"${PUSH_IMAGE_WO_TAGS}" --repository "${REPOSITORY}" --tag "custom" | ||
TAGS=$("${CRANE}" ls "$REPOSITORY") | ||
if [ "${TAGS}" != "custom" ]; then | ||
echo "image is supposed to have custom tag but got" | ||
echo "${TAGS}" | ||
exit 1 | ||
fi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
"Implementation details for the push rule" | ||
|
||
_DOC = """Push an oci_image or oci_image_index to a remote registry. | ||
Pushing and tagging are performed sequentially which MAY lead to non-atomic pushes if one the following events occur; | ||
- Remote registry rejects a tag due to various reasons. eg: forbidden characters, existing tags | ||
- Remote registry closes the connection during the tagging | ||
- Local network outages | ||
In order to avoid incomplete pushes oci_push will push the image by its digest and then apply the `default_tags` sequentially at | ||
the remote registry. | ||
Any failure during pushing or tagging will be reported with non-zero exit code cause remaining steps to be skipped. | ||
Push an oci_image to docker registry with latest tag | ||
```starlark | ||
oci_image(name = "image") | ||
oci_push( | ||
image = ":image", | ||
repository = "index.docker.io/<ORG>/image", | ||
default_tags = ["latest"] | ||
) | ||
``` | ||
Push an oci_image_index to github container registry with a semver tag | ||
```starlark | ||
oci_image(name = "app_linux_arm64") | ||
oci_image(name = "app_linux_amd64") | ||
oci_image(name = "app_windows_amd64") | ||
oci_image_index( | ||
name = "app_image", | ||
images = [ | ||
":app_linux_arm64", | ||
":app_linux_amd64", | ||
":app_windows_amd64", | ||
] | ||
) | ||
oci_push( | ||
image = ":app_image", | ||
repository = "ghcr.io/<OWNER>/image", | ||
default_tags = ["0.0.0"] | ||
) | ||
``` | ||
Ideally the semver information is gathered from a vcs, like git, instead of being hardcoded to the BUILD files. | ||
However, due to nature of BUILD files being static, one has to use `-t|--tag` flag to pass the tag at runtime instead of using `default_tags`. eg. `bazel run //target:push -- --tag $(git tag)` | ||
Similary, the `repository` attribute can be overridden at runtime with the `-r|--repository` flag. eg. `bazel run //target:push -- --repository index.docker.io/<ORG>/image` | ||
""" | ||
_attrs = { | ||
"image": attr.label(allow_single_file = True, doc = "Label to an oci_image or oci_image_index"), | ||
"repository": attr.string(mandatory = True, doc = "Repository URL where the image will be signed at. eg: index.docker.io/<user>/image. digests and tags are disallowed."), | ||
"default_tags": attr.string_list(doc = "List of tags to apply to the image at remote registry."), | ||
"_push_sh_tpl": attr.label(default = "push.sh.tpl", allow_single_file = True), | ||
} | ||
|
||
def _quote_args(args): | ||
return ["\"{}\"".format(arg) for arg in args] | ||
|
||
def _impl(ctx): | ||
crane = ctx.toolchains["@contrib_rules_oci//oci:crane_toolchain_type"] | ||
jq = ctx.toolchains["@aspect_bazel_lib//lib:yq_toolchain_type"] | ||
|
||
if not ctx.file.image.is_directory: | ||
fail("image attribute must be a oci_image or oci_image_index") | ||
|
||
if ctx.attr.repository.find(":") != -1 or ctx.attr.repository.find("@") != -1: | ||
fail("repository attribute should not contain digest or tag.") | ||
|
||
fixed_args = ["--tag={}".format(tag) for tag in ctx.attr.default_tags] | ||
fixed_args.extend(["--repository", ctx.attr.repository]) | ||
|
||
executable = ctx.actions.declare_file("push_%s.sh" % ctx.label.name) | ||
ctx.actions.expand_template( | ||
template = ctx.file._push_sh_tpl, | ||
output = executable, | ||
is_executable = True, | ||
substitutions = { | ||
"{{crane_path}}": crane.crane_info.crane_path, | ||
"{{yq_path}}": jq.yqinfo.bin.short_path, | ||
"{{image_dir}}": ctx.file.image.short_path, | ||
"{{fixed_args}}": " ".join(_quote_args(fixed_args)), | ||
}, | ||
) | ||
|
||
runfiles = ctx.runfiles(files = [ctx.file.image]) | ||
runfiles = runfiles.merge(jq.default.default_runfiles) | ||
runfiles = runfiles.merge(crane.default.default_runfiles) | ||
|
||
return DefaultInfo(executable = executable, runfiles = runfiles) | ||
|
||
oci_push = rule( | ||
implementation = _impl, | ||
attrs = _attrs, | ||
doc = _DOC, | ||
executable = True, | ||
toolchains = [ | ||
"@contrib_rules_oci//oci:crane_toolchain_type", | ||
"@aspect_bazel_lib//lib:yq_toolchain_type", | ||
], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
#!/usr/bin/env bash | ||
set -o pipefail -o errexit -o nounset | ||
|
||
readonly CRANE="{{crane_path}}" | ||
readonly YQ="{{yq_path}}" | ||
readonly IMAGE_DIR="{{image_dir}}" | ||
readonly FIXED_ARGS=({{fixed_args}}) | ||
|
||
# set $@ to be FIXED_ARGS+$@ | ||
ALL_ARGS=(${FIXED_ARGS[@]} $@) | ||
set -- ${ALL_ARGS[@]} | ||
|
||
REPOSITORY="{{repository}}" | ||
TAGS=() | ||
ARGS=() | ||
|
||
while (( $# > 0 )); do | ||
case $1 in | ||
(-t|--tag) | ||
TAGS+=( "$2" ) | ||
shift | ||
shift;; | ||
(--tag=*) | ||
TAGS+=( "${1#--tag=}" ) | ||
shift;; | ||
(-r|--repository) | ||
REPOSITORY="$2" | ||
shift | ||
shift;; | ||
(--repository=*) | ||
REPOSITORY="${1#--repository=}" | ||
shift;; | ||
(*) | ||
ARGS+=( "$1" ) | ||
shift;; | ||
esac | ||
done | ||
|
||
DIGEST=$("${YQ}" eval '.manifests[0].digest' "${IMAGE_DIR}/index.json") | ||
|
||
REFS=$(mktemp) | ||
"${CRANE}" push "${IMAGE_DIR}" "${REPOSITORY}@${DIGEST}" "${ARGS[@]+"${ARGS[@]}"}" --image-refs "${REFS}" | ||
|
||
for tag in "${TAGS[@]+"${TAGS[@]}"}" | ||
do | ||
"${CRANE}" tag $(cat "${REFS}") "${tag}" | ||
done |