potassium 5.2.3 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +22 -9
  3. data/.node-version +1 -0
  4. data/.ruby-version +1 -1
  5. data/CHANGELOG.md +26 -0
  6. data/docs/DSL.md +5 -5
  7. data/lib/potassium/assets/.circleci/config.yml.erb +102 -0
  8. data/lib/potassium/assets/.eslintrc.json +343 -0
  9. data/lib/potassium/assets/.rubocop.yml +515 -0
  10. data/lib/potassium/assets/.stylelintrc.json +46 -0
  11. data/lib/potassium/assets/Dockerfile.ci +1 -1
  12. data/lib/potassium/assets/Makefile.erb +6 -32
  13. data/lib/potassium/assets/README.yml +51 -7
  14. data/lib/potassium/assets/active_admin/admin-component.vue +35 -0
  15. data/lib/potassium/assets/active_admin/admin_application.js +14 -0
  16. data/lib/potassium/assets/active_admin/init_activeadmin_vue.rb +10 -0
  17. data/lib/potassium/assets/api/base_controller.rb +1 -3
  18. data/lib/potassium/assets/app/javascript/app.spec.js +14 -0
  19. data/lib/potassium/assets/app/uploaders/base_uploader.rb +13 -0
  20. data/lib/potassium/assets/app/uploaders/image_uploader.rb +5 -0
  21. data/lib/potassium/assets/bin/cibuild.erb +18 -1
  22. data/lib/potassium/assets/bin/setup.erb +1 -1
  23. data/lib/potassium/assets/config/database_mysql.yml.erb +2 -2
  24. data/lib/potassium/assets/config/database_postgresql.yml.erb +2 -2
  25. data/lib/potassium/assets/config/shrine.rb +33 -0
  26. data/lib/potassium/assets/docker-compose.ci.yml +1 -0
  27. data/lib/potassium/assets/lib/tasks/auto_annotate_models.rake +2 -1
  28. data/lib/potassium/assets/package.json +4 -1
  29. data/lib/potassium/cli/commands/create.rb +1 -0
  30. data/lib/potassium/cli_options.rb +6 -6
  31. data/lib/potassium/helpers/template-helpers.rb +4 -0
  32. data/lib/potassium/recipes/admin.rb +3 -3
  33. data/lib/potassium/recipes/annotate.rb +1 -1
  34. data/lib/potassium/recipes/ci.rb +1 -1
  35. data/lib/potassium/recipes/database_container.rb +5 -4
  36. data/lib/potassium/recipes/draper.rb +1 -1
  37. data/lib/potassium/recipes/file_storage.rb +15 -33
  38. data/lib/potassium/recipes/front_end.rb +128 -5
  39. data/lib/potassium/recipes/mailer.rb +5 -2
  40. data/lib/potassium/recipes/node.rb +21 -0
  41. data/lib/potassium/recipes/rack_cors.rb +18 -15
  42. data/lib/potassium/recipes/schedule.rb +1 -1
  43. data/lib/potassium/recipes/style.rb +21 -3
  44. data/lib/potassium/recipes/vue_admin.rb +124 -0
  45. data/lib/potassium/templates/application.rb +4 -2
  46. data/lib/potassium/version.rb +4 -3
  47. data/potassium.gemspec +6 -5
  48. data/spec/features/database_container_spec.rb +1 -1
  49. data/spec/features/file_storage_spec.rb +12 -16
  50. data/spec/features/front_end_spec.rb +74 -0
  51. data/spec/features/new_project_spec.rb +1 -1
  52. data/spec/features/node_spec.rb +28 -0
  53. data/spec/features/power_types_spec.rb +5 -16
  54. data/spec/features/vue_admin_spec.rb +47 -0
  55. data/spec/support/potassium_test_helpers.rb +23 -9
  56. metadata +56 -29
  57. data/lib/potassium/assets/.circleci/config.yml +0 -20
  58. data/lib/potassium/assets/active_admin/active_admin.js.coffee +0 -4
  59. data/lib/potassium/assets/active_admin/init_activeadmin_angular.rb +0 -8
  60. data/lib/potassium/assets/testing/paperclip.rb +0 -59
  61. data/lib/potassium/recipes/angular_admin.rb +0 -56
  62. data/spec/features/front_end.rb +0 -33
