puppet-armature 0.2.2 → 0.3.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
  SHA1:
3
- metadata.gz: f0a8b80f2d44ce34400277ea4760820da4e6fd66
4
- data.tar.gz: 2857d139910bfb9e29700ec61a318f5162ce64a5
3
+ metadata.gz: 20b1e802ab0134205a8fac195ba528a3664fd16f
4
+ data.tar.gz: c1a48279c939c21b4ae482ced27e44243c69c4fc
5
5
  SHA512:
6
- metadata.gz: 00efc4bd4c00da1f8547a31be2c83db2bed1dc5dabb62ebbc5a5100808a7a87449e5a19c7b3b9b99b5b0499c27267d13b807cb9f4dcda278df3fc5cf815184bf
7
- data.tar.gz: 4e4c492d820316e324c9cde18b37d7bbd76dce885df2231b6523e6405a3296e7c69b64542464d206bd1627b42ac879d529b1ed2c2f3354093d074ff90f64d883
6
+ metadata.gz: ee52d4da30d62132d98b0e0246c4ce6aeb5c99126e7ce9538fe7de28e72c7926f6d33edc377d403bb048d9b2e917ad1f4685b61703b32bf2d2435f85f019b1dc
7
+ data.tar.gz: 0da4f27f3df184cc48c1ae5d8383d7a62a874573a15fca64a3aff0cb54323144ef65da983a7c10c85d81c3977ce7e307abf1116ea5353fd8b7b32c28ce371a19
data/Gemfile.lock CHANGED
@@ -13,13 +13,15 @@ GEM
13
13
  logging (2.0.0)
14
14
  little-plugger (~> 1.1)
15
15
  multi_json (~> 1.10)
16
+ minitest (5.10.1)
16
17
  multi_json (1.12.1)
17
18
 
18
19
  PLATFORMS
19
20
  ruby
20
21
 
21
22
  DEPENDENCIES
23
+ minitest (~> 5.9)
22
24
  puppet-armature!
23
25
 
24
26
  BUNDLED WITH
25
- 1.10.4
27
+ 1.14.6
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require 'rubygems/package_task'
2
+ require 'rake/testtask'
3
+
4
+ # Build packages from all .gemspec files
5
+ FileList['*.gemspec'].each do |path|
6
+ Gem::PackageTask.new(eval(File.read(path))) { |pkg| }
7
+ end
8
+
9
+ Rake::TestTask.new do |t|
10
+ t.libs << "lib" << "test"
11
+ t.test_files = FileList['test/*_test.rb']
12
+ end
@@ -1,4 +1,5 @@
1
1
  require 'fileutils'
2
+ require 'logging'
2
3
  require 'pathname'
3
4
  require 'set'
4
5
 
@@ -6,17 +7,25 @@ module Armature
6
7
  class Cache
7
8
  def initialize(path)
8
9
  FileUtils.mkdir_p(path)
10
+ @lock_file = nil
9
11
  @path = File.realpath(path)
10
12
  @repos = {}
11
13
  @process_prefix = "#{Time.now.to_i}.#{Process.pid}"
12
14
  @sequence = 0
13
15
  @logger = Logging.logger[self]
14
16
 
15
- %w{repo mutable immutable object tmp}.each do |subdir|
17
+ %w{repo ref/mutable ref/immutable ref/identity object tmp}.each do |subdir|
16
18
  FileUtils.mkdir_p("#{@path}/#{subdir}")
17
19
  end
18
20
  end
19
21
 
22
+ def flush_memory!
23
+ @logger.debug("Flushing in-memory caches for all repos")
24
+ @repos.each do |name, repo|
25
+ repo.freshen!
26
+ end
27
+ end
28
+
20
29
  # Get GitRepo object for a local clone of a remote repo at a URL
21
30
  #
22
31
  # This will clone the repo if it doesn't already exist.
@@ -47,56 +56,38 @@ module Armature
47
56
  end
48
57
 
49
58
  # Check out a ref from a repo and return the path
50
- def checkout(repo, ref, options={})
51
- options = Armature::Util.process_options(options,
52
- { :name=>nil }, { :refresh=>false })
53
-
54
- safe_ref = fs_sanitize(ref)
55
-
56
- if options[:refresh]
59
+ def checkout(repo, ref, refresh=false, options={})
60
+ if refresh
57
61
  # Don't check the cache; refresh it from source.
58
62
  repo.freshen()
63
+ ref = repo.canonical_ref(ref)
59
64
  else
60
- # Check cache first
61
- ["immutable", "mutable"].each do |type|
62
- ref_path = "#{@path}/#{type}/#{repo.name}/#{safe_ref}"
63
- if Dir.exist? ref_path
64
- return ref_path
65
- end
65
+ # This will raise a RefError if the ref doesn't exist
66
+ begin
67
+ ref = repo.canonical_ref(ref)
68
+ rescue RefError
69
+ repo.freshen()
70
+ ref = repo.canonical_ref(ref)
66
71
  end
