potassium 6.0.0 → 6.4.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 -38
- data/.circleci/setup-rubygems.sh +3 -0
- data/.gitignore +2 -1
- data/.rubocop.yml +530 -0
- data/CHANGELOG.md +57 -0
- data/README.md +51 -45
- data/lib/potassium/assets/.circleci/config.yml.erb +83 -34
- data/lib/potassium/assets/.eslintrc.json +13 -4
- data/lib/potassium/assets/.github/pull_request_template.md +9 -0
- data/lib/potassium/assets/.rubocop.yml +13 -0
- data/lib/potassium/assets/README.yml +7 -7
- 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 +1 -1
- data/lib/potassium/assets/app/uploaders/base_uploader.rb +1 -3
- 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/config/graphql_playground.rb +20 -0
- data/lib/potassium/assets/config/puma.rb +1 -1
- data/lib/potassium/assets/config/shrine.rb +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 +11 -19
- data/lib/potassium/cli_options.rb +70 -10
- data/lib/potassium/helpers/template-helpers.rb +4 -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 +26 -16
- data/lib/potassium/recipes/api.rb +92 -27
- data/lib/potassium/recipes/background_processor.rb +62 -18
- data/lib/potassium/recipes/ci.rb +9 -39
- data/lib/potassium/recipes/database.rb +4 -0
- data/lib/potassium/recipes/draper.rb +0 -9
- data/lib/potassium/recipes/file_storage.rb +2 -1
- data/lib/potassium/recipes/front_end.rb +84 -9
- data/lib/potassium/recipes/github.rb +93 -15
- data/lib/potassium/recipes/google_tag_manager.rb +94 -0
- data/lib/potassium/recipes/heroku.rb +42 -29
- data/lib/potassium/recipes/mailer.rb +18 -5
- data/lib/potassium/recipes/monitoring.rb +5 -0
- data/lib/potassium/recipes/schedule.rb +16 -1
- data/lib/potassium/recipes/style.rb +2 -2
- data/lib/potassium/templates/application.rb +5 -2
- data/lib/potassium/version.rb +5 -2
- data/potassium.gemspec +5 -2
- 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/draper_spec.rb +1 -6
- data/spec/features/file_storage_spec.rb +5 -0
- data/spec/features/front_end_spec.rb +32 -1
- data/spec/features/github_spec.rb +53 -8
- data/spec/features/google_tag_manager_spec.rb +36 -0
- data/spec/features/graphql_spec.rb +71 -0
- data/spec/features/mailer_spec.rb +16 -0
- data/spec/features/schedule_spec.rb +11 -4
- data/spec/spec_helper.rb +1 -0
- data/spec/support/fake_octokit.rb +31 -0
- data/spec/support/potassium_test_helpers.rb +0 -1
- data/tmp/.keep +0 -0
- metadata +80 -15
- data/lib/potassium/assets/Dockerfile.ci +0 -6
- data/lib/potassium/assets/api/api_error_concern.rb +0 -32
- data/lib/potassium/assets/api/base_controller.rb +0 -7
- data/lib/potassium/assets/api/draper_responder.rb +0 -62
- data/lib/potassium/assets/api/responder.rb +0 -41
- data/lib/potassium/assets/bin/cibuild.erb +0 -117
- data/lib/potassium/assets/docker-compose.ci.yml +0 -12
- data/lib/potassium/assets/sidekiq_scheduler.yml +0 -9
@@ -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,8 +15,6 @@ 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
|
@@ -25,10 +22,4 @@ class Recipes::Draper < Rails::AppBuilder
|
|
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
|
@@ -39,10 +39,11 @@ class Recipes::FileStorage < Rails::AppBuilder
|
|
39
39
|
|
40
40
|
def add_shrine
|
41
41
|
gather_gem('shrine', '~> 3.0')
|
42
|
-
gather_gem('marcel', '~> 0
|
42
|
+
gather_gem('marcel', '~> 1.0')
|
43
43
|
copy_file('../assets/config/shrine.rb', 'config/initializers/shrine.rb', force: true)
|
44
44
|
copy_file('../assets/app/uploaders/image_uploader.rb', 'app/uploaders/image_uploader.rb')
|
45
45
|
copy_file('../assets/app/uploaders/base_uploader.rb', 'app/uploaders/base_uploader.rb')
|
46
|
+
append_to_file('.gitignore', "/public/uploads\n")
|
46
47
|
end
|
47
48
|
|
48
49
|
def common_setup
|
@@ -1,4 +1,6 @@
|
|
1
1
|
class Recipes::FrontEnd < Rails::AppBuilder
|
2
|
+
VUE_LOADER_VERSION = Potassium::VUE_LOADER_VERSION
|
3
|
+
|
2
4
|
def ask
|
3
5
|
frameworks = {
|
4
6
|
vue: "Vue",
|
@@ -15,18 +17,13 @@ class Recipes::FrontEnd < Rails::AppBuilder
|
|
15
17
|
end
|
16
18
|
|
17
19
|
def create
|
18
|
-
return if [:none, :None].include? get(:front_end).to_sym
|
19
|
-
|
20
20
|
recipe = self
|
21
21
|
after(:gem_install) do
|
22
22
|
value = get(:front_end)
|
23
23
|
run "rails webpacker:install"
|
24
|
-
run "rails webpacker:install:#{value}"
|
24
|
+
run "rails webpacker:install:#{value}" unless [:none, :None].include? value.to_sym
|
25
25
|
|
26
|
-
if value == :vue
|
27
|
-
recipe.setup_vue_with_compiler_build
|
28
|
-
recipe.setup_jest
|
29
|
-
end
|
26
|
+
recipe.setup_vue if value == :vue
|
30
27
|
recipe.add_responsive_meta_tag
|
31
28
|
recipe.setup_tailwind
|
32
29
|
add_readme_header :webpack
|
@@ -66,7 +63,8 @@ class Recipes::FrontEnd < Rails::AppBuilder
|
|
66
63
|
end
|
67
64
|
|
68
65
|
def setup_tailwind
|
69
|
-
run
|
66
|
+
run "bin/yarn add tailwindcss@#{Potassium::TAILWINDCSS}"
|
67
|
+
specify_autoprefixer_postcss_compatibility_versions
|
70
68
|
setup_client_css
|
71
69
|
remove_server_css_requires
|
72
70
|
setup_tailwind_requirements
|
@@ -83,6 +81,40 @@ class Recipes::FrontEnd < Rails::AppBuilder
|
|
83
81
|
copy_file '../assets/app/javascript/app.spec.js', 'app/javascript/app.spec.js'
|
84
82
|
end
|
85
83
|
|
84
|
+
def setup_apollo
|
85
|
+
run 'bin/yarn add vue-apollo graphql apollo-client apollo-link apollo-link-http apollo-cache-inmemory graphql-tag'
|
86
|
+
|
87
|
+
inject_into_file(
|
88
|
+
'app/javascript/packs/application.js',
|
89
|
+
apollo_imports,
|
90
|
+
after: "import App from '../app.vue';"
|
91
|
+
)
|
92
|
+
|
93
|
+
inject_into_file(
|
94
|
+
'app/javascript/packs/application.js',
|
95
|
+
apollo_loading,
|
96
|
+
after: "import VueApollo from 'vue-apollo';"
|
97
|
+
)
|
98
|
+
inject_into_file(
|
99
|
+
'app/javascript/packs/application.js',
|
100
|
+
"\n apolloProvider,",
|
101
|
+
after: "components: { App },"
|
102
|
+
)
|
103
|
+
end
|
104
|
+
|
105
|
+
def foce_vue_loader_version
|
106
|
+
run "bin/yarn add vue-loader@#{VUE_LOADER_VERSION}"
|
107
|
+
end
|
108
|
+
|
109
|
+
def setup_vue
|
110
|
+
foce_vue_loader_version
|
111
|
+
setup_vue_with_compiler_build
|
112
|
+
setup_jest
|
113
|
+
if get(:api) == :graphql
|
114
|
+
setup_apollo
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
86
118
|
private
|
87
119
|
|
88
120
|
def frameworks(framework)
|
@@ -94,6 +126,39 @@ class Recipes::FrontEnd < Rails::AppBuilder
|
|
94
126
|
frameworks[framework]
|
95
127
|
end
|
96
128
|
|
129
|
+
def apollo_imports
|
130
|
+
<<~JS
|
131
|
+
\n
|
132
|
+
import { ApolloClient } from 'apollo-client';
|
133
|
+
import { createHttpLink } from 'apollo-link-http';
|
134
|
+
import { InMemoryCache } from 'apollo-cache-inmemory';
|
135
|
+
import VueApollo from 'vue-apollo';
|
136
|
+
JS
|
137
|
+
end
|
138
|
+
|
139
|
+
def apollo_loading
|
140
|
+
<<~JS
|
141
|
+
\n
|
142
|
+
const httpLink = createHttpLink({
|
143
|
+
uri: `${window.location.origin}/graphql`,
|
144
|
+
})
|
145
|
+
const cache = new InMemoryCache()
|
146
|
+
const apolloClient = new ApolloClient({
|
147
|
+
link: httpLink,
|
148
|
+
cache,
|
149
|
+
})
|
150
|
+
|
151
|
+
Vue.use(VueApollo)
|
152
|
+
const apolloProvider = new VueApollo({
|
153
|
+
defaultClient: apolloClient,
|
154
|
+
})
|
155
|
+
JS
|
156
|
+
end
|
157
|
+
|
158
|
+
def specify_autoprefixer_postcss_compatibility_versions
|
159
|
+
run 'bin/yarn -D add postcss@^7 autoprefixer@^9'
|
160
|
+
end
|
161
|
+
|
97
162
|
def setup_client_css
|
98
163
|
application_css = 'app/javascript/css/application.css'
|
99
164
|
create_file application_css, "", force: true
|
@@ -163,6 +228,15 @@ class Recipes::FrontEnd < Rails::AppBuilder
|
|
163
228
|
},
|
164
229
|
variants: {},
|
165
230
|
plugins: [],
|
231
|
+
purge: {
|
232
|
+
enabled: process.env.NODE_ENV === 'production',
|
233
|
+
content: [
|
234
|
+
'./app/**/*.html',
|
235
|
+
'./app/**/*.vue',
|
236
|
+
'./app/**/*.js',
|
237
|
+
'./app/**/*.erb',
|
238
|
+
],
|
239
|
+
}
|
166
240
|
};
|
167
241
|
JS
|
168
242
|
end
|
@@ -202,7 +276,8 @@ class Recipes::FrontEnd < Rails::AppBuilder
|
|
202
276
|
},
|
203
277
|
"snapshotSerializers": [
|
204
278
|
"<rootDir>/node_modules/jest-serializer-vue"
|
205
|
-
]
|
279
|
+
],
|
280
|
+
"testEnvironment": "jsdom"
|
206
281
|
}
|
207
282
|
}
|
208
283
|
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
|
@@ -0,0 +1,94 @@
|
|
1
|
+
class Recipes::GoogleTagManager < Rails::AppBuilder
|
2
|
+
def ask
|
3
|
+
use_google_tag_manager = answer(:google_tag_manager) do
|
4
|
+
Ask.confirm 'Do you want to use Google Tag Manager?'
|
5
|
+
end
|
6
|
+
|
7
|
+
set(:google_tag_manager, use_google_tag_manager)
|
8
|
+
end
|
9
|
+
|
10
|
+
def create
|
11
|
+
install if selected?(:google_tag_manager)
|
12
|
+
end
|
13
|
+
|
14
|
+
def install
|
15
|
+
add_google_tag_manager
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_google_tag_manager
|
19
|
+
copy_tag_manager_files
|
20
|
+
append_to_file '.env.development', "GTM_CONTAINER_ID=\n"
|
21
|
+
include_tag_manager
|
22
|
+
add_content_security_policy
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_content_security_policy
|
26
|
+
inject_into_file(
|
27
|
+
'config/initializers/content_security_policy.rb',
|
28
|
+
content_security_policy_code
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
def copy_tag_manager_files
|
33
|
+
copy_file(
|
34
|
+
'../assets/app/views/shared/_gtm_head.html.erb',
|
35
|
+
'app/views/shared/_gtm_head.html.erb',
|
36
|
+
force: true
|
37
|
+
)
|
38
|
+
|
39
|
+
copy_file(
|
40
|
+
'../assets/app/views/shared/_gtm_body.html.erb',
|
41
|
+
'app/views/shared/_gtm_body.html.erb',
|
42
|
+
force: true
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
def include_tag_manager
|
47
|
+
inject_into_file(
|
48
|
+
'app/views/layouts/application.html.erb',
|
49
|
+
render_string('shared/gtm_head'),
|
50
|
+
before: '</head>'
|
51
|
+
)
|
52
|
+
|
53
|
+
inject_into_file(
|
54
|
+
'app/views/layouts/application.html.erb',
|
55
|
+
render_string('shared/gtm_body'),
|
56
|
+
after: '<body>'
|
57
|
+
)
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def render_string(file_path)
|
63
|
+
" <%if Rails.env.production? %>
|
64
|
+
<%= render \"#{file_path}\" %>
|
65
|
+
<% end %>\n "
|
66
|
+
end
|
67
|
+
|
68
|
+
def content_security_policy_code
|
69
|
+
<<~HERE
|
70
|
+
Rails.application.config.content_security_policy do |policy|
|
71
|
+
policy.connect_src(
|
72
|
+
:self,
|
73
|
+
:https,
|
74
|
+
'http://localhost:3035',
|
75
|
+
'ws://localhost:3035',
|
76
|
+
'https://www.google-analytics.com'
|
77
|
+
)
|
78
|
+
# google tag manager requires to enable unsafe inline and vue unsave eval:
|
79
|
+
# https://developers.google.com/tag-manager/web/csp
|
80
|
+
# https://vuejs.org/v2/guide/installation.html#CSP-environments
|
81
|
+
policy.script_src(
|
82
|
+
:self,
|
83
|
+
:https,
|
84
|
+
:unsafe_inline,
|
85
|
+
:unsafe_eval,
|
86
|
+
'https://www.googletagmanager.com',
|
87
|
+
'https://www.google-analytics.com',
|
88
|
+
'https://ssl.google-analytics.com'
|
89
|
+
)
|
90
|
+
policy.img_src :self, :https, 'https://www.googletagmanager.com', 'https://www.google-analytics.com'
|
91
|
+
end
|
92
|
+
HERE
|
93
|
+
end
|
94
|
+
end
|
@@ -1,13 +1,7 @@
|
|
1
1
|
class Recipes::Heroku < Rails::AppBuilder
|
2
2
|
NAME_PREFIX = 'pl'
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
def initialize(args)
|
7
|
-
super(args)
|
8
|
-
set(:heroku_app_name_staging, app_name_for('staging'))
|
9
|
-
set(:heroku_app_name_production, app_name_for('production'))
|
10
|
-
end
|
3
|
+
ENVIRONMENTS = ['staging', 'production']
|
4
|
+
HEROKU_NAMES_MAX_CHARS = 30
|
11
5
|
|
12
6
|
def ask
|
13
7
|
heroku = answer(:heroku) do
|
@@ -16,6 +10,8 @@ class Recipes::Heroku < Rails::AppBuilder
|
|
16
10
|
|
17
11
|
if heroku
|
18
12
|
set(:heroku, heroku)
|
13
|
+
|
14
|
+
ENVIRONMENTS.each { |environment| set_app_name_for(environment) }
|
19
15
|
end
|
20
16
|
end
|
21
17
|
|
@@ -47,31 +43,34 @@ class Recipes::Heroku < Rails::AppBuilder
|
|
47
43
|
template "../assets/bin/setup_heroku.erb", "bin/setup_heroku", force: true
|
48
44
|
run "chmod a+x bin/setup_heroku"
|
49
45
|
|
50
|
-
|
51
|
-
%w(staging production).each do |environment|
|
52
|
-
create_app_on_heroku(environment)
|
53
|
-
end
|
54
|
-
puts "Remember to connect the github repository to the new pipeline"
|
55
|
-
open_pipeline_command = "\e[33mheroku pipelines:open #{heroku_pipeline_name}\e[0m"
|
56
|
-
puts "run #{open_pipeline_command} to open the dashboard"
|
57
|
-
else
|
58
|
-
puts "You are not logged in into heroku"
|
59
|
-
login_command = "\e[33mheroku login\e[0m"
|
60
|
-
puts "Run #{login_command} and enter your credentials"
|
61
|
-
puts "You can install the heroku recipe again create the app in heroku"
|
62
|
-
install_command = "\e[33mpostassium install heroku --force\e[0m"
|
63
|
-
puts "Just run #{install_command}"
|
64
|
-
end
|
46
|
+
logged_in? ? create_apps : puts_not_logged_in_msg
|
65
47
|
|
66
48
|
add_readme_header :deployment
|
67
49
|
end
|
68
50
|
|
51
|
+
def create_apps
|
52
|
+
ENVIRONMENTS.each { |environment| create_app_on_heroku(environment) }
|
53
|
+
puts "Remember to connect the github repository to the new pipeline"
|
54
|
+
open_pipeline_command = "\e[33mheroku pipelines:open #{heroku_pipeline_name}\e[0m"
|
55
|
+
puts "run #{open_pipeline_command} to open the dashboard"
|
56
|
+
end
|
57
|
+
|
58
|
+
def puts_not_logged_in_msg
|
59
|
+
puts "You are not logged in into heroku"
|
60
|
+
login_command = "\e[33mheroku login\e[0m"
|
61
|
+
puts "Run #{login_command} and enter your credentials"
|
62
|
+
puts "You can install the heroku recipe again to create the app in heroku"
|
63
|
+
install_command = "\e[33mpostassium install heroku --force\e[0m"
|
64
|
+
puts "Just run #{install_command}"
|
65
|
+
end
|
66
|
+
|
69
67
|
def heroku_pipeline_name
|
70
|
-
app_name.dasherize
|
68
|
+
@heroku_pipeline_name ||= valid_heroku_name(app_name.dasherize, 'pipeline', false)
|
71
69
|
end
|
72
70
|
|
73
|
-
def
|
74
|
-
"#{NAME_PREFIX}-#{app_name.dasherize}-#{environment}"
|
71
|
+
def set_app_name_for(environment)
|
72
|
+
default_name = "#{NAME_PREFIX}-#{app_name.dasherize}-#{environment}"
|
73
|
+
set("heroku_app_name_#{environment}".to_sym, valid_heroku_name(default_name, environment))
|
75
74
|
end
|
76
75
|
|
77
76
|
def logged_in?
|
@@ -84,7 +83,7 @@ class Recipes::Heroku < Rails::AppBuilder
|
|
84
83
|
|
85
84
|
def create_app_on_heroku(environment)
|
86
85
|
rack_env = "RACK_ENV=production"
|
87
|
-
staged_app_name =
|
86
|
+
staged_app_name = get("heroku_app_name_#{environment}".to_sym)
|
88
87
|
|
89
88
|
run_toolbelt_command "create #{staged_app_name} --remote #{environment}"
|
90
89
|
run_toolbelt_command "labs:enable runtime-dyno-metadata", staged_app_name
|
@@ -99,14 +98,14 @@ class Recipes::Heroku < Rails::AppBuilder
|
|
99
98
|
def set_rails_secrets(environment)
|
100
99
|
run_toolbelt_command(
|
101
100
|
"config:add SECRET_KEY_BASE=#{generate_secret}",
|
102
|
-
|
101
|
+
get("heroku_app_name_#{environment}".to_sym)
|
103
102
|
)
|
104
103
|
end
|
105
104
|
|
106
105
|
def set_app_multi_buildpack(environment)
|
107
106
|
run_toolbelt_command(
|
108
107
|
"buildpacks:set https://github.com/heroku/heroku-buildpack-multi.git",
|
109
|
-
|
108
|
+
get("heroku_app_name_#{environment}".to_sym)
|
110
109
|
)
|
111
110
|
end
|
112
111
|
|
@@ -133,4 +132,18 @@ class Recipes::Heroku < Rails::AppBuilder
|
|
133
132
|
`heroku #{command} --app #{app_env_name}`
|
134
133
|
end
|
135
134
|
end
|
135
|
+
|
136
|
+
def valid_heroku_name(name, element, force_suffix = true)
|
137
|
+
suffix = "-#{element}"
|
138
|
+
while name.length > HEROKU_NAMES_MAX_CHARS
|
139
|
+
puts "Heroku names must be shorter than #{HEROKU_NAMES_MAX_CHARS} chars."
|
140
|
+
if force_suffix
|
141
|
+
puts "Potassium uses the heroku-stage gem, because of that '#{suffix}' will be "\
|
142
|
+
"added to your app name. The suffix, #{suffix}, counts towards the app name length."
|
143
|
+
end
|
144
|
+
name = Ask.input("Please enter a valid name for #{element}:")
|
145
|
+
name += suffix if force_suffix && !name.end_with?(suffix)
|
146
|
+
end
|
147
|
+
name
|
148
|
+
end
|
136
149
|
end
|