wellcar 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +2 -0
  5. data/Gemfile.lock +38 -0
  6. data/README.markdown +17 -0
  7. data/README.rdoc +6 -0
  8. data/Rakefile +44 -0
  9. data/bin/wellcar +442 -0
  10. data/command_history_example.txt +39 -0
  11. data/lib/wellcar.rb +18 -0
  12. data/lib/wellcar/templates/base.rb +61 -0
  13. data/lib/wellcar/templates/build-production-image.yml.erb +34 -0
  14. data/lib/wellcar/templates/build_production_image.rb +18 -0
  15. data/lib/wellcar/templates/database.yml.erb +20 -0
  16. data/lib/wellcar/templates/database_yaml.rb +20 -0
  17. data/lib/wellcar/templates/docker-compose-init.yml.erb +34 -0
  18. data/lib/wellcar/templates/docker-compose.yml.erb +70 -0
  19. data/lib/wellcar/templates/docker-entrypoint.sh.erb +20 -0
  20. data/lib/wellcar/templates/docker-stack.yml.erb +35 -0
  21. data/lib/wellcar/templates/docker_compose.rb +22 -0
  22. data/lib/wellcar/templates/docker_entrypoint.rb +13 -0
  23. data/lib/wellcar/templates/docker_stack.rb +23 -0
  24. data/lib/wellcar/templates/dockerfile.erb +48 -0
  25. data/lib/wellcar/templates/dockerfile.rb +13 -0
  26. data/lib/wellcar/templates/dockerfile_init.erb +38 -0
  27. data/lib/wellcar/templates/dockerfile_init.rb +18 -0
  28. data/lib/wellcar/templates/dockerignore.erb +10 -0
  29. data/lib/wellcar/templates/dockerignore.rb +12 -0
  30. data/lib/wellcar/templates/env_development_database.erb +3 -0
  31. data/lib/wellcar/templates/env_development_database.rb +13 -0
  32. data/lib/wellcar/templates/env_development_web.erb +1 -0
  33. data/lib/wellcar/templates/env_development_web.rb +14 -0
  34. data/lib/wellcar/templates/env_production_database.erb +3 -0
  35. data/lib/wellcar/templates/env_production_database.rb +14 -0
  36. data/lib/wellcar/templates/env_production_web.erb +5 -0
  37. data/lib/wellcar/templates/env_production_web.rb +14 -0
  38. data/lib/wellcar/templates/reverse_proxy.conf.erb +12 -0
  39. data/lib/wellcar/templates/reverse_proxy_conf.rb +14 -0
  40. data/lib/wellcar/version.rb +3 -0
  41. data/spec/.keep +0 -0
  42. data/spec/spec_helper.rb +101 -0
  43. data/spec/wellcar/templates/build_production_image_spec.rb +55 -0
  44. data/spec/wellcar/templates/database_yaml_spec.rb +27 -0
  45. data/spec/wellcar/templates/docker_compose_spec.rb +34 -0
  46. data/spec/wellcar/templates/docker_entrypoint_spec.rb +32 -0
  47. data/spec/wellcar/templates/docker_stack_spec.rb +37 -0
  48. data/spec/wellcar/templates/dockerfile_init_spec.rb +28 -0
  49. data/spec/wellcar/templates/dockerfile_spec.rb +44 -0
  50. data/spec/wellcar/templates/dockerignore_spec.rb +28 -0
  51. data/spec/wellcar/templates/env_development_database_spec.rb +25 -0
  52. data/spec/wellcar/templates/env_development_web_spec.rb +13 -0
  53. data/spec/wellcar/templates/env_production_database_spec.rb +25 -0
  54. data/spec/wellcar/templates/env_production_web_spec.rb +29 -0
  55. data/spec/wellcar/templates/reverse_proxy_conf_spec.rb +17 -0
  56. data/wellcar.gemspec +22 -0
  57. data/wellcar.rdoc +5 -0
  58. metadata +163 -0