72
+ end
67
73
 
68
- # Special case, since branches may be refered to by name
69
- safe_branch = fs_sanitize("refs/heads/#{ref}")
70
- ref_path = "#{@path}/mutable/#{repo.name}/#{safe_branch}"
71
- if Dir.exist? ref_path
72
- return ref_path
73
- end
74
+ type = repo.ref_type(ref)
75
+ safe_ref = fs_sanitize(ref)
76
+ repo_path = "#{@path}/ref/#{type}/#{repo.name}"
77
+ ref_path = "#{repo_path}/#{safe_ref}"
74
78
 
75
- # Special case, since tags may be refered to by name
76
- safe_tag = fs_sanitize("refs/tags/#{ref}")
77
- ref_path = "#{@path}/immutable/#{repo.name}/#{safe_tag}"
79
+ if ! refresh
80
+ # Check cache first
78
81
  if Dir.exist? ref_path
79
82
  return ref_path
80
83
  end
81
84
  end
82
85
 
83
- # This will raise if the ref doesn't exist
84
- begin
85
- type, sha, real_ref = repo.ref_info(ref)
86
- rescue
87
- repo.freshen()
88
- type, sha, real_ref = repo.ref_info(ref)
89
- end
90
-
91
- repo_dir = "#{@path}/#{type}/#{repo.name}"
92
- if ! Dir.exist? repo_dir
93
- Dir.mkdir(repo_dir)
94
- end
86
+ FileUtils.mkdir_p(repo_path)
95
87
 
96
- ref_path = "#{repo_dir}/#{safe_ref}"
97
- sha_path = checkout_sha(repo, sha, options[:name])
98
- if sha_path != ref_path
99
- atomic_symlink(sha_path, ref_path)
88
+ identity_path = checkout_identity(repo, repo.ref_identity(ref))
89
+ if identity_path != ref_path
90
+ atomic_symlink(identity_path, ref_path)
100
91
  end
101
92
 
102
93
  ref_path
@@ -129,9 +120,8 @@ module Armature
129
120
  end
130
121
 
131
122
  def update_branches()
132
- Dir.glob("#{@path}/mutable/*/*") do |path|
133
- ref = File.basename(path)
134
- ### FIXME decode
123
+ Dir.glob("#{@path}/ref/mutable/*/*") do |path|
124
+ ref = fs_unsanitize(File.basename(path))
135
125
  repo = get_repo_by_name(File.basename(File.dirname(path)))
136
126
  @logger.info("Updating #{ref} ref from #{repo.url}")
137
127
 
@@ -198,34 +188,38 @@ module Armature
198
188
  ref.sub(/\A\./, "\\.").gsub(/[\\|]/, '\\\0').gsub(/\//, '|')
199
189
  end
200
190
 
201
- # Assumes sha exists. Use checkout() if it might not.
202
- def checkout_sha(repo, sha, name=nil)
203
- safe_sha = fs_sanitize(sha)
191
+ def fs_unsanitize(name)
192
+ name.gsub(/\|/, '/').gsub(/\\([\\|])/, '\0').sub(/^\\\./, '.')
193
+ end
194
+
195
+ # Assumes identity exists. Use checkout() if it might not.
196
+ def checkout_identity(repo, identity)
197
+ safe_identity = fs_sanitize(identity)
204
198
 
205
- repo_path = "#{@path}/immutable/#{repo.name}"
206
- sha_path = "#{repo_path}/#{safe_sha}"
207
- if Dir.exist? sha_path
208
- return sha_path
199
+ repo_path = "#{@path}/identity/#{repo.name}"
200
+ identity_path = "#{repo_path}/#{safe_identity}"
201
+ if Dir.exist? identity_path
202
+ return identity_path
209
203
  end
210
204
 
211
205
  FileUtils.mkdir_p(repo_path)
212
206
 
213
- Armature::Util::lock sha_path, File::LOCK_EX, "checkout" do
207
+ Armature::Util::lock identity_path, File::LOCK_EX, "checkout" do
214
208
  # Another process may have created the object before we got the lock
215
- if Dir.exist? sha_path
216
- return sha_path
209
+ if Dir.exist? identity_path
210
+ return identity_path
217
211
  end
218
212
 
219
- object_path = new_object_path(name)
213
+ object_path = new_object_path(identity)
220
214
  FileUtils.mkdir_p object_path
221
215
 
222
216
  @logger.debug(
223
- "Checking out '#{sha}' from '#{repo.url}' into '#{object_path}'")
224
- repo.git "reset", "--hard", sha, :work_dir=>object_path
225
- atomic_symlink(object_path, sha_path)
217
+ "Checking out '#{identity}' from '#{repo.url}' into '#{object_path}'")
218
+ repo.git "reset", "--hard", identity, :work_dir=>object_path
219
+ atomic_symlink(object_path, identity_path)
226
220
  end
