Merge pull request #798 from basecamp/git-clone

Build from within a git clone by default
This commit is contained in:
Donal McBreen
2024-05-20 12:18:07 +01:00
committed by GitHub
15 changed files with 253 additions and 76 deletions

View File

@@ -19,21 +19,34 @@ class Kamal::Cli::Build < Kamal::Cli::Base
verify_local_dependencies
run_hook "pre-build"
if (uncommitted_changes = Kamal::Git.uncommitted_changes).present?
say "The following paths have uncommitted changes:\n #{uncommitted_changes}", :yellow
uncommitted_changes = Kamal::Git.uncommitted_changes
if KAMAL.config.builder.git_clone?
if uncommitted_changes.present?
say "Building from a local git clone, so ignoring these uncommitted changes:\n #{uncommitted_changes}", :yellow
end
prepare_clone
elsif uncommitted_changes.present?
say "Building with uncommitted changes:\n #{uncommitted_changes}", :yellow
end
# Get the command here to ensure the Dir.chdir doesn't interfere with it
push = KAMAL.builder.push
run_locally do
begin
KAMAL.with_verbosity(:debug) do
execute *KAMAL.builder.push
Dir.chdir(KAMAL.config.builder.build_directory) { execute *push }
end
rescue SSHKit::Command::Failed => e
if e.message =~ /(no builder)|(no such file or directory)/
warn "Missing compatible builder, so creating a new one first"
if cli.create
KAMAL.with_verbosity(:debug) { execute *KAMAL.builder.push }
KAMAL.with_verbosity(:debug) do
Dir.chdir(KAMAL.config.builder.build_directory) { execute *push }
end
end
else
raise
@@ -120,4 +133,23 @@ class Kamal::Cli::Build < Kamal::Cli::Base
end
end
end
def prepare_clone
run_locally do
begin
info "Cloning repo into build directory `#{KAMAL.config.builder.build_directory}`..."
execute *KAMAL.builder.create_clone_directory
execute *KAMAL.builder.clone
rescue SSHKit::Command::Failed => e
if e.message =~ /already exists and is not an empty directory/
info "Resetting local clone as `#{KAMAL.config.builder.build_directory}` already exists..."
KAMAL.builder.clone_reset_steps.each { |step| execute *step }
else
raise
end
end
end
end
end

View File

@@ -78,8 +78,8 @@ module Kamal::Commands
args.compact.unshift :docker
end
def git(*args)
args.compact.unshift :git
def git(*args, path: nil)
[ :git, *([ "-C", path ] if path), *args.compact ]
end
def tags(**details)

View File

@@ -2,6 +2,7 @@ require "active_support/core_ext/string/filters"
class Kamal::Commands::Builder < Kamal::Commands::Base
delegate :create, :remove, :push, :clean, :pull, :info, :validate_image, to: :target
delegate :clone_directory, :build_directory, to: :"config.builder"
def name
target.class.to_s.remove("Kamal::Commands::Builder::").underscore.inquiry
@@ -53,6 +54,23 @@ class Kamal::Commands::Builder < Kamal::Commands::Base
end
end
def create_clone_directory
make_directory clone_directory
end
def clone
git :clone, Kamal::Git.root, path: clone_directory
end
def clone_reset_steps
[
git(:remote, "set-url", :origin, Kamal::Git.root, path: build_directory),
git(:fetch, :origin, path: build_directory),
git(:reset, "--hard", Kamal::Git.revision, path: build_directory),
git(:clean, "-fdx", path: build_directory)
]
end
private
def ensure_local_docker_installed
docker "--version"

View File

@@ -3,7 +3,7 @@ class Kamal::Commands::Builder::Base < Kamal::Commands::Base
class BuilderError < StandardError; end
delegate :argumentize, to: Kamal::Utils
delegate :args, :secrets, :dockerfile, :target, :local_arch, :local_host, :remote_arch, :remote_host, :cache_from, :cache_to, :ssh, :git_archive?, to: :builder_config
delegate :args, :secrets, :dockerfile, :target, :local_arch, :local_host, :remote_arch, :remote_host, :cache_from, :cache_to, :ssh, to: :builder_config
def clean
docker :image, :rm, "--force", config.absolute_image
@@ -13,16 +13,6 @@ class Kamal::Commands::Builder::Base < Kamal::Commands::Base
docker :pull, config.absolute_image
end
def push
if git_archive?
pipe \
git(:archive, "--format=tar", :HEAD),
build_and_push
else
build_and_push
end
end
def build_options
[ *build_tags, *build_cache, *build_labels, *build_args, *build_secrets, *build_dockerfile, *build_target, *build_ssh ]
end

