Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ indent_style = tab
indent_style = space
indent_size = 2

# Non-standard config for shfmt
[[shell]]
indent_style = space
indent_size = 2
simplify = true

[*.py]
indent_style = space
indent_size = 4
Expand Down
53 changes: 30 additions & 23 deletions mise.devbase.lock

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

4 changes: 2 additions & 2 deletions mise.devbase.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ buf = "1.60.0"
go-jsonnet = "0.19.1"
gofumpt = "0.9.2"
golangci-lint = "2.9.0"
kubeconform = "0.6.4"
kubeconform = "0.8.0"
shellcheck = "0.11.0"
shfmt = "3.7.0"
shfmt = "3.13.1"
terraform = "1.4.4"
tombi = "0.7.27"
"github:getoutreach/kubecfg" = "0.34.0"
Expand Down
2 changes: 1 addition & 1 deletion orbs/shared/executors/testbed-machine.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
description: Standard executor for machine runtimes
machine:
image: ubuntu-2404:2026.05.1
image: ubuntu-2404:current
docker_layer_caching: true
environment:
TEST_RESULTS: /tmp/test-results
Expand Down
22 changes: 9 additions & 13 deletions shell/build-jsonnet.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,19 @@ source "$SCRIPTS_DIR/lib/box.sh"
# shellcheck source=./lib/docker.sh
source "$SCRIPTS_DIR/lib/docker.sh"

# shellcheck source=./lib/git_cache.sh
source "$SCRIPTS_DIR/lib/git_cache.sh"

# shellcheck source=./lib/mise/stub.sh
source "$SCRIPTS_DIR/lib/mise/stub.sh"

# Cache a local copy of the `jsonnet-libs` directory on disk if it doesn't yet exist. Do this
# because it helps us avoid accessing jsonnet-libs via raw.githubusercontent.com, which has
# aggressive rate limits that we can easily hit. Estimated API usage reduction is +10x since before
# we'd make 1 request per file (15+ *sonnet files), now we clone at most once per run.
JSONNET_LIBS_REPO="$HOME/.outreach/.cache/jsonnet-libs"

if [[ -d $JSONNET_LIBS_REPO ]]; then
pushd "$JSONNET_LIBS_REPO" >/dev/null || fatal "Could not find jsonnet-libs cache dir"
git pull --quiet
popd >/dev/null || fatal "Could not change directory out of jsonnet-libs cache dir"
else
mkdir -p "$(dirname "$JSONNET_LIBS_REPO")"
git clone --quiet --single-branch git@github.com:getoutreach/jsonnet-libs "$JSONNET_LIBS_REPO" >/dev/null
fi
# aggressive rate limits that we can easily hit. cache_git_repo clones the repo once and then
# refreshes it with a shallow fetch on later runs, instead of one request per file (15+ *sonnet
# files) as before.
info "Caching jsonnet-libs" >&2
jsonnetLibsCacheDir="$(cache_git_repo https://github.com/getoutreach/jsonnet-libs)"

action=$1

Expand All @@ -46,7 +42,7 @@ email="${DEV_EMAIL:-$(git config user.email || echo 'devbase@outreach.io')}"
appImageRegistry="${DEVENV_DEPLOY_IMAGE_REGISTRY:-"$(get_docker_pull_registry)"}"

mise_exec_tool_with_bin github:getoutreach/kubecfg kubecfg \
--jpath "$JSONNET_LIBS_REPO" \
--jpath "$jsonnetLibsCacheDir" \
--jurl http://k8s-clusters.outreach.cloud/ \
-n "$namespace" \
--context "dev-environment" "$action" "$(get_repo_directory)/$jsonnetSourcePath/$jsonnetManifestPath" \
Expand Down
51 changes: 51 additions & 0 deletions shell/kubeconform.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/usr/bin/env bash
# This is a wrapper around mise to run kubeconform.
# Useful for using the correct version of kubeconform
# with your editor, with the correct cache.
set -euo pipefail

DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"

# shellcheck source=./lib/git_cache.sh
source "$DIR/lib/git_cache.sh"

# shellcheck source=./lib/mise/stub.sh
source "$DIR/lib/mise/stub.sh"

# The Kubernetes version we validate against. Owned here (not passed in by
# callers) so we can both cache the matching schemas and tell kubeconform
# which version to use.
k8sVersion="$(get_tool_version kubernetes)"
# get_tool_version prints "null" when the key is missing. Guard against it:
# an unset version would cache non-existent "vnull-standalone" dirs and, with
# -ignore-missing-schemas, silently skip all validation while reporting green.
if [[ -z $k8sVersion || $k8sVersion == "null" ]]; then
fatal "Could not determine the kubernetes version from versions.yaml"
fi

# Do not add default to this list. Verified in v0.8.0, the magic
# "default" value adds the raw.githubusercontent.com URL template for
# kubernetes-json-schema, which is rate limited by GitHub.
schemaLocations=()

