Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions lib/kitchen/docker/helpers/image_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ module ImageHelper
include Kitchen::Docker::Helpers::CliHelper
include Kitchen::Docker::Helpers::ContainerHelper

# An id on a line of its own, which is all `docker build -q` prints.
QUIET_BUILD_IMAGE_ID = /\A(sha256:[[:xdigit:]]{64})\z/

# Pulls the built image's id out of `docker build` output.
#
# Scanned in reverse, and against several patterns, because the wording has
Expand All @@ -37,6 +40,13 @@ module ImageHelper
# @raise [Kitchen::ActionFailed] if no id could be found
def parse_image_id(output)
output.split("\n").reverse_each do |line|
line = line.strip
# `docker build -q` prints the id and nothing else -- none of the
# wording below appears -- so a build with `build_options: -q` had
# no line any of these matched and failed with "Could not parse
# Docker build output for image ID" (#225).
return Regexp.last_match(1) if line.match(QUIET_BUILD_IMAGE_ID)

if line =~ /writing image (sha256:[[:xdigit:]]{64})(?: \d*\.\ds)? done/i
img_id = line[/writing image (sha256:[[:xdigit:]]{64})(?: \d*\.\ds)? done/i, 1]
return img_id
Expand Down
24 changes: 24 additions & 0 deletions spec/image_helper_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,30 @@

describe Kitchen::Docker::Helpers::ImageHelper do
describe "#parse_image_id" do
# From #225. `docker build -q` prints the id on a line of its own and
# nothing else -- no "writing image", no "naming to", no "successfully
# built" -- so every pattern the parser had missed it, and a build with
# `build_options: -q` failed with "Could not parse Docker build output for
# image ID" rather than producing an instance.
context "with a quiet build" do
it "reads the id docker printed on its own" do
expect(helper.parse_image_id(DockerOutput::BUILD_QUIET))
.to eq DockerOutput::BUILD_QUIET_IMAGE_ID
end

it "reads it when docker also wrote a warning to stderr" do
expect(helper.parse_image_id("WARNING: something happened\n#{DockerOutput::BUILD_QUIET}"))
.to eq DockerOutput::BUILD_QUIET_IMAGE_ID
end

it "does not mistake a digest that is part of a longer line for the id" do
# Ordinary build output is full of "... sha256:... done" lines. Only a
# line that is nothing but a digest is the quiet form.
expect { helper.parse_image_id("#6 exporting manifest sha256:#{"a" * 64} done\n") }
.to raise_error(Kitchen::ActionFailed)
end
end

# Docker has changed how it reports the built image's id several times, and
# each change has broken this parser. Every format the driver claims to
# support gets a case here, against output copied from a real build.
Expand Down
9 changes: 9 additions & 0 deletions spec/support/docker_output.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@ module DockerOutput

BUILD_LEGACY_IMAGE_ID = "1a2b3c4d5e6f".freeze

# `docker build -q` on Docker 29.7.2. Quiet mode prints the id and nothing
# else -- no step lines, no exporting lines, none of the wording the other
# fixtures here are built around. Reachable through the driver as
# `build_options: -q`.
BUILD_QUIET = "sha256:ab86ce908a36ffb7de411a72550e416a4d8c268570a0f7313c284c79344d6c0f\n".freeze

BUILD_QUIET_IMAGE_ID =
"sha256:ab86ce908a36ffb7de411a72550e416a4d8c268570a0f7313c284c79344d6c0f".freeze

# `docker run -d`, the ordinary case: the id and nothing else.
RUN_CONTAINER_ID = "b89e1e8b07664a1ee0bd09decb833146eaf9cc810a152950e3576a56745944db".freeze
RUN_CLEAN = "#{RUN_CONTAINER_ID}\n".freeze
Expand Down