Skip to content

Commit

Permalink
feat: use headers attribute if available
Browse files Browse the repository at this point in the history
  • Loading branch information
thesayyn committed Mar 25, 2024
1 parent 6fb3b7b commit 5d0393a
Show file tree
Hide file tree
Showing 13 changed files with 442 additions and 296 deletions.
2 changes: 1 addition & 1 deletion .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ common --enable_bzlmod
common --lockfile_mode=off

# Required for rules_apko to make range requests
try-import %workspace%/.apko/.bazelrc


# Load any settings specific to the current user.
# .bazelrc.user should appear in .gitignore so that settings are not shared with team members
Expand Down
2 changes: 1 addition & 1 deletion .bazelversion
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
6.3.0
7.1.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.
Expand Down
92 changes: 79 additions & 13 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,83 @@ concurrency:
cancel-in-progress: true

jobs:
# matrix-prep-* steps generate JSON used to create a dynamic actions matrix.
# Inspired from
# https://stackoverflow.com/questions/65384420/how-to-make-a-github-action-matrix-element-conditional

matrix-prep-os:
# Prepares the 'os' axis of the test matrix, to reduce costs since GitHub hosted runners cost more on some platforms.
# https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions#included-storage-and-minutes
runs-on: ubuntu-latest
steps:
- id: linux
run: echo "os=ubuntu-latest" >> $GITHUB_OUTPUT
- id: windows
run: echo "os=windows-latest" >> $GITHUB_OUTPUT
# Only run on main branch (or PR branches that contain 'windows') to minimize Windows minutes (billed at 2X)
if: (github.ref == 'refs/heads/main' || contains(github.head_ref, 'windows')) && !inputs.exclude_windows
- id: macos
run: echo "os=macos-latest" >> $GITHUB_OUTPUT
# Only run on main branch (or PR branches that contain 'macos') to minimize macOS minutes (billed at 10X)
if: github.ref == 'refs/heads/main' || contains(github.head_ref, 'macos')
outputs:
# Will look like ["ubuntu-latest", "windows-latest", "macos-latest"]
os: ${{ toJSON(steps.*.outputs.os) }}

matrix-prep-bazelversion:
# Prepares the 'bazelversion' axis of the test matrix
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# NB: we assume this is Bazel 7
- id: bazel_from_bazelversion
run: echo "bazelversion=$(head -n 1 .bazelversion)" >> $GITHUB_OUTPUT
- id: bazel_6
run: echo "bazelversion=6.4.0" >> $GITHUB_OUTPUT
outputs:
# Will look like ["<version from .bazelversion>", "x.y.z"]
bazelversions: ${{ toJSON(steps.*.outputs.bazelversion) }}

test:
uses: bazel-contrib/.github/.github/workflows/bazel.yaml@29e53247c6366e30acbedfc767f58f79fc05836c
with:
folders: |
[
".",
"e2e/smoke"
]
exclude: |
[
{"bazelversion": "5.4.0"},
{"os": "windows-latest"},
{"os": "macos-latest"}
]
# The type of runner that the job will run on
runs-on: ${{ matrix.os }}

needs:
- matrix-prep-bazelversion
- matrix-prep-os

# Run bazel test in each workspace with each version of Bazel supported
strategy:
fail-fast: false
matrix:
os: ${{ fromJSON(needs.matrix-prep-os.outputs.os) }}
bazelversion: ${{ fromJSON(needs.matrix-prep-bazelversion.outputs.bazelversions) }}
folder:
- .
- e2e/smoke
bzlmodEnabled: [true, false]

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v4

- uses: bazel-contrib/setup-bazel@0.8.0
with:
repository-cache: true
bazelrc: |
common --announce_rc --color=yes --enable_bzlmod=${{ matrix.bzlmodEnabled }}
${{ (matrix.bazelversion == '6.4.0' && 'try-import %workspace%/.apko/.bazelrc') || '' }}
- name: Configure Bazel version
working-directory: ${{ matrix.folder }}
run: echo "${{ matrix.bazelversion }}" > .bazelversion

