jt_tools 0.0.2 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +35 -7
  3. data/.github/FUNDING.yml +4 -0
  4. data/.standard.yml +10 -0
  5. data/Gemfile +3 -1
  6. data/README.md +21 -11
  7. data/Rakefile +5 -5
  8. data/_config.yml +2 -1
  9. data/bin/test +22 -9
  10. data/jt_tools.gemspec +14 -14
  11. data/lib/install/.circleci/{config.yml.sample → config.yml} +72 -30
  12. data/lib/install/.dependabot/config.yml +3 -3
  13. data/lib/install/.editorconfig +70 -0
  14. data/lib/install/.erb-lint.yml +7 -7
  15. data/lib/install/.eslintrc.js +8 -11
  16. data/lib/install/.pronto.yml +3 -5
  17. data/lib/install/.reek.yml +8 -16
  18. data/lib/install/.rubocop.yml +59 -20
  19. data/lib/install/.simplecov +17 -0
  20. data/lib/install/{.yamllint → .yamllint.yml} +2 -1
  21. data/lib/install/Brewfile +15 -10
  22. data/lib/install/Gemfile.tools +4 -2
  23. data/lib/install/app.json +19 -41
  24. data/lib/install/bin/circleci-auto_upgrade_tools +3 -3
  25. data/lib/install/bin/git-hooks/{post-merge.sample → post-merge} +5 -10
  26. data/lib/install/bin/git-hooks/{pre-push.sample → pre-push} +1 -1
  27. data/lib/install/bin/heroku-postdeploy +1 -7
  28. data/lib/install/bin/heroku-release +4 -1
  29. data/lib/install/bin/{lint-github-pr → lint-pr} +0 -0
  30. data/lib/install/bin/tools-setup +1 -1
  31. data/lib/install/bin/tools-upgrade +2 -0
  32. data/lib/install/codecov.yml +5 -4
  33. data/lib/install/config/rails_best_practices.yml +43 -0
  34. data/lib/jt_tools.rb +3 -1
  35. data/lib/jt_tools/railtie.rb +4 -2
  36. data/lib/{version.rb → jt_tools/version.rb} +1 -1
  37. data/lib/tasks/install.rake +6 -4
  38. data/rejuvenation.rb +4 -5
  39. data/template.rb +139 -69
  40. metadata +14 -14
  41. data/_sample/test_erb.html.erb +0 -2
  42. data/_sample/test_eslint.js +0 -1
  43. data/_sample/test_yamlint.yml +0 -1
  44. data/lib/install/.prettierrc.js +0 -4
  45. data/lib/install/lib/test/coverage.rb +0 -14
@@ -4,7 +4,7 @@ set -e
4
4
 
5
5
  echo "-----Create and switch to new branch-----"
6
6
 
7
- current_date=`date +"%Y%m%d%H%M"`
7
+ current_date=$(date +"%Y%m%d%H%M")
8
8
  new_branch_name="auto-upgrade-tools-dependencies-${current_date}"
9
9
  git checkout -b $new_branch_name
10
10
 
@@ -17,11 +17,11 @@ if bin/tools-upgrade; then
17
17
  git config user.email "circleci.bot@example.com"
18
18
 
19
19
  git commit -am "Upgrades Gemfile.tools dependencies"
20
- git push https://$GITHUB_TOKEN@github.com/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME.git -f
20
+ git push "https://$GITHUB_TOKEN@github.com/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME.git" -f
21
21
 
22
22
  curl -X POST \
23
23
  -H "Authorization: token ${GITHUB_TOKEN}" \
24
- -d '{"title":"Upgrade tools dependencies","base":"master","head":"'$CIRCLE_PROJECT_USERNAME':'$new_branch_name'"}' \
24
+ -d '{"title":"Upgrades tools dependencies","base":"master","head":"'$CIRCLE_PROJECT_USERNAME':'$new_branch_name'"}' \
25
25
  https://api.github.com/repos/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME/pulls
26
26
  exit 0
27
27
  else
@@ -12,17 +12,12 @@ if [[ $reflog_message =~ "merge" ]]; then
12
12
  fi
13
13
 
14
14
  if [[ $branch_name == "master" ]]; then
