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.
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
@@ -0,0 +1,46 @@
1
+ {
2
+ "rules": {
3
+ "declaration-bang-space-before": "always",
4
+ "declaration-bang-space-after": "never",
5
+ "declaration-property-value-blacklist": {
6
+ "/^border/": ["none"]
7
+ },
8
+ "color-named": "never",
9
+ "declaration-block-no-duplicate-properties": true,
10
+ "rule-empty-line-before": ["always-multi-line", {
11
+ "except": ["after-single-line-comment", "first-nested"]
12
+ }],
13
+ "block-no-empty": true,
14
+ "no-missing-end-of-source-newline": true,
15
+ "color-hex-length": "short",
16
+ "color-hex-case": "lower",
17
+ "color-no-invalid-hex": true,
18
+ "selector-max-id": 0,
19
+ "declaration-no-important": true,
20
+ "indentation": 2,
21
+ "number-leading-zero": "never",
22
+ "no-duplicate-selectors": true,
23
+ "max-nesting-depth": 3,
24
+ "selector-pseudo-element-colon-notation": "double",
25
+ "selector-no-qualifying-type": true,
26
+ "shorthand-property-no-redundant-values": true,
27
+ "declaration-block-semicolon-newline-after": "always-multi-line",
28
+ "selector-list-comma-newline-after": "always",
29
+ "function-comma-space-after": "always-single-line",
30
+ "declaration-colon-space-after": "always",
31
+ "declaration-colon-space-before": "never",
32
+ "block-opening-brace-space-before": "always",
33
+ "function-parentheses-space-inside": "never",
34
+ "string-quotes": "single",
35
+ "declaration-block-trailing-semicolon": "always",
36
+ "no-eol-whitespace": true,
37
+ "number-no-trailing-zeros": true,
38
+ "function-url-quotes": "always",
39
+ "property-no-vendor-prefix": true,
40
+ "selector-no-vendor-prefix": true,
41
+ "media-feature-name-no-vendor-prefix": true,
42
+ "at-rule-no-vendor-prefix": true,
43
+ "value-no-vendor-prefix": true,
44
+ "length-zero-no-unit": true
45
+ }
46
+ }
@@ -1,4 +1,4 @@
1
- FROM platanus/ruby:2.5
1
+ FROM platanus/ruby:2.7
2
2
 
3
3
  RUN mkdir /app
4
4
  WORKDIR /app
@@ -1,7 +1,4 @@
1
- PROJECT ?= <%= get(:underscorized_app_name) %>
2
- DOCKER_COMPOSE_FILE ?= docker-compose.yml
3
-
4
- DOCKER_COMPOSE_ARGS ?= -p $(PROJECT) -f $(DOCKER_COMPOSE_FILE)
1
+ PROJECT ?= <%= get(:dasherized_app_name) %>
5
2
 
6
3
  SHELL := /bin/bash
7
4
 
@@ -11,39 +8,16 @@ BOLD ?= $(shell tput bold)
11
8
  NORMAL ?= $(shell tput sgr0)
12
9
 
13
10
  help:
14
- @echo Install dependencies:
15
- @echo " ${BOLD}make setup${NORMAL}"
16
- @echo ""
17
- @echo Runing the services like mysql:
18
- @echo " ${BOLD}make services-up${NORMAL}"
11
+ @echo "Generate a backup in the environment (staging|production) database:"
12
+ @echo " ${BOLD}make backup-<environment>${NORMAL}"
19
13
  @echo ""
20
- @echo "Reset the environment (rm mysql db):"
21
- @echo " ${BOLD}make services-down${NORMAL}"
14
+ @echo "Copy latest database backup from the environment (staging|production) to local database:"
15
+ @echo " ${BOLD}make restore-from-<environment>${NORMAL}"
22
16
  @echo ""
23
17
 
24
- setup:
25
- bin/setup
26
-
27
- services: services-up
28
-
29
- services-ps:
30
- docker-compose $(DOCKER_COMPOSE_ARGS) ps
31
-
32
- services-up:
33
- docker-compose $(DOCKER_COMPOSE_ARGS) up -d
34
-
35
- services-stop:
36
- docker-compose $(DOCKER_COMPOSE_ARGS) stop
37
-
38
- services-down:
39
- docker-compose $(DOCKER_COMPOSE_ARGS) down --volumes
40
-
41
- services-logs:
42
- docker-compose $(DOCKER_COMPOSE_ARGS) logs -f
43
-
44
18
  services-port:
45
19
  @set -o pipefail; \
46
- docker-compose $(DOCKER_COMPOSE_ARGS) port ${SERVICE} ${PORT} 2> /dev/null | cut -d':' -f2 || echo ${PORT}
20
+ docker-compose port ${SERVICE} ${PORT} 2> /dev/null | cut -d':' -f2 || echo ${PORT}
47
21
 