View File

@@ -13,6 +13,15 @@ class Kamal::Commands::Builder::Multiarch < Kamal::Commands::Builder::Base
docker(:buildx, :ls)
end
def push
docker :buildx, :build,
"--push",
"--platform", platform_names,
"--builder", builder_name,
*build_options,
build_context
end
private
def builder_name
"kamal-#{config.service}-multiarch"
@@ -25,13 +34,4 @@ class Kamal::Commands::Builder::Multiarch < Kamal::Commands::Builder::Base
"linux/amd64,linux/arm64"
end
end
def build_and_push
docker :buildx, :build,
"--push",
"--platform", platform_names,
"--builder", builder_name,
*build_options,
build_context
end
end

View File

@@ -11,11 +11,10 @@ class Kamal::Commands::Builder::Native < Kamal::Commands::Builder::Base
# No-op on native
end
private
def build_and_push
combine \
docker(:build, *build_options, build_context),
docker(:push, config.absolute_image),
docker(:push, config.latest_image)
end
def push
combine \
docker(:build, *build_options, build_context),
docker(:push, config.absolute_image),
docker(:push, config.latest_image)
end
end

View File

@@ -7,11 +7,10 @@ class Kamal::Commands::Builder::Native::Cached < Kamal::Commands::Builder::Nativ
docker :buildx, :rm, builder_name
end
private
def build_and_push
docker :buildx, :build,
"--push",
*build_options,
build_context
end
def push
docker :buildx, :build,
"--push",
*build_options,
build_context
end
end

View File

@@ -17,6 +17,15 @@ class Kamal::Commands::Builder::Native::Remote < Kamal::Commands::Builder::Nativ
docker(:buildx, :ls)
end
def push
docker :buildx, :build,
"--push",
"--platform", platform,
"--builder", builder_name,
*build_options,
build_context
end
private
def builder_name
@@ -47,13 +56,4 @@ class Kamal::Commands::Builder::Native::Remote < Kamal::Commands::Builder::Nativ
def remove_buildx
docker :buildx, :rm, builder_name
end
def build_and_push
docker :buildx, :build,
"--push",
"--platform", platform,
"--builder", builder_name,
*build_options,
build_context
end
end

View File

@@ -340,7 +340,7 @@ class Kamal::Configuration
def git_version
@git_version ||=
if Kamal::Git.used?
if Kamal::Git.uncommitted_changes.present? && !builder.git_archive?
if Kamal::Git.uncommitted_changes.present? && !builder.git_clone?
uncommitted_suffix = "_uncommitted_#{SecureRandom.hex(8)}"
end
[ Kamal::Git.revision, uncommitted_suffix ].compact.join

View File

@@ -3,6 +3,8 @@ class Kamal::Configuration::Builder
@options = config.raw_config.builder || {}
@image = config.image
@server = config.registry["server"]
@service = config.service
@destination = config.destination
valid?
end
@@ -44,7 +46,7 @@ class Kamal::Configuration::Builder
end
def context
@options["context"] || (git_archive? ? "-" : ".")
@options["context"] || "."
end
def local_arch
@@ -89,10 +91,23 @@ class Kamal::Configuration::Builder
@options["ssh"]
end
def git_archive?
def git_clone?
Kamal::Git.used? && @options["context"].nil?
end
def clone_directory
@clone_directory ||= File.join Dir.tmpdir, "kamal-clones", [ @service, pwd_sha ].compact.join("-")
end
def build_directory
@build_directory ||=
if git_clone?
File.join clone_directory, repo_basename, repo_relative_pwd
else
"."
end
end
private
def valid?
if @options["cache"] && @options["cache"]["type"]
@@ -123,4 +138,16 @@ class Kamal::Configuration::Builder
def cache_to_config_for_registry
[ "type=registry", @options["cache"]&.fetch("options", nil), "ref=#{cache_image_ref}" ].compact.join(",")
end
def repo_basename
File.basename(Kamal::Git.root)
end
def repo_relative_pwd
Dir.pwd.delete_prefix(Kamal::Git.root)
end
def pwd_sha
Digest::SHA256.hexdigest(Dir.pwd)[0..12]
end
end

View File

@@ -16,4 +16,8 @@ module Kamal::Git
def uncommitted_changes
`git status --porcelain`.strip
end
def root
`git rev-parse --show-toplevel`.strip
end
end