227
221
 
228
- sha_path
222
+ identity_path
229
223
  end
230
224
 
231
225
  # Put a directory into a trash directory for off-line deletion
@@ -318,7 +312,7 @@ module Armature
318
312
  def garbage_collect_refs(referenced_paths)
319
313
  # Must be run from garbage_collect, since that handles the lock as well
320
314
  # as emptying the trash
321
- all_references = Set.new(Dir.glob("#{@path}/{im,}mutable/*/*"))
315
+ all_references = Set.new(Dir.glob("#{@path}/ref/*/*/*"))
322
316
  difference = all_references - referenced_paths
323
317
  @logger.info(
324
318
  "Deleting #{difference.size} of #{all_references.size} references")
@@ -348,7 +342,7 @@ module Armature
348
342
  all_repos = Set.new(all_repos.map { |path| File.basename(path) })
349
343
  used_repos = Set.new()
350
344
 
351
- referenced_repos = Dir.glob("#{@path}/{im,}mutable/*")
345
+ referenced_repos = Dir.glob("#{@path}/ref/*/*")
352
346
  referenced_repos.each do |path|
353
347
  # No refs within the repo in use (for this ref type)
354
348
  if Dir.glob("#{path}/*").empty?
@@ -39,7 +39,7 @@ module Armature
39
39
  " environment '#{name}'"
40
40
 
41
41
  begin
42
- ref_path = @cache.checkout(repo, ref, :name=>ref, :refresh=>true)
42
+ ref_path = @cache.checkout(repo, ref, true)
43
43
  rescue RefError
44
44
  @logger.info "Ref '#{ref}' does not exist; ensuring environment" \
45
45
  " '#{name}' is gone"
@@ -50,9 +50,7 @@ module Armature
50
50
  puppetfile_path = "#{ref_path}/Puppetfile"
51
51
  if File.exist?(puppetfile_path)
52
52
  @logger.debug "Found Puppetfile in environment '#{name}'"
53
- puppetfile = Armature::Puppetfile.new()
54
- puppetfile.include(puppetfile_path)
55
- module_refs = puppetfile.results
53
+ module_refs = Armature::Puppetfile.new().include(puppetfile_path)
56
54
  @logger.debug "Loaded Puppetfile in environment '#{name}' with" \
57
55
  " #{module_refs.length} modules"
58
56
  else
@@ -84,10 +82,7 @@ module Armature
84
82
  raise "Module name may not contain /: '#{name}'"
85
83
  end
86
84
 
87
- ref_path = @cache.checkout(
88
- @cache.get_repo(info[:git]),
89
- info[:ref],
90
- :name=>"#{name}.#{info[:ref]}")
85
+ ref_path = @cache.checkout(@cache.get_repo(info[:git]), info[:ref])
91
86
 
92
87
  @cache.atomic_symlink(ref_path, "#{modules_path}/#{name}")
93
88
  end
@@ -19,17 +19,22 @@ module Armature
19
19
 
20
20
  def freshen
21
21
  if ! @fetched
22
- @logger.info("Fetching from #{url}")
23
- Armature::Util::lock @git_dir, File::LOCK_EX, "fetch" do
24
- git "remote", "update", "--prune"
25
- end
26
- @fetched = true
22
+ freshen!
27
23
  true
28
24
  else
29
25
  false
30
26
  end
31
27
  end
32
28
 
29
+ def freshen!
30
+ @logger.info("Fetching from #{url}")
31
+ Armature::Util::lock @git_dir, File::LOCK_EX, "fetch" do
32
+ git "remote", "update", "--prune"
33
+ end
34
+ @ref_cache = {}
35
+ @fetched = true
36
+ end
37
+
33
38
  def git(*arguments)
34
39
  # This accepts a hash of options as the last argument
35
40
  options = if arguments.last.is_a? Hash then arguments.pop else {} end
@@ -57,43 +62,78 @@ module Armature
57
62
 
58
63
  lines.map do |line|
59
64
  sha, ref = line.split(' ', 2)
60
- @ref_cache[ref] = [:mutable, sha, ref]
61
- # Strip refs/heads/ from the beginning of each ref
62
- ref["refs/heads/".length .. -1]
65
+ name = ref.sub("refs/heads/", "")
66
+ @ref_cache[ref] = [:mutable, sha, ref, "branch", name]
67
+ name
63
68
  end
64
69
  end
65
70
 
66
- # Get the type of a ref (:branch, :tag, or :sha) and its sha as [type, sha]
71
+ def ref_type(ref)
72
+ ref_info(ref)[0]
73
+ end
74
+
75
+ def ref_identity(ref)
76
+ ref_info(ref)[1]
77
+ end
78
+
79
+ def canonical_ref(ref)
80
+ ref_info(ref)[2]
81
+ end
82
+
83
+ def ref_human_name(ref)
84
+ info = ref_info(ref)
85
+
86
+ "#{info[3]} '#{info[4]}'"
87
+ end
88
+
89
+ private
90
+
91
+ # Get information about ref, checking the cache first
67
92
  def ref_info(ref)
