diff --git a/.bazelversion b/.bazelversion index e03f32c7..58cb2b7d 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1,4 +1,4 @@ -4.2.2 +5.0.0 # The first line of this file is used by Bazelisk and Bazel to be sure # the right version of Bazel is used to build and test this repo. # This also defines which version is used on CI. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0372d11a..f246aef5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,17 +28,12 @@ jobs: # Bazelisk will download bazel to here XDG_CACHE_HOME: ~/.cache/bazel-repo run: bazel --bazelrc=.github/workflows/ci.bazelrc --bazelrc=.bazelrc test //... - - name: Rename release artifact with version - run: cp $(ls bazel-out/*/bin/*.tar.gz | tail -1) "rules_container-$(git describe --tags | sed 's/^v//').tar.gz" - # TODO: move this into bazel to produce the file with expand_template rule when it has stamping - name: Prepare workspace snippet - run: | - echo -e "WORKSPACE snippet:\n\n\`\`\`starlark\nhttp_archive(\n name = \"rules_container\"," > release_notes.txt - echo " sha256 = \"$(shasum -a 256 *.tar.gz | awk '{print $1}')\"," >> release_notes.txt - echo -e " url = \"https://github.com/thesayyn/rules_container/releases/download/$(git describe --tags)/$(ls *.tar.gz)\",\n)\n\`\`\`" >> release_notes.txt + run: .github/workflows/workspace_snippet.sh ${{ env.GITHUB_REF_NAME }} > release_notes.txt - name: Release uses: softprops/action-gh-release@v1 with: prerelease: true + # Use GH feature to populate the changelog automatically + generate_release_notes: true body_path: release_notes.txt - files: "*.tar.gz" diff --git a/.github/workflows/workspace_snippet.sh b/.github/workflows/workspace_snippet.sh new file mode 100644 index 00000000..97dc07a3 --- /dev/null +++ b/.github/workflows/workspace_snippet.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +set -o errexit -o nounset -o pipefail + +# Set by GH actions, see +# https://docs.github.com/en/actions/learn-github-actions/environment-variables#default-environment-variables +TAG=${GITHUB_REF_NAME} +PREFIX="rules_container-${TAG:1}" +SHA=$(git archive --format=tar --prefix=${PREFIX}/ ${TAG} | gzip | shasum -a 256 | awk '{print $1}') + +cat << EOF +WORKSPACE snippet: +\`\`\`starlark +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +http_archive( + name = "aspect_rules_container", + sha256 = "${SHA}", + strip_prefix = "${PREFIX}", + url = "https://github.com/aspect-build/rules_container/archive/${TAG}.tar.gz", +) + +# Fetches the rules_container dependencies. +# If you want to have a different version of some dependency, +# you should fetch it *before* calling this. +# Alternatively, you can skip calling this function, so long as you've +# already fetched all the dependencies. +load("@aspect_rules_container//container:repositoriesp.bzl", "rules_container_dependencies") +rules_container_dependencies() + +\`\`\` +EOF diff --git a/BUILD.bazel b/BUILD.bazel index 7e5124d0..e7269d17 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -1,5 +1,4 @@ load("@bazel_skylib//:bzl_library.bzl", "bzl_library") -load("@rules_pkg//:pkg.bzl", "pkg_tar") load("@bazel_gazelle//:def.bzl", "gazelle", "gazelle_binary") gazelle_binary( @@ -12,22 +11,6 @@ gazelle( gazelle = "gazelle_bin", ) -# This declares the release artifact users -pkg_tar( - name = "rules_container", - srcs = [ - "LICENSE", - "README.md", - "//container:package_content", - ], - extension = "tar.gz", - # It is all source code, so make it read-only. - mode = "0444", - # Make it owned by root so it does not have the uid of the CI robot. - owner = "0.0", - strip_prefix = ".", -) - bzl_library( name = "internal_deps", srcs = ["internal_deps.bzl"], diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4534c9b9..cc8d1a29 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -30,18 +30,15 @@ artifact or a version fetched from the internet, run this from this directory: ```sh -OVERRIDE="--override_repository=rules_container=$(pwd)/rules_container" +OVERRIDE="--override_repository=aspect_rules_container=$(pwd)/rules_container" echo "build $OVERRIDE" >> ~/.bazelrc echo "query $OVERRIDE" >> ~/.bazelrc ``` -This means that any usage of `@rules_container` on your system will point to this folder. +This means that any usage of `@aspect_rules_container` on your system will point to this folder. ## Releasing -1. Make sure your git state is at the right place (something like `git fetch; git checkout origin/main`) 1. Determine the next release version, following semver (could automate in the future from changelog) -1. `git tag -a v1.2.3` (will open an editor to put release notes) -1. `git push --tags` +1. Tag the repo and push it 1. Watch the automation run on GitHub actions -1. Update the release page with auto-generated release notes diff --git a/README.md b/README.md index 3da64c71..87f34917 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,25 @@ -# Bazel rules for container +# Bazel rules for OCI containers + +**EXPERIMENTAL** This ruleset is highly experimental and not yet fit for production use. +We might abandon it at any time, there is no guarantee of support or stability. + +This is a speculative alternative to rules_docker. + +We start from first principles and plan to avoid some pitfalls learned in maintaining that repo: + +- Use a toolchain consisting of off-the-shelf, pre-built layer and container manipulation tools. +- Don't write language-specific rules, as we cannot be experts on all languages, nor can users deal with the versioning issues + that come with dependencies we might take on the rules for those languages. +- Don't be docker-specific, now that it has a commercial license and other container runtimes exist. +- Use our toolchain hermetically: don't assume there is a docker pre-installed on the machine. +- Keep a tight complexity budget for the project so we are able to commit to effective maintenance. ## Installation -Include this in your WORKSPACE file: - -```starlark -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") -http_archive( - name = "rules_container", - url = "https://github.com/thesayyn/rules_container/releases/download/0.0.0/rules_container-0.0.0.tar.gz", - sha256 = "", -) - -load("@rules_container//container:repositories.bzl", "container_rules_dependencies") - -# This fetches the rules_container dependencies, which are: -# - bazel_skylib -# If you want to have a different version of some dependency, -# you should fetch it *before* calling this. -# Alternatively, you can skip calling this function, so long as you've -# already fetched these dependencies. -rules_container_dependencies() -``` - -> note, in the above, replace the version and sha256 with the one indicated -> in the release notes for rules_container -> In the future, our release automation should take care of this. +From the release you wish to use: +copy the WORKSPACE snippet into your `WORKSPACE` file. + +## Usage + +See the API documentation in the [docs](docs/) folder and the example usage in the [example](example/) folder. +Note that the example relies on the setup code in the `/WORKSPACE` file in the root of this repo. diff --git a/WORKSPACE b/WORKSPACE index 66552f3e..4ea4ce0f 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -1,12 +1,6 @@ # Declare the local Bazel workspace. # This is *not* included in the published distribution. -workspace( - # If your ruleset is "official" - # (i.e. is in the bazelbuild GitHub org) - # then this should just be named "rules_container" - # see https://docs.bazel.build/versions/main/skylark/deploying.html#workspace - name = "rules_container", -) +workspace(name = "aspect_rules_container") load(":internal_deps.bzl", "rules_container_internal_deps") @@ -44,14 +38,9 @@ load("@rules_pkg//:deps.bzl", "rules_pkg_dependencies") rules_pkg_dependencies() - - - - # Belongs to examples load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") - # JS http_archive( name = "aspect_rules_js", @@ -71,7 +60,7 @@ nodejs_register_toolchains( node_version = "16.9.0", ) -load("@aspect_rules_js//js:npm_import.bzl", "npm_import", "translate_package_lock") +load("@aspect_rules_js//js:npm_import.bzl", "npm_import") npm_import( integrity = "sha512-ULr0LDaEqQrMFGyQ3bhJkLsbtrQ8QibAseGZeaSUiT/6zb9IvIkomWHJIvgvwad+hinRAgsI51JcWk2yvwyL+w==", @@ -83,8 +72,8 @@ npm_import( # PYTHON http_archive( name = "rules_python", - url = "https://github.com/bazelbuild/rules_python/releases/download/0.5.0/rules_python-0.5.0.tar.gz", sha256 = "cd6730ed53a002c56ce4e2f396ba3b3be262fd7cb68339f0377a45e8227fe332", + url = "https://github.com/bazelbuild/rules_python/releases/download/0.5.0/rules_python-0.5.0.tar.gz", ) load("@rules_python//python:pip.bzl", "pip_install") @@ -92,6 +81,6 @@ load("@rules_python//python:pip.bzl", "pip_install") # Create a central external repo, @my_deps, that contains Bazel targets for all the # third-party packages specified in the requirements.txt file. pip_install( - name = "my_deps", - requirements = "//example/py:requirements.txt", -) \ No newline at end of file + name = "my_deps", + requirements = "//example/py:requirements.txt", +) diff --git a/container/private/container.bzl b/container/private/container.bzl index 1bc92b96..d6a22a3f 100644 --- a/container/private/container.bzl +++ b/container/private/container.bzl @@ -1,6 +1,7 @@ +"Implementation details for container rule" _attrs = { "base": attr.string( - mandatory = True + mandatory = True, ), # See: https://github.com/opencontainers/image-spec/blob/main/config.md#properties @@ -11,13 +12,11 @@ _attrs = { "layers": attr.label_list(), } - def _strip_external(path): return path[len("external/"):] if path.startswith("external/") else path - def _impl(ctx): - toolchain = ctx.toolchains["@rules_container//container:toolchain_type"] + toolchain = ctx.toolchains["@aspect_rules_container//container:toolchain_type"] launcher = ctx.actions.declare_file("crane.sh") @@ -62,12 +61,12 @@ set -euo pipefail arguments = [pull], outputs = [tar], executable = launcher, - progress_message = "Pulling base image and appending new layers (%s)" % ctx.attr.base + progress_message = "Pulling base image and appending new layers (%s)" % ctx.attr.base, ) # Mutate it mutate = ctx.actions.args() - resultTar = ctx.actions.declare_file("%s.tar" % ctx.label.name) + result_tar = ctx.actions.declare_file("%s.tar" % ctx.label.name) mutate.add_all([ "mutate", @@ -75,33 +74,31 @@ set -euo pipefail ctx.label.name, tar, "--output", - resultTar + result_tar, ]) if ctx.attr.entrypoint: - mutate.add_joined("--entrypoint", ctx.attr.entrypoint, join_with=",") + mutate.add_joined("--entrypoint", ctx.attr.entrypoint, join_with = ",") if ctx.attr.cmd: - mutate.add_joined("--cmd", ctx.attr.cmd, join_with=",") - + mutate.add_joined("--cmd", ctx.attr.cmd, join_with = ",") + ctx.actions.run( inputs = [tar] + toolchain.containerinfo.crane_files, arguments = [mutate], - outputs = [resultTar], + outputs = [result_tar], executable = launcher, - progress_message = "Mutating base image (%s)" % ctx.attr.base + progress_message = "Mutating base image (%s)" % ctx.attr.base, ) return [ DefaultInfo( - files = depset([resultTar]), + files = depset([result_tar]), ), ] - - container = struct( implementation = _impl, attrs = _attrs, - toolchains = ["@rules_container//container:toolchain_type"], -) \ No newline at end of file + toolchains = ["@aspect_rules_container//container:toolchain_type"], +) diff --git a/container/private/toolchains_repo.bzl b/container/private/toolchains_repo.bzl index b80cea7b..fdf3f6a5 100644 --- a/container/private/toolchains_repo.bzl +++ b/container/private/toolchains_repo.bzl @@ -84,7 +84,7 @@ def _toolchains_repo_impl(repository_ctx): # Forward all the providers def _resolved_toolchain_impl(ctx): - toolchain_info = ctx.toolchains["@rules_container//container:toolchain_type"] + toolchain_info = ctx.toolchains["@aspect_rules_container//container:toolchain_type"] return [ toolchain_info, toolchain_info.default, @@ -96,7 +96,7 @@ def _resolved_toolchain_impl(ctx): # https://cs.opensource.google/bazel/bazel/+/master:tools/jdk/java_toolchain_alias.bzl resolved_toolchain = rule( implementation = _resolved_toolchain_impl, - toolchains = ["@rules_container//container:toolchain_type"], + toolchains = ["@aspect_rules_container//container:toolchain_type"], incompatible_use_toolchain_transition = True, ) """ @@ -121,7 +121,7 @@ toolchain( exec_compatible_with = {compatible_with}, target_compatible_with = {compatible_with}, toolchain = "@{user_repository_name}_{platform}//:container_toolchain", - toolchain_type = "@rules_container//container:toolchain_type", + toolchain_type = "@aspect_rules_container//container:toolchain_type", ) """.format( platform = platform, diff --git a/container/repositories.bzl b/container/repositories.bzl index 54de381d..0574b218 100644 --- a/container/repositories.bzl +++ b/container/repositories.bzl @@ -27,6 +27,16 @@ def rules_container_dependencies(): ], ) + maybe( + http_archive, + name = "rules_pkg", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/rules_pkg/releases/download/0.5.1/rules_pkg-0.5.1.tar.gz", + "https://github.com/bazelbuild/rules_pkg/releases/download/0.5.1/rules_pkg-0.5.1.tar.gz", + ], + sha256 = "a89e203d3cf264e564fcb96b6e06dd70bc0557356eb48400ce4b5d97c2c3720d", + ) + ######## # Remaining content of the file is only used to support toolchains. ######## @@ -46,7 +56,7 @@ def _container_repo_impl(repository_ctx): integrity = TOOL_VERSIONS[repository_ctx.attr.crane_version][repository_ctx.attr.platform], ) build_content = """#Generated by container/repositories.bzl -load("@rules_container//container:toolchain.bzl", "container_toolchain") +load("@aspect_rules_container//container:toolchain.bzl", "container_toolchain") container_toolchain( name = "container_toolchain", crane = select({ diff --git a/internal_deps.bzl b/internal_deps.bzl index 95fcff71..1d0d8474 100644 --- a/internal_deps.bzl +++ b/internal_deps.bzl @@ -7,19 +7,8 @@ statement from these, that's a bug in our distribution. load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") - def rules_container_internal_deps(): "Fetch deps needed for local development" - maybe( - http_archive, - name = "rules_pkg", - urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/rules_pkg/releases/download/0.5.1/rules_pkg-0.5.1.tar.gz", - "https://github.com/bazelbuild/rules_pkg/releases/download/0.5.1/rules_pkg-0.5.1.tar.gz", - ], - sha256 = "a89e203d3cf264e564fcb96b6e06dd70bc0557356eb48400ce4b5d97c2c3720d", - ) - maybe( http_archive, name = "aspect_bazel_lib",