potassium 6.0.0 → 6.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +19 -0
  3. data/README.md +41 -45
  4. data/lib/potassium/assets/.eslintrc.json +13 -4
  5. data/lib/potassium/assets/.github/pull_request_template.md +9 -0
  6. data/lib/potassium/assets/README.yml +6 -0
  7. data/lib/potassium/assets/app/graphql/graphql_controller.rb +55 -0
  8. data/lib/potassium/assets/app/graphql/mutations/login_mutation.rb +23 -0
  9. data/lib/potassium/assets/app/graphql/queries/base_query.rb +4 -0
  10. data/lib/potassium/assets/app/graphql/types/base/base_argument.rb +4 -0
  11. data/lib/potassium/assets/app/graphql/types/base/base_enum.rb +4 -0
  12. data/lib/potassium/assets/app/graphql/types/base/base_field.rb +5 -0
  13. data/lib/potassium/assets/app/graphql/types/base/base_input_object.rb +5 -0
  14. data/lib/potassium/assets/app/graphql/types/base/base_interface.rb +7 -0
  15. data/lib/potassium/assets/app/graphql/types/base/base_object.rb +5 -0
  16. data/lib/potassium/assets/app/graphql/types/base/base_scalar.rb +4 -0
  17. data/lib/potassium/assets/app/graphql/types/base/base_union.rb +4 -0
  18. data/lib/potassium/assets/app/graphql/types/mutation_type.rb +10 -0
  19. data/lib/potassium/assets/app/graphql/types/query_type.rb +13 -0
  20. data/lib/potassium/assets/app/uploaders/base_uploader.rb +1 -3
  21. data/lib/potassium/assets/config/graphql_playground.rb +20 -0
  22. data/lib/potassium/assets/config/puma.rb +1 -1
  23. data/lib/potassium/assets/config/shrine.rb +4 -1
  24. data/lib/potassium/assets/redis.yml +1 -2
  25. data/lib/potassium/assets/testing/rails_helper.rb +2 -0
  26. data/lib/potassium/cli/commands/create.rb +11 -19
  27. data/lib/potassium/cli_options.rb +59 -7
  28. data/lib/potassium/newest_version_ensurer.rb +19 -36
  29. data/lib/potassium/node_version_ensurer.rb +30 -0
  30. data/lib/potassium/recipes/api.rb +91 -27
  31. data/lib/potassium/recipes/background_processor.rb +34 -1
  32. data/lib/potassium/recipes/database.rb +4 -0
  33. data/lib/potassium/recipes/draper.rb +0 -9
  34. data/lib/potassium/recipes/file_storage.rb +1 -0
  35. data/lib/potassium/recipes/front_end.rb +62 -0
  36. data/lib/potassium/recipes/github.rb +93 -15
  37. data/lib/potassium/version.rb +1 -1
  38. data/potassium.gemspec +2 -1
  39. data/spec/features/api_spec.rb +25 -0
  40. data/spec/features/background_processor_spec.rb +12 -1
  41. data/spec/features/draper_spec.rb +1 -6
  42. data/spec/features/file_storage_spec.rb +5 -0
  43. data/spec/features/front_end_spec.rb +14 -0
  44. data/spec/features/github_spec.rb +53 -8
  45. data/spec/features/graphql_spec.rb +71 -0
  46. data/spec/spec_helper.rb +1 -0
  47. data/spec/support/fake_octokit.rb +31 -0
  48. metadata +40 -8
  49. data/lib/potassium/assets/api/api_error_concern.rb +0 -32
  50. data/lib/potassium/assets/api/base_controller.rb +0 -7
  51. data/lib/potassium/assets/api/draper_responder.rb +0 -62
  52. data/lib/potassium/assets/api/responder.rb +0 -41
@@ -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 1.day.seconds.to_i if rack_env == "development"
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[:store] = Shrine::Storage::Memory.new
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
@@ -1,6 +1,5 @@
1
1
  development: &default
2
- host: <%= ENV["BOXEN_REDIS_HOST"] || ENV["REDIS_HOST"] || "127.0.0.1" %>
3
- port: <%= ENV["BOXEN_REDIS_PORT"] || ENV["REDIS_PORT"] || 6379 %>
2
+ url: <%= ENV.fetch("REDIS_URL") %>
4
3
 