# Cache the kubernetes-json-schema repo. Pass the repo root as the schema
# location (no .json template): for a bare directory, kubeconform appends
# v<version>-standalone{-strict}/<kind>.json itself. Sparse-checkout only the
# version directories we need, since the full repo is multiple GB.
info "Schema cache: Kubernetes" >&2
k8sCacheDir="$(cache_git_repo https://github.com/yannh/kubernetes-json-schema kubeconform \
"v${k8sVersion}-standalone" "v${k8sVersion}-standalone-strict")"
schemaLocations+=("$k8sCacheDir")

# Cache the CRDs catalog. It is small (~20 MB), so clone it in full and use
# its explicit path template.
info "Schema cache: CRDs catalog" >&2
crdCacheDir="$(cache_git_repo https://github.com/datreeio/CRDs-catalog kubeconform)"
schemaLocations+=("$crdCacheDir/{{ .Group }}/{{ .ResourceKind }}_{{ .ResourceAPIVersion }}.json")

args=(-kubernetes-version "$k8sVersion")
for location in "${schemaLocations[@]}"; do
args+=(-schema-location "$location")
done

mise_exec_tool kubeconform "${args[@]}" "$@"
84 changes: 84 additions & 0 deletions shell/lib/git_cache.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#!/usr/bin/env bash

DEVBASE_CACHE_DIR="$HOME/.outreach/.cache"

# cache_git_repo <gitURL> [cacheSubdir] [sparsePath...]
#
# Cache the given git repository URL to avoid using
# raw.githubusercontent.com URLs, which are rate limited by GitHub.
# For network/space reasons, this uses a shallow checkout.
#
# If specified, cacheSubdir namespaces the cached git repo.
#
# If one or more sparsePath arguments are given, only those top-level
# paths are materialized (via a blobless, sparse checkout). This avoids
# checking out enormous repositories in full when only a few directories
# are needed.
#
# Prints out the cache directory path.
#
# Assumes that logging.sh is sourced. (Logs are sent to stderr.)
cache_git_repo() {
local gitURL="$1"
local cacheSubdir="${2:-}"
# Drop the two leading positional args so "$@" is just the sparse paths.
# `shift 2` fails when fewer than two args were passed (e.g. a caller that
# omits cacheSubdir), so fall back to shifting whatever is present.
shift 2 || shift $#
local sparsePaths=("$@")

# Derive the cache dir name from the repo's last path segment. Normalize a
# trailing slash and a ".git" suffix first so equivalent URLs map to the
# same name. Callers caching repos whose last segment could collide must
# pass distinct cacheSubdir values to disambiguate them.
local cacheDir cacheBasename normalizedURL="${gitURL%/}"
cacheBasename="$(basename "${normalizedURL%.git}")"
if [[ -n $cacheSubdir ]]; then
cacheDir="$DEVBASE_CACHE_DIR/$cacheSubdir/$cacheBasename"
else
cacheDir="$DEVBASE_CACHE_DIR/$cacheBasename"
fi

# True if every requested sparse path is present and non-empty. A blobless
# sparse checkout can leave a path unmaterialized after a failed fetch.
_sparse_paths_materialized() {
local path
for path in "${sparsePaths[@]}"; do
[[ -n "$(find "$cacheDir/$path" -type f -print -quit 2>/dev/null)" ]] || return 1
done
}

if [[ -d $cacheDir ]] && git -C "$cacheDir" rev-parse --git-dir >/dev/null 2>&1; then
info_sub "Updating local cache" >&2
# A usable checkout already exists; tolerate a transient refresh failure.
if ! { git -C "$cacheDir" fetch --depth 1 &&
git -C "$cacheDir" reset --hard -q origin/HEAD; }; then
warn "Could not refresh cache at $cacheDir; using the existing checkout" >&2
fi
if [[ ${#sparsePaths[@]} -gt 0 ]]; then
# Local re-apply; tolerate failure so a blip cannot abort a usable cache.
if ! git -C "$cacheDir" sparse-checkout set "${sparsePaths[@]}"; then
warn "Could not update sparse paths at $cacheDir; using the existing checkout" >&2
fi
# A cache missing its schemas would let -ignore-missing-schemas pass
# vacuously; fail loudly instead.
if ! _sparse_paths_materialized; then
fatal "Cache at $cacheDir is missing requested paths: ${sparsePaths[*]}"
fi
fi
else
# A leftover directory that is not a healthy git repo (e.g. an
# interrupted clone) is treated as a cache miss: remove it and re-clone.
[[ -d $cacheDir ]] && rm -rf "$cacheDir"
info_sub "Setting up local cache" >&2
if [[ ${#sparsePaths[@]} -gt 0 ]]; then
git clone --depth 1 --single-branch --filter=blob:none --sparse \
"$gitURL" "$cacheDir"
git -C "$cacheDir" sparse-checkout set "${sparsePaths[@]}"
else
git clone --depth 1 --single-branch "$gitURL" "$cacheDir"
fi
fi

echo "$cacheDir"
}
Loading