15
- bin/update
16
- bin/rake db:reset
15
+ bin/spring stop; pkill "spring";
16
+ rm -rf tmp/cache
17
+
18
+ bin/setup
17
19
 
18
- # For crystalball gem usage
19
- # file=tmp/crystalball_data.yml
20
- # find $file -mtime +5 -exec rm {} \;
21
- #
22
- # if [ ! -f "$file" ]; then
23
- # echo "Generete crystall ball index"
24
- # DISABLE_SPRING=1 CRYSTALBALL=true bin/rspec
25
- # fi
20
+ bin/rake db:reset
26
21
 
27
22
  echo "Removing merged branches..."
28
23
  git branch --merged master | grep -v "\*" | grep -v master | xargs -n 1 git branch -d
@@ -2,7 +2,7 @@
2
2
 
3
3
  set -eo pipefail
4
4
 
5
- bin/lint-github-pr
5
+ bin/lint-pr
6
6
 
7
7
  # bin/rspec --tag critical
8
8
  # bin/rails test
@@ -1,10 +1,4 @@
1
1
  #!/usr/bin/env bash
2
2
 
3
3
  echo "== Preparing database =="
4
- bin/rails db:migrate
5
-
6
- if [ "$DB_SEED_ON_DEPLOY" = "true" ]; then
7
- echo "Seeding ..."
8
- bin/rails db:seed
9
- echo "Seeding has been done!"
10
- fi
4
+ bin/rails db:prepare
@@ -1 +1,4 @@
1
- bin/rake db:migrate
1
+ #!/usr/bin/env bash
2
+
3
+ echo "== Update Database =="
4
+ bin/rake db:prepare
@@ -6,4 +6,4 @@ export BUNDLE_GEMFILE=Gemfile.tools
6
6
 
7
7
  bundle check || bundle install --jobs=4 --retry=3
8
8
 
9
- yarn install --link-duplicates --non-interactive
9
+ yarn check || yarn install
@@ -5,3 +5,5 @@ set -e
5
5
  export BUNDLE_GEMFILE=Gemfile.tools
6
6
 
7
7
  bundle update --jobs=4 --retry=3
8
+
9
+ yarn check || yarn install
@@ -1,8 +1,9 @@
1
+ ---
1
2
  codecov:
2
3
  notify:
3
- require_ci_to_pass: yes
4
+ require_ci_to_pass: true
4
5
 
5
6
  comment:
6
- layout: diff, flags, files
7
- behavior: once
8
- require_changes: no
7
+ layout: 'diff, flags, files'
8
+ behavior: 'once'
9
+ require_changes: false
@@ -0,0 +1,43 @@
1
+ ---
2
+ AddModelVirtualAttributeCheck:
3
+ AlwaysAddDbIndexCheck: {}
4
+ # CheckSaveReturnValueCheck: {}
5
+ # CheckDestroyReturnValueCheck: {}
6
+ DefaultScopeIsEvilCheck: {}
7
+ DryBundlerInCapistranoCheck: {}
8
+ # HashSyntaxCheck: {}
9
+ IsolateSeedDataCheck: {}
10
+ KeepFindersOnTheirOwnModelCheck: {}
11
+ LawOfDemeterCheck: {}
12
+ # LongLineCheck: { max_line_length: 80 }
13
+ MoveCodeIntoControllerCheck: {}
14
+ MoveCodeIntoHelperCheck: { array_count: 10 }
15
+ MoveCodeIntoModelCheck: { use_count: 10 }
16
+ MoveFinderToNamedScopeCheck: {}
17
+ MoveModelLogicIntoModelCheck: { use_count: 10 }
18
+ NeedlessDeepNestingCheck: { nested_count: 5 }
19
+ NotRescueExceptionCheck: {}
20
+ NotUseDefaultRouteCheck: {}
21
+ NotUseTimeAgoInWordsCheck: {}
22
+ OveruseRouteCustomizationsCheck: { customize_count: 3 }
23
+ ProtectMassAssignmentCheck: {}
24
+ RemoveEmptyHelpersCheck: {}
25
+ # RemoveTabCheck: {}
26
+ RemoveTrailingWhitespaceCheck: {}
27
+ # RemoveUnusedMethodsInControllersCheck: { except_methods: [] }
28
+ # RemoveUnusedMethodsInHelpersCheck: { except_methods: [] }
29
+ # RemoveUnusedMethodsInModelsCheck: { except_methods: [] }
30
+ ReplaceComplexCreationWithFactoryMethodCheck: { attribute_assignment_count: 5 }
31
+ ReplaceInstanceVariableWithLocalVariableCheck: {}
32
+ RestrictAutoGeneratedRoutesCheck: {}
33
+ SimplifyRenderInControllersCheck: {}
34
+ SimplifyRenderInViewsCheck: {}
35
+ # UseBeforeFilterCheck: { customize_count: 2 }
36
+ UseModelAssociationCheck: {}
37
+ UseMultipartAlternativeAsContentTypeOfEmailCheck: {}
38
+ # UseParenthesesInMethodDefCheck: {}
39
+ UseObserverCheck: {}
40
+ UseQueryAttributeCheck: {}
41
+ UseSayWithTimeInMigrationsCheck: {}
42
+ UseScopeAccessCheck: {}
43
+ UseTurboSprocketsRails3Check: {}
@@ -1,3 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'jt_tools/railtie' if defined?(Rails)
3
+ require "jt_tools/version"
4
+
5
+ require "jt_tools/railtie" if defined?(Rails)
@@ -1,7 +1,9 @@
1
- require 'rails/railtie'
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/railtie"
2
4
 