@@ -0,0 +1,48 @@
1
+ FROM nginx:alpine AS reverse_proxy
2
+ COPY config/nginx/reverse-proxy.conf /etc/nginx/conf.d/reverse-proxy.conf
3
+ STOPSIGNAL SIGTERM
4
+ CMD ["nginx", "-g", "daemon off;"]
5
+
6
+ FROM ruby:<%= ruby_version %> AS core_dependencies
7
+ LABEL maintainer="<your email here>"
8
+
9
+ RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add --no-tty -
10
+
11
+ RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends \
12
+ apt-transport-https
13
+
14
+ RUN curl -sL https://deb.nodesource.com/setup_10.x | bash -
15
+
16
+ RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
17
+ RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
18
+
19
+ RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends \
20
+ netcat \
21
+ nodejs \
22
+ yarn
23
+
24
+ WORKDIR /app/<%= app_name %>
25
+
26
+ ENV BUNDLE_PATH /gems
27
+ <% if use_bundler_2 %>RUN gem install bundler<% end %>
28
+
29
+ FROM core_dependencies AS dev_environment
30
+
31
+ COPY . /app/<%= app_name %>/
32
+ RUN chmod +x bin/docker-entrypoint.sh
33
+
34
+ ENTRYPOINT ["./bin/docker-entrypoint.sh"]
35
+ CMD ["bin/rails", "s", "-b", "0.0.0.0"]
36
+
37
+ FROM core_dependencies AS production
38
+
39
+ COPY Gemfile* yarn.lock package.json /app/<%= app_name %>/
40
+
41
+ RUN bundle install
42
+
43
+ COPY . /app/<%= app_name %>/
44
+ RUN chmod +x bin/docker-entrypoint.sh
45
+ RUN chmod +x bin/wait-for
46
+
47
+ RUN bin/rails assets:precompile
48
+ CMD ["bin/rails", "s", "-b", "0.0.0.0"]
@@ -0,0 +1,13 @@
1
+ require File.join(File.dirname(__FILE__), "base.rb")
2
+
3
+ module Wellcar
4
+ module Templates
5
+ class Dockerfile < Base
6
+ def initialize(ruby_version, app_name, use_bundler_2=false)
7
+ super "Dockerfile"
8
+ with_attributes ruby_version: ruby_version, app_name: app_name, use_bundler_2: use_bundler_2
9
+ with_template "dockerfile.erb"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,38 @@
1
+ # First stage: build an image that can create a new Ruby on Rails app
2
+ FROM ruby:<%= ruby_version %> AS base_for_new
3
+ LABEL description="Docker build to create a new Rails app and prepare for creating a docker-based development environment around it"
4
+
5
+ RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add --no-tty -
6
+
7
+ RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends \
8
+ apt-transport-https
9
+
10
+ RUN curl -sL https://deb.nodesource.com/setup_10.x | bash -
11
+
12
+ RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
13
+ RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
14
+
15
+ RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends \
16
+ nodejs \
17
+ yarn
18
+
19
+ WORKDIR /app/<%= app_name %>
20
+ ENV BUNDLE_PATH /gems
21
+ RUN gem install bundler
22
+
23
+ # Stage 1: Create a new Rails app
24
+ FROM base_for_new AS new_rails
25
+ RUN gem install rails --no-doc
26
+
27
+ CMD ["rails", "new", "--database", "postgresql", <%= skips %>, "."]
28
+
29
+ # Stage 2: Bundle install the Rails dependencies to a mounted volume
30
+ FROM base_for_new AS bundle_for_lockfile
31
+ COPY --from=new_rails /app/<%= app_name %>/ .
32
+ CMD ["bundle", "install"]
33
+
34
+ # Stage 3: Install webpacker in the Rails app, putting node_modules in a mounted volume
35
+ FROM base_for_new AS install_webpacker
36
+ COPY --from=bundle_for_lockfile /app/<%= app_name %>/ .
37
+
38
+ CMD ["bin/rails", "webpacker:install"]
@@ -0,0 +1,18 @@
1
+ require File.join(File.dirname(__FILE__), "base")
2
+
3
+ module Wellcar
4
+ module Templates
5
+ class DockerfileInit < Base
6
+ def initialize(ruby_version, app_name)
7
+ super "Dockerfile.init"
8
+ with_attributes ruby_version: ruby_version, app_name: app_name
9
+ with_template "dockerfile_init.erb"
10
+ end
11
+
12
+ def skips
13
+ skip_on_new = %w(bundle webpack-install test)
14
+ skip_on_new.map {|s| "\"--skip-#{s}\"" }.join(", ")
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,10 @@
1
+ Dockerfile
2
+ docker-compose.yml
3
+ .env
4
+ *.swp
5
+ *.swo
6
+ .git
7
+ .gitignore
8
+ .wellcar/*
9
+ logs/*
10
+ tmp/*
@@ -0,0 +1,12 @@
1
+ require File.join(File.dirname(__FILE__), "base")
2
+
3
+ module Wellcar
4
+ module Templates
5
+ class Dockerignore < Base
6
+ def initialize()
7
+ super ".dockerignore"
8
+ with_template "dockerignore.erb"
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ POSTGRES_USER=postgres
2
+ POSTGRES_PASSWORD=a-development-password
3
+ POSTGRES_DB=<%= app_name %>_development
@@ -0,0 +1,13 @@
1
+ require File.join(File.dirname(__FILE__), "base")
2
+
3
+ module Wellcar
4
+ module Templates
5
+ class EnvDevelopmentDatabase < Base
6
+ def initialize(app_name)
7
+ super ".env/development/database"
8
+ with_attributes app_name: app_name
9
+ with_template "env_development_database.erb"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1 @@
1
+ DATABASE_HOST=database
@@ -0,0 +1,14 @@
1
+ require File.join(File.dirname(__FILE__), "base")
2
+
3
+ module Wellcar
4
+ module Templates
5
+ class EnvDevelopmentWeb < Base
6
+ attr_accessor :app_name
7
+
8
+ def initialize
9
+ super ".env/development/web"
10
+ with_template "env_development_web.erb"
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ POSTGRES_USER=postgres
2
+ POSTGRES_PASSWORD=replace-me
3
+ POSTGRES_DB=<%= app_name %>_production
@@ -0,0 +1,14 @@
1
+ require File.join(File.dirname(__FILE__), "base")
2
+
3
+ module Wellcar
4
+ module Templates
5
+ class EnvProductionDatabase < Base
6
+ def initialize(app_name)
7
+ super ".env/production/database"
8
+ with_attributes app_name: app_name
9
+ with_template "env_production_database.erb"
10
+ end
11
+ end
12
+ end
13
+ end
14
+
@@ -0,0 +1,5 @@
1
+ DATABASE_HOST=database
2
+ RAILS_ENV=production
3
+ RAILS_MASTER_KEY=<%= master_key %>
4
+ RAILS_LOG_TO_STDOUT=true
5
+ RAILS_SERVE_STATIC_FILES=true
@@ -0,0 +1,14 @@
1
+ require File.join(File.dirname(__FILE__), "base")
2
+
3
+ module Wellcar
4
+ module Templates
5
+ class EnvProductionWeb < Base
6
+ def initialize(master_key)
7
+ super ".env/production/web"
8
+ with_template "env_production_web.erb"
9
+ with_attributes master_key: master_key
10
+ end
11
+ end
12
+ end
13
+ end
14
+
@@ -0,0 +1,12 @@
1
+ server {
2
+ listen 3001;
3
+ server_name <%= domain_name %> localhost;
4
+ allow 172.0.0.0/8;
5
+ deny all;
6
+
7
+ location / {
8
+ proxy_pass http://web:3000;
9
+ proxy_set_header Host $host;
10
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
11
+ }
12
+ }
@@ -0,0 +1,14 @@
1
+ require File.join(File.dirname(__FILE__), "base")
2
+
3
+ module Wellcar
4
+ module Templates
5
+ class ReverseProxyConf < Base
6
+ def initialize(domain_name)
7
+ super "reverse_proxy.conf"
8
+ with_attributes domain_name: domain_name
9
+ with_template "reverse_proxy.conf.erb"
10
+ within "config/nginx"
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ module Wellcar
2
+ VERSION = '0.0.1'
3
+ end
File without changes
@@ -0,0 +1,101 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
4
+ # this file to always be loaded, without a need to explicitly require it in any
5
+ # files.
6
+ #
7
+ # Given that it is always loaded, you are encouraged to keep this file as
8
+ # light-weight as possible. Requiring heavyweight dependencies from this file
9
+ # will add to the boot time of your test suite on EVERY test run, even for an
10
+ # individual file that may not need all of that loaded. Instead, consider making
11
+ # a separate helper file that requires the additional dependencies and performs
12
+ # the additional setup, and require it from the spec files that actually need
13
+ # it.
14
+ #
15
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
16
+
17
+ RSpec.configure do |config|
18
+ # rspec-expectations config goes here. You can use an alternate
19
+ # assertion/expectation library such as wrong or the stdlib/minitest
20
+ # assertions if you prefer.
21
+ config.expect_with :rspec do |expectations|
22
+ # This option will default to `true` in RSpec 4. It makes the `description`
23
+ # and `failure_message` of custom matchers include text for helper methods
24
+ # defined using `chain`, e.g.:
25
+ # be_bigger_than(2).and_smaller_than(4).description
26
+ # # => "be bigger than 2 and smaller than 4"
27
+ # ...rather than:
28
+ # # => "be bigger than 2"
29
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
30
+ end
31
+
32
+ # rspec-mocks config goes here. You can use an alternate test double
33
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
34
+ config.mock_with :rspec do |mocks|
35
+ # Prevents you from mocking or stubbing a method that does not exist on
36
+ # a real object. This is generally recommended, and will default to
37
+ # `true` in RSpec 4.
38
+ mocks.verify_partial_doubles = true
39
+ end
40
+
41
+ # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
42
+ # have no way to turn it off -- the option exists only for backwards
43
+ # compatibility in RSpec 3). It causes shared context metadata to be
44
+ # inherited by the metadata hash of host groups and examples, rather than
45
+ # triggering implicit auto-inclusion in groups with matching metadata.
46
+ config.shared_context_metadata_behavior = :apply_to_host_groups
47
+
48
+ # The settings below are suggested to provide a good initial experience
49
+ # with RSpec, but feel free to customize to your heart's content.
50
+ =begin
51
+ # This allows you to limit a spec run to individual examples or groups
52
+ # you care about by tagging them with `:focus` metadata. When nothing
53
+ # is tagged with `:focus`, all examples get run. RSpec also provides
54
+ # aliases for `it`, `describe`, and `context` that include `:focus`
55
+ # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
56
+ config.filter_run_when_matching :focus
57
+
58
+ # Allows RSpec to persist some state between runs in order to support
59
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
60
+ # you configure your source control system to ignore this file.
61
+ config.example_status_persistence_file_path = "spec/examples.txt"
62
+
63
+ # Limits the available syntax to the non-monkey patched syntax that is
64
+ # recommended. For more details, see:
65
+ # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
66
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
67
+ # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
68
+ config.disable_monkey_patching!
69
+
70
+ # This setting enables warnings. It's recommended, but in some cases may
71
+ # be too noisy due to issues in dependencies.
72
+ config.warnings = true
73
+
74
+ # Many RSpec users commonly either run the entire suite or an individual
75
+ # file, and it's useful to allow more verbose output when running an
76
+ # individual spec file.
77
+ if config.files_to_run.one?
78
+ # Use the documentation formatter for detailed output,
79
+ # unless a formatter has already been configured
80
+ # (e.g. via a command-line flag).
81
+ config.default_formatter = "doc"
82
+ end
83
+
84
+ # Print the 10 slowest examples and example groups at the
85
+ # end of the spec run, to help surface which specs are running
86
+ # particularly slow.
87
+ config.profile_examples = 10
88
+
89
+ # Run specs in random order to surface order dependencies. If you find an
90
+ # order dependency and want to debug it, you can fix the order by providing
91
+ # the seed, which is printed after each run.
92
+ # --seed 1234
93
+ config.order = :random
94
+
95
+ # Seed global randomization in this process using the `--seed` CLI option.
96
+ # Setting this allows you to use `--seed` to deterministically reproduce
97
+ # test failures related to randomization by passing the same `--seed` value
98
+ # as the one that triggered the failure.
99
+ Kernel.srand config.seed
100
+ =end
101
+ end
@@ -0,0 +1,55 @@
1
+ require File.join(File.dirname(__FILE__), "..", "..", "spec_helper.rb")
2
+ require "yaml"
3
+ require "wellcar/templates/build_production_image"
4
+
5
+ RSpec.describe Wellcar::Templates::BuildProductionImage do
6
+ describe "#write" do
7
+ context "with an app name and GitHub account when directory does not exist" do
8
+ let(:template) { described_class.new "test_app", "github_user" }
9
+
10
+ around do |spec|
11
+ Dir.chdir File.join(File.dirname(__FILE__), "..", "..", "..", "tmp") do
12
+ FileUtils.rm_rf ".github" if Dir.exist? ".github"
13
+ spec.run
14
+ FileUtils.rm_rf ".github" if Dir.exist? ".github"
15
+ end
16
+ end
17
+
18
+ it do
19
+ template.write
20
+
21
+ expect(Dir[".github/workflows/*"]).to match_array ".github/workflows/build-production-image.yml"
22
+
23
+ contents = YAML::load File.read(".github/workflows/build-production-image.yml")
24
+ expect(contents.dig("jobs", "push_to_registry", "steps")[1].dig("with", "repository")).to eq "github_user/test_app/nginx"
25
+ expect(contents.dig("jobs", "push_to_registry", "steps")[1].dig("with", "target")).to eq "reverse_proxy"
26
+ expect(contents.dig("jobs", "push_to_registry", "steps")[2].dig("with", "repository")).to eq "github_user/test_app/web"
27
+ expect(contents.dig("jobs", "push_to_registry", "steps")[2].dig("with", "target")).to eq "production"
28
+ end
29
+ end
30
+
31
+ context "with an app name and GitHub account when directory exists" do
32
+ let(:template) { described_class.new "test_app", "github_user" }
33
+
34
+ around do |spec|
35
+ Dir.chdir File.join(File.dirname(__FILE__), "..", "..", "..", "tmp") do
36
+ FileUtils.mkdir_p ".github/workflows"
37
+ spec.run
38
+ FileUtils.rm_rf ".github" if Dir.exist? ".github"
39
+ end
40
+ end
41
+
42
+ it do
43
+ template.write
44
+
45
+ expect(Dir[".github/workflows/*"]).to match_array ".github/workflows/build-production-image.yml"
46
+
47
+ contents = YAML::load File.read(".github/workflows/build-production-image.yml")
48
+ expect(contents.dig("jobs", "push_to_registry", "steps")[1].dig("with", "repository")).to eq "github_user/test_app/nginx"
49
+ expect(contents.dig("jobs", "push_to_registry", "steps")[1].dig("with", "target")).to eq "reverse_proxy"
50
+ expect(contents.dig("jobs", "push_to_registry", "steps")[2].dig("with", "repository")).to eq "github_user/test_app/web"
51
+ expect(contents.dig("jobs", "push_to_registry", "steps")[2].dig("with", "target")).to eq "production"
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,27 @@
1
+ require File.join(File.dirname(__FILE__), "..", "..", "spec_helper.rb")
2
+ require "yaml"
3
+ require "wellcar/templates/database_yaml"
4
+
5
+ RSpec.describe Wellcar::Templates::DatabaseYaml do
6
+ describe "#render" do
7
+ subject { YAML::load(template.render) }
8
+
9
+ context "with a first set of inputs" do
10
+ let(:template) { Wellcar::Templates::DatabaseYaml.new("test_app") }
11
+
12
+ it { expect(subject["development"]["host"]).to eq("<%= ENV.fetch(\"DATABASE_HOST\") %>") }
13
+ it { expect(subject["development"]["username"]).to eq("<%= ENV.fetch(\"POSTGRES_USER\") %>") }
14
+ it { expect(subject["development"]["password"]).to eq("<%= ENV.fetch(\"POSTGRES_PASSWORD\") %>") }
15
+ it { expect(subject["development"]["database"]).to eq("<%= ENV.fetch(\"POSTGRES_DB\") %>") }
16
+ it { expect(subject["test"]["database"]).to eq("test_app") }
17
+ end
18
+
19
+ context "with another set of inputs" do
20
+ let(:template) { Wellcar::Templates::DatabaseYaml.new("old_app") }
21
+
22
+ it { expect(subject["test"]["database"]).to eq("old_app") }
23
+ end
24
+ end
25
+ end
26
+
27
+