diff --git a/.docker/.entrypoints/docker-rails.sh b/.docker/.entrypoints/docker-rails.sh new file mode 100755 index 000000000..3a0544358 --- /dev/null +++ b/.docker/.entrypoints/docker-rails.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +set -e + +if [ -f /rails/tmp/pids/server.pid ]; then + rm /rails/tmp/pids/server.pid +fi + +/rails/bin/rails db:migrate +/rails/bin/dev diff --git a/.docker/db/init-postgres.sql b/.docker/db/init-postgres.sql new file mode 100644 index 000000000..1c637c547 --- /dev/null +++ b/.docker/db/init-postgres.sql @@ -0,0 +1 @@ +CREATE DATABASE "app_rails"; \ No newline at end of file diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..4d64059f6 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +/node_modules + diff --git a/.github/actions/cleanup-gemfile/action.yml b/.github/actions/cleanup-gemfile/action.yml new file mode 100644 index 000000000..d81f0b9e9 --- /dev/null +++ b/.github/actions/cleanup-gemfile/action.yml @@ -0,0 +1,12 @@ +# action.yml file for a custom composite action +name: 'Remove Debug Gems' +description: 'Removes debug-related gems from the Gemfile' +runs: + using: 'composite' + steps: + - name: Remove Debug Gems + shell: bash + run: | + sed -i '/debase-ruby_core_source/d' ./Gemfile + sed -i '/debase/d' ./Gemfile + sed -i '/ruby-debug-ide/d' ./Gemfile diff --git a/.github/actions/setup-languages/action.yml b/.github/actions/setup-languages/action.yml index 13ca4f77a..596352d7e 100644 --- a/.github/actions/setup-languages/action.yml +++ b/.github/actions/setup-languages/action.yml @@ -3,12 +3,15 @@ description: Set up ruby, javascript, and dependencies runs: using: composite steps: + - name: Cleanup gemfile + uses: ./.github/actions/cleanup-gemfile + - name: Set up Ruby uses: ruby/setup-ruby@v1 - with: - # bundler-cache automatically installs gems - bundler-cache: true - cache-version: 1 + + - name: Install Dependencies + shell: bash + run: bundle install - name: Set up node uses: actions/setup-node@v4 diff --git a/.github/workflows/rspec.yml b/.github/workflows/rspec.yml index 24b856ac0..8f16dd4c8 100644 --- a/.github/workflows/rspec.yml +++ b/.github/workflows/rspec.yml @@ -22,6 +22,7 @@ jobs: steps: - uses: actions/checkout@v4 + - uses: ./.github/actions/cleanup-gemfile - id: setup uses: ./.github/actions/setup-project diff --git a/.gitignore b/.gitignore index be20ac613..e0692e79f 100644 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,9 @@ spec/examples.txt secrets.auto.tfvars terraform.tfstate terraform.tfstate.backup + +#IDE Specific (RubyMine) +.idea + +#IDE Specific (VS Code) +.vscode \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..b1fb24805 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,138 @@ +# syntax = docker/dockerfile:1 + +# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile +ARG RUBY_VERSION=3.1.0 + +FROM node:20.12.0-bullseye-slim AS node-stage +WORKDIR /rails +ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true + +RUN apt-get update -qq && \ + apt-get install --no-install-recommends -y build-essential git + +RUN apt-get install --reinstall ca-certificates -y && \ + update-ca-certificates + +# print the node version +RUN node --version +COPY package.json ./ +RUN yarn install + +########################################################################################## +# BASE: Shared base docker image +########################################################################################## +FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim as base + +# Set production environment +ENV RAILS_ENV="production" \ + BUNDLE_DEPLOYMENT="1" \ + BUNDLE_PATH="/usr/local/bundle" + +# Start the server by default, this can be overwritten at runtime +EXPOSE 3000 + +########################################################################################## +# BUILD: Throw-away build stage +########################################################################################## +FROM base as build +ARG DOCKERIZE_VERSION=v0.7.0 +#copy the node binary from the node-stage to the base image +COPY --from=node-stage /usr/local/bin/node /usr/local/bin/node + +# Install dockerize +RUN apt-get update \ + && apt-get install -y wget \ + && wget -O - https://github.com/jwilder/dockerize/releases/download/${DOCKERIZE_VERSION}/dockerize-linux-amd64-${DOCKERIZE_VERSION}.tar.gz | tar xzf - -C /usr/local/bin \ + && apt-get autoremove -yqq --purge wget && rm -rf /var/lib/apt/lists/* + +# Install packages needed to build gems +RUN apt-get update -qq && \ + apt-get install --no-install-recommends -y build-essential git libpq-dev libvips pkg-config redis jq rbenv cu npm + + +# Clean up +RUN apt-get clean && rm -rf /var/lib/apt/lists/* + +########################################################################################## +# DEV: Used for development and test +########################################################################################## +FROM build as dev + +WORKDIR /rails + +ENV RAILS_ENV="development" + +# Install packages needed for development +RUN apt-get update -qq && \ + apt-get install --no-install-recommends -y postgresql-client graphviz && \ + rm -rf /var/lib/apt/lists /var/cache/apt/archives + +RUN gem install bundler + +# Install application gems for development +COPY Gemfile Gemfile.lock ./ + +RUN gem update --system +RUN bundle lock --add-platform ruby && \ + bundle lock --add-platform x86_64-linux + +RUN bundle config set --local without production && \ + bundle install && \ + rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git + +# copy node from node-stage to dev +COPY --from=node-stage /usr/local/bin/node /usr/local/bin/node +# Copy application code +COPY . . +# Copy node_modules from node-stage +COPY --from=node-stage /rails/node_modules ./ +ENTRYPOINT [".docker/.entrypoints/docker-rails.sh"] + +########################################################################################## +# RELEASE-BUILD: Throw-away build stage for RELEASE +########################################################################################## +FROM build as release-build + +# Install application gems for production +COPY Gemfile Gemfile.lock ./ + +RUN bundle config set --local without development test && \ + bundle install && \ + rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git + +# Precompile bootsnap code for faster boot times +RUN bundle exec bootsnap precompile --gemfile app/ lib/ + +# Precompiling assets for production without requiring secret RAILS_MASTER_KEY +RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile + + +########################################################################################## +# RELEASE: Used for production +########################################################################################## +FROM base as release + +# Install packages needed for deployment +RUN apt-get update -qq && \ + apt-get install -y --no-install-recommends unzip python3-venv python-is-python3 curl libvips postgresql-client && \ + rm -rf /var/lib/apt/lists /var/cache/apt/archives && \ + curl "https://s3.amazonaws.com/aws-cli/awscli-bundle.zip" -o "awscli-bundle.zip" && \ + unzip awscli-bundle.zip && \ + ./awscli-bundle/install -i /usr/local/aws -b /usr/local/bin/aws && \ + rm -rf ./awscli-bundle awscli-bundle.zip + +# Install custom db migrate script +COPY bin/db-migrate /usr/bin/ + +# Copy built artifacts: gems, application +COPY --from=release-build /usr/local/bundle /usr/local/bundle +COPY --from=release-build /rails /rails + +RUN rm /rails/tmp/pids/server.pid + +# Run and own only the runtime files as a non-root user for security +RUN useradd rails --create-home --shell /bin/bash && \ + chown -R rails:rails db log storage tmp +USER rails:rails + +ENTRYPOINT [".docker/.entrypoints/docker-rails.sh"] \ No newline at end of file diff --git a/Gemfile b/Gemfile index cc59cdbfe..eef4f86dd 100644 --- a/Gemfile +++ b/Gemfile @@ -68,6 +68,9 @@ group :development, :test do end group :development do + gem "debase-ruby_core_source" + gem "debase", "~> 0.2.5.beta2", require: false + gem "ruby-debug-ide" # Use console on exceptions pages [https://github.com/rails/web-console] gem "web-console" diff --git a/Gemfile.lock b/Gemfile.lock index 3a34d13bb..4572ae59a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -90,6 +90,9 @@ GEM cssbundling-rails (1.4.0) railties (>= 6.0.0) date (3.3.4) + debase (0.2.5.beta2) + debase-ruby_core_source (>= 0.10.12) + debase-ruby_core_source (3.3.1) debug (1.9.2) irb (~> 1.10) reline (>= 0.3.8) @@ -119,7 +122,7 @@ GEM irb (1.12.0) rdoc reline (>= 0.4.2) - jbuilder (2.11.5) + jbuilder (2.12.0) actionview (>= 5.0.0) activesupport (>= 5.0.0) jsbundling-rails (1.3.0) @@ -153,12 +156,10 @@ GEM nio4r (2.7.1) nokogiri (1.16.4-arm64-darwin) racc (~> 1.4) - nokogiri (1.16.4-x86_64-darwin) - racc (~> 1.4) nokogiri (1.16.4-x86_64-linux) racc (~> 1.4) parallel (1.24.0) - parser (3.3.0.5) + parser (3.3.1.0) ast (~> 2.4.1) racc pg (1.5.6) @@ -212,7 +213,7 @@ GEM psych (>= 4.0.0) redis (4.8.1) regexp_parser (2.9.0) - reline (0.5.2) + reline (0.5.4) io-console (~> 0.5) rexml (3.2.6) rspec-core (3.13.0) @@ -243,8 +244,8 @@ GEM rubocop-ast (>= 1.31.1, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.31.2) - parser (>= 3.3.0.4) + rubocop-ast (1.31.3) + parser (>= 3.3.1.0) rubocop-capybara (2.20.0) rubocop (~> 1.41) rubocop-factory_bot (2.25.1) @@ -272,6 +273,8 @@ GEM rubocop-rspec_rails (~> 2.28) rubocop-rspec_rails (2.28.3) rubocop (~> 1.40) + ruby-debug-ide (0.7.3) + rake (>= 0.8.1) ruby-graphviz (1.2.5) rexml ruby-progressbar (1.13.0) @@ -326,7 +329,6 @@ GEM PLATFORMS arm64-darwin-23 - x86_64-darwin-20 x86_64-linux DEPENDENCIES @@ -335,6 +337,8 @@ DEPENDENCIES bundler-audit (~> 0.9) climate_control (~> 1.0) cssbundling-rails + debase (~> 0.2.5.beta2) + debase-ruby_core_source debug dotenv-rails (~> 2.7) i18n-tasks (~> 1.0) @@ -350,6 +354,7 @@ DEPENDENCIES rubocop rubocop-rails-omakase rubocop-rspec + ruby-debug-ide secure_headers (~> 6.3) sidekiq (~> 6.4) sprockets-rails @@ -363,4 +368,4 @@ RUBY VERSION ruby 3.1.0p0 BUNDLED WITH - 2.3.6 + 2.3.26 diff --git a/Procfile.dev b/Procfile.dev index 62910424d..09c9c5a36 100644 --- a/Procfile.dev +++ b/Procfile.dev @@ -1,4 +1,4 @@ -web: env RUBY_DEBUG_OPEN=true bin/rails server +web: env RUBY_DEBUG_PORT=1234 RUBY_DEBUG_STOP_AT_LOAD=true RUBY_DEBUG_OPEN=true RUBY_DEBUG_HOST=0.0.0.0 bin/rails server -p 3000 -b 0.0.0.0 js: yarn build --watch -css: yarn build:css --verbose --watch -worker: bundle exec sidekiq +css: yarn build:css --watch +worker: RUBY_DEBUG_OPEN=true bundle exec sidekiq diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js index 9a99757a4..130001fbe 100644 --- a/app/assets/config/manifest.js +++ b/app/assets/config/manifest.js @@ -1,2 +1,3 @@ //= link_tree ../images //= link_tree ../builds +//= link application.postcss.css diff --git a/config/cable.yml b/config/cable.yml index 49110f2e4..d5cbbe5ac 100644 --- a/config/cable.yml +++ b/config/cable.yml @@ -1,6 +1,6 @@ development: adapter: redis - url: redis://localhost:6379/1 + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> test: adapter: test diff --git a/config/credentials/development.yml.enc b/config/credentials/development.yml.enc new file mode 100644 index 000000000..8e0c56934 --- /dev/null +++ b/config/credentials/development.yml.enc @@ -0,0 +1 @@ +Btn0OVg1L730VpNEbQ+H15cFKg1y3q/z6IwIaDc9c4iExboCtzTUsYU/NO4sXKVZ0m0ShItWOKR4IxwCqw7GrIRKckilMnNhJKKMZJ9clj6CieYC9efIb8WeUe3c11AA--KLu1KB+ynGorNBrB--+jEPdTuPzExEtrlSeJzR9g== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml index ed13b3876..1d103fa8c 100644 --- a/config/database.yml +++ b/config/database.yml @@ -23,21 +23,24 @@ default: &default development: <<: *default - database: iv_cbv_payroll_development + adapter: postgresql + encoding: unicode + database: <%= ENV.fetch("DB_NAME") { "iv_cbv_payroll_development" } %> + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> # The specified database role being used to connect to postgres. # To create additional roles in postgres see `$ createuser --help`. # When left blank, postgres will use the default role. This is # the same name as the operating system user running Rails. - #username: iv_cbv_payroll + username: <%= ENV.fetch("DB_USERNAME") { nil } %> # The password associated with the postgres role (username). - #password: + password: <%= ENV.fetch("DB_PASSWORD") { nil } %> # Connect on a TCP socket. Omitted by default since the client uses a # domain socket that doesn't need configuration. Windows does not have # domain sockets, so uncomment these lines. - #host: localhost + host: <%= ENV.fetch("DB_HOST") { "localhost" } %> # The TCP port the server listens on. Defaults to 5432. # If your server runs on a different port number, change accordingly. diff --git a/config/environments/development.rb b/config/environments/development.rb index 7287bef62..948ca5eb9 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -1,6 +1,10 @@ require "active_support/core_ext/integer/time" Rails.application.configure do + # Check if we use Docker to allow docker ip through web-console + + # if the env var DOCKERIZED is set to true then we allow the web console to be accessed from the docker network + config.web_console.allowed_ips = '192.168.65.1' if ENV["DOCKERIZED"] == "true" # Settings specified here will take precedence over those in config/application.rb. # In the development environment your application's code is reloaded any time diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..ef1539a6f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,67 @@ +services: + postgres: + image: postgres:14-alpine + command: postgres -c "log_lock_waits=on" -N 1000 -c "fsync=off" + environment: + POSTGRES_PASSWORD: secret123 + POSTGRES_USER: app_rails + healthcheck: + test: "pg_isready --username=app_rails" + timeout: 10s + retries: 20 + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + - .docker/db/init-postgres.sql:/docker-entrypoint-initdb.d/init-postgres.sql + + # Rails app + # Configured for "development" RAILS_ENV + app_rails: + tty: true + build: + context: . + target: dev + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + env_file: .env + environment: + - DOCKERIZED=true + - DB_HOST=postgres + - DB_NAME=app_rails + - REDIS_URL=redis://redis:6379/1 + - RAILS_BINDING=0.0.0.0 + - RAILS_ENV=development + ports: + - 3000:3000 + - 1234:1234 + volumes: + - ./:/rails + # Use named volumes for directories that the container should use the guest + # machine's dir instead of the host machine's dir, which may be divergent. + # This is especially true for any dependency or temp directories. + - app_rails_nodemodules:/rails/node_modules + - app_rails_tmp:/rails/tmp + - app_rails_storage:/rails/storage + + redis: + image: redis:alpine + ports: + - "6379:6379" + volumes: + - redis_data:/data + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 5s + retries: 5 + +volumes: + postgres_data: + app_rails_nodemodules: + app_rails_tmp: + app_rails_storage: + redis_data: \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index bcc68bdc6..d0b735861 100644 --- a/yarn.lock +++ b/yarn.lock @@ -808,9 +808,9 @@ domutils@^3.0.1: domhandler "^5.0.3" electron-to-chromium@^1.4.668: - version "1.4.746" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.746.tgz#787213e75f6c7bccb55dfe8b68170555c548d093" - integrity sha512-jeWaIta2rIG2FzHaYIhSuVWqC6KJYo7oSBX4Jv7g+aVujKztfvdpf+n6MGwZdC5hQXbax4nntykLH2juIQrfPg== + version "1.4.749" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.749.tgz#9869e2e258141da26a2272b58264584c3461279d" + integrity sha512-LRMMrM9ITOvue0PoBrvNIraVmuDbJV5QC9ierz/z5VilMdPOVMjOtpICNld3PuXuTZ3CHH/UPxX9gHhAPwi+0Q== element-closest@^2.0.1: version "2.0.2"