construi 0.35.2 → 0.36.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.
@@ -45,29 +45,37 @@ module Construi
45
45
  other.is_a? Container and id == other.id
46
46
  end
47
47
 
48
- def self.create(image, cmd, env)
48
+ def self.create(image, cmd, options = {})
49
+ env = options[:env] || []
50
+ privileged = options[:privileged] || false
51
+
52
+ host_config = {
53
+ 'Binds' => ["#{Dir.pwd}:/var/workspace"],
54
+ 'Privileged' => privileged
55
+ }
56
+
49
57
  wrap Docker::Container.create(
50
58
  'Cmd' => cmd.split,
51
59
  'Image' => image.id,
52
60
  'Env' => env.to_json,
53
61
  'Tty' => false,
54
62
  'WorkingDir' => '/var/workspace',
55
- 'HostConfig' => { 'Binds' => ["#{Dir.pwd}:/var/workspace"] })
63
+ 'HostConfig' => host_config)
56
64
  end
57
65
 
58
66
  def self.wrap(container)
59
67
  new container
60
68
  end
61
69
 
62
- def self.use(image, cmd, env)
63
- container = create(image, cmd, env)
70
+ def self.use(image, cmd, options = {})
71
+ container = create image, cmd, options
64
72
  yield container
65
73
  ensure
66
74
  container.delete unless container.nil?
67
75
  end
68
76
 
69
- def self.run(image, cmd, env)
70
- use(image, cmd, env, &:run)
77
+ def self.run(image, cmd, options = {})
78
+ use image, cmd, options, &:run
71
79
  end
72
80
 
73
81
  class Error < StandardError
@@ -56,8 +56,8 @@ module Construi
56
56
  run chmod
57
57
  end
58
58
 
59
- def run(cmd, env = [])
60
- Container.run(self, cmd, env)
59
+ def run(cmd, options = {})
60
+ Container.run self, cmd, options
61
61
  end
62
62
 
63
63
  def ==(other)
@@ -116,7 +116,7 @@ module Construi
116
116
  end
117
117
 
118
118
  def run(cmd, env = [])
119
- map { |i| i.run(cmd, env) }
119
+ map { |i| i.run cmd, env: env }
120
120
  end
121
121
 
122
122
  def map
@@ -9,7 +9,7 @@ require 'colorize'
9
9
  require 'docker'
10
10
 
11
11
  module Construi
12
-
12
+ # Runs Construi
13
13
  class Runner
14
14
  def initialize(config)
15
15
  @config = config
@@ -24,7 +24,12 @@ module Construi
24
24
  Excon.defaults[:ssl_verify_peer] = false
25
25
 
26
26
  Docker.validate_version!
27
- Docker.options[:read_timeout] = 60
27
+
28
+ # Don't time out. We can't differentiate between a long running
29
+ # task and a time out.
30
+ Docker.options[:read_timeout] = nil
31
+
32
+ # Low chunk size as we wish to receive streaming output ASAP
28
33
  Docker.options[:chunk_size] = 8
29
34
  end
30
35
 
@@ -35,9 +40,7 @@ module Construi
35
40
 
36
41
  puts "Current directory: #{Dir.pwd}"
37
42
 
38
- targets.map {|t| Target.new t, @config.target(t) } .each(&:run)
43
+ targets.map { |t| Target.new t, @config.target(t) } .each(&:run)
39
44
  end
40
45
  end
41
-
42
46
  end
43
-
@@ -20,7 +20,7 @@ module Construi
20
20
  final_image = IntermediateImage.seed(initial_image).reduce(commands) do |image, command|
21
21
  puts
22
22
  puts " > #{command}".green
23
- image.run(command, @config.env)
23
+ image.run command, @config.options
24
24
  end
25
25
 
26
26
  final_image.delete
@@ -1,3 +1,3 @@
1
1
  module Construi
2
- VERSION = "0.35.2"
2
+ VERSION = "0.36.0"
3
3
  end