5
4
  test:
6
5
  <<: *default
@@ -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 "Create a new Potassium Rails project."
6
+ desc 'Create a new Potassium Rails project.'
7
7
  arg 'app_path'
8
8
  command :create do |c|
9
- c.default_desc "Create a new project."
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 "potassium/newest_version_ensurer"
19
-
20
- begin_creation = -> do
21
- require "potassium/generators/application"
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
- end
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: :switch,
78
+ type: :flag,
63
79
  name: "api",
64
- desc: "Whether to apply the API mode or not",
65
- negatable: true,
80
+ desc: "Which API interface to use",
66
81
  default_value: "none",
67
- default_test_value: false
82
+ default_test_value: "None"
68
83
  },
69
84
  {
70
85
  type: :flag,
@@ -105,12 +120,41 @@ module Potassium::CliOptions # rubocop:disable Metrics/ModuleLength
105
120
  },
106
121
  {
107
122
  type: :switch,
108
- name: "github-private",
109
- desc: "Whether to the github repository is private",
123
+ name: "github_private",
124
+ desc: "Whether the github repository is private or not",
110
125
  negatable: true,
111
- default_value: false,
126
+ default_value: "none",
127
+ default_test_value: false
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",
112
135
  default_test_value: false
113
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,14 @@ 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: "test",
183
+ desc: "Whether or not it is a test project creation",
184
+ negatable: true,
185
+ default_value: false,
186
+ default_test_value: true
135
187
  }
136
188
  ]
137
189
 
@@ -1,51 +1,34 @@
1
- require "term/ansicolor"
2
- require "gems"
3
- require "semantic"
4
- require "potassium/text_spinner"
1
+ require 'gems'
2
+ require 'semantic'
3
+ require 'potassium/text_spinner'
4
+
5
+ class VersionError < StandardError
6
+ end
5
7
 
6
8
  module Potassium
7
9
  class NewestVersionEnsurer
8
- include Term::ANSIColor
9
-
10
- def initialize(current_version = Potassium::VERSION)
11
- self.current_version = Semantic::Version.new(current_version)
10
+ def initialize
11
+ self.installed_version = Semantic::Version.new(Potassium::VERSION)
12
12
  self.text_spinner = Potassium::TextSpinner.new
13
13
  end
14
14
 
15
- def ensure(&success_block)
16
- spin_text("Checking your Potassium installation") { latest_version }
15
+ def ensure!
16
+ spin_text('Checking your Potassium installation') { published_version }
17
17
 
18
- self.latest_version = Semantic::Version.new(
19
- Gems.versions("potassium").first["number"]
20
- )
21
-
22
- if latest_version <= current_version
23
- up_to_date
24
- success_block.call
25
- else
26
- please_update
27
- end
18
+ self.published_version = Semantic::Version.new(Gems.versions('potassium').first['number'])
19
+ raise VersionError.new(update_message) if published_version > installed_version
28
20
  end
29
21
 
30
22
  private
31
23
 
32
- attr_accessor :latest_version, :current_version, :text_spinner
33
-
34
- def up_to_date
35
- puts green("\nYour Potassium installation is up to date.")
36
- end
24
+ attr_accessor :published_version, :installed_version, :text_spinner
37
25
 
38
- def please_update
39
- puts red("\nYour Potassium installation is not up to date.")
40
- puts red("Found: #{current_version}")
41
- puts red("Expected: #{latest_version}\n")
42
- print white("Please run: ")
43
- print green("gem update potassium ")
44
- print white("to upgrade your potassium installation.\n\n")
45
- print white("If you really need to run this outdated version of potassium anyway, ")
46
- print white("re-run this command with the ")
47
- print black("--no-version-check")
48
- puts white(" flag.")
26
+ def update_message
27
+ <<~HERE
28
+ Your potassium installation is not up to date.
29
+ The last available version is #{published_version} while the running version is #{installed_version}.
30
+ If you really need to run this outdated version of potassium, re-run this command with the `--no-version-check` flag.
31
+ HERE
49
32
  end
50
33
 
51
34
  def spin_text(message, &block)
