From 4d82d1782d9a6295352fe913b6459e22dfb75e2f Mon Sep 17 00:00:00 2001 From: John McCall Date: Tue, 18 Aug 2026 18:44:59 -0400 Subject: [PATCH 1/2] fix(s5cmd): add subcommand-flags input for subcommand-level flags s5cmd flags like sync --delete are subcommand-scoped, not global, and must come after the subcommand. The flags input places everything before the subcommand, so passing flags: --delete broke with 'flag provided but not defined: -delete'. Add a separate subcommand-flags input placed after the subcommand; flags keeps its documented global-flag behavior. Fixes #83 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Signed-off-by: John McCall --- .github/actions/s5cmd/action.yml | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/.github/actions/s5cmd/action.yml b/.github/actions/s5cmd/action.yml index 8398288..2fd28f5 100644 --- a/.github/actions/s5cmd/action.yml +++ b/.github/actions/s5cmd/action.yml @@ -45,6 +45,16 @@ inputs: Examples: "--no-sign-request", "--credentials-file /path/to/creds". required: false default: "" + subcommand-flags: + description: > + Flags to pass to the s5cmd subcommand itself, placed after the + subcommand and before source/destination, as a single string. These are + distinct from 'flags' (global flags before the subcommand): s5cmd + subcommands take their own flags, e.g. "sync --delete". Not used with + the run command, since its batch-file lines carry their own per-command + flags. Example: "--delete" for sync. + required: false + default: "" version: description: > s5cmd version to install. Pinned to 2.3.0 by default. Override only @@ -68,6 +78,7 @@ runs: SRC="${INPUTS_SOURCE}" DST="${INPUTS_DESTINATION}" BATCH="${INPUTS_BATCH_FILE}" + SUBCMD_FLAGS="${INPUTS_SUBCOMMAND_FLAGS}" case "$CMD" in cp|mv|rm|ls|sync|run) ;; @@ -89,11 +100,16 @@ runs: echo "::error::'batch-file' is only valid with the 'run' command. Did you mean to use 'source'?" exit 1 fi + if [[ "$CMD" == "run" && -n "$SUBCMD_FLAGS" ]]; then + echo "::error::'subcommand-flags' is not valid with the 'run' command. Put per-command flags inline in the batch-file instead." + exit 1 + fi env: INPUTS_COMMAND: ${{ inputs.command }} INPUTS_SOURCE: ${{ inputs.source }} INPUTS_DESTINATION: ${{ inputs.destination }} INPUTS_BATCH_FILE: ${{ inputs.batch-file }} + INPUTS_SUBCOMMAND_FLAGS: ${{ inputs.subcommand-flags }} - name: s5cmd ${{ inputs.command }} shell: bash @@ -103,8 +119,9 @@ runs: DST="${INPUTS_DESTINATION}" BATCH="${INPUTS_BATCH_FILE}" FLAGS="${INPUTS_FLAGS}" + SUBCMD_FLAGS="${INPUTS_SUBCOMMAND_FLAGS}" - # Build argument array: global flags first, then subcommand, then positional args + # Build argument array: global flags, then subcommand, then subcommand flags, then positional args ARGS=() # Word-split flags safely (simple space split; quote within flags if needed) @@ -118,6 +135,10 @@ runs: if [[ "$CMD" == "run" ]]; then ARGS+=("$BATCH") else + if [[ -n "$SUBCMD_FLAGS" ]]; then + read -ra SUBCMD_FLAG_ARRAY <<< "$SUBCMD_FLAGS" + ARGS+=("${SUBCMD_FLAG_ARRAY[@]}") + fi [[ -n "$SRC" ]] && ARGS+=("$SRC") [[ -n "$DST" ]] && ARGS+=("$DST") fi @@ -130,3 +151,4 @@ runs: INPUTS_DESTINATION: ${{ inputs.destination }} INPUTS_BATCH_FILE: ${{ inputs.batch-file }} INPUTS_FLAGS: ${{ inputs.flags }} + INPUTS_SUBCOMMAND_FLAGS: ${{ inputs.subcommand-flags }} From 1e394d3cfcdc529069e9abe8643c3288ea940a52 Mon Sep 17 00:00:00 2001 From: John McCall Date: Tue, 18 Aug 2026 18:51:03 -0400 Subject: [PATCH 2/2] fix(s5cmd): auto-correct --delete passed via flags for sync Hardcode a targeted fix so existing callers (e.g. stac's publish-catalog.yaml, which pins this action @main and predates subcommand-flags) keep working without a coordinated follow-up PR: if 'flags' contains --delete and the command is sync, move it after the subcommand automatically and emit a warning pointing callers at subcommand-flags. Anything else misplaced in 'flags' still fails as before; extend this case-by-case if more subcommand flags need it. Also documents the whitespace-only splitting behavior of flags and subcommand-flags per PR #84 review feedback. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Signed-off-by: John McCall --- .github/actions/s5cmd/action.yml | 47 ++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/.github/actions/s5cmd/action.yml b/.github/actions/s5cmd/action.yml index 2fd28f5..2ef66ee 100644 --- a/.github/actions/s5cmd/action.yml +++ b/.github/actions/s5cmd/action.yml @@ -42,7 +42,12 @@ inputs: flags: description: > Global flags to pass to s5cmd before the subcommand, as a single string. - Examples: "--no-sign-request", "--credentials-file /path/to/creds". + Examples: "--no-sign-request", "--credentials-file /path/to/creds". If + "--delete" is passed here with the sync command, it's automatically + moved after the subcommand (where s5cmd requires it) with a warning; + use 'subcommand-flags' instead to avoid the warning. Split on + whitespace, not shell quoting rules; don't pass flag values containing + spaces (e.g. quoted strings) here. required: false default: "" subcommand-flags: @@ -52,7 +57,9 @@ inputs: distinct from 'flags' (global flags before the subcommand): s5cmd subcommands take their own flags, e.g. "sync --delete". Not used with the run command, since its batch-file lines carry their own per-command - flags. Example: "--delete" for sync. + flags. Example: "--delete" for sync. Split on whitespace, not shell + quoting rules; don't pass flag values containing spaces (e.g. quoted + strings) here. required: false default: "" version: @@ -121,24 +128,40 @@ runs: FLAGS="${INPUTS_FLAGS}" SUBCMD_FLAGS="${INPUTS_SUBCOMMAND_FLAGS}" - # Build argument array: global flags, then subcommand, then subcommand flags, then positional args - ARGS=() + # Split on whitespace only, no shell quoting; see input descriptions + # above for the flag-value-with-spaces limitation this implies. + FLAG_ARRAY=() + [[ -n "$FLAGS" ]] && read -ra FLAG_ARRAY <<< "$FLAGS" + + SUBCMD_FLAG_ARRAY=() + [[ -n "$SUBCMD_FLAGS" ]] && read -ra SUBCMD_FLAG_ARRAY <<< "$SUBCMD_FLAGS" - # Word-split flags safely (simple space split; quote within flags if needed) - if [[ -n "$FLAGS" ]]; then - read -ra FLAG_ARRAY <<< "$FLAGS" - ARGS+=("${FLAG_ARRAY[@]}") + # --delete is a sync-subcommand flag, not global, but callers written + # against the old (pre-subcommand-flags) 'flags' input still pass it + # there. Auto-correct that one known case so existing callers keep + # working; anything else misplaced in 'flags' still fails as before. + if [[ "$CMD" == "sync" ]]; then + CORRECTED_FLAG_ARRAY=() + for flag in "${FLAG_ARRAY[@]}"; do + if [[ "$flag" == "--delete" ]]; then + echo "::warning::'--delete' is a sync-subcommand flag, not a global one; moving it after 'sync' automatically. Pass it via 'subcommand-flags' instead of 'flags' to avoid this warning." + SUBCMD_FLAG_ARRAY+=("--delete") + else + CORRECTED_FLAG_ARRAY+=("$flag") + fi + done + FLAG_ARRAY=("${CORRECTED_FLAG_ARRAY[@]}") fi + # Build argument array: global flags, then subcommand, then subcommand flags, then positional args + ARGS=() + ARGS+=("${FLAG_ARRAY[@]}") ARGS+=("$CMD") if [[ "$CMD" == "run" ]]; then ARGS+=("$BATCH") else - if [[ -n "$SUBCMD_FLAGS" ]]; then - read -ra SUBCMD_FLAG_ARRAY <<< "$SUBCMD_FLAGS" - ARGS+=("${SUBCMD_FLAG_ARRAY[@]}") - fi + ARGS+=("${SUBCMD_FLAG_ARRAY[@]}") [[ -n "$SRC" ]] && ARGS+=("$SRC") [[ -n "$DST" ]] && ARGS+=("$DST") fi