Build from a git archive

Building directly from a checkout will pull in uncommitted files to or
more sneakily files that are git ignored, but not docker ignored.

To avoid this, we'll add an option to build from a git archive of HEAD
instead. Docker doesn't provide a way to build directly from a git
repo, so instead we create a tarball of the current HEAD with git
archive and pipe it into the build command.

When building from a git archive, we'll still display the warning about
uncommitted changes, but we won't add the `_uncommitted_...` suffix to
the container name as they won't be included in the build.

Perhaps this should be the default, but we'll leave that decision for
now.
This commit is contained in:
Donal McBreen
2024-03-04 14:57:55 +00:00
parent 786454f2ee
commit f3b7569032
11 changed files with 100 additions and 34 deletions

View File

@@ -123,6 +123,34 @@ class CommandsBuilderTest < ActiveSupport::TestCase
assert_equal "docker inspect -f '{{ .Config.Labels.service }}' dhh/app:123 | grep -x app || (echo \"Image dhh/app:123 is missing the 'service' label\" && exit 1)", new_builder_command.validate_image.join(" ")
end
test "multiarch git archive build" do
builder = new_builder_command(builder: { "git_archive" => true })
assert_equal \
"git archive --format=tar HEAD | docker buildx build --push --platform linux/amd64,linux/arm64 --builder kamal-app-multiarch -t dhh/app:123 -t dhh/app:latest --label service=\"app\" --file Dockerfile -",
builder.push.join(" ")
end
test "native git archive build" do
builder = new_builder_command(builder: { "multiarch" => false, "git_archive" => true })
assert_equal \
"git archive --format=tar HEAD | docker build -t dhh/app:123 -t dhh/app:latest --label service=\"app\" --file Dockerfile - && docker push dhh/app:123 && docker push dhh/app:latest",
builder.push.join(" ")
end
test "cached git archive build" do
builder = new_builder_command(builder: { "multiarch" => false, "git_archive" => true, "cache" => { "type" => "gha" } })
assert_equal \
"git archive --format=tar HEAD | docker buildx build --push -t dhh/app:123 -t dhh/app:latest --cache-to type=gha --cache-from type=gha --label service=\"app\" --file Dockerfile -",
builder.push.join(" ")
end
test "remote git archive build" do
builder = new_builder_command(builder: { "remote" => { "arch" => "amd64" }, "git_archive" => true })
assert_equal \
"git archive --format=tar HEAD | docker buildx build --push --platform linux/amd64 --builder kamal-app-native-remote -t dhh/app:123 -t dhh/app:latest --label service=\"app\" --file Dockerfile -",
builder.push.join(" ")
end
private
def new_builder_command(additional_config = {})
Kamal::Commands::Builder.new(Kamal::Configuration.new(@config.merge(additional_config), version: "123"))

View File

@@ -106,6 +106,16 @@ class ConfigurationTest < ActiveSupport::TestCase
assert_match /^git-version_uncommitted_[0-9a-f]{16}$/, @config.version
end
test "version from git archive uncommitted" do
ENV.delete("VERSION")
config = Kamal::Configuration.new(@deploy.tap { |c| c[:builder] = { "git_archive" => true } })
Kamal::Git.expects(:revision).returns("git-version")
Kamal::Git.expects(:uncommitted_changes).returns("M file\n")
assert_equal "git-version", config.version
end
test "version from env" do
ENV["VERSION"] = "env-version"
assert_equal "env-version", @config.version