@@ -0,0 +1,30 @@
1
+ module Potassium
2
+ class NodeVersionEnsurer
3
+ def ensure!
4
+ raise VersionError.new(install_message) if installed_node_version.nil?
5
+ raise VersionError.new(update_message) if Potassium::NODE_VERSION != installed_node_version
6
+ end
7
+
8
+ private
9
+
10
+ def installed_node_version
11
+ node_version = `node -v 2>&1`
12
+ return node_version.delete('^[0-9\.]').split('.').first if $?.success?
13
+ end
14
+
15
+ def install_message
16
+ <<~HERE
17
+ Node doesn't appear to be installed.
18
+ Please make sure you have node #{Potassium::NODE_VERSION} installed.
19
+ HERE
20
+ end
21
+
22
+ def update_message
23
+ <<~HERE
24
+ An unsupported version of node was found.
25
+ Please make sure you have node #{Potassium::NODE_VERSION} installed. Newer versions may work but potassium only supports that one.
26
+ If you really need to run potassium with a different version of node, re-run this command with the `--no-node-version-check` flag.
27
+ HERE
28
+ end
29
+ end
30
+ end
@@ -1,51 +1,115 @@
1
1
  class Recipes::Api < Rails::AppBuilder
2
2
  def ask
3
- api_support = answer(:api) { Ask.confirm("Do you want to enable API support?") }
4
- set(:api_support, api_support)
3
+ api_interfaces = {
4
+ rest: "REST (with Power API)",
5
+ graphql: "GraphQL (beta)",
6
+ none: "None, thanks"
7
+ }
8
+ api_interface = answer(:api) do
9
+ api_interfaces.keys[Ask.list("Which API interface are you using?", api_interfaces.values)]
10
+ end
11
+ set :api, api_interface.to_sym
5
12
  end
6
13
 
7
14
  def create
8
- add_api if get(:api_support)
15
+ if get(:api) == :graphql
16
+ add_graphql
17
+ elsif get(:api) == :rest
18
+ add_power_api
19
+ end
9
20
  end
10
21
 
11
22
  def install
12
- add_api
23
+ ask
24
+ create
13
25
  end
14
26
 
15
27
  def installed?
16
- gem_exists?(/versionist/)
28
+ gem_exists?(/power_api/) || gem_exists?(/graphql/)
17
29
  end
18
30
 
19
31
  private
20
32
 
21
- def add_api
22
- gather_gem 'versionist'
23
- gather_gem 'responders'
24
- gather_gem 'active_model_serializers', '~> 0.9.3'
25
- gather_gem 'simple_token_authentication', '~> 1.0'
33
+ def add_power_api
34
+ gather_gem 'power_api'
35
+
36
+ gather_gems(:development, :test) do
37
+ gather_gem 'rswag-specs'
38
+ end
39
+
40
+ add_readme_section :internal_dependencies, :power_api
26
41
 
27
42
  after(:gem_install) do
28
- line = "Rails.application.routes.draw do\n"
29
- insert_into_file "config/routes.rb", after: line do
30
- <<-HERE.gsub(/^ {8}/, '')
31
- scope path: '/api' do
32
- api_version(module: "Api::V1", path: { value: "v1" }, defaults: { format: 'json' }) do
33
- end
34
- end
35
- HERE
36
- end
43
+ generate "power_api:install"
44
+ end
45
+ end
37
46
 
38
- api_error_concern_path = 'app/controllers/concerns/api_error_concern.rb'
47
+ def add_graphql
48
+ gather_gem 'graphql'
49
+ if get(:authentication)
50
+ gather_gem 'jwt'
51
+ end
52
+ gather_gems(:development, :test) do
53
+ gather_gem 'graphql_playground-rails'
54
+ end
39
55
 