data/site/_config.yml ADDED
@@ -0,0 +1,18 @@
1
+ # Site settings
2
+ title: Construi
3
+ email: levi.stephen@gmail.com
4
+ description: > # this means to ignore newlines until "baseurl:"
5
+ Write an awesome description for your new site here. You can edit this
6
+ line in _config.yml. It will appear in your document head meta (for
7
+ Google search results) and in your feed.xml site description.
8
+ baseurl: "" # the subpath of your site, e.g. /blog/
9
+ url: "http://yourdomain.com" # the base hostname & protocol for your site
10
+ twitter_username: jekyllrb
11
+ github_username: jekyll
12
+ github:
13
+ project: https://github.com/lstephen/construi
14
+ issues: https://github.com/lstephen/construi/issues
15
+
16
+
17
+
18
+ markdown: redcarpet
@@ -0,0 +1,79 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1">
7
+ <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
8
+ <title>{{ site.title }}</title>
9
+
10
+ <!-- Bootstrap -->
11
+ <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
12
+
13
+ <link href="css/main.css" rel="stylesheet"/>
14
+
15
+ <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
16
+ <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
17
+ <!--[if lt IE 9]>
18
+ <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
19
+ <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
20
+ <![endif]-->
21
+ </head>
22
+ <body>
23
+ <nav class="navbar navbar-inverse navbar-fixed-top">
24
+ <div class="container">
25
+ <div class="navbar-header">
26
+ <a class="navbar-brand" href="./">{{ site.title }}</a>
27
+ </div>
28
+ <div id="navbar" class="collapse navbar-collapse">
29
+ <ul class="nav navbar-nav pull-right">
30
+ <li><a href="{{ site.github.project }}">GitHub project</a></li>
31
+ <li class="dropdown">
32
+ <a href="#" class="dropdown-toggle" data-toggle="dropdown">Contribute <b class="caret"></b></a>
33
+ <ul class="dropdown-menu">
34
+ <li><a href="{{ site.github.issues }}">Issues</a></li>
35
+ <li><a href="{{ site.github.project }}">Fork on GitHub</a></li>
36
+ </ul>
37
+ </li>
38
+ <li class="dropdown">
39
+ <a href="#" class="dropdown-toggle" data-toggle="dropdown">Reports <b class="caret"></b></a>
40
+ <ul class="dropdown-menu">
41
+ <li><a href="yard/index.html">Yard Doc</a></li>
42
+ <li><a href="coverage/index.html">SimpleCov</a></li>
43
+ <li><a href="rubocop.html">Rubocop</a></li>
44
+ </ul>
45
+ </li>
46
+ </ul>
47
+ </div><!--/.nav-collapse -->
48
+ </div>
49
+ </nav>
50
+
51
+ <div class="main-body">
52
+ <div class="container">
53
+ {{ content }}
54
+ </div>
55
+ </div>
56
+
57
+ <footer class="well">
58
+ <div class="container">
59
+ <div class="row">
60
+ <div class="col-md-12">
61
+ <a href="https://rubygems.org/gems/construi">
62
+ <img src="https://img.shields.io/gem/v/formatador.svg?style=plastic"/>
63
+ </a>
64
+ <a href='http://jenkins.mylonelybear.org/job/construi-develop/'>
65
+ <img src='http://jenkins.mylonelybear.org/buildStatus/icon?job=construi-develop&style=plastic'>
66
+ </a>
67
+ <p class="pull-right"><a href="#">Back to top</a></p>
68
+ </div>
69
+ </div>
70
+ </div>
71
+ </footer>
72
+
73
+ <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
74
+ <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
75
+ <!-- Include all compiled plugins (below), or include individual files as needed -->
76
+ <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
77
+ </body>
78
+ </html>
79
+
data/site/css/main.css ADDED
@@ -0,0 +1,11 @@
1
+
2
+ @media (min-width: 980px) {
3
+ body {
4
+ padding-top: 60px;
5
+ }
6
+ }
7
+
8
+ .main-body {
9
+ padding-bottom: 30px;
10
+ }
11
+
data/site/index.md ADDED
@@ -0,0 +1,161 @@
1
+ ---
2
+ layout: default
3
+ ---
4
+
5
+ # Construi
6
+
7
+ Construi allows you to use [Docker](http://www.docker.com) containers as your build environment.
8
+ This allows a consistent and recreatable build environment on any machine running Construi
9
+ and Docker.
10
+
11
+ This is useful for ensuring consistency between development machines.
12
+ It is also useful in a CI environment where you may need to build projects from many different
13
+ languages and/or versions (e.g., Java 6, Java 8, Ruby).
14
+
15
+ ## Installation
16
+
17
+ Construi requires [Ruby](http://www.ruby-lang.org) version 1.9 or higher.
18
+ It can be installed as a Gem.
19
+
20
+ ```
21
+ > gem install construi
22
+ ```
23
+
24
+ ## Running
25
+
26
+ Construi requires that a `construi.yml` file be present in the root directory of your project.
27
+ Targets can then be run by specifying them on the command line. For example:
28
+
29
+ ```
30
+ > construi build
31
+ > construi build install
32
+ ```
33
+
34
+ Construi will create a Docker container with the project directory as a volume.
35
+ It will then run the commands configured for the given targets.
36
+
37
+ ## The Construi File
38
+
39
+ As a minimal `construi.yml` requires an image and a target to be configured.
40
+ For example a simple configuration for a Java 8 project built with Maven could be:
41
+
42
+ ```
43
+ image: maven:3-jdk-8
44
+
45
+ targets:
46
+ install: mvn install
47
+ ```
48
+
49
+ Construi is built using itself, so it's
50
+ [`construi.yml`](https://github.com/lstephen/construi/blob/develop/construi.yml)
51
+ can be used as an example.
52
+
53
+ ### Image
54
+
55
+ Specifies an image to be pulled that will be used as the build environment.
56
+ It can also be given on a per target basis.
57
+
58
+ ```
59
+ image: maven:3-jdk-7
60
+
61
+ targets:
62
+ install: mvn install
63
+
64
+ test-java-8:
65
+ image: maven:3-jdk-8
66
+ run: mvn verify
67
+ ```
68
+
69
+ ### Build
70
+
71
+ Specifies a directory containing a `Dockerfile`.
72
+ Construi will build a Docker container based on that `Dockerfile` and use it as the build
73
+ environment.
74
+ Can be used as an alternative to providing an image.
75
+ Can also be given on a per target basis.
76
+
77
+ ```
78
+ build: etc/build_environment
79
+
80
+ targets:
81
+ build:
82
+ - mvn install
83
+ - /usr/local/bin/custom_installed_command.sh
84
+ ```
85
+
86
+
87
+ ### Privileged
88
+
89
+ An image can be marked as a privileged image.
90
+ This is equivalent to passing `--privileged` to the Docker command line.
91
+ Useful when requiring docker to be part of the build process.
92
+
93
+ ```
94
+ build: lstephen/docker
95
+ privileged: true
96
+
97
+ targets:
98
+ build: docker build latest/
99
+ ```
100
+
101
+ ### Environment
102
+
103
+ Declares environment variables that will be passed through or set in the build environment.
104
+ If no value is provided then the value from the host environment will be used.
105
+ In this example `NEXUS_SERVER_URL` will be set as provided, while `NEXUS_USERNAME` and
106
+ `NEXUS_PASSWORD` will be retrieved from the host.
107
+
108
+ ```
109
+ image: maven:3-jdk-7
110
+
111
+ environment:
112
+ - NEXUS_SERVER_URL=http://nexus.example.com
113
+ - NEXUS_USERNAME
114
+ - NEXUS_PASSWORD
115
+ targets:
116
+ build: mvn install
117
+ ```
118
+
119
+ ### Files
120
+
121
+ Declares files to be copied into the build environment before the build is run.
122
+ Also allows setting of permissions.
123
+ Can be used on a per target basis.
124
+
125
+ ```
126
+ image: maven:3-jdk-7
127
+
128
+ files:
129
+ - etc/maven-settings.xml:/home/root/.m2/settings.xml
130
+
131
+ targets:
132
+ deploy:
133
+ files:
134
+ - $GIT_SSH_KEY:/home/root/.ssh/id_rsa:0600
135
+ run: scripts/construi/deploy.sh
136
+ ```
137
+
138
+ ### Targets
139
+
140
+ Any number of targets can be specified.
141
+ Each must specify at least one command.
142
+ If additional configuration is required for a target then the commands should be provided
143
+ under the `run` key.
144
+ If more than one command is required then a YAML list should be used.
145
+
146
+ ```
147
+ image: maven:3-jdk-7
148
+
149
+ targets:
150
+ build: mvn install
151
+
152
+ test-java-8:
153
+ image: maven:3-jdk-8
154
+ run: mvn verify
155
+
156
+ deploy:
157
+ - mvn deploy
158
+ - curl http://ci.example.com/deploy/trigger
159
+ ```
160
+
161
+
@@ -281,7 +281,49 @@ RSpec.describe Construi::Config do
281
281
  .to have_attributes :host => host, :container => container, :permissions => permissions
282
282
  end
283
283
  end
284
+ end
285
+
286
+ describe '#privileged?' do
287
+ subject { config.target('build').privileged? }
288
+
289
+ context 'when privileged absent' do
290
+ let(:config_content) do
291
+ <<-YAML
292
+ targets:
293
+ build:
294
+ run: cmd1
295
+ YAML
296
+ end
297
+
298
+ it { is_expected.to eq(false) }
299
+ end
284
300
 
301
+ context 'when present' do
302
+ let(:config_content) do
303
+ <<-YAML
304
+ privileged: true
305
+ targets:
306
+ build:
307
+ run: cmd1
308
+ YAML
309
+ end
310
+
311
+ it { is_expected.to eq(true) }
312
+ end
313
+
314
+ context 'when overridden on target' do
315
+ let(:config_content) do
316
+ <<-YAML
317
+ privileged: true
318
+ targets:
319
+ build:
320
+ run: cmd1
321
+ privileged: false
322
+ YAML
323
+ end
324
+
325
+ it { is_expected.to eq(false) }
326
+ end
285
327
  end
286
328
  end
287
329
 
@@ -87,11 +87,12 @@ RSpec.describe Construi::Container do
87
87
  let(:cmd) { 'cmd1 p1 p2' }
88
88
  let(:env) { ['ENV1=VAL1', 'ENV2=VAL2'] }
89
89
  let(:pwd) { '/project/dir' }
90
+ let(:privileged) { true }
90
91
 
91
92
  before { allow(docker_container_class).to receive(:create).and_return docker_container }
92
93
  before { allow(Dir).to receive(:pwd).and_return(pwd) }
93
94
 
94
- subject! { Construi::Container::create(image, cmd, env) }
95
+ subject! { Construi::Container::create(image, cmd, env: env, privileged: privileged) }
95
96
 
96
97
  it do
97
98
  expect(docker_container_class).to have_received(:create).with( {
@@ -100,8 +101,11 @@ RSpec.describe Construi::Container do
100
101
  'Env' => env.to_json,
101
102
  'Tty' => false,
102
103
  'WorkingDir' => '/var/workspace',
103
- 'HostConfig' => { 'Binds' => ["#{pwd}:/var/workspace"] }
104
- } )
104
+ 'HostConfig' => {
105
+ 'Binds' => ["#{pwd}:/var/workspace"],
106
+ 'Privileged' => true
107
+ }
108
+ } )
105
109
  end
106
110
  it { is_expected.to eq(Construi::Container.wrap docker_container) }
107
111
  end
@@ -113,7 +117,7 @@ RSpec.describe Construi::Container do
113
117
  before { allow(docker_container).to receive(:wait).and_return({'StatusCode' => 0}) }
114
118
  before { allow(docker_container).to receive(:commit).and_return image }
115
119
 
116
- subject! { Construi::Container.run(image, cmd, []) }
120
+ subject! { Construi::Container.run(image, cmd) }
117
121
 
118
122
  it do
119
123
  expect(docker_container_class).to have_received(:create).with(