potassium 5.2.2 → 6.3.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 +103 -28
- data/.circleci/setup-rubygems.sh +3 -0
- data/.gitignore +2 -1
- data/.node-version +1 -0
- data/.rubocop.yml +530 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +92 -1
- data/README.md +51 -45
- data/docs/DSL.md +5 -5
- data/lib/potassium/assets/.circleci/config.yml.erb +151 -0
- data/lib/potassium/assets/.eslintrc.json +352 -0
- data/lib/potassium/assets/.github/pull_request_template.md +9 -0
- data/lib/potassium/assets/.rubocop.yml +528 -0
- data/lib/potassium/assets/.stylelintrc.json +46 -0
- data/lib/potassium/assets/Makefile.erb +21 -32
- data/lib/potassium/assets/README.yml +59 -15
- 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/app/graphql/graphql_controller.rb +55 -0
- data/lib/potassium/assets/app/graphql/mutations/login_mutation.rb +23 -0
- data/lib/potassium/assets/app/graphql/queries/base_query.rb +4 -0
- data/lib/potassium/assets/app/graphql/types/base/base_argument.rb +4 -0
- data/lib/potassium/assets/app/graphql/types/base/base_enum.rb +4 -0
- data/lib/potassium/assets/app/graphql/types/base/base_field.rb +5 -0
- data/lib/potassium/assets/app/graphql/types/base/base_input_object.rb +5 -0
- data/lib/potassium/assets/app/graphql/types/base/base_interface.rb +7 -0
- data/lib/potassium/assets/app/graphql/types/base/base_object.rb +5 -0
- data/lib/potassium/assets/app/graphql/types/base/base_scalar.rb +4 -0
- data/lib/potassium/assets/app/graphql/types/base/base_union.rb +4 -0
- data/lib/potassium/assets/app/graphql/types/mutation_type.rb +10 -0
- data/lib/potassium/assets/app/graphql/types/query_type.rb +13 -0
- data/lib/potassium/assets/app/javascript/app.spec.js +14 -0
- data/lib/potassium/assets/app/uploaders/base_uploader.rb +11 -0
- data/lib/potassium/assets/app/uploaders/image_uploader.rb +5 -0
- data/lib/potassium/assets/app/views/shared/_gtm_body.html.erb +4 -0
- data/lib/potassium/assets/app/views/shared/_gtm_head.html.erb +7 -0
- data/lib/potassium/assets/bin/release +1 -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/graphql_playground.rb +20 -0
- data/lib/potassium/assets/config/puma.rb +1 -1
- data/lib/potassium/assets/config/shrine.rb +36 -0
- data/lib/potassium/assets/lib/tasks/auto_annotate_models.rake +2 -1
- data/lib/potassium/assets/package.json +4 -1
- data/lib/potassium/assets/redis.yml +1 -2
- data/lib/potassium/assets/testing/rails_helper.rb +2 -0
- data/lib/potassium/cli/commands/create.rb +12 -19
- data/lib/potassium/cli_options.rb +77 -26
- data/lib/potassium/helpers/gem-helpers.rb +1 -1
- data/lib/potassium/helpers/template-helpers.rb +8 -0
- data/lib/potassium/newest_version_ensurer.rb +19 -36
- data/lib/potassium/node_version_ensurer.rb +30 -0
- data/lib/potassium/recipes/admin.rb +3 -3
- data/lib/potassium/recipes/annotate.rb +1 -1
- data/lib/potassium/recipes/api.rb +93 -21
- data/lib/potassium/recipes/background_processor.rb +66 -19
- data/lib/potassium/recipes/ci.rb +10 -38
- data/lib/potassium/recipes/data_migrate.rb +44 -0
- data/lib/potassium/recipes/database.rb +4 -0
- data/lib/potassium/recipes/database_container.rb +7 -5
- data/lib/potassium/recipes/draper.rb +1 -10
- data/lib/potassium/recipes/file_storage.rb +66 -0
- data/lib/potassium/recipes/front_end.rb +225 -9
- data/lib/potassium/recipes/github.rb +93 -15
- data/lib/potassium/recipes/google_tag_manager.rb +90 -0
- data/lib/potassium/recipes/heroku.rb +42 -29
- data/lib/potassium/recipes/mailer.rb +18 -2
- data/lib/potassium/recipes/monitoring.rb +5 -0
- data/lib/potassium/recipes/node.rb +21 -0
- data/lib/potassium/recipes/rack_cors.rb +18 -15
- data/lib/potassium/recipes/schedule.rb +17 -2
- data/lib/potassium/recipes/style.rb +21 -3
- data/lib/potassium/recipes/vue_admin.rb +124 -0
- data/lib/potassium/templates/application.rb +10 -7
- data/lib/potassium/version.rb +7 -4
- data/potassium.gemspec +11 -6
- data/spec/features/api_spec.rb +25 -0
- data/spec/features/background_processor_spec.rb +19 -6
- data/spec/features/ci_spec.rb +7 -4
- data/spec/features/data_migrate_spec.rb +14 -0
- data/spec/features/database_container_spec.rb +1 -5
- data/spec/features/draper_spec.rb +1 -6
- data/spec/features/file_storage_spec.rb +75 -0
- data/spec/features/front_end_spec.rb +102 -0
- data/spec/features/github_spec.rb +53 -8
- data/spec/features/google_tag_manager_spec.rb +59 -0
- data/spec/features/graphql_spec.rb +71 -0
- data/spec/features/heroku_spec.rb +1 -1
- data/spec/features/mailer_spec.rb +16 -0
- data/spec/features/new_project_spec.rb +6 -14
- data/spec/features/node_spec.rb +28 -0
- data/spec/features/power_types_spec.rb +5 -16
- data/spec/features/schedule_spec.rb +11 -4
- data/spec/features/vue_admin_spec.rb +47 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/support/fake_octokit.rb +31 -0
- data/spec/support/potassium_test_helpers.rb +26 -9
- data/tmp/.keep +0 -0
- metadata +152 -46
- data/lib/potassium/assets/.circleci/config.yml +0 -20
- data/lib/potassium/assets/Dockerfile.ci +0 -6
- 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/api/api_error_concern.rb +0 -32
- data/lib/potassium/assets/api/base_controller.rb +0 -9
- data/lib/potassium/assets/api/draper_responder.rb +0 -62
- data/lib/potassium/assets/api/responder.rb +0 -41
- data/lib/potassium/assets/aws.rb +0 -1
- data/lib/potassium/assets/bin/cibuild.erb +0 -100
- data/lib/potassium/assets/docker-compose.ci.yml +0 -11
- data/lib/potassium/assets/sidekiq_scheduler.yml +0 -9
- data/lib/potassium/assets/testing/paperclip.rb +0 -59
- data/lib/potassium/recipes/active_storage.rb +0 -40
- data/lib/potassium/recipes/angular_admin.rb +0 -56
- data/lib/potassium/recipes/aws_sdk.rb +0 -7
- data/lib/potassium/recipes/paperclip.rb +0 -47
- data/spec/features/active_storage_spec.rb +0 -30
- data/spec/features/front_end.rb +0 -30
|
@@ -24,20 +24,21 @@ class Recipes::DatabaseContainer < Rails::AppBuilder
|
|
|
24
24
|
environment:
|
|
25
25
|
MYSQL_ALLOW_EMPTY_PASSWORD: 'true'
|
|
26
26
|
volumes:
|
|
27
|
-
|
|
27
|
+
- mysql_data:/var/lib/mysql
|
|
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,11 +54,12 @@ 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
|
|
|
60
61
|
insert_into_file 'bin/setup', setup_text, before: "# Set up database"
|
|
62
|
+
create
|
|
61
63
|
run 'bin/setup'
|
|
62
64
|
info "A new container with a #{get(:database)} database has been created."
|
|
63
65
|
end
|
|
@@ -7,7 +7,6 @@ class Recipes::Draper < Rails::AppBuilder
|
|
|
7
7
|
def create
|
|
8
8
|
return unless selected?(:draper)
|
|
9
9
|
add_draper
|
|
10
|
-
add_api_responder if selected?(:api_support)
|
|
11
10
|
end
|
|
12
11
|
|
|
13
12
|
def installed?
|
|
@@ -16,19 +15,11 @@ class Recipes::Draper < Rails::AppBuilder
|
|
|
16
15
|
|
|
17
16
|
def install
|
|
18
17
|
add_draper
|
|
19
|
-
api_recipe = load_recipe(:api)
|
|
20
|
-
add_api_responder if api_recipe.installed?
|
|
21
18
|
end
|
|
22
19
|
|
|
23
20
|
def add_draper
|
|
24
|
-
gather_gem 'draper', '3.
|
|
21
|
+
gather_gem 'draper', '~> 3.1'
|
|
25
22
|
add_readme_section :internal_dependencies, :draper
|
|
26
23
|
create_file 'app/decorators/.keep'
|
|
27
24
|
end
|
|
28
|
-
|
|
29
|
-
def add_api_responder
|
|
30
|
-
after(:gem_install) do
|
|
31
|
-
copy_file '../assets/api/draper_responder.rb', 'app/responders/api_responder.rb', force: true
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
25
|
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
class Recipes::FileStorage < Rails::AppBuilder
|
|
2
|
+
def ask
|
|
3
|
+
storages = {
|
|
4
|
+
active_storage: 'ActiveStorage',
|
|
5
|
+
shrine: 'Shrine',
|
|
6
|
+
none: 'None, thanks'
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
storage = answer(:storage) do
|
|
10
|
+
storages.keys[Ask.list('Which storage are you going to use?', storages.values)]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
set(:storage, storage.to_sym)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def create
|
|
17
|
+
add_chosen_storage
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def install
|
|
21
|
+
ask
|
|
22
|
+
add_chosen_storage
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def installed?
|
|
26
|
+
file_exist?('config/storage.yml')
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def add_active_storage
|
|
32
|
+
after(:gem_install) { run('bundle exec rails active_storage:install') }
|
|
33
|
+
copy_file('../assets/config/storage.yml', 'config/storage.yml', force: true)
|
|
34
|
+
active_storage_service_regexp = /config.active_storage.service = :local\n/
|
|
35
|
+
gsub_file 'config/environments/production.rb', active_storage_service_regexp do
|
|
36
|
+
'config.active_storage.service = :amazon'
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def add_shrine
|
|
41
|
+
gather_gem('shrine', '~> 3.0')
|
|
42
|
+
gather_gem('marcel', '~> 1.0')
|
|
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
|
+
append_to_file('.gitignore', "/public/uploads\n")
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def common_setup
|
|
50
|
+
gather_gem 'aws-sdk-s3', '~> 1.0'
|
|
51
|
+
add_readme_section :internal_dependencies, get(:storage)
|
|
52
|
+
append_to_file '.env.development', "S3_BUCKET=\n"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def add_chosen_storage
|
|
56
|
+
return if [:none, :None].include? get(:storage).to_sym
|
|
57
|
+
|
|
58
|
+
common_setup
|
|
59
|
+
case get(:storage)
|
|
60
|
+
when :active_storage
|
|
61
|
+
add_active_storage
|
|
62
|
+
when :shrine
|
|
63
|
+
add_shrine
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -17,22 +17,22 @@ class Recipes::FrontEnd < Rails::AppBuilder
|
|
|
17
17
|
def create
|
|
18
18
|
return if [:none, :None].include? get(:front_end).to_sym
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
recipe = self
|
|
22
21
|
after(:gem_install) do
|
|
23
22
|
value = get(:front_end)
|
|
24
23
|
run "rails webpacker:install"
|
|
25
24
|
run "rails webpacker:install:#{value}" if value
|
|
26
25
|
|
|
27
26
|
if value == :vue
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
layout_file = "app/views/layouts/application.html.erb"
|
|
34
|
-
insert_into_file layout_file, js_pack_tag, after: "<%= csrf_meta_tags %>"
|
|
27
|
+
recipe.setup_vue_with_compiler_build
|
|
28
|
+
recipe.setup_jest
|
|
29
|
+
if get(:api) == :graphql
|
|
30
|
+
recipe.setup_apollo
|
|
31
|
+
end
|
|
35
32
|
end
|
|
33
|
+
recipe.add_responsive_meta_tag
|
|
34
|
+
recipe.setup_tailwind
|
|
35
|
+
add_readme_header :webpack
|
|
36
36
|
end
|
|
37
37
|
end
|
|
38
38
|
|
|
@@ -48,6 +48,66 @@ class Recipes::FrontEnd < Rails::AppBuilder
|
|
|
48
48
|
package_content.include?("\"@angular/core\"") || package_content.include?("\"vue\"")
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
+
def setup_vue_with_compiler_build
|
|
52
|
+
application_js = 'app/javascript/packs/application.js'
|
|
53
|
+
remove_file "app/javascript/packs/hello_vue.js"
|
|
54
|
+
create_file application_js, application_js_content, force: true
|
|
55
|
+
|
|
56
|
+
layout_file = "app/views/layouts/application.html.erb"
|
|
57
|
+
insert_into_file(
|
|
58
|
+
layout_file,
|
|
59
|
+
"<div id=\"vue-app\">\n <app></app>\n ",
|
|
60
|
+
before: "<%= yield %>"
|
|
61
|
+
)
|
|
62
|
+
insert_into_file layout_file, "\n </div>", after: "<%= yield %>"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def add_responsive_meta_tag
|
|
66
|
+
tag = "\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n"
|
|
67
|
+
layout_file = "app/views/layouts/application.html.erb"
|
|
68
|
+
insert_into_file layout_file, tag, after: "<%= csrf_meta_tags %>"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def setup_tailwind
|
|
72
|
+
run "bin/yarn add tailwindcss@#{Potassium::TAILWINDCSS}"
|
|
73
|
+
specify_autoprefixer_postcss_compatibility_versions
|
|
74
|
+
setup_client_css
|
|
75
|
+
remove_server_css_requires
|
|
76
|
+
setup_tailwind_requirements
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def setup_jest
|
|
80
|
+
run 'bin/yarn add jest vue-jest babel-jest @vue/test-utils jest-serializer-vue babel-core@^7.0.0-bridge.0 --dev'
|
|
81
|
+
json_file = File.read(Pathname.new("package.json"))
|
|
82
|
+
js_package = JSON.parse(json_file)
|
|
83
|
+
js_package = js_package.merge(jest_config)
|
|
84
|
+
json_string = JSON.pretty_generate(js_package)
|
|
85
|
+
create_file 'package.json', json_string, force: true
|
|
86
|
+
|
|
87
|
+
copy_file '../assets/app/javascript/app.spec.js', 'app/javascript/app.spec.js'
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def setup_apollo
|
|
91
|
+
run 'bin/yarn add vue-apollo graphql apollo-client apollo-link apollo-link-http apollo-cache-inmemory graphql-tag'
|
|
92
|
+
|
|
93
|
+
inject_into_file(
|
|
94
|
+
'app/javascript/packs/application.js',
|
|
95
|
+
apollo_imports,
|
|
96
|
+
after: "import App from '../app.vue';"
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
inject_into_file(
|
|
100
|
+
'app/javascript/packs/application.js',
|
|
101
|
+
apollo_loading,
|
|
102
|
+
after: "import VueApollo from 'vue-apollo';"
|
|
103
|
+
)
|
|
104
|
+
inject_into_file(
|
|
105
|
+
'app/javascript/packs/application.js',
|
|
106
|
+
"\n apolloProvider,",
|
|
107
|
+
after: "components: { App },"
|
|
108
|
+
)
|
|
109
|
+
end
|
|
110
|
+
|
|
51
111
|
private
|
|
52
112
|
|
|
53
113
|
def frameworks(framework)
|
|
@@ -58,4 +118,160 @@ class Recipes::FrontEnd < Rails::AppBuilder
|
|
|
58
118
|
}
|
|
59
119
|
frameworks[framework]
|
|
60
120
|
end
|
|
121
|
+
|
|
122
|
+
def apollo_imports
|
|
123
|
+
<<~JS
|
|
124
|
+
\n
|
|
125
|
+
import { ApolloClient } from 'apollo-client';
|
|
126
|
+
import { createHttpLink } from 'apollo-link-http';
|
|
127
|
+
import { InMemoryCache } from 'apollo-cache-inmemory';
|
|
128
|
+
import VueApollo from 'vue-apollo';
|
|
129
|
+
JS
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def apollo_loading
|
|
133
|
+
<<~JS
|
|
134
|
+
\n
|
|
135
|
+
const httpLink = createHttpLink({
|
|
136
|
+
uri: `${window.location.origin}/graphql`,
|
|
137
|
+
})
|
|
138
|
+
const cache = new InMemoryCache()
|
|
139
|
+
const apolloClient = new ApolloClient({
|
|
140
|
+
link: httpLink,
|
|
141
|
+
cache,
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
Vue.use(VueApollo)
|
|
145
|
+
const apolloProvider = new VueApollo({
|
|
146
|
+
defaultClient: apolloClient,
|
|
147
|
+
})
|
|
148
|
+
JS
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def specify_autoprefixer_postcss_compatibility_versions
|
|
152
|
+
run 'bin/yarn -D add postcss@^7 autoprefixer@^9'
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def setup_client_css
|
|
156
|
+
application_css = 'app/javascript/css/application.css'
|
|
157
|
+
create_file application_css, "", force: true
|
|
158
|
+
|
|
159
|
+
stylesheet_pack_tag = "\n <%= stylesheet_pack_tag 'application' %>\n "
|
|
160
|
+
layout_file = "app/views/layouts/application.html.erb"
|
|
161
|
+
insert_into_file layout_file, stylesheet_pack_tag, before: "</head>"
|
|
162
|
+
|
|
163
|
+
application_js = 'app/javascript/packs/application.js'
|
|
164
|
+
if get(:front_end) != :vue
|
|
165
|
+
create_file application_js, "import '../css/application.css';\n", force: true
|
|
166
|
+
else
|
|
167
|
+
insert_into_file(
|
|
168
|
+
application_js,
|
|
169
|
+
"\nimport '../css/application.css';",
|
|
170
|
+
after: "import App from '../app.vue';"
|
|
171
|
+
)
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def setup_tailwind_requirements
|
|
176
|
+
application_css = 'app/javascript/css/application.css'
|
|
177
|
+
insert_into_file application_css, tailwind_client_css
|
|
178
|
+
|
|
179
|
+
tailwind_config = 'tailwind.config.js'
|
|
180
|
+
create_file tailwind_config, tailwind_config_content, force: true
|
|
181
|
+
|
|
182
|
+
postcss_file = 'postcss.config.js'
|
|
183
|
+
insert_into_file postcss_file, postcss_require_tailwind, after: "plugins: [\n"
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def remove_server_css_requires
|
|
187
|
+
assets_css_file = 'app/assets/stylesheets/application.css'
|
|
188
|
+
gsub_file(assets_css_file, " *= require_tree .\n *= require_self\n", "")
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def application_js_content
|
|
192
|
+
<<~JS
|
|
193
|
+
import Vue from 'vue/dist/vue.esm';
|
|
194
|
+
import App from '../app.vue';
|
|
195
|
+
|
|
196
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
197
|
+
const app = new Vue({
|
|
198
|
+
el: '#vue-app',
|
|
199
|
+
components: { App },
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
return app;
|
|
203
|
+
});
|
|
204
|
+
JS
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def tailwind_client_css
|
|
208
|
+
<<~CSS
|
|
209
|
+
@import 'tailwindcss/base';
|
|
210
|
+
@import 'tailwindcss/components';
|
|
211
|
+
@import 'tailwindcss/utilities';
|
|
212
|
+
CSS
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def tailwind_config_content
|
|
216
|
+
<<~JS
|
|
217
|
+
/* eslint-disable no-undef */
|
|
218
|
+
module.exports = {
|
|
219
|
+
theme: {
|
|
220
|
+
extend: {},
|
|
221
|
+
},
|
|
222
|
+
variants: {},
|
|
223
|
+
plugins: [],
|
|
224
|
+
purge: {
|
|
225
|
+
enabled: process.env.NODE_ENV === 'production',
|
|
226
|
+
content: [
|
|
227
|
+
'./app/**/*.html',
|
|
228
|
+
'./app/**/*.vue',
|
|
229
|
+
'./app/**/*.js',
|
|
230
|
+
'./app/**/*.erb',
|
|
231
|
+
],
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
JS
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def postcss_require_tailwind
|
|
238
|
+
<<-JS.gsub(/^ {4}/, ' ')
|
|
239
|
+
require('tailwindcss'),
|
|
240
|
+
require('autoprefixer'),
|
|
241
|
+
JS
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
def jest_config
|
|
245
|
+
{
|
|
246
|
+
"scripts": {
|
|
247
|
+
"test": "jest",
|
|
248
|
+
"test:watch": "jest --watch"
|
|
249
|
+
},
|
|
250
|
+
"jest": {
|
|
251
|
+
"roots": [
|
|
252
|
+
"app/javascript"
|
|
253
|
+
],
|
|
254
|
+
"moduleDirectories": [
|
|
255
|
+
"node_modules",
|
|
256
|
+
"app/javascript"
|
|
257
|
+
],
|
|
258
|
+
"moduleNameMapper": {
|
|
259
|
+
"^@/(.*)$": "app/javascript/$1"
|
|
260
|
+
},
|
|
261
|
+
"moduleFileExtensions": [
|
|
262
|
+
"js",
|
|
263
|
+
"json",
|
|
264
|
+
"vue"
|
|
265
|
+
],
|
|
266
|
+
"transform": {
|
|
267
|
+
"^.+\\.js$": "<rootDir>/node_modules/babel-jest",
|
|
268
|
+
".*\\.(vue)$": "<rootDir>/node_modules/vue-jest"
|
|
269
|
+
},
|
|
270
|
+
"snapshotSerializers": [
|
|
271
|
+
"<rootDir>/node_modules/jest-serializer-vue"
|
|
272
|
+
],
|
|
273
|
+
"testEnvironment": "jsdom"
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
end
|
|
61
277
|
end
|
|
@@ -1,29 +1,107 @@
|
|
|
1
|
+
require 'octokit'
|
|
2
|
+
|
|
1
3
|
class Recipes::Github < Rails::AppBuilder
|
|
2
4
|
def ask
|
|
3
|
-
repo_name = "platanus/#{get(:dasherized_app_name)}"
|
|
4
5
|
github_repo_create = answer(:github) do
|
|
5
|
-
|
|
6
|
-
"for this project?"
|
|
7
|
-
Ask.confirm(q)
|
|
8
|
-
end
|
|
9
|
-
if github_repo_create
|
|
10
|
-
github_repo_private = answer(:"github-private") do
|
|
11
|
-
Ask.confirm("Should the repository be private?")
|
|
12
|
-
end
|
|
6
|
+
Ask.confirm('Do you want to create a Github repository?')
|
|
13
7
|
end
|
|
14
|
-
set(:github_repo_name, repo_name)
|
|
15
8
|
set(:github_repo, github_repo_create)
|
|
16
|
-
|
|
9
|
+
setup_repo if github_repo_create
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def setup_repo
|
|
13
|
+
setup_repo_private
|
|
14
|
+
setup_repo_org
|
|
15
|
+
setup_repo_name
|
|
16
|
+
set(:github_access_token, get_access_token)
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def create
|
|
20
|
-
|
|
20
|
+
return unless selected?(:github_repo)
|
|
21
|
+
|
|
22
|
+
create_github_repo
|
|
23
|
+
copy_file '../assets/.github/pull_request_template.md', '.github/pull_request_template.md'
|
|
21
24
|
end
|
|
22
25
|
|
|
23
26
|
private
|
|
24
27
|
|
|
25
|
-
def
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
def setup_repo_private
|
|
29
|
+
repo_private = answer(:github_private) do
|
|
30
|
+
Ask.confirm('Should the repository be private?')
|
|
31
|
+
end
|
|
32
|
+
set(:github_repo_private, repo_private)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def setup_repo_org
|
|
36
|
+
has_organization = answer(:github_has_org) do
|
|
37
|
+
Ask.confirm('Is this repo for a Github organization?')
|
|
38
|
+
end
|
|
39
|
+
set(:github_has_org, has_organization)
|
|
40
|
+
if has_organization
|
|
41
|
+
repo_organization = answer(:github_org) do
|
|
42
|
+
Ask.input('What is the organization for this repository?', default: 'platanus')
|
|
43
|
+
end
|
|
44
|
+
set(:github_org, repo_organization)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def setup_repo_name
|
|
49
|
+
repo_name = answer(:github_name) do
|
|
50
|
+
Ask.input('What is the name for this repository?', default: get(:dasherized_app_name))
|
|
51
|
+
end
|
|
52
|
+
set(:github_repo_name, repo_name)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def create_github_repo
|
|
56
|
+
options = { private: get(:github_repo_private) }
|
|
57
|
+
options[:organization] = get(:github_org) if get(:github_has_org)
|
|
58
|
+
repo_name = get(:github_repo_name)
|
|
59
|
+
|
|
60
|
+
is_retry = false
|
|
61
|
+
begin
|
|
62
|
+
github_client(is_retry).create_repository(repo_name, options)
|
|
63
|
+
rescue Octokit::Unauthorized
|
|
64
|
+
is_retry = true
|
|
65
|
+
retry if retry_create_repo
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def retry_create_repo
|
|
70
|
+
puts "Bad credentials, information on Personal Access Tokens here:"
|
|
71
|
+
puts "https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token"
|
|
72
|
+
puts "Make sure to give repo access to the personal access token"
|
|
73
|
+
Ask.confirm("Do you want to retry?")
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def github_client(is_retry = false)
|
|
77
|
+
access_token = is_retry ? set_access_token : get(:github_access_token)
|
|
78
|
+
octokit_client.new(access_token: access_token)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def octokit_client
|
|
82
|
+
if answer(:test)
|
|
83
|
+
require_relative '../../../spec/support/fake_octokit'
|
|
84
|
+
FakeOctokit
|
|
85
|
+
else
|
|
86
|
+
Octokit::Client
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def get_access_token
|
|
91
|
+
return File.open(config_filename, 'r').read if File.exists?(config_filename)
|
|
92
|
+
|
|
93
|
+
set_access_token
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def set_access_token
|
|
97
|
+
access_token = answer(:github_access_token) do
|
|
98
|
+
Ask.input('Enter a GitHub personal access token', password: true)
|
|
99
|
+
end
|
|
100
|
+
File.open(config_filename, 'w') { |f| f.write(access_token) }
|
|
101
|
+
access_token
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def config_filename
|
|
105
|
+
@config_filename ||= File.expand_path('~/.potassium')
|
|
28
106
|
end
|
|
29
107
|
end
|