40
- copy_file '../assets/api/base_controller.rb', 'app/controllers/api/v1/base_controller.rb'
41
- copy_file '../assets/api/api_error_concern.rb', api_error_concern_path
42
- copy_file '../assets/api/responder.rb', 'app/responders/api_responder.rb'
56
+ after(:gem_install) do
57
+ generate "graphql:install --skip_graphiql"
58
+ playground_route = <<~HEREDOC
59
+ \n
60
+ if Rails.env.development?
61
+ mount GraphqlPlayground::Rails::Engine, at: "/graphiql", graphql_path: "/graphql"
62
+ end
63
+ HEREDOC
64
+ inject_into_file(
65
+ 'config/routes.rb',
66
+ playground_route,
67
+ after: 'post "/graphql", to: "graphql#execute"'
68
+ )
69
+ copy_file(
70
+ "../assets/config/graphql_playground.rb",
71
+ "config/initializers/graphql_playground.rb"
72
+ )
73
+ remove_dir 'app/graphql/types'
74
+ directory '../assets/app/graphql/types', 'app/graphql/types'
75
+ gsub_file 'app/graphql/mutations/base_mutation.rb', 'Types::Base', 'Types::Base::Base'
76
+ directory '../assets/app/graphql/queries', 'app/graphql/queries'
77
+ gsub_file 'app/graphql/mutations/base_mutation.rb', 'RelayClassic', ''
78
+ gsub_file(
79
+ 'app/graphql/mutations/base_mutation.rb',
80
+ " input_object_class Types::Base::BaseInputObject\n", ''
81
+ )
43
82
 
44
- if selected?(:report_error)
45
- previous_line = 'logger.error exception.backtrace.join("\n")'
46
- new_line = "\n Raven.capture_exception(exception)"
47
- insert_into_file api_error_concern_path, new_line, after: previous_line
83
+ if get(:authentication)
84
+ copy_file(
85
+ '../assets/app/graphql/graphql_controller.rb',
86
+ 'app/controllers/graphql_controller.rb',
87
+ force: true
88
+ )
89
+ gsub_file(
90
+ 'app/controllers/graphql_controller.rb',
91
+ 'GqlSampleSchema',
92
+ "#{get(:titleized_app_name).delete(' ')}Schema"
93
+ )
94
+ copy_file(
95
+ '../assets/app/graphql/mutations/login_mutation.rb',
96
+ 'app/graphql/mutations/login_mutation.rb'
97
+ )
98
+ inject_into_file(
99
+ 'app/graphql/types/mutation_type.rb',
100
+ "\n field :login, mutation: Mutations::LoginMutation",
101
+ after: 'class MutationType < Types::Base::BaseObject'
102
+ )
103
+ append_to_file(".env.development", "HMAC_SECRET=\n")
48
104
  end
105
+
106
+ inject_into_file(
107
+ 'app/controllers/graphql_controller.rb',
108
+ "\n\n skip_before_action :verify_authenticity_token",
109
+ after: '# protect_from_forgery with: :null_session'
110
+ )
111
+
112
+ add_readme_section :internal_dependencies, :graphql
49
113
  end
50
114
  end
51
115
  end
@@ -12,7 +12,11 @@ class Recipes::BackgroundProcessor < Rails::AppBuilder
12
12
  end
13
13
 
14
14
  def create
15
- add_sidekiq if get(:background_processor)
15
+ if get(:background_processor)
16
+ add_sidekiq
17
+ add_docker_compose_redis_config
18
+ set_redis_dot_env
19
+ end
16
20
  end
17
21
 
18
22
  def install
@@ -26,6 +30,35 @@ class Recipes::BackgroundProcessor < Rails::AppBuilder
26
30
  gem_exists?(/sidekiq/)
27
31
  end
28
32
 
33
+ private
34
+
35
+ def add_docker_compose_redis_config
36
+ compose = DockerHelpers.new('docker-compose.yml')
37
+
38
+ service_definition =
39
+ <<~YAML
40
+ image: redis
41
+ ports:
42
+ - 6379
43
+ volumes:
44
+ - redis_data:/data
45
+ YAML
46
+
47
+ compose.add_service('redis', service_definition)
48
+ compose.add_volume('redis_data')
49
+ end
50
+
51
+ def set_redis_dot_env
52
+ append_to_file(
53
+ '.env.development',
54
+ <<~TEXT
55
+ REDIS_HOST=127.0.0.1
56
+ REDIS_PORT=$(make services-port SERVICE=redis PORT=6379)
57
+ REDIS_URL=redis://${REDIS_HOST}:${REDIS_PORT}/1
58
+ TEXT
59
+ )
60
+ end
61
+
29
62
  def add_sidekiq
30
63
  gather_gem("sidekiq")
31
64
  add_adapters("sidekiq")