@@ -8,7 +8,7 @@ class Recipes::Schedule < Rails::AppBuilder
8
8
 
9
9
  def create
10
10
  if selected?(:schedule)
11
- gather_gem 'sidekiq-scheduler'
11
+ gather_gem 'sidekiq-scheduler', '>= 3.0.1'
12
12
  add_readme_section :internal_dependencies, :sidekiq_scheduler
13
13
  end
14
14
  template '../assets/sidekiq_scheduler.yml', 'config/sidekiq.yml', force: true
@@ -1,12 +1,30 @@
1
1
  class Recipes::Style < Rails::AppBuilder
2
2
  def create
3
- append_to_file ".gitignore", ".rubocop.yml\n"
4
- append_to_file ".gitignore", ".eslintrc.json\n"
5
- append_to_file ".gitignore", ".sscs-lint.yml\n"
3
+ add_linters
4
+ add_config_files
6
5
  add_readme_header :style_guide
7
6
  end
8
7
 
9
8
  def install
10
9
  create
11
10
  end
11
+
12
+ private
13
+
14
+ def add_linters
15
+ gather_gems(:development, :test) do
16
+ gather_gem 'rubocop', '~> 0.82.0'
17
+ gather_gem 'rubocop-performance'
18
+ gather_gem 'rubocop-rails'
19
+ gather_gem 'rubocop-rspec'
20
+ end
21
+ run 'bin/yarn add --dev stylelint eslint eslint-plugin-import'
22
+ run 'bin/yarn add --dev eslint-plugin-vue' if selected?(:front_end, :vue)
23
+ end
24
+
25
+ def add_config_files
26
+ copy_file '../assets/.rubocop.yml', '.rubocop.yml'
27
+ copy_file '../assets/.eslintrc.json', '.eslintrc.json'
28
+ copy_file '../assets/.stylelintrc.json', '.stylelintrc.json'
29
+ end
12
30
  end