3
5
  class JtToolsRailtie < Rails::Railtie
4
6
  rake_tasks do
5
- load 'tasks/install.rake'
7
+ load "tasks/install.rake"
6
8
  end
7
9
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JtTools
4
- VERSION = '0.0.2'
4
+ VERSION = "0.0.7"
5
5
  end
@@ -1,9 +1,11 @@
1
- install_template_path = File.expand_path('../../template.rb', __dir__).freeze
2
- bin_path = ENV['BUNDLE_BIN'] || './bin'
1
+ # frozen_string_literal: true
2
+
3
+ install_template_path = File.expand_path("../../template.rb", __dir__).freeze
4
+ bin_path = ENV["BUNDLE_BIN"] || "./bin"
3
5
 
4
6
  namespace :jt_tools do
5
- desc 'Install jt-tools in this application'
6
- task :install do
7
+ desc "Install jt-tools in this application"
8
+ task install: :environment do
7
9
  exec "#{RbConfig.ruby} #{bin_path}/rails app:template LOCATION=#{install_template_path}"
8
10
  end
9
11
  end
@@ -1,18 +1,17 @@
1
-
2
- require 'json'
1
+ require "json"
3
2
 
4
3
  EXTRACT_DEPENDENCY_NAME = /"?(.+?)@.+?"?(?:,\s+|\Z)/.freeze
5
4
  EXTRACT_DEPENDENCY_DETAILS = /(^((?!= ).*?):\n.*?(?:\n\n|\Z))/m.freeze
6
5
 
7
6
  def direct_dependencies_names
8
- package_json = JSON.parse(File.open('package.json').read)
9
- direct_dependencies = package_json.fetch_values('dependencies', 'devDependencies', 'peerDependencies') { }
7
+ package_json = JSON.parse(File.open("package.json").read)
8
+ direct_dependencies = package_json.fetch_values("dependencies", "devDependencies", "peerDependencies") {}
10
9
  direct_dependencies.compact.inject([]) { |memo, v| memo.concat(v.keys) }
11
10
  end
12
11
 
13
12
  @dependencies = direct_dependencies_names
14
13
 
15
- yarn_lock_content = File.open('yarn.lock').read
14
+ yarn_lock_content = File.open("yarn.lock").read
16
15
  yarn_lock_content.scan(EXTRACT_DEPENDENCY_DETAILS).each do |dependency_block|
17
16
  direct_dep = @dependencies.include?(dependency_block[1].match(EXTRACT_DEPENDENCY_NAME).to_a[1])
18
17
  puts dependency_block[0] if direct_dep
@@ -7,17 +7,17 @@
7
7
  # In that case, use `git clone` to download them to a local temporary dir.
8
8
  def add_template_repository_to_source_path