68
- if result = check_cache(ref)
69
- result
93
+ if ! @ref_cache[ref]
94
+ freshen_ref_cache(ref)
95
+ end
96
+
97
+ @ref_cache[ref]
98
+ end
99
+
100
+ # Get information about a ref and put it in the cache
101
+ def freshen_ref_cache(ref)
102
+ if ref.start_with? "refs/heads/"
103
+ @ref_cache[ref] = [:mutable, rev_parse!(ref), ref, "branch", ref.sub("refs/heads/", "")]
104
+ elsif ref.start_with? "refs/tags/"
105
+ @ref_cache[ref] = [:immutable, rev_parse!(ref), ref, "tag", ref.sub("refs/tags/", "")]
106
+ elsif ref.start_with? "refs/"
107
+ @ref_cache[ref] = [:mutable, rev_parse!(ref), ref, "ref", ref]
70
108
  elsif sha = rev_parse("refs/heads/#{ref}")
71
- @ref_cache["refs/heads/#{ref}"] = [:mutable, sha, "refs/heads/#{ref}"]
109
+ @ref_cache["refs/heads/#{ref}"] = [:mutable, sha, "refs/heads/#{ref}", "branch", ref]
110
+ @ref_cache[ref] = @ref_cache["refs/heads/#{ref}"]
72
111
  elsif sha = rev_parse("refs/tags/#{ref}")
73
- @ref_cache["refs/tags/#{ref}"] = [:immutable, sha, "refs/tags/#{ref}"]
112
+ @ref_cache["refs/tags/#{ref}"] = [:immutable, sha, "refs/tags/#{ref}", "tag", ref]
113
+ @ref_cache[ref] = @ref_cache["refs/tags/#{ref}"]
74
114
  elsif sha = rev_parse(ref)
75
115
  if sha == ref
76
- @ref_cache[ref] = [:immutable, sha, ref]
116
+ @ref_cache[ref] = [:identity, sha, ref, "revision", ref]
77
117
  else
78
- @ref_cache[ref] = [:mutable, sha, ref]
118
+ @ref_cache[ref] = [:mutable, sha, ref, "ref", ref]
79
119
  end
80
120
  else
81
121
  raise RefError.new("no such ref '#{ref}' in repo '#{url}'")
82
122
  end
83
123
  end
84
124
 
85
- private
86
- def check_cache(ref)
87
- @ref_cache[ref] \
88
- || @ref_cache["refs/heads/#{ref}"] \
89
- || @ref_cache["refs/tags/#{ref}"]
90
- end
91
-
92
125
  # Get the sha for a ref, or nil if it doesn't exist
93
126
  def rev_parse(ref)
127
+ rev_parse!(ref)
128
+ rescue RefError
129
+ nil
130
+ end
131
+
132
+ # Get the sha for a ref, or raise if it doesn't exist
133
+ def rev_parse!(ref)
94
134
  git("rev-parse", "--verify", "#{ref}^{commit}").chomp
95
135
  rescue Armature::Run::CommandFailureError
96
- nil
136
+ raise RefError.new("no such ref '#{ref}' in repo '#{url}'")
97
137
  end
98
138
  end
99
139
  end
@@ -8,6 +8,7 @@ module Armature
8
8
 
9
9
  def include(path)
10
10
  instance_eval(IO.read(path), path)
11
+ @results
11
12
  end
12
13
 
13
14
  def mod(name, options={})
@@ -21,10 +22,50 @@ module Armature
21
22
  raise "Module #{name} declared twice"
22
23
  end
23
24
 