48
22
  backup-staging: ROLE=staging
49
23
  backup-production: ROLE=production
@@ -22,6 +22,20 @@ readme:
22
22
  $ heroku local
23
23
 
24
24
  [Heroku Local]: https://devcenter.heroku.com/articles/heroku-local
25
+ webpack:
26
+ title: "Development"
27
+ body: |
28
+ For hot-reloading and fast webpacker compilation you need to run webpack's dev server along with the rails server:
29
+
30
+ $ ./bin/webpack-dev-server
31
+
32
+ Running the dev server will also solve problems with the cache not refreshing between changes and provide better error messages if something fails to compile.
33
+
34
+ For even faster in-place component refreshing (with no page reloads), you can enable Hot Module Reloading in `config/webpacker.yml`
35
+
36
+ development:
37
+ dev_server:
38
+ hmr: true
25
39
  ci:
26
40
  title: "Continuous Integrations"
27
41
  body: |
@@ -61,10 +75,17 @@ readme:
61
75
  style_guide:
62
76
  title: "Style Guides"
63
77
  body: |
64
- The style guides are enforced through a self hosted version of [Hound CI](http://monkeyci.platan.us). The style configuration can also be used locally
65
- in development runing `rubocop` or just using the rubocop integration for your text editor of choice.
78
+ Style guides are enforced through a CircleCI [job](.circleci/config.yml) with [reviewdog](https://github.com/reviewdog/reviewdog) as a reporter, using per-project dependencies and style configurations.
79
+ Please note that this reviewdog implementation requires a GitHub user token to comment on pull requests. A token can be generated [here](https://github.com/settings/tokens), and it should have at least the `repo` option checked.
80
+ The included `config.yml` assumes your CircleCI organization has a context named `org-global` with the required token under the environment variable `REVIEWDOG_GITHUB_API_TOKEN`.
81
+
82
+ The project comes bundled with configuration files available in this repository.
83
+
84
+ Linting dependencies like `rubocop` or `rubocop-rspec` must be locked in your `Gemfile`. Similarly, packages like `eslint` or `eslint-plugin-vue` must be locked in your `package.json`.
85
+
86
+ You can add or modify rules by editing the [`.rubocop.yml`](.rubocop.yml), [`.eslintrc.json`](.eslintrc.json) or [`.stylelintrc.json`](.stylelintrc.json) files.
66
87
 
67
- You can add custom rules to this project just adding them to the `.ruby-style.yml` file.
88
+ You can (and should) use linter integrations for your text editor of choice, using the project's configuration.
68
89
  mailing:
69
90
  title: "Sending Emails"
70
91
  body: |
@@ -82,12 +103,12 @@ readme:
82
103
  devise:
83
104
  title: "Authentication"
84
105
  body: "We are using the great [Devise](https://github.com/plataformatec/devise) library by [PlataformaTec](http://plataformatec.com.br/)"
85
- paperclip:
86
- title: "Uploads"
87
- body: "For managing uploads, this project uses [Paperclip](https://github.com/thoughtbot/paperclip), a gem made by the awesome [Thoughbot](https://thoughtbot.com/) team."
88
106
  active_storage:
89
- title: "Active Storage"
107
+ title: "File Storage"
90
108
  body: "For managing uploads, this project uses [Active Storage](https://github.com/rails/rails/tree/master/activestorage)."
109
+ shrine:
110
+ title: "File Storage"
111
+ body: "For managing uploads, this project uses [Shrine](https://github.com/shrinerb/shrine)."
91
112
  pundit:
92
113
  title: "Authorization"
93
114
  body: "For defining which parts of the system each user has access to, we have chosen to include the [Pundit](https://github.com/elabs/pundit) gem, by [Elabs](http://elabs.se/)."
@@ -109,6 +130,29 @@ readme:
109
130
  power_types:
110
131
  title: "Rails pattern enforcing types"
111
132
  body: "This projects uses [Power-Types](https://github.com/platanus/power-types) to generate Services, Commands, Utils and Values."
133
+ active_admin:
134
+ title: "Administration"
135
+ body: |
136
+ This project uses [Active Admin](https://github.com/activeadmin/activeadmin) which is a Ruby on Rails framework for creating elegant backends for website administration.
137
+ <% if get(:vue_admin) %>
138
+ This project supports Vue inside ActiveAdmin
139
+ - The main package is located in `app/javascript/packs/admin_application.js`, here you will declare the components you want to include in your ActiveAdmin views as you would in a normal Vue App.
140
+ - Additionally, to be able to use Vue components as [Arbre](https://github.com/activeadmin/arbre) Nodes the component names are also declared in `config/initializers/active_admin.rb`
141
+ - The generator includes an example component called `admin_component`, you can use this component inside any ActiveAdmin view by just writing `admin_component` as you would with any `html` tag.
142
+ - For example:
143
+ ```
144
+ admin_component(class:"myCustomClass",id:"myCustomId") do
145
+ admin_component(id:"otherCustomId")
146
+ end
147
+ ```
148
+ - (Keep in mind that the example works with ruby blocks because `AdminComponent` has a `<slot>` tag defined, therefore children can be added to the component)
149
+ - The integration supports passing props to the components and converts them to their corresponing javascript objects.
150
+ - For example, the following works
151
+ ```
152
+ admin_component(testList:[1,2,3,4],testObject:{"name":"Vue component"})
153
+ ```
154
+ - You can also use **any** vue bindings such as `v-for` , `:key` etc.
155
+ <% end %>
112
156
  seeds:
113
157
  title: "Seeds"
114
158
  body: |
@@ -0,0 +1,35 @@
1
+ <template>
2
+ <div>
3
+ I am a Vue Component {{ test }} {{ message }}
4
+ <slot />
5
+ </div>
6
+ </template>
7
+
8
+ <script>
9
+ export default {
10
+ props: {
11
+ test: {
12
+ type: String,
13
+ default: '',
14
+ },
15
+ testNumber: {
16
+ type: Number,
17
+ default: 0,
18
+ },
19
+ testObject: {
20
+ type: Object,
21
+ default: null,
22
+ },
23
+ testList: {
24
+ type: Array,
25
+ default: null,
26
+ },
27
+ },
28
+
29
+ data() {
30
+ return {
31
+ message: 'Hello World',
32
+ };
33
+ },
34
+ };
35
+ </script>
@@ -0,0 +1,14 @@
1
+ import Vue from 'vue/dist/vue.esm';
2
+ import AdminComponent from '../components/admin-component';
3
+
4
+ Vue.component('admin_component', AdminComponent);
5
+
6
+ document.addEventListener('DOMContentLoaded', () => {
7
+ if (document.getElementById('wrapper') !== null) {
8
+ return new Vue({
9
+ el: '#wrapper',
10
+ });
11
+ }
12
+
13
+ return null;
14
+ });
@@ -0,0 +1,10 @@
1
+ module AdminPageLayoutOverride
2
+ def build_page(*args)
3
+ within head do
4
+ text_node(javascript_packs_with_chunks_tag('admin_application'))
5
+ end
6
+ super
7
+ end
8
+ end
9
+
10
+ ActiveAdmin::Views::Pages::Base.send :prepend, AdminPageLayoutOverride
@@ -1,7 +1,5 @@
1
1
  class Api::V1::BaseController < ApplicationController
2
- if Rails.env.production?
3
- include ApiErrorConcern
4
- end
2
+ include ApiErrorConcern
5
3
 
6
4
  self.responder = ApiResponder
7
5
 
@@ -0,0 +1,14 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import App from 'app';
3
+
4
+ describe('App', () => {
5
+ test('is a Vue instance', () => {
6
+ const wrapper = shallowMount(App);
7
+ expect(wrapper.isVueInstance()).toBeTruthy();
8
+ });
9
+
10
+ it('displays message on load', () => {
11
+ const wrapper = shallowMount(App);
12
+ expect(wrapper.find('p').text()).toEqual('Hello Vue!');
13
+ });
14
+ });
@@ -0,0 +1,13 @@
1
+ class BaseUploader < Shrine
2
+ plugin :validation_helpers
3
+
4
+ Attacher.validate do
5
+ validate_mime_type allowed_types
6
+ end
7
+
8
+ private
9
+
10
+ def allowed_types
11
+ raise NotImplementedError
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ class ImageUploader < BaseUploader
2
+ def allowed_types
3
+ @allowed_types ||= %w[image/jpeg image/jpg image/png image/svg+xml image/gif].freeze
4
+ end
5
+ end
@@ -44,6 +44,12 @@ dependencies(){
44
44
  docker-compose $DOCKER_COMPOSE_ARGS run --rm test bundle install
45
45
  }
46
46
 
47
+ <% if selected?(:front_end, :vue) %>
48
+ yarn_dependencies(){
49
+ docker-compose $DOCKER_COMPOSE_ARGS run --rm test yarn install
50
+ }
51
+ <% end %>
52
+
47
53
  assets() {
48
54
  docker-compose $DOCKER_COMPOSE_ARGS run --rm test /bin/bash -c "bin/setup && bundle exec rake assets:precompile"
49
55
  }
@@ -62,6 +68,12 @@ tests(){
62
68
  docker-compose $DOCKER_COMPOSE_ARGS run --rm test bundle exec rspec spec $RSPEC_FORMAT_ARGS $RSPEC_JUNIT_ARGS
63
69
  }
64
70
 
71
+ <% if selected?(:front_end, :vue) %>
72
+ js_tests(){
73
+ docker-compose $DOCKER_COMPOSE_ARGS run --rm test yarn run test
74
+ }
75
+ <% end %>
76
+
65
77
  # Run the complete ci build
66
78
  no_ci(){
67
79
  build
@@ -80,7 +92,7 @@ case "$1" in
80
92
  wait_services
81
93
  ;;
82
94
  "deps"|"dependencies")
83
- dependencies
95
+ dependencies <% if selected?(:front_end, :vue) %>&& yarn_dependencies<% end %>
84
96
  ;;
85
97
  "assets")
86
98
  assets
@@ -88,6 +100,11 @@ case "$1" in
88
100
  "db"|"database")
89
101
  database
90
102
  ;;
103
+ <% if selected?(:front_end, :vue) %>
104
+ "js_tests")
105
+ js_tests
106
+ ;;
107
+ <% end %>
91
108
  "specs"|"tests")
92
109
  tests
93
110
  ;;
@@ -14,7 +14,7 @@ bundle check || bundle install
14
14
  bin/yarn install
15
15
 
16
16
  # Set up required services
17
- make services-up
17
+ docker-compose up -d
18
18
 
19
19
  # Set up database
20
20
  bin/rails db:setup
@@ -1,6 +1,6 @@
1
1
  development: &default
2
2
  adapter: mysql2
3
- database: <%= get(:underscorized_app_name) %>_development
3
+ database: <%= get(:dasherized_app_name) %>_development
4
4
  encoding: utf8
5
5
  host: <%%= ENV["DB_HOST"] || "127.0.0.1" %>
6
6
  port: <%%= ENV["DB_PORT"] || 3306 %>
@@ -12,7 +12,7 @@ development: &default
12
12
 
13
13
  test:
14
14
  <<: *default
15
- database: <%= get(:underscorized_app_name) %>_test
15
+ database: <%= get(:dasherized_app_name) %>_test
16
16
 
17
17
  production: &deploy
18
18
  encoding: utf8
@@ -1,6 +1,6 @@
1
1
  development: &default
2
2
  adapter: postgresql
3
- database: <%= get(:underscorized_app_name) %>_development
3
+ database: <%= get(:dasherized_app_name) %>_development
4
4
  encoding: utf8
5
5
  host: <%%= ENV["DB_HOST"] || "127.0.0.1" %>
6
6
  port: <%%= ENV["DB_PORT"] || 5432 %>
@@ -12,7 +12,7 @@ development: &default
12
12
 
13
13
  test:
14
14
  <<: *default
15
- database: <%= get(:underscorized_app_name) %>_test
15
+ database: <%= get(:dasherized_app_name) %>_test
16
16
 
17
17
  production: &deploy
18
18
  encoding: utf8
@@ -0,0 +1,33 @@
1
+ require 'shrine'
2
+
3
+ if Rails.env.development?
4
+ require 'shrine/storage/file_system'
5
+
6
+ Shrine.storages = {
7
+ cache: Shrine::Storage::FileSystem.new('public', prefix: 'uploads/cache'),
8
+ store: Shrine::Storage::FileSystem.new('public', prefix: 'uploads')
9
+ }
10
+ elsif Rails.env.production?
11
+ require 'shrine/storage/s3'
12
+
13
+ s3_options = {
14
+ bucket: ENV.fetch('S3_BUCKET'),
15
+ region: ENV.fetch('AWS_REGION'),
16
+ access_key_id: ENV.fetch('AWS_ACCESS_KEY_ID'),
17
+ secret_access_key: ENV.fetch('AWS_SECRET_ACCESS_KEY')
18
+ }
19
+
20
+ Shrine.storages = {
21
+ cache: Shrine::Storage::S3.new(prefix: 'cache', **s3_options),
22
+ store: Shrine::Storage::S3.new(**s3_options)
23
+ }
24
+ else
25
+ require 'shrine/storage/memory'
26
+
27
+ Shrine.storages[:store] = Shrine::Storage::Memory.new
28
+ end
29
+
30
+ Shrine.plugin :activerecord
31
+ Shrine.plugin :cached_attachment_data
32
+ Shrine.plugin :restore_cached_data
33
+ Shrine.plugin :determine_mime_type, analyzer: :marcel
@@ -7,5 +7,6 @@ services:
7
7
  dockerfile: Dockerfile.ci
8
8
  volumes:
9
9
  - "test_data:/usr/local/bundle"
10
+ - "./node_modules:/app/node_modules"
10
11
  environment:
11
12
  RACK_ENV: test
@@ -36,7 +36,8 @@ if Rails.env.development?
36
36
  'force' => 'false',
37
37
  'trace' => 'false',
38
38
  'wrapper_open' => nil,
39
- 'wrapper_close' => nil
39
+ 'wrapper_close' => nil,
40
+ 'models' => true
40
41
  )
41
42
  end
42
43