From 9c3ddd6df73763f002108f6b025b2bfd9f02ee50 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 May 2026 20:51:14 +0000 Subject: [PATCH 01/14] Initial plan From f45180a11087359be8a2bd496df4bee89c73e070 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 May 2026 20:57:09 +0000 Subject: [PATCH 02/14] ci: improve deploy webhook diagnostics and status handling Agent-Logs-Url: https://github.com/taonity/docker-webhook/sessions/4c8b0405-ff32-4251-83de-dd1cd166ba1b Co-authored-by: GeneralTao2 <42372666+GeneralTao2@users.noreply.github.com> --- .github/workflows/deploy.yml | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index c5f4518..e7c9300 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -29,7 +29,12 @@ jobs: echo "Deploying project [${{ inputs.project_name }}] to [${{ inputs.environment }}]" echo "---" - curl --no-buffer --fail-with-body --max-time 300 \ + response_body_file="$(mktemp)" + + curl_exit=0 + http_code=$(curl --no-buffer --silent --show-error --max-time 600 \ + --output "$response_body_file" \ + --write-out "%{http_code}" \ -X POST \ -H "Content-Type: application/json" \ -d '{ @@ -37,7 +42,21 @@ jobs: "repository": { "name": "${{ inputs.project_name }}" }, "environment": "${{ inputs.environment }}" }' \ - "${{ secrets.WEBHOOK_URL }}/hooks/${{ secrets.WEBHOOK_SECRET }}/docker-webhook" + "${{ secrets.WEBHOOK_URL }}/hooks/${{ secrets.WEBHOOK_SECRET }}/docker-webhook") || curl_exit=$? + echo "HTTP status: ${http_code:-N/A}" + echo "--- Response body ---" + cat "$response_body_file" echo "" + + if [ "$curl_exit" -ne 0 ]; then + echo "--- Deployment request failed before receiving a successful HTTP response ---" + exit "$curl_exit" + fi + + if [ "$http_code" -lt 200 ] || [ "$http_code" -ge 300 ]; then + echo "--- Deployment failed ---" + exit 1 + fi + echo "--- Deployment completed successfully ---" From 25db709ded95795403a40113d86c324c99f6b99e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 May 2026 21:00:08 +0000 Subject: [PATCH 03/14] ci: cleanup deploy response temp file and clarify curl error message Agent-Logs-Url: https://github.com/taonity/docker-webhook/sessions/4c8b0405-ff32-4251-83de-dd1cd166ba1b Co-authored-by: GeneralTao2 <42372666+GeneralTao2@users.noreply.github.com> --- .github/workflows/deploy.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index e7c9300..7f8918f 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -30,6 +30,7 @@ jobs: echo "---" response_body_file="$(mktemp)" + trap 'rm -f "$response_body_file"' EXIT curl_exit=0 http_code=$(curl --no-buffer --silent --show-error --max-time 600 \ @@ -50,7 +51,7 @@ jobs: echo "" if [ "$curl_exit" -ne 0 ]; then - echo "--- Deployment request failed before receiving a successful HTTP response ---" + echo "--- Deployment request failed due to network/transport error ---" exit "$curl_exit" fi From 0360bcd63cafe149d86f6169519e24e0f85d5a98 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 May 2026 21:21:35 +0000 Subject: [PATCH 04/14] Harden deploy script failure handling Agent-Logs-Url: https://github.com/taonity/docker-webhook/sessions/8c98fc1f-d103-4c8c-808b-3beaa6f0c7f4 Co-authored-by: GeneralTao2 <42372666+GeneralTao2@users.noreply.github.com> --- README.md | 13 ++- assets/scripts/restart-project.sh | 149 +++++++++++++++++++++++++++--- 2 files changed, 142 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 609343c..a119af3 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ An example of the usage of the image can be found in a [test](test/run-project-o - `WEBHOOK_SECRET` - you have to create a webhook with a secret placed into its URL `http:///hooks//docker-webhook`. The secret can be then loaded as an environment variable `WEBHOOK_SECRET` in `docker-webhook` service. The secret is used for security purposes. - `DOCKER_USERNAME` - an env var that contains your DockerHub username. - `DEPLOY_DEFAULT_ENV` - (optional) the default environment to deploy to when no environment is specified in the webhook payload. Defaults to `stage` if not set. + - `DEPLOY_HEALTHCHECK_TIMEOUT` - (optional) wait this many seconds for Docker health checks after `docker compose up -d`. When set to a value greater than `0`, the deploy script fails if any service exits early, becomes unhealthy, or does not become healthy before the timeout. When omitted or set to `0`, health-check waiting is skipped. - `project-whitelist.list` - is a file with target image names being listed (without owner name). The tool will check if the list contains the image name from webhook details and will proceed only on finding a match. Each image name should be written from the new line. The file should placed in `shared/config` folder and the `shared` folder should be mounted into `/etc/webhook/shared` of the container. - `envs` - a folder that loads env vars for each docker compose project. Envs should be stored in `.envs` file a placed in `shared/-/` folder (e.g., `shared/envs/myapp-stage/` or `shared/envs/myapp-prod/`). The `shared` folder should be mounted into `/etc/webhook/shared` of the container. This configuration is optional. - `docker-compose.override.yml` - (optional) you can place environment-specific Docker Compose override files in `shared/envs/-/docker-compose.override.yml`. These override files will be automatically applied when deploying to that environment, allowing you to customize ports, volumes, environment variables, or any other Docker Compose settings per environment. @@ -26,11 +27,13 @@ The webhook service supports deploying to multiple environments (e.g., stage and - **Default behavior**: By default, webhooks deploy to the `stage` environment (or whatever `DEPLOY_DEFAULT_ENV` is set to). - **Production deployments**: To deploy to production, include an `environment` field with value `prod` in your webhook payload. -- **Environment isolation**: Each environment maintains separate: - - Cache directories: `/etc/webhook/cache/-` - - Docker Compose project names: `-` - - Environment variable files: `shared/envs/-/` - - Docker Compose override files: `shared/envs/-/docker-compose.override.yml` + - **Environment isolation**: Each environment maintains separate: + - Cache directories: `/etc/webhook/cache/-` + - Docker Compose project names: `-` + - Environment variable files: `shared/envs/-/` + - Docker Compose override files: `shared/envs/-/docker-compose.override.yml` + +If your services define Docker health checks, set `DEPLOY_HEALTHCHECK_TIMEOUT` to make deployments wait for them before reporting success. **Example webhook payload for production deployment:** ```json diff --git a/assets/scripts/restart-project.sh b/assets/scripts/restart-project.sh index d53d678..8331307 100755 --- a/assets/scripts/restart-project.sh +++ b/assets/scripts/restart-project.sh @@ -1,25 +1,143 @@ #!/bin/bash -set -e +set -euo pipefail -PROJECT_NAME=$1 -ENVIRONMENT=$2 +PROJECT_NAME=${1:?Project name argument is required} +ENVIRONMENT=${2-} # If environment is not provided or empty, use default from env var (defaults to "stage") if [ -z "$ENVIRONMENT" ]; then ENVIRONMENT="${DEPLOY_DEFAULT_ENV:-stage}" fi +: "${SHARED_DIR_PATH:?SHARED_DIR_PATH environment variable is required}" +: "${DOCKER_USERNAME:?DOCKER_USERNAME environment variable is required}" + echo "Deploying project [$PROJECT_NAME] to environment [$ENVIRONMENT]" +PROJECT_DOCKER_COMPOSE_FILE= +PROJECT_DOCKER_COMPOSE_OVERRIDE= +COMPOSE_PROJECT_NAME= +declare -a COMPOSE_ARGS=() + +print_container_logs() { + local container_id=$1 + local service_name=$2 + + echo "Logs for service [$service_name]:" + docker logs "$container_id" || true +} + +get_compose_container_ids() { + mapfile -t COMPOSE_CONTAINER_IDS < <(docker compose "${COMPOSE_ARGS[@]}" -p "$COMPOSE_PROJECT_NAME" ps -q) + + if [ "${#COMPOSE_CONTAINER_IDS[@]}" -eq 0 ]; then + echo "WARN! Deploy for [$PROJECT_NAME] environment [$ENVIRONMENT] did not create any containers" + exit 1 + fi +} + +validate_compose_container_states() { + local container_id service_name container_status + + get_compose_container_ids + + for container_id in "${COMPOSE_CONTAINER_IDS[@]}"; do + service_name=$(docker inspect --format '{{index .Config.Labels "com.docker.compose.service"}}' "$container_id") + container_status=$(docker inspect --format '{{.State.Status}}' "$container_id") + + case "$container_status" in + running) + ;; + *) + echo "WARN! Service [$service_name] is in [$container_status] state after deploy" + docker compose "${COMPOSE_ARGS[@]}" -p "$COMPOSE_PROJECT_NAME" ps + print_container_logs "$container_id" "$service_name" + exit 1 + ;; + esac + done +} + +wait_for_container_healthchecks() { + local healthcheck_timeout=${DEPLOY_HEALTHCHECK_TIMEOUT:-0} + local deadline container_id service_name health_status has_healthcheck pending_healthchecks + + if ! [[ "$healthcheck_timeout" =~ ^[0-9]+$ ]]; then + echo "WARN! DEPLOY_HEALTHCHECK_TIMEOUT must be a non-negative integer, got [$healthcheck_timeout]" + exit 1 + fi + + if [ "$healthcheck_timeout" -le 0 ]; then + return 0 + fi + + echo "Waiting up to [$healthcheck_timeout] seconds for container health checks" + deadline=$((SECONDS + healthcheck_timeout)) + + while true; do + has_healthcheck=false + pending_healthchecks=false + + validate_compose_container_states + + for container_id in "${COMPOSE_CONTAINER_IDS[@]}"; do + service_name=$(docker inspect --format '{{index .Config.Labels "com.docker.compose.service"}}' "$container_id") + health_status=$(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}' "$container_id") + + case "$health_status" in + none) + ;; + healthy) + has_healthcheck=true + ;; + starting) + has_healthcheck=true + pending_healthchecks=true + ;; + unhealthy) + echo "WARN! Service [$service_name] failed its health check after deploy" + docker compose "${COMPOSE_ARGS[@]}" -p "$COMPOSE_PROJECT_NAME" ps + print_container_logs "$container_id" "$service_name" + exit 1 + ;; + *) + echo "WARN! Service [$service_name] returned unexpected health status [$health_status]" + docker compose "${COMPOSE_ARGS[@]}" -p "$COMPOSE_PROJECT_NAME" ps + print_container_logs "$container_id" "$service_name" + exit 1 + ;; + esac + done + + if [ "$has_healthcheck" = false ]; then + echo "No container health checks configured for [$PROJECT_NAME] environment [$ENVIRONMENT], skipping health verification" + return 0 + fi + + if [ "$pending_healthchecks" = false ]; then + echo "All container health checks passed for [$PROJECT_NAME] environment [$ENVIRONMENT]" + return 0 + fi + + if [ "$SECONDS" -ge "$deadline" ]; then + echo "WARN! Timed out waiting [$healthcheck_timeout] seconds for container health checks" + docker compose "${COMPOSE_ARGS[@]}" -p "$COMPOSE_PROJECT_NAME" ps + exit 1 + fi + + sleep 2 + done +} + # Check if project name is present in project-whitelist.list ./verify-project.sh "$PROJECT_NAME" # Use environment-specific paths -PROJECT_CACHE_PATH=/etc/webhook/cache/${PROJECT_NAME}-${ENVIRONMENT} -PROJECT_ENVS_PATH=$SHARED_DIR_PATH/envs/${PROJECT_NAME}-${ENVIRONMENT} -REPO_NAME=$DOCKER_USERNAME/$PROJECT_NAME -COMPOSE_PROJECT_NAME=${PROJECT_NAME}-${ENVIRONMENT} +PROJECT_CACHE_PATH="/etc/webhook/cache/${PROJECT_NAME}-${ENVIRONMENT}" +PROJECT_ENVS_PATH="${SHARED_DIR_PATH}/envs/${PROJECT_NAME}-${ENVIRONMENT}" +REPO_NAME="${DOCKER_USERNAME}/${PROJECT_NAME}" +COMPOSE_PROJECT_NAME="${PROJECT_NAME}-${ENVIRONMENT}" # Create if not exists a directory for project files mkdir -p "$PROJECT_CACHE_PATH" @@ -45,22 +163,23 @@ else echo "Env file for project [$PROJECT_NAME] environment [$ENVIRONMENT] was not found" fi -PROJECT_DOCKER_COMPOSE_FILE=$PROJECT_CACHE_PATH/docker-compose.yml -PROJECT_DOCKER_COMPOSE_OVERRIDE=$PROJECT_CACHE_PATH/docker-compose.override.yml +PROJECT_DOCKER_COMPOSE_FILE="$PROJECT_CACHE_PATH/docker-compose.yml" +PROJECT_DOCKER_COMPOSE_OVERRIDE="$PROJECT_CACHE_PATH/docker-compose.override.yml" # RESTART PROCESS # Build docker compose command with override file if it exists -COMPOSE_FILES="-f $PROJECT_DOCKER_COMPOSE_FILE" +COMPOSE_ARGS=(-f "$PROJECT_DOCKER_COMPOSE_FILE") if [ -f "$PROJECT_DOCKER_COMPOSE_OVERRIDE" ]; then echo "Docker compose override file found for [$PROJECT_NAME] environment [$ENVIRONMENT]" - COMPOSE_FILES="$COMPOSE_FILES -f $PROJECT_DOCKER_COMPOSE_OVERRIDE" + COMPOSE_ARGS+=(-f "$PROJECT_DOCKER_COMPOSE_OVERRIDE") else echo "No docker compose override file for [$PROJECT_NAME] environment [$ENVIRONMENT]" fi -docker compose $COMPOSE_FILES -p "$COMPOSE_PROJECT_NAME" pull -docker compose $COMPOSE_FILES -p "$COMPOSE_PROJECT_NAME" down -docker compose $COMPOSE_FILES -p "$COMPOSE_PROJECT_NAME" up -d - +docker compose "${COMPOSE_ARGS[@]}" -p "$COMPOSE_PROJECT_NAME" pull +docker compose "${COMPOSE_ARGS[@]}" -p "$COMPOSE_PROJECT_NAME" down +docker compose "${COMPOSE_ARGS[@]}" -p "$COMPOSE_PROJECT_NAME" up -d +validate_compose_container_states +wait_for_container_healthchecks From 15ed39ad8b93d61dc3a5a68500ca4596f65d3243 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 May 2026 21:27:54 +0000 Subject: [PATCH 05/14] Add deploy script regression coverage Agent-Logs-Url: https://github.com/taonity/docker-webhook/sessions/8c98fc1f-d103-4c8c-808b-3beaa6f0c7f4 Co-authored-by: GeneralTao2 <42372666+GeneralTao2@users.noreply.github.com> --- test/test-restart-project.sh | 146 +++++++++++++++++++++++++++++++++++ test/test.sh | 2 + 2 files changed, 148 insertions(+) create mode 100755 test/test-restart-project.sh diff --git a/test/test-restart-project.sh b/test/test-restart-project.sh new file mode 100755 index 0000000..16a910b --- /dev/null +++ b/test/test-restart-project.sh @@ -0,0 +1,146 @@ +#!/bin/bash + +set -euo pipefail + +REPO_ROOT=$(cd "$(dirname "$0")/.." && pwd) +TMP_ROOT=$(mktemp -d) +trap 'rm -rf "$TMP_ROOT"' EXIT + +SCRIPT_DIR="$TMP_ROOT/scripts" +MOCK_BIN="$TMP_ROOT/bin" +SHARED_DIR="$TMP_ROOT/shared" +WEBHOOK_ROOT="$TMP_ROOT/webhook" + +mkdir -p "$SCRIPT_DIR" "$MOCK_BIN" "$SHARED_DIR/envs" "$SHARED_DIR/configs" "$WEBHOOK_ROOT/cache" + +sed "s#/etc/webhook#$WEBHOOK_ROOT#g" "$REPO_ROOT/assets/scripts/restart-project.sh" > "$SCRIPT_DIR/restart-project.sh" + +cat > "$SCRIPT_DIR/verify-project.sh" <<'EOF' +#!/bin/bash +exit 0 +EOF + +cat > "$SCRIPT_DIR/extract-file.sh" <<'EOF' +#!/bin/bash +set -euo pipefail +mkdir -p "$3/docker" +cat > "$3/docker/docker-compose.yml" <<'YAML' +services: + app: + image: example/app:latest +YAML +EOF + +cat > "$MOCK_BIN/docker" <<'EOF' +#!/bin/bash +set -euo pipefail + +cmd=$1 +shift + +case "$cmd" in + pull|create|cp|rm) + exit 0 + ;; + logs) + echo "mock logs for $1" + exit 0 + ;; + inspect) + format=$2 + case "$format" in + *com.docker.compose.service*) + echo "app" + ;; + *'.State.Status'*) + echo "${MOCK_CONTAINER_STATUS:-running}" + ;; + *'.State.Health'*) + echo "${MOCK_HEALTH_STATUS:-none}" + ;; + *) + exit 1 + ;; + esac + ;; + compose) + subcmd= + while [ "$#" -gt 0 ]; do + case "$1" in + -f|-p) + shift 2 + ;; + *) + subcmd=$1 + shift + break + ;; + esac + done + + case "$subcmd" in + pull|down|up) + exit 0 + ;; + ps) + if [ "${1:-}" = "-q" ]; then + echo "container-1" + else + echo "NAME STATUS" + fi + exit 0 + ;; + *) + echo "unsupported compose subcommand: $subcmd" >&2 + exit 1 + ;; + esac + ;; + *) + echo "unsupported docker command: $cmd" >&2 + exit 1 + ;; +esac +EOF + +cat > "$MOCK_BIN/chown" <<'EOF' +#!/bin/bash +exit 0 +EOF + +chmod +x \ + "$SCRIPT_DIR/restart-project.sh" \ + "$SCRIPT_DIR/verify-project.sh" \ + "$SCRIPT_DIR/extract-file.sh" \ + "$MOCK_BIN/docker" \ + "$MOCK_BIN/chown" + +printf 'project\n' > "$SHARED_DIR/configs/project-whitelist.list" + +run_restart_project() { + local expected_exit=$1 + shift + + set +e + ( + cd "$SCRIPT_DIR" + PATH="$MOCK_BIN:$PATH" \ + SHARED_DIR_PATH="$SHARED_DIR" \ + DOCKER_USERNAME=tester \ + "$@" \ + ./restart-project.sh project stage + ) >/dev/null 2>&1 + local status=$? + set -e + + if [ "$status" -ne "$expected_exit" ]; then + echo "Expected exit code $expected_exit, got $status" >&2 + exit 1 + fi +} + +bash -n "$SCRIPT_DIR/restart-project.sh" +run_restart_project 0 env DEPLOY_HEALTHCHECK_TIMEOUT=5 MOCK_CONTAINER_STATUS=running MOCK_HEALTH_STATUS=healthy +run_restart_project 1 env MOCK_CONTAINER_STATUS=exited MOCK_HEALTH_STATUS=none + +echo "restart-project.sh tests passed" diff --git a/test/test.sh b/test/test.sh index e085cce..f089fac 100755 --- a/test/test.sh +++ b/test/test.sh @@ -6,6 +6,8 @@ set -e image_name=$(basename "$(dirname "$(pwd)")") +./test-restart-project.sh + docker build -t "generaltao725/$image_name:test" $(dirname $(pwd)) for dir in $(find -mindepth 1 -maxdepth 1 -type d | sort); do From 52a7b74d1fc9fab23821472473e758e73f8c7787 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 May 2026 21:28:40 +0000 Subject: [PATCH 06/14] Cover deploy health check timeout Agent-Logs-Url: https://github.com/taonity/docker-webhook/sessions/8c98fc1f-d103-4c8c-808b-3beaa6f0c7f4 Co-authored-by: GeneralTao2 <42372666+GeneralTao2@users.noreply.github.com> --- test/test-restart-project.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test-restart-project.sh b/test/test-restart-project.sh index 16a910b..88fbad5 100755 --- a/test/test-restart-project.sh +++ b/test/test-restart-project.sh @@ -142,5 +142,6 @@ run_restart_project() { bash -n "$SCRIPT_DIR/restart-project.sh" run_restart_project 0 env DEPLOY_HEALTHCHECK_TIMEOUT=5 MOCK_CONTAINER_STATUS=running MOCK_HEALTH_STATUS=healthy run_restart_project 1 env MOCK_CONTAINER_STATUS=exited MOCK_HEALTH_STATUS=none +run_restart_project 1 env DEPLOY_HEALTHCHECK_TIMEOUT=1 MOCK_CONTAINER_STATUS=running MOCK_HEALTH_STATUS=starting echo "restart-project.sh tests passed" From 2594290aca5e4670ecdca689f3cdffa56164d570 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 May 2026 21:29:29 +0000 Subject: [PATCH 07/14] Address deploy script review feedback Agent-Logs-Url: https://github.com/taonity/docker-webhook/sessions/8c98fc1f-d103-4c8c-808b-3beaa6f0c7f4 Co-authored-by: GeneralTao2 <42372666+GeneralTao2@users.noreply.github.com> --- README.md | 2 +- assets/scripts/restart-project.sh | 8 ++++---- test/test-restart-project.sh | 5 +++++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a119af3..635eb37 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ An example of the usage of the image can be found in a [test](test/run-project-o - `WEBHOOK_SECRET` - you have to create a webhook with a secret placed into its URL `http:///hooks//docker-webhook`. The secret can be then loaded as an environment variable `WEBHOOK_SECRET` in `docker-webhook` service. The secret is used for security purposes. - `DOCKER_USERNAME` - an env var that contains your DockerHub username. - `DEPLOY_DEFAULT_ENV` - (optional) the default environment to deploy to when no environment is specified in the webhook payload. Defaults to `stage` if not set. - - `DEPLOY_HEALTHCHECK_TIMEOUT` - (optional) wait this many seconds for Docker health checks after `docker compose up -d`. When set to a value greater than `0`, the deploy script fails if any service exits early, becomes unhealthy, or does not become healthy before the timeout. When omitted or set to `0`, health-check waiting is skipped. + - `DEPLOY_HEALTHCHECK_TIMEOUT` - (optional) a non-negative integer number of seconds to wait for Docker health checks after `docker compose up -d`. When set to a value greater than `0`, the deploy script fails if any service exits early, becomes unhealthy, or does not become healthy before the timeout. When omitted or set to `0`, health-check waiting is skipped. - `project-whitelist.list` - is a file with target image names being listed (without owner name). The tool will check if the list contains the image name from webhook details and will proceed only on finding a match. Each image name should be written from the new line. The file should placed in `shared/config` folder and the `shared` folder should be mounted into `/etc/webhook/shared` of the container. - `envs` - a folder that loads env vars for each docker compose project. Envs should be stored in `.envs` file a placed in `shared/-/` folder (e.g., `shared/envs/myapp-stage/` or `shared/envs/myapp-prod/`). The `shared` folder should be mounted into `/etc/webhook/shared` of the container. This configuration is optional. - `docker-compose.override.yml` - (optional) you can place environment-specific Docker Compose override files in `shared/envs/-/docker-compose.override.yml`. These override files will be automatically applied when deploying to that environment, allowing you to customize ports, volumes, environment variables, or any other Docker Compose settings per environment. diff --git a/assets/scripts/restart-project.sh b/assets/scripts/restart-project.sh index 8331307..eb81727 100755 --- a/assets/scripts/restart-project.sh +++ b/assets/scripts/restart-project.sh @@ -20,7 +20,7 @@ PROJECT_DOCKER_COMPOSE_OVERRIDE= COMPOSE_PROJECT_NAME= declare -a COMPOSE_ARGS=() -print_container_logs() { +print_service_logs() { local container_id=$1 local service_name=$2 @@ -52,7 +52,7 @@ validate_compose_container_states() { *) echo "WARN! Service [$service_name] is in [$container_status] state after deploy" docker compose "${COMPOSE_ARGS[@]}" -p "$COMPOSE_PROJECT_NAME" ps - print_container_logs "$container_id" "$service_name" + print_service_logs "$container_id" "$service_name" exit 1 ;; esac @@ -98,13 +98,13 @@ wait_for_container_healthchecks() { unhealthy) echo "WARN! Service [$service_name] failed its health check after deploy" docker compose "${COMPOSE_ARGS[@]}" -p "$COMPOSE_PROJECT_NAME" ps - print_container_logs "$container_id" "$service_name" + print_service_logs "$container_id" "$service_name" exit 1 ;; *) echo "WARN! Service [$service_name] returned unexpected health status [$health_status]" docker compose "${COMPOSE_ARGS[@]}" -p "$COMPOSE_PROJECT_NAME" ps - print_container_logs "$container_id" "$service_name" + print_service_logs "$container_id" "$service_name" exit 1 ;; esac diff --git a/test/test-restart-project.sh b/test/test-restart-project.sh index 88fbad5..0e0ce16 100755 --- a/test/test-restart-project.sh +++ b/test/test-restart-project.sh @@ -84,6 +84,9 @@ case "$cmd" in ;; ps) if [ "${1:-}" = "-q" ]; then + if [ "${MOCK_NO_CONTAINERS:-0}" = "1" ]; then + exit 0 + fi echo "container-1" else echo "NAME STATUS" @@ -142,6 +145,8 @@ run_restart_project() { bash -n "$SCRIPT_DIR/restart-project.sh" run_restart_project 0 env DEPLOY_HEALTHCHECK_TIMEOUT=5 MOCK_CONTAINER_STATUS=running MOCK_HEALTH_STATUS=healthy run_restart_project 1 env MOCK_CONTAINER_STATUS=exited MOCK_HEALTH_STATUS=none +run_restart_project 1 env DEPLOY_HEALTHCHECK_TIMEOUT=5 MOCK_CONTAINER_STATUS=running MOCK_HEALTH_STATUS=unhealthy run_restart_project 1 env DEPLOY_HEALTHCHECK_TIMEOUT=1 MOCK_CONTAINER_STATUS=running MOCK_HEALTH_STATUS=starting +run_restart_project 1 env MOCK_NO_CONTAINERS=1 echo "restart-project.sh tests passed" From 8c7abbfcb9de5c036208d6faab30031c61ef757e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 May 2026 21:30:10 +0000 Subject: [PATCH 08/14] Polish deploy timeout handling Agent-Logs-Url: https://github.com/taonity/docker-webhook/sessions/8c98fc1f-d103-4c8c-808b-3beaa6f0c7f4 Co-authored-by: GeneralTao2 <42372666+GeneralTao2@users.noreply.github.com> --- assets/scripts/restart-project.sh | 7 ++++--- test/test-restart-project.sh | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/assets/scripts/restart-project.sh b/assets/scripts/restart-project.sh index eb81727..05149de 100755 --- a/assets/scripts/restart-project.sh +++ b/assets/scripts/restart-project.sh @@ -61,7 +61,7 @@ validate_compose_container_states() { wait_for_container_healthchecks() { local healthcheck_timeout=${DEPLOY_HEALTHCHECK_TIMEOUT:-0} - local deadline container_id service_name health_status has_healthcheck pending_healthchecks + local start_time current_time container_id service_name health_status has_healthcheck pending_healthchecks if ! [[ "$healthcheck_timeout" =~ ^[0-9]+$ ]]; then echo "WARN! DEPLOY_HEALTHCHECK_TIMEOUT must be a non-negative integer, got [$healthcheck_timeout]" @@ -73,7 +73,7 @@ wait_for_container_healthchecks() { fi echo "Waiting up to [$healthcheck_timeout] seconds for container health checks" - deadline=$((SECONDS + healthcheck_timeout)) + start_time=$(date +%s) while true; do has_healthcheck=false @@ -120,7 +120,8 @@ wait_for_container_healthchecks() { return 0 fi - if [ "$SECONDS" -ge "$deadline" ]; then + current_time=$(date +%s) + if [ $((current_time - start_time)) -ge "$healthcheck_timeout" ]; then echo "WARN! Timed out waiting [$healthcheck_timeout] seconds for container health checks" docker compose "${COMPOSE_ARGS[@]}" -p "$COMPOSE_PROJECT_NAME" ps exit 1 diff --git a/test/test-restart-project.sh b/test/test-restart-project.sh index 0e0ce16..77500d2 100755 --- a/test/test-restart-project.sh +++ b/test/test-restart-project.sh @@ -10,10 +10,11 @@ SCRIPT_DIR="$TMP_ROOT/scripts" MOCK_BIN="$TMP_ROOT/bin" SHARED_DIR="$TMP_ROOT/shared" WEBHOOK_ROOT="$TMP_ROOT/webhook" +ESCAPED_WEBHOOK_ROOT=$(printf '%s\n' "$WEBHOOK_ROOT" | sed 's/[&#]/\\&/g') mkdir -p "$SCRIPT_DIR" "$MOCK_BIN" "$SHARED_DIR/envs" "$SHARED_DIR/configs" "$WEBHOOK_ROOT/cache" -sed "s#/etc/webhook#$WEBHOOK_ROOT#g" "$REPO_ROOT/assets/scripts/restart-project.sh" > "$SCRIPT_DIR/restart-project.sh" +sed "s#/etc/webhook#$ESCAPED_WEBHOOK_ROOT#g" "$REPO_ROOT/assets/scripts/restart-project.sh" > "$SCRIPT_DIR/restart-project.sh" cat > "$SCRIPT_DIR/verify-project.sh" <<'EOF' #!/bin/bash @@ -64,7 +65,7 @@ case "$cmd" in esac ;; compose) - subcmd= + subcmd='' while [ "$#" -gt 0 ]; do case "$1" in -f|-p) From 2856dc2223d1ddfc15703b8e04e57d6e8dc30f87 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 May 2026 21:30:53 +0000 Subject: [PATCH 09/14] Polish deploy script regression tests Agent-Logs-Url: https://github.com/taonity/docker-webhook/sessions/8c98fc1f-d103-4c8c-808b-3beaa6f0c7f4 Co-authored-by: GeneralTao2 <42372666+GeneralTao2@users.noreply.github.com> --- assets/scripts/restart-project.sh | 4 +++- test/test-restart-project.sh | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/assets/scripts/restart-project.sh b/assets/scripts/restart-project.sh index 05149de..5fd899b 100755 --- a/assets/scripts/restart-project.sh +++ b/assets/scripts/restart-project.sh @@ -19,6 +19,8 @@ PROJECT_DOCKER_COMPOSE_FILE= PROJECT_DOCKER_COMPOSE_OVERRIDE= COMPOSE_PROJECT_NAME= declare -a COMPOSE_ARGS=() +declare -a COMPOSE_CONTAINER_IDS=() +HEALTHCHECK_POLL_INTERVAL=2 print_service_logs() { local container_id=$1 @@ -127,7 +129,7 @@ wait_for_container_healthchecks() { exit 1 fi - sleep 2 + sleep "$HEALTHCHECK_POLL_INTERVAL" done } diff --git a/test/test-restart-project.sh b/test/test-restart-project.sh index 77500d2..1297cbd 100755 --- a/test/test-restart-project.sh +++ b/test/test-restart-project.sh @@ -10,7 +10,7 @@ SCRIPT_DIR="$TMP_ROOT/scripts" MOCK_BIN="$TMP_ROOT/bin" SHARED_DIR="$TMP_ROOT/shared" WEBHOOK_ROOT="$TMP_ROOT/webhook" -ESCAPED_WEBHOOK_ROOT=$(printf '%s\n' "$WEBHOOK_ROOT" | sed 's/[&#]/\\&/g') +ESCAPED_WEBHOOK_ROOT=$(printf '%s\n' "$WEBHOOK_ROOT" | sed 's#[/&]#\\&#g') mkdir -p "$SCRIPT_DIR" "$MOCK_BIN" "$SHARED_DIR/envs" "$SHARED_DIR/configs" "$WEBHOOK_ROOT/cache" From 7a7237480e7cf4fa07bdcf93e9e2eb3d949ffe7c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 May 2026 21:31:39 +0000 Subject: [PATCH 10/14] Finalize deploy script hardening Agent-Logs-Url: https://github.com/taonity/docker-webhook/sessions/8c98fc1f-d103-4c8c-808b-3beaa6f0c7f4 Co-authored-by: GeneralTao2 <42372666+GeneralTao2@users.noreply.github.com> --- assets/scripts/restart-project.sh | 11 +++++++++-- test/test-restart-project.sh | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/assets/scripts/restart-project.sh b/assets/scripts/restart-project.sh index 5fd899b..6766dab 100755 --- a/assets/scripts/restart-project.sh +++ b/assets/scripts/restart-project.sh @@ -31,7 +31,14 @@ print_service_logs() { } get_compose_container_ids() { - mapfile -t COMPOSE_CONTAINER_IDS < <(docker compose "${COMPOSE_ARGS[@]}" -p "$COMPOSE_PROJECT_NAME" ps -q) + local container_ids_output + + container_ids_output=$(docker compose "${COMPOSE_ARGS[@]}" -p "$COMPOSE_PROJECT_NAME" ps -q) + + COMPOSE_CONTAINER_IDS=() + if [ -n "$container_ids_output" ]; then + mapfile -t COMPOSE_CONTAINER_IDS <<< "$container_ids_output" + fi if [ "${#COMPOSE_CONTAINER_IDS[@]}" -eq 0 ]; then echo "WARN! Deploy for [$PROJECT_NAME] environment [$ENVIRONMENT] did not create any containers" @@ -65,7 +72,7 @@ wait_for_container_healthchecks() { local healthcheck_timeout=${DEPLOY_HEALTHCHECK_TIMEOUT:-0} local start_time current_time container_id service_name health_status has_healthcheck pending_healthchecks - if ! [[ "$healthcheck_timeout" =~ ^[0-9]+$ ]]; then + if ! [[ "$healthcheck_timeout" =~ ^(0|[1-9][0-9]*)$ ]]; then echo "WARN! DEPLOY_HEALTHCHECK_TIMEOUT must be a non-negative integer, got [$healthcheck_timeout]" exit 1 fi diff --git a/test/test-restart-project.sh b/test/test-restart-project.sh index 1297cbd..b1998eb 100755 --- a/test/test-restart-project.sh +++ b/test/test-restart-project.sh @@ -4,7 +4,7 @@ set -euo pipefail REPO_ROOT=$(cd "$(dirname "$0")/.." && pwd) TMP_ROOT=$(mktemp -d) -trap 'rm -rf "$TMP_ROOT"' EXIT +trap 'if [[ -n "${TMP_ROOT:-}" && "$TMP_ROOT" == /tmp/* ]]; then rm -rf "$TMP_ROOT"; fi' EXIT SCRIPT_DIR="$TMP_ROOT/scripts" MOCK_BIN="$TMP_ROOT/bin" From 3ad8458629778c8bece43047bda2e61c3c722a31 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 May 2026 21:32:16 +0000 Subject: [PATCH 11/14] Adjust deploy script test cleanup Agent-Logs-Url: https://github.com/taonity/docker-webhook/sessions/8c98fc1f-d103-4c8c-808b-3beaa6f0c7f4 Co-authored-by: GeneralTao2 <42372666+GeneralTao2@users.noreply.github.com> --- test/test-restart-project.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-restart-project.sh b/test/test-restart-project.sh index b1998eb..1579ace 100755 --- a/test/test-restart-project.sh +++ b/test/test-restart-project.sh @@ -4,7 +4,7 @@ set -euo pipefail REPO_ROOT=$(cd "$(dirname "$0")/.." && pwd) TMP_ROOT=$(mktemp -d) -trap 'if [[ -n "${TMP_ROOT:-}" && "$TMP_ROOT" == /tmp/* ]]; then rm -rf "$TMP_ROOT"; fi' EXIT +trap 'if [[ -n "${TMP_ROOT:-}" && -d "$TMP_ROOT" ]]; then rm -rf "$TMP_ROOT"; fi' EXIT SCRIPT_DIR="$TMP_ROOT/scripts" MOCK_BIN="$TMP_ROOT/bin" From 0647750eaa0e1cd25afb24d431642a0f55b0b884 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 12 May 2026 10:01:00 +0000 Subject: [PATCH 12/14] Stabilize Dockerfile package installs Agent-Logs-Url: https://github.com/taonity/docker-webhook/sessions/f8db322e-3d51-4f77-ad06-6994084e5b64 Co-authored-by: GeneralTao2 <42372666+GeneralTao2@users.noreply.github.com> --- Dockerfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 896c9e3..385a935 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM thecatlady/webhook:2.8.2 WORKDIR /etc/webhook COPY assets /etc/webhook/assets ENV SHARED_DIR_PATH=/etc/webhook/shared -RUN apk update && apk add --no-cache docker-cli bash dos2unix +RUN apk add --no-cache docker-cli bash dos2unix RUN find /etc/webhook/assets/scripts -type f -name '*.sh' -exec dos2unix {} \; RUN echo https://ftp.halifax.rwth-aachen.de/alpine/v3.17/main >> /etc/apk/repositories RUN echo https://ftp.halifax.rwth-aachen.de/alpine/v3.17/community >> /etc/apk/repositories @@ -11,11 +11,11 @@ ENV BUILD_DEPS="gettext" \ RUNTIME_DEPS="libintl" RUN set -x && \ - apk add --update $RUNTIME_DEPS && \ + apk add --no-cache $RUNTIME_DEPS && \ apk add --virtual build_deps $BUILD_DEPS && \ cp /usr/bin/envsubst /usr/local/bin/envsubst && \ apk del build_deps -RUN apk update --allow-untrusted && apk add --allow-untrusted --no-cache docker-cli-compose +RUN apk add --allow-untrusted --no-cache docker-cli-compose -ENTRYPOINT ["/etc/webhook/assets/scripts/entrypoint.sh"] \ No newline at end of file +ENTRYPOINT ["/etc/webhook/assets/scripts/entrypoint.sh"] From ee3a35ed5c444d658074105cb15894391b45214e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 12 May 2026 10:04:31 +0000 Subject: [PATCH 13/14] Allow one-shot deploys without health checks Agent-Logs-Url: https://github.com/taonity/docker-webhook/sessions/f8db322e-3d51-4f77-ad06-6994084e5b64 Co-authored-by: GeneralTao2 <42372666+GeneralTao2@users.noreply.github.com> --- README.md | 2 +- assets/scripts/restart-project.sh | 8 +++----- test/test-restart-project.sh | 5 +++-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 635eb37..f5ba93c 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ An example of the usage of the image can be found in a [test](test/run-project-o - `WEBHOOK_SECRET` - you have to create a webhook with a secret placed into its URL `http:///hooks//docker-webhook`. The secret can be then loaded as an environment variable `WEBHOOK_SECRET` in `docker-webhook` service. The secret is used for security purposes. - `DOCKER_USERNAME` - an env var that contains your DockerHub username. - `DEPLOY_DEFAULT_ENV` - (optional) the default environment to deploy to when no environment is specified in the webhook payload. Defaults to `stage` if not set. - - `DEPLOY_HEALTHCHECK_TIMEOUT` - (optional) a non-negative integer number of seconds to wait for Docker health checks after `docker compose up -d`. When set to a value greater than `0`, the deploy script fails if any service exits early, becomes unhealthy, or does not become healthy before the timeout. When omitted or set to `0`, health-check waiting is skipped. + - `DEPLOY_HEALTHCHECK_TIMEOUT` - (optional) a non-negative integer number of seconds to wait for Docker health checks after `docker compose up -d`. When set to a value greater than `0`, the deploy script fails if any service exits while waiting, becomes unhealthy, or does not become healthy before the timeout. When omitted or set to `0`, the deploy only relies on the Docker Compose command result, which keeps one-shot jobs supported. - `project-whitelist.list` - is a file with target image names being listed (without owner name). The tool will check if the list contains the image name from webhook details and will proceed only on finding a match. Each image name should be written from the new line. The file should placed in `shared/config` folder and the `shared` folder should be mounted into `/etc/webhook/shared` of the container. - `envs` - a folder that loads env vars for each docker compose project. Envs should be stored in `.envs` file a placed in `shared/-/` folder (e.g., `shared/envs/myapp-stage/` or `shared/envs/myapp-prod/`). The `shared` folder should be mounted into `/etc/webhook/shared` of the container. This configuration is optional. - `docker-compose.override.yml` - (optional) you can place environment-specific Docker Compose override files in `shared/envs/-/docker-compose.override.yml`. These override files will be automatically applied when deploying to that environment, allowing you to customize ports, volumes, environment variables, or any other Docker Compose settings per environment. diff --git a/assets/scripts/restart-project.sh b/assets/scripts/restart-project.sh index 6766dab..e637bcb 100755 --- a/assets/scripts/restart-project.sh +++ b/assets/scripts/restart-project.sh @@ -46,11 +46,9 @@ get_compose_container_ids() { fi } -validate_compose_container_states() { +ensure_healthcheck_containers_are_active() { local container_id service_name container_status - get_compose_container_ids - for container_id in "${COMPOSE_CONTAINER_IDS[@]}"; do service_name=$(docker inspect --format '{{index .Config.Labels "com.docker.compose.service"}}' "$container_id") container_status=$(docker inspect --format '{{.State.Status}}' "$container_id") @@ -88,7 +86,8 @@ wait_for_container_healthchecks() { has_healthcheck=false pending_healthchecks=false - validate_compose_container_states + get_compose_container_ids + ensure_healthcheck_containers_are_active for container_id in "${COMPOSE_CONTAINER_IDS[@]}"; do service_name=$(docker inspect --format '{{index .Config.Labels "com.docker.compose.service"}}' "$container_id") @@ -191,5 +190,4 @@ docker compose "${COMPOSE_ARGS[@]}" -p "$COMPOSE_PROJECT_NAME" pull docker compose "${COMPOSE_ARGS[@]}" -p "$COMPOSE_PROJECT_NAME" down docker compose "${COMPOSE_ARGS[@]}" -p "$COMPOSE_PROJECT_NAME" up -d -validate_compose_container_states wait_for_container_healthchecks diff --git a/test/test-restart-project.sh b/test/test-restart-project.sh index 1579ace..0869ff1 100755 --- a/test/test-restart-project.sh +++ b/test/test-restart-project.sh @@ -145,9 +145,10 @@ run_restart_project() { bash -n "$SCRIPT_DIR/restart-project.sh" run_restart_project 0 env DEPLOY_HEALTHCHECK_TIMEOUT=5 MOCK_CONTAINER_STATUS=running MOCK_HEALTH_STATUS=healthy -run_restart_project 1 env MOCK_CONTAINER_STATUS=exited MOCK_HEALTH_STATUS=none +run_restart_project 0 env MOCK_CONTAINER_STATUS=exited MOCK_HEALTH_STATUS=none +run_restart_project 1 env DEPLOY_HEALTHCHECK_TIMEOUT=5 MOCK_CONTAINER_STATUS=exited MOCK_HEALTH_STATUS=none run_restart_project 1 env DEPLOY_HEALTHCHECK_TIMEOUT=5 MOCK_CONTAINER_STATUS=running MOCK_HEALTH_STATUS=unhealthy run_restart_project 1 env DEPLOY_HEALTHCHECK_TIMEOUT=1 MOCK_CONTAINER_STATUS=running MOCK_HEALTH_STATUS=starting -run_restart_project 1 env MOCK_NO_CONTAINERS=1 +run_restart_project 1 env DEPLOY_HEALTHCHECK_TIMEOUT=5 MOCK_NO_CONTAINERS=1 echo "restart-project.sh tests passed" From 4ca9099e643057b6be8c7f0cac67e5ef6fd3aa80 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 12 May 2026 10:06:43 +0000 Subject: [PATCH 14/14] Refine deploy failure messages Agent-Logs-Url: https://github.com/taonity/docker-webhook/sessions/f8db322e-3d51-4f77-ad06-6994084e5b64 Co-authored-by: GeneralTao2 <42372666+GeneralTao2@users.noreply.github.com> --- assets/scripts/restart-project.sh | 12 ++++++------ test/test-restart-project.sh | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/assets/scripts/restart-project.sh b/assets/scripts/restart-project.sh index e637bcb..cf750f2 100755 --- a/assets/scripts/restart-project.sh +++ b/assets/scripts/restart-project.sh @@ -41,7 +41,7 @@ get_compose_container_ids() { fi if [ "${#COMPOSE_CONTAINER_IDS[@]}" -eq 0 ]; then - echo "WARN! Deploy for [$PROJECT_NAME] environment [$ENVIRONMENT] did not create any containers" + echo "ERROR! Deploy for [$PROJECT_NAME] environment [$ENVIRONMENT] did not create any containers" exit 1 fi } @@ -57,7 +57,7 @@ ensure_healthcheck_containers_are_active() { running) ;; *) - echo "WARN! Service [$service_name] is in [$container_status] state after deploy" + echo "ERROR! Service [$service_name] is in [$container_status] state after deploy" docker compose "${COMPOSE_ARGS[@]}" -p "$COMPOSE_PROJECT_NAME" ps print_service_logs "$container_id" "$service_name" exit 1 @@ -71,7 +71,7 @@ wait_for_container_healthchecks() { local start_time current_time container_id service_name health_status has_healthcheck pending_healthchecks if ! [[ "$healthcheck_timeout" =~ ^(0|[1-9][0-9]*)$ ]]; then - echo "WARN! DEPLOY_HEALTHCHECK_TIMEOUT must be a non-negative integer, got [$healthcheck_timeout]" + echo "ERROR! DEPLOY_HEALTHCHECK_TIMEOUT must be a non-negative integer, got [$healthcheck_timeout]" exit 1 fi @@ -104,13 +104,13 @@ wait_for_container_healthchecks() { pending_healthchecks=true ;; unhealthy) - echo "WARN! Service [$service_name] failed its health check after deploy" + echo "ERROR! Service [$service_name] failed its health check after deploy" docker compose "${COMPOSE_ARGS[@]}" -p "$COMPOSE_PROJECT_NAME" ps print_service_logs "$container_id" "$service_name" exit 1 ;; *) - echo "WARN! Service [$service_name] returned unexpected health status [$health_status]" + echo "ERROR! Service [$service_name] returned unexpected health status [$health_status]" docker compose "${COMPOSE_ARGS[@]}" -p "$COMPOSE_PROJECT_NAME" ps print_service_logs "$container_id" "$service_name" exit 1 @@ -130,7 +130,7 @@ wait_for_container_healthchecks() { current_time=$(date +%s) if [ $((current_time - start_time)) -ge "$healthcheck_timeout" ]; then - echo "WARN! Timed out waiting [$healthcheck_timeout] seconds for container health checks" + echo "ERROR! Timed out waiting [$healthcheck_timeout] seconds for container health checks" docker compose "${COMPOSE_ARGS[@]}" -p "$COMPOSE_PROJECT_NAME" ps exit 1 fi diff --git a/test/test-restart-project.sh b/test/test-restart-project.sh index 0869ff1..008c268 100755 --- a/test/test-restart-project.sh +++ b/test/test-restart-project.sh @@ -145,6 +145,7 @@ run_restart_project() { bash -n "$SCRIPT_DIR/restart-project.sh" run_restart_project 0 env DEPLOY_HEALTHCHECK_TIMEOUT=5 MOCK_CONTAINER_STATUS=running MOCK_HEALTH_STATUS=healthy +run_restart_project 0 env MOCK_CONTAINER_STATUS=running MOCK_HEALTH_STATUS=none run_restart_project 0 env MOCK_CONTAINER_STATUS=exited MOCK_HEALTH_STATUS=none run_restart_project 1 env DEPLOY_HEALTHCHECK_TIMEOUT=5 MOCK_CONTAINER_STATUS=exited MOCK_HEALTH_STATUS=none run_restart_project 1 env DEPLOY_HEALTHCHECK_TIMEOUT=5 MOCK_CONTAINER_STATUS=running MOCK_HEALTH_STATUS=unhealthy