diff --git a/ssh-deploy/action.yaml b/ssh-deploy/action.yaml index d907e2d..7d17106 100644 --- a/ssh-deploy/action.yaml +++ b/ssh-deploy/action.yaml @@ -111,78 +111,36 @@ runs: echo "Compose files: ${COMPOSE_FILES}" fi - # Optional tag override (Docker-only). When `image` is set, pin every - # compose service whose image base matches `image` to `image_tag`. - # We generate a remote override file (layered on the compose files via - # -f, later wins) so the deploy pulls/starts exactly the requested tag. - # The override is built on the runner (simple shell) then scp'd to the - # remote, avoiding fragile quoting inside an SSH command. - OVERRIDE_FLAGS="" + # Optional tag replacement in compose files on the remote. + # When `image` is set, find the files and replace the tag directly in them. if [ -n "${OVERRIDE_IMAGE}" ] && [ "${OVERRIDE_IMAGE// }" != "" ]; then if [ -z "${OVERRIDE_TAG}" ] || [ "${OVERRIDE_TAG// }" = "" ]; then echo "::error::image is set but image_tag is empty. Provide image_tag (defaults to latest)." exit 1 fi - echo "Pinning image ${OVERRIDE_IMAGE} to tag :${OVERRIDE_TAG}" + echo "Replacing image ${OVERRIDE_IMAGE} tag with :${OVERRIDE_TAG} in remote compose files" + + # Escape image name for sed + ESC_IMAGE=$(echo "${OVERRIDE_IMAGE}" | sed 's/[.[\*^$()|?+]/\\&/g') + SED_EXPR="s@(image:[[:space:]]*${ESC_IMAGE})(:[^[:space:]]*)?([[:space:]]|\$)@\1:${OVERRIDE_TAG}\3@g" + + # Determine which files to modify on the remote host + if [ -n "${COMPOSE_FILES}" ] && [ "${COMPOSE_FILES// }" != "" ]; then + # If explicit files are specified, modify those + REMOTE_COMMAND="" + for f in ${COMPOSE_FILES}; do + REMOTE_COMMAND="${REMOTE_COMMAND} sed -E -i \"${SED_EXPR}\" '${REMOTE_DIR}/${f}';" + done + else + # Otherwise, find all yml/yaml files in remote_dir and run sed on them + REMOTE_COMMAND="find '${REMOTE_DIR}' -maxdepth 1 \( -name '*.yml' -o -name '*.yaml' \) -exec sed -E -i \"${SED_EXPR}\" {} \+;" + fi - # 1) Fetch the merged remote compose config to the runner. ssh -i ~/.ssh/id_deploy \ -p "${SSH_PORT}" \ -o StrictHostKeyChecking=yes \ "${SSH_USERNAME}@${SSH_HOST}" \ - "cd '${REMOTE_DIR}' && docker compose ${COMPOSE_FLAGS} config" \ - > /tmp/ssh-deploy-remote.yml - - # 2) Emit a minimal override: only matching services, retagged. - awk -v img="${OVERRIDE_IMAGE}" -v tag="${OVERRIDE_TAG}" ' - /^services:/ { s=1; next } - s && /^ [A-Za-z0-9_-]+:/ { svc=$1; sub(/:$/, "", svc); next } - s && /^ image:/ { - val=$0; sub(/^ image:[ \t]*/, "", val) - last_slash = 0 - for (i = length(val); i > 0; i--) { - if (substr(val, i, 1) == "/") { - last_slash = i - break - } - } - last_colon = 0 - for (i = length(val); i > 0; i--) { - if (substr(val, i, 1) == ":") { - last_colon = i - break - } - } - if (last_colon > last_slash) { - b = substr(val, 1, last_colon - 1) - } else { - b = val - } - if (b == img) { - out = out sprintf(" %s:\n image: %s:%s\n", svc, img, tag) - count++ - } - } - END { - if (count > 0) { - print "services:" - printf "%s", out - } - } - ' /tmp/ssh-deploy-remote.yml > /tmp/ssh-deploy-override.yml - - if [ ! -s /tmp/ssh-deploy-override.yml ]; then - echo "::warning::No compose service uses image base '${OVERRIDE_IMAGE}'. Deploying without override." - else - # 3) Push the override to /tmp on the remote (not into remote_dir, - # so future tag-less deploys don't inherit a stale pinned tag). - scp -i ~/.ssh/id_deploy \ - -P "${SSH_PORT}" \ - -o StrictHostKeyChecking=yes \ - /tmp/ssh-deploy-override.yml \ - "${SSH_USERNAME}@${SSH_HOST}:/tmp/.ssh-deploy-override.yml" - OVERRIDE_FLAGS="-f /tmp/.ssh-deploy-override.yml" - fi + "${REMOTE_COMMAND}" fi ssh -i ~/.ssh/id_deploy \ @@ -190,5 +148,5 @@ runs: -o StrictHostKeyChecking=yes \ "${SSH_USERNAME}@${SSH_HOST}" \ "cd '${REMOTE_DIR}' \ - && docker compose ${COMPOSE_FLAGS} ${OVERRIDE_FLAGS} pull \ - && docker compose ${COMPOSE_FLAGS} ${OVERRIDE_FLAGS} up -d --force-recreate" + && docker compose ${COMPOSE_FLAGS} pull \ + && docker compose ${COMPOSE_FLAGS} up -d --force-recreate"