9
9
  if __FILE__.match?(%r{\Ahttps?://})
10
- require 'shellwords'
11
- require 'tmpdir'
10
+ require "shellwords"
11
+ require "tmpdir"
12
12
 
13
- source_paths.unshift(temp_dir = Dir.mktmpdir('jt_tools-'))
13
+ source_paths.unshift(temp_dir = Dir.mktmpdir("jt_tools-"))
14
14
  at_exit { FileUtils.remove_entry(temp_dir) }
15
15
  git clone: [
16
- '--quiet',
17
- 'https://github.com/jetthoughts/jt_tools.git',
16
+ "--quiet",
17
+ "https://github.com/jetthoughts/jt_tools.git",
18
18
  temp_dir
19
19
  ].map { |args| Shellwords.escape(args) }
20
- .join(' ')
20
+ .join(" ")
21
21
 
22
22
  if (branch = __FILE__[%r{jt_tools/(.+)/template.rb}, 1])
23
23
  Dir.chdir(temp_dir) { git checkout: branch }
@@ -29,101 +29,171 @@ end
29
29
 
30
30
  add_template_repository_to_source_path
31
31
 
32
- say '=> Copying binstubs'
33
- directory 'lib/install/bin', 'bin'
32
+ say "=> Copying binstubs"
33
+ directory "lib/install/bin", "bin"
34
34
 
35
- chmod 'bin', 0o755 & ~File.umask, verbose: false
35
+ chmod "bin", 0o755 & ~File.umask, verbose: false
36
36
 
37
- say '=> Copying tools gemfile'
38
- copy_file 'lib/install/Gemfile.tools', 'Gemfile.tools'
37
+ say "=> Copying tools gemfile"
38
+ copy_file "lib/install/Gemfile.tools", "Gemfile.tools"
39
39
 
40
- run 'yarn add -D eslint eslint-config-airbnb-base \
41
- eslint-config-prettier eslint-plugin-import eslint-plugin-prettier prettier'
40
+ run "yarn add -D eslint jest-junit"
42
41
 
43
- say 'Copying lint configurations'
44
- copy_file 'lib/install/.better-html.yml', '.better-html.yml'
45
- copy_file 'lib/install/.erb-lint.yml', '.erb-lint.yml'
46
- copy_file 'lib/install/.eslintrc.js', '.eslintrc.js'
47
- copy_file 'lib/install/.prettierrc.js', '.prettierrc.js'
48
- copy_file 'lib/install/.pronto.yml', '.pronto.yml'
49
- copy_file 'lib/install/.pronto_eslint_npm.yml', '.pronto_eslint_npm.yml'
50
- copy_file 'lib/install/.rubocop.yml', '.rubocop.yml'
51
- copy_file 'lib/install/.yamllint', '.yamllint'
52
- copy_file 'lib/install/.reek.yml', '.reek.yml'
42
+ say "Copying lint configurations"
43
+ copy_file "lib/install/.better-html.yml", ".better-html.yml"
44
+ copy_file "lib/install/.erb-lint.yml", ".erb-lint.yml"
45
+ copy_file "lib/install/.eslintrc.js", ".eslintrc.js"
46
+ copy_file "lib/install/.pronto.yml", ".pronto.yml"
47
+ copy_file "lib/install/.pronto_eslint_npm.yml", ".pronto_eslint_npm.yml"
48
+ copy_file "lib/install/.rubocop.yml", ".rubocop.yml"
49
+ copy_file "lib/install/.yamllint.yml", ".yamllint.yml"
50
+ copy_file "lib/install/.reek.yml", ".reek.yml"
51
+ copy_file "lib/install/config/rails_best_practices.yml", "config/rails_best_practices.yml"
52
+ copy_file "lib/install/.editorconfig", ".editorconfig"
53
53
 
54
- say '=> Copying services configuration'
55
- gem 'simplecov', require: false, group: :test
54
+ say "=> Copying services configuration"
55
+ copy_file "lib/install/.simplecov", ".simplecov"
56
+ copy_file "lib/install/codecov.yml", "codecov.yml"
56
57
 
57
- copy_file 'lib/install/codecov.yml', 'codecov.yml'
58
- gem 'codecov', require: false, group: :test
58
+ say "=> Adds service client API gems"
59
59
 
60
- directory 'lib/install/.circleci', '.circleci'
60
+ gem_group :test do
61
+ gem "simplecov", require: false, group: :test
62
+ gem "codecov", require: false, group: :test
63
+ end
64
+
65
+ gem "oj"
61
66
 
62
- # Add helpers to setup Simplecov and codecov loading for tests
63
- directory 'lib/install/lib/test', 'lib/test'
67
+ gem_group :production, :staging do
68
+ gem "dalli"
69
+ gem "r7insight"
70
+ gem "rollbar"
71
+ end
64
72
 
65
- if File.read('Gemfile').include? 'rspec'
66
- gem 'rspec_junit_formatter', require: false, group: :test
73
+ directory "lib/install/.circleci", ".circleci"
74
+
75
+ if File.read("Gemfile").include? "rspec"
76
+ gem "rspec_junit_formatter", require: false, group: :test
67
77
  insert_into_file(
68
- 'spec/spec_helper.rb',
69
- "require 'test/coverage'\n",
78
+ "spec/spec_helper.rb",
79
+ "require 'simplecov' if ENV['COVERAGE']\n",
70
80
  after: /\A/
71
81
  )
82
+ insert_into_file(
83
+ ".circleci/config.yml",
84
+ "\n" + " - run: bin/rspec --format RspecJunitFormatter --out tmp/reports/rspec-results.xml --format progress",
85
+ after: "# rails test"
86
+ )
72
87
  else
73
- gem 'minitest-ci', require: false, group: :test
88
+ gem "minitest-ci", require: false, group: :test
74
89
  insert_into_file(
75
- 'test/test_helper.rb',
76
- "require 'test/coverage'\n",
90
+ "test/test_helper.rb",
91
+ "require 'simplecov' if ENV['COVERAGE']\n",
77
92
  after: /\A/
78
93
  )
94
+ insert_into_file(
95
+ ".circleci/config.yml",
96
+ "\n" + ' - run: bin/rails test "test/**/*_test.rb"',
97
+ after: "# rails test"
98
+ )
99
+
100
+ gsub_file "test/test_helper.rb",
101
+ "parallelize(workers: :number_of_processors)",
102
+ "parallelize(workers: :number_of_processors) unless ENV['COVERAGE']"
79
103
  end
80
104
 
81
- directory 'lib/install/.dependabot', '.dependabot'
105
+ directory "lib/install/.dependabot", ".dependabot"
82
106
 
83
- say '=> Copying heroku configuration'
84
- copy_file 'lib/install/app.json', 'app.json'
85
- copy_file 'lib/install/Procfile', 'Procfile'
107
+ say "=> Copying heroku configuration"
108
+ copy_file "lib/install/app.json", "app.json"
109
+ copy_file "lib/install/Procfile", "Procfile"
86
110
 
87
- say '=> Install Brew dependencies'
88
- copy_file 'lib/install/Brewfile', 'Brewfile'
111
+ say "=> Install Brew dependencies"
112
+ copy_file "lib/install/Brewfile", "Brewfile"
89
113
 
90
- say 'Setup git hooks'
91
- directory 'lib/install/bin/git-hooks', 'bin/git-hooks'
114
+ say "Setup git hooks"
115
+ directory "lib/install/bin/git-hooks", "bin/git-hooks"
92
116
 
93
- require 'bundler'
117
+ require "bundler"
94
118
  Bundler.with_original_env do
95
- say '=> Install tools'
96
- run 'bin/tools-setup'
119
+ say "=> Install tools"
120
+ run "bin/tools-setup"
97
121
 
98
- say '=> Generate binstubs for linters'
99
- run 'BUNDLE_GEMFILE=Gemfile.tools bundle binstub pronto'
100
- run 'BUNDLE_GEMFILE=Gemfile.tools bundle binstub rubocop'
122
+ say "=> Generate binstubs for linters"
123
+ run "BUNDLE_GEMFILE=Gemfile.tools bundle binstub --force pronto"
124
+ run "BUNDLE_GEMFILE=Gemfile.tools bundle binstub --force rubocop"
101
125
  end
102
126
 
103
- say '=> Set git hooks'
104
- run 'git config core.hooksPath ./bin/git-hooks'
127
+ say "=> Set git hooks"
128
+ run "git config core.hooksPath ./bin/git-hooks"
129
+ say "=> Install all new dependencies"
105
130
 
106
- say '=> Install all new dependencies'
107
131
  run <<~BREW_INSTALL
108
132
  hash brew 2> /dev/null \
109
133
  && (brew bundle check || brew bundle install) \
110
134
  || echo "Please install Homebrew: https://brew.sh/"
111
135
  BREW_INSTALL
112
136
 
113
- after_bundle do
114
- say '=> Setup default bundle config'
115
- run 'bundle config jobs 4'
116
- run 'bundle config retry 3'
137
+ say "=> Update development config"
138
+ uncomment_lines "config/environments/development.rb", /config\.file_watcher = ActiveSupport::EventedFileUpdateChecker/
139
+
140
+ say "=> Set up R7Insight"
141
+ r7insight_config = <<-CODE
142
+ if ENV['R7INSIGHT_TOKEN'].present?
143
+ Rails.logger = R7Insight.new(ENV['R7INSIGHT_TOKEN'], ENV['R7INSIGHT_REGION'])
144
+ end
145
+ CODE
146
+ insert_into_file "config/environments/production.rb",
147
+ "require 'r7_insight.rb'" + "\n\n",
148
+ before: "Rails.application.configure do"
149
+ environment(r7insight_config, env: "production")
150
+ if File.exist?("config/environments/staging.rb")
151
+ insert_into_file "config/environments/staging.rb",
152
+ "require 'r7_insight.rb'" + "\n\n",
153
+ before: "Rails.application.configure do"
154
+ environment(r7insight_config, env: "staging")
155
+ end
156
+
157
+ gem "connection_pool"
158
+
159
+ say "=> Set up Memcachier"
160
+ memcachier_config = <<-CODE
161
+ if ENV["MEMCACHIER_SERVERS"]
162
+ config.cache_store = :mem_cache_store,
163
+ ENV["MEMCACHIER_SERVERS"].split(","), {
164
+ username: ENV["MEMCACHIER_USERNAME"], password: ENV["MEMCACHIER_PASSWORD"],
165
+ failover: true, socket_timeout: 1.5, socket_failure_delay: 0.2, down_retry_delay: 60,
166
+ pool_size: ENV.fetch("RAILS_MAX_THREADS") { 5 },
167
+ }
168
+ end
169
+
170
+ CODE
171
+ environment(memcachier_config, env: "production")
172
+ if File.exist?("config/environments/staging.rb")
173
+ environment(memcachier_config, env: "staging")
174
+ end
175
+
176
+ Bundler.with_original_env do
177
+ say "=> Setup default bundle config"
178
+ run "bundle config jobs 4"
179
+ run "bundle config retry 3"
180
+
181
+ run "bundle"
117
182
  end
118
183
 
119
- say '**************************************************************************'
120
- say '**************************************************************************'
121
- say ''
122
- say 'For code coverage report aggregator, running code static analysis'
123
- say 'and auto-update of the tools.'
124
- say ''
125
- say 'Please, set CODECOV_TOKEN, GITHUB_TOKEN and PRONTO_GITHUB_ACCESS_TOKEN'
126
- say 'environment variables in CircleCI and your local env'
127
- say ''
128
- say '**************************************************************************'
129
- say '**************************************************************************'
184
+ say "**************************************************************************"
185
+ say "**************************************************************************"
186
+ say ""
187
+ say "1. Recommended Heroku Addons: Mailtrap, Rollbar, Cloudinary"
188
+ say ""
189
+ say "2. Setup Git Hooks to auto-check code and cleanup staled branches:"
190
+ say "$ `git config core.hooksPath bin/git-hooks`"
191
+ say ""
192
+ say "3. Please, set CODECOV_TOKEN, GITHUB_TOKEN and PRONTO_GITHUB_ACCESS_TOKEN"
193
+ say "environment variables in CircleCI and your local env"
194
+ say ""
195
+ say " For code coverage report aggregator, running code static analysis"
196
+ say "and auto-update of the tools."
197
+ say ""
198
+ say "**************************************************************************"
199
+ say "**************************************************************************"