diff --git a/.bundle/config b/.bundle/config new file mode 100644 index 00000000..9c6dba45 --- /dev/null +++ b/.bundle/config @@ -0,0 +1,2 @@ +--- +BUNDLE_GEMFILE: ".template/Gemfile" diff --git a/.github/workflows/test_template.yml b/.github/workflows/test_template.yml new file mode 100644 index 00000000..20ae608a --- /dev/null +++ b/.github/workflows/test_template.yml @@ -0,0 +1,42 @@ +name: Test Template + +on: push + +env: + RUBY_VERSION: 3.0.1 + +jobs: + test: + name: Test template + runs-on: ubuntu-latest + + steps: + - name: Cancel previous runs + uses: styfle/cancel-workflow-action@0.6.0 + with: + access_token: ${{ github.token }} + + - name: Checkout Repository + uses: actions/checkout@v2.3.4 + + - name: Setup Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ env.RUBY_VERSION }} + bundler-cache: true + + - name: Cache gems + uses: actions/cache@v2 + with: + path: vendor/bundle + key: ${{ runner.os }}-template-${{ env.RUBY_VERSION }}-${{ hashFiles('**/Gemfile.lock') }} + restore-keys: | + ${{ runner.os }}-template-${{ env.RUBY_VERSION }}- + + - name: Install gems + run: | + bundle config path vendor/bundle + bundle install --jobs 4 --retry 3 + + - name: Run RuboCop + run: bundle exec rubocop --config .template/.rubocop.yml --parallel diff --git a/.rubocop.yml b/.rubocop.yml index b60c529c..db34c042 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,4 +1,4 @@ -require: +require: - rubocop-rails - rubocop-rspec - rubocop-performance @@ -15,7 +15,7 @@ AllCops: - 'node_modules/**/*' - 'config/**/*' - 'tmp/**/*' - TargetRubyVersion: 2.7 + TargetRubyVersion: 3 NewCops: enable Style/Documentation: diff --git a/.template/.rubocop.yml b/.template/.rubocop.yml new file mode 100644 index 00000000..a7831f9c --- /dev/null +++ b/.template/.rubocop.yml @@ -0,0 +1,53 @@ +AllCops: + NewCops: enable + TargetRubyVersion: 3 + Exclude: + - 'vendor/**/*' + +Lint/NonDeterministicRequireOrder: + Exclude: + - '../spec/rails_helper.rb' + +Metrics/MethodLength: + Exclude: + - '../template.rb' + - '**/template.rb' + - 'hooks/**/*' + +Metrics/AbcSize: + Enabled: false + +Metrics/BlockLength: + Enabled: false + +Metrics/CyclomaticComplexity: + Exclude: + - '../template.rb' + - '**/template.rb' + +Metrics/PerceivedComplexity: + Exclude: + - '../template.rb' + - '**/template.rb' + +Naming/FileName: + Enabled: false + +Style/Documentation: + Enabled: false + +Style/FrozenStringLiteralComment: + Enabled: false + +# TODO: Enable this rule later +Style/GlobalVars: + Enabled: false + +# TODO: Enable this rule later +Style/RegexpLiteral: + Enabled: false + +Style/TrivialAccessors: + Exclude: + - '../template.rb' + - '**/template.rb' diff --git a/.template/Gemfile b/.template/Gemfile index 06558bb4..9bf79d1f 100644 --- a/.template/Gemfile +++ b/.template/Gemfile @@ -1,6 +1,7 @@ source 'https://rubygems.org' +gem 'docker-api' # A lightweight Ruby client for the Docker Remote API gem 'rspec' # BDD for Ruby gem 'rspec-wait' # Wait for conditions in RSpec +gem 'rubocop', require: false # A Ruby static code analyzer and formatter, based on the community Ruby style guide. gem 'serverspec' # RSpec tests for your servers -gem 'docker-api' # A lightweight Ruby client for the Docker Remote API diff --git a/.template/Gemfile.lock b/.template/Gemfile.lock index bc472589..0b460254 100644 --- a/.template/Gemfile.lock +++ b/.template/Gemfile.lock @@ -1,6 +1,7 @@ GEM remote: https://rubygems.org/ specs: + ast (2.4.2) diff-lcs (1.4.4) docker-api (2.2.0) excon (>= 0.47.0) @@ -11,6 +12,12 @@ GEM net-ssh (>= 2.6.5, < 7.0.0) net-ssh (6.1.0) net-telnet (0.1.1) + parallel (1.21.0) + parser (3.1.0.0) + ast (~> 2.4.1) + rainbow (3.1.1) + regexp_parser (2.2.0) + rexml (3.2.5) rspec (3.9.0) rspec-core (~> 3.9.0) rspec-expectations (~> 3.9.0) @@ -29,6 +36,18 @@ GEM rspec-support (3.9.3) rspec-wait (0.0.9) rspec (>= 3, < 4) + rubocop (1.25.0) + parallel (~> 1.10) + parser (>= 3.1.0.0) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 1.8, < 3.0) + rexml + rubocop-ast (>= 1.15.1, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 1.4.0, < 3.0) + rubocop-ast (1.15.1) + parser (>= 3.0.1.1) + ruby-progressbar (1.11.0) serverspec (2.41.5) multi_json rspec (~> 3.0) @@ -40,6 +59,7 @@ GEM net-ssh (>= 2.7) net-telnet (= 0.1.1) sfl + unicode-display_width (2.1.0) PLATFORMS ruby @@ -48,6 +68,7 @@ DEPENDENCIES docker-api rspec rspec-wait + rubocop serverspec BUNDLED WITH diff --git a/.template/addons/nginx/docker.rb b/.template/addons/nginx/docker.rb index 4ad76fe0..a389ff3b 100644 --- a/.template/addons/nginx/docker.rb +++ b/.template/addons/nginx/docker.rb @@ -2,7 +2,7 @@ 'nginx ' end -insert_into_file 'Dockerfile', after: %r(WORKDIR.+\n) do +insert_into_file 'Dockerfile', after: %r{WORKDIR.+\n} do <<~DOCKERFILE # Nginx config diff --git a/.template/addons/phrase_app/template.rb b/.template/addons/phrase_app/template.rb index d7a29f98..383dd400 100644 --- a/.template/addons/phrase_app/template.rb +++ b/.template/addons/phrase_app/template.rb @@ -1,6 +1,6 @@ after_bundle do use_source_path __dir__ - + copy_file '.phraseapp.yml' apply 'spec/template.rb' end diff --git a/.template/bin/rubocop b/.template/bin/rubocop new file mode 100755 index 00000000..8c983bad --- /dev/null +++ b/.template/bin/rubocop @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +bundle exec rubocop --config .template/.rubocop.yml $@ diff --git a/.template/hooks/before_complete/fix_rubocop.rb b/.template/hooks/before_complete/fix_rubocop.rb index ab77ff79..5d29b324 100644 --- a/.template/hooks/before_complete/fix_rubocop.rb +++ b/.template/hooks/before_complete/fix_rubocop.rb @@ -2,11 +2,11 @@ def fixing_rubocop after_bundle do use_source_path __dir__ - cops = %w( + cops = %w[ Style/FrozenStringLiteralComment Style/StringLiterals Layout/EmptyLineAfterMagicComment - ).join(',') + ].join(',') run "rubocop --only #{cops} --auto-correct-all --out tmp/template_rubocop.txt" end diff --git a/.template/lib/template/errors.rb b/.template/lib/template/errors.rb index 87728b71..47f99445 100644 --- a/.template/lib/template/errors.rb +++ b/.template/lib/template/errors.rb @@ -1 +1,3 @@ +# rubocop:todo Style/ClassAndModuleChildren class Template::Errors < Template::Messages; end +# rubocop:enable Style/ClassAndModuleChildren diff --git a/.template/lib/template/messages.rb b/.template/lib/template/messages.rb index f90aee11..53d9eee8 100644 --- a/.template/lib/template/messages.rb +++ b/.template/lib/template/messages.rb @@ -1,3 +1,4 @@ +# rubocop:todo Style/ClassAndModuleChildren class Template::Messages delegate :empty?, to: :messages @@ -17,3 +18,4 @@ def to_s attr_reader :messages end +# rubocop:enable Style/ClassAndModuleChildren diff --git a/.template/spec/addons/base/github/template_spec.rb b/.template/spec/addons/base/github/template_spec.rb index e74d36d3..2d48d911 100644 --- a/.template/spec/addons/base/github/template_spec.rb +++ b/.template/spec/addons/base/github/template_spec.rb @@ -20,11 +20,11 @@ # TODO: Can't test this as it is now ignored by `.dockerignore` xit 'modifies the README.md' do - expect(file('README.md')).to contain("## Documentation") + expect(file('README.md')).to contain('## Documentation') - expect(file('README.md')).not_to contain("## Getting Started") - expect(file('README.md')).not_to contain("## Testing") - expect(file('README.md')).not_to contain("## CI/CD") + expect(file('README.md')).not_to contain('## Getting Started') + expect(file('README.md')).not_to contain('## Testing') + expect(file('README.md')).not_to contain('## CI/CD') end describe '.github/wiki/Getting-Started.md' do @@ -33,9 +33,9 @@ end it 'contains the correct content extracted from README.md' do - expect(file('.github/wiki/Getting-Started.md')).to contain("### Prerequisites") - expect(file('.github/wiki/Getting-Started.md')).to contain("### Docker") - expect(file('.github/wiki/Getting-Started.md')).to contain("### Development") + expect(file('.github/wiki/Getting-Started.md')).to contain('### Prerequisites') + expect(file('.github/wiki/Getting-Started.md')).to contain('### Docker') + expect(file('.github/wiki/Getting-Started.md')).to contain('### Development') end end @@ -51,10 +51,10 @@ end it 'contains the correct content extracted from the workflow README.md' do - expect(file('.github/wiki/CI-CD.md')).to contain("## Test workflow") - expect(file('.github/wiki/CI-CD.md')).to contain("## Test production build workflow") - expect(file('.github/wiki/CI-CD.md')).to contain("## Deploy to Heroku workflow") - expect(file('.github/wiki/CI-CD.md')).to contain("## Publish to Wiki workflow") + expect(file('.github/wiki/CI-CD.md')).to contain('## Test workflow') + expect(file('.github/wiki/CI-CD.md')).to contain('## Test production build workflow') + expect(file('.github/wiki/CI-CD.md')).to contain('## Deploy to Heroku workflow') + expect(file('.github/wiki/CI-CD.md')).to contain('## Publish to Wiki workflow') end it 'deletes the workflow README.md' do @@ -68,9 +68,9 @@ end it 'contains the correct content extracted from README.md' do - expect(file('.github/wiki/Testing.md')).to contain("### Docker-based tests on the CI server") - expect(file('.github/wiki/Testing.md')).to contain("### Test") - expect(file('.github/wiki/Testing.md')).to contain("### Automated Code Review Setup") + expect(file('.github/wiki/Testing.md')).to contain('### Docker-based tests on the CI server') + expect(file('.github/wiki/Testing.md')).to contain('### Test') + expect(file('.github/wiki/Testing.md')).to contain('### Automated Code Review Setup') end end end diff --git a/.template/spec/addons/base/phrase_app/template.rb b/.template/spec/addons/base/phrase_app/template.rb index 1285f34d..505ad730 100644 --- a/.template/spec/addons/base/phrase_app/template.rb +++ b/.template/spec/addons/base/phrase_app/template.rb @@ -2,7 +2,7 @@ it 'creates .phraseapp.yml file' do expect(file('.phraseapp.yml')).to exist end - + it 'adds PhraseApp to codebase_spec' do expect(file('spec/codebase/codebase_spec.rb')).to contain("it 'does not offend PhraseApp Pull configuration' do") end diff --git a/.template/spec/base/app/controllers/concerns/localization_spec.rb b/.template/spec/base/app/controllers/concerns/localization_spec.rb index 8c7b1254..48087414 100644 --- a/.template/spec/base/app/controllers/concerns/localization_spec.rb +++ b/.template/spec/base/app/controllers/concerns/localization_spec.rb @@ -1,6 +1,6 @@ describe 'localization concern' do subject { file('app/controllers/concerns/localization.rb') } - + it 'contains the around_action' do expect(subject).to contain('around_action :switch_locale') end diff --git a/.template/spec/base/config/environments/production_spec.rb b/.template/spec/base/config/environments/production_spec.rb index 003ab918..2e18306e 100644 --- a/.template/spec/base/config/environments/production_spec.rb +++ b/.template/spec/base/config/environments/production_spec.rb @@ -14,7 +14,7 @@ end it 'removes the config.i18n.fallbacks = true' do - expect(subject).not_to contain("config.i18n.fallbacks = true") + expect(subject).not_to contain('config.i18n.fallbacks = true') end private diff --git a/.template/variants/web/.gitignore.rb b/.template/variants/web/.gitignore.rb index 3a8e1f0e..60fe5dce 100644 --- a/.template/variants/web/.gitignore.rb +++ b/.template/variants/web/.gitignore.rb @@ -1,13 +1,13 @@ append_to_file '.gitignore' do <<~IGNORE - # Ignore i18n.js generated files - # If deploy to heroku with git, please remove this as it prevents the files to be committed - /app/javascript/translations/* + # Ignore i18n.js generated files + # If deploy to heroku with git, please remove this as it prevents the files to be committed + /app/javascript/translations/* - # Ignore asset builds - /app/assets/builds/* + # Ignore asset builds + /app/assets/builds/* - # Ignore Node dependencies - /node_modules + # Ignore Node dependencies + /node_modules IGNORE end diff --git a/.template/variants/web/package.json.rb b/.template/variants/web/package.json.rb index d124d820..86f4851b 100644 --- a/.template/variants/web/package.json.rb +++ b/.template/variants/web/package.json.rb @@ -32,6 +32,13 @@ source_stylesheet = 'app/assets/stylesheets/application.scss' bundled_stylesheet = 'app/assets/builds/application.css' +bundled_stylesheet_options = [ + '--no-source-map', + '--load-path=node_modules' +] run %(npm set-script build "node app/javascript/build.js") -run %(npm set-script build:css "sass #{source_stylesheet} #{bundled_stylesheet} --no-source-map --load-path=node_modules") +run %( + npm set-script build:css \ + "sass #{source_stylesheet} #{bundled_stylesheet} #{bundled_stylesheet_options.join(' ')}" +) diff --git a/README.md b/README.md index fda3d101..f0212198 100644 --- a/README.md +++ b/README.md @@ -20,11 +20,13 @@ with building complex applications over the years. - Install rails `7.0.1` - Install node `16.13.2` (For creating web application) +> 📝 If running on Apple M1, to build docker image, please make sure to set platform to AMD64 by `export DOCKER_DEFAULT_PLATFORM=linux/amd64` + ### Use the template In order to use the template, initialize a new app with the following parameters: -``` +```sh rails new -m https://raw.githubusercontent.com/nimblehq/rails-templates/master/template.rb ``` @@ -33,7 +35,7 @@ Supported template options: To apply the template on an existing application, run following rails command: -``` +```sh rails app:template LOCATION=https://raw.githubusercontent.com/nimblehq/rails-templates/master/template.rb # To apply on an api application @@ -172,6 +174,21 @@ e.g. `TOOL_VERSION` for `.tool-version` file. For the normal string, name it after the content e.g. `ERROR` for template error message. +## Testing the Template + +To run [RuboCop](https://github.com/rubocop/rubocop) against the template: + +```sh +.template/bin/rubocop +``` + +Any RuboCop command options can be passed: + +```sh +# Run RuboCop with auto correct +.template/bin/rubocop -a +``` + ## License This project is Copyright (c) 2014 and onwards. It is free software, diff --git a/bin/docker-prepare b/bin/docker-prepare index 03c05e88..ef2819dc 100755 --- a/bin/docker-prepare +++ b/bin/docker-prepare @@ -2,8 +2,8 @@ require 'fileutils' # Copy the project dependencies to build the docker image -DOCKER_TMP_FOLDER = 'tmp/docker' -ENGINES_DIRECTORY = 'engines' +DOCKER_TMP_FOLDER = 'tmp/docker'.freeze +ENGINES_DIRECTORY = 'engines'.freeze FileUtils.rm_rf DOCKER_TMP_FOLDER FileUtils.mkdir DOCKER_TMP_FOLDER diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 7c8e0f31..6efafcdd 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -6,7 +6,7 @@ require 'json_matchers/rspec' require 'pundit/rspec' -Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f } +Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f } ActiveRecord::Migration.maintain_test_schema! diff --git a/template.rb b/template.rb index 1e3eecf3..2b7eb8c0 100644 --- a/template.rb +++ b/template.rb @@ -19,8 +19,8 @@ }.freeze if WEB_VARIANT - NODE_VERSION='16.13.2'.freeze - NODE_SOURCE_VERSION='16'.freeze # Used in Dockerfile https://github.com/nodesource/distributions + NODE_VERSION = '16.13.2'.freeze + NODE_SOURCE_VERSION = '16'.freeze # Used in Dockerfile https://github.com/nodesource/distributions end def apply_template!(template_root) @@ -59,7 +59,7 @@ def apply_template!(template_root) # Add-ons - [Default] DEFAULT_ADDONS.each_key do |addon| - apply ".template/addons/#{addon.to_s}/template.rb" + apply ".template/addons/#{addon}/template.rb" end post_default_addons_install @@ -117,7 +117,7 @@ def install_addon_prompt(addon) end def post_default_addons_install - addons = "" + addons = '' DEFAULT_ADDONS.each_value do |addon| addons << "* #{addon}\n " end