diff --git a/.changeset/tough-clouds-drive.md b/.changeset/tough-clouds-drive.md new file mode 100644 index 000000000..72ed6f4d0 --- /dev/null +++ b/.changeset/tough-clouds-drive.md @@ -0,0 +1,6 @@ +--- +"build-push-docker": minor +"ctf-build-image": minor +--- + +Adds buildkit-cache-dance to properly, persistently cache docker build layers in CI diff --git a/actions/build-push-docker/README.md b/actions/build-push-docker/README.md index bb91c1ad3..63d851cc8 100644 --- a/actions/build-push-docker/README.md +++ b/actions/build-push-docker/README.md @@ -28,8 +28,12 @@ multi-platform manifest from per-arch builds. | `docker-push` | no | `true` | Push the built image. Set to `false` for a build-only (no push) run. | | `tags` | no | `type=sha,prefix=pr=,event=pr` / `type=ref,event=tag` | Tag spec consumed by [docker/metadata-action](https://github.com/docker/metadata-action). | | `allow-overwrites` | no | `true` | When `false`, the action fails before building if any computed tag already exists in ECR. Useful for pseudo-immutability on public ECRs (which don't support native immutability) or as a fast-fail guard on private immutable ECRs. Ignored when `docker-push` is `false`. | -| `docker-restore-cache` | no | `false` | Restore the Docker layer cache before building. | -| `docker-save-cache` | no | `false` | Save the Docker layer cache after building. | +| `cache-mode` | no | `auto` | Caching mode preset: `auto` (default: save on push/schedule, restore on PRs), `read-write`, `read-only`, `write-only`, or `off`. | +| `cache-map` | no | — | JSON string mapping cache mount paths for `buildkit-cache-dance` (e.g. `'{"go-mod-cache": "/go/pkg/mod"}'`). Passing a non-empty `cache-map` automatically enables `buildkit-cache-dance`. | +| `cache-dance` | no | — | _(Deprecated)_ Explicitly enable/disable `buildkit-cache-dance`. Inferred automatically if `cache-map` is set. | +| `cache-dance-cache-map` | no | — | _(Deprecated)_ Alias for `cache-map`. | +| `docker-restore-cache` | no | `false` | _(Deprecated override)_ Restore the Docker layer cache before building. | +| `docker-save-cache` | no | `false` | _(Deprecated override)_ Save the Docker layer cache after building. | | `docker-build-cache-from` | no | GHA cache scoped to OS/arch | Override the cache source. Effective only when `docker-restore-cache` is `true`. | | `docker-build-cache-to` | no | GHA cache scoped to OS/arch | Override the cache destination. Effective only when `docker-save-cache` is `true`. | | `docker-attestations` | no | `true` | Generate SBOM and provenance attestations. See [Docker docs](https://docs.docker.com/build/ci/github-actions/attestations/). | diff --git a/actions/build-push-docker/action.yml b/actions/build-push-docker/action.yml index 6a7465f73..41d6e5781 100644 --- a/actions/build-push-docker/action.yml +++ b/actions/build-push-docker/action.yml @@ -123,6 +123,29 @@ inputs: Defaults to `true` for backwards compatibility. Ignored when inputs.docker-push is false. required: false default: "true" + cache-mode: + description: | + Caching mode preset: "auto" (default), "read-write", "read-only", "write-only", or "off". + required: false + default: "auto" + cache-map: + description: | + JSON string mapping cache mount paths/names for buildkit-cache-dance (e.g. '{"go-mod-cache": "/go/pkg/mod"}'). + Passing a non-empty cache-map automatically enables buildkit-cache-dance. + See: https://github.com/reproducible-containers/buildkit-cache-dance + See: https://docs.docker.com/build/ci/github-actions/cache/#cache-mounts + required: false + default: "" + cache-dance: + description: | + Deprecated: Explicitly enable/disable buildkit-cache-dance. If unset, cache-dance is automatically enabled when cache-map is provided. + required: false + default: "" + cache-dance-cache-map: + description: | + Deprecated alias for cache-map. + required: false + default: "" outputs: docker-repository-name: @@ -172,6 +195,16 @@ runs: exit 1 fi + - name: Validate cache-dance configuration + id: validate-cache-dance + shell: bash + env: + ACTION_PATH: ${{ github.action_path }} + CACHE_DANCE: ${{ inputs.cache-dance }} + CACHE_MAP: ${{ inputs.cache-map || inputs.cache-dance-cache-map }} + run: | + "${ACTION_PATH}/scripts/validate-cache-dance-config.sh" >> "$GITHUB_OUTPUT" + - name: Check runner arch and platform compatibility shell: bash env: @@ -361,6 +394,15 @@ runs: echo "no-cache=false" | tee -a "${GITHUB_OUTPUT}" echo "cache-from=${CACHE_FROM}" | tee -a "${GITHUB_OUTPUT}" + # Persist BuildKit RUN --mount=type=cache directories across GHA runs + # See: https://github.com/reproducible-containers/buildkit-cache-dance + # See: https://docs.docker.com/build/ci/github-actions/cache/#cache-mounts + - name: Cache Dance + if: ${{ steps.validate-cache-dance.outputs.cache-dance == 'true' }} + uses: reproducible-containers/buildkit-cache-dance@5422eac04292c961a382e0f584ea0f03ad9da723 # v3.4.0 + with: + cache-map: ${{ steps.validate-cache-dance.outputs.cache-map }} + - name: Build & push image id: build-image uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 diff --git a/actions/build-push-docker/scripts/test-cache-dance-config.sh b/actions/build-push-docker/scripts/test-cache-dance-config.sh new file mode 100755 index 000000000..2ae0784c0 --- /dev/null +++ b/actions/build-push-docker/scripts/test-cache-dance-config.sh @@ -0,0 +1,58 @@ +#!/bin/bash +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +VALIDATE_SCRIPT="${SCRIPT_DIR}/validate-cache-dance-config.sh" + +echo "===== Testing build-push-docker cache dance configuration (Option 1) =====" + +parse_val() { + local output="$1" + local key="$2" + echo "$output" | grep "^${key}=" | cut -d'=' -f2 +} + +echo "Test 1: Default - no cache-dance and no cache-map" +RES=$("$VALIDATE_SCRIPT" "" "") +DANCE=$(parse_val "$RES" "cache-dance") +[ "$DANCE" = "false" ] || (echo "FAIL: expected cache-dance=false, got $DANCE" && exit 1) +echo "Test 1 passed." + +echo "Test 2: Implicit enable - cache-map provided without explicit cache-dance flag" +VALID_MAP='{"go-mod-cache": "/go/pkg/mod"}' +RES=$("$VALIDATE_SCRIPT" "" "$VALID_MAP") +DANCE=$(parse_val "$RES" "cache-dance") +MAP=$(parse_val "$RES" "cache-map") +[ "$DANCE" = "true" ] || (echo "FAIL: expected cache-dance=true, got $DANCE" && exit 1) +[ "$MAP" = "$VALID_MAP" ] || (echo "FAIL: expected cache-map match" && exit 1) +echo "Test 2 passed." + +echo "Test 3: Invalid JSON in cache-map (should fail)" +if "$VALIDATE_SCRIPT" "" "invalid-json"; then + echo "FAIL: Expected failure when cache-map is invalid JSON" + exit 1 +else + echo "Test 3 passed (failed as expected)." +fi + +echo "Test 4: Explicit cache-dance=false overrides non-empty cache-map" +RES=$("$VALIDATE_SCRIPT" "false" "$VALID_MAP") +DANCE=$(parse_val "$RES" "cache-dance") +[ "$DANCE" = "false" ] || (echo "FAIL: expected cache-dance=false when explicitly disabled, got $DANCE" && exit 1) +echo "Test 4 passed." + +echo "Test 5: Explicit cache-dance=true with missing cache-map (should fail)" +if "$VALIDATE_SCRIPT" "true" ""; then + echo "FAIL: Expected failure when cache-dance=true with missing cache-map" + exit 1 +else + echo "Test 5 passed (failed as expected)." +fi + +echo "Test 6: Backward compatibility with CACHE_DANCE_CACHE_MAP env var" +RES=$(CACHE_DANCE_CACHE_MAP="$VALID_MAP" "$VALIDATE_SCRIPT" "" "") +DANCE=$(parse_val "$RES" "cache-dance") +[ "$DANCE" = "true" ] || (echo "FAIL: expected cache-dance=true from env var fallback, got $DANCE" && exit 1) +echo "Test 6 passed." + +echo "All cache dance configuration tests completed successfully." diff --git a/actions/build-push-docker/scripts/validate-cache-dance-config.sh b/actions/build-push-docker/scripts/validate-cache-dance-config.sh new file mode 100755 index 000000000..7af327903 --- /dev/null +++ b/actions/build-push-docker/scripts/validate-cache-dance-config.sh @@ -0,0 +1,35 @@ +#!/bin/bash +set -e + +# Validates cache-dance configuration inputs. +# Accepts positional arguments: +# $1: CACHE_DANCE ("true" | "false" | "") +# $2: CACHE_MAP (JSON string or path map) +# Or environment variables: CACHE_DANCE, CACHE_MAP, CACHE_DANCE_CACHE_MAP + +EXPLICIT_DANCE="${1:-${CACHE_DANCE}}" +CACHE_MAP="${2:-${CACHE_MAP:-${CACHE_DANCE_CACHE_MAP}}}" + +if [ -n "$CACHE_MAP" ]; then + if [ "$EXPLICIT_DANCE" = "false" ]; then + CACHE_DANCE="false" + else + CACHE_DANCE="true" + fi +else + if [ "$EXPLICIT_DANCE" = "true" ]; then + echo "::error::cache-map (or cache-dance-cache-map) input is required when cache-dance is true." + exit 1 + fi + CACHE_DANCE="false" +fi + +if [ "$CACHE_DANCE" = "true" ]; then + if ! echo "$CACHE_MAP" | jq . >/dev/null 2>&1; then + echo "::error::cache-map (or cache-dance-cache-map) must be valid JSON." + exit 1 + fi +fi + +echo "cache-dance=${CACHE_DANCE}" +echo "cache-map=${CACHE_MAP}" diff --git a/actions/ctf-build-image/README.md b/actions/ctf-build-image/README.md index 87a46f2b5..ec28e14d3 100644 --- a/actions/ctf-build-image/README.md +++ b/actions/ctf-build-image/README.md @@ -66,3 +66,9 @@ environments. If you find something broken, and need support reach out on leave this alone. - `platform` - Defaults to `linux/amd64`, use `linux/arm64` for arm-based runners. Cross-platform builds are not supported. +- `cache-mode` - Caching preset: `auto` (default: restores cache for PRs, saves + cache for default branch push/schedule events), `read-write`, `read-only`, + `write-only`, or `off`. +- `cache-map` - JSON string mapping cache mount paths for `buildkit-cache-dance` + (e.g. `'{"go-mod-cache": "/go/pkg/mod"}'`). Passing a non-empty `cache-map` + automatically enables `buildkit-cache-dance`. diff --git a/actions/ctf-build-image/action.yml b/actions/ctf-build-image/action.yml index 48e049868..e5b2ff3cc 100644 --- a/actions/ctf-build-image/action.yml +++ b/actions/ctf-build-image/action.yml @@ -123,6 +123,47 @@ inputs: on runners with sufficient disk (e.g. RunsOn with 100GB+) to save ~30-60s. default: "true" + cache-mode: + required: false + description: | + Caching mode preset: "auto" (default), "read-write", "read-only", "write-only", or "off". + If unset, defaults to "auto" (restores cache for PRs, saves cache for default branch push/schedule events). + See: https://docs.docker.com/build/ci/github-actions/cache/ + default: "auto" + + cache-map: + required: false + description: | + JSON string mapping cache mount paths/names for buildkit-cache-dance (e.g. '{"go-mod-cache": "/go/pkg/mod"}'). + Passing a non-empty cache-map automatically enables buildkit-cache-dance. + See: https://github.com/reproducible-containers/buildkit-cache-dance + See: https://docs.docker.com/build/ci/github-actions/cache/#cache-mounts + default: "" + + docker-restore-cache: + required: false + description: | + Deprecated explicit override for docker restore cache ("true" or "false"). + default: "" + + docker-save-cache: + required: false + description: | + Deprecated explicit override for docker save cache ("true" or "false"). + default: "" + + cache-dance: + required: false + description: | + Deprecated: Explicitly enable/disable buildkit-cache-dance. + default: "" + + cache-dance-cache-map: + required: false + description: | + Deprecated alias for cache-map. + default: "" + outputs: docker-image-sha-digest-amd64: description: "Docker image SHA digest for platform: amd64" @@ -148,40 +189,37 @@ runs: - name: Process plugin manifest overrides (public) shell: bash env: + ACTION_PATH: ${{ github.action_path }} PLUGIN_OVERRIDES: ${{ inputs.plugin-manifest-overrides }} PLUGINS_MANIFEST_PATH: ${{ github.workspace }}/plugins/plugins.public.yaml - ACTIONS_PATH: ${{ github.action_path }} - run: ${ACTIONS_PATH}/scripts/plugin-overrides.sh - - - name: Setup Go for dependency overrides - if: inputs.go-get-overrides != '' - uses: actions/setup-go@v7 - with: - go-version-file: go.mod - cache: false + run: | + "${ACTION_PATH}/scripts/plugin-overrides.sh" - - name: Apply go-get dependency overrides - if: inputs.go-get-overrides != '' + - name: Process Go dependency overrides shell: bash env: + ACTION_PATH: ${{ github.action_path }} GO_OVERRIDES: ${{ inputs.go-get-overrides }} run: | - set -e - while IFS= read -r line; do - [ -z "$line" ] && continue - dep="${line%%=*}" - sha="${line#*=}" - [ -z "$dep" ] || [ -z "$sha" ] && continue - echo "Overriding: github.com/smartcontractkit/${dep}@${sha}" - go get "github.com/smartcontractkit/${dep}@${sha}" - done <<< "$GO_OVERRIDES" - go mod tidy + "${ACTION_PATH}/scripts/go-get-overrides.sh" - name: Free up disk space (to avoid 'no space left on device' errors) if: inputs.free-disk-space == 'true' uses: smartcontractkit/.github/actions/free-disk-space@free-disk-space/v1 + - name: Resolve cache settings + shell: bash + id: cache-settings + env: + ACTION_PATH: ${{ github.action_path }} + CACHE_MODE: ${{ inputs.cache-mode }} + DOCKER_SAVE_CACHE_INPUT: ${{ inputs.docker-save-cache }} + DOCKER_RESTORE_CACHE_INPUT: ${{ inputs.docker-restore-cache }} + GITHUB_EVENT_NAME: ${{ github.event_name }} + run: | + "${ACTION_PATH}/scripts/resolve-cache-settings.sh" >> "$GITHUB_OUTPUT" + - name: Build push docker image id: build-image uses: smartcontractkit/.github/actions/build-push-docker@build-push-docker/v1 @@ -197,19 +235,17 @@ runs: docker-attestations: "false" docker-registry-url: ${{ inputs.docker-registry-url }} docker-repository-name: ${{ inputs.docker-repository-name }} - # only save on events which are expected to be from the default branch - docker-save-cache: - ${{ github.event_name == 'schedule' || github.event_name == 'push' }} - # dont use cache on events which are expected to be from the default branch - # this is to create a fresh cache/snapshot unpolluted by previous cache entries - docker-restore-cache: - ${{ github.event_name != 'schedule' && github.event_name != 'push' }} + docker-save-cache: ${{ steps.cache-settings.outputs.save-cache }} + docker-restore-cache: ${{ steps.cache-settings.outputs.restore-cache }} docker-build-cache-to: "type=gha,timeout=10m,mode=max,ignore-error=true,compression=zstd,compression-level=3,scope=ctf-build-image-${{ inputs.cache-scope || format('{0}-{1}', runner.os, runner.arch) }}" docker-build-cache-from: "type=gha,timeout=10m,scope=ctf-build-image-${{ inputs.cache-scope || format('{0}-{1}', runner.os, runner.arch) }}" + cache-mode: ${{ inputs.cache-mode }} + cache-map: ${{ inputs.cache-map || inputs.cache-dance-cache-map }} + cache-dance: ${{ inputs.cache-dance }} tags: type=raw,value=${{ inputs.image-tag }} aws-account-number: ${{ inputs.aws-account-number }} diff --git a/actions/ctf-build-image/scripts/go-get-overrides.sh b/actions/ctf-build-image/scripts/go-get-overrides.sh new file mode 100755 index 000000000..b4548eabe --- /dev/null +++ b/actions/ctf-build-image/scripts/go-get-overrides.sh @@ -0,0 +1,45 @@ +#!/bin/bash +set -e + +# Applies Go dependency overrides +# Env inputs: GO_OVERRIDES + +if [[ -z "${GO_OVERRIDES}" ]]; then + echo "No Go dependency overrides provided." + exit 0 +fi + +echo "Applying Go dependency overrides..." +while IFS= read -r line || [[ -n "$line" ]]; do + [[ -z "$line" ]] && continue + if [[ "$line" != *"="* ]]; then + echo "::warning::Skipping malformed override line (missing '='): ${line}" + continue + fi + + dep="${line%%=*}" + sha="${line#*=}" + [[ -z "$dep" || -z "$sha" ]] && continue + + # Qualify module name if short name provided + if [[ "$dep" != *"/"* ]]; then + module="github.com/smartcontractkit/${dep}" + else + module="${dep}" + fi + + echo "Replacing Go module: ${module} -> ${sha}" + if [[ "${DRY_RUN}" == "true" ]]; then + echo "[DRY RUN] go mod edit -replace ${module}=${sha}" + else + if [[ "$sha" == *"/"* ]]; then + go mod edit -replace "${module}=${sha}" + else + go mod edit -replace "${module}=${module}@${sha}" + fi + fi +done <<< "$GO_OVERRIDES" + +if [[ "${DRY_RUN}" != "true" ]]; then + go mod tidy +fi diff --git a/actions/ctf-build-image/scripts/plugin-overrides.sh b/actions/ctf-build-image/scripts/plugin-overrides.sh index d3b2e0878..efc9be9b5 100755 --- a/actions/ctf-build-image/scripts/plugin-overrides.sh +++ b/actions/ctf-build-image/scripts/plugin-overrides.sh @@ -1,10 +1,12 @@ #!/bin/bash set -e -# Check for dependencies +# Check for dependencies (skip in dry run if yq missing) if ! command -v yq &> /dev/null; then - echo "::error::'yq' command not found. Please install yq (https://github.com/mikefarah/yq)." - exit 1 + if [[ "${DRY_RUN}" != "true" ]]; then + echo "::error::'yq' command not found. Please install yq (https://github.com/mikefarah/yq)." + exit 1 + fi fi # Validate environment variables @@ -13,7 +15,7 @@ if [[ -z "${PLUGINS_MANIFEST_PATH}" ]]; then exit 1 fi -if [[ ! -f "$PLUGINS_MANIFEST_PATH" ]]; then +if [[ ! -f "$PLUGINS_MANIFEST_PATH" && "${DRY_RUN}" != "true" ]]; then echo "::info::Plugins manifest $PLUGINS_MANIFEST_PATH not found, skipping update." exit 0 fi @@ -34,9 +36,16 @@ while IFS= read -r line || [[ -n "$line" ]]; do plugin="${line%%=*}" sha="${line#*=}" - # Skip if SHA is empty - if [[ -z "$sha" ]]; then - echo "::warning::Empty SHA for plugin $plugin, skipping." + # Skip if line missing '=' or SHA is empty + if [[ "$line" != *"="* ]] || [[ -z "$sha" ]]; then + echo "::warning::Empty SHA or malformed override for plugin $plugin, skipping." + continue + fi + + if [[ "${DRY_RUN}" == "true" ]]; then + echo "[DRY RUN] Updating plugins manifest with $plugin@${sha}" + echo "[DRY RUN] yq eval -i '.plugins.${plugin}[0].gitRef = \"${sha}\"' \"${PLUGINS_MANIFEST_PATH}\"" + updated_plugins_manifest=true continue fi @@ -66,7 +75,9 @@ done <<< "$PLUGIN_OVERRIDES" if [[ "$updated_plugins_manifest" = true ]]; then echo "::info::Plugins manifest updated, contents:" - cat "$PLUGINS_MANIFEST_PATH" + if [[ -f "$PLUGINS_MANIFEST_PATH" ]]; then + cat "$PLUGINS_MANIFEST_PATH" + fi else echo "::info::No changes made to plugins manifest." fi diff --git a/actions/ctf-build-image/scripts/resolve-cache-settings.sh b/actions/ctf-build-image/scripts/resolve-cache-settings.sh new file mode 100755 index 000000000..1a954d6c4 --- /dev/null +++ b/actions/ctf-build-image/scripts/resolve-cache-settings.sh @@ -0,0 +1,58 @@ +#!/bin/bash +set -e + +# Resolves docker save/restore cache settings given cache-mode preset or input overrides. +# Usage: resolve-cache-settings.sh + +CACHE_MODE="${1:-${CACHE_MODE}}" +SAVE_INPUT="${2:-${DOCKER_SAVE_CACHE_INPUT}}" +RESTORE_INPUT="${3:-${DOCKER_RESTORE_CACHE_INPUT}}" +EVENT_NAME="${4:-${GITHUB_EVENT_NAME}}" + +# Default to "auto" if cache-mode is un-specified +if [ -z "$CACHE_MODE" ]; then + CACHE_MODE="auto" +fi + +if [ -n "$SAVE_INPUT" ]; then + SAVE_CACHE="$SAVE_INPUT" +else + case "$CACHE_MODE" in + read-write|write-only|true) + SAVE_CACHE="true" + ;; + read-only|off|false) + SAVE_CACHE="false" + ;; + auto|*) + if [ "$EVENT_NAME" = "schedule" ] || [ "$EVENT_NAME" = "push" ]; then + SAVE_CACHE="true" + else + SAVE_CACHE="false" + fi + ;; + esac +fi + +if [ -n "$RESTORE_INPUT" ]; then + RESTORE_CACHE="$RESTORE_INPUT" +else + case "$CACHE_MODE" in + read-write|read-only|true) + RESTORE_CACHE="true" + ;; + write-only|off|false) + RESTORE_CACHE="false" + ;; + auto|*) + if [ "$EVENT_NAME" != "schedule" ] && [ "$EVENT_NAME" != "push" ]; then + RESTORE_CACHE="true" + else + RESTORE_CACHE="false" + fi + ;; + esac +fi + +echo "save-cache=${SAVE_CACHE}" +echo "restore-cache=${RESTORE_CACHE}" diff --git a/actions/ctf-build-image/scripts/test-cache-event-overrides.sh b/actions/ctf-build-image/scripts/test-cache-event-overrides.sh new file mode 100755 index 000000000..8bc6fc310 --- /dev/null +++ b/actions/ctf-build-image/scripts/test-cache-event-overrides.sh @@ -0,0 +1,63 @@ +#!/bin/bash +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +RESOLVE_SCRIPT="${SCRIPT_DIR}/resolve-cache-settings.sh" + +echo "===== Testing ctf-build-image cache event overrides (Option 1) =====" + +parse_val() { + local output="$1" + local key="$2" + echo "$output" | grep "^${key}=" | cut -d'=' -f2 +} + +echo "Test 1: Default cache-mode=auto on push event (save=true, restore=false)" +RES=$("$RESOLVE_SCRIPT" "auto" "" "" "push") +RES_SAVE=$(parse_val "$RES" "save-cache") +RES_RESTORE=$(parse_val "$RES" "restore-cache") +[ "$RES_SAVE" = "true" ] || (echo "FAIL: expected save=true, got $RES_SAVE" && exit 1) +[ "$RES_RESTORE" = "false" ] || (echo "FAIL: expected restore=false, got $RES_RESTORE" && exit 1) +echo "Test 1 passed." + +echo "Test 2: Default cache-mode=auto on pull_request event (save=false, restore=true)" +RES=$("$RESOLVE_SCRIPT" "auto" "" "" "pull_request") +RES_SAVE=$(parse_val "$RES" "save-cache") +RES_RESTORE=$(parse_val "$RES" "restore-cache") +[ "$RES_SAVE" = "false" ] || (echo "FAIL: expected save=false, got $RES_SAVE" && exit 1) +[ "$RES_RESTORE" = "true" ] || (echo "FAIL: expected restore=true, got $RES_RESTORE" && exit 1) +echo "Test 2 passed." + +echo "Test 3: cache-mode=read-write on pull_request event (save=true, restore=true)" +RES=$("$RESOLVE_SCRIPT" "read-write" "" "" "pull_request") +RES_SAVE=$(parse_val "$RES" "save-cache") +RES_RESTORE=$(parse_val "$RES" "restore-cache") +[ "$RES_SAVE" = "true" ] || (echo "FAIL: expected save=true, got $RES_SAVE" && exit 1) +[ "$RES_RESTORE" = "true" ] || (echo "FAIL: expected restore=true, got $RES_RESTORE" && exit 1) +echo "Test 3 passed." + +echo "Test 4: cache-mode=off on push event (save=false, restore=false)" +RES=$("$RESOLVE_SCRIPT" "off" "" "" "push") +RES_SAVE=$(parse_val "$RES" "save-cache") +RES_RESTORE=$(parse_val "$RES" "restore-cache") +[ "$RES_SAVE" = "false" ] || (echo "FAIL: expected save=false, got $RES_SAVE" && exit 1) +[ "$RES_RESTORE" = "false" ] || (echo "FAIL: expected restore=false, got $RES_RESTORE" && exit 1) +echo "Test 4 passed." + +echo "Test 5: Explicit legacy input override for save-cache (docker-save-cache=true on pull_request)" +RES=$("$RESOLVE_SCRIPT" "auto" "true" "" "pull_request") +RES_SAVE=$(parse_val "$RES" "save-cache") +RES_RESTORE=$(parse_val "$RES" "restore-cache") +[ "$RES_SAVE" = "true" ] || (echo "FAIL: expected save=true, got $RES_SAVE" && exit 1) +[ "$RES_RESTORE" = "true" ] || (echo "FAIL: expected restore=true, got $RES_RESTORE" && exit 1) +echo "Test 5 passed." + +echo "Test 6: cache-mode=read-only on push event (save=false, restore=true)" +RES=$("$RESOLVE_SCRIPT" "read-only" "" "" "push") +RES_SAVE=$(parse_val "$RES" "save-cache") +RES_RESTORE=$(parse_val "$RES" "restore-cache") +[ "$RES_SAVE" = "false" ] || (echo "FAIL: expected save=false, got $RES_SAVE" && exit 1) +[ "$RES_RESTORE" = "true" ] || (echo "FAIL: expected restore=true, got $RES_RESTORE" && exit 1) +echo "Test 6 passed." + +echo "All cache event override tests completed successfully." diff --git a/actions/ctf-build-image/scripts/test-go-get-overrides.sh b/actions/ctf-build-image/scripts/test-go-get-overrides.sh index 9aca387aa..4af0088a5 100755 --- a/actions/ctf-build-image/scripts/test-go-get-overrides.sh +++ b/actions/ctf-build-image/scripts/test-go-get-overrides.sh @@ -1,34 +1,34 @@ #!/bin/bash set -e +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +GO_SCRIPT="${SCRIPT_DIR}/go-get-overrides.sh" + echo "===== Testing go-get-overrides.sh =====" export DRY_RUN=true - # Test 1: Dry run with valid input echo "Test 1: Dry run with valid input" -export GO_OVERRIDES="chainlink-solana=abc123 -atlas=def456 -chainlink-common=ghi789" -./go-get-overrides.sh +export GO_OVERRIDES="github.com/smartcontractkit/chainlink-solana=abc123 +github.com/smartcontractkit/atlas=def456" +"$GO_SCRIPT" echo "Test 1 completed." echo # Test 2: Empty overrides echo "Test 2: Empty overrides" export GO_OVERRIDES="" -./go-get-overrides.sh +"$GO_SCRIPT" echo "Test 2 completed." echo # Test 3: Malformed input echo "Test 3: Malformed input" -export GO_OVERRIDES="chainlink-solana=abc123 +export GO_OVERRIDES="github.com/smartcontractkit/chainlink-solana=abc123 atlas= -invalid-line -chainlink-common=ghi789" -./go-get-overrides.sh +invalid-line" +"$GO_SCRIPT" echo "Test 3 completed." echo diff --git a/actions/ctf-build-image/scripts/test-plugin-overrides.sh b/actions/ctf-build-image/scripts/test-plugin-overrides.sh index 093525908..179064aed 100755 --- a/actions/ctf-build-image/scripts/test-plugin-overrides.sh +++ b/actions/ctf-build-image/scripts/test-plugin-overrides.sh @@ -1,65 +1,54 @@ #!/bin/bash set -e +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PLUGIN_SCRIPT="${SCRIPT_DIR}/plugin-overrides.sh" + echo "===== Testing plugin-overrides.sh =====" export DRY_RUN=true -# Create a temporary manifest file for testing +# Create a temporary manifest file matching chainlink plugins.public.yaml schema TEMP_MANIFEST=$(mktemp) cat > "$TEMP_MANIFEST" << EOF plugins: cosmos: - gitRef: "old-cosmos-ref" - modulePath: "github.com/smartcontractkit/chainlink-cosmos" + moduleURI: "github.com/smartcontractkit/chainlink-cosmos" solana: - gitRef: "old-solana-ref" - modulePath: "github.com/smartcontractkit/chainlink-solana" - starknet: - - gitRef: "old-starknet-ref" - modulePath: "github.com/smartcontractkit/chainlink-starknet" + moduleURI: "github.com/smartcontractkit/chainlink-solana" EOF # Test 1: Dry run with valid input echo "Test 1: Dry run with valid input" export PLUGIN_OVERRIDES="cosmos=new-cosmos-ref -solana=new-solana-ref -starknet=new-starknet-ref" +solana=new-solana-ref" export PLUGINS_MANIFEST_PATH="$TEMP_MANIFEST" -echo "Initial manifest:" -cat "$TEMP_MANIFEST" -echo "Running with overrides:" -echo "$PLUGIN_OVERRIDES" -./plugin-overrides.sh -echo "Manifest after dry run (should be unchanged):" -cat "$TEMP_MANIFEST" +"$PLUGIN_SCRIPT" echo "Test 1 completed." echo -# Test 2: Real run with valid input -echo "Test 2: Real run with valid input" -export PLUGIN_OVERRIDES="cosmos=new-cosmos-ref -solana=new-solana-ref" -./plugin-overrides.sh -echo "Test 2 completed." -echo - -# Test 3: Non-existent plugin -echo "Test 3: Non-existent plugin" -export PLUGIN_OVERRIDES="non-existent-plugin=some-ref" -./plugin-overrides.sh -echo "Test 3 completed." -echo - -# Test 4: Empty overrides -echo "Test 4: Empty overrides" +# Test 2: Real run with valid input (if yq installed) +if command -v yq &>/dev/null; then + echo "Test 2: Real run with valid input" + unset DRY_RUN + "$PLUGIN_SCRIPT" + unset DRY_RUN + export DRY_RUN=true + echo "Updated manifest:" + cat "$TEMP_MANIFEST" + echo "Test 2 completed." + echo +fi + +# Test 3: Empty overrides +echo "Test 3: Empty overrides" export PLUGIN_OVERRIDES="" -./plugin-overrides.sh -echo "Test 4 completed." +"$PLUGIN_SCRIPT" +echo "Test 3 completed." echo # Clean up rm "$TEMP_MANIFEST" -echo "Temporary manifest file removed." - -echo "All tests for update-plugin-manifest.sh completed." +echo "All tests for plugin-overrides.sh completed."