boxing 0.3.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bc45fc502d0e92045969b463a8371bfd70c0375903be656554d0b0523a4e54db
4
- data.tar.gz: 2f65fa15db1b98e7f2c8b58c592fdef26feb484408d1bdc75329f882b0561f6c
3
+ metadata.gz: cd1ab96ae737b37be480b3d7d862a5925b951062f7ccae22eb200d26e55f3a14
4
+ data.tar.gz: 8cd2271e0cb3fc6736c2440f978bdee63b0ba43c90a57596f9064f5b576788ae
5
5
  SHA512:
6
- metadata.gz: b3d12460d64bd448880826172ea91393f58ea1b2e44178ae343da1ca2023909a45b2ff1d3c7afc5efcb7b8f0657c8f99d2490d633638cfef45ae2f28ecb176c5
7
- data.tar.gz: 0c8ba08ef084fe5881e8cb90b54ff1d9486abe2de905d21103346b4e445962dbe488c714aac8fe8d599319036d795fd0ac4cef9e9db83680b331e8106fe4e721
6
+ metadata.gz: 0c4c43055ed9973e21b4e1660fff4bc5f6cd870f08f82339a0ea88be4edde2914c2e37086a5bf92a48e493c12fb2ba20c68bb28c936fcd2e3f77a6fe5e5edf29
7
+ data.tar.gz: 25dd924fc89a7aa20361acbcdc2c52b0e320c007308ac1a79a227df9938c2b575f7ee468a0dac1dd5cda8d17a820ea0c6e2fcb18de3ad7e7c15c5fa8746205cd
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- boxing (0.3.1)
4
+ boxing (0.6.0)
5
5
  bundler (~> 2.0)
6
6
  thor (~> 1.0)
7
7
 
data/README.md CHANGED
@@ -78,21 +78,90 @@ bundle exec boxing update
78
78
 
79
79
  > If the generated `Dockerfile` is not satisfy, please try to update it.
80
80
 
81
+ ## Configuration
82
+
83
+ If `config/boxing.rb` is found, it will be loaded and change the generated `Dockerfile` and `.dockerignore`
84
+
85
+ ### Source Code Root
86
+
87
+ ```ruby
88
+ Boxing.config do |c|
89
+ c.root = '/var/www'
90
+ end
91
+ ```
92
+
93
+ ### Ignore Files
94
+
95
+ ```ruby
96
+ Boxing.config do |c|
97
+ c.ignores = %w[
98
+ vendor/gems
99
+ ]
100
+ end
101
+ ```
102
+
103
+ ### Extra Packages
104
+
105
+ ```ruby
106
+ Boxing.config do |c|
107
+ c.build_packages = %w[nodejs]
108
+ c.runtime_packages = %w[git]
109
+ end
110
+ ```
111
+
112
+ ### Assets Precompile
113
+
114
+ This feature is disabled by default and suggest to use CI to build it.
115
+
116
+ ```ruby
117
+ Boxing.config do |c|
118
+ c.assets_precompile = true
119
+ # If not given the `node -v` will be execute
120
+ c.node_version = '14.18'
121
+ end
122
+ ```
123
+
124
+ ### Health Check
125
+
126
+ ```ruby
127
+ Boxing.config do |c|
128
+ c.health_check = true
129
+ c.health_check_path = '/api/status.json'
130
+ end
131
+ ```
132
+
133
+ > If `liveness` gem is installed, the health check will enabled by default with `/status` path.
134
+
81
135
  ## Roadmap
82
136
 
83
137
  * [x] `Dockerfile` generator
84
- * [x] `.gitignore` generator
138
+ * [x] `.dockerignore` generator
85
139
  * [x] Common ignore files
