diff --git a/.dockerignore b/.dockerignore index 8501fa57..05d26098 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,16 +1,19 @@ # flyctl launch added from .gitignore +**/*.gem +**/*.key +**/Gemfile.lock .bundle +.env doc +fly.toml log/*.log +node_modules pkg -tmp +tags test/dummy/db/*.sqlite3 test/dummy/db/*.sqlite3-* test/dummy/log/*.log +test/dummy/public/assets test/dummy/storage test/dummy/tmp -test/dummy/public/assets -node_modules -**/Gemfile.lock -**/*.key -fly.toml +tmp diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 8b9eecff..16e46bfc 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -9,14 +9,14 @@ # the `language` matrix defined below to confirm you have the correct set of # supported CodeQL languages. # -name: "CodeQL" +name: 'CodeQL' on: push: - branches: [ "main" ] + branches: ['main'] pull_request: # The branches below must be a subset of the branches above - branches: [ "main" ] + branches: ['main'] schedule: - cron: '45 17 * * 2' @@ -32,41 +32,40 @@ jobs: strategy: fail-fast: false matrix: - language: [ 'javascript', 'ruby' ] + language: ['javascript', 'ruby'] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support steps: - - name: Checkout repository - uses: actions/checkout@v3 + - name: Checkout repository + uses: actions/checkout@v3 - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - - # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs - # queries: security-extended,security-and-quality + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v2 + # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality - # âšī¸ Command-line programs to run using the OS shell. - # đ See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 - # If the Autobuild fails above, remove it and uncomment the following three lines. - # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + # âšī¸ Command-line programs to run using the OS shell. + # đ See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - # - run: | - # echo "Run, Build Application using script" - # ./location_of_script_within_repo/buildscript.sh + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/prettier-standard.yml b/.github/workflows/prettier-standard.yml deleted file mode 100644 index 6ef2a1ba..00000000 --- a/.github/workflows/prettier-standard.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Prettier-Standard - -on: - pull_request: - branches: - - '*' - push: - branches: - - main - -jobs: - prettier: - name: Prettier-Standard Check Action - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Setup Node - uses: actions/setup-node@v3 - with: - version: '16.x' - - run: yarn - working-directory: . - - run: yarn run prettier-standard --check ./app/javascript/**/*.js - working-directory: . diff --git a/.github/workflows/prettier.yml b/.github/workflows/prettier.yml new file mode 100644 index 00000000..0381a8bf --- /dev/null +++ b/.github/workflows/prettier.yml @@ -0,0 +1,28 @@ +name: Prettier + +on: + pull_request: + branches: + - '*' + push: + branches: + - main + +jobs: + prettier: + name: Prettier Check Action + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Setup Node + uses: actions/setup-node@v3 + with: + version: '16.x' + cache: 'yarn' + + - name: Yarn install + run: yarn install --frozen-lockfile + + - name: Run Prettier + run: yarn run prettier --write package.json prettier.config.js bin/build.mjs app/javascript/**/**/**/**/*.js test/dummy/app/javascript/**/**/**/**/*.js test/dummy/app/assets/stylesheets/**/**/**/**/*.css test/dummy/app/views/**/**/**/**/*.css + diff --git a/.github/workflows/standardrb.yml b/.github/workflows/standardrb.yml index 11a69e54..a1756d36 100644 --- a/.github/workflows/standardrb.yml +++ b/.github/workflows/standardrb.yml @@ -14,23 +14,15 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ruby-version: ['3.1'] + ruby-version: ['2.7'] + steps: - - uses: actions/checkout@v3 - - name: Set up Ruby ${{ matrix.ruby-version }} - uses: ruby/setup-ruby@v1 - with: - ruby-version: ${{ matrix.ruby-version }} - - uses: actions/cache@v1 - with: - path: vendor/bundle - key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }} - restore-keys: | - ${{ runner.os }}-gems- - - name: Bundle install - run: | - gem install bundler - bundle config path vendor/bundle - bundle install --jobs 4 --retry 3 - - name: Run StandardRB - run: bundle exec standardrb --format progress + - uses: actions/checkout@v3 + - name: Set up Ruby ${{ matrix.ruby-version }} + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby-version }} + bundler-cache: true + + - name: Run StandardRB + run: bundle exec standardrb --format progress diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 752b4d20..9993b9d7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -15,28 +15,23 @@ jobs: strategy: matrix: ruby-version: ['2.7', '3.0', '3.1', '3.2'] + steps: - - uses: actions/checkout@v3 - - name: Set up Ruby ${{ matrix.ruby-version }} - uses: ruby/setup-ruby@v1 - with: - ruby-version: ${{ matrix.ruby-version }} - - uses: actions/cache@v1 - with: - path: vendor/bundle - key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }} - restore-keys: | - ${{ runner.os }}-gems- - - name: Setup Node - uses: actions/setup-node@v3 - with: - version: '16.x' - - run: yarn - working-directory: . - - name: Bundle install - run: | - gem install bundler - bundle config path vendor/bundle - bundle install --jobs 4 --retry 3 - - name: Run ruby tests - run: bundle exec rake test + - uses: actions/checkout@v3 + - name: Set up Ruby ${{ matrix.ruby-version }} + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby-version }} + bundler-cache: true + + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: '16.x' + cache: 'yarn' + + - name: Yarn install + run: yarn install --frozen-lockfile + + - name: Run ruby tests + run: bundle exec rake test diff --git a/.gitignore b/.gitignore index cbaebc3d..3d63ae9d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,15 +1,17 @@ +*.gem +*.key +.containers.yml /.bundle/ /doc/ /log/*.log +/node_modules/ /pkg/ -/tmp/ /test/dummy/db/*.sqlite3 /test/dummy/db/*.sqlite3-* /test/dummy/log/*.log +/test/dummy/public/assets/ /test/dummy/storage/ /test/dummy/tmp/ -/test/dummy/public/assets/ -/node_modules +/tmp/ Gemfile.lock -*.key -*~ +test/dummy/app/javascript/@turbo-boost diff --git a/.yarnclean b/.yarnclean new file mode 100644 index 00000000..b591611e --- /dev/null +++ b/.yarnclean @@ -0,0 +1,45 @@ +# test directories +__tests__ +test +tests +powered-test + +# asset directories +docs +doc +website +images +assets + +# examples +example +examples + +# code coverage directories +coverage +.nyc_output + +# build scripts +Makefile +Gulpfile.js +Gruntfile.js + +# configs +appveyor.yml +circle.yml +codeship-services.yml +codeship-steps.yml +wercker.yml +.tern-project +.gitattributes +.editorconfig +.*ignore +.eslintrc +.jshintrc +.flowconfig +.documentup.json +.yarn-metadata.json +.travis.yml + +# misc +*.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 4eb6401a..8ba5ce6b 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -17,23 +17,23 @@ diverse, inclusive, and healthy community. Examples of behavior that contributes to a positive environment for our community include: -* Demonstrating empathy and kindness toward other people -* Being respectful of differing opinions, viewpoints, and experiences -* Giving and gracefully accepting constructive feedback -* Accepting responsibility and apologizing to those affected by our mistakes, +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience -* Focusing on what is best not just for us as individuals, but for the +- Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior include: -* The use of sexualized language or imagery, and sexual attention or +- The use of sexualized language or imagery, and sexual attention or advances of any kind -* Trolling, insulting or derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or email +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email address, without their explicit permission -* Other conduct which could reasonably be considered inappropriate in a +- Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement Responsibilities @@ -106,7 +106,7 @@ Violating these terms may lead to a permanent ban. ### 4. Permanent Ban **Community Impact**: Demonstrating a pattern of violation of community -standards, including sustained inappropriate behavior, harassment of an +standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. **Consequence**: A permanent ban from any sort of public interaction within diff --git a/Dockerfile b/Dockerfile index fecf9372..9ab5f541 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,51 +1,23 @@ -FROM ruby:3.1.2 - -ENV GEM_HOME=/opt/bundle -RUN mkdir -p /opt/bundle /opt/node_modules -RUN curl -fsSL https://deb.nodesource.com/setup_16.x | bash - +FROM ruby:3.2.2-slim-bullseye RUN apt-get -y update && \ -apt-get -y upgrade && \ -apt-get -y --allow-downgrades --allow-remove-essential --allow-change-held-packages install \ +apt-get -y --no-install-recommends install \ build-essential \ -git \ -nodejs \ +curl \ +libjemalloc2 \ sqlite3 \ -tzdata && \ -apt-get clean - -# setup ruby gems -RUN gem update --system && \ -gem install bundler +tzdata -# setup yarn -RUN npm install -g yarn - -# get application code -RUN rm -rf /opt/turbo_boost-commands -RUN git clone --origin github --branch main --depth 1 https://github.com/hopsoft/turbo_boost-commands.git /opt/turbo_boost-commands - -# install application dependencies 1st time -WORKDIR /opt/turbo_boost-commands -RUN ln -s /opt/node_modules /opt/turbo_boost-commands/node_modules -RUN yarn install --ignore-engines -RUN bundle +RUN curl -fsSL https://deb.nodesource.com/setup_16.x | bash - +RUN apt-get -y --no-install-recommends install nodejs && \ +npm install -g npm@latest yarn -# cleanup -RUN rm -rf /usr/local/share/.cache/* /usr/local/bundle/cache/* /opt/bundle/cache/* /root/.bundle/cache/* /root/.cache/* +RUN apt-get clean +RUN gem update --system +RUN bundle config set --local clean 'true' -# prepare the environment -ENV RAILS_ENV=production RAILS_LOG_TO_STDOUT=true RAILS_SERVE_STATIC_FILES=true -WORKDIR / +RUN mkdir -p /mnt/external/node_modules /mnt/external/yarn/.cache /mnt/external/gems /mnt/external/database -# prepare and run the application -CMD rm -rf /opt/turbo_boost-commands && \ -git clone --origin github --branch main --depth 1 https://github.com/hopsoft/turbo_boost-commands.git /opt/turbo_boost-commands && \ -cd /opt/turbo_boost-commands/test/dummy && \ -ln -s /opt/node_modules /opt/turbo_boost-commands/node_modules && \ -yarn install --ignore-engines && \ -bundle && \ -rm -rf tmp/pids/server.pid /usr/local/share/.cache/* /usr/local/bundle/cache/* /opt/bundle/cache/* /root/.bundle/cache/* /root/.cache/* && \ -bin/rails db:create db:migrate && \ -bin/rails assets:precompile && \ -bin/rails s --binding=0.0.0.0 --port=3000 +COPY . /app +WORKDIR /app +CMD bin/docker/run/remote diff --git a/Gemfile b/Gemfile index 72edf1b7..5ff335e4 100644 --- a/Gemfile +++ b/Gemfile @@ -5,3 +5,5 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" } # Specify your gem's dependencies in turbo_boost-commands.gemspec. gemspec + +gem "dockerfile-rails", ">= 1.3", group: :development diff --git a/README.md b/README.md index d0f88b5f..afa6fd0c 100644 --- a/README.md +++ b/README.md @@ -59,29 +59,29 @@ ## Table of Contents - - [Why TurboBoost Commands?](#why-turboboost-commands) - - [Sponsors](#sponsors) - - [Dependencies](#dependencies) - - [Setup](#setup) - - [Usage](#usage) - - [Event Delegates](#event-delegates) - - [Lifecycle Events](#lifecycle-events) - - [Targeting Frames](#targeting-frames) - - [Working with Forms](#working-with-forms) - - [Server Side Commands](#server-side-commands) - - [Appending Turbo Streams](#appending-turbo-streams) - - [Setting Instance Variables](#setting-instance-variables) - - [Prevent Controller Action](#prevent-controller-action) - - [Broadcasting Turbo Streams](#broadcasting-turbo-streams) - - [Putting it All Together](#putting-it-all-together) - - [Running Locally](#running-locally) - - [Running in Docker](#running-in-docker) - - [Community](#community) - - [Discussions](#discussions) - - [Twitter](#twitter) - - [Releasing](#releasing) - - [About TurboBoost](#about-turboboost) - - [License](#license) +- [Why TurboBoost Commands?](#why-turboboost-commands) +- [Sponsors](#sponsors) +- [Dependencies](#dependencies) +- [Setup](#setup) +- [Usage](#usage) + - [Event Delegates](#event-delegates) + - [Lifecycle Events](#lifecycle-events) + - [Targeting Frames](#targeting-frames) + - [Working with Forms](#working-with-forms) + - [Server Side Commands](#server-side-commands) + - [Appending Turbo Streams](#appending-turbo-streams) + - [Setting Instance Variables](#setting-instance-variables) + - [Prevent Controller Action](#prevent-controller-action) + - [Broadcasting Turbo Streams](#broadcasting-turbo-streams) +- [Community](#community) +- [Developing](#developing) + - [Notable Files](#notable-files) +- [Deploying](#deploying) + - [Notable Files](#notable-files-1) + - [How to Deploy](#how-to-deploy) +- [Releasing](#releasing) +- [About TurboBoost](#about-turboboost) +- [License](#license) @@ -91,11 +91,11 @@ Commands help you build robust reactive applications with Rails & Hotwire. They allow you to declaratively specify server methods that will execute whenever client side events are triggered by users. TurboBoost Commands work with Hotwire's Turbo Frames. -__They also work independent of frames.__ +**They also work independent of frames.** -Commands let you *sprinkle* ⨠in reactive functionality and skip the ceremony of the typical +Commands let you _sprinkle_ ⨠in reactive functionality and skip the ceremony of the typical [REST semantics](https://en.wikipedia.org/wiki/Representational_state_transfer) -imposed by Rails conventions and Turbo Frames i.e. boilerplate *(routes, controllers, actions, etc...)*. +imposed by Rails conventions and Turbo Frames i.e. boilerplate _(routes, controllers, actions, etc...)_. Commands are great for features adjacent to traditional RESTful resources. Things like making selections, toggling switches, adding filters, etc... @@ -108,9 +108,9 @@ Namely, 1. **Trigger an event** 2. **Change state** 3. **(Re)render to reflect the new state** -4. *repeat...* +4. _repeat..._ -*The primary distinction being that __state is wholly managed by the server__.* +_The primary distinction being that **state is wholly managed by the server**._ Commands are executed via a Rails `before_action` which means that reactivity runs over HTTP. _**Web sockets are NOT used for the reactive critical path!** đ_ @@ -138,97 +138,108 @@ Commands can be tested in isolation as well as with standard Rails controller, i ## Setup +Complete the steps below, or use [this RailsByte](https://railsbytes.com/templates/xkjsbB): + +```sh +rails app:template LOCATION='https://railsbytes.com/script/xkjsbB' +``` + 1. Add TurboBoost Commands dependencies - ```diff - # Gemfile - gem "turbo-rails", ">= 1.1", "< 2" - +gem "turbo_boost-commands", "~> VERSION" - ``` + ```diff + # Gemfile + gem "turbo-rails", ">= 1.1", "< 2" + +gem "turbo_boost-commands", "~> VERSION" + ``` - ```diff - # package.json - "dependencies": { - "@hotwired/turbo-rails": ">=7.2", - + "@turbo-boost/commands": "^VERSION" - ``` + ```diff + # package.json + "dependencies": { + "@hotwired/turbo-rails": ">=7.2", + + "@turbo-boost/commands": "^VERSION" + ``` - *Be sure to install the __same version__ of the Ruby and JavaScript libraries.* + _Be sure to install the **same version** of the Ruby and JavaScript libraries._ 2. Import TurboBoost Commands in your JavaScript app - ```diff - # app/javascript/application.js - import '@hotwired/turbo-rails' - +import '@turbo-boost/commands' - ``` - -2. Add TurboBoost to your Rails app - - ```diff - # app/views/layouts/application.html.erb - -
- + <%= turbo_boost.meta_tag %> - - - - - ``` + ```diff + # app/javascript/application.js + import '@hotwired/turbo-rails' + +import '@turbo-boost/commands' + ``` + +3. Add TurboBoost to your Rails app + + ```diff + # app/views/layouts/application.html.erb + + + + <%= turbo_boost.meta_tag %> + + + + + ``` ## Usage This example illustrates how to use TurboBoost Commands to manage upvotes on a Post. -1. **Trigger an event** - *register an element to listen for client side events that trigger server side commands* +1. **Trigger an event** - _register an element to listen for client side events that trigger server side commands_ - ```erb - - <%= turbo_frame_tag dom_id(@post) do %> - Upvote - Upvote Count: <%= @post.votes %> - <% end %> - ``` + ```erb + + <%= turbo_frame_tag dom_id(@post) do %> + Upvote + Upvote Count: <%= @post.votes %> + <% end %> + ``` -2. **Change state** - *create a server side command that modifies state* +2. **Change state** - _create a server side command that modifies state_ - ```ruby - # app/commands/post_command.rb - class PostCommand < TurboBoost::Commands::Command - def upvote - Post.find(controller.params[:id]).increment! :votes - end - end - ``` + ```ruby + # app/commands/post_command.rb + class PostCommand < TurboBoost::Commands::Command + def upvote + Post.find(controller.params[:id]).increment! :votes + end + end + ``` -3. **(Re)render to reflect the new state** - *normal Rails / Turbo Frame behavior runs and (re)renders the frame* +3. **(Re)render to reflect the new state** - _normal Rails / Turbo Frame behavior runs and (re)renders the frame_ ### Event Delegates TurboBoost Commands use [event delegation](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#event_delegation) to capture client side events that invoke server side commands. -Here is the list of default **event delegates** *(DOM event name + CSS selectors)* that TurboBoost Commands monitors. +Here is the list of default **event delegates** _(DOM event name + CSS selectors)_ that TurboBoost Commands monitors. - **`change`** - `input[data-turbo-command],select[data-turbo-command],textarea[data-turbo-command]` - **`submit`** - `form[data-turbo-command]` - **`click`** - `[data-turbo-command]` Note that the list of event delegates is ordinal. -Matches are identified by scanning the list of delegates top to bottom *(first match wins)*. +Matches are identified by scanning the list of delegates top to bottom _(first match wins)_. It's possible to override the default event delegates. Just note that registered events are required to [bubble up through the DOM tree](https://developer.mozilla.org/en-US/docs/Web/API/Event/bubbles). -**IMPORTANT:** *New entries and overrides are prepended to the list of delegates and will match before defaults.* +**IMPORTANT:** _New entries and overrides are prepended to the list of delegates and will match before defaults._ ```js // restrict `click` monitoring to and