From f6b8b1f64b131f4bd03e991ce0516609f60ac51d Mon Sep 17 00:00:00 2001 From: hisco <39222286+hisco@users.noreply.github.com> Date: Tue, 26 May 2026 22:49:41 +0300 Subject: [PATCH 1/5] ci: add semantic-release workflow + minimal test perms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit README markets `uses: skyhook-io/read-config@v1` but nothing was creating that tag. Add the same `codfish/semantic-release-action@v4` release workflow used by skyhook-io/kustomize-edit and skyhook-io/kustomize-deploy so pushes to main mint v1.x.y tags + a sliding v1 ref automatically. Also add a minimal `permissions: contents: read` block to test.yml — sibling workflows already gate perms explicitly; the test workflow had no token-reaching steps but defaulting to whatever GITHUB_TOKEN scope is configured at the repo level isn't great hygiene. --- .github/workflows/release.yml | 22 ++++++++++++++++++++++ .github/workflows/test.yml | 3 +++ 2 files changed, 25 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..75a7b40 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,22 @@ +name: Release +on: + push: + branches: [main] + workflow_dispatch: {} + +permissions: + contents: write + issues: write + pull-requests: write + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: codfish/semantic-release-action@v4 + with: + additional-packages: "['semantic-release-github-actions-tags']" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 158f355..ff10fad 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,6 +5,9 @@ on: branches: [main] pull_request: +permissions: + contents: read + jobs: shell-tests: strategy: From b6b182fbf5fdc4f72615e5726a8a02a4dbc9f0ba Mon Sep 17 00:00:00 2001 From: hisco <39222286+hisco@users.noreply.github.com> Date: Tue, 26 May 2026 23:05:52 +0300 Subject: [PATCH 2/5] feat(defaults): caller-supplied fallbacks for build_context + dockerfile_path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously the action hardcoded "." as the fallback for build_context when the YAML didn't supply one, but emitted empty for dockerfile_path. That asymmetry pushed defaulting logic onto every consumer's workflow (`|| 'Dockerfile'` sprinkled everywhere) and made the "default" value an action implementation detail rather than a caller choice. Two new optional inputs let the caller own the fallback policy: default_dockerfile_path - emitted when YAML doesn't supply dockerfilePath default_build_context - emitted when YAML doesn't supply buildContext Rule (now symmetric for both fields): YAML wins when the config is readable AND the service exists AND the field is non-empty. In every other case (config missing, service missing, field absent/null/empty) the corresponding default_* input is emitted. Defaults are empty strings so a caller without an opinion still gets a clean empty signal — same back-compat behavior for the missing-config/ missing-service paths, just symmetric across the two build-tool fields. README's behavior matrix rewritten to document the single rule. Tests extended to cover both code paths (with and without default_* inputs) plus the YAML-wins-over-default precedence. CI smoke job exercises three new scenarios (no caller default, caller default for absent field, caller default on missing service). --- .github/workflows/test.yml | 46 ++++++++++++++++-- README.md | 33 +++++++++---- action.yml | 14 +++++- scripts/parse.sh | 32 +++++++++--- tests/parse_test.sh | 99 +++++++++++++++++++++++++++++++++----- 5 files changed, 189 insertions(+), 35 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ff10fad..c8b782d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -60,16 +60,54 @@ jobs: test "${{ steps.cfg.outputs.dockerfile_path }}" = "services/smoke/Dockerfile" echo "smoke-svc outputs OK" - - name: Run action against fixture (buildContext absent -> default '.') + - name: Run action against fixture (buildContext absent, no caller default) id: cfg2 uses: ./ with: working_directory: tests/fixtures service_name: smoke-default-context - - name: Verify default-context outputs + - name: Verify outputs when YAML lacks buildContext and no caller default run: | set -e - test "${{ steps.cfg2.outputs.build_context }}" = "." + # build_context comes from YAML when present; otherwise echoes whatever + # default_build_context the caller passed (here: nothing → empty). + test "${{ steps.cfg2.outputs.build_context }}" = "" test "${{ steps.cfg2.outputs.dockerfile_path }}" = "services/default/Dockerfile" - echo "default-context outputs OK" + echo "default-context outputs OK (empty fallback)" + + - name: Run action with caller-supplied default_* fallbacks + id: cfg3 + uses: ./ + with: + working_directory: tests/fixtures + service_name: smoke-default-context + default_build_context: 'services/default' + default_dockerfile_path: 'services/default/Custom.Dockerfile' + + - name: Verify caller defaults fill in YAML-absent fields + run: | + set -e + # buildContext is absent in YAML for smoke-default-context → fall back to caller-supplied default + test "${{ steps.cfg3.outputs.build_context }}" = "services/default" + # dockerfilePath IS in YAML → YAML wins, caller default is ignored + test "${{ steps.cfg3.outputs.dockerfile_path }}" = "services/default/Dockerfile" + echo "caller-default fallback OK" + + - name: Run action against missing service with caller defaults + id: cfg4 + uses: ./ + with: + working_directory: tests/fixtures + service_name: not-a-real-service + default_build_context: '.' + default_dockerfile_path: 'Dockerfile' + + - name: Verify caller defaults applied on missing service + run: | + set -e + test "${{ steps.cfg4.outputs.config_found }}" = "true" + test "${{ steps.cfg4.outputs.service_found }}" = "false" + test "${{ steps.cfg4.outputs.build_context }}" = "." + test "${{ steps.cfg4.outputs.dockerfile_path }}" = "Dockerfile" + echo "missing-service caller-default OK" diff --git a/README.md b/README.md index a4fba51..eb2859f 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,8 @@ This action parses the Skyhook configuration file and extracts service-specific | `working_directory` | Path to the repository root containing `.skyhook/skyhook.yaml` | No | `.` | | `service_name` | Name of the service to look up in the config | Yes | - | | `config_path` | Path to the skyhook config file relative to working_directory | No | `.skyhook/skyhook.yaml` | +| `default_dockerfile_path` | Fallback for `dockerfile_path` when the YAML doesn't supply one (config unreadable, service missing, or `buildTool.docker.dockerfilePath` unset/empty). | No | `""` | +| `default_build_context` | Fallback for `build_context` when the YAML doesn't supply one. | No | `""` | ## Outputs @@ -105,21 +107,34 @@ jobs: ## Behavior matrix -| Scenario | `config_found` | `service_found` | `build_context` | Other outputs | +The two build-tool outputs (`build_context`, `dockerfile_path`) follow a single rule: + +> **YAML wins when the config is readable AND the service exists AND the field is non-empty. In every other case, the caller-supplied `default_*` input is emitted.** + +`name`, `path`, `deployment_repo`, and `deployment_repo_path` are always sourced from the YAML and emit empty when the config/service can't be read — there are no `default_*` fallbacks for them. + +| Scenario | `config_found` | `service_found` | `build_context` | `dockerfile_path` | |---|---|---|---|---| -| Config file missing | `false` | `false` | `""` | `""` | -| Config found, service missing | `true` | `false` | `""` | `""` | -| Service found, `buildContext` set | `true` | `true` | from config | from config | -| Service found, `buildContext` absent | `true` | `true` | `"."` | from config | -| Duplicate service names in config | n/a | n/a | n/a | action exits 1 | +| Config file missing | `false` | `false` | `default_build_context` | `default_dockerfile_path` | +| Config found, service missing | `true` | `false` | `default_build_context` | `default_dockerfile_path` | +| Service found, both fields set | `true` | `true` | from YAML | from YAML | +| Service found, only `buildContext` set | `true` | `true` | from YAML | `default_dockerfile_path` | +| Service found, neither field set | `true` | `true` | `default_build_context` | `default_dockerfile_path` | +| Duplicate service names | n/a | n/a | n/a | action exits 1 | -`build_context` defaults to `"."` only when the service is found and the field is absent. When the service or config itself is missing, `build_context` is empty - the workflow should decide whether to fall back or fail loudly: +Without `default_*` inputs the fallback is empty — meaning a workflow that wants a guaranteed-non-empty value should pass them at the call site: ```yaml -context: ${{ steps.config.outputs.build_context || '.' }} -dockerfile: ${{ steps.config.outputs.dockerfile_path || 'Dockerfile' }} +- uses: skyhook-io/read-config@v1 + with: + service_name: my-svc + # Computed sensible fallbacks the caller controls: + default_dockerfile_path: services/my-svc/Dockerfile + default_build_context: . ``` +`config_found` and `service_found` remain available so the caller can distinguish between a YAML-sourced value and a fallback if needed. + ## Runner requirements - Bash + `yq` v4.x. The action installs yq v4.47.1 if missing. diff --git a/action.yml b/action.yml index 173e9fb..0ae0199 100644 --- a/action.yml +++ b/action.yml @@ -14,6 +14,14 @@ inputs: description: 'Path to the skyhook config file relative to working_directory' required: false default: '.skyhook/skyhook.yaml' + default_dockerfile_path: + description: 'Fallback for the dockerfile_path output. Used when the YAML config is unreadable, the service is missing, or buildTool.docker.dockerfilePath is unset/empty. Empty by default — the caller decides whether to fall back ("Dockerfile", "/Dockerfile", etc.).' + required: false + default: '' + default_build_context: + description: 'Fallback for the build_context output. Used when the YAML config is unreadable, the service is missing, or buildTool.docker.buildContext is unset/empty. Empty by default — the caller decides (".", the source path, etc.).' + required: false + default: '' outputs: # Service configuration @@ -32,10 +40,10 @@ outputs: # Build tool configuration build_context: - description: 'Docker build context relative to repo root (defaults to "." when absent in config)' + description: 'Docker build context relative to repo root. Sourced from buildTool.docker.buildContext in the YAML when available; falls back to the default_build_context input otherwise.' value: ${{ steps.parse.outputs.build_context }} dockerfile_path: - description: 'Dockerfile path relative to repo root' + description: 'Dockerfile path relative to repo root. Sourced from buildTool.docker.dockerfilePath in the YAML when available; falls back to the default_dockerfile_path input otherwise.' value: ${{ steps.parse.outputs.dockerfile_path }} # Status @@ -110,6 +118,8 @@ runs: WORKING_DIR: ${{ inputs.working_directory }} SERVICE_NAME: ${{ inputs.service_name }} CONFIG_PATH: ${{ inputs.config_path }} + DEFAULT_DOCKERFILE_PATH: ${{ inputs.default_dockerfile_path }} + DEFAULT_BUILD_CONTEXT: ${{ inputs.default_build_context }} run: bash "$GITHUB_ACTION_PATH/scripts/parse.sh" branding: diff --git a/scripts/parse.sh b/scripts/parse.sh index 812eb4c..f5e5ed7 100755 --- a/scripts/parse.sh +++ b/scripts/parse.sh @@ -2,10 +2,18 @@ # Parse a Skyhook config file and emit GitHub Actions-style outputs. # # Inputs (env): -# WORKING_DIR - repo root containing the config (default ".") -# SERVICE_NAME - service to look up (required, non-empty) -# CONFIG_PATH - path to config relative to WORKING_DIR (default ".skyhook/skyhook.yaml") -# GITHUB_OUTPUT - file to append outputs to (required by GitHub Actions; tests pass a tempfile) +# WORKING_DIR - repo root containing the config (default ".") +# SERVICE_NAME - service to look up (required, non-empty) +# CONFIG_PATH - path to config relative to WORKING_DIR (default ".skyhook/skyhook.yaml") +# DEFAULT_DOCKERFILE_PATH - fallback when YAML doesn't supply dockerfile_path +# DEFAULT_BUILD_CONTEXT - fallback when YAML doesn't supply build_context +# GITHUB_OUTPUT - file to append outputs to (required by GitHub Actions; tests pass a tempfile) +# +# Fallback rule for build_context / dockerfile_path: the YAML value wins when +# the config is readable AND the service exists AND the field is non-empty. +# In every other case (config missing, service missing, field absent or +# explicitly null/empty) the corresponding DEFAULT_* input is emitted — +# empty by default, so the caller decides what their fallback should be. # # Exits non-zero with ::error:: on: # - empty SERVICE_NAME @@ -21,6 +29,8 @@ WORKING_DIR="${WORKING_DIR:-.}" WORKING_DIR="${WORKING_DIR%/}" CONFIG_PATH="${CONFIG_PATH:-.skyhook/skyhook.yaml}" SERVICE_NAME="${SERVICE_NAME:-}" +DEFAULT_DOCKERFILE_PATH="${DEFAULT_DOCKERFILE_PATH:-}" +DEFAULT_BUILD_CONTEXT="${DEFAULT_BUILD_CONTEXT:-}" if [ -z "$SERVICE_NAME" ]; then echo "::error::service_name input is required and must be non-empty" @@ -42,13 +52,16 @@ write_output() { } >> "$GITHUB_OUTPUT" } +# Emit empty/identity outputs for the no-data path. build_context and +# dockerfile_path still fall back to the caller-supplied defaults so a +# missing config / service yields the same shape as a present-but-empty one. write_empty_outputs() { write_output name "" write_output path "" write_output deployment_repo "" write_output deployment_repo_path "" - write_output build_context "" - write_output dockerfile_path "" + write_output build_context "$DEFAULT_BUILD_CONTEXT" + write_output dockerfile_path "$DEFAULT_DOCKERFILE_PATH" } # Config file missing @@ -114,8 +127,11 @@ DOCKERFILE_PATH=$(yq e "${SERVICE_PATH}.buildTool.docker.dockerfilePath // \"\"" [ "$BUILD_CONTEXT" = "null" ] && BUILD_CONTEXT="" [ "$DOCKERFILE_PATH" = "null" ] && DOCKERFILE_PATH="" -# Default build context to "." when absent -[ -z "$BUILD_CONTEXT" ] && BUILD_CONTEXT="." +# Apply caller-supplied fallbacks for the build-tool fields when YAML didn't +# provide a value. No hardcoded action-side defaults — the caller owns the +# fallback policy via the default_* inputs. +[ -z "$BUILD_CONTEXT" ] && BUILD_CONTEXT="$DEFAULT_BUILD_CONTEXT" +[ -z "$DOCKERFILE_PATH" ] && DOCKERFILE_PATH="$DEFAULT_DOCKERFILE_PATH" write_output name "$NAME" write_output path "$PATH_VALUE" diff --git a/tests/parse_test.sh b/tests/parse_test.sh index 6eb209d..ce67821 100755 --- a/tests/parse_test.sh +++ b/tests/parse_test.sh @@ -100,6 +100,24 @@ run_parse() { WORKING_DIR="$working_dir" \ SERVICE_NAME="$svc" \ CONFIG_PATH="$cfg_path" \ + DEFAULT_DOCKERFILE_PATH="${DEFAULT_DOCKERFILE_PATH:-}" \ + DEFAULT_BUILD_CONTEXT="${DEFAULT_BUILD_CONTEXT:-}" \ + GITHUB_OUTPUT="$out_file" \ + bash "$PARSE_SCRIPT" >/dev/null + echo "$out_file" +} + +# Run parse.sh with explicit caller-supplied default_* fallback inputs. +run_parse_with_defaults() { + local working_dir="$1" svc="$2" default_df="$3" default_ctx="$4" + local out_file + out_file="$WORK/gh_output.$RANDOM" + : >"$out_file" + WORKING_DIR="$working_dir" \ + SERVICE_NAME="$svc" \ + CONFIG_PATH=".skyhook/skyhook.yaml" \ + DEFAULT_DOCKERFILE_PATH="$default_df" \ + DEFAULT_BUILD_CONTEXT="$default_ctx" \ GITHUB_OUTPUT="$out_file" \ bash "$PARSE_SCRIPT" >/dev/null echo "$out_file" @@ -155,19 +173,53 @@ assert_eq "$(read_output "$out" deployment_repo_path)" "nbjkgj" "with-context: d assert_eq "$(read_output "$out" build_context)" "java-web-project/src" "with-context: build_context" assert_eq "$(read_output "$out" dockerfile_path)" "java-web-project/src/Dockerfile" "with-context: dockerfile_path" -# --- buildContext absent => default "." --- +# --- buildContext absent + no DEFAULT_BUILD_CONTEXT => empty --- +# The action no longer hardcodes "." — the caller owns the fallback via the +# default_build_context input. Without one supplied, the output is empty. out=$(run_parse "$WORK" no-context) -assert_eq "$(read_output "$out" build_context)" "." "no-context: build_context defaults to '.'" +assert_eq "$(read_output "$out" build_context)" "" "no-context: build_context empty when no default supplied" assert_eq "$(read_output "$out" dockerfile_path)" "java-multi-modules/Dockerfile" "no-context: dockerfile_path" assert_eq "$(read_output "$out" deployment_repo)" "skyhook-dev/deployment" "no-context: deployment_repo" -# --- buildContext: null => default "." --- +# --- buildContext: null + no DEFAULT_BUILD_CONTEXT => empty --- out=$(run_parse "$WORK" explicit-null) -assert_eq "$(read_output "$out" build_context)" "." "explicit-null: build_context defaults to '.'" +assert_eq "$(read_output "$out" build_context)" "" "explicit-null: build_context empty when no default supplied" -# --- buildContext: "" => default "." --- +# --- buildContext: "" + no DEFAULT_BUILD_CONTEXT => empty --- out=$(run_parse "$WORK" empty-string) -assert_eq "$(read_output "$out" build_context)" "." "empty-string: build_context defaults to '.'" +assert_eq "$(read_output "$out" build_context)" "" "empty-string: build_context empty when no default supplied" + +# --- DEFAULT_BUILD_CONTEXT fills in when YAML field is absent --- +out=$(run_parse_with_defaults "$WORK" no-context "" ".") +assert_eq "$(read_output "$out" build_context)" "." "no-context + default_build_context='.': output is '.'" + +out=$(run_parse_with_defaults "$WORK" explicit-null "" "java-multi-modules") +assert_eq "$(read_output "$out" build_context)" "java-multi-modules" "explicit-null + custom default: output is the default" + +out=$(run_parse_with_defaults "$WORK" empty-string "" "svc-empty") +assert_eq "$(read_output "$out" build_context)" "svc-empty" "empty-string + custom default: output is the default" + +# --- DEFAULT_BUILD_CONTEXT NOT used when YAML provides a value --- +out=$(run_parse_with_defaults "$WORK" with-context "" "should-not-be-used") +assert_eq "$(read_output "$out" build_context)" "java-web-project/src" "yaml value wins over default_build_context" + +# --- DEFAULT_DOCKERFILE_PATH fills in when YAML field is absent --- +# (Add a fixture without dockerfilePath to exercise this.) +NO_DF_DIR="$WORK/no-df" +mkdir -p "$NO_DF_DIR/.skyhook" +cat >"$NO_DF_DIR/.skyhook/skyhook.yaml" <<'YAML' +services: + - name: bare + path: services/bare +YAML +out=$(run_parse_with_defaults "$NO_DF_DIR" bare "services/bare/Dockerfile" "services/bare") +assert_eq "$(read_output "$out" dockerfile_path)" "services/bare/Dockerfile" "bare service + default_dockerfile_path: output is the default" +assert_eq "$(read_output "$out" build_context)" "services/bare" "bare service + default_build_context: output is the default" +assert_eq "$(read_output "$out" service_found)" "true" "bare service still reports service_found=true" + +# --- DEFAULT_DOCKERFILE_PATH NOT used when YAML provides a value --- +out=$(run_parse_with_defaults "$WORK" with-context "should-not-be-used" "") +assert_eq "$(read_output "$out" dockerfile_path)" "java-web-project/src/Dockerfile" "yaml value wins over default_dockerfile_path" # --- value with spaces survives heredoc round-trip --- out=$(run_parse "$WORK" with-spaces) @@ -179,17 +231,32 @@ out=$(run_parse "$WORK" 'name-with-"-quote') assert_eq "$(read_output "$out" service_found)" "true" "quoted service name resolves" assert_eq "$(read_output "$out" path)" "svc-quote" "quoted service name: path" -# --- service not found --- +# --- service not found, no defaults => empty --- out=$(run_parse "$WORK" nonexistent-service) assert_eq "$(read_output "$out" config_found)" "true" "missing service: config_found=true" assert_eq "$(read_output "$out" service_found)" "false" "missing service: service_found=false" -assert_eq "$(read_output "$out" build_context)" "" "missing service: build_context empty (asymmetry)" +assert_eq "$(read_output "$out" build_context)" "" "missing service: build_context empty when no default" +assert_eq "$(read_output "$out" dockerfile_path)" "" "missing service: dockerfile_path empty when no default" + +# --- service not found, WITH defaults => defaults are emitted --- +out=$(run_parse_with_defaults "$WORK" nonexistent-service "Dockerfile" ".") +assert_eq "$(read_output "$out" config_found)" "true" "missing service + defaults: config_found=true" +assert_eq "$(read_output "$out" service_found)" "false" "missing service + defaults: service_found=false" +assert_eq "$(read_output "$out" build_context)" "." "missing service + defaults: build_context fallback applied" +assert_eq "$(read_output "$out" dockerfile_path)" "Dockerfile" "missing service + defaults: dockerfile_path fallback applied" -# --- config file missing --- +# --- config file missing, no defaults => empty --- out=$(run_parse "$WORK/no-such-dir" any-service) assert_eq "$(read_output "$out" config_found)" "false" "missing config: config_found=false" assert_eq "$(read_output "$out" service_found)" "false" "missing config: service_found=false" -assert_eq "$(read_output "$out" build_context)" "" "missing config: build_context empty" +assert_eq "$(read_output "$out" build_context)" "" "missing config: build_context empty when no default" +assert_eq "$(read_output "$out" dockerfile_path)" "" "missing config: dockerfile_path empty when no default" + +# --- config file missing, WITH defaults => defaults are emitted --- +out=$(run_parse_with_defaults "$WORK/no-such-dir" any-service "fallback/Dockerfile" "fallback") +assert_eq "$(read_output "$out" config_found)" "false" "missing config + defaults: config_found=false" +assert_eq "$(read_output "$out" build_context)" "fallback" "missing config + defaults: build_context fallback applied" +assert_eq "$(read_output "$out" dockerfile_path)" "fallback/Dockerfile" "missing config + defaults: dockerfile_path fallback applied" # --- empty service_name --- err=$(run_parse_expect_fail "$WORK" "") @@ -271,5 +338,13 @@ grep -q "strenv(SERVICE_NAME)" "$PARSE_SCRIPT" || { echo "FAIL: parse.sh does no grep -q "Multiple services named" "$PARSE_SCRIPT" || { echo "FAIL: parse.sh does not detect duplicate names"; exit 1; } grep -q "service_name input is required" "$PARSE_SCRIPT" || { echo "FAIL: parse.sh does not validate non-empty service_name"; exit 1; } grep -q 'Failed to parse' "$PARSE_SCRIPT" || { echo "FAIL: parse.sh does not surface yq parse errors"; exit 1; } -grep -q 'BUILD_CONTEXT="\."' "$PARSE_SCRIPT" || { echo "FAIL: parse.sh does not default build_context to '.'"; exit 1; } -echo "PASS: parse.sh has strenv, dup-detection, empty-name validation, parse-error surfacing, build_context default" +grep -q 'DEFAULT_BUILD_CONTEXT' "$PARSE_SCRIPT" || { echo "FAIL: parse.sh does not consume DEFAULT_BUILD_CONTEXT"; exit 1; } +grep -q 'DEFAULT_DOCKERFILE_PATH' "$PARSE_SCRIPT" || { echo "FAIL: parse.sh does not consume DEFAULT_DOCKERFILE_PATH"; exit 1; } +echo "PASS: parse.sh has strenv, dup-detection, empty-name validation, parse-error surfacing, caller-driven defaults" + +# --- action.yml exposes the new default_* inputs --- +grep -q 'default_dockerfile_path:' "$ACTION_FILE" || { echo "FAIL: action.yml does not declare default_dockerfile_path input"; exit 1; } +grep -q 'default_build_context:' "$ACTION_FILE" || { echo "FAIL: action.yml does not declare default_build_context input"; exit 1; } +grep -q 'DEFAULT_DOCKERFILE_PATH: ${{ inputs.default_dockerfile_path }}' "$ACTION_FILE" || { echo "FAIL: action.yml does not pipe default_dockerfile_path to parse.sh"; exit 1; } +grep -q 'DEFAULT_BUILD_CONTEXT: ${{ inputs.default_build_context }}' "$ACTION_FILE" || { echo "FAIL: action.yml does not pipe default_build_context to parse.sh"; exit 1; } +echo "PASS: action.yml exposes default_dockerfile_path + default_build_context inputs piped to parse.sh" From f0352bc659c62d70e66b493611cf969b786a28b1 Mon Sep 17 00:00:00 2001 From: hisco <39222286+hisco@users.noreply.github.com> Date: Tue, 26 May 2026 23:38:15 +0300 Subject: [PATCH 3/5] fix(release): add .releaserc.json so semantic-release can actually run Bugbot caught this: codfish/semantic-release-action invokes semantic-release with whatever release config it finds in the repo. Without a .releaserc the default plugin list includes @semantic-release/npm, which fails on this repo (no package.json), and the additional-packages install of semantic-release-github-actions-tags doesn't register it either. Mirror the .releaserc.json that skyhook-io/kustomize-edit and skyhook-io/kustomize-deploy use: - commit-analyzer + release-notes-generator: pick version + write notes - github: cut the GH Release - semantic-release-github-actions-tags: mint the v1 / v1.x.y sliding refs - NO @semantic-release/npm --- .releaserc.json | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .releaserc.json diff --git a/.releaserc.json b/.releaserc.json new file mode 100644 index 0000000..39045a4 --- /dev/null +++ b/.releaserc.json @@ -0,0 +1,10 @@ +{ + "branches": ["main"], + "tagFormat": "v${version}", + "plugins": [ + "@semantic-release/commit-analyzer", + "@semantic-release/release-notes-generator", + "@semantic-release/github", + "semantic-release-github-actions-tags" + ] +} From 518ed11acbf3d832402f9e70599df419e8b294c2 Mon Sep 17 00:00:00 2001 From: hisco <39222286+hisco@users.noreply.github.com> Date: Wed, 27 May 2026 09:13:23 +0300 Subject: [PATCH 4/5] fix(parse): portable delimiter generator + CI timeout cap The macOS shell-tests job in CI hung for 6 hours on tests/parse_test.sh. Root cause was the heredoc delimiter generator in parse.sh: tr -dc 'a-f0-9' Date: Wed, 27 May 2026 09:20:54 +0300 Subject: [PATCH 5/5] fix(release): fetch-depth: 0 so semantic-release sees full history MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cursor Bugbot flagged that actions/checkout@v4 defaults to a shallow fetch (fetch-depth: 1), but semantic-release walks the full commit history to find the previous release tag + analyze commits since. Without fetch-depth: 0 the first run could pick the wrong base and later runs could mis-version or skip releases entirely. The other Bugbot finding (".releaserc missing") was already addressed by f0352bc — the .releaserc.json is present with an explicit plugin list that excludes @semantic-release/npm and includes semantic-release-github-actions-tags. The latest review flagging it appears to be operating on a stale snapshot. --- .github/workflows/release.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 75a7b40..083f550 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,6 +14,12 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + with: + # semantic-release walks the full commit history to find the + # previous release tag and analyze commits since. Without a deep + # fetch the first run can pick the wrong base, and subsequent + # runs can mis-version or skip releases entirely. + fetch-depth: 0 - uses: codfish/semantic-release-action@v4 with: