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
@@ -0,0 +1,55 @@
|
|
1
|
+
class GraphqlController < ApplicationController
|
2
|
+
# If accessing from outside this domain, nullify the session
|
3
|
+
# This allows for outside API access while preventing CSRF attacks,
|
4
|
+
# but you'll have to authenticate your user separately
|
5
|
+
# protect_from_forgery with: :null_session
|
6
|
+
|
7
|
+
def execute
|
8
|
+
variables = prepare_variables(params[:variables])
|
9
|
+
query = params[:query]
|
10
|
+
operation_name = params[:operationName]
|
11
|
+
context = { current_user: get_current_user }
|
12
|
+
result = GqlSampleSchema.execute(query, variables: variables, context: context, operation_name: operation_name)
|
13
|
+
render json: result
|
14
|
+
rescue => e
|
15
|
+
raise e unless Rails.env.development?
|
16
|
+
handle_error_in_development e
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
# Handle variables in form data, JSON body, or a blank value
|
22
|
+
def prepare_variables(variables_param)
|
23
|
+
case variables_param
|
24
|
+
when String
|
25
|
+
if variables_param.present?
|
26
|
+
JSON.parse(variables_param) || {}
|
27
|
+
else
|
28
|
+
{}
|
29
|
+
end
|
30
|
+
when Hash
|
31
|
+
variables_param
|
32
|
+
when ActionController::Parameters
|
33
|
+
variables_param.to_unsafe_hash # GraphQL-Ruby will validate name and type of incoming variables.
|
34
|
+
when nil
|
35
|
+
{}
|
36
|
+
else
|
37
|
+
raise ArgumentError, "Unexpected parameter: #{variables_param}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def handle_error_in_development(e)
|
42
|
+
logger.error e.message
|
43
|
+
logger.error e.backtrace.join("\n")
|
44
|
+
|
45
|
+
render json: { errors: [{ message: e.message, backtrace: e.backtrace }], data: {} }, status: 500
|
46
|
+
end
|
47
|
+
|
48
|
+
def get_current_user
|
49
|
+
if request.headers['Authorization']
|
50
|
+
_, token = request.headers['Authorization'].split
|
51
|
+
decoded_token = JWT.decode token, ENV['HMAC_SECRET'], true, { algorithm: 'HS256' }
|
52
|
+
User.find(decoded_token.first["id"])
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'jwt'
|
2
|
+
|
3
|
+
class Mutations::LoginMutation < Mutations::BaseMutation
|
4
|
+
null true
|
5
|
+
|
6
|
+
argument :email, String, required: true
|
7
|
+
argument :password, String, required: true
|
8
|
+
|
9
|
+
|
10
|
+
field :token, String, null: true
|
11
|
+
|
12
|
+
def resolve(email:, password:)
|
13
|
+
user = User.find_by(email: email)
|
14
|
+
if user&.valid_password?(password)
|
15
|
+
payload = { id: user.id, email: user.email, exp: (Time.zone.now + 24.hours).to_i }
|
16
|
+
token = JWT.encode payload, ENV['HMAC_SECRET'], 'HS256'
|
17
|
+
return { token: token }
|
18
|
+
end
|
19
|
+
GraphQL::ExecutionError.new("User or Password invalid")
|
20
|
+
rescue ActiveRecord::RecordInvalid => e
|
21
|
+
GraphQL::ExecutionError.new("Invalid input: #{e.record.errors.full_messages.join(', ')}")
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Types
|
2
|
+
class QueryType < Types::Base::BaseObject
|
3
|
+
# Add root-level fields here.
|
4
|
+
# They will be entry points for queries on your schema.
|
5
|
+
|
6
|
+
# TODO: remove me
|
7
|
+
field :test_field, String, null: false,
|
8
|
+
description: "An example field added by the generator"
|
9
|
+
def test_field
|
10
|
+
"Hello World!"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<!-- Google Tag Manager -->
|
2
|
+
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
|
3
|
+
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
|
4
|
+
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
|
5
|
+
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
|
6
|
+
})(window,document,'script','dataLayer','<%=ENV['GTM_CONTAINER_ID']%>');</script>
|
7
|
+
<!-- End Google Tag Manager -->
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# config/initializers/graphql_playground.rb
|
2
|
+
# All config options have a default that should work out of the box
|
3
|
+
if Rails.env.development?
|
4
|
+
GraphqlPlayground::Rails.configure do |config|
|
5
|
+
# config.headers = {
|
6
|
+
# 'X-Auth-Header' => ->(view_context) { "123" }
|
7
|
+
# }
|
8
|
+
# config.title = "Playground"
|
9
|
+
# config.csrf = true
|
10
|
+
# config.playground_version = "latest"
|
11
|
+
# # Ideally the assets would be added to your projects `vendor/assets` directories
|
12
|
+
# config.favicon = "/assets/playground.ico"
|
13
|
+
# config.playground_js_url = "/assets/playground.js"
|
14
|
+
# config.playground_css_url = "/assets/playground.css"
|
15
|
+
# # see: https://github.com/prisma-labs/graphql-playground#settings
|
16
|
+
config.settings = {
|
17
|
+
"schema.polling.enable": false
|
18
|
+
}
|
19
|
+
end
|
20
|
+
end
|
@@ -24,7 +24,7 @@ rack_env = ENV.fetch("RACK_ENV", "development")
|
|
24
24
|
environment rack_env
|
25
25
|
|
26
26
|
# Set 1 day timeout for workers while developing
|
27
|
-
worker_timeout
|
27
|
+
worker_timeout 24 * 60 * 60 if rack_env == "development"
|
28
28
|
|
29
29
|
on_worker_boot do
|
30
30
|
# Worker specific setup for Rails 4.1+
|
@@ -24,7 +24,10 @@ elsif Rails.env.production?
|
|
24
24
|
else
|
25
25
|
require 'shrine/storage/memory'
|
26
26
|
|
27
|
-
Shrine.storages
|
27
|
+
Shrine.storages = {
|
28
|
+
cache: Shrine::Storage::Memory.new,
|
29
|
+
store: Shrine::Storage::Memory.new
|
30
|
+
}
|
28
31
|
end
|
29
32
|
|
30
33
|
Shrine.plugin :activerecord
|
@@ -26,6 +26,8 @@ Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }
|
|
26
26
|
# If you are not using ActiveRecord, you can remove this line.
|
27
27
|
ActiveRecord::Migration.maintain_test_schema!
|
28
28
|
|
29
|
+
PowerTypes::Observable.observable_disabled = true
|
30
|
+
|
29
31
|
RSpec.configure do |config|
|
30
32
|
# If you're not using ActiveRecord, or you'd prefer not to run each of your
|
31
33
|
# examples within a transaction, remove the following line or assign false
|
@@ -3,37 +3,29 @@ require 'potassium/cli_options'
|
|
3
3
|
module Potassium::CLI
|
4
4
|
extend Potassium::CliOptions
|
5
5
|
|
6
|
-
desc
|
6
|
+
desc 'Create a new Potassium Rails project.'
|
7
7
|
arg 'app_path'
|
8
8
|
command :create do |c|
|
9
|
-
c.default_desc
|
10
|
-
c.switch "version-check",
|
11
|
-
default_value: true,
|
12
|
-
desc: "Performs a version check before running.",
|
13
|
-
negatable: true
|
14
|
-
|
9
|
+
c.default_desc 'Create a new project.'
|
15
10
|
create_options.each { |opts| c.send(opts.delete(:type), opts.delete(:name), opts) }
|
16
11
|
|
17
12
|
c.action do |_global_options, options, _args|
|
18
|
-
require
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
require "potassium/template_finder"
|
13
|
+
require 'potassium/newest_version_ensurer'
|
14
|
+
require 'potassium/node_version_ensurer'
|
15
|
+
require 'potassium/generators/application'
|
16
|
+
require 'potassium/template_finder'
|
23
17
|
|
18
|
+
begin
|
19
|
+
Potassium::NewestVersionEnsurer.new.ensure! if options['version-check']
|
20
|
+
Potassium::NodeVersionEnsurer.new.ensure! if options['node-version-check']
|
24
21
|
template_finder = Potassium::TemplateFinder.new
|
25
22
|
template = template_finder.default_template
|
26
23
|
template.cli_options = options
|
27
24
|
template.source_paths << Rails::Generators::AppGenerator.source_root
|
28
25
|
ARGV.push('--skip-webpack-install', '--skip-bundle')
|
29
26
|
template.start
|
30
|
-
|
31
|
-
|
32
|
-
if options["version-check"]
|
33
|
-
ensurer = Potassium::NewestVersionEnsurer.new
|
34
|
-
ensurer.ensure(&begin_creation)
|
35
|
-
else
|
36
|
-
begin_creation.call
|
27
|
+
rescue VersionError => e
|
28
|
+
print "\nError: #{e.message}" # rubocop:disable Rails/Output
|
37
29
|
end
|
38
30
|
end
|
39
31
|
end
|
@@ -1,5 +1,21 @@
|
|
1
1
|
module Potassium::CliOptions # rubocop:disable Metrics/ModuleLength
|
2
2
|
CREATE_OPTIONS = [
|
3
|
+
{
|
4
|
+
type: :switch,
|
5
|
+
name: 'version-check',
|
6
|
+
desc: 'Performs a version check before running.',
|
7
|
+
negatable: true,
|
8
|
+
default_value: true,
|
9
|
+
default_test_value: true
|
10
|
+
},
|
11
|
+
{
|
12
|
+
type: :switch,
|
13
|
+
name: 'node-version-check',
|
14
|
+
desc: 'Performs a node version check before running.',
|
15
|
+
negatable: true,
|
16
|
+
default_value: true,
|
17
|
+
default_test_value: true
|
18
|
+
},
|
3
19
|
{
|
4
20
|
type: :flag,
|
5
21
|
name: [:db, :database],
|
@@ -59,12 +75,11 @@ module Potassium::CliOptions # rubocop:disable Metrics/ModuleLength
|
|
59
75
|
default_test_value: false
|
60
76
|
},
|
61
77
|
{
|
62
|
-
type: :
|
78
|
+
type: :flag,
|
63
79
|
name: "api",
|
64
|
-
desc: "
|
65
|
-
negatable: true,
|
80
|
+
desc: "Which API interface to use",
|
66
81
|
default_value: "none",
|
67
|
-
default_test_value:
|
82
|
+
default_test_value: "None"
|
68
83
|
},
|
69
84
|
{
|
70
85
|
type: :flag,
|
@@ -82,10 +97,10 @@ module Potassium::CliOptions # rubocop:disable Metrics/ModuleLength
|
|
82
97
|
default_test_value: false
|
83
98
|
},
|
84
99
|
{
|
85
|
-
type: :
|
100
|
+
type: :switch,
|
86
101
|
name: "background_processor",
|
87
|
-
desc: "
|
88
|
-
default_test_value:
|
102
|
+
desc: "Whether to use Sidekiq for background processing or not",
|
103
|
+
default_test_value: false
|
89
104
|
},
|
90
105
|
{
|
91
106
|
type: :switch,
|
@@ -105,12 +120,41 @@ module Potassium::CliOptions # rubocop:disable Metrics/ModuleLength
|
|
105
120
|
},
|
106
121
|
{
|
107
122
|
type: :switch,
|
108
|
-
name: "
|
109
|
-
desc: "Whether
|
123
|
+
name: "github_private",
|
124
|
+
desc: "Whether the github repository is private or not",
|
110
125
|
negatable: true,
|
111
|
-
default_value:
|
126
|
+
default_value: "none",
|
112
127
|
default_test_value: false
|
113
128
|
},
|
129
|
+
{
|
130
|
+
type: :switch,
|
131
|
+
name: "github_has_org",
|
132
|
+
desc: "Whether the github repository should belong to an organization",
|
133
|
+
negatable: true,
|
134
|
+
default_value: "none",
|
135
|
+
default_test_value: false
|
136
|
+
},
|
137
|
+
{
|
138
|
+
type: :flag,
|
139
|
+
name: "github_org",
|
140
|
+
desc: "The github organization where the repository will be created",
|
141
|
+
default_value: "none",
|
142
|
+
default_test_value: "none"
|
143
|
+
},
|
144
|
+
{
|
145
|
+
type: :flag,
|
146
|
+
name: "github_name",
|
147
|
+
desc: "The github repository name",
|
148
|
+
default_value: "none",
|
149
|
+
default_test_value: "none"
|
150
|
+
},
|
151
|
+
{
|
152
|
+
type: :flag,
|
153
|
+
name: "github_access_token",
|
154
|
+
desc: "Github personal access token used to auth to Github API",
|
155
|
+
default_value: "none",
|
156
|
+
default_test_value: "none"
|
157
|
+
},
|
114
158
|
{
|
115
159
|
type: :switch,
|
116
160
|
name: "schedule",
|
@@ -132,6 +176,22 @@ module Potassium::CliOptions # rubocop:disable Metrics/ModuleLength
|
|
132
176
|
name: :front_end,
|
133
177
|
desc: "Decides which front-end framework to use. Available: Vue, Angular 2, None",
|
134
178
|
default_test_value: "None"
|
179
|
+
},
|
180
|
+
{
|
181
|
+
type: :switch,
|
182
|
+
name: 'google_tag_manager',
|
183
|
+
desc: 'Whether to use google tag manager',
|
184
|
+
negatable: true,
|
185
|
+
default_value: 'none',
|
186
|
+
default_test_value: false
|
187
|
+
},
|
188
|
+
{
|
189
|
+
type: :switch,
|
190
|
+
name: "test",
|
191
|
+
desc: "Whether or not it is a test project creation",
|
192
|
+
negatable: true,
|
193
|
+
default_value: false,
|
194
|
+
default_test_value: true
|
135
195
|
}
|
136
196
|
]
|
137
197
|
|
@@ -7,6 +7,10 @@ module TemplateHelpers
|
|
7
7
|
"#{Potassium::NODE_VERSION}.x"
|
8
8
|
end
|
9
9
|
|
10
|
+
def ruby_version
|
11
|
+
Semantic::Version.new(Potassium::RUBY_VERSION).instance_eval { "#{major}.#{minor}" }
|
12
|
+
end
|
13
|
+
|
10
14
|
def load_recipe(recipe_name)
|
11
15
|
@recipes ||= {}
|
12
16
|
@recipes[recipe_name] ||= get_recipe_class(recipe_name.to_sym).new(self)
|