zen_pro 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: '09bdf662ec106fd06acc6981f1f834c82ea21d8604b5b5cfee72ad3c83de0a50'
4
+ data.tar.gz: fb856080fad9946ae7d32926226e566f1ae9abdf1617053a5cc3b1b648fc1aba
5
+ SHA512:
6
+ metadata.gz: e2dc2a15aa6a0ee277a0aa41bd44d24abc9a0abc16f72e4afd0c100dc36d53623b0158ffc13d182dd1a1572ec701d7eb6a7355a8a4f7f4c002eeba6b1189c169
7
+ data.tar.gz: 66d71ffd60bf5bcd37326e3116d6acc509c7dae1b56a9d843e478831dd8b75cfb4fb334c3b2e808477c4ceae0d11b48b13a42c0457868e587b45df6aaecba074
data/.rubocop.yml ADDED
@@ -0,0 +1,8 @@
1
+ AllCops:
2
+ TargetRubyVersion: 3.0
3
+
4
+ Style/StringLiterals:
5
+ EnforcedStyle: double_quotes
6
+
7
+ Style/StringLiteralsInInterpolation:
8
+ EnforcedStyle: double_quotes
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2024-05-04
4
+
5
+ - Initial release
data/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # Zen
2
+
3
+ Zen - CLI for [Zero Config Rails](https://zeroconfigrails.com/)
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "minitest/test_task"
5
+
6
+ Minitest::TestTask.create
7
+
8
+ require "rubocop/rake_task"
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[test rubocop]
data/exe/zen_pro ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative "../lib/zen_pro/cli"
4
+
5
+ ZenPro::CLI.start(ARGV)
@@ -0,0 +1,28 @@
1
+ require "rest-client"
2
+
3
+ module ZenPro
4
+ module Api
5
+ class ProjectTemplate
6
+ def fetch_details(id)
7
+ response = RestClient.get("#{api_url}/#{id}")
8
+
9
+ JSON.parse(response)
10
+ rescue RestClient::ExceptionWithResponse => e
11
+ raise e.response
12
+ end
13
+
14
+ private
15
+
16
+ def api_url
17
+ base_url =
18
+ if ENV["DEVELOPMENT"]
19
+ "http://localhost:3000"
20
+ else
21
+ "https://zeroconfigrails.com"
22
+ end
23
+
24
+ "#{base_url}/api/v1/project_templates"
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,22 @@
1
+ require "thor"
2
+
3
+ require_relative "commands/generate"
4
+ require_relative "commands/configure"
5
+
6
+ module ZenPro
7
+ class CLI < Thor
8
+ map "g" => :generate
9
+ map %w[-v --version] => "version"
10
+
11
+ desc "create project and configure gems",
12
+ "Generate a Rails app and configure gems using Project Template configurations"
13
+ def generate(project_template_id)
14
+ Commands::Generate.run(project_template_id, options)
15
+ end
16
+
17
+ desc "version", "Display gem version", hide: true
18
+ def version
19
+ say "zen_pro/#{VERSION} #{RUBY_DESCRIPTION}"
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,87 @@
1
+ require "tty-prompt"
2
+
3
+ module ZenPro
4
+ module Commands
5
+ class Configure
6
+ def self.run(options)
7
+ new(options).execute
8
+ end
9
+
10
+ def initialize(options)
11
+ @app_name = options[:app_name]
12
+ @gems_configuration_commands =
13
+ options[:project_configurations]["gems_configuration_commands"]
14
+ end
15
+
16
+ # TODO: CLI doesn't exit when generators are not found, find some way to raise error and exit in this case. Maybe Rails doesn't raise any error at all when generators are not found?
17
+ def execute
18
+ return unless Dir.exist?(app_name)
19
+
20
+ if gems_configuration_commands.length.zero?
21
+ return
22
+ end
23
+
24
+ confirm_commands_to_execute
25
+
26
+ Dir.chdir(app_name) do
27
+ gems_configuration_commands.each do |command|
28
+ system! "bundle exec #{command}"
29
+ # TODO: save progress in some file inside the user's generated app so we can continue from same point if user leaves in the middle or if app exits due to some error. Also find some way to update configurations in async without stopping any gem configuration operations (not important till MVP)
30
+ end
31
+ end
32
+
33
+ # TODO: Run generators that have dynamic options here e.g. Github CI requires repository name
34
+
35
+ run_pending_migrations
36
+ end
37
+
38
+ def confirm_commands_to_execute
39
+ commands_to_display =
40
+ gems_configuration_commands
41
+ .map
42
+ .with_index do |command, index|
43
+ item_number = format("%02d", index + 1)
44
+
45
+ "#{item_number}. #{command}"
46
+ end
47
+ .join("\n")
48
+
49
+ prompt.say <<~BANNER
50
+ \nRails app is now ready with initial configurations. Next, we will move on to configuring gems you have chosen by executing following commands:
51
+
52
+ #{commands_to_display}
53
+ BANNER
54
+
55
+ continue_if? "\nContinue?"
56
+ end
57
+
58
+ def run_pending_migrations
59
+ Dir.chdir(app_name) { system! "bin/rails db:migrate" }
60
+ end
61
+
62
+ private
63
+
64
+ attr_reader :app_name, :gems_configuration_commands
65
+
66
+ def prompt
67
+ return @prompt if defined?(@prompt)
68
+
69
+ TTY::Prompt.new
70
+ end
71
+
72
+ def continue_if?(question)
73
+ return if prompt.yes?(question)
74
+
75
+ prompt.error "Cancelled"
76
+ exit
77
+ end
78
+
79
+ def system!(*args)
80
+ system(*args)
81
+ rescue StandardError
82
+ prompt.error "\n== Command #{args} failed =="
83
+ exit
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,121 @@
1
+ require "json"
2
+ require "tty-prompt"
3
+ require "tty-spinner"
4
+
5
+ module ZenPro
6
+ module Commands
7
+ class Create
8
+ def self.run(options)
9
+ new(options).execute
10
+ end
11
+
12
+ def initialize(options)
13
+ @app_name = options[:app_name]
14
+ @project_configurations = options[:project_configurations]
15
+ end
16
+
17
+ def execute
18
+ generate_rails_app
19
+ run_bin_setup
20
+ rescue StandardError => e
21
+ system! "rm -rf #{app_name}"
22
+
23
+ raise e
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :app_name, :project_configurations
29
+
30
+ def generate_rails_app
31
+ rails_generate_command =
32
+ "rails new #{app_name} #{rails_generator_options}"
33
+ commands_to_display = [
34
+ rails_generate_command,
35
+ "bundle add boring_generators --group=development",
36
+ "bin/setup"
37
+ ]
38
+
39
+ if after_rails_generate_commands.length.positive?
40
+ commands_to_display.insert(2, after_rails_generate_commands)
41
+ end
42
+
43
+ commands_to_display =
44
+ commands_to_display
45
+ .map
46
+ .with_index { |command, index| "#{index + 1}. #{command}" }
47
+ .join("\n")
48
+
49
+ prompt.say <<~BANNER
50
+ \nWe will generate a new Rails app at ./#{app_name} and execute following commands:
51
+
52
+ #{commands_to_display}
53
+ BANNER
54
+
55
+ continue_if? "\nContinue?"
56
+
57
+ system! rails_generate_command
58
+
59
+ install_boring_generators_gem
60
+
61
+ Dir.chdir(app_name) do
62
+ after_rails_generate_commands.each do |command|
63
+ system! "bundle exec #{command}"
64
+ end
65
+ end
66
+ end
67
+
68
+ def run_bin_setup
69
+ Dir.chdir(app_name) { system! "bin/setup" }
70
+ end
71
+
72
+ def rails_generator_options
73
+ project_configurations["rails_generator_options"]
74
+ end
75
+
76
+ def after_rails_generate_commands
77
+ project_configurations["after_rails_generate_commands"]
78
+ end
79
+
80
+ def install_boring_generators_gem
81
+ message = <<~BANNER
82
+ \nZen requires boring_generators gem to install and configure gems you have chosen, adding it to your project's Gemfile so generators for gems are available inside your app during configuration.\n
83
+ BANNER
84
+
85
+ prompt.say message, color: :blue
86
+
87
+ Dir.chdir(app_name) do
88
+ system! "bundle add boring_generators --group=development"
89
+ end
90
+ end
91
+
92
+ # TODO: Register everything below this as Thor commands so they can be used throughout the app
93
+ def prompt
94
+ return @prompt if defined?(@prompt)
95
+
96
+ TTY::Prompt.new
97
+ end
98
+
99
+ # TODO: only load spinners if --silent option is enabled else output will be shown in shell so this is not required
100
+ def spinner
101
+ return @spinner if defined?(@spinner)
102
+
103
+ TTY::Spinner.new(format: :dots)
104
+ end
105
+
106
+ def continue_if?(question)
107
+ return if prompt.yes?(question)
108
+
109
+ prompt.error "Cancelled"
110
+ exit
111
+ end
112
+
113
+ def system!(*args)
114
+ system(*args)
115
+ rescue StandardError
116
+ prompt.error "\n== Command #{args} failed =="
117
+ exit
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,81 @@
1
+ require "forwardable"
2
+
3
+ require "thor"
4
+
5
+ require_relative "create"
6
+ require_relative "configure"
7
+ require_relative "../api/project_template"
8
+
9
+ module ZenPro
10
+ module Commands
11
+ class Generate
12
+ extend Forwardable
13
+
14
+ def self.run(project_template_id, options)
15
+ instance = new
16
+
17
+ instance.welcome_message
18
+ app_name = instance.ask_app_name
19
+ project_configurations =
20
+ instance.fetch_project_template_configurations(project_template_id)
21
+ all_options = {
22
+ project_template_id: project_template_id,
23
+ app_name: app_name,
24
+ project_configurations: project_configurations,
25
+ **options
26
+ }
27
+
28
+ ZenPro::Commands::Create.run(all_options)
29
+ # TODO: call class/method to save progress since rails app is now generated
30
+ ZenPro::Commands::Configure.run(all_options)
31
+ # TODO: API call to mark project as configured and store all configurations
32
+ instance.setup_complete_message(app_name)
33
+ rescue StandardError => e
34
+ prompt = TTY::Prompt.new
35
+
36
+ prompt.error "\nOops, Zen encountered an error!"
37
+
38
+ prompt.say "\n#{e.message}"
39
+ end
40
+
41
+ def welcome_message
42
+ prompt.say <<~BANNER
43
+ Welcome to Zero Config Rails!
44
+
45
+ We will ask you a few questions while all other options will automatically be added as per application configurations in the Web App.
46
+ BANNER
47
+ end
48
+
49
+ def ask_app_name
50
+ name =
51
+ prompt.ask "\nWhat would you like to name your app? e.g. zero_config_rails or zero-config-rails"
52
+
53
+ name.chomp
54
+ end
55
+
56
+ def fetch_project_template_configurations(id)
57
+ prompt.say "\nFetching your project's configurations from the server ..."
58
+
59
+ ZenPro::Api::ProjectTemplate.new.fetch_details(id)
60
+ end
61
+
62
+ def setup_complete_message(app_name)
63
+ prompt.say "\nšŸŽ‰šŸŽ‰šŸŽ‰"
64
+ prompt.ok "Congratulations! Your app is fully configured.\n"
65
+
66
+ prompt.say <<~BANNER
67
+ 1. Run the rails server with `cd #{app_name} && rails s`
68
+ 2. You can access the app at http://localhost:3000
69
+ BANNER
70
+ end
71
+
72
+ private
73
+
74
+ def prompt
75
+ return @prompt if defined?(@prompt)
76
+
77
+ TTY::Prompt.new
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ZenPro
4
+ VERSION = "0.1.0"
5
+ end
data/lib/zen_pro.rb ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "zen_pro/version"
4
+
5
+ module ZenPro
6
+ class Error < StandardError
7
+ end
8
+ # Your code goes here...
9
+ end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: zen_pro
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Prabin Poudel
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-05-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: tty-prompt
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.23'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.23'
41
+ - !ruby/object:Gem::Dependency
42
+ name: tty-spinner
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.9'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.9'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rest-client
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.1'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.1'
69
+ description: CLI for Zero Config Rails. Run the command and relax (zen mode).
70
+ email:
71
+ - probnpoudel@gmail.com
72
+ executables:
73
+ - zen_pro
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".rubocop.yml"
78
+ - CHANGELOG.md
79
+ - README.md
80
+ - Rakefile
81
+ - exe/zen_pro
82
+ - lib/zen_pro.rb
83
+ - lib/zen_pro/api/project_template.rb
84
+ - lib/zen_pro/cli.rb
85
+ - lib/zen_pro/commands/configure.rb
86
+ - lib/zen_pro/commands/create.rb
87
+ - lib/zen_pro/commands/generate.rb
88
+ - lib/zen_pro/version.rb
89
+ homepage: https://zeroconfigrails.com
90
+ licenses:
91
+ -
92
+ metadata:
93
+ source_code_uri: https://github.com/Zero-Config-Rails/zen
94
+ bug_tracker_uri: https://github.com/Zero-Config-Rails/zen/issues
95
+ documentation_uri: https://github.com/Zero-Config-Rails/zen/blob/main/README.md
96
+ homepage_uri: https://zeroconfigrails.com
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: 3.0.0
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubygems_version: 3.5.10
113
+ signing_key:
114
+ specification_version: 4
115
+ summary: CLI for https://zeroconfigrails.com
116
+ test_files: []