From 6c3936802e12065c34b73759ff140aff9f272740 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Thu, 8 Jan 2026 02:46:44 -0500 Subject: [PATCH] feat: add a method to force build when re-using an image with git:from-image Closes #6847 --- docs/deployment/methods/image.md | 8 +++++++- plugins/git/git-from-image | 11 +++++++++-- plugins/git/internal-functions | 11 ++++++++++- tests/unit/git_4.bats | 22 ++++++++++++++++++++++ 4 files changed, 48 insertions(+), 4 deletions(-) diff --git a/docs/deployment/methods/image.md b/docs/deployment/methods/image.md index aca831f9b..bc180a9f7 100644 --- a/docs/deployment/methods/image.md +++ b/docs/deployment/methods/image.md @@ -17,7 +17,13 @@ In the above example, Dokku will build the app as if the repository contained _o FROM my-registry/node-js-getting-started:latest ``` -If the specified image already exists on the Dokku host, it will not be pulled again, though this behavior may be changed using [build phase docker-options](/docs/advanced-usage/docker-options.md). +If the specified image already exists on the Dokku host, it will not be pulled again. To force a pull even when the image exists locally, use the `--force` flag: + +```shell +dokku git:from-image --force node-js-app my-registry/node-js-getting-started:latest +``` + +This is useful when the remote image has been updated but the tag remains the same. Triggering a build with the same arguments multiple times will result in Dokku exiting `0` early as there will be no changes detected. If the image tag is reused but the underlying image is different, it is recommended to use the image digest instead of the tag. This can be retrieved via the following command: diff --git a/plugins/git/git-from-image b/plugins/git/git-from-image index 8977a810a..e5731d2d9 100755 --- a/plugins/git/git-from-image +++ b/plugins/git/git-from-image @@ -26,9 +26,16 @@ trigger-git-git-from-image() { echo "FROM $DOCKER_IMAGE" >>"$TMP_WORK_DIR/Dockerfile" echo "LABEL com.dokku.docker-image-labeler/alternate-tags=[\\\"$DOCKER_IMAGE\\\"]" >>"$TMP_WORK_DIR/Dockerfile" - if [[ "$(docker images -q "$DOCKER_IMAGE" 2>/dev/null)" == "" ]]; then + if [[ "$("$DOCKER_BIN" image ls -q "$DOCKER_IMAGE" 2>/dev/null)" == "" ]]; then dokku_log_info1 "Pulling image" - "$DOCKER_BIN" image pull "$DOCKER_IMAGE" + if ! "$DOCKER_BIN" image pull "$DOCKER_IMAGE"; then + dokku_log_fail "Failed to pull image: $DOCKER_IMAGE" + fi + elif [[ "$DOKKU_APPS_FORCE_DELETE" == "1" ]]; then + dokku_log_info1 "Force pulling image" + if ! "$DOCKER_BIN" image pull "$DOCKER_IMAGE"; then + dokku_log_fail "Failed to pull image: $DOCKER_IMAGE" + fi else dokku_log_info1 "Image exists on host, skipping pull" fi diff --git a/plugins/git/internal-functions b/plugins/git/internal-functions index 5641cd923..5652725f7 100755 --- a/plugins/git/internal-functions +++ b/plugins/git/internal-functions @@ -141,7 +141,7 @@ cmd-git-from-image() { local cmd="git:from-image" [[ "$1" == "$cmd" ]] && shift 1 declare APP DOCKER_IMAGE USER_NAME USER_EMAIL - local BUILD_DIR + local BUILD_DIR FORCE=false ARGS=() skip=false @@ -151,6 +151,11 @@ cmd-git-from-image() { continue fi + if [[ "$arg" == "--force" ]]; then + FORCE=true + continue + fi + if [[ "$skip" == "true" ]]; then BUILD_DIR="$arg" skip=false @@ -168,6 +173,10 @@ cmd-git-from-image() { verify_app_name "$APP" [[ -z "$DOCKER_IMAGE" ]] && dokku_log_fail "Please specify a docker image" + if [[ "$FORCE" == "true" ]]; then + export DOKKU_APPS_FORCE_DELETE=1 + fi + if ! plugn trigger git-from-image "$APP" "$DOCKER_IMAGE" "$BUILD_DIR" "$USER_NAME" "$USER_EMAIL"; then return 1 fi diff --git a/tests/unit/git_4.bats b/tests/unit/git_4.bats index 2d29aec68..3abdc460b 100644 --- a/tests/unit/git_4.bats +++ b/tests/unit/git_4.bats @@ -35,6 +35,28 @@ teardown() { assert_output "ref: refs/heads/master" } +@test "(git) git:from-image --force" { + run /bin/bash -c "docker image rm linuxserver/foldingathome:7.6.21 2>/dev/null || true" + + run /bin/bash -c "dokku git:from-image $TEST_APP linuxserver/foldingathome:7.6.21" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "Pulling image" + + run /bin/bash -c "dokku git:from-image $TEST_APP linuxserver/foldingathome:7.6.21" + echo "output: $output" + echo "status: $status" + assert_output_contains "Image exists on host, skipping pull" + assert_output_contains "No changes detected, skipping git commit" + + run /bin/bash -c "dokku git:from-image --force $TEST_APP linuxserver/foldingathome:7.6.21" + echo "output: $output" + echo "status: $status" + assert_output_contains "Force pulling image" + assert_output_contains "No changes detected, skipping git commit" +} + @test "(git) git:from-image [normal-custom-branch]" { run /bin/bash -c "dokku git:set $TEST_APP deploy-branch main" echo "output: $output"