potassium 5.2.3 → 6.0.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.
- checksums.yaml +4 -4
- data/.circleci/config.yml +22 -9
- data/.node-version +1 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +26 -0
- data/docs/DSL.md +5 -5
- data/lib/potassium/assets/.circleci/config.yml.erb +102 -0
- data/lib/potassium/assets/.eslintrc.json +343 -0
- data/lib/potassium/assets/.rubocop.yml +515 -0
- data/lib/potassium/assets/.stylelintrc.json +46 -0
- data/lib/potassium/assets/Dockerfile.ci +1 -1
- data/lib/potassium/assets/Makefile.erb +6 -32
- data/lib/potassium/assets/README.yml +51 -7
- data/lib/potassium/assets/active_admin/admin-component.vue +35 -0
- data/lib/potassium/assets/active_admin/admin_application.js +14 -0
- data/lib/potassium/assets/active_admin/init_activeadmin_vue.rb +10 -0
- data/lib/potassium/assets/api/base_controller.rb +1 -3
- data/lib/potassium/assets/app/javascript/app.spec.js +14 -0
- data/lib/potassium/assets/app/uploaders/base_uploader.rb +13 -0
- data/lib/potassium/assets/app/uploaders/image_uploader.rb +5 -0
- data/lib/potassium/assets/bin/cibuild.erb +18 -1
- data/lib/potassium/assets/bin/setup.erb +1 -1
- data/lib/potassium/assets/config/database_mysql.yml.erb +2 -2
- data/lib/potassium/assets/config/database_postgresql.yml.erb +2 -2
- data/lib/potassium/assets/config/shrine.rb +33 -0
- data/lib/potassium/assets/docker-compose.ci.yml +1 -0
- data/lib/potassium/assets/lib/tasks/auto_annotate_models.rake +2 -1
- data/lib/potassium/assets/package.json +4 -1
- data/lib/potassium/cli/commands/create.rb +1 -0
- data/lib/potassium/cli_options.rb +6 -6
- data/lib/potassium/helpers/template-helpers.rb +4 -0
- data/lib/potassium/recipes/admin.rb +3 -3
- data/lib/potassium/recipes/annotate.rb +1 -1
- data/lib/potassium/recipes/ci.rb +1 -1
- data/lib/potassium/recipes/database_container.rb +5 -4
- data/lib/potassium/recipes/draper.rb +1 -1
- data/lib/potassium/recipes/file_storage.rb +15 -33
- data/lib/potassium/recipes/front_end.rb +128 -5
- data/lib/potassium/recipes/mailer.rb +5 -2
- data/lib/potassium/recipes/node.rb +21 -0
- data/lib/potassium/recipes/rack_cors.rb +18 -15
- data/lib/potassium/recipes/schedule.rb +1 -1
- data/lib/potassium/recipes/style.rb +21 -3
- data/lib/potassium/recipes/vue_admin.rb +124 -0
- data/lib/potassium/templates/application.rb +4 -2
- data/lib/potassium/version.rb +4 -3
- data/potassium.gemspec +6 -5
- data/spec/features/database_container_spec.rb +1 -1
- data/spec/features/file_storage_spec.rb +12 -16
- data/spec/features/front_end_spec.rb +74 -0
- data/spec/features/new_project_spec.rb +1 -1
- data/spec/features/node_spec.rb +28 -0
- data/spec/features/power_types_spec.rb +5 -16
- data/spec/features/vue_admin_spec.rb +47 -0
- data/spec/support/potassium_test_helpers.rb +23 -9
- metadata +56 -29
- data/lib/potassium/assets/.circleci/config.yml +0 -20
- data/lib/potassium/assets/active_admin/active_admin.js.coffee +0 -4
- data/lib/potassium/assets/active_admin/init_activeadmin_angular.rb +0 -8
- data/lib/potassium/assets/testing/paperclip.rb +0 -59
- data/lib/potassium/recipes/angular_admin.rb +0 -56
- data/spec/features/front_end.rb +0 -33
@@ -16,7 +16,7 @@ module Potassium::CliOptions # rubocop:disable Metrics/ModuleLength
|
|
16
16
|
type: :flag,
|
17
17
|
name: [:email_service, :email],
|
18
18
|
desc: "Decides which email adapter to use. Available: aws_ses, sendgrid, none",
|
19
|
-
default_test_value: "
|
19
|
+
default_test_value: "None"
|
20
20
|
},
|
21
21
|
{
|
22
22
|
type: :switch,
|
@@ -44,8 +44,8 @@ module Potassium::CliOptions # rubocop:disable Metrics/ModuleLength
|
|
44
44
|
},
|
45
45
|
{
|
46
46
|
type: :switch,
|
47
|
-
name:
|
48
|
-
desc: "Whether to use
|
47
|
+
name: :vue_admin,
|
48
|
+
desc: "Whether to use Vue within ActiveAdmin or not",
|
49
49
|
negatable: true,
|
50
50
|
default_value: "none",
|
51
51
|
default_test_value: false
|
@@ -69,9 +69,9 @@ module Potassium::CliOptions # rubocop:disable Metrics/ModuleLength
|
|
69
69
|
{
|
70
70
|
type: :flag,
|
71
71
|
name: "storage",
|
72
|
-
desc: "Decides which file storage to use. Available: active_storage,
|
72
|
+
desc: "Decides which file storage to use. Available: active_storage, shrine, none",
|
73
73
|
default_value: "none",
|
74
|
-
default_test_value: "
|
74
|
+
default_test_value: "None"
|
75
75
|
},
|
76
76
|
{
|
77
77
|
type: :switch,
|
@@ -85,7 +85,7 @@ module Potassium::CliOptions # rubocop:disable Metrics/ModuleLength
|
|
85
85
|
type: :flag,
|
86
86
|
name: "background_processor",
|
87
87
|
desc: "Decides which background processor to use. Available: sidekiq, delayed_job, none",
|
88
|
-
default_test_value: "
|
88
|
+
default_test_value: "None"
|
89
89
|
},
|
90
90
|
{
|
91
91
|
type: :switch,
|
@@ -32,10 +32,10 @@ class Recipes::Admin < Rails::AppBuilder
|
|
32
32
|
private
|
33
33
|
|
34
34
|
def add_active_admin
|
35
|
-
gather_gem 'activeadmin', '~>
|
35
|
+
gather_gem 'activeadmin', '~> 2.6'
|
36
36
|
gather_gem 'activeadmin_addons'
|
37
|
-
gather_gem 'active_skin'
|
38
|
-
|
37
|
+
gather_gem 'active_skin', github: 'SoftwareBrothers/active_skin'
|
38
|
+
add_readme_section :internal_dependencies, :active_admin
|
39
39
|
after(:gem_install, wrap_in_action: :admin_install) do
|
40
40
|
generate "active_admin:install"
|
41
41
|
line = "ActiveAdmin.setup do |config|"
|
data/lib/potassium/recipes/ci.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
class Recipes::Ci < Rails::AppBuilder
|
2
2
|
def create
|
3
3
|
copy_file '../assets/Dockerfile.ci', 'Dockerfile.ci'
|
4
|
-
|
4
|
+
template '../assets/.circleci/config.yml.erb', '.circleci/config.yml'
|
5
5
|
|
6
6
|
template '../assets/bin/cibuild.erb', 'bin/cibuild'
|
7
7
|
run "chmod a+x bin/cibuild"
|
@@ -28,16 +28,17 @@ class Recipes::DatabaseContainer < Rails::AppBuilder
|
|
28
28
|
YAML
|
29
29
|
|
30
30
|
def create
|
31
|
-
|
31
|
+
db_type = get(:database)
|
32
|
+
return if [:None, :none].include? db_type.to_sym
|
32
33
|
|
34
|
+
copy_file '../assets/docker-compose.yml', 'docker-compose.yml'
|
33
35
|
compose = DockerHelpers.new('docker-compose.yml')
|
34
36
|
|
35
|
-
db_type = get(:database)
|
36
37
|
compose.add_service(db_type.to_s, self.class.const_get("#{db_type}_service".upcase))
|
37
38
|
compose.add_volume("#{db_type}_data")
|
38
39
|
template '../assets/Makefile.erb', 'Makefile'
|
39
40
|
|
40
|
-
run
|
41
|
+
run "docker-compose up -d"
|
41
42
|
|
42
43
|
set_env(db_type, CONTAINER_VARS[db_type][:port], CONTAINER_VARS[db_type][:user])
|
43
44
|
set_dot_env(db_type, CONTAINER_VARS[db_type][:port], CONTAINER_VARS[db_type][:user])
|
@@ -53,7 +54,7 @@ class Recipes::DatabaseContainer < Rails::AppBuilder
|
|
53
54
|
setup_text = # setup file is templated on project creation, manual install is needed
|
54
55
|
<<~TEXT
|
55
56
|
# Set up required services
|
56
|
-
|
57
|
+
docker-compose up -d
|
57
58
|
|
58
59
|
TEXT
|
59
60
|
|
@@ -2,7 +2,7 @@ class Recipes::FileStorage < Rails::AppBuilder
|
|
2
2
|
def ask
|
3
3
|
storages = {
|
4
4
|
active_storage: 'ActiveStorage',
|
5
|
-
|
5
|
+
shrine: 'Shrine',
|
6
6
|
none: 'None, thanks'
|
7
7
|
}
|
8
8
|
|
@@ -14,45 +14,20 @@ class Recipes::FileStorage < Rails::AppBuilder
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def create
|
17
|
-
add_chosen_storage
|
17
|
+
add_chosen_storage
|
18
18
|
end
|
19
19
|
|
20
20
|
def install
|
21
21
|
ask
|
22
|
-
add_chosen_storage
|
22
|
+
add_chosen_storage
|
23
23
|
end
|
24
24
|
|
25
25
|
def installed?
|
26
|
-
|
26
|
+
file_exist?('config/storage.yml')
|
27
27
|
end
|
28
28
|
|
29
29
|
private
|
30
30
|
|
31
|
-
def paperclip_config
|
32
|
-
@paperclip_config ||=
|
33
|
-
<<~RUBY
|
34
|
-
config.paperclip_defaults = {
|
35
|
-
storage: :s3,
|
36
|
-
s3_protocol: 'https',
|
37
|
-
s3_region: ENV.fetch('AWS_REGION', 'us-east-1'),
|
38
|
-
s3_credentials: {
|
39
|
-
bucket: ENV['S3_BUCKET']
|
40
|
-
}
|
41
|
-
}
|
42
|
-
RUBY
|
43
|
-
end
|
44
|
-
|
45
|
-
def config_rspec_for_paperclip
|
46
|
-
copy_file '../assets/testing/platanus.png', 'spec/assets/platanus.png'
|
47
|
-
copy_file '../assets/testing/paperclip.rb', 'spec/support/paperclip.rb'
|
48
|
-
end
|
49
|
-
|
50
|
-
def add_paperclip
|
51
|
-
gather_gem 'paperclip', '~> 6.0'
|
52
|
-
application paperclip_config, env: 'production'
|
53
|
-
append_to_file '.gitignore', "/public/system/*\n"
|
54
|
-
end
|
55
|
-
|
56
31
|
def add_active_storage
|
57
32
|
after(:gem_install) { run('bundle exec rails active_storage:install') }
|
58
33
|
copy_file('../assets/config/storage.yml', 'config/storage.yml', force: true)
|
@@ -62,22 +37,29 @@ class Recipes::FileStorage < Rails::AppBuilder
|
|
62
37
|
end
|
63
38
|
end
|
64
39
|
|
40
|
+
def add_shrine
|
41
|
+
gather_gem('shrine', '~> 3.0')
|
42
|
+
gather_gem('marcel', '~> 0.3.3')
|
43
|
+
copy_file('../assets/config/shrine.rb', 'config/initializers/shrine.rb', force: true)
|
44
|
+
copy_file('../assets/app/uploaders/image_uploader.rb', 'app/uploaders/image_uploader.rb')
|
45
|
+
copy_file('../assets/app/uploaders/base_uploader.rb', 'app/uploaders/base_uploader.rb')
|
46
|
+
end
|
47
|
+
|
65
48
|
def common_setup
|
66
49
|
gather_gem 'aws-sdk-s3', '~> 1.0'
|
67
50
|
add_readme_section :internal_dependencies, get(:storage)
|
68
51
|
append_to_file '.env.development', "S3_BUCKET=\n"
|
69
52
|
end
|
70
53
|
|
71
|
-
def add_chosen_storage
|
54
|
+
def add_chosen_storage
|
72
55
|
return if [:none, :None].include? get(:storage).to_sym
|
73
56
|
|
74
57
|
common_setup
|
75
58
|
case get(:storage)
|
76
|
-
when :paperclip
|
77
|
-
add_paperclip
|
78
|
-
config_rspec_for_paperclip if !check_rspec || gem_exists?(/rspec-rails/)
|
79
59
|
when :active_storage
|
80
60
|
add_active_storage
|
61
|
+
when :shrine
|
62
|
+
add_shrine
|
81
63
|
end
|
82
64
|
end
|
83
65
|
end
|
@@ -17,15 +17,19 @@ class Recipes::FrontEnd < Rails::AppBuilder
|
|
17
17
|
def create
|
18
18
|
return if [:none, :None].include? get(:front_end).to_sym
|
19
19
|
|
20
|
-
gather_gem 'webpacker'
|
21
|
-
|
22
20
|
recipe = self
|
23
21
|
after(:gem_install) do
|
24
22
|
value = get(:front_end)
|
25
23
|
run "rails webpacker:install"
|
26
24
|
run "rails webpacker:install:#{value}" if value
|
27
25
|
|
28
|
-
|
26
|
+
if value == :vue
|
27
|
+
recipe.setup_vue_with_compiler_build
|
28
|
+
recipe.setup_jest
|
29
|
+
end
|
30
|
+
recipe.add_responsive_meta_tag
|
31
|
+
recipe.setup_tailwind
|
32
|
+
add_readme_header :webpack
|
29
33
|
end
|
30
34
|
end
|
31
35
|
|
@@ -46,9 +50,7 @@ class Recipes::FrontEnd < Rails::AppBuilder
|
|
46
50
|
remove_file "app/javascript/packs/hello_vue.js"
|
47
51
|
create_file application_js, application_js_content, force: true
|
48
52
|
|
49
|
-
js_pack_tag = "\n <%= javascript_pack_tag 'application' %>\n"
|
50
53
|
layout_file = "app/views/layouts/application.html.erb"
|
51
|
-
insert_into_file layout_file, js_pack_tag, after: "<%= csrf_meta_tags %>"
|
52
54
|
insert_into_file(
|
53
55
|
layout_file,
|
54
56
|
"<div id=\"vue-app\">\n <app></app>\n ",
|
@@ -57,6 +59,30 @@ class Recipes::FrontEnd < Rails::AppBuilder
|
|
57
59
|
insert_into_file layout_file, "\n </div>", after: "<%= yield %>"
|
58
60
|
end
|
59
61
|
|
62
|
+
def add_responsive_meta_tag
|
63
|
+
tag = "\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n"
|
64
|
+
layout_file = "app/views/layouts/application.html.erb"
|
65
|
+
insert_into_file layout_file, tag, after: "<%= csrf_meta_tags %>"
|
66
|
+
end
|
67
|
+
|
68
|
+
def setup_tailwind
|
69
|
+
run 'bin/yarn add tailwindcss'
|
70
|
+
setup_client_css
|
71
|
+
remove_server_css_requires
|
72
|
+
setup_tailwind_requirements
|
73
|
+
end
|
74
|
+
|
75
|
+
def setup_jest
|
76
|
+
run 'bin/yarn add jest vue-jest babel-jest @vue/test-utils jest-serializer-vue babel-core@^7.0.0-bridge.0 --dev'
|
77
|
+
json_file = File.read(Pathname.new("package.json"))
|
78
|
+
js_package = JSON.parse(json_file)
|
79
|
+
js_package = js_package.merge(jest_config)
|
80
|
+
json_string = JSON.pretty_generate(js_package)
|
81
|
+
create_file 'package.json', json_string, force: true
|
82
|
+
|
83
|
+
copy_file '../assets/app/javascript/app.spec.js', 'app/javascript/app.spec.js'
|
84
|
+
end
|
85
|
+
|
60
86
|
private
|
61
87
|
|
62
88
|
def frameworks(framework)
|
@@ -68,6 +94,42 @@ class Recipes::FrontEnd < Rails::AppBuilder
|
|
68
94
|
frameworks[framework]
|
69
95
|
end
|
70
96
|
|
97
|
+
def setup_client_css
|
98
|
+
application_css = 'app/javascript/css/application.css'
|
99
|
+
create_file application_css, "", force: true
|
100
|
+
|
101
|
+
stylesheet_pack_tag = "\n <%= stylesheet_pack_tag 'application' %>\n "
|
102
|
+
layout_file = "app/views/layouts/application.html.erb"
|
103
|
+
insert_into_file layout_file, stylesheet_pack_tag, before: "</head>"
|
104
|
+
|
105
|
+
application_js = 'app/javascript/packs/application.js'
|
106
|
+
if get(:front_end) != :vue
|
107
|
+
create_file application_js, "import '../css/application.css';\n", force: true
|
108
|
+
else
|
109
|
+
insert_into_file(
|
110
|
+
application_js,
|
111
|
+
"\nimport '../css/application.css';",
|
112
|
+
after: "import App from '../app.vue';"
|
113
|
+
)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def setup_tailwind_requirements
|
118
|
+
application_css = 'app/javascript/css/application.css'
|
119
|
+
insert_into_file application_css, tailwind_client_css
|
120
|
+
|
121
|
+
tailwind_config = 'tailwind.config.js'
|
122
|
+
create_file tailwind_config, tailwind_config_content, force: true
|
123
|
+
|
124
|
+
postcss_file = 'postcss.config.js'
|
125
|
+
insert_into_file postcss_file, postcss_require_tailwind, after: "plugins: [\n"
|
126
|
+
end
|
127
|
+
|
128
|
+
def remove_server_css_requires
|
129
|
+
assets_css_file = 'app/assets/stylesheets/application.css'
|
130
|
+
gsub_file(assets_css_file, " *= require_tree .\n *= require_self\n", "")
|
131
|
+
end
|
132
|
+
|
71
133
|
def application_js_content
|
72
134
|
<<~JS
|
73
135
|
import Vue from 'vue/dist/vue.esm';
|
@@ -83,4 +145,65 @@ class Recipes::FrontEnd < Rails::AppBuilder
|
|
83
145
|
});
|
84
146
|
JS
|
85
147
|
end
|
148
|
+
|
149
|
+
def tailwind_client_css
|
150
|
+
<<~CSS
|
151
|
+
@import 'tailwindcss/base';
|
152
|
+
@import 'tailwindcss/components';
|
153
|
+
@import 'tailwindcss/utilities';
|
154
|
+
CSS
|
155
|
+
end
|
156
|
+
|
157
|
+
def tailwind_config_content
|
158
|
+
<<~JS
|
159
|
+
/* eslint-disable no-undef */
|
160
|
+
module.exports = {
|
161
|
+
theme: {
|
162
|
+
extend: {},
|
163
|
+
},
|
164
|
+
variants: {},
|
165
|
+
plugins: [],
|
166
|
+
};
|
167
|
+
JS
|
168
|
+
end
|
169
|
+
|
170
|
+
def postcss_require_tailwind
|
171
|
+
<<-JS.gsub(/^ {4}/, ' ')
|
172
|
+
require('tailwindcss'),
|
173
|
+
require('autoprefixer'),
|
174
|
+
JS
|
175
|
+
end
|
176
|
+
|
177
|
+
def jest_config
|
178
|
+
{
|
179
|
+
"scripts": {
|
180
|
+
"test": "jest",
|
181
|
+
"test:watch": "jest --watch"
|
182
|
+
},
|
183
|
+
"jest": {
|
184
|
+
"roots": [
|
185
|
+
"app/javascript"
|
186
|
+
],
|
187
|
+
"moduleDirectories": [
|
188
|
+
"node_modules",
|
189
|
+
"app/javascript"
|
190
|
+
],
|
191
|
+
"moduleNameMapper": {
|
192
|
+
"^@/(.*)$": "app/javascript/$1"
|
193
|
+
},
|
194
|
+
"moduleFileExtensions": [
|
195
|
+
"js",
|
196
|
+
"json",
|
197
|
+
"vue"
|
198
|
+
],
|
199
|
+
"transform": {
|
200
|
+
"^.+\\.js$": "<rootDir>/node_modules/babel-jest",
|
201
|
+
".*\\.(vue)$": "<rootDir>/node_modules/vue-jest"
|
202
|
+
},
|
203
|
+
"snapshotSerializers": [
|
204
|
+
"<rootDir>/node_modules/jest-serializer-vue"
|
205
|
+
]
|
206
|
+
}
|
207
|
+
}
|
208
|
+
end
|
86
209
|
end
|
@@ -24,8 +24,11 @@ class Recipes::Mailer < Rails::AppBuilder
|
|
24
24
|
dependencies(email_service)
|
25
25
|
config(email_service)
|
26
26
|
|
27
|
-
|
28
|
-
|
27
|
+
background_processor_recipe = load_recipe(:background_processor)
|
28
|
+
background_processor_answer = get(:background_processor)
|
29
|
+
|
30
|
+
background_processor_recipe.add_sidekiq unless background_processor_recipe.installed? ||
|
31
|
+
background_processor_answer
|
29
32
|
end
|
30
33
|
|
31
34
|
def install
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'semantic'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
class Recipes::Node < Rails::AppBuilder
|
6
|
+
def create
|
7
|
+
info "Using node version LTS #{version}"
|
8
|
+
create_file '.node-version', version, force: true
|
9
|
+
json_file = File.read(Pathname.new("package.json"))
|
10
|
+
js_package = JSON.parse(json_file)
|
11
|
+
js_package["engines"] = { "node" => "#{version}.x" }
|
12
|
+
json_string = JSON.pretty_generate(js_package)
|
13
|
+
create_file 'package.json', json_string, force: true
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def version
|
19
|
+
Potassium::NODE_VERSION
|
20
|
+
end
|
21
|
+
end
|
@@ -4,23 +4,26 @@ class Recipes::RackCors < Rails::AppBuilder
|
|
4
4
|
end
|
5
5
|
|
6
6
|
def create
|
7
|
-
gather_gem('rack-cors', '~>
|
7
|
+
gather_gem('rack-cors', '~> 1.1')
|
8
|
+
recipe = self
|
8
9
|
after(:gem_install) do
|
9
|
-
rack_cors_config
|
10
|
-
|
11
|
-
|
12
|
-
allow do
|
13
|
-
origins '*'
|
14
|
-
resource '*',
|
15
|
-
headers: :any,
|
16
|
-
expose: ['X-Page', 'X-PageTotal'],
|
17
|
-
methods: [:get, :post, :delete, :put, :options]
|
18
|
-
end
|
19
|
-
end
|
10
|
+
application recipe.rack_cors_config
|
11
|
+
end
|
12
|
+
end
|
20
13
|
|
21
|
-
|
14
|
+
def rack_cors_config
|
15
|
+
<<~RUBY
|
16
|
+
config.middleware.insert_before 0, Rack::Cors do
|
17
|
+
allow do
|
18
|
+
origins '*'
|
19
|
+
resource '/public/*', headers: :any, methods: :get
|
20
|
+
resource '/api/*',
|
21
|
+
headers: :any,
|
22
|
+
expose: ['X-Page', 'X-PageTotal'],
|
23
|
+
methods: [:get, :post, :patch, :put, :delete, :options]
|
24
|
+
end
|
25
|
+
end
|
22
26
|
|
23
|
-
|
24
|
-
end
|
27
|
+
RUBY
|
25
28
|
end
|
26
29
|
end
|