menagerie 0.1.3 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +8 -4
- data/CHANGELOG.md +4 -0
- data/README.md +137 -1
- data/lib/menagerie.rb +9 -0
- data/lib/menagerie/artifact.rb +15 -12
- data/lib/menagerie/collection.rb +17 -7
- data/lib/menagerie/release.rb +27 -13
- data/menagerie.gemspec +5 -5
- data/spec/examples/empty/.keep +0 -0
- data/spec/examples/empty_with_dirs/artifacts/.keep +0 -0
- data/spec/examples/empty_with_dirs/releases/.keep +0 -0
- data/spec/examples/existing/artifacts/a/0.0.1 +0 -0
- data/spec/examples/existing/artifacts/a/0.0.2 +0 -0
- data/spec/examples/existing/artifacts/a/0.0.3 +0 -0
- data/spec/examples/existing/artifacts/b/1.0.0 +0 -0
- data/spec/examples/existing/artifacts/b/1.0.1 +0 -0
- data/spec/examples/existing/artifacts/c/0.1.1 +0 -0
- data/spec/examples/existing/artifacts/c/0.1.2 +0 -0
- data/spec/examples/existing/artifacts/c/0.2.0 +0 -0
- data/spec/examples/existing/releases/0/a +0 -0
- data/spec/examples/existing/releases/0/b +0 -0
- data/spec/examples/existing/releases/0/c +0 -0
- data/spec/examples/existing/releases/1/a +0 -0
- data/spec/examples/existing/releases/1/b +0 -0
- data/spec/examples/existing/releases/1/c +0 -0
- data/spec/examples/existing/releases/2/a +0 -0
- data/spec/examples/existing/releases/2/b +0 -0
- data/spec/examples/existing/releases/2/c +0 -0
- data/spec/examples/orphaned/artifacts/a/0.0.1 +0 -0
- data/spec/examples/orphaned/artifacts/a/0.0.2 +0 -0
- data/spec/examples/orphaned/artifacts/a/0.0.3 +0 -0
- data/spec/examples/orphaned/artifacts/b/1.0.0 +0 -0
- data/spec/examples/orphaned/artifacts/b/1.0.1 +0 -0
- data/spec/examples/orphaned/artifacts/c/0.1.0 +0 -0
- data/spec/examples/orphaned/artifacts/c/0.1.1 +0 -0
- data/spec/examples/orphaned/artifacts/c/0.1.2 +0 -0
- data/spec/examples/orphaned/artifacts/c/0.2.0 +0 -0
- data/spec/examples/orphaned/releases/0/a +0 -0
- data/spec/examples/orphaned/releases/0/b +0 -0
- data/spec/examples/orphaned/releases/0/c +0 -0
- data/spec/examples/orphaned/releases/1/a +0 -0
- data/spec/examples/orphaned/releases/1/b +0 -0
- data/spec/examples/orphaned/releases/1/c +0 -0
- data/spec/examples/orphaned/releases/2/a +0 -0
- data/spec/examples/orphaned/releases/2/b +0 -0
- data/spec/examples/orphaned/releases/2/c +0 -0
- data/spec/menagerie/artifact_spec.rb +43 -0
- data/spec/menagerie/collection_spec.rb +114 -0
- data/spec/menagerie/release_spec.rb +58 -0
- data/spec/menagerie_spec.rb +32 -0
- metadata +94 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b98fd545ddccb263db3f21023fd0dc02aad05189
|
4
|
+
data.tar.gz: 308c931a27d9573b6d70a8be093d6fa6ea7f44ad
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b40e70f809cd646aab6ac63b90e10477f4ffaab400a84e870fb6b93ba339fe1eea51cfd0fe3a870615ac62543e7a55d558e3acc8c033ee3f588b528128b430b2
|
7
|
+
data.tar.gz: ff6b695108b03b845701f6aa55d4b267c966d621edea7625fe38827f01c34140d1cf9e76152d621e862203581de942a9e96b635cb1f9d9e24a0ec01fa7e3bfbd
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
language: ruby
|
2
2
|
cache: bundler
|
3
|
+
sudo: false
|
3
4
|
rvm:
|
4
|
-
- 2.
|
5
|
-
- 2.
|
6
|
-
-
|
5
|
+
- 2.2.0
|
6
|
+
- 2.1.5
|
7
|
+
- 2.0.0-p598
|
8
|
+
- 1.9.3-p551
|
7
9
|
notifications:
|
8
10
|
email: false
|
9
11
|
irc:
|
10
12
|
template:
|
11
|
-
|
13
|
+
- '%{repository}/%{branch}/%{build_number}: %{message} -- %{build_url}'
|
14
|
+
channels:
|
15
|
+
- irc.oftc.net#akerl
|
data/CHANGELOG.md
ADDED
data/README.md
CHANGED
@@ -8,10 +8,146 @@ menagerie
|
|
8
8
|
[![Build Status](https://img.shields.io/travis/akerl/menagerie.svg)](https://travis-ci.org/akerl/menagerie)
|
9
9
|
[![MIT Licensed](https://img.shields.io/badge/license-MIT-green.svg)](https://tldrlegal.com/license/mit-license)
|
10
10
|
|
11
|
-
Simple release management tool for controlling versioned artifacts
|
11
|
+
Simple release management tool for controlling versioned artifacts
|
12
12
|
|
13
13
|
## Usage
|
14
14
|
|
15
|
+
Menagerie manages Collections of Releases, as well as the Artifacts that are used in those Releases. A quick tl;dr:
|
16
|
+
|
17
|
+
* Artifact -- a downloaded asset: a compiled Linux kernel, the python package, a picture of your cat, etc
|
18
|
+
* Release -- a set of Artifacts at specific versions: "Python 2.7, Linux kernel 3.18.1, and the 3rd revision of your cat's picture"
|
19
|
+
* Collection - all the Releases currently downloaded, including the "latest" release as well any previous releases
|
20
|
+
|
21
|
+
Also relevant are "Orphans"; these are artifacts that are not needed by any currently tracked releases.
|
22
|
+
|
23
|
+
The gem provides a simple script that will print out the contents of an existing collection:
|
24
|
+
|
25
|
+
```
|
26
|
+
Release: 0
|
27
|
+
initrd: 0.0.36
|
28
|
+
kernel: 3.19-rc7_1
|
29
|
+
vm_root: 0.0.73
|
30
|
+
Release: 1
|
31
|
+
initrd: 0.0.36
|
32
|
+
kernel: 3.19-rc7_1
|
33
|
+
vm_root: 0.0.71
|
34
|
+
Release: 2
|
35
|
+
initrd: 0.0.36
|
36
|
+
kernel: 3.19-rc6_1
|
37
|
+
vm_root: 0.0.69
|
38
|
+
|
39
|
+
Orphans:
|
40
|
+
kernel
|
41
|
+
3.19-rc5_1
|
42
|
+
```
|
43
|
+
|
44
|
+
To start using Menagerie, create a collection:
|
45
|
+
|
46
|
+
```
|
47
|
+
require 'menagerie'
|
48
|
+
my_collection = Menagerie.new
|
49
|
+
```
|
50
|
+
|
51
|
+
Initially, your collection has no releases. To add a release, call `.add_release` with the details for the artifacts you want to install:
|
52
|
+
|
53
|
+
```
|
54
|
+
new_artifacts = [
|
55
|
+
{
|
56
|
+
name: 'kernel',
|
57
|
+
version: '3.19-rc7_1',
|
58
|
+
url: 'https://github.com/dock0/kernel/releases/download/3.19-rc7_1/vmlinuz'
|
59
|
+
},
|
60
|
+
{
|
61
|
+
name: 'initrd',
|
62
|
+
version: '0.0.36',
|
63
|
+
url: 'https://github.com/dock0/initrd/releases/download/0.0.36/initrd.img'
|
64
|
+
}
|
65
|
+
]
|
66
|
+
my_collection.add_release(new_artifacts)
|
67
|
+
```
|
68
|
+
|
69
|
+
This will download the new artifacts into `./artifacts` and symlink them into `./releases/0`, with `./latest` linked to `./releases/0`:
|
70
|
+
|
71
|
+
```
|
72
|
+
# tree
|
73
|
+
.
|
74
|
+
├── artifacts
|
75
|
+
│ ├── initrd
|
76
|
+
│ │ └── 0.0.36
|
77
|
+
│ └── kernel
|
78
|
+
│ └── 3.19-rc7_1
|
79
|
+
├── latest -> releases/0
|
80
|
+
└── releases
|
81
|
+
└── 0
|
82
|
+
├── initrd -> ../../artifacts/initrd/0.0.36
|
83
|
+
└── kernel -> ../../artifacts/kernel/3.19-rc7_1
|
84
|
+
```
|
85
|
+
|
86
|
+
Now lets say you update your kernel package, so you want to make a new releaes with your updated 3.19_1 kernel:
|
87
|
+
|
88
|
+
```
|
89
|
+
new_artifacts = [
|
90
|
+
{
|
91
|
+
name: 'kernel',
|
92
|
+
version: '3.19_1',
|
93
|
+
url: 'https://github.com/dock0/kernel/releases/download/3.19-rc7_1/vmlinuz'
|
94
|
+
},
|
95
|
+
{
|
96
|
+
name: 'initrd',
|
97
|
+
version: '0.0.36',
|
98
|
+
url: 'https://github.com/dock0/initrd/releases/download/0.0.36/initrd.img'
|
99
|
+
}
|
100
|
+
]
|
101
|
+
my_collection.add_release(new_artifacts)
|
102
|
+
```
|
103
|
+
|
104
|
+
Menagerie will rotate the '0' release to '1', download the new kernel, and link the correct assets into '0'. Note that it doesn't download a new copy of the initrd asset, as the version didn't change:
|
105
|
+
|
106
|
+
```
|
107
|
+
# tree
|
108
|
+
.
|
109
|
+
├── artifacts
|
110
|
+
│ ├── initrd
|
111
|
+
│ │ └── 0.0.36
|
112
|
+
│ └── kernel
|
113
|
+
│ ├── 3.19_1
|
114
|
+
│ └── 3.19-rc7_1
|
115
|
+
├── latest -> releases/0
|
116
|
+
└── releases
|
117
|
+
├── 0
|
118
|
+
│ ├── initrd -> ../../artifacts/initrd/0.0.36
|
119
|
+
│ └── kernel -> ../../artifacts/kernel/3.19_1
|
120
|
+
└── 1
|
121
|
+
├── initrd -> ../../artifacts/initrd/0.0.36
|
122
|
+
└── kernel -> ../../artifacts/kernel/3.19-rc7_1
|
123
|
+
```
|
124
|
+
|
125
|
+
Menagerie will retain 5 old releases by default (for a total of 6, including the current version). Older releases will be removed, and orphaned artifacts (those no longer used in any releases) will be deleted. To change the retention or disable reaping of orphans, pass the desired options to Menagerie when you create your collection:
|
126
|
+
|
127
|
+
```
|
128
|
+
larger_collection = Menagerie.new(options: { retention: 20 }) # this will retain 20 old releases
|
129
|
+
|
130
|
+
permanent_collection = Menagerie.new(options: { reap: false }) # this will not reap orphaned artifacts
|
131
|
+
```
|
132
|
+
|
133
|
+
By default, Menagerie will log to STDOUT when it manipulates releases and artifacts. You can disable this via the `verbose` option:
|
134
|
+
|
135
|
+
```
|
136
|
+
quiet_collection = Menagerie.new(options: { verbose: false })
|
137
|
+
```
|
138
|
+
|
139
|
+
You can also override the paths used for artifacts/releases and the "latest" symlink, via the `paths` parameter:
|
140
|
+
|
141
|
+
```
|
142
|
+
custom_paths = {
|
143
|
+
artifacts: '/srv/artifacts',
|
144
|
+
releases: '/opt/releases',
|
145
|
+
latest: '/var/latest_release'
|
146
|
+
}
|
147
|
+
|
148
|
+
my_collection = Menagerie.new(paths: custom_paths)
|
149
|
+
```
|
150
|
+
|
15
151
|
## Installation
|
16
152
|
|
17
153
|
gem install menagerie
|
data/lib/menagerie.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
1
3
|
##
|
2
4
|
# This module provides release collection management
|
3
5
|
module Menagerie
|
@@ -8,6 +10,13 @@ module Menagerie
|
|
8
10
|
def new(*args)
|
9
11
|
self::Collection.new(*args)
|
10
12
|
end
|
13
|
+
|
14
|
+
def get_logger(verbose = true)
|
15
|
+
logger = Logger.new(STDOUT)
|
16
|
+
logger.level = verbose ? Logger::DEBUG : Logger::WARN
|
17
|
+
logger.progname = 'menagerie'
|
18
|
+
logger
|
19
|
+
end
|
11
20
|
end
|
12
21
|
end
|
13
22
|
|
data/lib/menagerie/artifact.rb
CHANGED
@@ -1,31 +1,34 @@
|
|
1
|
-
require 'pathname'
|
2
1
|
require 'open-uri'
|
3
2
|
|
4
3
|
module Menagerie
|
5
4
|
##
|
6
5
|
# Artifacts are a stored file for a particular version of a project
|
7
6
|
class Artifact
|
8
|
-
attr_reader :
|
7
|
+
attr_reader :name, :version
|
9
8
|
|
10
9
|
def initialize(params = {})
|
11
|
-
@
|
12
|
-
@
|
10
|
+
@options = params
|
11
|
+
@logger = @options[:logger] || Menagerie.get_logger
|
12
|
+
@options[:artifact] ? create : parse
|
13
|
+
end
|
14
|
+
|
15
|
+
def path
|
16
|
+
@path ||= "#{@options[:paths][:artifacts]}/#{@name}/#{@version}"
|
13
17
|
end
|
14
18
|
|
15
19
|
private
|
16
20
|
|
17
21
|
def create
|
18
|
-
|
19
|
-
@
|
20
|
-
|
21
|
-
|
22
|
+
artifact = @options[:artifact]
|
23
|
+
@name, @version = artifact.values_at(:name, :version)
|
24
|
+
@logger.info "Downloading artifact: #{path}"
|
25
|
+
download(artifact[:url], path) unless File.exist? path
|
26
|
+
File.chmod(artifact[:mode], path) if artifact[:mode]
|
22
27
|
end
|
23
28
|
|
24
29
|
def parse
|
25
|
-
|
26
|
-
@
|
27
|
-
@version = File.basename File.readlink(link_path)
|
28
|
-
@path = "#{@config[:paths][:artifacts]}/#{@name}/#{@version}"
|
30
|
+
@name = File.basename @options[:path]
|
31
|
+
@version = File.basename File.readlink(@options[:path])
|
29
32
|
end
|
30
33
|
|
31
34
|
def download(url, path)
|
data/lib/menagerie/collection.rb
CHANGED
@@ -5,16 +5,17 @@ module Menagerie
|
|
5
5
|
##
|
6
6
|
# Connection object that contains releases
|
7
7
|
class Collection
|
8
|
-
def initialize(params =
|
8
|
+
def initialize(params = {})
|
9
9
|
params = Cymbal.symbolize(params || {})
|
10
10
|
@paths = default_paths.merge(params[:paths] || {})
|
11
11
|
@options = default_options.merge(params[:options] || {})
|
12
|
+
@logger = Menagerie.get_logger(@options[:verbosity])
|
12
13
|
end
|
13
14
|
|
14
15
|
def releases
|
15
16
|
Dir.glob("#{@paths[:releases]}/*").map do |x|
|
16
|
-
Release.new path: x, paths: @paths
|
17
|
-
end
|
17
|
+
Release.new path: x, paths: @paths, logger: @logger
|
18
|
+
end.sort
|
18
19
|
end
|
19
20
|
|
20
21
|
def orphans
|
@@ -24,9 +25,13 @@ module Menagerie
|
|
24
25
|
end
|
25
26
|
end
|
26
27
|
|
27
|
-
def
|
28
|
+
def add_release(artifacts)
|
28
29
|
rotate
|
29
|
-
Release.new
|
30
|
+
Release.new(
|
31
|
+
artifacts: Cymbal.symbolize(artifacts),
|
32
|
+
paths: @paths,
|
33
|
+
logger: @logger
|
34
|
+
)
|
30
35
|
reap if @options[:reap]
|
31
36
|
link_latest
|
32
37
|
end
|
@@ -41,12 +46,16 @@ module Menagerie
|
|
41
46
|
end
|
42
47
|
|
43
48
|
def reap
|
44
|
-
orphans.each
|
49
|
+
orphans.each do |orphan|
|
50
|
+
@logger.info "Reaping orphan: #{orphan}"
|
51
|
+
FileUtils.rm_f orphan
|
52
|
+
end
|
45
53
|
end
|
46
54
|
|
47
55
|
def link_latest
|
48
56
|
FileUtils.rm_f @paths[:latest]
|
49
57
|
FileUtils.ln_sf releases.sort.first.path, @paths[:latest]
|
58
|
+
@logger.debug "Linked latest release to #{@paths[:latest]}"
|
50
59
|
end
|
51
60
|
|
52
61
|
def default_paths
|
@@ -60,7 +69,8 @@ module Menagerie
|
|
60
69
|
def default_options
|
61
70
|
{
|
62
71
|
retention: 5,
|
63
|
-
reap: true
|
72
|
+
reap: true,
|
73
|
+
verbose: true
|
64
74
|
}
|
65
75
|
end
|
66
76
|
end
|
data/lib/menagerie/release.rb
CHANGED
@@ -8,14 +8,15 @@ module Menagerie
|
|
8
8
|
attr_reader :id, :base, :path
|
9
9
|
|
10
10
|
def initialize(params = {})
|
11
|
-
@
|
12
|
-
@
|
13
|
-
@
|
11
|
+
@options = params
|
12
|
+
@logger = @options[:logger] || Menagerie.get_logger
|
13
|
+
@path = @options[:path] || create
|
14
|
+
parse_path
|
14
15
|
end
|
15
16
|
|
16
17
|
def artifacts
|
17
18
|
Dir.glob("#{@path}/*").map do |x|
|
18
|
-
Artifact.new
|
19
|
+
Artifact.new path: x, paths: @options[:paths], logger: @logger
|
19
20
|
end
|
20
21
|
end
|
21
22
|
|
@@ -24,11 +25,28 @@ module Menagerie
|
|
24
25
|
@id.to_i <=> other.id.to_i
|
25
26
|
end
|
26
27
|
|
28
|
+
def rotate
|
29
|
+
old_path = @path
|
30
|
+
@path = "#{@base}/#{@id.to_i + 1}"
|
31
|
+
FileUtils.mv old_path, @path
|
32
|
+
parse_path
|
33
|
+
end
|
34
|
+
|
35
|
+
def delete
|
36
|
+
@logger.info "Deleting release: #{@path}"
|
37
|
+
FileUtils.rm_r @path
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
27
42
|
def create
|
28
|
-
path = "#{@
|
43
|
+
path = "#{@options[:paths][:releases]}/0"
|
44
|
+
@logger.info "Creating release: #{path}"
|
29
45
|
FileUtils.mkdir_p path
|
30
|
-
@
|
31
|
-
artifact = Artifact.new
|
46
|
+
@options[:artifacts].each do |x|
|
47
|
+
artifact = Artifact.new(
|
48
|
+
artifact: x, paths: @options[:paths], logger: @logger
|
49
|
+
)
|
32
50
|
link artifact.path, "#{path}/#{x[:name]}"
|
33
51
|
end
|
34
52
|
path
|
@@ -40,12 +58,8 @@ module Menagerie
|
|
40
58
|
FileUtils.ln_s relative_source, target
|
41
59
|
end
|
42
60
|
|
43
|
-
def
|
44
|
-
|
45
|
-
end
|
46
|
-
|
47
|
-
def delete
|
48
|
-
FileUtils.rm_r @path
|
61
|
+
def parse_path
|
62
|
+
@base, @id = Pathname.new(@path).split.map(&:to_s)
|
49
63
|
end
|
50
64
|
end
|
51
65
|
end
|
data/menagerie.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'menagerie'
|
3
|
-
s.version = '0.
|
3
|
+
s.version = '1.0.0'
|
4
4
|
s.date = Time.now.strftime("%Y-%m-%d")
|
5
5
|
|
6
6
|
s.summary = ''
|
@@ -14,11 +14,11 @@ Gem::Specification.new do |s|
|
|
14
14
|
s.test_files = `git ls-files spec/*`.split
|
15
15
|
s.executables = ['menagerie']
|
16
16
|
|
17
|
-
s.add_dependency 'cymbal', '~> 0.0
|
17
|
+
s.add_dependency 'cymbal', '~> 1.0.0'
|
18
18
|
|
19
|
-
s.add_development_dependency 'rubocop', '~> 0.
|
20
|
-
s.add_development_dependency 'rake', '~> 10.
|
19
|
+
s.add_development_dependency 'rubocop', '~> 0.29.0'
|
20
|
+
s.add_development_dependency 'rake', '~> 10.4.0'
|
21
21
|
s.add_development_dependency 'coveralls', '~> 0.7.1'
|
22
|
-
s.add_development_dependency 'rspec', '~> 3.
|
22
|
+
s.add_development_dependency 'rspec', '~> 3.2.0'
|
23
23
|
s.add_development_dependency 'fuubar', '~> 2.0.0'
|
24
24
|
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Menagerie::Artifact do
|
4
|
+
before(:each) do
|
5
|
+
FileUtils.rm_rf 'spec/examples/scratch'
|
6
|
+
FileUtils.cp_r 'spec/examples/existing', 'spec/examples/scratch'
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:base_path) { 'spec/examples/scratch' }
|
10
|
+
let(:paths) do
|
11
|
+
{
|
12
|
+
artifacts: "#{base_path}/artifacts",
|
13
|
+
releases: "#{base_path}/releases",
|
14
|
+
latest: "#{base_path}/latest"
|
15
|
+
}
|
16
|
+
end
|
17
|
+
let(:new_artifact) do
|
18
|
+
{ name: 'a', version: '2.0.0', url: 'https://goo.gl/pWew5I' }
|
19
|
+
end
|
20
|
+
let(:produce_output) do
|
21
|
+
output(/Downloading artifact/).to_stdout_from_any_process
|
22
|
+
end
|
23
|
+
let(:artifact) { Menagerie.new(paths: paths).releases.first.artifacts.first }
|
24
|
+
|
25
|
+
it 'has a name attribute' do
|
26
|
+
expect(artifact.name).to eql 'a'
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'has a version attribute' do
|
30
|
+
expect(artifact.version).to eql '0.0.3'
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'has a path attribute' do
|
34
|
+
expect(artifact.path).to eql "#{base_path}/artifacts/a/0.0.3"
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'is created if it does not exist' do
|
38
|
+
expect(File.exist? "#{base_path}/artifacts/a/2.0.0").to be_falsey
|
39
|
+
params = { paths: paths, artifact: new_artifact }
|
40
|
+
expect { Menagerie::Artifact.new params }.to produce_output
|
41
|
+
expect(File.exist? "#{base_path}/artifacts/a/2.0.0").to be_truthy
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
describe Menagerie::Collection do
|
6
|
+
let(:examples) { 'spec/examples' }
|
7
|
+
let(:collection) { Menagerie.new }
|
8
|
+
|
9
|
+
describe '#releases' do
|
10
|
+
it 'parses releases in a collection' do
|
11
|
+
Dir.chdir("#{examples}/existing") do
|
12
|
+
expect(collection.releases.size).to eql 3
|
13
|
+
expect(collection.releases.first).to be_a Menagerie::Release
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'parses an empty collection as empty' do
|
18
|
+
Dir.chdir("#{examples}/empty") do
|
19
|
+
expect(collection.releases.size).to eql 0
|
20
|
+
end
|
21
|
+
Dir.chdir("#{examples}/empty_with_dirs") do
|
22
|
+
expect(collection.releases.size).to eql 0
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'supports an alternate path for releases' do
|
27
|
+
x = Menagerie.new paths: { releases: 'spec/examples/existing/releases' }
|
28
|
+
expect(x.releases.size).to eql 3
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#orphans' do
|
33
|
+
it 'identifies orphaned artifacts' do
|
34
|
+
Dir.chdir("#{examples}/orphaned") do
|
35
|
+
expect(collection.orphans.size).to eql 1
|
36
|
+
expect(collection.orphans.first).to be_a String
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'returns an empty list if there are no orphans' do
|
41
|
+
Dir.chdir("#{examples}/existing") do
|
42
|
+
expect(collection.orphans.size).to eql 0
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '#add_release' do
|
48
|
+
before(:each) do
|
49
|
+
FileUtils.rm_rf 'spec/examples/scratch'
|
50
|
+
FileUtils.cp_r 'spec/examples/existing', 'spec/examples/scratch'
|
51
|
+
end
|
52
|
+
|
53
|
+
let(:base_path) { 'spec/examples/scratch' }
|
54
|
+
let(:paths) do
|
55
|
+
{
|
56
|
+
artifacts: "#{base_path}/artifacts",
|
57
|
+
releases: "#{base_path}/releases",
|
58
|
+
latest: "#{base_path}/latest"
|
59
|
+
}
|
60
|
+
end
|
61
|
+
let(:artifacts) do
|
62
|
+
[
|
63
|
+
{ name: 'a', version: '2.0.0', url: 'https://goo.gl/pWew5I' },
|
64
|
+
{ name: 'b', version: '3.0.0', url: 'https://goo.gl/fkNplq' }
|
65
|
+
]
|
66
|
+
end
|
67
|
+
let(:default_collection) { Menagerie.new(paths: paths) }
|
68
|
+
|
69
|
+
it 'rotates existing releases' do
|
70
|
+
expect(default_collection.releases.size).to eql 3
|
71
|
+
default_collection.add_release(artifacts)
|
72
|
+
expect(default_collection.releases.size).to eql 4
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'retains a set number of old releases' do
|
76
|
+
10.times { default_collection.add_release(artifacts) }
|
77
|
+
expect(default_collection.releases.size).to eql 6
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'can be configured to allow a differnet number of releases' do
|
81
|
+
collection = Menagerie.new(paths: paths, options: { retention: 8 })
|
82
|
+
10.times { collection.add_release(artifacts) }
|
83
|
+
expect(collection.releases.size).to eql 9
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'creates a new release' do
|
87
|
+
default_collection.add_release(artifacts)
|
88
|
+
expect(default_collection.releases.first.artifacts.size).to eql 2
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'reaps orphaned artifacts' do
|
92
|
+
FileUtils.touch "#{base_path}/artifacts/a/0.0.4"
|
93
|
+
FileUtils.mkdir "#{base_path}/artifacts/d"
|
94
|
+
FileUtils.touch "#{base_path}/artifacts/d/0.0.4"
|
95
|
+
expect(File.exist? "#{base_path}/artifacts/a/0.0.4").to be_truthy
|
96
|
+
expect(File.exist? "#{base_path}/artifacts/d/0.0.4").to be_truthy
|
97
|
+
default_collection.add_release(artifacts)
|
98
|
+
expect(File.exist? "#{base_path}/artifacts/a/0.0.4").to be_falsey
|
99
|
+
expect(File.exist? "#{base_path}/artifacts/d/0.0.4").to be_falsey
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'can be configure to not reap orphaned artifacts' do
|
103
|
+
FileUtils.touch "#{base_path}/artifacts/a/0.0.4"
|
104
|
+
FileUtils.mkdir "#{base_path}/artifacts/d"
|
105
|
+
FileUtils.touch "#{base_path}/artifacts/d/0.0.4"
|
106
|
+
expect(File.exist? "#{base_path}/artifacts/a/0.0.4").to be_truthy
|
107
|
+
expect(File.exist? "#{base_path}/artifacts/d/0.0.4").to be_truthy
|
108
|
+
collection = Menagerie.new(paths: paths, options: { reap: false })
|
109
|
+
collection.add_release(artifacts)
|
110
|
+
expect(File.exist? "#{base_path}/artifacts/a/0.0.4").to be_truthy
|
111
|
+
expect(File.exist? "#{base_path}/artifacts/d/0.0.4").to be_truthy
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Menagerie::Release do
|
4
|
+
before(:each) do
|
5
|
+
FileUtils.rm_rf 'spec/examples/scratch'
|
6
|
+
FileUtils.cp_r 'spec/examples/existing', 'spec/examples/scratch'
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:base_path) { 'spec/examples/scratch' }
|
10
|
+
let(:paths) do
|
11
|
+
{
|
12
|
+
artifacts: "#{base_path}/artifacts",
|
13
|
+
releases: "#{base_path}/releases",
|
14
|
+
latest: "#{base_path}/latest"
|
15
|
+
}
|
16
|
+
end
|
17
|
+
let(:release) { Menagerie.new(paths: paths).releases.first }
|
18
|
+
|
19
|
+
it 'has an id attribute' do
|
20
|
+
expect(release.id).to eql '0'
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'has a base attribute' do
|
24
|
+
expect(release.base).to eql "#{base_path}/releases"
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'has a path attribute' do
|
28
|
+
expect(release.path).to eql "#{release.base}/#{release.id}"
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'sorts' do
|
32
|
+
other_release = Menagerie.new(paths: paths).releases.last
|
33
|
+
expect(release <=> other_release).to eql(-1)
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#artifacts' do
|
37
|
+
it 'is an array of Artifacts' do
|
38
|
+
expect(release.artifacts).to all(be_a Menagerie::Artifact)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#rotate' do
|
43
|
+
it 'rotates the release path' do
|
44
|
+
last_release = Menagerie.new(paths: paths).releases.last
|
45
|
+
expect(last_release.id).to eql '2'
|
46
|
+
last_release.rotate
|
47
|
+
expect(last_release.id).to eql '3'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '#delete' do
|
52
|
+
it 'deletes the release' do
|
53
|
+
expect(Dir.exist? release.path).to be_truthy
|
54
|
+
release.delete
|
55
|
+
expect(Dir.exist? release.path).to be_falsey
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/spec/menagerie_spec.rb
CHANGED
@@ -1 +1,33 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Menagerie do
|
4
|
+
describe '#new' do
|
5
|
+
it 'creates collection objects' do
|
6
|
+
expect(Menagerie.new).to be_an_instance_of Menagerie::Collection
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#get_logger' do
|
11
|
+
let(:logger) { Menagerie.get_logger }
|
12
|
+
let(:quiet_logger) { Menagerie.get_logger(false) }
|
13
|
+
|
14
|
+
let(:produce_output) { output(/hello/).to_stdout_from_any_process }
|
15
|
+
|
16
|
+
it 'returns a logger object' do
|
17
|
+
expect(logger).to be_an_instance_of Logger
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'writes to stdout' do
|
21
|
+
expect { logger.warn('hello') }.to produce_output
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'shows debugging by default' do
|
25
|
+
expect { logger.info('hello') }.to produce_output
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'allows silencing debug output' do
|
29
|
+
expect { quiet_logger.info('hello') }.to_not produce_output
|
30
|
+
expect { quiet_logger.warn('hello') }.to produce_output
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: menagerie
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Les Aker
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-02-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cymbal
|
@@ -16,42 +16,42 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.0
|
19
|
+
version: 1.0.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.0
|
26
|
+
version: 1.0.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rubocop
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.
|
33
|
+
version: 0.29.0
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 0.
|
40
|
+
version: 0.29.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 10.
|
47
|
+
version: 10.4.0
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 10.
|
54
|
+
version: 10.4.0
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: coveralls
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -72,14 +72,14 @@ dependencies:
|
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: 3.
|
75
|
+
version: 3.2.0
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: 3.
|
82
|
+
version: 3.2.0
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: fuubar
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -105,6 +105,7 @@ files:
|
|
105
105
|
- ".rspec"
|
106
106
|
- ".rubocop.yml"
|
107
107
|
- ".travis.yml"
|
108
|
+
- CHANGELOG.md
|
108
109
|
- Gemfile
|
109
110
|
- LICENSE
|
110
111
|
- README.md
|
@@ -115,6 +116,47 @@ files:
|
|
115
116
|
- lib/menagerie/collection.rb
|
116
117
|
- lib/menagerie/release.rb
|
117
118
|
- menagerie.gemspec
|
119
|
+
- spec/examples/empty/.keep
|
120
|
+
- spec/examples/empty_with_dirs/artifacts/.keep
|
121
|
+
- spec/examples/empty_with_dirs/releases/.keep
|
122
|
+
- spec/examples/existing/artifacts/a/0.0.1
|
123
|
+
- spec/examples/existing/artifacts/a/0.0.2
|
124
|
+
- spec/examples/existing/artifacts/a/0.0.3
|
125
|
+
- spec/examples/existing/artifacts/b/1.0.0
|
126
|
+
- spec/examples/existing/artifacts/b/1.0.1
|
127
|
+
- spec/examples/existing/artifacts/c/0.1.1
|
128
|
+
- spec/examples/existing/artifacts/c/0.1.2
|
129
|
+
- spec/examples/existing/artifacts/c/0.2.0
|
130
|
+
- spec/examples/existing/releases/0/a
|
131
|
+
- spec/examples/existing/releases/0/b
|
132
|
+
- spec/examples/existing/releases/0/c
|
133
|
+
- spec/examples/existing/releases/1/a
|
134
|
+
- spec/examples/existing/releases/1/b
|
135
|
+
- spec/examples/existing/releases/1/c
|
136
|
+
- spec/examples/existing/releases/2/a
|
137
|
+
- spec/examples/existing/releases/2/b
|
138
|
+
- spec/examples/existing/releases/2/c
|
139
|
+
- spec/examples/orphaned/artifacts/a/0.0.1
|
140
|
+
- spec/examples/orphaned/artifacts/a/0.0.2
|
141
|
+
- spec/examples/orphaned/artifacts/a/0.0.3
|
142
|
+
- spec/examples/orphaned/artifacts/b/1.0.0
|
143
|
+
- spec/examples/orphaned/artifacts/b/1.0.1
|
144
|
+
- spec/examples/orphaned/artifacts/c/0.1.0
|
145
|
+
- spec/examples/orphaned/artifacts/c/0.1.1
|
146
|
+
- spec/examples/orphaned/artifacts/c/0.1.2
|
147
|
+
- spec/examples/orphaned/artifacts/c/0.2.0
|
148
|
+
- spec/examples/orphaned/releases/0/a
|
149
|
+
- spec/examples/orphaned/releases/0/b
|
150
|
+
- spec/examples/orphaned/releases/0/c
|
151
|
+
- spec/examples/orphaned/releases/1/a
|
152
|
+
- spec/examples/orphaned/releases/1/b
|
153
|
+
- spec/examples/orphaned/releases/1/c
|
154
|
+
- spec/examples/orphaned/releases/2/a
|
155
|
+
- spec/examples/orphaned/releases/2/b
|
156
|
+
- spec/examples/orphaned/releases/2/c
|
157
|
+
- spec/menagerie/artifact_spec.rb
|
158
|
+
- spec/menagerie/collection_spec.rb
|
159
|
+
- spec/menagerie/release_spec.rb
|
118
160
|
- spec/menagerie_spec.rb
|
119
161
|
- spec/spec_helper.rb
|
120
162
|
homepage: https://github.com/akerl/menagerie
|
@@ -137,10 +179,51 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
137
179
|
version: '0'
|
138
180
|
requirements: []
|
139
181
|
rubyforge_project:
|
140
|
-
rubygems_version: 2.
|
182
|
+
rubygems_version: 2.4.5
|
141
183
|
signing_key:
|
142
184
|
specification_version: 4
|
143
185
|
summary: ''
|
144
186
|
test_files:
|
187
|
+
- spec/examples/empty/.keep
|
188
|
+
- spec/examples/empty_with_dirs/artifacts/.keep
|
189
|
+
- spec/examples/empty_with_dirs/releases/.keep
|
190
|
+
- spec/examples/existing/artifacts/a/0.0.1
|
191
|
+
- spec/examples/existing/artifacts/a/0.0.2
|
192
|
+
- spec/examples/existing/artifacts/a/0.0.3
|
193
|
+
- spec/examples/existing/artifacts/b/1.0.0
|
194
|
+
- spec/examples/existing/artifacts/b/1.0.1
|
195
|
+
- spec/examples/existing/artifacts/c/0.1.1
|
196
|
+
- spec/examples/existing/artifacts/c/0.1.2
|
197
|
+
- spec/examples/existing/artifacts/c/0.2.0
|
198
|
+
- spec/examples/existing/releases/0/a
|
199
|
+
- spec/examples/existing/releases/0/b
|
200
|
+
- spec/examples/existing/releases/0/c
|
201
|
+
- spec/examples/existing/releases/1/a
|
202
|
+
- spec/examples/existing/releases/1/b
|
203
|
+
- spec/examples/existing/releases/1/c
|
204
|
+
- spec/examples/existing/releases/2/a
|
205
|
+
- spec/examples/existing/releases/2/b
|
206
|
+
- spec/examples/existing/releases/2/c
|
207
|
+
- spec/examples/orphaned/artifacts/a/0.0.1
|
208
|
+
- spec/examples/orphaned/artifacts/a/0.0.2
|
209
|
+
- spec/examples/orphaned/artifacts/a/0.0.3
|
210
|
+
- spec/examples/orphaned/artifacts/b/1.0.0
|
211
|
+
- spec/examples/orphaned/artifacts/b/1.0.1
|
212
|
+
- spec/examples/orphaned/artifacts/c/0.1.0
|
213
|
+
- spec/examples/orphaned/artifacts/c/0.1.1
|
214
|
+
- spec/examples/orphaned/artifacts/c/0.1.2
|
215
|
+
- spec/examples/orphaned/artifacts/c/0.2.0
|
216
|
+
- spec/examples/orphaned/releases/0/a
|
217
|
+
- spec/examples/orphaned/releases/0/b
|
218
|
+
- spec/examples/orphaned/releases/0/c
|
219
|
+
- spec/examples/orphaned/releases/1/a
|
220
|
+
- spec/examples/orphaned/releases/1/b
|
221
|
+
- spec/examples/orphaned/releases/1/c
|
222
|
+
- spec/examples/orphaned/releases/2/a
|
223
|
+
- spec/examples/orphaned/releases/2/b
|
224
|
+
- spec/examples/orphaned/releases/2/c
|
225
|
+
- spec/menagerie/artifact_spec.rb
|
226
|
+
- spec/menagerie/collection_spec.rb
|
227
|
+
- spec/menagerie/release_spec.rb
|
145
228
|
- spec/menagerie_spec.rb
|
146
229
|
- spec/spec_helper.rb
|