vps 0.2.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.
@@ -0,0 +1,18 @@
1
+ ---
2
+ description:
3
+ Install software on the server
4
+ usage:
5
+ install HOST [TOOL]
6
+ arguments:
7
+ - host
8
+ - tool
9
+ tasks:
10
+ - task: ensure
11
+ argument: tool
12
+ fallbacks:
13
+ - description: Choose which deploy tool to install
14
+ task: select
15
+ question: Which deployment tool do you want to install?
16
+ options: << playbooks >>
17
+ - task: playbook
18
+ playbook: install/{{ tool }}
@@ -0,0 +1,35 @@
1
+ ---
2
+ source:
3
+ - https://docs.docker.com/install/linux/docker-ce/ubuntu/#install-using-the-repository
4
+ - https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-18-04
5
+ tasks:
6
+ - description: Updating apt package index
7
+ task: remote_execute
8
+ command: sudo apt-get update
9
+ - description: Installing packages which let apt use packages over HTTPS
10
+ task: remote_execute
11
+ command:
12
+ sudo apt-get install
13
+ apt-transport-https
14
+ ca-certificates
15
+ curl
16
+ gnupg-agent
17
+ software-properties-common
18
+ - description: Adding Docker’s official GPG key
19
+ task: remote_execute
20
+ command: curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
21
+ - description: Adding the Docker repository to APT sources
22
+ task: remote_execute
23
+ command: sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable"
24
+ - description: Updating apt package index
25
+ task: remote_execute
26
+ command: sudo apt-get update
27
+ - description: Installing Docker
28
+ task: remote_execute
29
+ command: sudo apt install -y docker-ce docker-compose
30
+ - description: Adding current user to the docker group
31
+ task: remote_execute
32
+ command: sudo usermod -aG docker ${USER}
33
+ - description: Checking docker state
34
+ task: remote_execute
35
+ command: sudo systemctl status docker
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler"
4
+ Bundler.require :default, :development
5
+
6
+ puts "Loading VPS development environment (#{VPS::VERSION})"
7
+ Pry.start
@@ -0,0 +1,69 @@
1
+ <%- upstreams.each do |upstream| %>
2
+
3
+ upstream <%= upstream[:name] %> {
4
+ server <%= upstream[:name] %>:<%= upstream[:port] %>;
5
+ }
6
+ <%- upstream[:domains].partition{|domain| domain.include?("http://")}.reject(&:empty?).each do |domains| %>
7
+ <%-
8
+ https = domains.first.include?("https://")
9
+ domains = domains.collect{|domain| domain.gsub(/https?:\/\//, "")}.join(" ")
10
+ domain = domains.split(" ")[0]
11
+ nginx = upstream[:nginx] || {}
12
+ proxy_pass = "http://#{ upstream[:name] }"
13
+ %>
14
+
15
+ server {
16
+ <%- unless domains.empty? %>
17
+ listen 80;
18
+ server_name <%= domains %>;
19
+ server_tokens off;
20
+
21
+ <%- end %>
22
+ <%- if nginx[:http] %>
23
+ <%= nginx[:http].gsub("PROXY_PASS", proxy_pass).indent(2) %>
24
+
25
+ <%- end %>
26
+ <%- if https %>
27
+ location /.well-known/acme-challenge/ {
28
+ root /var/www/certbot;
29
+ }
30
+
31
+ location / {
32
+ return 301 https://$host$request_uri;
33
+ }
34
+ }
35
+
36
+ server {
37
+ listen 443 ssl;
38
+ server_name <%= domains %>;
39
+ server_tokens off;
40
+
41
+ ssl_certificate /etc/letsencrypt/live/<%= domain %>/fullchain.pem;
42
+ ssl_certificate_key /etc/letsencrypt/live/<%= domain %>/privkey.pem;
43
+ include /etc/letsencrypt/options-ssl-nginx.conf;
44
+ ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
45
+
46
+ <%- end %>
47
+ <%- if nginx[:root] %>
48
+ root <%= nginx[:root] %>;
49
+ <%- end %>
50
+ <%- if nginx[:try_files] %>
51
+ try_files $uri @app;
52
+
53
+ <%- end %>
54
+ <%- if nginx[:https] %>
55
+ <%= nginx[:https].gsub("PROXY_PASS", proxy_pass).indent(2) %>
56
+
57
+ <%- end %>
58
+ location <%= nginx[:try_files] ? "@app" : "/" %> {
59
+ proxy_pass <%= proxy_pass %>;
60
+ proxy_set_header Host $http_host;
61
+ proxy_set_header X-Real-IP $remote_addr;
62
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
63
+ <%- if nginx[:proxy_redirect] %>
64
+ proxy_redirect <%= nginx[:proxy_redirect] %>;
65
+ <%- end %>
66
+ }
67
+ }
68
+ <%- end %>
69
+ <%- end %>
@@ -0,0 +1,58 @@
1
+ version: "3"
2
+ <% https = upstreams.any?{|upstream| upstream[:domains].any?{|domain| domain.include?("https://")}} %>
3
+ services:
4
+
5
+ nginx:
6
+ image: nginx:1.15-alpine
7
+ container_name: nginx
8
+ restart: unless-stopped
9
+ ports:
10
+ - 80:80
11
+ <%- if https %>
12
+ - 443:443
13
+ <%- end %>
14
+ depends_on:
15
+ <%- upstreams.each do |upstream| %>
16
+ - <%= upstream.name %>
17
+ <%- end %>
18
+ volumes:
19
+ - ./data/nginx:/etc/nginx/conf.d
20
+ <%- if https %>
21
+ - ./data/certbot/conf:/etc/letsencrypt
22
+ - ./data/certbot/www:/var/www/certbot
23
+ command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"
24
+
25
+ certbot:
26
+ image: certbot/certbot:v0.27.1
27
+ container_name: certbot
28
+ restart: unless-stopped
29
+ volumes:
30
+ - ./data/certbot/conf:/etc/letsencrypt
31
+ - ./data/certbot/www:/var/www/certbot
32
+ entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
33
+ <%- end %>
34
+ <%- services.to_h.each do |name, spec| %>
35
+
36
+ <%= name %>:
37
+ <%= OpenStruct.to_hash(spec).to_yaml.sub(/^.*?\n/, "").indent(4) %>
38
+ <%- end %>
39
+ <%- upstreams.each do |upstream| %>
40
+
41
+ <%= upstream.name %>:
42
+ image: <%= upstream.name %>
43
+ restart: always
44
+ <%- unless upstream[:compose].inspect.match(/\bports\b/) %>
45
+ ports:
46
+ - <%= upstream.port %>
47
+ <%- end %>
48
+ <%- if upstream[:compose] %>
49
+ <%= OpenStruct.to_hash(upstream[:compose]).to_yaml.sub(/^.*?\n/, "").indent(4) %>
50
+ <%- end %>
51
+ <%- end %>
52
+ <%- unless (volumes || []).empty? %>
53
+
54
+ volumes:
55
+ <%- volumes.each do |volume| %>
56
+ <%= volume %>:
57
+ <%- end %>
58
+ <%- end %>
@@ -0,0 +1,13 @@
1
+ FROM elixir:<%= upstream.elixir_version %>-alpine
2
+
3
+ RUN apk update \
4
+ && apk --no-cache --update add alpine-sdk \
5
+ && mix local.rebar --force \
6
+ && mix local.hex --force
7
+
8
+ WORKDIR /opt/app
9
+ COPY . .
10
+
11
+ ENV MIX_ENV=prod
12
+ RUN mix do deps.get --only prod, deps.compile
13
+ CMD ["sh", "-c", "mix phx.server"]
@@ -0,0 +1,13 @@
1
+ FROM elixir:<%= upstream.elixir_version %>-alpine
2
+
3
+ RUN apk update \
4
+ && apk --no-cache --update add alpine-sdk \
5
+ && mix local.rebar --force \
6
+ && mix local.hex --force
7
+
8
+ WORKDIR /opt/app
9
+ COPY . .
10
+
11
+ ENV MIX_ENV=prod
12
+ RUN mix do deps.get --only prod, deps.compile
13
+ CMD ["sh", "-c", "mix run --no-halt"]
@@ -0,0 +1,16 @@
1
+ FROM ruby:<%= upstream.ruby_version %>-alpine
2
+
3
+ RUN apk update \
4
+ && apk --no-cache --update add \
5
+ build-base nodejs tzdata \
6
+ mysql-dev mysql-client --no-install-recommends \
7
+ postgresql-dev postgresql-client \
8
+ libxslt-dev libxml2-dev
9
+
10
+ WORKDIR /opt/app
11
+ COPY . .
12
+
13
+ ENV RACK_ENV=production
14
+ RUN gem install bundler -v <%= upstream.bundler_version %>
15
+ RUN bundle install --without development test
16
+ CMD ["bundle", "exec", "rackup", "config.ru", "-o", "0.0.0.0"]
@@ -0,0 +1,18 @@
1
+ FROM ruby:<%= upstream.ruby_version %>-alpine
2
+
3
+ RUN apk update \
4
+ && apk --no-cache --update add \
5
+ build-base nodejs tzdata \
6
+ mysql-dev mysql-client --no-install-recommends \
7
+ postgresql-dev postgresql-client \
8
+ libxslt-dev libxml2-dev
9
+
10
+ WORKDIR /opt/app
11
+ COPY . .
12
+
13
+ ENV RAILS_ENV=production
14
+ EXPOSE <%= upstream.port %>
15
+ RUN gem install bundler -v <%= upstream.bundler_version %>
16
+ RUN bundle install --without development test
17
+ CMD ["rm", "-f", "tmp/pids/server.pid"]
18
+ CMD ["rails", "server", "-b", "0.0.0.0"]
@@ -0,0 +1,76 @@
1
+ #!/bin/bash
2
+
3
+ <%- if (domains = upstream[:domains].collect{|domain| domain.dup.gsub!("https://", "")}.compact).any? %>
4
+ domains=(<%= domains.join(" ") %>)
5
+ email="<%= upstream[:email] || "noreply@#{domains.first}" %>" # Adding a valid address is strongly recommended
6
+ data_path="./data/certbot"
7
+ staging=0 # Set to 1 if you're testing your setup to avoid hitting request limits
8
+ rsa_key_size=4096
9
+
10
+ if [ -d "$data_path" ]; then
11
+ read -p "Existing data found for $domains. Continue and replace existing certificate? (y/N) " decision
12
+ if [ "$decision" != "Y" ] && [ "$decision" != "y" ]; then
13
+ exit
14
+ fi
15
+ fi
16
+
17
+ if [ ! -e "$data_path/conf/options-ssl-nginx.conf" ] || [ ! -e "$data_path/conf/ssl-dhparams.pem" ]; then
18
+ echo "### Downloading recommended TLS parameters ..."
19
+ mkdir -p "$data_path/conf"
20
+ curl -s https://raw.githubusercontent.com/certbot/certbot/v0.40.1/certbot-nginx/certbot_nginx/tls_configs/options-ssl-nginx.conf > "$data_path/conf/options-ssl-nginx.conf"
21
+ curl -s https://raw.githubusercontent.com/certbot/certbot/v0.40.1/certbot/ssl-dhparams.pem > "$data_path/conf/ssl-dhparams.pem"
22
+ echo
23
+ fi
24
+
25
+ echo "### Creating dummy certificate for $domains ..."
26
+ path="/etc/letsencrypt/live/$domains"
27
+ mkdir -p "$data_path/conf/live/$domains"
28
+ docker-compose run --rm --entrypoint "\
29
+ openssl req -x509 -nodes -newkey rsa:1024 -days 1\
30
+ -keyout '$path/privkey.pem' \
31
+ -out '$path/fullchain.pem' \
32
+ -subj '/CN=localhost'" certbot
33
+ echo
34
+
35
+ echo "### Starting nginx ..."
36
+ docker-compose up --force-recreate -d nginx
37
+ echo
38
+
39
+ echo "### Deleting dummy certificate for $domains ..."
40
+ docker-compose run --rm --entrypoint "\
41
+ rm -Rf /etc/letsencrypt/live/$domains && \
42
+ rm -Rf /etc/letsencrypt/archive/$domains && \
43
+ rm -Rf /etc/letsencrypt/renewal/$domains.conf" certbot
44
+ echo
45
+
46
+ echo "### Requesting Let's Encrypt certificate for $domains ..."
47
+ #Join $domains to -d args
48
+ domain_args=""
49
+ for domain in "${domains[@]}"; do
50
+ domain_args="$domain_args -d $domain"
51
+ done
52
+
53
+ # Select appropriate email arg
54
+ case "$email" in
55
+ "") email_arg="--register-unsafely-without-email" ;;
56
+ *) email_arg="--email $email" ;;
57
+ esac
58
+
59
+ # Enable staging mode if needed
60
+ if [ $staging != "0" ]; then staging_arg="--staging"; fi
61
+
62
+ docker-compose run --rm --entrypoint "\
63
+ certbot certonly --webroot -w /var/www/certbot \
64
+ $staging_arg \
65
+ $email_arg \
66
+ $domain_args \
67
+ --rsa-key-size $rsa_key_size \
68
+ --agree-tos \
69
+ --force-renewal" certbot
70
+ echo
71
+
72
+ echo "### Reloading nginx ..."
73
+ docker-compose exec nginx nginx -s reload
74
+ <%- else %>
75
+ # NO HTTPS
76
+ <%- end %>
@@ -0,0 +1,12 @@
1
+ require_relative "test_helper/coverage"
2
+
3
+ require "minitest"
4
+ require "minitest/autorun"
5
+ require "mocha/setup"
6
+
7
+ def path(path)
8
+ File.expand_path "../../#{path}", __FILE__
9
+ end
10
+
11
+ require "bundler"
12
+ Bundler.require :default, :development, :test
@@ -0,0 +1,8 @@
1
+ if Dir.pwd == File.expand_path("../../..", __FILE__)
2
+ require "simplecov"
3
+ SimpleCov.coverage_dir "test/coverage"
4
+ SimpleCov.start do
5
+ add_group "VPS", "lib"
6
+ add_group "Test suite", "test"
7
+ end
8
+ end
@@ -0,0 +1,15 @@
1
+ require_relative "../test_helper"
2
+
3
+ module Unit
4
+ class TestVersion < MiniTest::Test
5
+
6
+ describe VPS::VERSION do
7
+ it "has the current version" do
8
+ version = File.read(path("VERSION")).strip
9
+ assert_equal version, VPS::VERSION
10
+ assert File.read(path "CHANGELOG.md").include?("Version #{version} ")
11
+ end
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path("../lib/vps/version", __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Paul Engel"]
6
+ gem.email = ["pm_engel@icloud.com"]
7
+ gem.summary = %q{Zero-config deployments of Plug, Phoenix, Rack and Rails apps on a clean Ubuntu server using Docker and Let's Encrypt}
8
+ gem.description = %q{Zero-config deployments of Plug, Phoenix, Rack and Rails apps on a clean Ubuntu server using Docker and Let's Encrypt}
9
+ gem.homepage = "https://github.com/archan937/vps"
10
+
11
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
12
+ gem.files = `git ls-files`.split("\n")
13
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
14
+ gem.name = "vps"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = VPS::VERSION
17
+ gem.licenses = ["MIT"]
18
+
19
+ gem.add_dependency "thor"
20
+ gem.add_dependency "erubis"
21
+ gem.add_dependency "inquirer"
22
+ gem.add_dependency "net-ssh"
23
+ gem.add_dependency "activesupport", ">= 4.1.8"
24
+
25
+ gem.add_development_dependency "pry"
26
+ gem.add_development_dependency "simplecov"
27
+ gem.add_development_dependency "minitest"
28
+ gem.add_development_dependency "mocha"
29
+ end
metadata ADDED
@@ -0,0 +1,214 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vps
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Paul Engel
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-12-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: erubis
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: inquirer
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: net-ssh
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: activesupport
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 4.1.8
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 4.1.8
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: simplecov
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: minitest
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: mocha
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ description: Zero-config deployments of Plug, Phoenix, Rack and Rails apps on a clean
140
+ Ubuntu server using Docker and Let's Encrypt
141
+ email:
142
+ - pm_engel@icloud.com
143
+ executables:
144
+ - vps
145
+ extensions: []
146
+ extra_rdoc_files: []
147
+ files:
148
+ - ".gitignore"
149
+ - CHANGELOG.md
150
+ - Gemfile
151
+ - MIT-LICENSE
152
+ - README.md
153
+ - Rakefile
154
+ - VERSION
155
+ - bin/vps
156
+ - config/services.yml
157
+ - lib/vps.rb
158
+ - lib/vps/cli.rb
159
+ - lib/vps/cli/domain.rb
160
+ - lib/vps/cli/playbook.rb
161
+ - lib/vps/cli/playbook/state.rb
162
+ - lib/vps/cli/playbook/tasks.rb
163
+ - lib/vps/cli/service.rb
164
+ - lib/vps/cli/upstream.rb
165
+ - lib/vps/core_ext/ostruct.rb
166
+ - lib/vps/core_ext/string.rb
167
+ - lib/vps/version.rb
168
+ - playbooks/deploy.yml
169
+ - playbooks/deploy/docker.yml
170
+ - playbooks/init.yml
171
+ - playbooks/init/ubuntu-18.04.yml
172
+ - playbooks/install.yml
173
+ - playbooks/install/docker/ubuntu-18.04.yml
174
+ - script/console
175
+ - templates/docker/data/nginx/app.conf.erb
176
+ - templates/docker/docker-compose.yml.erb
177
+ - templates/docker/upstream/Dockerfile.phoenix.erb
178
+ - templates/docker/upstream/Dockerfile.plug.erb
179
+ - templates/docker/upstream/Dockerfile.rack.erb
180
+ - templates/docker/upstream/Dockerfile.rails.erb
181
+ - templates/docker/upstream/init-letsencrypt.sh.erb
182
+ - test/test_helper.rb
183
+ - test/test_helper/coverage.rb
184
+ - test/unit/test_version.rb
185
+ - vps.gemspec
186
+ homepage: https://github.com/archan937/vps
187
+ licenses:
188
+ - MIT
189
+ metadata: {}
190
+ post_install_message:
191
+ rdoc_options: []
192
+ require_paths:
193
+ - lib
194
+ required_ruby_version: !ruby/object:Gem::Requirement
195
+ requirements:
196
+ - - ">="
197
+ - !ruby/object:Gem::Version
198
+ version: '0'
199
+ required_rubygems_version: !ruby/object:Gem::Requirement
200
+ requirements:
201
+ - - ">="
202
+ - !ruby/object:Gem::Version
203
+ version: '0'
204
+ requirements: []
205
+ rubyforge_project:
206
+ rubygems_version: 2.4.5.4
207
+ signing_key:
208
+ specification_version: 4
209
+ summary: Zero-config deployments of Plug, Phoenix, Rack and Rails apps on a clean
210
+ Ubuntu server using Docker and Let's Encrypt
211
+ test_files:
212
+ - test/test_helper.rb
213
+ - test/test_helper/coverage.rb
214
+ - test/unit/test_version.rb