capistrano-dockerbuild 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d7346efa239fc872e0194afb86f2e155aec196f8ef16490af28dfb16a8e1b726
4
- data.tar.gz: 647ae21571209763324edb86400d78498bdbd5b5423784530cac71e01544e783
3
+ metadata.gz: ed984b515b7f0d43d3985d442dba5bf85c1539f3109d8360bf9864db5a549a2d
4
+ data.tar.gz: cbcea200c07484a17aec1edb9d6e5e99ec2548811e3bc3de34cec1f2deb993a0
5
5
  SHA512:
6
- metadata.gz: 9e3b6d93525ef5baf7d376f9d893f5f0db6227bb4c8fbb04c11f7c92a126e6ec2481c1dfb7c61562004aa58f4391bca3b31f73217df843b0af062032e32514b4
7
- data.tar.gz: 949edfc5295850a32f6dbef737127ba2d1e700214fb560666936b4a6e6c8f4be3f60846f7c635b394914088afb97ee93270c4bbb382287c4ac285936d2e007e5
6
+ metadata.gz: eb19d9ee91eb190e367a5dfe3fe75c9a695465afae9eff6d9a6f9d79c1548b4e6ede86a66f004bc4d9d23d5bbc56e70b719ca157903b59f8ca4251b4fc6342e7
7
+ data.tar.gz: 98752e45ab74d37285903f283efa3c8c2e167d51e8fd366c381099bc33b33b947c9a03ea018d93e90bfa91bcfbfd5a302288db93630a6700e671e7c9490f44e0
data/README.md CHANGED
@@ -139,9 +139,11 @@ The temporary directory is removed automatically by `docker:clean` after `docker
139
139
 
140
140
  #### docker:clone
141
141
  - Clone repo to `#{docker_build_base_dir}` as mirror
142
+ - Serialized with `docker:update_mirror` via a `flock` keyed by `#{docker_build_base_dir}`'s basename, since both mutate the shared repo directory (a mirror by default, or a regular checkout under `:docker_build_no_worktree`) at `#{docker_build_base_dir}`. This matters when multiple deploys (e.g. CI jobs for different branches) target the same build host concurrently — without it, concurrent `git clone`/`git remote update` on the shared directory can corrupt its `.git/config` or fail with transport errors. Keying the lock by basename keeps unrelated consumers that share the same parent directory from serializing against each other.
142
143
 
143
144
  #### docker:update_mirror
144
145
  - git remote update `#{docker_build_base_dir}`
146
+ - Serialized with `docker:clone` via the same `flock` (see above)
145
147
 
146
148
  #### docker:build
147
149
  - Create `#{branch}` worktree to `#{docker_tag}-#{timestamp}`
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "capistrano-dockerbuild"
7
- spec.version = "1.1.0"
7
+ spec.version = "1.2.0"
8
8
  spec.authors = ["joker1007"]
9
9
  spec.email = ["kakyoin.hierophant@gmail.com"]
10
10
 
@@ -22,6 +22,6 @@ Gem::Specification.new do |spec|
22
22
 
23
23
  spec.add_runtime_dependency "capistrano", ">= 3.2"
24
24
 
25
- spec.add_development_dependency "bundler", "~> 2.3"
25
+ spec.add_development_dependency "bundler", ">= 2.3"
26
26
  spec.add_development_dependency "rake", "~> 13.0"
27
27
  end
@@ -1,6 +1,7 @@
1
1
  require "cgi"
2
2
  require "uri"
3
3
  require "securerandom"
4
+ require "shellwords"
4
5
 
5
6
  class Capistrano::Dockerbuild < Capistrano::Plugin
6
7
  def set_defaults
@@ -28,6 +29,16 @@ class Capistrano::Dockerbuild < Capistrano::Plugin
28
29
  Pathname(fetch(:docker_build_base_dir))
29
30
  end
30
31
 
32
+ # Lock serializing access to the shared repo dir at docker_build_base_path
33
+ # across concurrent deploys on the same build host (see README for the race).
34
+ #
35
+ # Keyed by basename, not a fixed name, so unrelated consumers sharing a parent
36
+ # directory don't serialize against each other.
37
+ def docker_build_lock_path
38
+ base = docker_build_base_path
39
+ base.dirname.join("capistrano_dockerbuild.#{base.basename}.lock").to_s
40
+ end
41
+
31
42
  def git_repo_url
32
43
  if fetch(:git_http_username) && fetch(:git_http_password)
33
44
  URI.parse(repo_url).tap do |repo_uri|