# See https://github.com/bazel-contrib/publish-to-bcr#including-patches
- name: verify bcr patches
if: matrix.bzlmodEnabled && hashFiles('.bcr/patches/*.patch') != ''
run: patch --dry-run -p1 < .bcr/patches/*.patch

- name: Test
working-directory: ${{ matrix.folder }}
run: bazel test //...
23 changes: 11 additions & 12 deletions .github/workflows/release_prep.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,17 @@ git archive --format=tar --prefix=${PREFIX}/ ${TAG} | gzip > $ARCHIVE
SHA=$(shasum -a 256 $ARCHIVE | awk '{print $1}')

cat << EOF
## Using Bzlmod with Bazel 6
## Initial setup (when using with Bazel < 7.1)
rules_apko requires a one-time setup to configure bazel to be able to make partial fetches.
Follow https://github.com/chainguard-dev/rules_apko/blob/main/docs/initial-setup.md for the setup.
EOF

cat << EOF
## Using Bzlmod
1. Enable with \`common --enable_bzlmod\` in \`.bazelrc\`.
2. Add to your \`MODULE.bazel\` file:
Expand All @@ -37,14 +47,3 @@ EOF

awk 'f;/--SNIP--/{f=1}' e2e/smoke/WORKSPACE.bazel
echo "\`\`\`"


cat << EOF
## Initial setup
rules_apko requires a one-time setup to configure bazel to be able to make partial fetches.
Follow https://github.com/chainguard-dev/rules_apko/blob/main/docs/initial-setup.md for the setup.
EOF
18 changes: 12 additions & 6 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,22 @@ module(
compatibility_level = 1,
)

bazel_dep(name = "bazel_skylib", version = "1.4.2")
bazel_dep(name = "platforms", version = "0.0.5")
bazel_dep(name = "aspect_bazel_lib", version = "1.34.5")
bazel_dep(name = "bazel_skylib", version = "1.5.0")
bazel_dep(name = "platforms", version = "0.0.8")
bazel_dep(name = "aspect_bazel_lib", version = "1.40.3")

# We need this fix https://github.com/aspect-build/bazel-lib/pull/713 to be able to generate docs
single_version_override(
module_name = "aspect_bazel_lib",
version = "2.5.3",
)

bazel_dep(name = "container_structure_test", version = "1.15.0", dev_dependency = True)
bazel_dep(name = "rules_pkg", version = "0.7.0", dev_dependency = True)
bazel_dep(name = "rules_oci", version = "1.3.3", dev_dependency = True)
bazel_dep(name = "gazelle", version = "0.29.0", dev_dependency = True, repo_name = "bazel_gazelle")
bazel_dep(name = "bazel_skylib_gazelle_plugin", version = "1.4.1", dev_dependency = True)
bazel_dep(name = "buildifier_prebuilt", version = "6.1.0", dev_dependency = True)
bazel_dep(name = "gazelle", version = "0.34.0", dev_dependency = True, repo_name = "bazel_gazelle")
bazel_dep(name = "bazel_skylib_gazelle_plugin", version = "1.5.0", dev_dependency = True)
bazel_dep(name = "buildifier_prebuilt", version = "6.1.2", dev_dependency = True)

toolchain = use_extension("//apko:extensions.bzl", "apko")
toolchain.toolchain(apko_version = "v0.13.1")
Expand Down
12 changes: 6 additions & 6 deletions apko/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,16 @@ bzl_library(
],
)

bzl_library(
name = "toolchain",
srcs = ["toolchain.bzl"],
visibility = ["//visibility:public"],
)

# Enables calling apko tool directly by bazel.
# To resolve given `./apko.yaml` file into `./apko.lock.json`, once can call:
# e.g. (cd ./examples/oci; bazel run @rules_apko//apko lock ./apko.yaml)
apko_run(
name = "apko",
visibility = ["//visibility:public"],
)

bzl_library(
name = "toolchain",
srcs = ["toolchain.bzl"],
visibility = ["//visibility:public"],
)
6 changes: 6 additions & 0 deletions apko/private/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,9 @@ bzl_library(
srcs = ["versions.bzl"],
visibility = ["//apko:__subpackages__"],
)

bzl_library(
name = "bazelversion",
srcs = ["bazelversion.bzl"],
visibility = ["//apko:__subpackages__"],
)
40 changes: 31 additions & 9 deletions apko/private/apk.bzl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"Repository rules for importing remote apk packages"

load(":bazelversion.bzl", "bazel_version_gte")
load(":util.bzl", "util")

APK_IMPORT_TMPL = """\
Expand All @@ -16,8 +17,10 @@ def _range(url, range):

def _check_initial_setup(rctx):
output = rctx.path(".rangecheck/output")
rctx.download(
url = [_range(rctx.attr.url, "bytes=0-0")],
_download(
rctx,
url = rctx.attr.url,
rng = "bytes=0-0",
output = output,
)
r = rctx.execute(["wc", "-c", output])
Expand All @@ -39,6 +42,19 @@ To resolve this issue and enable partial package fetching, please follow the ste
""".format(bytes[0]))

def _download(rctx, url, rng, **kwargs):
if bazel_version_gte("7.1.0"):
return rctx.download(
url = [url],
headers = {"Range": [rng]},
**kwargs
)
else:
return rctx.download(
url = [_range(url, rng)],
**kwargs
)

def _apk_import_impl(rctx):
repo = util.repo_url(rctx.attr.url, rctx.attr.architecture)
repo_escaped = util.url_escape(repo)
Expand All @@ -53,19 +69,25 @@ def _apk_import_impl(rctx):
data_output = "{}/{}.dat.tar.gz".format(output, data_sha256)
apk_output = "{}/{}/{}-{}.apk".format(repo_escaped, rctx.attr.architecture, rctx.attr.package_name, rctx.attr.version)

rctx.download(
url = [_range(rctx.attr.url, rctx.attr.signature_range)],
_download(
rctx,
url = rctx.attr.url,
rng = rctx.attr.signature_range,
output = sig_output,
# TODO: signatures does not have stable checksums. find a way to fail gracefully.
integrity = rctx.attr.signature_checksum,
# integrity = rctx.attr.signature_checksum,
)
rctx.download(
url = [_range(rctx.attr.url, rctx.attr.control_range)],
_download(
rctx,
url = rctx.attr.url,
rng = rctx.attr.control_range,
output = control_output,
integrity = rctx.attr.control_checksum,
)
rctx.download(
url = [_range(rctx.attr.url, rctx.attr.data_range)],
_download(
rctx,
url = rctx.attr.url,
rng = rctx.attr.data_range,
output = data_output,
integrity = rctx.attr.data_checksum,
)
Expand Down
45 changes: 45 additions & 0 deletions apko/private/bazelversion.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""Internal functions to parse versions."""

# Taken from https://github.com/bazel-contrib/bazel_features/blob/main/private/parse.bzl
# We can't use bazel_features because it requires two loads and macro calls in the WORKSPACE
# file but rules_apko users make one load and two macro calls where marcros exported from
# the same file which makes it not possible to add bazel_features to `repositories.bzl` file
# and load from it in the repositories.bzl file.
#
# TODO(2.0): depend on bazel_features directly by splitting the repositories.bzl file into two.
# https://github.com/chainguard-dev/rules_apko/issues/55

def _safe_int(s, v):
if not s.isdigit():
fail("invalid Bazel version '{}': non-numeric segment '{}'".format(v, s))
return int(s)

def _partition(s):
for i in range(len(s)):
c = s[i]
if c == "-":
return s[:i], s[i + 1:]
if not c.isdigit() and c != ".":
return s[:i], s[i:]
return s, ""

def parse_version(v):
"""Parses the given Bazel version string into a comparable value.
Args:
v (str): version string
Returns:
a triple ([major, minor, patch], is_released, prerelease)
"""
if not v:
# An empty string is treated as a "dev version", which is greater than anything.
v = "999999.999999.999999"
release, prerelease = _partition(v.partition(" ")[0])
segments = release.split(".")
if len(segments) != 3:
fail("invalid Bazel version '{}': got {} dot-separated segments, want 3".format(v, len(segments)))
return [_safe_int(s, v) for s in segments], not prerelease, prerelease

def bazel_version_gte(version):
return parse_version(native.bazel_version) >= parse_version(version)
2 changes: 2 additions & 0 deletions docs/initial-setup.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Initial setup

You can skip initial setup if you are using Bazel 7.1 or above.

rules_apko requires a one-time setup to configure bazel to be able to make partial fetches.

> See the issue: https://github.com/bazelbuild/bazel/issues/17829
Expand Down
Loading

0 comments on commit 5d0393a

Please sign in to comment.