24
- @results[name] = Armature::Util.process_options(options, {}, {
25
+ options = Armature::Util.process_options(options, {
26
+ :commit => nil,
27
+ :tag => nil,
28
+ :branch => nil,
29
+ :ref => nil,
30
+ }, {
25
31
  :git => nil,
26
- :ref => "master",
27
32
  })
33
+
34
+ ref = nil
35
+
36
+ if options[:commit]
37
+ if ref
38
+ raise "Module #{name} has more than one of :commit, :tag, :branch, or :ref"
39
+ end
40
+ ref = options[:commit]
41
+ end
42
+
43
+ if options[:tag]
44
+ if ref
45
+ raise "Module #{name} has more than one of :commit, :tag, :branch, or :ref"
46
+ end
47
+ ref = "refs/tags/#{options[:tag]}"
48
+ end
49
+
50
+ if options[:branch]
51
+ if ref
52
+ raise "Module #{name} has more than one of :commit, :tag, :branch, or :ref"
53
+ end
54
+ ref = "refs/heads/#{options[:branch]}"
55
+ end
56
+
57
+ if options[:ref]
58
+ if ref
59
+ raise "Module #{name} has more than one of :commit, :tag, :branch, or :ref"
60
+ end
61
+ ref = options[:ref]
62
+ end
63
+
64
+ if ! ref
65
+ ref = "refs/heads/master"
66
+ end
67
+
68
+ @results[name] = { :name => name, :ref => ref, :git => options[:git] }
28
69
  end
29
70
 
30
71
  def forge(*arguments)
data/lib/armature/run.rb CHANGED
@@ -26,11 +26,11 @@ module Armature::Run
26
26
  command.shelljoin
27
27
  end
28
28
 
29
- def command(*command)
29
+ def command(environment={}, *command)
30
30
  logger = Logging.logger[self]
31
31
 
32
32
  logger.debug(command_to_string(*command))
33
- out, status = Open3.capture2e(*command)
33
+ out, status = Open3.capture2e(environment, *command)
34
34
  logger.debug(command_to_string(command.first) + ": #{status}")
35
35
 
36
36
  if ! status.success?
@@ -39,4 +39,15 @@ module Armature::Run
39
39
 
40
40
  out
41
41
  end
42
+
43
+ def clean_git(*command)
44
+ # Disable general configuration files
45
+ environment = {
46
+ "HOME" => "",
47
+ "XDG_CONFIG_HOME" => "",
48
+ "GIT_CONFIG_NOSYSTEM" => "1",
49
+ }
50
+
51
+ command(environment, "git", *command)
52
+ end
42
53
  end
@@ -1,3 +1,3 @@
1
1
  module Armature
2
- VERSION = '0.2.2'
2
+ VERSION = '0.3.0'
3
3
  end
@@ -17,4 +17,5 @@ spec = Gem::Specification.new do |s|
17
17
  s.executables << 'armature'
18
18
  s.add_runtime_dependency('gli','2.14.0')
19
19
  s.add_runtime_dependency('logging','~> 2')
20
+ s.add_development_dependency('minitest','~> 5.9')
20
21
  end
@@ -0,0 +1,306 @@
1
+ require 'minitest/autorun'
2
+ require 'helpers'
3
+
4
+ class DeployTest < Minitest::Test
5
+ include ArmatureTestHelpers
6
+
7
+ def test_deploy_just_master_branch
8
+ with_context do
9
+ repo = @cache.get_repo(repo_path("control"))
10
+ branches = Set.new(repo.get_branches())
11
+
12
+ assert_equal(Set.new(['master']), branches,
13
+ "Branches before test incorrect")
14
+ assert_equal([], @environments.names(),
15
+ "Environments before test incorrect")
16
+
17
+ @environments.checkout_ref(repo, "master")
18
+
19
+ assert_equal(["master"], @environments.names(),
20
+ "Environments after test incorrect")
21
+ assert_equal([".", "..", "master"], Dir.entries(@environments.path),
22
+ "Environments directory after test incorrect")
23
+ end
24
+ end
25
+
26
+ ### FIXME: should this generate an error?
27
+ def test_deploy_nonexistant_branch
28
+ with_context do
29
+ repo = @cache.get_repo(repo_path("control"))
30
+ branches = Set.new(repo.get_branches())
31
+
32
+ assert_equal(Set.new(['master']), branches,
33
+ "Branches before test incorrect")
34
+
35
+ @environments.checkout_ref(repo, "foo")
36
+
37
+ assert_equal([], @environments.names(),
38
+ "Environments after test incorrect")
39
+ end
40
+ end
41
+
42
+ def test_deploy_all_branches
43
+ with_context do
44
+ repo = @cache.get_repo(repo_path("control"))
45
+ branches = Set.new(repo.get_branches())
46
+
47
+ Dir.mkdir(@context_path + "/foo")
48
+ File.symlink(@context_path + "/foo", @environments.path + "/foo")
49
+
50
+ assert_equal(["foo"], @environments.names(),
51
+ "Environments before test incorrect")
52
+
53
+ (Set.new(@environments.names()) - branches).each do |name|
54
+ @environments.remove(name)
55
+ end
56
+
57
+ branches.each do |branch|
58
+ @environments.checkout_ref(repo, branch)
59
+ end
60
+
61
+ assert_equal(["master"], @environments.names(),
62
+ "Environments after test incorrect")
63
+ end
64
+ end
65
+
66
+ def test_deploy_one_module
67
+ with_context do
68
+ repo = @cache.get_repo(repo_path("control"))
69
+ @environments.checkout_ref(repo, "master")
70
+
71
+ assert_equal(
72
+ [".", "..", "module1"],
73
+ Dir.entries(@environments.path + "/master/modules"),
74
+ "Modules installed after test incorrect")
75
+ end
76
+ end
77
+
78
+ def test_adding_module_and_redeploying
79
+ with_context do
80
+ repo = @cache.get_repo(repo_path("control"))
81
+ @environments.checkout_ref(repo, "master")
82
+
83
+ repo_init("module-2")
84
+ repo_commit("control", "Add module-2") do
85
+ File.write("Puppetfile", <<-PUPPETFILE)
86
+ forge "https://forge.puppet.com"
87
+
88
+ mod "module1", :git=>"#{repo_path('module-1')}"
89
+ mod "module2", :git=>"#{repo_path('module-2')}"
90
+ PUPPETFILE
91
+ end
92
+
93
+ @cache.flush_memory!
94
+ @environments.checkout_ref(repo, "master")
95
+ assert_equal(
96
+ [".", "..", "module1", "module2"],
97
+ Dir.entries(@environments.path + "/master/modules"),
98
+ "Modules installed after test incorrect")
99
+ assert_environment_file_contains(
100
+ "master/modules/module1/README.md",
101
+ "# Armature test repo: module-1")
102
+ assert_environment_file_contains(
103
+ "master/modules/module2/README.md",
104
+ "# Armature test repo: module-2")
105
+ end
106
+ end
107
+
108
+ def test_removing_module_and_redeploying
109
+ with_context do
110
+ repo = @cache.get_repo(repo_path("control"))
111
+ @environments.checkout_ref(repo, "master")
112
+
113
+ repo_commit("control", "Remove module-1") do
114
+ File.write("Puppetfile", <<-PUPPETFILE)
115
+ forge "https://forge.puppet.com"
116
+ PUPPETFILE
117
+ end
118
+
119
+ @cache.flush_memory!
120
+ @environments.checkout_ref(repo, "master")
121
+ assert_equal(
122
+ [".", ".."],
123
+ Dir.entries(@environments.path + "/master/modules"),
124
+ "Modules installed after test incorrect")
125
+ end
126
+ end
127
+
128
+ def test_module_with_bad_ref
129
+ with_context do
130
+ repo = @cache.get_repo(repo_path("control"))
131
+ repo_commit("control", "Set module-1 to bad ref") do
132
+ File.write("Puppetfile", <<-PUPPETFILE)
133
+ forge "https://forge.puppet.com"
134
+
135
+ mod "module1", :git=>"#{repo_path('module-1')}", :ref=>"bad"
136
+ PUPPETFILE
137
+ end
138
+
139
+ assert_raises(Armature::RefError) do
140
+ @environments.checkout_ref(repo, "master")
141
+ end
142
+
143
+ ### FIXME state of repo after an error is undefined, but this behavior
144
+ ### seems reasonable.
145
+ assert_equal(
146
+ [".", ".."],
147
+ Dir.entries(@environments.path),
148
+ "Modules installed after test incorrect")
149
+ end
150
+ end
151
+
152
+ def test_redeploying_module_with_bad_ref
153
+ with_context do
154
+ repo = @cache.get_repo(repo_path("control"))
155
+ @environments.checkout_ref(repo, "master")
156
+
157
+ repo_commit("control", "Set module-1 to bad ref") do
158
+ File.write("Puppetfile", <<-PUPPETFILE)
159
+ forge "https://forge.puppet.com"
160
+
161
+ mod "module1", :git=>"#{repo_path('module-1')}", :ref=>"bad"
162
+ PUPPETFILE
163
+ end
164
+
165
+ @cache.flush_memory!
166
+ assert_raises(Armature::RefError) do
167
+ @environments.checkout_ref(repo, "master")
168
+ end
169
+
170
+ ### FIXME state of repo after an error is undefined
171
+ ### What happens if other modules already exist?
172
+ skip("state of repo after an error is undefined")
173
+ assert_equal(
174
+ [".", "..", "module1"],
175
+ Dir.entries(@environments.path + "/master/modules"),
176
+ "Modules installed after test incorrect")
177
+ end
178
+ end
179
+
180
+ def test_redeploying_module_with_ref_tag
181
+ with_context do
182
+ set_up_interesting_module("interesting")
183
+ redeploy_module_with_ref_of_type("ref", "tag_one") do
184
+ assert_module_manifests("interesting", ["one.pp"],
185
+ "Incorrect module version after redeploy")
186
+ end
187
+ end
188
+ end
189
+
190
+ def test_redeploying_module_with_ref_branch
191
+ with_context do
192
+ set_up_interesting_module("interesting")
193
+ redeploy_module_with_ref_of_type("ref", "branch_two") do
194
+ assert_module_manifests("interesting", ["one.pp", "two.pp", "two_a.pp"],
195
+ "Incorrect module version after redeploy")
196
+ end
197
+ end
198
+ end
199
+
200
+ def test_redeploying_module_with_ref_commit
201
+ with_context do
202
+ set_up_interesting_module("interesting")
203
+ sha = repo_git("interesting", "rev-parse", "branch_two^").chomp
204
+ redeploy_module_with_ref_of_type("ref", sha) do
205
+ assert_module_manifests("interesting", ["one.pp", "two.pp"],
206
+ "Incorrect module version after redeploy")
207
+ end
208
+ end
209
+ end
210
+
211
+ def test_redeploying_module_with_tag
212
+ with_context do
213
+ set_up_interesting_module("interesting")
214
+ redeploy_module_with_ref_of_type("tag", "tag_one") do
215
+ assert_module_manifests("interesting", ["one.pp"],
216
+ "Incorrect module version after redeploy")
217
+ end
218
+ end
219
+ end
220
+
221
+ def test_redeploying_module_with_branch
222
+ with_context do
223
+ set_up_interesting_module("interesting")
224
+ redeploy_module_with_ref_of_type("branch", "branch_two") do
225
+ assert_module_manifests("interesting", ["one.pp", "two.pp", "two_a.pp"],
226
+ "Incorrect module version after redeploy")
227
+ end
228
+ end
229
+ end
230
+
231
+ def test_redeploying_module_with_commit
232
+ with_context do
233
+ set_up_interesting_module("interesting")
234
+ sha = repo_git("interesting", "rev-parse", "branch_two^").chomp
235
+ redeploy_module_with_ref_of_type("commit", sha) do
236
+ assert_module_manifests("interesting", ["one.pp", "two.pp"],
237
+ "Incorrect module version after redeploy")
238
+ end
239
+ end
240
+ end
241
+
242
+ def test_redeploying_module_with_updated_branch
243
+ with_context do
244
+ set_up_interesting_module("interesting")
245
+ redeploy_module_with_ref_of_type("ref", "branch_two") do
246
+ repo_git("interesting", "checkout", "branch_two")
247
+ add_module_class("interesting", "two_b")
248
+
249
+ @cache.flush_memory!
250
+ @environments.checkout_ref(@cache.get_repo(repo_path("control")), "master")
251
+
252
+ skip("checkout_ref doesn't update branches at the moment")
253
+ assert_module_manifests("interesting",
254
+ ["one.pp", "two.pp", "two_a.pp", "two_b.pp"],
255
+ "Incorrect module version after redeploy")
256
+ end
257
+ end
258
+ end
259
+
260
+ def test_updating_branches_on_module_with_updated_branch
261
+ with_context do
262
+ set_up_interesting_module("interesting")
263
+ redeploy_module_with_ref_of_type("ref", "branch_two") do
264
+ repo_git("interesting", "checkout", "branch_two")
265
+ add_module_class("interesting", "two_b")
266
+
267
+ @cache.flush_memory!
268
+ @cache.update_branches()
269
+
270
+ assert_module_manifests("interesting",
271
+ ["one.pp", "two.pp", "two_a.pp", "two_b.pp"],
272
+ "Incorrect module version after redeploy")
273
+ end
274
+ end
275
+ end
276
+
277
+ private
278
+
279
+ # The "interesting" repo must be created first so it can be queried for shas
280
+ def redeploy_module_with_ref_of_type(ref_type, ref)
281
+ repo = @cache.get_repo(repo_path("control"))
282
+
283
+ repo_puppetfile_update("control", <<-MODULES)
284
+ mod "interesting", :git=>"#{repo_path('interesting')}"
285
+ MODULES
286
+
287
+ @environments.checkout_ref(repo, "master")
288
+
289
+ assert_module_manifests("interesting", ["one.pp", "two.pp", "three.pp"],
290
+ "Incorrect module version after initial deploy")
291
+
292
+ repo_commit("control", "Add interesting module") do
293
+ File.write("Puppetfile", <<-PUPPETFILE)
294
+ forge "https://forge.puppet.com"
295
+
296
+ mod "interesting", :git=>"#{repo_path('interesting')}",
297
+ :#{ref_type}=>"#{ref}"
298
+ PUPPETFILE
299
+ end
300
+
301
+ @cache.flush_memory!
302
+ @environments.checkout_ref(repo, "master")
303
+
304
+ yield
305
+ end
306
+ end
data/test/helpers.rb ADDED
@@ -0,0 +1,130 @@
1
+ require 'armature'
2
+ require 'fileutils'
3
+ require 'tmpdir'
4
+
5
+ module ArmatureTestHelpers
6
+ def repo_path(name)
7
+ @context_path + "/repos/" + name
8
+ end
9
+
10
+ def repo_init(name)
11
+ Armature::Run.clean_git("init", repo_path(name))
12
+ repo_commit(name, "Initial revision of #{name}") do
13
+ File.write("README.md", <<-README)
14
+ # Armature test repo: #{name}
15
+
16
+ Located at #{repo_path(name)}
17
+ README
18
+
19
+ Dir.mkdir("manifests")
20
+ File.write("manifests/.keep", "")
21
+
22
+ if block_given?
23
+ yield
24
+ end
25
+ end
26
+ end
27
+
28
+ def repo_commit(name, message)
29
+ Dir.chdir(repo_path(name)) do
30
+ yield
31
+ Armature::Run.clean_git("add", ".")
32
+ Armature::Run.clean_git("commit", "-m", message)
33
+ end
34
+ end
35
+
36
+ def repo_git(name, *command)
37
+ Dir.chdir(repo_path(name)) do
38
+ Armature::Run.clean_git(*command)
39
+ end
40
+ end
41
+
42
+ def repo_puppetfile_update(name, modules)
43
+ repo_commit(name, "Update Puppetfile") do
44
+ File.write("Puppetfile", <<-PUPPETFILE)
45
+ forge "https://forge.puppet.com"
46
+
47
+ #{modules}
48
+ PUPPETFILE
49
+ end
50
+ end
51
+
52
+ def add_module_class(module_name, class_name)
53
+ repo_commit(module_name, "Add #{class_name}.pp") do
54
+ File.write("manifests/#{class_name}.pp", <<-MANIFEST)
55
+ class module1::#{class_name} {
56
+ notify { "in #{module_name}::#{class_name}": }
57
+ }
58
+ MANIFEST
59
+ end
60
+ end
61
+
62
+ def set_up_interesting_module(module_name)
63
+ repo_init(module_name)
64
+
65
+ add_module_class(module_name, "one")
66
+ repo_git(module_name, "tag", "tag_one")
67
+ add_module_class(module_name, "two")
68
+ repo_git(module_name, "checkout", "-b", "branch_two")
69
+ add_module_class(module_name, "two_a")
70
+ repo_git(module_name, "checkout", "master")
71
+ add_module_class(module_name, "three")
72
+ end
73
+
74
+ def set_up_context
75
+ @context_path = Dir.mktmpdir("armature.test_context.")
76
+ @cache = Armature::Cache.new(@context_path + "/cache")
77
+
78
+ Dir.mkdir(@context_path + "/environments")
79
+ @environments = Armature::Environments.new(@context_path + "/environments", @cache)
80
+
81
+ repo_init("module-1")
82
+
83
+ repo_init("control") do
84
+ File.write("Puppetfile", <<-PUPPETFILE)
85
+ forge "https://forge.puppet.com"
86
+
87
+ mod "module1", :git=>"#{repo_path('module-1')}"
88
+ PUPPETFILE
89
+ end
90
+ end
91
+
92
+ def tear_down_context
93
+ FileUtils.rm_rf(@context_path)
94
+
95
+ # Ensure that code trying to use these after this point fails in a
96
+ # predictable way.
97
+ @context_path = nil
98
+ @cache = nil
99
+ @environments = nil
100
+ end
101
+
102
+ def with_context
103
+ set_up_context
104
+ yield
105
+ tear_down_context
106
+ end
107
+
108
+ def environment_file_contains?(path, search)
109
+ File.foreach(@environments.path + "/" + path).any? do
110
+ |line| line.include? search
111
+ end
112
+ end
113
+
114
+ def assert_environment_file_contains(path, search, message=nil)
115
+ if ! message
116
+ message = "#{path} does not contain '#{search}'"
117
+ end
118
+
119
+ assert(environment_file_contains?(path, search), message)
120
+ end
121
+
122
+ def assert_module_manifests(module_name, manifest_names=["init.pp"],
123
+ message="Incorrect manifests in module '#{module_name}'",
124
+ environment="master")
125
+ assert_equal(
126
+ ([".", "..", ".keep"] + manifest_names).sort(),
127
+ Dir.entries(@environments.path + "/#{environment}/modules/#{module_name}/manifests"),
128
+ message)
129
+ end
130
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puppet-armature
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Parks
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-31 00:00:00.000000000 Z
11
+ date: 2017-04-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: gli
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.9'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.9'
41
55
  description: Armature sets up Puppet environments for each branch in your control
42
56
  repo and installs modules as specified by the Puppetfile for each environment. It
43
57
  is designed as a replacement for r10k.
@@ -51,6 +65,7 @@ files:
51
65
  - Gemfile.lock
52
66
  - LICENSE
53
67
  - README.md
68
+ - Rakefile
54
69
  - TODO.md
55
70
  - bin/armature
56
71
  - docs/puppetfile-syntax.md
@@ -63,6 +78,8 @@ files:
63
78
  - lib/armature/util.rb
64
79
  - lib/armature/version.rb
65
80
  - puppet-armature.gemspec
81
+ - test/deploy_test.rb
82
+ - test/helpers.rb
66
83
  homepage: https://github.com/danielparks/armature
67
84
  licenses:
68
85
  - BSD-2-Clause
@@ -89,4 +106,3 @@ signing_key:
89
106
  specification_version: 4
90
107
  summary: Deploy Puppet environments and manage modules
91
108
  test_files: []
92
- has_rdoc: false