86
- * [ ] Customizable ignore files
87
- * [ ] Customize config file `config/boxing.rb`
88
- * [ ] Entrypoint Detection
89
- * [x] Openbox (Suggested)
140
+ * [x] Customizable ignore files
141
+ * [ ] Docker Compose generator
142
+ * [ ] Production Version
143
+ * [x] Development Version
144
+ * [x] Allow run Assets Precompile in Container
145
+ * [ ] Disable `RAILS_SERVE_STATIC_FILES` by default
146
+ * [x] Customize config file `config/boxing.rb`
147
+ * [x] Customize `APP_ROOT`
148
+ * [ ] Extra packages
149
+ * [ ] DSL to customize `Dockerfile`
150
+ * [ ] Build Stage
151
+ * [ ] Entrypoint
152
+ * [ ] Command
153
+ * [x] Expose Port
154
+ * [x] Health Check
155
+ * [x] [Liveness](https://github.com/elct9620/openbox) gem detection
156
+ * [x] Add `curl` for web application
157
+ * [x] Entrypoint Detection
158
+ * [x] [Openbox](https://github.com/elct9620/openbox) (Suggested)
90
159
  * [x] Ruby on Rails
91
- * [ ] Rack
92
- * [ ] Ruby
160
+ * [x] Rack (Default)
93
161
  * [ ] Package Database
94
162
  * [x] Built-in (Move to standalone repoistory in future)
95
163
  * [x] Standalone Repoistory
164
+ * [x] Support gems from `git` repoistory
96
165
  * [x] Customize Source
97
166
  * [ ] Base Image
98
167
  * [x] Alpine
@@ -12,7 +12,9 @@ module Boxing
12
12
  true
13
13
  end
14
14
 
15
+ require_relative 'commands/base'
15
16
  require_relative 'commands/generate'
17
+ require_relative 'commands/compose'
16
18
  require_relative 'commands/update'
17
19
  end
18
20
  end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Boxing
4
+ # :nodoc:
5
+ module Commands
6
+ # The Base Command
7
+ #
8
+ # @since 0.5.0
9
+ class Base < Thor::Group
10
+ include Thor::Actions
11
+
12
+ # :nodoc:
13
+ def self.source_root
14
+ Pathname.new(File.dirname(__FILE__)).join('../../..')
15
+ end
16
+
17
+ # Prepare command environment
18
+ #
19
+ # @since 0.5.0
20
+ def prepare
21
+ config = Bundler.root.join('config/boxing.rb')
22
+ return unless config.exist?
23
+
24
+ load config
25
+ end
26
+
27
+ private
28
+
29
+ # :nodoc:
30
+ def context
31
+ @context = Context.new(
32
+ Boxing.config,
33
+ Database.new,
34
+ Boxing.dependencies
35
+ )
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Boxing
4
+ # :nodoc:
5
+ module Commands
6
+ # The Docker Compose Generator
7
+ #
8
+ # @since 0.1.0
9
+ class Compose < Base
10
+ # Create Dockerfile
11
+ #
12
+ # @since 0.1.0
13
+ def execute
14
+ Database.download! unless Database.exist?
15
+
16
+ # TODO: Allow set image registry
17
+ # TODO: Allow set application name
18
+ template('templates/docker-compose.yml.tt', 'docker-compose.yml', context: context.to_binding)
19
+ end
20
+ end
21
+
22
+ Boxing::Command.register(Compose, 'compose', 'compose', 'Generate docker-compose.yml')
23
+ end
24
+ end
@@ -9,14 +9,7 @@ module Boxing
9
9
  # The Dockerfle Generator
10
10
  #
11
11
  # @since 0.1.0
12
- class Generate < Thor::Group
13
- include Thor::Actions
14
-
15
- # :nodoc:
16
- def self.source_root
17
- Pathname.new(File.dirname(__FILE__)).join('../../..')
18
- end
19
-
12
+ class Generate < Base
20
13
  # Create Dockerfile
21
14
  #
22
15
  # @since 0.1.0
@@ -26,15 +19,6 @@ module Boxing
26
19
  template('templates/Dockerfile.tt', 'Dockerfile', context: context.to_binding)
27
20
  template('templates/dockerignore.tt', '.dockerignore', context: context.to_binding)
28
21
  end
29
-
30
- private
31
-
32
- def context
33
- @context = Context.new(
34
- Database.new,
35
- Boxing.dependencies
36
- )
37
- end
38
22
  end
39
23
 
40
24
  Boxing::Command.register(Generate, 'generate', 'generate', 'Generate Dockerfile')
@@ -6,7 +6,7 @@ module Boxing
6
6
  # The Database Updater
7
7
  #
8
8
  # @since 0.3.0
9
- class Update < Thor::Group
9
+ class Update < Base
10
10
  # Update Database
11
11
  #
12
12
  # @since 0.3.0
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Boxing
4
+ # The config of boxing
5
+ #
6
+ # @since 0.5.0
7
+ class Config
8
+ # @!attribute root
9
+ # @return [String] the application root
10
+ #
11
+ # @since 0.5.0
12
+ attr_accessor :root, :name, :registry, :ignores, :port,
13
+ :health_check, :health_check_path,
14
+ :assets_precompile, :node_version,
15
+ :build_packages, :runtime_packages
16
+
17
+ # @since 0.5.0
18
+ def initialize(&block)
19
+ @name = 'myapp'
20
+ @root = '/srv/app'
21
+ @port = 9292
22
+ @health_path = '/status'
23
+ @assets_precompile = false
24
+
25
+ instance_exec(self, &block) if defined?(yield)
26
+ end
27
+ end
28
+ end
@@ -5,13 +5,20 @@ module Boxing
5
5
  #
6
6
  # @since 0.1.0
7
7
  class Context
8
+ # @since 0.5.0
9
+ attr_reader :config
10
+
11
+ # @param config [Boxing::Config]
8
12
  # @param database [Boxing::Database]
9
13
  # @param dependencies [Array<Bundler::Dependency>]
10
14
  #
11
15
  # @since 0.1.0
12
- def initialize(database, dependencies = [])
16
+ def initialize(config, database, dependencies = [])
17
+ @config = config
13
18
  @database = database
14
19
  @dependencies = dependencies
20
+
21
+ @config.port = 3000 if has?('rails')
15
22
  end
16
23
 
17
24
  # Return required packages
@@ -20,11 +27,14 @@ module Boxing
20
27
  #
21
28
  # @since 0.1.0
22
29
  def packages
23
- @packages ||= Set.new(
24
- @dependencies
25
- .map(&:name)
26
- .flat_map { |name| @database.package_for(name).to_a }
27
- )
30
+ @packages ||=
31
+ Set
32
+ .new(default_packages + extra_packages)
33
+ .merge(
34
+ @dependencies
35
+ .map(&:name)
36
+ .flat_map { |name| @database.package_for(name).to_a }
37
+ )
28
38
  end
29
39
 
30
40
  # Check rubygems exists
@@ -38,6 +48,54 @@ module Boxing
38
48
  @dependencies.any? { |dep| names.include?(dep.name) }
39
49
  end
40
50
 
51
+ # Does any gem from git
52
+ #
53
+ # @return [TrueClass|FalseClass]
54
+ #
55
+ # @since 0.4.0
56
+ def git?
57
+ @dependencies.any?(&:git)
58
+ end
59
+
60
+ # Default packages
61
+ #
62
+ # @return [Array<Boxing::Package>]
63
+ #
64
+ # @since 0.4.0
65
+ def default_packages
66
+ [
67
+ Package.new('build-base', mode: Package::BUILD)
68
+ ]
69
+ .push(git? ? Package.new('git', mode: Package::BUILD) : nil)
70
+ .push(has?('liveness') ? Package.new('curl', mode: Package::RUNTIME) : nil)
71
+ .compact
72
+ end
73
+
74
+ # Extra Packages
75
+ #
76
+ # @return [Array<Boxing::Package>]
77
+ #
78
+ # @since 0.6.0
79
+ def extra_packages
80
+ Array[config.build_packages, config.runtime_packages].compact.flat_map do |name|
81
+ mode = 0
82
+ mode |= Package::BUILD if config.build_packages&.include?(name)
83
+ mode |= Package::RUNTIME if config.runtime_packages&.include?(name)
84
+ Package.new(name, mode: mode)
85
+ end
86
+ end
87
+
88
+ # Return node.js version
89
+ #
90
+ # @return [String]
91
+ #
92
+ # @since 0.6.0
93
+ def node_version
94
+ return config.node_version if config.node_version
95
+
96
+ `node -v`.gsub(/^v/, '')
97
+ end
98
+
41
99
  # Convert to binding
42
100
  #
43
101
  # @return [Binding]
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Boxing
4
- VERSION = '0.3.1'
4
+ VERSION = '0.6.0'
5
5
  end
data/lib/boxing.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'boxing/version'
4
+ require_relative 'boxing/config'
4
5
  require_relative 'boxing/package'
5
6
  require_relative 'boxing/database'
6
7
  require_relative 'boxing/context'
@@ -10,6 +11,8 @@ require_relative 'boxing/command'
10
11
  #
11
12
  # @since 0.1.0
12
13
  module Boxing
14
+ LOCK = Mutex.new
15
+
13
16
  module_function
14
17
 
15
18
  # @return [Bundler::Dependency]
@@ -21,4 +24,19 @@ module Boxing
21
24
  .current_dependencies
22
25
  .select { |dep| (dep.groups & groups).any? }
23
26
  end
27
+
28
+ # @return [Boxing::Config]
29
+ #
30
+ # @since 0.5.0
31
+ def config(&block)
32
+ return @config if @config
33
+
34
+ LOCK.synchronize do
35
+ return @config if @config
36
+
37
+ @config = Config.new(&block)
38
+ end
39
+
40
+ @config
41
+ end
24
42
  end
@@ -1,10 +1,11 @@
1
- ARG APP_ROOT=/src/app
1
+ ARG APP_ROOT=<%= config.root %>
2
2
  ARG RUBY_VERSION=<%= RUBY_VERSION %>
3
+ <%- if config.assets_precompile -%>ARG NODE_VERSION=<%= node_version %><%- end -%>
3
4
 
4
5
  FROM ruby:${RUBY_VERSION}-alpine AS gem
5
6
  ARG APP_ROOT
6
7
 
7
- RUN apk add --no-cache build-base <%= packages.select(&:build?).join(' ') %>
8
+ RUN apk add --no-cache <%= packages.select(&:build?).join(' ') %>
8
9
 
9
10
  RUN mkdir -p ${APP_ROOT}
10
11
  COPY Gemfile Gemfile.lock ${APP_ROOT}/
@@ -23,15 +24,35 @@ RUN gem install bundler:<%= Bundler::VERSION %> \
23
24
  && find /usr/local/bundle -type f -name '*.o' -delete \
24
25
  && rm -rf /usr/local/bundle/cache/*.gem
25
26
 
27
+ <%- if config.assets_precompile -%>
28
+ FROM node:${NODE_VERSION}-alpine as node
29
+ FROM ruby:${RUBY_VERSION}-alpine as assets
30
+ ARG APP_ROOT
31
+
32
+ <%- if packages.select(&:runtime?).any? -%>
33
+ RUN apk add --no-cache <%= packages.select(&:runtime?).join(' ') %> yarn
34
+
35
+ <%- end -%>
36
+ COPY --from=node /usr/local/bin/node /usr/local/bin/node
37
+
38
+ COPY --from=gem /usr/local/bundle/config /usr/local/bundle/config
39
+ COPY --from=gem /usr/local/bundle /usr/local/bundle
40
+ COPY --from=gem /${APP_ROOT}/vendor/bundle /${APP_ROOT}/vendor/bundle
41
+
42
+ RUN mkdir -p ${APP_ROOT}
43
+ COPY . ${APP_ROOT}
44
+
45
+ ENV RAILS_ENV production
46
+ WORKDIR ${APP_ROOT}
47
+ RUN bundle exec rake assets:precompile
48
+
49
+ <%- end -%>
26
50
  FROM ruby:${RUBY_VERSION}-alpine
27
51
  ARG APP_ROOT
28
52
 
29
53
  <%- if packages.select(&:runtime?).any? -%>
30
54
  RUN apk add --no-cache <%= packages.select(&:runtime?).join(' ') %>
31
55
 
32
- ARG REVISION
33
- ENV REVISION $REVISION
34
-
35
56
  <%- end -%>
36
57
  COPY --from=gem /usr/local/bundle/config /usr/local/bundle/config
37
58
  COPY --from=gem /usr/local/bundle /usr/local/bundle
@@ -42,10 +63,15 @@ RUN mkdir -p ${APP_ROOT}
42
63
  <%- if has?('rails') -%>
43
64
  ENV RAILS_ENV=production
44
65
  ENV RAILS_LOG_TO_STDOUT=true
66
+ ENV RAILS_SERVE_STATIC_FILES=yes
45
67
  <%- end -%>
46
68
  ENV APP_ROOT=$APP_ROOT
47
69
 
48
70
  COPY . ${APP_ROOT}
71
+ COPY --from=assets /${APP_ROOT}/public /${APP_ROOT}/public
72
+
73
+ ARG REVISION
74
+ ENV REVISION $REVISION
49
75
  RUN echo $REVISION > ${SERVER_ROOT}/REVISION
50
76
 
51
77
  # Apply Execute Permission
@@ -60,7 +86,10 @@ RUN adduser -h ${APP_ROOT} -D -s /bin/nologin ruby ruby && \
60
86
  USER ruby
61
87
  WORKDIR ${APP_ROOT}
62
88
 
63
- EXPOSE <%= has?('rails') ? '3000' : '9292' %>
89
+ EXPOSE <%= config.port %>
90
+ <%- if has?('liveness') || config.health_check -%>
91
+ HEALTHCHECK CMD curl -f http://localhost:<%= config.port %><%= config.health_check_path %> || exit 1
92
+ <%- end -%>
64
93
  <%- if has?('openbox') -%>
65
94
  ENTRYPOINT ["bin/openbox"]
66
95
  CMD ["server"]
@@ -0,0 +1,47 @@
1
+ version: '3.4'
2
+
3
+ volumes:
4
+ database:
5
+ driver: local
6
+
7
+ services:
8
+ <%- if has?('pg') -%>
9
+ postgres:
10
+ image: postgres:13.1
11
+ volumes:
12
+ - database:/var/lib/postgresql/data
13
+ environment:
14
+ - POSTGRES_DB=<%= config.name %>
15
+ - POSTGRES_USER=<%= config.name %>
16
+ - POSTGRES_PASSWORD=<%= config.name %>
17
+ <%- end -%>
18
+ <%- if has?('mysql2') -%>
19
+ mysql:
20
+ image: mysql:8.0
21
+ volumes:
22
+ - database:/var/lib/mysql
23
+ environment:
24
+ - MYSQL_USER=<%= config.name %>
25
+ - MYSQL_PASSWORD=<%= config.name %>
26
+ - MYSQL_DATABASE=<%= config.name %>
27
+ - MYSQL_ROOT_PASSWORD=<%= config.name %>
28
+ <%- end -%>
29
+ application:
30
+ <%- if config.registry.nil? -%>
31
+ build:
32
+ context: .
33
+ <%- else -%>
34
+ image: <%= config.registry %>
35
+ <%- end -%>
36
+ environment:
37
+ - RAILS_MASTER_KEY
38
+ - AUTO_MIGRATION=yes
39
+ <%- if has?('pg') -%>
40
+ - DATABASE_URL=postgres://<%= config.name %>:<%= config.name %>@postgres/<%= config.name %>
41
+ <%- elsif has?('mysql2') %>
42
+ - DATABASE_URL=mysql2://<%= config.name %>:<%= config.name %>@mysql/<%= config.name %>
43
+ <%- end -%>
44
+ ports:
45
+ - "3000:3000"
46
+ depends_on:
47
+ - postgres
@@ -8,8 +8,10 @@ docker-compose*.yml
8
8
  # CI/CD
9
9
  .github/
10
10
  .cache/
11
+ .circleci/
11
12
  coverage/
12
13
  spec/
14
+ test/
13
15
  features/
14
16
  .gitlab-ci.yml
15
17
  .travis.yml
@@ -28,6 +30,17 @@ rspec.xml
28
30
  log/*
29
31
  tmp/*
30
32
 
33
+ # Frontend
34
+ node_modules/
35
+
31
36
  # Licensed
32
37
  .licensed.yml
33
38
  .licenses
39
+
40
+ # Boxing
41
+ config/boxing.rb
42
+ <% if config.ignores -%>
43
+
44
+ # Customize Ignores
45
+ <%= Array[config.ignores].join("\n") %>
46
+ <%- end -%>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: boxing
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - 蒼時弦也
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-12-29 00:00:00.000000000 Z
11
+ date: 2022-02-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -60,13 +60,17 @@ files:
60
60
  - exe/boxing
61
61
  - lib/boxing.rb
62
62
  - lib/boxing/command.rb
63
+ - lib/boxing/commands/base.rb
64
+ - lib/boxing/commands/compose.rb
63
65
  - lib/boxing/commands/generate.rb
64
66
  - lib/boxing/commands/update.rb
67
+ - lib/boxing/config.rb
65
68
  - lib/boxing/context.rb
66
69
  - lib/boxing/database.rb
67
70
  - lib/boxing/package.rb
68
71
  - lib/boxing/version.rb
69
72
  - templates/Dockerfile.tt
73
+ - templates/docker-compose.yml.tt
70
74
  - templates/dockerignore.tt
71
75
  homepage: https://github.com/elct9620/boxing
72
76
  licenses: []