cide 0.2.0 → 0.4.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 +4 -4
- data/.cide.yml +2 -2
- data/.rubocop.yml +5 -4
- data/.travis.yml +2 -1
- data/CHANGELOG.md +17 -0
- data/Gemfile.lock +3 -3
- data/README.md +53 -22
- data/cide.gemspec +3 -3
- data/lib/cide/build/config.rb +13 -6
- data/lib/cide/build/config_loader.rb +106 -26
- data/lib/cide/cli.rb +115 -14
- data/lib/cide/dockerfile_template.erb +24 -12
- data/spec/build_config_loader_spec.rb +40 -23
- metadata +6 -7
- data/lib/cide/ssh_config +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c7fc120b6cb172fbbea20e8d325ba1ce9068b6e7
|
4
|
+
data.tar.gz: 43589b67baf32850c037b28e9a7ca3e597e3557e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4c7f2f7cc1c0bed1b49d73f73eff33cb146f1ce4827579cbc7328d569a32de29552c71d562c4a3c196665b4b2ed153fa86eb73ffe0ec5f4460acd080904adae7
|
7
|
+
data.tar.gz: c93b2cd8962571d7f5fb66b13b71b24ab2f47f8c6dd8677d9d99af36c324637b1b897b0c095dd161d64706c00d4d3ac16b64c36f379bb2098dde15709706e137
|
data/.cide.yml
CHANGED
data/.rubocop.yml
CHANGED
@@ -1,24 +1,25 @@
|
|
1
1
|
AllCops:
|
2
2
|
Exclude:
|
3
3
|
- 'spec/**/*'
|
4
|
+
- 'vendor/**/*'
|
4
5
|
|
5
6
|
# Rubocop is not smart enough
|
6
7
|
Metrics/AbcSize:
|
7
|
-
|
8
|
+
Enabled: false
|
8
9
|
|
9
10
|
# CIDE::CLI is essentially a big dispatcher, no need to break it
|
10
11
|
# in smaller chunks.
|
11
12
|
Metrics/ClassLength:
|
12
|
-
|
13
|
+
Enabled: false
|
13
14
|
|
14
15
|
# Offense count: 28
|
15
16
|
Metrics/CyclomaticComplexity:
|
16
|
-
|
17
|
+
Enabled: false
|
17
18
|
|
18
19
|
# CIDE::CLI methods can be read top to bottom. No need to factor out
|
19
20
|
# functionality unless it can be shared.
|
20
21
|
Metrics/MethodLength:
|
21
|
-
|
22
|
+
Enabled: false
|
22
23
|
|
23
24
|
Metrics/PerceivedComplexity:
|
24
25
|
Max: 20
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,21 @@
|
|
1
1
|
|
2
|
+
0.4.0 / 2015-04-19
|
3
|
+
==================
|
4
|
+
|
5
|
+
* NEW: Allow for arbitrary env on multiple levels
|
6
|
+
* NEW: Better link image to name coercion. `foo/bar:tag` will now get a `bar` name.
|
7
|
+
* NEW: Error reporting of broken linked containers
|
8
|
+
* NEW: More control over the `add` directive. It's now possible to set the target path.
|
9
|
+
* NEW: The `as_root` key is now a build step making it possible to set environment and add files.
|
10
|
+
* NEW: `cide build --no-pull`
|
11
|
+
* NEW: `cide debug` command to debug builds
|
12
|
+
* CHANGE: Force cleaning of old images
|
13
|
+
* FIX: Work around issue #7
|
14
|
+
* FIX: caching issues with ssh keys
|
15
|
+
* FIX: cide was using the wrong user to run the ci script
|
16
|
+
* FIX: export_dir and ssh_key command-line options
|
17
|
+
* FIX: running commands with arguments
|
18
|
+
|
2
19
|
0.2.0 / 2015-04-15
|
3
20
|
==================
|
4
21
|
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,29 +1,40 @@
|
|
1
|
-
cide - Continuous Integration Docker Environment
|
1
|
+
*cide* - Continuous Integration Docker Environment
|
2
2
|
================================================
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
*cide* is a command-line tool that runs tests in an isolated (docker)
|
5
|
+
environment. It solves a problem where Jenkins workers need all the project's
|
6
|
+
dependencies (possibly conflicting) to be installed on the boxes. With *cide*
|
7
|
+
each run gets it's own set of temporary docker containers which are scratched
|
8
|
+
at the end. Incidentally it's also possible to the the same `cide` command on
|
9
|
+
the developer machine and get the same build environent as on the CI. This
|
10
|
+
makes configuration iterations much shorter and allow to converge on a working
|
11
|
+
configuration faster.
|
9
12
|
|
10
13
|
Usage
|
11
14
|
-----
|
12
15
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
+
Go to the target project's root and run `cide init` to populate a default
|
17
|
+
`.cide.yml`. This file contains all the instruction to build your project with
|
18
|
+
cide.
|
19
|
+
|
20
|
+
Once the file is configure run `cide` to execute the build. All the output
|
21
|
+
will appear in the console.
|
16
22
|
|
17
23
|
Example
|
18
24
|
-------
|
19
25
|
|
20
26
|
`.cide.yml`
|
21
|
-
```
|
27
|
+
```yaml
|
22
28
|
---
|
23
29
|
from: "ruby:2.1"
|
24
30
|
as_root:
|
25
31
|
- apt-get update -qy && apt-get install -qy libxml2-dev
|
26
|
-
|
32
|
+
before:
|
33
|
+
add:
|
34
|
+
- Gemfile
|
35
|
+
- Gemfile.lock
|
36
|
+
run: bundle install --jobs=3 --retry=3 --deployment
|
37
|
+
run: bundle exec rspec
|
27
38
|
```
|
28
39
|
|
29
40
|
Features
|
@@ -32,34 +43,54 @@ Features
|
|
32
43
|
* straighforward to use, just run `cide` inside of your project
|
33
44
|
* works on OSX with boot2docker
|
34
45
|
* integrates easily with jenkins or other CI systems
|
35
|
-
* can
|
46
|
+
* can use linked containers for backend dependencies like MySQL or redis
|
47
|
+
* artefact export
|
36
48
|
|
37
|
-
|
38
|
-
|
49
|
+
Missing features
|
50
|
+
----------------
|
39
51
|
|
40
|
-
|
52
|
+
* Linked container readiness detection. Some containers take a while to boot
|
53
|
+
up. Currently the `script/ci` must implement some sort of detection loop.
|
54
|
+
* Language detection: default settings per language (see Travis-CI). The
|
55
|
+
current format might be a bit daunting for non-experts.
|
56
|
+
* Build matrix: run variations of the tests, for example with different
|
57
|
+
versions of ruby to make sure all are supported (useful for libraries).
|
58
|
+
|
59
|
+
PR welcome !
|
41
60
|
|
42
61
|
Installation
|
43
62
|
------------
|
44
63
|
|
45
|
-
|
64
|
+
The current dependencies are [ruby
|
65
|
+
2.0+](https://www.ruby-lang.org/en/documentation/installation/) and [docker
|
66
|
+
1.5.0+](https://docs.docker.com/installation/#installation)
|
46
67
|
|
47
|
-
|
48
|
-
gem install cide
|
49
|
-
```
|
68
|
+
On OSX, boot2docker is automatically used if installed.
|
50
69
|
|
51
|
-
OSX docker install:
|
70
|
+
Quick OSX docker install:
|
52
71
|
```sh
|
53
72
|
brew install boot2docker
|
54
73
|
boot2docker init
|
55
74
|
boot2docker up
|
56
|
-
|
75
|
+
```
|
76
|
+
|
77
|
+
Then install the *cide* ruby gem:
|
78
|
+
```sh
|
79
|
+
gem install cide
|
57
80
|
```
|
58
81
|
|
59
82
|
Similar projects
|
60
83
|
----------------
|
61
84
|
|
62
85
|
* [Docker Compose](https://docs.docker.com/compose/) - Docker development environment
|
86
|
+
* [Travis CI](https://travis-ci.org/) - Great CI for Open Source projects
|
87
|
+
* [Construi](https://github.com/lstephen/construi) - Another ruby command-line builder
|
88
|
+
|
89
|
+
TODO
|
90
|
+
----
|
63
91
|
|
64
|
-
|
92
|
+
* Document the `.cide.yml` format. Look into `lib/cide/build/config_loader.rb`
|
93
|
+
for now
|
94
|
+
* Explain how to use *cide* with Jenkins
|
95
|
+
* Explain Travis CI vs *cide* + Jenkins
|
65
96
|
|
data/cide.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = 'cide'
|
5
|
-
s.version = '0.
|
5
|
+
s.version = '0.4.0'
|
6
6
|
s.authors = ['zimbatm']
|
7
7
|
s.email = ['zimbatm@zimbatm.com']
|
8
8
|
s.summary = 'CI docker runner'
|
@@ -20,8 +20,8 @@ DESC
|
|
20
20
|
|
21
21
|
s.required_ruby_version = '>= 1.9.3'
|
22
22
|
|
23
|
-
s.add_runtime_dependency 'thor', '~> 0.19
|
24
|
-
s.add_runtime_dependency 'virtus', '~> 1.0
|
23
|
+
s.add_runtime_dependency 'thor', '~> 0.19'
|
24
|
+
s.add_runtime_dependency 'virtus', '~> 1.0'
|
25
25
|
s.add_development_dependency 'rake'
|
26
26
|
s.add_development_dependency 'rubocop'
|
27
27
|
s.add_development_dependency 'rspec'
|
data/lib/cide/build/config.rb
CHANGED
@@ -21,11 +21,18 @@ module CIDE
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
+
class FileAdd
|
25
|
+
include Virtus.model(strict: true)
|
26
|
+
include NiceInspect
|
27
|
+
attribute :src, Array[String], default: []
|
28
|
+
attribute :dest, String
|
29
|
+
end
|
30
|
+
|
24
31
|
class Step
|
25
32
|
include Virtus.model(strict: true)
|
26
33
|
include NiceInspect
|
27
|
-
attribute :add, Array[
|
28
|
-
attribute :
|
34
|
+
attribute :add, Array[FileAdd], default: []
|
35
|
+
attribute :env, Hash[String, String], default: {}
|
29
36
|
attribute :run, Array[String], default: []
|
30
37
|
end
|
31
38
|
|
@@ -34,7 +41,7 @@ module CIDE
|
|
34
41
|
include NiceInspect
|
35
42
|
attribute :name, String
|
36
43
|
attribute :image, String
|
37
|
-
attribute :env, Hash[String, String]
|
44
|
+
attribute :env, Hash[String, String], default: {}
|
38
45
|
attribute :run, String
|
39
46
|
# Container ID added after the fact
|
40
47
|
attr_accessor :id
|
@@ -43,13 +50,13 @@ module CIDE
|
|
43
50
|
include Virtus.model(strict: true)
|
44
51
|
include NiceInspect
|
45
52
|
attribute :from, String, default: 'ubuntu'
|
46
|
-
attribute :as_root,
|
53
|
+
attribute :as_root, Step, required: false
|
47
54
|
attribute :use_ssh, Boolean, default: false
|
48
55
|
attribute :before, Step, required: false
|
49
|
-
attribute :
|
56
|
+
attribute :env, Hash[String, String], default: {}
|
50
57
|
attribute :export_dir, String, required: false
|
51
58
|
attribute :links, Array[Link], default: []
|
52
|
-
attribute :run, String, default: 'script/ci'
|
59
|
+
attribute :run, Array[String], default: ['script/ci']
|
53
60
|
|
54
61
|
attr_reader :warnings, :errors
|
55
62
|
|
@@ -27,20 +27,21 @@ module CIDE
|
|
27
27
|
wanted_key(path, 'from', key)
|
28
28
|
@config.from = expect_string(path, value)
|
29
29
|
when 'as_root' then
|
30
|
-
@config.as_root =
|
30
|
+
@config.as_root = maybe_step(path, value)
|
31
31
|
when 'use_ssh' then
|
32
32
|
@config.use_ssh = expect_boolean(path, value)
|
33
33
|
when 'before' then
|
34
34
|
@config.before = maybe_step(path, value)
|
35
|
-
when 'forward_env' then
|
36
|
-
|
35
|
+
when 'env', 'forward_env' then
|
36
|
+
wanted_key(path, 'env', key)
|
37
|
+
@config.env = expect_env_hash(path, value)
|
37
38
|
when 'export_dir' then
|
38
39
|
@config.export_dir = maybe_string(path, value)
|
39
40
|
when 'link', 'links' then
|
40
41
|
@config.links = expect_links(path, value)
|
41
42
|
when 'run', 'command' then
|
42
43
|
wanted_key(path, 'run', key)
|
43
|
-
@config.run =
|
44
|
+
@config.run = expect_run(path, value)
|
44
45
|
else
|
45
46
|
unknown_key(path)
|
46
47
|
end
|
@@ -50,19 +51,25 @@ module CIDE
|
|
50
51
|
|
51
52
|
protected
|
52
53
|
|
54
|
+
def warn(message)
|
55
|
+
@config.warnings << message
|
56
|
+
end
|
57
|
+
|
58
|
+
def error(message)
|
59
|
+
@config.errors << message
|
60
|
+
end
|
61
|
+
|
53
62
|
def wanted_key(path, wanted_key, key)
|
54
63
|
return if key == wanted_key
|
55
|
-
|
56
|
-
"#{path} is deprecated. use '#{wanted_key}' instead."
|
64
|
+
warn "#{path} is deprecated. use '#{wanted_key}' instead."
|
57
65
|
end
|
58
66
|
|
59
67
|
def unknown_key(path)
|
60
|
-
|
68
|
+
warn "Unknown key #{path}"
|
61
69
|
end
|
62
70
|
|
63
71
|
def type_error(path, wanted_type, value)
|
64
|
-
|
65
|
-
"expected #{path} to be a #{wanted_type} but got a #{value.class}"
|
72
|
+
error "expected #{path} to be a #{wanted_type} but got a #{value.class}"
|
66
73
|
end
|
67
74
|
|
68
75
|
def expect_string(path, value)
|
@@ -77,7 +84,7 @@ module CIDE
|
|
77
84
|
|
78
85
|
def maybe_string(path, value)
|
79
86
|
case value
|
80
|
-
when String, Symbol
|
87
|
+
when String, Symbol, Integer
|
81
88
|
value.to_s
|
82
89
|
when nil
|
83
90
|
nil
|
@@ -89,7 +96,7 @@ module CIDE
|
|
89
96
|
|
90
97
|
def maybe_step(path, value)
|
91
98
|
case value
|
92
|
-
when String, Symbol, Array then
|
99
|
+
when String, Symbol, Integer, Array then
|
93
100
|
load_step(path, run: value)
|
94
101
|
when Hash then
|
95
102
|
load_step(path, value)
|
@@ -109,10 +116,11 @@ module CIDE
|
|
109
116
|
case key
|
110
117
|
when 'run' then
|
111
118
|
step.run = expect_array(path_, value)
|
112
|
-
when 'forward_env' then
|
113
|
-
|
119
|
+
when 'env', 'forward_env' then
|
120
|
+
wanted_key(path_, 'env', key)
|
121
|
+
step.env = expect_env_hash(path_, value)
|
114
122
|
when 'add' then
|
115
|
-
step.add =
|
123
|
+
step.add = expect_adds(path_, value)
|
116
124
|
else
|
117
125
|
unknown_key(path_)
|
118
126
|
end
|
@@ -123,7 +131,7 @@ module CIDE
|
|
123
131
|
def expect_links(path, value)
|
124
132
|
array = []
|
125
133
|
case value
|
126
|
-
when String, Symbol, Hash then
|
134
|
+
when String, Symbol, Integer, Hash then
|
127
135
|
array << expect_link(path, value)
|
128
136
|
when Array then
|
129
137
|
value.compact.each_with_index do |value_, i|
|
@@ -139,8 +147,8 @@ module CIDE
|
|
139
147
|
|
140
148
|
def expect_link(path, value)
|
141
149
|
case value
|
142
|
-
when String, Symbol then
|
143
|
-
load_link(path,
|
150
|
+
when String, Symbol, Integer then
|
151
|
+
load_link(path, image: value)
|
144
152
|
when Hash
|
145
153
|
load_link(path, value)
|
146
154
|
else
|
@@ -160,14 +168,14 @@ module CIDE
|
|
160
168
|
wanted_key(path_, 'image', key)
|
161
169
|
link.image = expect_string(path_, value)
|
162
170
|
when 'env' then
|
163
|
-
link.env =
|
171
|
+
link.env = expect_env_hash(path_, value)
|
164
172
|
when 'run' then
|
165
173
|
link.run = maybe_string(path_, value)
|
166
174
|
else
|
167
175
|
unknown_key(path_)
|
168
176
|
end
|
169
177
|
end
|
170
|
-
link.name ||= link.image
|
178
|
+
link.name ||= link.image.split(':').first.split('/').last if link.image
|
171
179
|
link.image ||= link.name
|
172
180
|
if link.name.nil?
|
173
181
|
type_error(
|
@@ -199,7 +207,7 @@ module CIDE
|
|
199
207
|
value.compact.each_with_index do |value_, i|
|
200
208
|
array << expect_string(path.append(i), value_)
|
201
209
|
end
|
202
|
-
when String, Symbol then
|
210
|
+
when String, Symbol, Integer then
|
203
211
|
array << value.to_s
|
204
212
|
when nil then
|
205
213
|
# nothing to do
|
@@ -209,18 +217,90 @@ module CIDE
|
|
209
217
|
array.compact
|
210
218
|
end
|
211
219
|
|
212
|
-
def
|
220
|
+
def expect_adds(path, value)
|
221
|
+
array = []
|
213
222
|
case value
|
223
|
+
when Array then
|
224
|
+
value.compact.each_with_index do |value_, i|
|
225
|
+
str = expect_string(path.append(i), value_)
|
226
|
+
array << load_add_str(str)
|
227
|
+
end
|
228
|
+
when Hash then
|
229
|
+
value.each_pair do |key_, value_|
|
230
|
+
src = expect_array(path.append(key_), value_)
|
231
|
+
array << Config::FileAdd.new(src: src, dest: key_.to_s)
|
232
|
+
end
|
233
|
+
when String, Symbol, Integer then
|
234
|
+
array << load_add_str(value.to_s)
|
235
|
+
when nil then
|
236
|
+
# nothing to do
|
237
|
+
else
|
238
|
+
type_error(path, 'arrays of string, hash, string or nil', value)
|
239
|
+
end
|
240
|
+
array.compact
|
241
|
+
end
|
242
|
+
|
243
|
+
def load_add_str(str)
|
244
|
+
Config::FileAdd.new(
|
245
|
+
src: [str],
|
246
|
+
dest: str,
|
247
|
+
)
|
248
|
+
end
|
249
|
+
|
250
|
+
def expect_env(path, key)
|
251
|
+
str = expect_string(path, key)
|
252
|
+
return nil if str == ''
|
253
|
+
value = ENV[str]
|
254
|
+
error "Missing environment variable #{key} in #{path}" if value.nil?
|
255
|
+
value
|
256
|
+
end
|
257
|
+
|
258
|
+
def expect_env_hash(path, value)
|
259
|
+
hash = {}
|
260
|
+
case value
|
261
|
+
when String, Symbol, Integer
|
262
|
+
key1 = value
|
263
|
+
value1 = expect_env(path, key1)
|
264
|
+
hash[key1] = value1 if value1
|
265
|
+
when Array then
|
266
|
+
value.compact.each_with_index do |key, i|
|
267
|
+
value_ = expect_env(path.append(i), key)
|
268
|
+
hash[key.to_s] = value_ if value_
|
269
|
+
end
|
214
270
|
when Hash then
|
215
|
-
hash = {}
|
216
271
|
value.each_pair do |key, value_|
|
217
|
-
|
272
|
+
key = key.to_s
|
273
|
+
path_ = path.append(key)
|
274
|
+
if value_.nil?
|
275
|
+
value_ = expect_env(path_, key)
|
276
|
+
else
|
277
|
+
value_ = expect_string(path_, value_)
|
278
|
+
end
|
279
|
+
hash[key.to_s] = value_ if value_
|
218
280
|
end
|
219
|
-
hash
|
220
281
|
else
|
221
|
-
type_error(path, 'hash', value)
|
222
|
-
|
282
|
+
type_error(path, 'hash or array of keys or just a string', value)
|
283
|
+
end
|
284
|
+
hash
|
285
|
+
end
|
286
|
+
|
287
|
+
def expect_run(path, value)
|
288
|
+
array = []
|
289
|
+
has_error = false
|
290
|
+
case value
|
291
|
+
when Array
|
292
|
+
value.compact.each_with_index do |key, i|
|
293
|
+
array << expect_string(path.append(i), key)
|
294
|
+
end
|
295
|
+
when String, Symbol, Integer
|
296
|
+
array.push('sh', '-e', '-c', value.to_s)
|
297
|
+
when nil then
|
298
|
+
else
|
299
|
+
has_error = true
|
300
|
+
type_error(path, 'string or array of string', value)
|
223
301
|
end
|
302
|
+
error("#{path} shouldn't be empty") if array.empty? && !has_error
|
303
|
+
array
|
224
304
|
end
|
225
305
|
end
|
226
306
|
end
|
data/lib/cide/cli.rb
CHANGED
@@ -5,6 +5,7 @@ require 'cide/build'
|
|
5
5
|
require 'thor'
|
6
6
|
|
7
7
|
require 'json'
|
8
|
+
require 'securerandom'
|
8
9
|
require 'time'
|
9
10
|
|
10
11
|
module CIDE
|
@@ -35,8 +36,14 @@ module CIDE
|
|
35
36
|
|
36
37
|
method_option 'run',
|
37
38
|
desc: 'Override the script to run',
|
39
|
+
type: :array,
|
38
40
|
aliases: ['r'],
|
39
|
-
default:
|
41
|
+
default: []
|
42
|
+
|
43
|
+
method_option 'pull',
|
44
|
+
desc: 'Whenever to pull for new images on build',
|
45
|
+
type: :boolean,
|
46
|
+
default: true
|
40
47
|
|
41
48
|
method_option 'ssh_key',
|
42
49
|
desc: 'Path to a ssh key to import into the docker image',
|
@@ -52,8 +59,10 @@ module CIDE
|
|
52
59
|
banner 'Config'
|
53
60
|
build = Build::Config.load_file CONFIG_FILE
|
54
61
|
exit 1 if build.nil?
|
55
|
-
export_dir = options.export_dir
|
56
|
-
|
62
|
+
export_dir = options.export_dir
|
63
|
+
export_dir ||= File.dirname(build.export_dir) if build.export_dir
|
64
|
+
ssh_key = File.expand_path(options.ssh_key)
|
65
|
+
build.run = options.run unless options.run.empty?
|
57
66
|
name = CIDE::Docker.id options.name
|
58
67
|
tag = "cide/#{name}"
|
59
68
|
say_status :config, build.inspect
|
@@ -61,15 +70,18 @@ module CIDE
|
|
61
70
|
## Build ##
|
62
71
|
banner 'Build'
|
63
72
|
if build.use_ssh
|
64
|
-
unless File.exist?(
|
65
|
-
fail ArgumentError, "SSH key #{
|
73
|
+
unless File.exist?(ssh_key)
|
74
|
+
fail ArgumentError, "SSH key #{ssh_key} not found"
|
66
75
|
end
|
67
|
-
|
68
|
-
create_tmp_file SSH_CONFIG_FILE, File.read(SSH_CONFIG_PATH)
|
69
|
-
create_tmp_file TEMP_SSH_KEY, File.read(build.ssh_key)
|
76
|
+
create_tmp_file TEMP_SSH_KEY, File.read(ssh_key)
|
70
77
|
end
|
71
78
|
create_tmp_file DOCKERFILE, build.to_dockerfile
|
72
|
-
|
79
|
+
build_options = ['--force-rm']
|
80
|
+
build_options << '--pull' if options.pull
|
81
|
+
build_options.push '-f', DOCKERFILE
|
82
|
+
build_options.push '-t', tag
|
83
|
+
build_options << '.'
|
84
|
+
docker :build, *build_options
|
73
85
|
|
74
86
|
## CI ##
|
75
87
|
banner 'Run'
|
@@ -86,21 +98,26 @@ module CIDE
|
|
86
98
|
|
87
99
|
run_options = ['--detach']
|
88
100
|
|
89
|
-
build.
|
90
|
-
run_options.push '--env', [
|
101
|
+
build.env.each_pair do |key, value|
|
102
|
+
run_options.push '--env', [key, value].join('=')
|
91
103
|
end
|
92
104
|
|
93
105
|
build.links.each do |link|
|
94
106
|
run_options.push '--link', [link.id, link.name].join(':')
|
95
107
|
end
|
96
108
|
|
109
|
+
id = SecureRandom.hex
|
110
|
+
run_options.push '--name', id
|
111
|
+
|
97
112
|
run_options.push tag
|
98
|
-
run_options.push
|
113
|
+
run_options.push(*build.run)
|
99
114
|
|
100
|
-
id = docker(:run, *run_options, capture: true).strip
|
101
115
|
containers << id
|
116
|
+
docker(:run, *run_options, capture: true).strip
|
102
117
|
docker(:attach, id)
|
103
118
|
|
119
|
+
say_status :status, 'SUCCESS', :green
|
120
|
+
|
104
121
|
## Export ##
|
105
122
|
return unless options.export
|
106
123
|
banner 'Export'
|
@@ -109,6 +126,88 @@ module CIDE
|
|
109
126
|
guest_export_dir = File.expand_path(build.export_dir, CIDE_SRC_DIR)
|
110
127
|
host_export_dir = File.expand_path(export_dir, Dir.pwd)
|
111
128
|
docker :cp, [id, guest_export_dir].join(':'), host_export_dir
|
129
|
+
rescue Docker::Error => ex
|
130
|
+
say_status :status, 'ERROR', :red
|
131
|
+
exit ex.exitstatus
|
132
|
+
ensure
|
133
|
+
linked_containers = containers - [id]
|
134
|
+
unless linked_containers.empty?
|
135
|
+
infos = docker(
|
136
|
+
:inspect,
|
137
|
+
*linked_containers,
|
138
|
+
capture: true,
|
139
|
+
verbose: false,
|
140
|
+
)
|
141
|
+
JSON.parse(infos).each do |info|
|
142
|
+
config = info['Config']
|
143
|
+
state = info['State']
|
144
|
+
|
145
|
+
next unless state['Dead'] || state['ExitCode'] > 0
|
146
|
+
|
147
|
+
$stderr.puts "=== Failed linked container #{info['Id']} ==="
|
148
|
+
$stderr.puts "Image: #{config['Image']}"
|
149
|
+
$stderr.puts "State: #{state.inspect}"
|
150
|
+
docker(:logs, '--tail', 20, info['Id'])
|
151
|
+
end
|
152
|
+
end
|
153
|
+
# Shutdown old containers
|
154
|
+
unless containers.empty?
|
155
|
+
docker :rm, '--force', *containers.reverse,
|
156
|
+
verbose: false,
|
157
|
+
capture: true
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
desc 'debug', 'Opens a debug console in the last project image'
|
162
|
+
method_option 'name',
|
163
|
+
desc: 'Name of the build',
|
164
|
+
aliases: %w(n t),
|
165
|
+
default: File.basename(Dir.pwd)
|
166
|
+
method_option 'user',
|
167
|
+
desc: 'User to run under',
|
168
|
+
default: 'cide'
|
169
|
+
def debug
|
170
|
+
containers = []
|
171
|
+
|
172
|
+
setup_docker
|
173
|
+
|
174
|
+
## Config ##
|
175
|
+
banner 'Config'
|
176
|
+
build = Build::Config.load_file CONFIG_FILE
|
177
|
+
exit 1 if build.nil?
|
178
|
+
name = CIDE::Docker.id options.name
|
179
|
+
tag = "cide/#{name}"
|
180
|
+
say_status :config, build.inspect
|
181
|
+
|
182
|
+
## CI ##
|
183
|
+
banner 'Run'
|
184
|
+
build.links.each do |link|
|
185
|
+
args = ['--detach']
|
186
|
+
link.env.each_pair do |key, value|
|
187
|
+
args.push('--env', [key, value].join('='))
|
188
|
+
end
|
189
|
+
args << link.image
|
190
|
+
args << link.run if link.run
|
191
|
+
link.id = docker(:run, *args, capture: true).strip
|
192
|
+
containers << link.id
|
193
|
+
end
|
194
|
+
|
195
|
+
run_options = ['--rm', '-t', '-i']
|
196
|
+
|
197
|
+
run_options.push '--user', options.user
|
198
|
+
|
199
|
+
build.env.each_pair do |key, value|
|
200
|
+
run_options.push '--env', [key, value].join('=')
|
201
|
+
end
|
202
|
+
|
203
|
+
build.links.each do |link|
|
204
|
+
run_options.push '--link', [link.id, link.name].join(':')
|
205
|
+
end
|
206
|
+
|
207
|
+
run_options.push tag
|
208
|
+
run_options.push 'bash'
|
209
|
+
|
210
|
+
docker(:run, *run_options)
|
112
211
|
rescue Docker::Error => ex
|
113
212
|
exit ex.exitstatus
|
114
213
|
ensure
|
@@ -168,7 +267,7 @@ module CIDE
|
|
168
267
|
return
|
169
268
|
end
|
170
269
|
|
171
|
-
docker('rmi', *old_cide_images)
|
270
|
+
docker('rmi', '--force', *old_cide_images)
|
172
271
|
end
|
173
272
|
|
174
273
|
desc 'init', "Creates a blank #{CONFIG_FILE} into the project"
|
@@ -181,6 +280,8 @@ module CIDE
|
|
181
280
|
|
182
281
|
def create_tmp_file(destination, *args, &block)
|
183
282
|
create_file(destination, *args, &block)
|
283
|
+
# Dockerfile ADD compares content and mtime, we don't want that
|
284
|
+
File.utime(1_286_701_800, 1_286_701_800, destination)
|
184
285
|
at_exit do
|
185
286
|
remove_file(destination, verbose: false)
|
186
287
|
end
|
@@ -4,8 +4,16 @@ RUN useradd -m -U -d <%= CIDE_DIR %> cide
|
|
4
4
|
|
5
5
|
# Install system build dependencies here
|
6
6
|
|
7
|
-
<% as_root
|
7
|
+
<% if as_root -%>
|
8
|
+
<% as_root.add.each do |file| -%>
|
9
|
+
ADD <%= file.src.join(' ') %> <%= file.dest %>
|
10
|
+
<% end -%>
|
11
|
+
<% as_root.env.each_pair do |key, value| -%>
|
12
|
+
ENV <%= key %> <%= value %>
|
13
|
+
<% end -%>
|
14
|
+
<% as_root.run.each do |cmd| -%>
|
8
15
|
RUN <%= cmd %>
|
16
|
+
<% end -%>
|
9
17
|
<% end -%>
|
10
18
|
|
11
19
|
# Common
|
@@ -14,32 +22,36 @@ ENV HOME <%= CIDE_DIR %>
|
|
14
22
|
WORKDIR <%= CIDE_SRC_DIR %>
|
15
23
|
|
16
24
|
# SSH config
|
25
|
+
|
17
26
|
<% if use_ssh -%>
|
18
|
-
|
19
|
-
RUN
|
27
|
+
RUN mkdir <%= CIDE_SSH_DIR %>
|
28
|
+
RUN echo StrictHostKeyChecking no > <%= File.join(CIDE_SSH_DIR, 'config') %>
|
29
|
+
RUN chmod 400 <%= File.join(CIDE_SSH_DIR, 'config') %>
|
20
30
|
|
21
|
-
ADD <%= TEMP_SSH_KEY %> <%= File.
|
31
|
+
ADD <%= TEMP_SSH_KEY %> <%= File.join(CIDE_SSH_DIR, 'id_rsa') %>
|
22
32
|
RUN chmod 400 <%= File.expand_path('id_rsa', CIDE_SSH_DIR) %>
|
23
|
-
RUN chmod 755 <%= CIDE_SSH_DIR %>
|
24
33
|
RUN chown -R cide:cide <%= CIDE_DIR %>
|
25
|
-
<% end
|
34
|
+
<% end -%>
|
26
35
|
|
27
36
|
# Before
|
28
37
|
|
29
38
|
<% if before -%>
|
30
|
-
<% before.forward_env.each do |key| -%>
|
31
|
-
ENV <%= key %> <%= ENV[key] %>
|
32
|
-
<% end %>
|
33
39
|
<% before.add.each do |file| -%>
|
34
|
-
ADD <%= file %> <%=
|
40
|
+
ADD <%= file.src.join(' ') %> <%= file.dest %>
|
35
41
|
<% end %>
|
36
42
|
RUN chown -R cide:cide <%= CIDE_DIR %>
|
43
|
+
<% before.env.each_pair do |key, value| -%>
|
44
|
+
ENV <%= key %> <%= value %>
|
45
|
+
<% end %>
|
37
46
|
USER cide
|
38
|
-
|
39
|
-
|
47
|
+
<% before.run.each do |cmd| -%>
|
48
|
+
RUN <%= cmd %>
|
49
|
+
<% end %>
|
40
50
|
<% end -%>
|
41
51
|
|
42
52
|
# Add project data
|
43
53
|
|
54
|
+
USER root
|
44
55
|
ADD . <%= CIDE_SRC_DIR %>
|
45
56
|
RUN chown -R cide:cide <%= CIDE_DIR %>
|
57
|
+
USER cide
|
@@ -7,17 +7,19 @@ describe "CIDE::Build::Config::Loader" do
|
|
7
7
|
before do
|
8
8
|
@config = CIDE::Build::Config.new
|
9
9
|
@loader = CIDE::Build::ConfigLoader.new(@config)
|
10
|
+
ENV['TEST1'] = 'test1'
|
11
|
+
ENV['TEST2'] = 'test2'
|
10
12
|
end
|
11
13
|
|
12
14
|
default_config = {
|
13
15
|
"from" => "ubuntu",
|
14
|
-
"as_root" =>
|
16
|
+
"as_root" => nil,
|
15
17
|
"use_ssh" => false,
|
16
18
|
"before" => nil,
|
17
|
-
"
|
19
|
+
"env" => {},
|
18
20
|
"export_dir" => nil,
|
19
21
|
"links" => [],
|
20
|
-
"run" => "script/ci",
|
22
|
+
"run" => ["script/ci"],
|
21
23
|
}
|
22
24
|
|
23
25
|
it "works - empty config" do
|
@@ -30,19 +32,25 @@ describe "CIDE::Build::Config::Loader" do
|
|
30
32
|
it "works2 - full config" do
|
31
33
|
full_config = {
|
32
34
|
"from" => "god",
|
33
|
-
"as_root" =>
|
35
|
+
"as_root" => {
|
36
|
+
#"add" => [["http://df.ru", "zzz"], "yyy" => ["."]],
|
37
|
+
"add" => [],
|
38
|
+
"env" => {"HOME" => "/"},
|
39
|
+
"run" => ["one", "two"],
|
40
|
+
},
|
34
41
|
"use_ssh" => true,
|
35
42
|
"before" => {
|
36
|
-
"add" => ["zzz", "yyy"],
|
37
|
-
"
|
43
|
+
#"add" => [["http://df.ru", "zzz"], "yyy" => ["."]],
|
44
|
+
"add" => [],
|
45
|
+
"env" => {"HOME" => "/"},
|
38
46
|
"run" => ["a", "b"],
|
39
47
|
},
|
40
|
-
"
|
48
|
+
"env" => {"HOME" => "/"},
|
41
49
|
"links" => [
|
42
50
|
{"name" => "redis", "image" => "redis2:foo", "env" => {"HOME" => "/"}, "run" => "redis-server"}
|
43
51
|
],
|
44
52
|
"export_dir" => "./artifacts",
|
45
|
-
"run" => "do/something",
|
53
|
+
"run" => ["do/something"],
|
46
54
|
}
|
47
55
|
|
48
56
|
@loader.load(full_config)
|
@@ -53,25 +61,31 @@ describe "CIDE::Build::Config::Loader" do
|
|
53
61
|
end
|
54
62
|
|
55
63
|
it "coerces things around" do
|
64
|
+
ENV['LOL'] = 'zzz'
|
65
|
+
ENV['555'] = '666'
|
56
66
|
@loader.load(
|
57
67
|
as_root: "xxxxx",
|
58
|
-
before:
|
59
|
-
|
60
|
-
|
68
|
+
before: {
|
69
|
+
add: {bin: 555}
|
70
|
+
},
|
71
|
+
links: ["mysql:5.6", {image: "redis", env: {PATH: "/bin", TEST1: nil}}, nil],
|
72
|
+
env: ["LOL", nil, 555],
|
73
|
+
run: "hello world",
|
61
74
|
)
|
62
75
|
|
63
76
|
expect(@config.to_h.as_json).to eq(default_config.merge(
|
64
|
-
"as_root" => ["xxxxx"],
|
77
|
+
"as_root" => {"add" => [], "env" => {}, "run" => ["xxxxx"]},
|
65
78
|
"before" => {
|
66
|
-
"add" => [],
|
67
|
-
"
|
68
|
-
"run" => [
|
79
|
+
"add" => [{"src" => ["555"], "dest" => "bin"}],
|
80
|
+
"env" => {},
|
81
|
+
"run" => [],
|
69
82
|
},
|
70
83
|
"links" => [
|
71
|
-
{"name" => "mysql", "image" => "mysql", "
|
72
|
-
{"name" => "redis", "image" => "redis", "
|
84
|
+
{"name" => "mysql", "image" => "mysql:5.6", "env" => {}, "run" => nil},
|
85
|
+
{"name" => "redis", "image" => "redis", "env" => {"PATH" => "/bin", "TEST1" => "test1"}, "run" => nil},
|
73
86
|
],
|
74
|
-
"
|
87
|
+
"env" => {"LOL" => "zzz", "555" => "666"},
|
88
|
+
"run" => ["sh", "-e", "-c", "hello world"],
|
75
89
|
))
|
76
90
|
expect(@config.warnings).to eq([])
|
77
91
|
expect(@config.errors).to eq([])
|
@@ -79,15 +93,18 @@ describe "CIDE::Build::Config::Loader" do
|
|
79
93
|
|
80
94
|
it "notifies deprecations" do
|
81
95
|
@loader.load(
|
96
|
+
link: { from: "hoho" },
|
82
97
|
image: "foo",
|
83
98
|
command: "lol",
|
84
99
|
zzz: 4,
|
85
100
|
)
|
86
101
|
expect(@config.as_json).to eq(default_config.merge(
|
102
|
+
"links" => [{"name" => "hoho", "image" => "hoho", "env" => {}, "run" => nil}],
|
87
103
|
"from" => "foo",
|
88
|
-
"run" => "lol",
|
104
|
+
"run" => ["sh", "-e", "-c", "lol"],
|
89
105
|
))
|
90
106
|
expect(@config.warnings).to eq([
|
107
|
+
"link.from is deprecated. use 'image' instead.",
|
91
108
|
"image is deprecated. use 'from' instead.",
|
92
109
|
"command is deprecated. use 'run' instead.",
|
93
110
|
"Unknown key zzz",
|
@@ -98,17 +115,17 @@ describe "CIDE::Build::Config::Loader" do
|
|
98
115
|
it "reports type errors" do
|
99
116
|
@loader.load(
|
100
117
|
as_root: ["aaa", Time.now],
|
101
|
-
|
118
|
+
env: Time.now,
|
102
119
|
links: {},
|
103
120
|
)
|
104
121
|
|
105
122
|
expect(@config.to_h.as_json).to eq(default_config.merge(
|
106
|
-
"as_root" => ["aaa", ""]
|
123
|
+
"as_root" => {"add" => [], "env" => {}, "run" => ["aaa", ""]}
|
107
124
|
))
|
108
125
|
expect(@config.warnings).to eq([])
|
109
126
|
expect(@config.errors).to eq([
|
110
|
-
"expected as_root[1] to be a string but got a Time",
|
111
|
-
"expected
|
127
|
+
"expected as_root.run[1] to be a string but got a Time",
|
128
|
+
"expected env to be a hash or array of keys or just a string but got a Time",
|
112
129
|
"expected links to be a expected hash to either declare the name or image but got a Hash",
|
113
130
|
])
|
114
131
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cide
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- zimbatm
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-04-
|
11
|
+
date: 2015-04-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.19
|
19
|
+
version: '0.19'
|
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.19
|
26
|
+
version: '0.19'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: virtus
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 1.0
|
33
|
+
version: '1.0'
|
34
34
|
type: :runtime
|
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: 1.0
|
40
|
+
version: '1.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -128,7 +128,6 @@ files:
|
|
128
128
|
- lib/cide/default_cide.yml
|
129
129
|
- lib/cide/docker.rb
|
130
130
|
- lib/cide/dockerfile_template.erb
|
131
|
-
- lib/cide/ssh_config
|
132
131
|
- spec/build_config_loader_spec.rb
|
133
132
|
- spec/spec_helper.rb
|
134
133
|
homepage: https://github.com/zimbatm/cide
|
data/lib/cide/ssh_config
DELETED