@@ -38,25 +38,20 @@ namespace :docker do
38
38
  desc "Clone the repo to docker build base directory"
39
39
  task :clone => [:'docker:check'] do
40
40
  on roles(:docker_build) do |host|
41
- if fetch(:docker_build_no_worktree)
42
- if test " [ -f #{dockerbuild_plugin.docker_build_base_path}/.git/HEAD ] "
43
- info "The repository is at #{dockerbuild_plugin.docker_build_base_path}"
44
- else
45
- within dockerbuild_plugin.docker_build_base_path.dirname do
46
- with dockerbuild_plugin.git_env(host) do
47
- execute :git, :clone, dockerbuild_plugin.git_repo_url, dockerbuild_plugin.docker_build_base_path.to_s
48
- end
49
- end
50
- end
51
- else
52
- if test " [ -f #{dockerbuild_plugin.docker_build_base_path}/HEAD ] "
53
- info t(:mirror_exists, at: dockerbuild_plugin.docker_build_base_path.to_s)
54
- else
55
- within dockerbuild_plugin.docker_build_base_path.dirname do
56
- with dockerbuild_plugin.git_env(host) do
57
- execute :git, :clone, "--mirror", dockerbuild_plugin.git_repo_url, dockerbuild_plugin.docker_build_base_path.to_s
41
+ within dockerbuild_plugin.docker_build_base_path.dirname do
42
+ with dockerbuild_plugin.git_env(host) do
43
+ path = dockerbuild_plugin.docker_build_base_path.to_s.shellescape
44
+ url = dockerbuild_plugin.git_repo_url.shellescape
45
+ # Existence check runs inside the same flock as the clone itself, not before
46
+ # acquiring it — otherwise two concurrent deploys can both observe the repo
47
+ # missing and the second `git clone` fails once the first has created it.
48
+ commands =
49
+ if fetch(:docker_build_no_worktree)
50
+ "[ -f #{path}/.git/HEAD ] || git clone #{url} #{path}"
51
+ else
52
+ "[ -f #{path}/HEAD ] || git clone --mirror #{url} #{path}"
58
53
  end
59
- end
54
+ execute :flock, dockerbuild_plugin.docker_build_lock_path.shellescape, "-c", commands.shellescape
60
55
  end
61
56
  end
62
57
  end
@@ -67,8 +62,8 @@ namespace :docker do
67
62
  on roles(:docker_build) do |host|
68
63
  within dockerbuild_plugin.docker_build_base_path do
69
64
  with dockerbuild_plugin.git_env(host) do
70
- execute :git, :remote, "set-url", :origin, dockerbuild_plugin.git_repo_url
71
- execute :git, :remote, :update, "--prune"
65
+ commands = "git remote set-url origin #{dockerbuild_plugin.git_repo_url.shellescape} && git remote update --prune"
66
+ execute :flock, dockerbuild_plugin.docker_build_lock_path.shellescape, "-c", commands.shellescape
72
67
  end
73
68
  end
74
69
  end
@@ -90,7 +85,7 @@ namespace :docker do
90
85
  submodule_cmd = fetch(:update_git_submodule) ? "; git submodule update --init --recursive" : ""
91
86
  commands = "sha1=$(git rev-parse #{fetch(:branch)}); git reset --hard ${sha1}#{submodule_cmd}; #{build_cmd.map {|c| c.to_s.shellescape }.join(" ")}"
92
87
  with dockerbuild_plugin.git_env(host) do
93
- execute(:flock, "capistrano_dockerbuild.lock", "-c", "'#{commands}'")
88
+ execute(:flock, dockerbuild_plugin.docker_build_lock_path.shellescape, "-c", "'#{commands}'")
94
89
  end
95
90
  else
96
91
  timestamp = Time.now.to_i
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capistrano-dockerbuild
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - joker1007
@@ -27,14 +27,14 @@ dependencies:
27
27
  name: bundler
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
- - - "~>"
30
+ - - ">="
31
31
  - !ruby/object:Gem::Version
32
32
  version: '2.3'
33
33
  type: :development
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
- - - "~>"
37
+ - - ">="
38
38
  - !ruby/object:Gem::Version
39
39
  version: '2.3'
40
40
  - !ruby/object:Gem::Dependency
@@ -86,7 +86,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
86
86
  - !ruby/object:Gem::Version
87
87
  version: '0'
88
88
  requirements: []
89
- rubygems_version: 4.0.10
89
+ rubygems_version: 4.0.16
90
90
  specification_version: 4
91
91
  summary: Capistrano task definition for `docker build`
92
92
  test_files: []