@@ -0,0 +1,124 @@
1
+ class Recipes::VueAdmin < Rails::AppBuilder
2
+ def ask
3
+ if selected?(:admin_mode)
4
+ vue_admin = answer(:vue_admin) do
5
+ Ask.confirm "Do you want Vue support for ActiveAdmin?"
6
+ end
7
+ set(:vue_admin, vue_admin)
8
+ set(:front_end, :vue) if vue_admin
9
+ end
10
+ end
11
+
12
+ def create
13
+ recipe = self
14
+ if selected?(:vue_admin)
15
+ after(:admin_install) do
16
+ recipe.add_vue_admin
17
+ end
18
+ end
19
+ end
20
+
21
+ def install
22
+ active_admin = load_recipe(:admin)
23
+ if active_admin.installed?
24
+ add_vue_admin
25
+ info "VueAdmin installed"
26
+ else
27
+ info "VueAdmin can't be installed because Active Admin isn't installed."
28
+ end
29
+ end
30
+
31
+ def installed?
32
+ dir_exist?("app/assets/javascripts/admin")
33
+ end
34
+
35
+ def add_vue_admin
36
+ add_vue_component_library
37
+ add_component_integration
38
+ copy_file '../assets/active_admin/init_activeadmin_vue.rb',
39
+ 'config/initializers/init_activeadmin_vue.rb'
40
+ copy_file '../assets/active_admin/admin_application.js',
41
+ 'app/javascript/packs/admin_application.js',
42
+ force: true
43
+ empty_directory 'app/javascript/components'
44
+ copy_file '../assets/active_admin/admin-component.vue',
45
+ 'app/javascript/components/admin-component.vue',
46
+ force: true
47
+ end
48
+
49
+ def add_component_integration
50
+ line = "class CustomFooter < ActiveAdmin::Component"
51
+ initializer = "config/initializers/active_admin.rb"
52
+ gsub_file initializer, /(#{Regexp.escape(line)})/mi do |_match|
53
+ <<~HERE
54
+ require "vue_component.rb"
55
+ AUTO_BUILD_ELEMENTS=[:admin_component, :template, :slot]
56
+ component_creator(AUTO_BUILD_ELEMENTS)
57
+
58
+ #{line}
59
+ HERE
60
+ end
61
+ end
62
+
63
+ def add_vue_component_library
64
+ lib_component_path = "lib/vue_component.rb"
65
+ class_definitions =
66
+ <<~HERE
67
+ #{vue_component}
68
+ #{component_builder}
69
+ HERE
70
+ File.open(lib_component_path, "w") { |file| file.write(class_definitions) }
71
+ end
72
+
73
+ def vue_component
74
+ <<~HERE
75
+ class VueComponent < Arbre::Component
76
+ builder_method :root
77
+ def tag_name
78
+ :root
79
+ end
80
+
81
+ def initialize(*)
82
+ super
83
+ end
84
+
85
+ def build(attributes = {})
86
+ super(process_attributes(attributes))
87
+ end
88
+
89
+ def process_attributes(attributes)
90
+ vue_attributes = {}
91
+ attributes.each do |key, value|
92
+ dasherized_key = key.to_s.dasherize
93
+ if value.is_a?(String)
94
+ vue_attributes[dasherized_key] = value
95
+ elsif !dasherized_key.index(':').nil? && dasherized_key.index(':').zero?
96
+ vue_attributes[dasherized_key] = value.to_json
97
+ else
98
+ vue_attributes[":" + dasherized_key] = value.to_json
99
+ end
100
+ end
101
+ vue_attributes
102
+ end
103
+ end
104
+ HERE
105
+ end
106
+
107
+ def component_builder
108
+ <<~HERE
109
+ def component_creator(auto_build_elements)
110
+ auto_build_elements.each do |element|
111
+ as_string=element.to_s
112
+ camelized_element = as_string.camelize
113
+ Object.const_set(camelized_element,Class.new(VueComponent))
114
+ Object.const_get(camelized_element).class_eval do
115
+ builder_method as_string.to_sym
116
+ def tag_name
117
+ self.class.to_s.underscore
118
+ end
119
+ end
120
+ end
121
+ end
122
+ HERE
123
+ end
124
+ end
@@ -1,4 +1,5 @@
1
1
  set :app_name, app_name
2
+ set :node_version, node_version
2
3
  set :titleized_app_name, get(:app_name).titleize
3
4
  set :underscorized_app_name, get(:app_name).underscore
4
5
  set :dasherized_app_name, get(:app_name).dasherize
@@ -20,7 +21,7 @@ run_action(:asking) do
20
21
  ask :devise
21
22
  ask :admin
22
23
  ask :front_end
23
- ask :angular_admin
24
+ ask :vue_admin
24
25
  ask :mailer
25
26
  ask :background_processor
26
27
  ask :schedule
@@ -47,6 +48,7 @@ run_action(:recipe_loading) do
47
48
  create :annotate
48
49
  create :data_migrate
49
50
  create :listen
51
+ create :node
50
52
  create :ruby
51
53
  create :yarn
52
54
  create :editorconfig
@@ -58,7 +60,7 @@ run_action(:recipe_loading) do
58
60
  create :better_errors
59
61
  create :devise
60
62
  create :admin
61
- create :angular_admin
63
+ create :vue_admin
62
64
  create :seeds
63
65
  create :error_reporting
64
66
  create :pundit
@@ -1,8 +1,9 @@
1
1
  module Potassium
2
- VERSION = "5.2.3"
3
- RUBY_VERSION = "2.5.5"
4
- RAILS_VERSION = "~> 5.2.1"
2
+ VERSION = "6.0.0"
3
+ RUBY_VERSION = "2.7.0"
4
+ RAILS_VERSION = "~> 6.0.2"
5
5
  RUBOCOP_VERSION = "~> 0.65.0"
6
6
  POSTGRES_VERSION = "11.3"
7
7
  MYSQL_VERSION = "5.7"
8
+ NODE_VERSION = "12"
8
9
  end
@@ -18,16 +18,17 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_development_dependency "bundler", "~> 1.7"
21
+ spec.add_development_dependency "bundler", "~> 2.0"
22
+ spec.add_development_dependency "pry", "~> 0.10.3"
22
23
  spec.add_development_dependency "rake", "~> 10.0"
23
24
  spec.add_development_dependency "rspec", "~> 3.4.0"
24
- spec.add_development_dependency "pry", "~> 0.10.3"
25
+ spec.add_development_dependency "rspec_junit_formatter"
25
26
  spec.add_development_dependency "rubocop", Potassium::RUBOCOP_VERSION
26
27
  spec.add_development_dependency "rubocop-rspec"
27
- spec.add_runtime_dependency "rails", Potassium::RAILS_VERSION
28
+ spec.add_runtime_dependency "gems", "~> 0.8"
28
29
  spec.add_runtime_dependency "gli", "~> 2.12.2"
29
30
  spec.add_runtime_dependency "inquirer", "~> 0.2"
30
- spec.add_runtime_dependency "gems", "~> 0.8"
31
- spec.add_runtime_dependency "semantic", "~> 1.4"
32
31
  spec.add_runtime_dependency "levenshtein", "~> 0.2"
32
+ spec.add_runtime_dependency "rails", Potassium::RAILS_VERSION
33
+ spec.add_runtime_dependency "semantic", "~> 1.4"
33
34
  end
@@ -28,7 +28,7 @@ RSpec.describe "DatabaseContainer" do
28
28
  .to include("DB_PORT=$(make services-port SERVICE=#{service_name} PORT=#{db_port})")
29
29
  expect(env_file).to include("DB_HOST=127.0.0.1")
30
30
  expect(File.exist?("#{project_path}/Makefile")).to be true
31
- expect(setup_file).to include("make services-up")
31
+ expect(setup_file).to include("docker-compose up -d")
32
32
  end
33
33
  end
34
34
  end
@@ -34,39 +34,35 @@ RSpec.describe "File Storage" do
34
34
  end
35
35
  end
36
36
 
37
- context "when selecting paperclip" do
37
+ context "when selecting shrine" do
38
38
  before :all do
39
39
  drop_dummy_database
40
40
  remove_project_directory
41
- create_dummy_project(storage: :paperclip)
41
+ create_dummy_project(storage: :shrine)
42
42
  end
43
43
 
44
- it "adds the Paperclip gem to Gemfile" do
45
- gemfile_content = IO.read("#{project_path}/Gemfile")
46
- expect(gemfile_content).to include("gem 'paperclip'")
47
- end
48
-
49
- it "adds the aws-sdk-s3 gem to Gemfile" do
44
+ it "adds the aws-sdk-s3, shrine and marcel gems to Gemfile" do
50
45
  gemfile_content = IO.read("#{project_path}/Gemfile")
51
46
  expect(gemfile_content).to include("gem 'aws-sdk-s3'")
47
+ expect(gemfile_content).to include("gem 'shrine'")
48
+ expect(gemfile_content).to include("gem 'marcel'")
52
49
  end
53
50
 
54
51
  it "adds brief to README file" do
55
52
  content = IO.read("#{project_path}/README.md")
56
- expect(content).to include("Paperclip")
53
+ expect(content).to include("Shrine")
57
54
  end
58
55
 
59
- it "adds local file storage path to gitignore" do
60
- content = IO.read("#{project_path}/.gitignore")
61
- expect(content).to include("/public/system/*")
56
+ it "adds shrine initializer" do
57
+ expect(File.exist?("#{project_path}/config/initializers/shrine.rb")).to be true
62
58
  end
63
59
 
64
- it "adds paperclip_defaults config to production" do
65
- content = IO.read("#{project_path}/config/environments/production.rb")
66
- expect(content).to include("config.paperclip_defaults")
60
+ it "adds base_uploader and image_uploader" do
61
+ expect(File.exist?("#{project_path}/app/uploaders/base_uploader.rb")).to be true
62
+ expect(File.exist?("#{project_path}/app/uploaders/image_uploader.rb")).to be true
67
63
  end
68
64
 
69
- it "adds S3 bucket ENV var" do
65
+ it "adds S3 bucket ENV vars" do
70
66
  content = IO.read("#{project_path}/.env.development")
71
67
  expect(content).to include("S3_BUCKET=")
72
68
  end
@@ -0,0 +1,74 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "Front end" do
4
+ before :all do
5
+ drop_dummy_database
6
+ remove_project_directory
7
+ end
8
+
9
+ let(:application_css_path) { "#{project_path}/app/javascript/css/application.css" }
10
+ let(:gemfile) { IO.read("#{project_path}/Gemfile") }
11
+ let(:node_modules_file) { IO.read("#{project_path}/package.json") }
12
+ let(:application_js_file) { IO.read("#{project_path}/app/javascript/packs/application.js") }
13
+ let(:layout_file) { IO.read("#{project_path}/app/views/layouts/application.html.erb") }
14
+ let(:application_css_file) { IO.read(application_css_path) }
15
+ let(:tailwind_config_file) { IO.read("#{project_path}/tailwind.config.js") }
16
+ let(:rails_css_file) { IO.read("#{project_path}/app/assets/stylesheets/application.css") }
17
+
18
+ it "creates a project without a front end framework" do
19
+ remove_project_directory
20
+ create_dummy_project("front_end" => "None")
21
+ expect(gemfile).to include('webpacker')
22
+ expect(File).not_to exist(application_css_path)
23
+ end
24
+
25
+ context "with vue" do
26
+ before(:all) do
27
+ remove_project_directory
28
+ create_dummy_project("front_end" => "vue")
29
+ end
30
+
31
+ it "creates a project with vue in compiler mode as frontend framework" do
32
+ expect(gemfile).to include('webpacker')
33
+ expect(node_modules_file).to include("\"vue\"")
34
+ expect(application_js_file).to include('vue/dist/vue.esm')
35
+ expect(application_js_file).to include("el: '#vue-app'")
36
+ expect(layout_file).to include('id="vue-app"')
37
+ end
38
+
39
+ it "creates a project with only one js pack tag" do
40
+ expect(layout_file.scan("javascript_pack_tag").length).to eq(1)
41
+ end
42
+
43
+ it "creates a vue project with client css" do
44
+ expect(application_js_file).to include("import '../css/application.css';")
45
+ expect(layout_file).to include("<%= stylesheet_pack_tag 'application' %>")
46
+ expect(rails_css_file).not_to include('*= require_tree', '*= require_self')
47
+ end
48
+
49
+ it "creates a vue project with tailwindcss" do
50
+ expect(node_modules_file).to include("\"tailwindcss\"")
51
+ expect(application_css_file).to include(
52
+ "@import 'tailwindcss/base';",
53
+ "@import 'tailwindcss/components';"
54
+ )
55
+ expect(tailwind_config_file).to include('module.exports')
56
+ end
57
+ end
58
+
59
+ context "with angular" do
60
+ before(:all) do
61
+ remove_project_directory
62
+ create_dummy_project("front_end" => "angular")
63
+ end
64
+
65
+ it "creates a project without vue as front end framework" do
66
+ expect(gemfile).to include('webpacker')
67
+ expect(node_modules_file).to include("\"@angular/core\"")
68
+ end
69
+
70
+ it "creates application_js_file for tailwind without vue" do
71
+ expect(application_js_file).to include("import '../css/application.css';")
72
+ end
73
+ end
74
+ end
@@ -29,7 +29,7 @@ RSpec.describe "A new project" do
29
29
  it "configures the correct ruby version" do
30
30
  ruby_version_file = IO.read("#{project_path}/.ruby-version")
31
31
 
32
- expect(ruby_version_file).to eq("2.5")
32
+ expect(ruby_version_file).to eq("2.7")
33
33
  end
34
34
 
35
35
  it "setup ssl" do
@@ -0,0 +1,28 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "Node" do
4
+ let(:version) { "12" }
5
+
6
+ before(:all) do
7
+ drop_dummy_database
8
+ remove_project_directory
9
+ create_dummy_project
10
+ end
11
+
12
+ it "adds engine with node version to package.json" do
13
+ package_json_path = "#{project_path}/package.json"
14
+ expect(File).to be_file(package_json_path)
15
+ json_file = File.read(package_json_path)
16
+ js_package = JSON.parse(json_file)
17
+ expect(js_package).to have_key("engines")
18
+ expect(js_package["engines"]).to have_key("node")
19
+ expect(js_package["engines"]["node"]).to eq("#{version}.x")
20
+ end
21
+
22
+ it "adds .node-version with correct version" do
23
+ node_version_path = "#{project_path}/.node-version"
24
+ expect(File).to be_file(node_version_path)
25
+ node_version_file = File.read(node_version_path)
26
+ expect(node_version_file).to eq(version)
27
+ end
28
+ end
@@ -17,21 +17,10 @@ RSpec.describe "PowerTypes" do
17
17
  expect(readme).to include("Power-Types")
18
18
  end
19
19
 
20
- it "adds commands directory" do
21
- commands_directory = "#{project_path}/app/commands"
22
- expect(File.directory?(commands_directory)).to eq(true)
23
- end
24
-
25
- it "adds services directory" do
26
- services_directory = "#{project_path}/app/services"
27
- expect(File.directory?(services_directory)).to eq(true)
28
- end
29
- it "adds utils directory" do
30
- utils_directory = "#{project_path}/app/utils"
31
- expect(File.directory?(utils_directory)).to eq(true)
32
- end
33
- it "adds values directory" do
34
- values_directory = "#{project_path}/app/values"
35
- expect(File.directory?(values_directory)).to eq(true)
20
+ it "adds every power type directory" do
21
+ [:commands, :services, :observers, :utils, :values].each do |type|
22
+ commands_directory = "#{project_path}/app/#{type}"
23
+ expect(File.directory?(commands_directory)).to eq(true)
24
+ end
36
25
  end
37
26
  end
@@ -0,0 +1,47 @@
1
+ require "spec_helper"
2
+ require "pry"
3
+ RSpec.describe "VueAdmin" do
4
+ before(:all) do
5
+ drop_dummy_database
6
+ remove_project_directory
7
+ create_dummy_project(:vue_admin => true, "admin" => true, "devise" => true)
8
+ end
9
+
10
+ it "adds component integration to active admin initializer" do
11
+ admin_initializer_path = "#{project_path}/config/initializers/active_admin.rb"
12
+ expect(File).to be_file(admin_initializer_path)
13
+ initializer_file = File.read(admin_initializer_path)
14
+ expect(initializer_file).to include("AUTO_BUILD_ELEMENTS")
15
+ end
16
+
17
+ it "adds layout tags to active admin layout initializer" do
18
+ initializer_path = "#{project_path}/config/initializers/init_activeadmin_vue.rb"
19
+ expect(File).to be_file(initializer_path)
20
+ end
21
+
22
+ it "adds vue_component to library" do
23
+ vue_component_lib_path = "#{project_path}/lib/vue_component.rb"
24
+ expect(File).to be_file(vue_component_lib_path)
25
+ vue_component_lib = File.read(vue_component_lib_path)
26
+ expect(vue_component_lib).to include("VueComponent")
27
+ end
28
+
29
+ it "adds admin_application pack to packs" do
30
+ application_pack_path = "#{project_path}/app/javascript/packs/admin_application.js"
31
+ expect(File).to be_file(application_pack_path)
32
+ end
33
+
34
+ it "adds admin_component to vue components" do
35
+ application_pack_path = "#{project_path}/app/javascript/components/admin-component.vue"
36
+ expect(File).to be_file(application_pack_path)
37
+ end
38
+
39
+ it "installs vue to project" do
40
+ package_json_path = "#{project_path}/package.json"
41
+ expect(File).to be_file(package_json_path)
42
+ json_file = File.read(package_json_path)
43
+ js_package = JSON.parse(json_file)
44
+ expect(js_package).to have_key("dependencies")
45
+ expect(js_package["dependencies"]).to have_key("vue")
46
+ end
47
+ end