diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 8252e1e..0000000 Binary files a/.DS_Store and /dev/null differ diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..e029ed3 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,77 @@ +name: Ruby with PostgreSQL + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +permissions: + contents: read + +jobs: + test: + + runs-on: ubuntu-latest + strategy: + matrix: + ruby-version: ['3.3.0'] + + services: + db: + image: postgres:latest + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: test_db + ports: + - 5432:5432 + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + + steps: + - uses: actions/checkout@v4 + - name: Set up Ruby and PostgreSQL + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby-version }} + bundler-cache: true # runs 'bundle install' and caches installed gems automatically + mirror: 'bd' # Use the Brazilian mirror for faster downloads + + - name: Install PostgreSQL client + run: | + sudo apt-get install postgresql-client + + - name: Wait for PostgreSQL to be ready + run: | + until pg_isready -h localhost -p 5432 -U postgres; do + echo "Waiting for PostgreSQL to start..." + sleep 1 + done + - name: Generate creds file + run: | + EDITOR="mate --wait" ./bin/rails credentials:edit + + - name: Install Node.js and Yarn + run: | + curl -fsSL https://deb.nodesource.com/setup_current.x | sudo -E bash - + sudo apt-get install -y nodejs + npm install -g yarn + + - name: Yarn install + run: | + yarn install + + - name: Precompile assets + run: | + SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile + + - name: Setup database schema + run: | + # Replace with your database setup commands (e.g., migrations) + bundle exec rake db:create db:schema:load + + - name: Run tests + run: bundle exec rspec + + - name: Run rubocop + run: bundle exec rubocop -DES diff --git a/.gitignore b/.gitignore index f8579cd..6f8ffb9 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,4 @@ /app/assets/builds/* !/app/assets/builds/.keep +.DS_Store diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..5be63fc --- /dev/null +++ b/.rspec @@ -0,0 +1,2 @@ +--require spec_helper +--format documentation diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..2ed5182 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,59 @@ +# This configuration was generated by +# `rubocop --auto-gen-config` +# on 2024-07-15 13:37:11 UTC using RuboCop version 1.65.0. +# The point is for the user to remove these configuration records +# one by one as the offenses are removed from the code base. +# Note that changes in the inspected code, or installation of new +# versions of RuboCop, may require this file to be generated again. + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: TreatCommentsAsGroupSeparators, ConsiderPunctuation, Include. +# Include: **/*.gemfile, **/Gemfile, **/gems.rb +Bundler/OrderedGems: + Exclude: + - 'Gemfile' + +# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes. +Metrics/AbcSize: + Max: 66 + +# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. +# AllowedMethods: refine +Metrics/BlockLength: + Max: 155 + +# Configuration parameters: AllowedMethods, AllowedPatterns. +Metrics/CyclomaticComplexity: + Max: 9 + +# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. +Metrics/MethodLength: + Max: 74 + +# Configuration parameters: AllowedMethods, AllowedPatterns. +Metrics/PerceivedComplexity: + Max: 9 + +# Configuration parameters: EnforcedStyle, CheckMethodNames, CheckSymbols, AllowedIdentifiers, AllowedPatterns. +# SupportedStyles: snake_case, normalcase, non_integer +# AllowedIdentifiers: capture3, iso8601, rfc1123_date, rfc822, rfc2822, rfc3339, x86_64 +Naming/VariableNumber: + Exclude: + - 'spec/controllers/*' + - 'spec/controllers/*' + +# Configuration parameters: AllowedConstants. +Style/Documentation: + Enabled: false + +# This cop supports safe autocorrection (--autocorrect). +Style/IfUnlessModifier: + Exclude: + - 'bin/bundle' + +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns. +# URISchemes: http, https +Layout/LineLength: + Max: 198 diff --git a/Dockerfile b/Dockerfile index f287da1..6c191f2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,8 +11,7 @@ WORKDIR /rails ENV RAILS_ENV="production" \ BUNDLE_DEPLOYMENT="1" \ BUNDLE_PATH="/usr/local/bundle" \ - BUNDLE_WITHOUT="development" \ - SECRET_KEY_BASE="a20aff0f4264e4896b81c5377418b46f104fdb209ded3d58b521abf871853adcabd0d904c569def108a35345e29b5e1affad36cb6619f0b51738f7de5d59b528" + BUNDLE_WITHOUT="development" # Throw-away build stage to reduce size of final image FROM base as build @@ -38,6 +37,10 @@ COPY . . # Install JavaScript dependencies RUN yarn install +RUN gem install rails + +RUN gem install foreman + # Precompile bootsnap code for faster boot times RUN bundle exec bootsnap precompile app/ lib/ @@ -56,6 +59,8 @@ RUN apt-get update -qq && \ COPY --from=build /usr/local/bundle /usr/local/bundle COPY --from=build /rails /rails +# Generate Rails master key and encrypt database credentials + # 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 diff --git a/Gemfile b/Gemfile index c4a3f2a..4b9b2fa 100644 --- a/Gemfile +++ b/Gemfile @@ -1,30 +1,32 @@ -source "https://rubygems.org" +# frozen_string_literal: true -ruby "3.3.0" +source 'https://rubygems.org' + +ruby '3.3.0' # Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main" -gem "rails", "~> 7.1.3", ">= 7.1.3.4" +gem 'rails', '~> 7.1.3', '>= 7.1.3.4' # The original asset pipeline for Rails [https://github.com/rails/sprockets-rails] -gem "sprockets-rails" +gem 'sprockets-rails' # Use sqlite3 as the database for Active Record -gem "sqlite3", "~> 1.4" +gem 'sqlite3', '~> 1.4' # Use the Puma web server [https://github.com/puma/puma] -gem "puma", ">= 5.0" +gem 'puma', '>= 5.0' # Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails] -gem "importmap-rails" +gem 'importmap-rails' # Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev] -gem "turbo-rails" +gem 'turbo-rails' # Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev] -gem "stimulus-rails" +gem 'stimulus-rails' # Build JSON APIs with ease [https://github.com/rails/jbuilder] -gem "jbuilder" +gem 'jbuilder' # Use Redis adapter to run Action Cable in production # gem "redis", ">= 4.0.1" @@ -36,24 +38,31 @@ gem "jbuilder" # gem "bcrypt", "~> 3.1.7" # Windows does not include zoneinfo files, so bundle the tzinfo-data gem -gem "tzinfo-data", platforms: %i[ windows jruby ] +gem 'tzinfo-data', platforms: %i[windows jruby] # Reduces boot times through caching; required in config/boot.rb -gem "bootsnap", require: false +gem 'bootsnap', require: false # Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images] # gem "image_processing", "~> 1.2" group :development, :test do # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem + gem 'debug', platforms: %i[mri windows] + gem 'dotenv', '~> 3.1' + gem 'factory_bot_rails' gem 'pry' - gem "debug", platforms: %i[ mri windows ] - gem "dotenv", "~> 3.1" + gem 'rails-controller-testing' + gem 'rspec-rails', '~> 5.0.0' + gem 'rubocop', require: false + gem 'rubocop-rails', require: false + gem 'rubocop-performance', require: false + gem 'rubocop-rspec', require: false end group :development do # Use console on exceptions pages [https://github.com/rails/web-console] - gem "web-console" + gem 'web-console' # Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler] # gem "rack-mini-profiler" @@ -64,17 +73,19 @@ end group :test do # Use system testing [https://guides.rubyonrails.org/testing.html#system-testing] - gem "capybara" - gem "selenium-webdriver" + gem 'capybara' + gem 'database_cleaner' + gem 'selenium-webdriver' + gem 'webmock', '~> 3.14' end -gem "ruby-openai", "~> 7.0" +gem 'ruby-openai', '~> 7.0' -gem "devise", "~> 4.9" -gem "devise-jwt", "~> 0.12.0" +gem 'devise', '~> 4.9' +gem 'devise-jwt', '~> 0.12.0' -gem "solid_queue", "~> 0.3.3" +gem 'solid_queue', '~> 0.3.3' -gem "tailwindcss-rails", "~> 2.6" +gem 'tailwindcss-rails', '~> 2.6' -gem "pg", "~> 1.5" +gem 'pg', '~> 1.5' diff --git a/Gemfile.lock b/Gemfile.lock index 4d1342e..6ad16ff 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -77,6 +77,7 @@ GEM tzinfo (~> 2.0) addressable (2.8.6) public_suffix (>= 2.0.2, < 6.0) + ast (2.4.2) base64 (0.2.0) bcrypt (3.1.20) bigdecimal (3.1.8) @@ -96,7 +97,16 @@ GEM coderay (1.1.3) concurrent-ruby (1.3.1) connection_pool (2.4.1) + crack (1.0.0) + bigdecimal + rexml crass (1.0.6) + database_cleaner (2.0.2) + database_cleaner-active_record (>= 2, < 3) + database_cleaner-active_record (2.2.0) + activerecord (>= 5.a) + database_cleaner-core (~> 2.0.0) + database_cleaner-core (2.0.1) date (3.3.4) debug (1.9.2) irb (~> 1.10) @@ -110,6 +120,7 @@ GEM devise-jwt (0.12.1) devise (~> 4.0) warden-jwt_auth (~> 0.10) + diff-lcs (1.5.1) dotenv (3.1.2) drb (2.2.1) dry-auto_inject (1.0.1) @@ -125,6 +136,11 @@ GEM et-orbi (1.2.11) tzinfo event_stream_parser (1.0.0) + factory_bot (6.4.6) + activesupport (>= 5.0.0) + factory_bot_rails (6.4.3) + factory_bot (~> 6.4) + railties (>= 5.0.0) faraday (2.9.1) faraday-net_http (>= 2.0, < 3.2) faraday-multipart (1.0.4) @@ -136,6 +152,7 @@ GEM raabro (~> 1.4) globalid (1.2.1) activesupport (>= 6.1) + hashdiff (1.1.0) i18n (1.14.5) concurrent-ruby (~> 1.0) importmap-rails (2.0.1) @@ -149,8 +166,10 @@ GEM jbuilder (2.12.0) actionview (>= 5.0.0) activesupport (>= 5.0.0) + json (2.7.2) jwt (2.8.2) base64 + language_server-protocol (3.17.0.3) loofah (2.22.0) crass (~> 1.0.2) nokogiri (>= 1.12.0) @@ -192,6 +211,10 @@ GEM nokogiri (1.16.5-x86_64-linux) racc (~> 1.4) orm_adapter (0.5.0) + parallel (1.25.1) + parser (3.3.4.0) + ast (~> 2.4.1) + racc pg (1.5.6) pry (0.14.2) coderay (~> 1.1) @@ -225,6 +248,10 @@ GEM activesupport (= 7.1.3.4) bundler (>= 1.15.0) railties (= 7.1.3.4) + rails-controller-testing (1.0.5) + actionpack (>= 5.0.1.rc1) + actionview (>= 5.0.1.rc1) + activesupport (>= 5.0.1.rc1) rails-dom-testing (2.2.0) activesupport (>= 5.0.0) minitest @@ -240,6 +267,7 @@ GEM rake (>= 12.2) thor (~> 1.0, >= 1.2.2) zeitwerk (~> 2.6) + rainbow (3.1.1) rake (13.2.1) rdoc (6.7.0) psych (>= 4.0.0) @@ -251,10 +279,51 @@ GEM railties (>= 5.2) rexml (3.2.8) strscan (>= 3.0.9) + rspec-core (3.13.0) + rspec-support (~> 3.13.0) + rspec-expectations (3.13.1) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-mocks (3.13.1) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-rails (5.0.3) + actionpack (>= 5.2) + activesupport (>= 5.2) + railties (>= 5.2) + rspec-core (~> 3.10) + rspec-expectations (~> 3.10) + rspec-mocks (~> 3.10) + rspec-support (~> 3.10) + rspec-support (3.13.1) + rubocop (1.65.0) + json (~> 2.3) + language_server-protocol (>= 3.17.0) + parallel (~> 1.10) + parser (>= 3.3.0.2) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 2.4, < 3.0) + rexml (>= 3.2.5, < 4.0) + rubocop-ast (>= 1.31.1, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 2.4.0, < 3.0) + rubocop-ast (1.31.3) + parser (>= 3.3.1.0) + rubocop-performance (1.21.1) + rubocop (>= 1.48.1, < 2.0) + rubocop-ast (>= 1.31.1, < 2.0) + rubocop-rails (2.25.1) + activesupport (>= 4.2.0) + rack (>= 1.1) + rubocop (>= 1.33.0, < 2.0) + rubocop-ast (>= 1.31.1, < 2.0) + rubocop-rspec (3.0.3) + rubocop (~> 1.61) ruby-openai (7.0.1) event_stream_parser (>= 0.3.0, < 2.0.0) faraday (>= 1) faraday-multipart (>= 1) + ruby-progressbar (1.13.0) rubyzip (2.3.2) selenium-webdriver (4.21.1) base64 (~> 0.2) @@ -304,6 +373,7 @@ GEM railties (>= 6.0.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) + unicode-display_width (2.5.0) uri (0.13.0) warden (1.2.9) rack (>= 2.0.9) @@ -317,6 +387,10 @@ GEM activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) + webmock (3.23.1) + addressable (>= 2.8.0) + crack (>= 0.3.2) + hashdiff (>= 0.4.0, < 2.0.0) webrick (1.8.1) websocket (1.2.10) websocket-driver (0.7.6) @@ -338,16 +412,24 @@ PLATFORMS DEPENDENCIES bootsnap capybara + database_cleaner debug devise (~> 4.9) devise-jwt (~> 0.12.0) dotenv (~> 3.1) + factory_bot_rails importmap-rails jbuilder pg (~> 1.5) pry puma (>= 5.0) rails (~> 7.1.3, >= 7.1.3.4) + rails-controller-testing + rspec-rails (~> 5.0.0) + rubocop + rubocop-performance + rubocop-rails + rubocop-rspec ruby-openai (~> 7.0) selenium-webdriver solid_queue (~> 0.3.3) @@ -358,6 +440,7 @@ DEPENDENCIES turbo-rails tzinfo-data web-console + webmock (~> 3.14) RUBY VERSION ruby 3.3.0p0 diff --git a/Rakefile b/Rakefile index 9a5ea73..488c551 100644 --- a/Rakefile +++ b/Rakefile @@ -1,6 +1,8 @@ +# frozen_string_literal: true + # Add your own tasks in files placed in lib/tasks ending in .rake, # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. -require_relative "config/application" +require_relative 'config/application' Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb index d672697..9aec230 100644 --- a/app/channels/application_cable/channel.rb +++ b/app/channels/application_cable/channel.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ApplicationCable class Channel < ActionCable::Channel::Base end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb index 0ff5442..8d6c2a1 100644 --- a/app/channels/application_cable/connection.rb +++ b/app/channels/application_cable/connection.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ApplicationCable class Connection < ActionCable::Connection::Base end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index c5268d9..b8546f7 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + class ApplicationController < ActionController::Base - protect_from_forgery with: :exception, if: Proc.new { |c| c.request.format != 'application/json' } - protect_from_forgery with: :null_session, if: Proc.new { |c| c.request.format == 'application/json' } + protect_from_forgery with: :exception, if: proc { |c| c.request.format != 'application/json' } + protect_from_forgery with: :null_session, if: proc { |c| c.request.format == 'application/json' } before_action :authenticate_user! diff --git a/app/controllers/chats_controller.rb b/app/controllers/chats_controller.rb deleted file mode 100644 index 247ca77..0000000 --- a/app/controllers/chats_controller.rb +++ /dev/null @@ -1,70 +0,0 @@ -class ChatsController < ApplicationController - before_action :set_chat, only: %i[ show edit update destroy ] - - # GET /chats or /chats.json - def index - @chats = Chat.all - end - - # GET /chats/1 or /chats/1.json - def show - end - - # GET /chats/new - def new - @chat = Chat.new - end - - # GET /chats/1/edit - def edit - end - - # POST /chats or /chats.json - def create - @chat = Chat.new(chat_params) - - respond_to do |format| - if @chat.save - format.html { redirect_to chat_url(@chat), notice: "Chat was successfully created." } - format.json { render :show, status: :created, location: @chat } - else - format.html { render :new, status: :unprocessable_entity } - format.json { render json: @chat.errors, status: :unprocessable_entity } - end - end - end - - # PATCH/PUT /chats/1 or /chats/1.json - def update - respond_to do |format| - if @chat.update(chat_params) - format.html { redirect_to chat_url(@chat), notice: "Chat was successfully updated." } - format.json { render :show, status: :ok, location: @chat } - else - format.html { render :edit, status: :unprocessable_entity } - format.json { render json: @chat.errors, status: :unprocessable_entity } - end - end - end - - # DELETE /chats/1 or /chats/1.json - def destroy - @chat.destroy! - - respond_to do |format| - format.html { redirect_to chats_url, notice: "Chat was successfully destroyed." } - format.json { head :no_content } - end - end - - private - # Use callbacks to share common setup or constraints between actions. - def set_chat - @chat = Chat.find(params[:id]) - end - - # Only allow a list of trusted parameters through. - def chat_params - params.require(:chat).permit(:title) - end -end diff --git a/app/controllers/compare_controller.rb b/app/controllers/compare_controller.rb index bc42217..1e6d9b1 100644 --- a/app/controllers/compare_controller.rb +++ b/app/controllers/compare_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CompareController < ApplicationController def index @prompts = current_user.prompts diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index 2473590..6049155 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class DashboardController < ApplicationController def index; end end diff --git a/app/controllers/messages_controller.rb b/app/controllers/messages_controller.rb deleted file mode 100644 index a594dc0..0000000 --- a/app/controllers/messages_controller.rb +++ /dev/null @@ -1,79 +0,0 @@ -class MessagesController < ApplicationController - before_action :set_chat - before_action :set_message, only: %i[ show edit update destroy ] - - def index - @message = Message.new - @messages = Message.all - end - - def show - end - - def new - @message = Message.new - end - - def edit - end - - def create - @messages = Message.all - @message = @chat.messages.new(message_params) - - respond_to do |format| - if @message.save - # FIXME: this is a massive hack - # client = OpenAI::Client.new - # response = client.chat(parameters: { - # model: "gpt-3.5-turbo", - # messages: [{ role: "user", content: @message.body }], - # temperature: 0.5 - # }) - # Message.create body: "CHATGPT: " + response.dig("choices", 0, "message", "content") - # FIXME: the hack ends here - - format.html { redirect_to chat_message_url(@chat, @message), notice: "Message was successfully created." } - format.json { render :show, status: :created, location: @message } - format.turbo_stream - else - format.html { render :new, status: :unprocessable_entity } - format.json { render json: @message.errors, status: :unprocessable_entity } - end - end - end - - def update - respond_to do |format| - if @message.update(message_params) - format.html { redirect_to chat_message_url(@chat, @message), notice: "Message was successfully updated." } - format.json { render :show, status: :ok, location: @message } - else - format.html { render :edit, status: :unprocessable_entity } - format.json { render json: @message.errors, status: :unprocessable_entity } - end - end - end - - def destroy - @message.destroy! - - respond_to do |format| - format.html { redirect_to chat_messages_url(@chat), notice: "Message was successfully destroyed." } - format.json { head :no_content } - end - end - - private - def set_chat - @chat = Chat.find(params[:chat_id]) - end - - def set_message - @message = @chat.messages.find(params[:id]) - end - - def message_params - params.require(:message).permit(:body) - end -end diff --git a/app/controllers/model_versions_controller.rb b/app/controllers/model_versions_controller.rb index 680bd58..608acdd 100644 --- a/app/controllers/model_versions_controller.rb +++ b/app/controllers/model_versions_controller.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + class ModelVersionsController < ApplicationController before_action :set_model - before_action :set_model_version, only: %i[ show edit update destroy ] + before_action :set_model_version, only: %i[show edit update destroy] # GET /model_versions or /model_versions.json def index @@ -8,8 +10,7 @@ def index end # GET /model_versions/1 or /model_versions/1.json - def show - end + def show; end # GET /model_versions/new def new @@ -17,8 +18,7 @@ def new end # GET /model_versions/1/edit - def edit - end + def edit; end # POST /model_versions or /model_versions.json def create @@ -26,7 +26,9 @@ def create respond_to do |format| if @model_version.save - format.html { redirect_to model_model_version_url(@model, @model_version), notice: "Model version was successfully created." } + format.html do + redirect_to model_model_version_url(@model, @model_version), notice: 'Model version was successfully created.' + end format.json { render :show, status: :created, location: model_model_version_url(@model, @model_version) } else format.html { render :new, status: :unprocessable_entity } @@ -39,7 +41,9 @@ def create def update respond_to do |format| if @model_version.update(model_version_params) - format.html { redirect_to model_model_version_url(@model, @model_version), notice: "Model version was successfully updated." } + format.html do + redirect_to model_model_version_url(@model, @model_version), notice: 'Model version was successfully updated.' + end format.json { render :show, status: :ok, location: @model_version } else format.html { render :edit, status: :unprocessable_entity } @@ -53,12 +57,13 @@ def destroy @model_version.destroy! respond_to do |format| - format.html { redirect_to model_model_versions_url(@model), notice: "Model version was successfully destroyed." } + format.html { redirect_to model_model_versions_url(@model), notice: 'Model version was successfully destroyed.' } format.json { head :no_content } end end private + # Use callbacks to share common setup or constraints between actions. def set_model_version @model_version = @model.model_versions.find(params[:id]) diff --git a/app/controllers/models_controller.rb b/app/controllers/models_controller.rb index c0f48dc..d0bb4fe 100644 --- a/app/controllers/models_controller.rb +++ b/app/controllers/models_controller.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + class ModelsController < ApplicationController - before_action :set_model, only: %i[ show edit update destroy ] + before_action :set_model, only: %i[show edit update destroy] # GET /models or /models.json def index @@ -17,8 +19,7 @@ def new end # GET /models/1/edit - def edit - end + def edit; end # POST /models or /models.json def create @@ -26,7 +27,7 @@ def create respond_to do |format| if @model.save - format.html { redirect_to model_url(@model), notice: "Model successfully created." } + format.html { redirect_to model_url(@model), notice: 'Model successfully created.' } format.json { render :show, status: :created, location: @model } else format.html { render :new, status: :unprocessable_entity } @@ -39,7 +40,7 @@ def create def update respond_to do |format| if @model.update(model_params) - format.html { redirect_to model_url(@model), notice: "Model successfully updated." } + format.html { redirect_to model_url(@model), notice: 'Model successfully updated.' } format.json { render :show, status: :ok, location: @model } else format.html { render :edit, status: :unprocessable_entity } @@ -53,12 +54,13 @@ def destroy @model.destroy! respond_to do |format| - format.html { redirect_to models_url, notice: "Model successfully destroyed." } + format.html { redirect_to models_url, notice: 'Model successfully destroyed.' } format.json { head :no_content } end end private + # Use callbacks to share common setup or constraints between actions. def set_model @model = current_user.models.find(params[:id]) diff --git a/app/controllers/participants_controller.rb b/app/controllers/participants_controller.rb deleted file mode 100644 index c861fc5..0000000 --- a/app/controllers/participants_controller.rb +++ /dev/null @@ -1,70 +0,0 @@ -class ParticipantsController < ApplicationController - before_action :set_participant, only: %i[ show edit update destroy ] - - # GET /participants or /participants.json - def index - @participants = Participant.all - end - - # GET /participants/1 or /participants/1.json - def show - end - - # GET /participants/new - def new - @participant = Participant.new - end - - # GET /participants/1/edit - def edit - end - - # POST /participants or /participants.json - def create - @participant = Participant.new(participant_params) - - respond_to do |format| - if @participant.save - format.html { redirect_to participant_url(@participant), notice: "Participant was successfully created." } - format.json { render :show, status: :created, location: @participant } - else - format.html { render :new, status: :unprocessable_entity } - format.json { render json: @participant.errors, status: :unprocessable_entity } - end - end - end - - # PATCH/PUT /participants/1 or /participants/1.json - def update - respond_to do |format| - if @participant.update(participant_params) - format.html { redirect_to participant_url(@participant), notice: "Participant was successfully updated." } - format.json { render :show, status: :ok, location: @participant } - else - format.html { render :edit, status: :unprocessable_entity } - format.json { render json: @participant.errors, status: :unprocessable_entity } - end - end - end - - # DELETE /participants/1 or /participants/1.json - def destroy - @participant.destroy! - - respond_to do |format| - format.html { redirect_to participants_url, notice: "Participant was successfully destroyed." } - format.json { head :no_content } - end - end - - private - # Use callbacks to share common setup or constraints between actions. - def set_participant - @participant = Participant.find(params[:id]) - end - - # Only allow a list of trusted parameters through. - def participant_params - params.require(:participant).permit(:name, :configuration, :implementor) - end -end diff --git a/app/controllers/prompts_controller.rb b/app/controllers/prompts_controller.rb index bc84b09..3ba6072 100644 --- a/app/controllers/prompts_controller.rb +++ b/app/controllers/prompts_controller.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + class PromptsController < ApplicationController - before_action :set_prompt, only: %i[ show destroy ] + before_action :set_prompt, only: %i[show destroy] # GET /prompts or /prompts.json def index @@ -22,7 +24,7 @@ def create respond_to do |format| if @prompt.save - format.html { redirect_to prompt_url(@prompt), notice: "Prompt was successfully created." } + format.html { redirect_to prompt_url(@prompt), notice: 'Prompt was successfully created.' } format.json { render :show, status: :created, location: @prompt } else format.html { render :new, status: :unprocessable_entity } @@ -36,12 +38,13 @@ def destroy @prompt.destroy! respond_to do |format| - format.html { redirect_to prompts_url, notice: "Prompt was successfully destroyed." } + format.html { redirect_to prompts_url, notice: 'Prompt was successfully destroyed.' } format.json { head :no_content } end end private + # Use callbacks to share common setup or constraints between actions. def set_prompt @prompt = current_user.prompts.find(params[:id]) diff --git a/app/controllers/test_results_controller.rb b/app/controllers/test_results_controller.rb index 50cf885..0d3459e 100644 --- a/app/controllers/test_results_controller.rb +++ b/app/controllers/test_results_controller.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + class TestResultsController < ApplicationController - before_action :set_test_result, only: [:show, :update] + before_action :set_test_result, only: %i[show update] def update if @test_result.update(test_results_params) @@ -12,7 +14,10 @@ def update def index @test_results = current_user.test_results.includes(model_version: :model).order(created_at: :desc) - @test_results = @test_results.where(model_version_id: params[:model_version_id], prompt_id: params[:prompt_id]) if params[:model_version_id].present? && params[:prompt_id].present? + if params[:model_version_id].present? && params[:prompt_id].present? + @test_results = @test_results.where(model_version_id: params[:model_version_id], + prompt_id: params[:prompt_id]) + end respond_to do |format| format.html { render :index } diff --git a/app/controllers/test_runs_controller.rb b/app/controllers/test_runs_controller.rb index 824ada3..ad65610 100644 --- a/app/controllers/test_runs_controller.rb +++ b/app/controllers/test_runs_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class TestRunsController < ApplicationController before_action :set_prompt diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 886a869..51b2678 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ApplicationHelper def define_status_class(status) case status diff --git a/app/helpers/chats_helper.rb b/app/helpers/chats_helper.rb deleted file mode 100644 index cf92be3..0000000 --- a/app/helpers/chats_helper.rb +++ /dev/null @@ -1,2 +0,0 @@ -module ChatsHelper -end diff --git a/app/helpers/messages_helper.rb b/app/helpers/messages_helper.rb deleted file mode 100644 index f1bca9f..0000000 --- a/app/helpers/messages_helper.rb +++ /dev/null @@ -1,2 +0,0 @@ -module MessagesHelper -end diff --git a/app/helpers/model_versions_helper.rb b/app/helpers/model_versions_helper.rb index 4a3993d..eead013 100644 --- a/app/helpers/model_versions_helper.rb +++ b/app/helpers/model_versions_helper.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + module ModelVersionsHelper end diff --git a/app/helpers/models_helper.rb b/app/helpers/models_helper.rb index d90a580..0fddda5 100644 --- a/app/helpers/models_helper.rb +++ b/app/helpers/models_helper.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + module ModelsHelper end diff --git a/app/helpers/participants_helper.rb b/app/helpers/participants_helper.rb deleted file mode 100644 index 7059f83..0000000 --- a/app/helpers/participants_helper.rb +++ /dev/null @@ -1,2 +0,0 @@ -module ParticipantsHelper -end diff --git a/app/helpers/prompts_helper.rb b/app/helpers/prompts_helper.rb index 6ab8fce..76643bc 100644 --- a/app/helpers/prompts_helper.rb +++ b/app/helpers/prompts_helper.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + module PromptsHelper end diff --git a/app/helpers/test_runs_helper.rb b/app/helpers/test_runs_helper.rb index 72fc5ee..8959344 100644 --- a/app/helpers/test_runs_helper.rb +++ b/app/helpers/test_runs_helper.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + module TestRunsHelper end diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb index d394c3d..bef3959 100644 --- a/app/jobs/application_job.rb +++ b/app/jobs/application_job.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ApplicationJob < ActiveJob::Base # Automatically retry jobs that encountered a deadlock # retry_on ActiveRecord::Deadlocked diff --git a/app/jobs/test_run_job.rb b/app/jobs/test_run_job.rb index ca8e54a..5d1b7fb 100644 --- a/app/jobs/test_run_job.rb +++ b/app/jobs/test_run_job.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + class TestRunJob < ApplicationJob def perform(model_version_id, prompt_id) model_version = ModelVersion.find(model_version_id) prompt = Prompt.find(prompt_id) - test_result = TestResult.create(model_version: model_version, prompt: prompt) + test_result = TestResult.create(model_version:, prompt:) result = {} benchmark = Benchmark.measure do diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb index 3c34c81..d84cb6e 100644 --- a/app/mailers/application_mailer.rb +++ b/app/mailers/application_mailer.rb @@ -1,4 +1,6 @@ +# frozen_string_literal: true + class ApplicationMailer < ActionMailer::Base - default from: "from@example.com" - layout "mailer" + default from: 'from@example.com' + layout 'mailer' end diff --git a/app/models/application_record.rb b/app/models/application_record.rb index b63caeb..08dc537 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ApplicationRecord < ActiveRecord::Base primary_abstract_class end diff --git a/app/models/chat.rb b/app/models/chat.rb deleted file mode 100644 index 447f26b..0000000 --- a/app/models/chat.rb +++ /dev/null @@ -1,3 +0,0 @@ -class Chat < ApplicationRecord - has_many :messages, dependent: :destroy -end diff --git a/app/models/message.rb b/app/models/message.rb deleted file mode 100644 index 644a5cb..0000000 --- a/app/models/message.rb +++ /dev/null @@ -1,6 +0,0 @@ -class Message < ApplicationRecord - belongs_to :chat - - validates :body, presence: true - validates :from, presence: true -end diff --git a/app/models/model.rb b/app/models/model.rb index d3dae0e..d8bbebb 100644 --- a/app/models/model.rb +++ b/app/models/model.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + class Model < ApplicationRecord encrypts :api_key belongs_to :user has_many :model_versions, dependent: :destroy - enum :executor_type, [ :base, :openai ], scopes: false, default: :base + enum :executor_type, %i[base openai], scopes: false, default: :base end diff --git a/app/models/model_version.rb b/app/models/model_version.rb index 18affed..0ced5ad 100644 --- a/app/models/model_version.rb +++ b/app/models/model_version.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ModelVersion < ApplicationRecord belongs_to :model has_many :test_results, dependent: :destroy diff --git a/app/models/participant.rb b/app/models/participant.rb deleted file mode 100644 index 770dc2b..0000000 --- a/app/models/participant.rb +++ /dev/null @@ -1,3 +0,0 @@ -class Participant < ApplicationRecord - validates :name, presence: true -end diff --git a/app/models/prompt.rb b/app/models/prompt.rb index 6ef9d81..a6b1544 100644 --- a/app/models/prompt.rb +++ b/app/models/prompt.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Prompt < ApplicationRecord belongs_to :user has_many :test_results, dependent: :destroy diff --git a/app/models/test_result.rb b/app/models/test_result.rb index 8f38d3c..d312985 100644 --- a/app/models/test_result.rb +++ b/app/models/test_result.rb @@ -1,10 +1,12 @@ +# frozen_string_literal: true + class TestResult < ApplicationRecord belongs_to :model_version belongs_to :prompt - enum :status, [ :pending, :completed, :failed ], scopes: true, default: :pending + enum :status, %i[pending completed failed], scopes: true, default: :pending - def as_json(options={}) + def as_json(options = {}) options[:methods] ||= [:content] super end @@ -12,12 +14,12 @@ def as_json(options={}) def content return '' if pending? - return JSON.parse(result).dig("error", "message") if failed? + return JSON.parse(result).dig('error', 'message') if failed? - return JSON.parse(result).dig("choices", 0, "message", "content") if model_version.executor_type == 'openai' + return JSON.parse(result).dig('choices', 0, 'message', 'content') if model_version.executor_type == 'openai' - return JSON.parse(result)['content'] if completed? - rescue + JSON.parse(result)['content'] if completed? + rescue StandardError '' end end diff --git a/app/models/user.rb b/app/models/user.rb index 5974e9c..60a7402 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable diff --git a/app/services/executors/base.rb b/app/services/executors/base.rb index 088d336..c069a65 100644 --- a/app/services/executors/base.rb +++ b/app/services/executors/base.rb @@ -1,26 +1,30 @@ -class Executors::Base - attr_reader :model_version +# frozen_string_literal: true - def initialize(model_version) - @model_version = model_version - end +module Executors + class Base + attr_reader :model_version + + def initialize(model_version) + @model_version = model_version + end - def call(prompt) - model = model_version.model - uri = URI.parse(model.url) - header = {'Content-Type': 'application/json'} - data = model_version.configuration.merge(prompt: "This is a conversation between User and OLMo<|endoftext|>\n\nUser:\n#{prompt}\n OLMo: ") + def call(prompt) + model = model_version.model + uri = URI.parse(model.url) + header = { 'Content-Type': 'application/json' } + data = model_version.configuration.merge(prompt: "This is a conversation between User and OLMo<|endoftext|>\n\nUser:\n#{prompt}\n OLMo: ") - http = Net::HTTP.new(uri.host, uri.port) - request = Net::HTTP::Post.new(uri.request_uri, header) - request.body = data.to_json - http.read_timeout = 2000 - response = http.request(request) + http = Net::HTTP.new(uri.host, uri.port) + request = Net::HTTP::Post.new(uri.request_uri, header) + request.body = data.to_json + http.read_timeout = 2000 + response = http.request(request) - return { status: :completed, result: response.body } if response.code.to_i == 200 + return { status: :completed, result: response.body } if response.code.to_i == 200 - { status: :failed, result: response.body } - rescue - { status: :failed } + { status: :failed, result: response.body } + rescue StandardError + { status: :failed } + end end end diff --git a/app/services/executors/openai.rb b/app/services/executors/openai.rb index d9d408e..692fbc2 100644 --- a/app/services/executors/openai.rb +++ b/app/services/executors/openai.rb @@ -1,24 +1,28 @@ -class Executors::Openai < Executors::Base - def initialize(model_version) - @client = OpenAI::Client.new(access_token: model_version.api_key, log_errors: true ) - super(model_version) - end +# frozen_string_literal: true - def call(prompt) - model = model_version.model +module Executors + class Openai < Executors::Base + def initialize(model_version) + @client = OpenAI::Client.new(access_token: model_version.api_key, log_errors: true) + super(model_version) + end - parameters = model_version.configuration.merge(messages: [{ role: "user", content: prompt }]) + def call(prompt) + model_version.model - result = client.chat(parameters: parameters) + parameters = model_version.configuration.merge(messages: [{ role: 'user', content: prompt }]) - { status: :completed, result: result.to_json.to_s } - rescue => e - return { status: :failed, result: e.response[:body].to_json.to_s } if e.respond_to?(:response) + result = client.chat(parameters:) - { status: :failed } - end + { status: :completed, result: result.to_json.to_s } + rescue StandardError => e + return { status: :failed, result: e.response[:body].to_json.to_s } if e.respond_to?(:response) - private + { status: :failed } + end - attr_reader :client + private + + attr_reader :client + end end diff --git a/app/services/model_executor.rb b/app/services/model_executor.rb index 2dfc3fa..837175e 100644 --- a/app/services/model_executor.rb +++ b/app/services/model_executor.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ModelExecutor attr_reader :executor diff --git a/app/views/chats/_chat.html.erb b/app/views/chats/_chat.html.erb deleted file mode 100644 index 2a32089..0000000 --- a/app/views/chats/_chat.html.erb +++ /dev/null @@ -1,7 +0,0 @@ -
-

- Title: - <%= chat.title %> -

- -
diff --git a/app/views/chats/_chat.json.jbuilder b/app/views/chats/_chat.json.jbuilder deleted file mode 100644 index 74c3e76..0000000 --- a/app/views/chats/_chat.json.jbuilder +++ /dev/null @@ -1,2 +0,0 @@ -json.extract! chat, :id, :title, :created_at, :updated_at -json.url chat_url(chat, format: :json) diff --git a/app/views/chats/_form.html.erb b/app/views/chats/_form.html.erb deleted file mode 100644 index 559c519..0000000 --- a/app/views/chats/_form.html.erb +++ /dev/null @@ -1,22 +0,0 @@ -<%= form_with(model: chat) do |form| %> - <% if chat.errors.any? %> -
-

<%= pluralize(chat.errors.count, "error") %> prohibited this chat from being saved:

- - -
- <% end %> - -
- <%= form.label :title, style: "display: block" %> - <%= form.text_field :title %> -
- -
- <%= form.submit %> -
-<% end %> diff --git a/app/views/chats/edit.html.erb b/app/views/chats/edit.html.erb deleted file mode 100644 index 19417c3..0000000 --- a/app/views/chats/edit.html.erb +++ /dev/null @@ -1,10 +0,0 @@ -

Editing chat

- -<%= render "form", chat: @chat %> - -
- -
- <%= link_to "Show this chat", @chat %> | - <%= link_to "Back to chats", chats_path %> -
diff --git a/app/views/chats/index.html.erb b/app/views/chats/index.html.erb deleted file mode 100644 index f222c48..0000000 --- a/app/views/chats/index.html.erb +++ /dev/null @@ -1,14 +0,0 @@ -

<%= notice %>

- -

Chats

- -
- <% @chats.each do |chat| %> - <%= render chat %> -

- <%= link_to "Show this chat", chat %> -

- <% end %> -
- -<%= link_to "New chat", new_chat_path %> diff --git a/app/views/chats/index.json.jbuilder b/app/views/chats/index.json.jbuilder deleted file mode 100644 index d2e78c5..0000000 --- a/app/views/chats/index.json.jbuilder +++ /dev/null @@ -1 +0,0 @@ -json.array! @chats, partial: "chats/chat", as: :chat diff --git a/app/views/chats/new.html.erb b/app/views/chats/new.html.erb deleted file mode 100644 index 759d552..0000000 --- a/app/views/chats/new.html.erb +++ /dev/null @@ -1,9 +0,0 @@ -

New chat

- -<%= render "form", chat: @chat %> - -
- -
- <%= link_to "Back to chats", chats_path %> -
diff --git a/app/views/chats/show.html.erb b/app/views/chats/show.html.erb deleted file mode 100644 index 42cab1a..0000000 --- a/app/views/chats/show.html.erb +++ /dev/null @@ -1,10 +0,0 @@ -

<%= notice %>

- -<%= render @chat %> - -
- <%= link_to "Edit this chat", edit_chat_path(@chat) %> | - <%= link_to "Back to chats", chats_path %> - - <%= button_to "Destroy this chat", @chat, method: :delete %> -
diff --git a/app/views/chats/show.json.jbuilder b/app/views/chats/show.json.jbuilder deleted file mode 100644 index c480788..0000000 --- a/app/views/chats/show.json.jbuilder +++ /dev/null @@ -1 +0,0 @@ -json.partial! "chats/chat", chat: @chat diff --git a/app/views/compare/index.html.erb b/app/views/compare/index.html.erb index ca35701..6d03205 100644 --- a/app/views/compare/index.html.erb +++ b/app/views/compare/index.html.erb @@ -2,7 +2,7 @@
- <%= select_tag 'prompt-id-select', options_from_collection_for_select(@prompts, 'id', 'name', @prompts.first.id), + <%= select_tag 'prompt-id-select', options_from_collection_for_select(@prompts, 'id', 'name', @prompts.first&.id), class: 'form-control w-full px-3 py-2 border border-gray-300 rounded-md mb-4', id: 'prompt-id-select' %>
diff --git a/app/views/devise/registrations/new.html.erb b/app/views/devise/registrations/new.html.erb index 4eb0529..11e9ee3 100644 --- a/app/views/devise/registrations/new.html.erb +++ b/app/views/devise/registrations/new.html.erb @@ -8,35 +8,44 @@
-
-

Sign Up

-
- - +
+
+ Logo
-
- - -
-
- - -
- - + <%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { class: "w-full" }) do |form| %> + <%= form.hidden_field :role, value: "user" %> +

Sign Up

+ + <% if resource.errors.any? %> + + <% end %> + +
+ <%= form.label :email, class: "block text-gray-700 text-sm font-bold mb-2" %> + <%= form.email_field :email, class: "shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline", required: true %> +
+ +
+ <%= form.label :password, class: "block text-gray-700 text-sm font-bold mb-2" %> + <%= form.password_field :password, class: "shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 mb-3 leading-tight focus:outline-none focus:shadow-outline", required: true %> +
+ +
+ <%= form.label :password_confirmation, "Confirm Password", class: "block text-gray-700 text-sm font-bold mb-2" %> + <%= form.password_field :password_confirmation, class: "shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 mb-3 leading-tight focus:outline-none focus:shadow-outline", required: true %> +
+ +
+ <%= form.submit "Sign Up", class: "bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline" %> + <%= link_to "Sign In", new_session_path(resource_name), class: "inline-block align-baseline font-bold text-sm text-blue-500 hover:text-blue-800" %> +
+ <% end %> +
diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb index b0c93eb..564261b 100644 --- a/app/views/devise/sessions/new.html.erb +++ b/app/views/devise/sessions/new.html.erb @@ -8,39 +8,50 @@
-
-

Sign In

-
- - -
-
- - +
+
+
- <% if devise_mapping.rememberable? -%> +

Sign In

+ <% if flash[:alert] %> + + <% end %> + + <%= form_for(resource, as: resource_name, url: session_path(resource_name), html: { class: "w-full" }) do |form| %>
- + <%= form.label :email, class: "block text-gray-700 text-sm font-bold mb-2" %> + <%= form.email_field :email, class: "shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline", required: true, autofocus: true %>
- <% end -%> -
- - <% if devise_mapping.recoverable? && controller_name != 'sessions' %> - - Forgot Password? - + +
+ <%= form.label :password, class: "block text-gray-700 text-sm font-bold mb-2" %> + <%= form.password_field :password, class: "shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 mb-3 leading-tight focus:outline-none focus:shadow-outline", required: true %> +
+ + <% if devise_mapping.rememberable? %> +
+ +
<% end %> -
- + +
+ <%= form.submit "Sign In", class: "bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline" %> + <% if devise_mapping.recoverable? && controller_name != 'sessions' %> + <%= link_to "Forgot Password?", new_password_path(resource_name), class: "inline-block align-baseline font-bold text-sm text-blue-500 hover:text-blue-800" %> + <% end %> +
+ <% end %> + +

+ Don't have an account? <%= link_to "Sign Up", new_registration_path(resource_name), class: "font-bold text-sm text-blue-500 hover:text-blue-800" %> +

+
diff --git a/app/views/layouts/_signed_in_header.html.erb b/app/views/layouts/_signed_in_header.html.erb index b0328cb..8a5965a 100644 --- a/app/views/layouts/_signed_in_header.html.erb +++ b/app/views/layouts/_signed_in_header.html.erb @@ -8,9 +8,10 @@ >
+ Logo Llamagator
    diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index a87f18c..b54145e 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -4,6 +4,7 @@ Llamagator + <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag "tailwind", "inter-font", "data-turbo-track": "reload" %> @@ -12,6 +13,8 @@ <%= javascript_include_tag 'init-alpine' %> <%= javascript_include_tag 'compare' %> <%= javascript_include_tag 'focus-trap' %> + + <%= javascript_importmap_tags %> <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %> - <%= javascript_include_tag 'init-alpine' %> - <%= javascript_include_tag 'compare' %> - <%= javascript_include_tag 'focus-trap' %> <%= javascript_importmap_tags %> + + + <%= yield %> diff --git a/app/views/messages/_form.html.erb b/app/views/messages/_form.html.erb deleted file mode 100644 index 4581dd3..0000000 --- a/app/views/messages/_form.html.erb +++ /dev/null @@ -1,22 +0,0 @@ -<%= form_with(model: [@chat, message]) do |form| %> - <% if message.errors.any? %> -
    -

    <%= pluralize(message.errors.count, "error") %> prohibited this message from being saved:

    - -
      - <% message.errors.each do |error| %> -
    • <%= error.full_message %>
    • - <% end %> -
    -
    - <% end %> - -
    - <%= form.label :body, style: "display: block" %> - <%= form.text_area :body %> -
    - -
    - <%= form.submit %> -
    -<% end %> diff --git a/app/views/messages/_message.html.erb b/app/views/messages/_message.html.erb deleted file mode 100644 index 3d60ef9..0000000 --- a/app/views/messages/_message.html.erb +++ /dev/null @@ -1,7 +0,0 @@ -
    - <% if message.body.start_with? "CHATGPT: " %> - <%= message.body.gsub! /^CHATGPT: /, "" %> - <% else %> - <%= message.body %> - <% end %> -
    diff --git a/app/views/messages/_message.json.jbuilder b/app/views/messages/_message.json.jbuilder deleted file mode 100644 index 35267ca..0000000 --- a/app/views/messages/_message.json.jbuilder +++ /dev/null @@ -1,2 +0,0 @@ -json.extract! message, :id, :body, :created_at, :updated_at -json.url message_url(message, format: :json) diff --git a/app/views/messages/create.turbo_stream.erb b/app/views/messages/create.turbo_stream.erb deleted file mode 100644 index a23aead..0000000 --- a/app/views/messages/create.turbo_stream.erb +++ /dev/null @@ -1,5 +0,0 @@ -<%= turbo_stream.update('messages') do %> - <% @messages.each do |message| %> - <%= render message %> - <% end %> -<% end %> diff --git a/app/views/messages/edit.html.erb b/app/views/messages/edit.html.erb deleted file mode 100644 index 4759883..0000000 --- a/app/views/messages/edit.html.erb +++ /dev/null @@ -1,10 +0,0 @@ -

    Editing message

    - -<%= render "form", message: @message %> - -
    - -
    - <%= link_to "Show this message", [@chat, @message] %> | - <%= link_to "Back to messages", chat_messages_path(@chat) %> -
    diff --git a/app/views/messages/index.html.erb b/app/views/messages/index.html.erb deleted file mode 100644 index 11b7ec2..0000000 --- a/app/views/messages/index.html.erb +++ /dev/null @@ -1,16 +0,0 @@ -

    <%= notice %>

    - -

    Messages

    - -
    - <%= turbo_frame_tag "messages" %> - <% @messages.each do |message| %> - <%= render message %> - <% end %> -
    - -<%= turbo_frame_tag "new_message", target: "_top" do %> - <%= form_with model: [@chat, @message] do |f| %> - <%= f.text_field :body, placeholder: "Enter text ...", autofocus: true %> - <% end %> -<% end %> diff --git a/app/views/messages/index.json.jbuilder b/app/views/messages/index.json.jbuilder deleted file mode 100644 index 27db314..0000000 --- a/app/views/messages/index.json.jbuilder +++ /dev/null @@ -1 +0,0 @@ -json.array! @messages, partial: "messages/message", as: :message diff --git a/app/views/messages/new.html.erb b/app/views/messages/new.html.erb deleted file mode 100644 index 6362970..0000000 --- a/app/views/messages/new.html.erb +++ /dev/null @@ -1,9 +0,0 @@ -

    New message

    - -<%= render "form", message: @message %> - -
    - -
    - <%= link_to "Back to messages", chat_messages_path(@chat) %> -
    diff --git a/app/views/messages/show.html.erb b/app/views/messages/show.html.erb deleted file mode 100644 index 6c404fb..0000000 --- a/app/views/messages/show.html.erb +++ /dev/null @@ -1,10 +0,0 @@ -

    <%= notice %>

    - -<%= render @message %> - -
    - <%= link_to "Edit this message", edit_chat_message_path(@chat, @message) %> | - <%= link_to "Back to messages", chat_messages_path(@chat) %> - - <%= button_to "Destroy this message", [@chat, @message], method: :delete %> -
    diff --git a/app/views/messages/show.json.jbuilder b/app/views/messages/show.json.jbuilder deleted file mode 100644 index a500e40..0000000 --- a/app/views/messages/show.json.jbuilder +++ /dev/null @@ -1 +0,0 @@ -json.partial! "messages/message", message: @message diff --git a/app/views/model_versions/_model_version.json.jbuilder b/app/views/model_versions/_model_version.json.jbuilder index 6ecf620..c11d2f9 100644 --- a/app/views/model_versions/_model_version.json.jbuilder +++ b/app/views/model_versions/_model_version.json.jbuilder @@ -1,2 +1,5 @@ -json.extract! model_version, :id, :model_id, :configuration, :description, :built_on, :build_name, :created_at, :updated_at +# frozen_string_literal: true + +json.extract! model_version, :id, :model_id, :configuration, :description, :built_on, :build_name, :created_at, + :updated_at json.url model_model_version_url(id: model_version.id, format: :json) diff --git a/app/views/model_versions/index.json.jbuilder b/app/views/model_versions/index.json.jbuilder index 3d1ee79..17f29c6 100644 --- a/app/views/model_versions/index.json.jbuilder +++ b/app/views/model_versions/index.json.jbuilder @@ -1 +1,3 @@ -json.array! @model_versions, partial: "model_versions/model_version", as: :model_version +# frozen_string_literal: true + +json.array! @model_versions, partial: 'model_versions/model_version', as: :model_version diff --git a/app/views/model_versions/show.json.jbuilder b/app/views/model_versions/show.json.jbuilder index a1c57f8..f732605 100644 --- a/app/views/model_versions/show.json.jbuilder +++ b/app/views/model_versions/show.json.jbuilder @@ -1 +1,3 @@ -json.partial! "model_versions/model_version", model_version: @model_version +# frozen_string_literal: true + +json.partial! 'model_versions/model_version', model_version: @model_version diff --git a/app/views/models/_model.json.jbuilder b/app/views/models/_model.json.jbuilder index 4bb52af..b66d3e1 100644 --- a/app/views/models/_model.json.jbuilder +++ b/app/views/models/_model.json.jbuilder @@ -1,2 +1,3 @@ +# frozen_string_literal: true + json.extract! model, :id, :name, :url, :executor_type, :created_at, :updated_at -json.url model_url(model, format: :json) diff --git a/app/views/models/index.json.jbuilder b/app/views/models/index.json.jbuilder index 35c25e5..2eed983 100644 --- a/app/views/models/index.json.jbuilder +++ b/app/views/models/index.json.jbuilder @@ -1 +1,3 @@ -json.array! @models, partial: "models/model", as: :model +# frozen_string_literal: true + +json.array! @models, partial: 'models/model', as: :model diff --git a/app/views/models/show.json.jbuilder b/app/views/models/show.json.jbuilder index 3b2c28a..7b2e1c4 100644 --- a/app/views/models/show.json.jbuilder +++ b/app/views/models/show.json.jbuilder @@ -1 +1,3 @@ -json.partial! "models/model", model: @model +# frozen_string_literal: true + +json.partial! 'models/model', model: @model diff --git a/app/views/participants/_form.html.erb b/app/views/participants/_form.html.erb deleted file mode 100644 index 44c9a49..0000000 --- a/app/views/participants/_form.html.erb +++ /dev/null @@ -1,32 +0,0 @@ -<%= form_with(model: participant) do |form| %> - <% if participant.errors.any? %> -
    -

    <%= pluralize(participant.errors.count, "error") %> prohibited this participant from being saved:

    - -
      - <% participant.errors.each do |error| %> -
    • <%= error.full_message %>
    • - <% end %> -
    -
    - <% end %> - -
    - <%= form.label :name, style: "display: block" %> - <%= form.text_field :name %> -
    - -
    - <%= form.label :configuration, style: "display: block" %> - <%= form.text_area :configuration %> -
    - -
    - <%= form.label :implementor, style: "display: block" %> - <%= form.text_field :implementor %> -
    - -
    - <%= form.submit %> -
    -<% end %> diff --git a/app/views/participants/_participant.html.erb b/app/views/participants/_participant.html.erb deleted file mode 100644 index 3f5f1e8..0000000 --- a/app/views/participants/_participant.html.erb +++ /dev/null @@ -1,17 +0,0 @@ -
    -

    - Name: - <%= participant.name %> -

    - -

    - Configuration: - <%= participant.configuration&.to_json %> -

    - -

    - Implementor: - <%= participant.implementor %> -

    - -
    diff --git a/app/views/participants/_participant.json.jbuilder b/app/views/participants/_participant.json.jbuilder deleted file mode 100644 index 830f6d1..0000000 --- a/app/views/participants/_participant.json.jbuilder +++ /dev/null @@ -1,2 +0,0 @@ -json.extract! participant, :id, :name, :configuration, :implementor, :created_at, :updated_at -json.url participant_url(participant, format: :json) diff --git a/app/views/participants/edit.html.erb b/app/views/participants/edit.html.erb deleted file mode 100644 index f0a27e7..0000000 --- a/app/views/participants/edit.html.erb +++ /dev/null @@ -1,10 +0,0 @@ -

    Editing participant

    - -<%= render "form", participant: @participant %> - -
    - -
    - <%= link_to "Show this participant", @participant %> | - <%= link_to "Back to participants", participants_path %> -
    diff --git a/app/views/participants/index.html.erb b/app/views/participants/index.html.erb deleted file mode 100644 index 62726ef..0000000 --- a/app/views/participants/index.html.erb +++ /dev/null @@ -1,14 +0,0 @@ -

    <%= notice %>

    - -

    Participants

    - -
    - <% @participants.each do |participant| %> - <%= render participant %> -

    - <%= link_to "Show this participant", participant %> -

    - <% end %> -
    - -<%= link_to "New participant", new_participant_path %> diff --git a/app/views/participants/index.json.jbuilder b/app/views/participants/index.json.jbuilder deleted file mode 100644 index c0f82d5..0000000 --- a/app/views/participants/index.json.jbuilder +++ /dev/null @@ -1 +0,0 @@ -json.array! @participants, partial: "participants/participant", as: :participant diff --git a/app/views/participants/new.html.erb b/app/views/participants/new.html.erb deleted file mode 100644 index 926b155..0000000 --- a/app/views/participants/new.html.erb +++ /dev/null @@ -1,9 +0,0 @@ -

    New participant

    - -<%= render "form", participant: @participant %> - -
    - -
    - <%= link_to "Back to participants", participants_path %> -
    diff --git a/app/views/participants/show.html.erb b/app/views/participants/show.html.erb deleted file mode 100644 index 2b96bcf..0000000 --- a/app/views/participants/show.html.erb +++ /dev/null @@ -1,10 +0,0 @@ -

    <%= notice %>

    - -<%= render @participant %> - -
    - <%= link_to "Edit this participant", edit_participant_path(@participant) %> | - <%= link_to "Back to participants", participants_path %> - - <%= button_to "Destroy this participant", @participant, method: :delete %> -
    diff --git a/app/views/participants/show.json.jbuilder b/app/views/participants/show.json.jbuilder deleted file mode 100644 index 2ead1b0..0000000 --- a/app/views/participants/show.json.jbuilder +++ /dev/null @@ -1 +0,0 @@ -json.partial! "participants/participant", participant: @participant diff --git a/app/views/prompts/_prompt.json.jbuilder b/app/views/prompts/_prompt.json.jbuilder index 2fddcc6..521b8b5 100644 --- a/app/views/prompts/_prompt.json.jbuilder +++ b/app/views/prompts/_prompt.json.jbuilder @@ -1,2 +1,4 @@ +# frozen_string_literal: true + json.extract! prompt, :id, :user_id, :value, :name, :created_at, :updated_at json.url prompt_url(prompt, format: :json) diff --git a/app/views/prompts/index.html.erb b/app/views/prompts/index.html.erb index 474375b..f34c5ef 100644 --- a/app/views/prompts/index.html.erb +++ b/app/views/prompts/index.html.erb @@ -8,7 +8,6 @@

    Prompts

    - <%= link_to "Import", '', class: "rounded-lg py-3 px-5 bg-blue-600 text-white block font-medium mr-1" %> <%= link_to "New prompt", new_prompt_path, class: "rounded-lg py-3 px-5 bg-blue-600 text-white block font-medium" %>
    diff --git a/app/views/prompts/index.json.jbuilder b/app/views/prompts/index.json.jbuilder index 8be6797..1a064d2 100644 --- a/app/views/prompts/index.json.jbuilder +++ b/app/views/prompts/index.json.jbuilder @@ -1 +1,3 @@ -json.array! @prompts, partial: "prompts/prompt", as: :prompt +# frozen_string_literal: true + +json.array! @prompts, partial: 'prompts/prompt', as: :prompt diff --git a/app/views/prompts/show.json.jbuilder b/app/views/prompts/show.json.jbuilder index d2cd4a5..0cb32c9 100644 --- a/app/views/prompts/show.json.jbuilder +++ b/app/views/prompts/show.json.jbuilder @@ -1 +1,3 @@ -json.partial! "prompts/prompt", prompt: @prompt +# frozen_string_literal: true + +json.partial! 'prompts/prompt', prompt: @prompt diff --git a/app/views/test_results/index.html.erb b/app/views/test_results/index.html.erb index f67f740..1b5ac32 100644 --- a/app/views/test_results/index.html.erb +++ b/app/views/test_results/index.html.erb @@ -1,7 +1,6 @@

    Test Results

    - <%= link_to "Export", '', class: "rounded-lg py-3 px-5 bg-blue-600 text-white block font-medium" %>
    diff --git a/bin/bundle b/bin/bundle index 50da5fd..ef688ec 100755 --- a/bin/bundle +++ b/bin/bundle @@ -8,46 +8,46 @@ # this file is here to facilitate running it. # -require "rubygems" +require 'rubygems' m = Module.new do module_function def invoked_as_script? - File.expand_path($0) == File.expand_path(__FILE__) + File.expand_path($PROGRAM_NAME) == File.expand_path(__FILE__) end def env_var_version - ENV["BUNDLER_VERSION"] + ENV['BUNDLER_VERSION'] end def cli_arg_version return unless invoked_as_script? # don't want to hijack other binstubs - return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update` + return unless 'update'.start_with?(ARGV.first || ' ') # must be running `bundle update` + bundler_version = nil update_index = nil ARGV.each_with_index do |a, i| - if update_index && update_index.succ == i && a.match?(Gem::Version::ANCHORED_VERSION_PATTERN) - bundler_version = a - end + bundler_version = a if update_index && update_index.succ == i && a.match?(Gem::Version::ANCHORED_VERSION_PATTERN) next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/ - bundler_version = $1 + + bundler_version = Regexp.last_match(1) update_index = i end bundler_version end def gemfile - gemfile = ENV["BUNDLE_GEMFILE"] + gemfile = ENV['BUNDLE_GEMFILE'] return gemfile if gemfile && !gemfile.empty? - File.expand_path("../Gemfile", __dir__) + File.expand_path('../Gemfile', __dir__) end def lockfile lockfile = case File.basename(gemfile) - when "gems.rb" then gemfile.sub(/\.rb$/, ".locked") + when 'gems.rb' then gemfile.sub(/\.rb$/, '.locked') else "#{gemfile}.lock" end File.expand_path(lockfile) @@ -55,8 +55,10 @@ m = Module.new do def lockfile_version return unless File.file?(lockfile) + lockfile_contents = File.read(lockfile) return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/ + Regexp.last_match(1) end @@ -76,20 +78,24 @@ m = Module.new do end def load_bundler! - ENV["BUNDLE_GEMFILE"] ||= gemfile + ENV['BUNDLE_GEMFILE'] ||= gemfile activate_bundler end def activate_bundler gem_error = activation_error_handling do - gem "bundler", bundler_requirement + gem 'bundler', bundler_requirement end return if gem_error.nil? + require_error = activation_error_handling do - require "bundler/version" + require 'bundler/version' + end + if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION)) + return end - return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION)) + warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`" exit 42 end @@ -104,6 +110,4 @@ end m.load_bundler! -if m.invoked_as_script? - load Gem.bin_path("bundler", "bundle") -end +load Gem.bin_path('bundler', 'bundle') if m.invoked_as_script? diff --git a/bin/docker-entrypoint b/bin/docker-entrypoint index 0d6c863..69e341e 100755 --- a/bin/docker-entrypoint +++ b/bin/docker-entrypoint @@ -1,6 +1,18 @@ #!/bin/bash -e # If running the rails server then create or migrate existing database +generate_credentials() { + if [ ! -f "config/master.key" ] || [ ! -f "config/credentials.yml.enc" ]; then + echo "Generating master key and credentials..." + rm -f config/master.key config/credentials.yml.enc + # Generate credentials + rails credentials:edit + fi +} + +# Generate credentials +generate_credentials + ./bin/rails db:prepare exec "${@}" diff --git a/bin/importmap b/bin/importmap index 36502ab..d423864 100755 --- a/bin/importmap +++ b/bin/importmap @@ -1,4 +1,5 @@ #!/usr/bin/env ruby +# frozen_string_literal: true -require_relative "../config/application" -require "importmap/commands" +require_relative '../config/application' +require 'importmap/commands' diff --git a/bin/rails b/bin/rails index efc0377..a31728a 100755 --- a/bin/rails +++ b/bin/rails @@ -1,4 +1,6 @@ #!/usr/bin/env ruby -APP_PATH = File.expand_path("../config/application", __dir__) -require_relative "../config/boot" -require "rails/commands" +# frozen_string_literal: true + +APP_PATH = File.expand_path('../config/application', __dir__) +require_relative '../config/boot' +require 'rails/commands' diff --git a/bin/rake b/bin/rake index 4fbf10b..c199955 100755 --- a/bin/rake +++ b/bin/rake @@ -1,4 +1,6 @@ #!/usr/bin/env ruby -require_relative "../config/boot" -require "rake" +# frozen_string_literal: true + +require_relative '../config/boot' +require 'rake' Rake.application.run diff --git a/bin/setup b/bin/setup index 3cd5a9d..3a74034 100755 --- a/bin/setup +++ b/bin/setup @@ -1,8 +1,10 @@ #!/usr/bin/env ruby -require "fileutils" +# frozen_string_literal: true + +require 'fileutils' # path to your application root. -APP_ROOT = File.expand_path("..", __dir__) +APP_ROOT = File.expand_path('..', __dir__) def system!(*args) system(*args, exception: true) @@ -13,9 +15,9 @@ FileUtils.chdir APP_ROOT do # This script is idempotent, so that you can run it at any time and get an expectable outcome. # Add necessary setup steps to this file. - puts "== Installing dependencies ==" - system! "gem install bundler --conservative" - system("bundle check") || system!("bundle install") + puts '== Installing dependencies ==' + system! 'gem install bundler --conservative' + system('bundle check') || system!('bundle install') # puts "\n== Copying sample files ==" # unless File.exist?("config/database.yml") @@ -23,11 +25,11 @@ FileUtils.chdir APP_ROOT do # end puts "\n== Preparing database ==" - system! "bin/rails db:prepare" + system! 'bin/rails db:prepare' puts "\n== Removing old logs and tempfiles ==" - system! "bin/rails log:clear tmp:clear" + system! 'bin/rails log:clear tmp:clear' puts "\n== Restarting application server ==" - system! "bin/rails restart" + system! 'bin/rails restart' end diff --git a/config.ru b/config.ru index 4a3c09a..6dc8321 100644 --- a/config.ru +++ b/config.ru @@ -1,6 +1,8 @@ +# frozen_string_literal: true + # This file is used by Rack-based servers to start the application. -require_relative "config/environment" +require_relative 'config/environment' run Rails.application Rails.application.load_server diff --git a/config/application.rb b/config/application.rb index bf71aef..b1bad52 100644 --- a/config/application.rb +++ b/config/application.rb @@ -1,6 +1,8 @@ -require_relative "boot" +# frozen_string_literal: true -require "rails/all" +require_relative 'boot' + +require 'rails/all' # Require the gems listed in Gemfile, including any gems # you've limited to :test, :development, or :production. @@ -14,7 +16,7 @@ class Application < Rails::Application # Please, add to the `ignore` list any other `lib` subdirectories that do # not contain `.rb` files, or that should not be reloaded or eager loaded. # Common ones are `templates`, `generators`, or `middleware`, for example. - config.autoload_lib(ignore: %w(assets tasks)) + config.autoload_lib(ignore: %w[assets tasks]) config.active_job.queue_adapter = :solid_queue config.solid_queue.silence_polling = false diff --git a/config/boot.rb b/config/boot.rb index 988a5dd..c04863f 100644 --- a/config/boot.rb +++ b/config/boot.rb @@ -1,4 +1,6 @@ -ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) +# frozen_string_literal: true -require "bundler/setup" # Set up gems listed in the Gemfile. -require "bootsnap/setup" # Speed up boot time by caching expensive operations. +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) + +require 'bundler/setup' # Set up gems listed in the Gemfile. +require 'bootsnap/setup' # Speed up boot time by caching expensive operations. diff --git a/config/environment.rb b/config/environment.rb index cac5315..d5abe55 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + # Load the Rails application. -require_relative "application" +require_relative 'application' # Initialize the Rails application. Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb index 714c01f..8881f77 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -1,4 +1,6 @@ -require "active_support/core_ext/integer/time" +# frozen_string_literal: true + +require 'active_support/core_ext/integer/time' Dotenv.load Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. @@ -19,13 +21,13 @@ # Enable/disable caching. By default caching is disabled. # Run rails dev:cache to toggle caching. - if Rails.root.join("tmp/caching-dev.txt").exist? + if Rails.root.join('tmp/caching-dev.txt').exist? config.action_controller.perform_caching = true config.action_controller.enable_fragment_cache_logging = true config.cache_store = :memory_store config.public_file_server.headers = { - "Cache-Control" => "public, max-age=#{2.days.to_i}" + 'Cache-Control' => "public, max-age=#{2.days.to_i}" } else config.action_controller.perform_caching = false diff --git a/config/environments/production.rb b/config/environments/production.rb index 214f719..af008a2 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -1,4 +1,6 @@ -require "active_support/core_ext/integer/time" +# frozen_string_literal: true + +require 'active_support/core_ext/integer/time' Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. @@ -53,17 +55,17 @@ config.force_ssl = false # Log to STDOUT by default - config.logger = ActiveSupport::Logger.new(STDOUT) - .tap { |logger| logger.formatter = ::Logger::Formatter.new } - .then { |logger| ActiveSupport::TaggedLogging.new(logger) } + config.logger = ActiveSupport::Logger.new($stdout) + .tap { |logger| logger.formatter = ::Logger::Formatter.new } + .then { |logger| ActiveSupport::TaggedLogging.new(logger) } # Prepend all log lines with the following tags. - config.log_tags = [ :request_id ] + config.log_tags = [:request_id] # "info" includes generic and useful information about system operation, but avoids logging too much # information to avoid inadvertent exposure of personally identifiable information (PII). If you # want to log everything, set the level to "debug". - config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "info") + config.log_level = ENV.fetch('RAILS_LOG_LEVEL', 'info') # Use a different cache store in production. # config.cache_store = :mem_cache_store diff --git a/config/environments/test.rb b/config/environments/test.rb index adbb4a6..f1d2fb5 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -1,4 +1,6 @@ -require "active_support/core_ext/integer/time" +# frozen_string_literal: true + +require 'active_support/core_ext/integer/time' # The test environment is used exclusively to run your application's # test suite. You never need to work with it otherwise. Remember that @@ -15,12 +17,12 @@ # this is usually not necessary, and can slow down your test suite. However, it's # recommended that you enable it in continuous integration systems to ensure eager # loading is working properly before deploying your code. - config.eager_load = ENV["CI"].present? + config.eager_load = ENV['CI'].present? # Configure public file server for tests with Cache-Control for performance. config.public_file_server.enabled = true config.public_file_server.headers = { - "Cache-Control" => "public, max-age=#{1.hour.to_i}" + 'Cache-Control' => "public, max-age=#{1.hour.to_i}" } # Show full error reports and disable caching. diff --git a/config/importmap.rb b/config/importmap.rb index a0405df..467411f 100644 --- a/config/importmap.rb +++ b/config/importmap.rb @@ -1,10 +1,12 @@ +# frozen_string_literal: true + # Pin npm packages by running ./bin/importmap -pin "application" -pin "@hotwired/turbo-rails", to: "turbo.min.js" -pin "@hotwired/stimulus", to: "stimulus.min.js" -pin "@hotwired/stimulus-loading", to: "stimulus-loading.js" -pin "init-alpine", to: "init-alpine.js" -pin "compare", to: "compare.js" -pin "focus-trap.js", to: "focus-trap.js" -pin_all_from "app/javascript/controllers", under: "controllers" +pin 'application' +pin '@hotwired/turbo-rails', to: 'turbo.min.js' +pin '@hotwired/stimulus', to: 'stimulus.min.js' +pin '@hotwired/stimulus-loading', to: 'stimulus-loading.js' +pin 'init-alpine', to: 'init-alpine.js' +pin 'compare', to: 'compare.js' +pin 'focus-trap.js', to: 'focus-trap.js' +pin_all_from 'app/javascript/controllers', under: 'controllers' diff --git a/config/initializers/active_record_encryption.rb b/config/initializers/active_record_encryption.rb new file mode 100644 index 0000000..330d0b4 --- /dev/null +++ b/config/initializers/active_record_encryption.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +credentials = begin + Rails.application.credentials +rescue StandardError + nil +end + +if credentials.present? && !(credentials.dig(:active_record_encryption, :primary_key) && + credentials.dig(:active_record_encryption, :deterministic_key) && + credentials.dig(:active_record_encryption, :key_derivation_salt)) + new_keys = { + active_record_encryption: { + primary_key: SecureRandom.hex(16), + deterministic_key: SecureRandom.hex(16), + key_derivation_salt: SecureRandom.hex(16) + } + } + + encrypted = ActiveSupport::EncryptedConfiguration.new( + config_path: 'config/credentials.yml.enc', + key_path: 'config/master.key', + env_key: 'RAILS_MASTER_KEY', + raise_if_missing_key: true + ) + + current_credentials = YAML.load(encrypted.read) || {} + updated_credentials = current_credentials.deep_merge(new_keys) + encrypted.write(updated_credentials.to_yaml) +end diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb index f2b2004..c2264b3 100644 --- a/config/initializers/assets.rb +++ b/config/initializers/assets.rb @@ -1,7 +1,9 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. # Version of your assets, change this if you want to expire all your assets. -Rails.application.config.assets.version = "1.0" +Rails.application.config.assets.version = '1.0' # Add additional assets to the asset load path. Rails.application.config.assets.paths << Rails.root.join('app', 'assets', 'builds') diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb index b3076b3..35ab3fd 100644 --- a/config/initializers/content_security_policy.rb +++ b/config/initializers/content_security_policy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. # Define an application-wide content security policy. diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 5376fec..c7f2fae 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -97,7 +97,7 @@ # Notice that if you are skipping storage for all authentication paths, you # may want to disable generating routes to Devise's sessions controller by # passing skip: :sessions to `devise_for` in your config/routes.rb - config.skip_session_storage = [:http_auth, :params_auth] + config.skip_session_storage = %i[http_auth] # By default, Devise cleans up the CSRF token on authentication to # avoid CSRF token fixation attacks. This means that, when using AJAX @@ -313,6 +313,29 @@ # devise-jwt config config.jwt do |jwt| - jwt.secret = Rails.application.credentials.devise_jwt_secret_key! + credentials = begin + Rails.application.credentials + rescue StandardError + nil + end + + if credentials&.devise_jwt_secret_key.present? + jwt.secret = credentials.devise_jwt_secret_key! + elsif credentials.present? + encrypted = ActiveSupport::EncryptedConfiguration.new( + config_path: 'config/credentials.yml.enc', + key_path: 'config/master.key', + env_key: 'RAILS_MASTER_KEY', + raise_if_missing_key: true + ) + + current_credentials = YAML.load(encrypted.read) || {} + devise_jwt_secret_key = SecureRandom.hex(12) + updated_credentials = current_credentials.deep_merge({ devise_jwt_secret_key: }) + encrypted.write(updated_credentials.to_yaml) + jwt.secret = devise_jwt_secret_key + else + jwt.secret = '' + end end end diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb index c2d89e2..c416e6a 100644 --- a/config/initializers/filter_parameter_logging.rb +++ b/config/initializers/filter_parameter_logging.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. # Configure parameters to be partially matched (e.g. passw matches password) and filtered from the log file. # Use this to limit dissemination of sensitive information. # See the ActiveSupport::ParameterFilter documentation for supported notations and behaviors. -Rails.application.config.filter_parameters += [ - :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +Rails.application.config.filter_parameters += %i[ + passw secret token _key crypt salt certificate otp ssn ] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb index 3860f65..9e049dc 100644 --- a/config/initializers/inflections.rb +++ b/config/initializers/inflections.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. # Add new inflection rules using the following format. Inflections diff --git a/config/initializers/openai.rb b/config/initializers/openai.rb deleted file mode 100644 index 6c2a180..0000000 --- a/config/initializers/openai.rb +++ /dev/null @@ -1,8 +0,0 @@ -openai_credentials = Rails.application.credentials&.openai - -return unless openai_credentials && openai_credentials.access_token && openai_credentials.organization_id - -OpenAI.configure do |config| - config.access_token = openai_credentials.access_token - config.organization_id = openai_credentials.organization_id -end diff --git a/config/initializers/permissions_policy.rb b/config/initializers/permissions_policy.rb index 7db3b95..e8d0b2a 100644 --- a/config/initializers/permissions_policy.rb +++ b/config/initializers/permissions_policy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. # Define an application-wide HTTP permissions policy. For further diff --git a/config/puma.rb b/config/puma.rb index afa809b..7ed4157 100644 --- a/config/puma.rb +++ b/config/puma.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This configuration file will be evaluated by Puma. The top-level methods that # are invoked here are part of Puma's configuration DSL. For more information # about methods provided by the DSL, see https://puma.io/puma/Puma/DSL.html. @@ -7,29 +9,29 @@ # Any libraries that use thread pools should be configured to match # the maximum value specified for Puma. Default is set to 5 threads for minimum # and maximum; this matches the default thread size of Active Record. -max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } -min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +max_threads_count = ENV.fetch('RAILS_MAX_THREADS', 5) +min_threads_count = ENV.fetch('RAILS_MIN_THREADS') { max_threads_count } threads min_threads_count, max_threads_count # Specifies that the worker count should equal the number of processors in production. -if ENV["RAILS_ENV"] == "production" - require "concurrent-ruby" - worker_count = Integer(ENV.fetch("WEB_CONCURRENCY") { Concurrent.physical_processor_count }) +if ENV['RAILS_ENV'] == 'production' + require 'concurrent-ruby' + worker_count = Integer(ENV.fetch('WEB_CONCURRENCY') { Concurrent.physical_processor_count }) workers worker_count if worker_count > 1 end # Specifies the `worker_timeout` threshold that Puma will use to wait before # terminating a worker in development environments. -worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" +worker_timeout 3600 if ENV.fetch('RAILS_ENV', 'development') == 'development' # Specifies the `port` that Puma will listen on to receive requests; default is 3000. -port ENV.fetch("PORT") { 3000 } +port ENV.fetch('PORT', 3000) # Specifies the `environment` that Puma will run in. -environment ENV.fetch("RAILS_ENV") { "development" } +environment ENV.fetch('RAILS_ENV', 'development') # Specifies the `pidfile` that Puma will use. -pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } +pidfile ENV.fetch('PIDFILE', 'tmp/pids/server.pid') # Allow puma to be restarted by `bin/rails restart` command. plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb index b49a0f6..91a983e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,22 +1,20 @@ +# frozen_string_literal: true + Rails.application.routes.draw do resources :prompts, except: %i[edit update] do - resources :test_runs, only: [:new, :create] + resources :test_runs, only: %i[new create] end resources :compare, only: [:index] - resources :test_results, only: [:index, :update, :show] + resources :test_results, only: %i[index update show] resources :models do resources :model_versions end devise_for :users - resources :participants - resources :chats do - resources :messages - end - get "up" => "rails/health#show", as: :rails_health_check + get 'up' => 'rails/health#show', as: :rails_health_check - root "dashboard#index" + root 'dashboard#index' end diff --git a/db/migrate/20240605185921_create_messages.rb b/db/migrate/20240605185921_create_messages.rb deleted file mode 100644 index 7cbb47a..0000000 --- a/db/migrate/20240605185921_create_messages.rb +++ /dev/null @@ -1,9 +0,0 @@ -class CreateMessages < ActiveRecord::Migration[7.1] - def change - create_table :messages do |t| - t.text :body - - t.timestamps - end - end -end diff --git a/db/migrate/20240605222045_add_from_to_message.rb b/db/migrate/20240605222045_add_from_to_message.rb deleted file mode 100644 index cb3cb3d..0000000 --- a/db/migrate/20240605222045_add_from_to_message.rb +++ /dev/null @@ -1,5 +0,0 @@ -class AddFromToMessage < ActiveRecord::Migration[7.1] - def change - add_column :messages, :from, :string, default: :user - end -end diff --git a/db/migrate/20240605222936_create_chats.rb b/db/migrate/20240605222936_create_chats.rb deleted file mode 100644 index 7e1fdc1..0000000 --- a/db/migrate/20240605222936_create_chats.rb +++ /dev/null @@ -1,9 +0,0 @@ -class CreateChats < ActiveRecord::Migration[7.1] - def change - create_table :chats do |t| - t.string :title - - t.timestamps - end - end -end diff --git a/db/migrate/20240609152859_create_participants.rb b/db/migrate/20240609152859_create_participants.rb deleted file mode 100644 index dff1260..0000000 --- a/db/migrate/20240609152859_create_participants.rb +++ /dev/null @@ -1,11 +0,0 @@ -class CreateParticipants < ActiveRecord::Migration[7.1] - def change - create_table :participants do |t| - t.string :name - t.text :configuration - t.string :implementor - - t.timestamps - end - end -end diff --git a/db/migrate/20240609153938_add_chat_ref_to_messages.rb b/db/migrate/20240609153938_add_chat_ref_to_messages.rb deleted file mode 100644 index 6635c3c..0000000 --- a/db/migrate/20240609153938_add_chat_ref_to_messages.rb +++ /dev/null @@ -1,5 +0,0 @@ -class AddChatRefToMessages < ActiveRecord::Migration[7.1] - def change - add_reference :messages, :chat, null: false, foreign_key: true - end -end diff --git a/db/migrate/20240609173654_devise_create_users.rb b/db/migrate/20240609173654_devise_create_users.rb index b99f25b..b255814 100644 --- a/db/migrate/20240609173654_devise_create_users.rb +++ b/db/migrate/20240609173654_devise_create_users.rb @@ -4,8 +4,8 @@ class DeviseCreateUsers < ActiveRecord::Migration[7.1] def change create_table :users do |t| ## Database authenticatable - t.string :email, null: false, default: "" - t.string :encrypted_password, null: false, default: "" + t.string :email, null: false, default: '' + t.string :encrypted_password, null: false, default: '' ## Recoverable t.string :reset_password_token @@ -32,7 +32,6 @@ def change # t.string :unlock_token # Only if unlock strategy is :email or :both # t.datetime :locked_at - t.timestamps null: false end diff --git a/db/migrate/20240708135340_create_solid_queue_tables.solid_queue.rb b/db/migrate/20240708135340_create_solid_queue_tables.solid_queue.rb index 6d8c4f6..9edfc57 100644 --- a/db/migrate/20240708135340_create_solid_queue_tables.solid_queue.rb +++ b/db/migrate/20240708135340_create_solid_queue_tables.solid_queue.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This migration comes from solid_queue (originally 20231211200639) class CreateSolidQueueTables < ActiveRecord::Migration[7.0] def change @@ -13,8 +15,8 @@ def change t.timestamps - t.index [ :queue_name, :finished_at ], name: "index_solid_queue_jobs_for_filtering" - t.index [ :scheduled_at, :finished_at ], name: "index_solid_queue_jobs_for_alerting" + t.index %i[queue_name finished_at], name: 'index_solid_queue_jobs_for_filtering' + t.index %i[scheduled_at finished_at], name: 'index_solid_queue_jobs_for_alerting' end create_table :solid_queue_scheduled_executions do |t| @@ -25,7 +27,7 @@ def change t.datetime :created_at, null: false - t.index [ :scheduled_at, :priority, :job_id ], name: "index_solid_queue_dispatch_all" + t.index %i[scheduled_at priority job_id], name: 'index_solid_queue_dispatch_all' end create_table :solid_queue_ready_executions do |t| @@ -35,8 +37,8 @@ def change t.datetime :created_at, null: false - t.index [ :priority, :job_id ], name: "index_solid_queue_poll_all" - t.index [ :queue_name, :priority, :job_id ], name: "index_solid_queue_poll_by_queue" + t.index %i[priority job_id], name: 'index_solid_queue_poll_all' + t.index %i[queue_name priority job_id], name: 'index_solid_queue_poll_by_queue' end create_table :solid_queue_claimed_executions do |t| @@ -44,7 +46,7 @@ def change t.bigint :process_id t.datetime :created_at, null: false - t.index [ :process_id, :job_id ] + t.index %i[process_id job_id] end create_table :solid_queue_blocked_executions do |t| @@ -56,7 +58,7 @@ def change t.datetime :created_at, null: false - t.index [ :expires_at, :concurrency_key ], name: "index_solid_queue_blocked_executions_for_maintenance" + t.index %i[expires_at concurrency_key], name: 'index_solid_queue_blocked_executions_for_maintenance' end create_table :solid_queue_failed_executions do |t| @@ -89,7 +91,7 @@ def change t.timestamps - t.index [ :key, :value ], name: "index_solid_queue_semaphores_on_key_and_value" + t.index %i[key value], name: 'index_solid_queue_semaphores_on_key_and_value' end add_foreign_key :solid_queue_blocked_executions, :solid_queue_jobs, column: :job_id, on_delete: :cascade diff --git a/db/migrate/20240708135341_add_missing_index_to_blocked_executions.solid_queue.rb b/db/migrate/20240708135341_add_missing_index_to_blocked_executions.solid_queue.rb index 2d96b10..b4fffb5 100644 --- a/db/migrate/20240708135341_add_missing_index_to_blocked_executions.solid_queue.rb +++ b/db/migrate/20240708135341_add_missing_index_to_blocked_executions.solid_queue.rb @@ -1,6 +1,9 @@ +# frozen_string_literal: true + # This migration comes from solid_queue (originally 20240110143450) class AddMissingIndexToBlockedExecutions < ActiveRecord::Migration[7.1] def change - add_index :solid_queue_blocked_executions, [ :concurrency_key, :priority, :job_id ], name: "index_solid_queue_blocked_executions_for_release" + add_index :solid_queue_blocked_executions, %i[concurrency_key priority job_id], + name: 'index_solid_queue_blocked_executions_for_release' end end diff --git a/db/migrate/20240708135342_create_recurring_executions.solid_queue.rb b/db/migrate/20240708135342_create_recurring_executions.solid_queue.rb index 4c49821..6dd45dd 100644 --- a/db/migrate/20240708135342_create_recurring_executions.solid_queue.rb +++ b/db/migrate/20240708135342_create_recurring_executions.solid_queue.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This migration comes from solid_queue (originally 20240218110712) class CreateRecurringExecutions < ActiveRecord::Migration[7.1] def change @@ -7,7 +9,7 @@ def change t.datetime :run_at, null: false t.datetime :created_at, null: false - t.index [ :task_key, :run_at ], unique: true + t.index %i[task_key run_at], unique: true end add_foreign_key :solid_queue_recurring_executions, :solid_queue_jobs, column: :job_id, on_delete: :cascade diff --git a/db/migrate/20240709142816_create_models.rb b/db/migrate/20240709142816_create_models.rb index fc642d0..b02ee87 100644 --- a/db/migrate/20240709142816_create_models.rb +++ b/db/migrate/20240709142816_create_models.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateModels < ActiveRecord::Migration[7.1] def change create_table :models do |t| diff --git a/db/migrate/20240710114447_create_model_versions.rb b/db/migrate/20240710114447_create_model_versions.rb index f426c5a..692e36e 100644 --- a/db/migrate/20240710114447_create_model_versions.rb +++ b/db/migrate/20240710114447_create_model_versions.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateModelVersions < ActiveRecord::Migration[7.1] def change create_table :model_versions do |t| diff --git a/db/migrate/20240710132806_create_prompts.rb b/db/migrate/20240710132806_create_prompts.rb index db473c6..b2e855e 100644 --- a/db/migrate/20240710132806_create_prompts.rb +++ b/db/migrate/20240710132806_create_prompts.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreatePrompts < ActiveRecord::Migration[7.1] def change create_table :prompts do |t| diff --git a/db/migrate/20240711071633_create_test_results.rb b/db/migrate/20240711071633_create_test_results.rb index d6346c8..3997a70 100644 --- a/db/migrate/20240711071633_create_test_results.rb +++ b/db/migrate/20240711071633_create_test_results.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateTestResults < ActiveRecord::Migration[7.1] def change create_table :test_results do |t| diff --git a/db/migrate/20240712095024_add_executor_type_to_models.rb b/db/migrate/20240712095024_add_executor_type_to_models.rb index 2ba4af0..8bae826 100644 --- a/db/migrate/20240712095024_add_executor_type_to_models.rb +++ b/db/migrate/20240712095024_add_executor_type_to_models.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddExecutorTypeToModels < ActiveRecord::Migration[7.1] def change add_column :models, :executor_type, :integer diff --git a/db/migrate/20240712102033_add_api_key_to_models.rb b/db/migrate/20240712102033_add_api_key_to_models.rb index 77b721c..8801be2 100644 --- a/db/migrate/20240712102033_add_api_key_to_models.rb +++ b/db/migrate/20240712102033_add_api_key_to_models.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddApiKeyToModels < ActiveRecord::Migration[7.1] def change add_column :models, :api_key, :string diff --git a/db/schema.rb b/db/schema.rb index 1444a41..30a4ea3 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This file is auto-generated from the current state of the database. Instead # of editing this file, please use the migrations feature of Active Record to # incrementally modify your database, and then regenerate this schema definition. @@ -10,201 +12,177 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_07_12_102033) do +ActiveRecord::Schema[7.1].define(version: 20_240_712_102_033) do # These are extensions that must be enabled in order to support this database - enable_extension "plpgsql" - - create_table "chats", force: :cascade do |t| - t.string "title" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - end - - create_table "messages", force: :cascade do |t| - t.text "body" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.string "from", default: "user" - t.bigint "chat_id", null: false - t.index ["chat_id"], name: "index_messages_on_chat_id" - end - - create_table "model_versions", force: :cascade do |t| - t.bigint "model_id", null: false - t.json "configuration" - t.text "description" - t.date "built_on" - t.string "build_name" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["model_id"], name: "index_model_versions_on_model_id" - end - - create_table "models", force: :cascade do |t| - t.string "name" - t.string "url" - t.bigint "user_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.integer "executor_type" - t.string "api_key" - t.index ["user_id"], name: "index_models_on_user_id" - end - - create_table "participants", force: :cascade do |t| - t.string "name" - t.text "configuration" - t.string "implementor" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - end - - create_table "prompts", force: :cascade do |t| - t.bigint "user_id", null: false - t.text "value" - t.string "name" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["user_id"], name: "index_prompts_on_user_id" - end - - create_table "solid_queue_blocked_executions", force: :cascade do |t| - t.bigint "job_id", null: false - t.string "queue_name", null: false - t.integer "priority", default: 0, null: false - t.string "concurrency_key", null: false - t.datetime "expires_at", null: false - t.datetime "created_at", null: false - t.index ["concurrency_key", "priority", "job_id"], name: "index_solid_queue_blocked_executions_for_release" - t.index ["expires_at", "concurrency_key"], name: "index_solid_queue_blocked_executions_for_maintenance" - t.index ["job_id"], name: "index_solid_queue_blocked_executions_on_job_id", unique: true - end - - create_table "solid_queue_claimed_executions", force: :cascade do |t| - t.bigint "job_id", null: false - t.bigint "process_id" - t.datetime "created_at", null: false - t.index ["job_id"], name: "index_solid_queue_claimed_executions_on_job_id", unique: true - t.index ["process_id", "job_id"], name: "index_solid_queue_claimed_executions_on_process_id_and_job_id" - end - - create_table "solid_queue_failed_executions", force: :cascade do |t| - t.bigint "job_id", null: false - t.text "error" - t.datetime "created_at", null: false - t.index ["job_id"], name: "index_solid_queue_failed_executions_on_job_id", unique: true - end - - create_table "solid_queue_jobs", force: :cascade do |t| - t.string "queue_name", null: false - t.string "class_name", null: false - t.text "arguments" - t.integer "priority", default: 0, null: false - t.string "active_job_id" - t.datetime "scheduled_at" - t.datetime "finished_at" - t.string "concurrency_key" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["active_job_id"], name: "index_solid_queue_jobs_on_active_job_id" - t.index ["class_name"], name: "index_solid_queue_jobs_on_class_name" - t.index ["finished_at"], name: "index_solid_queue_jobs_on_finished_at" - t.index ["queue_name", "finished_at"], name: "index_solid_queue_jobs_for_filtering" - t.index ["scheduled_at", "finished_at"], name: "index_solid_queue_jobs_for_alerting" - end - - create_table "solid_queue_pauses", force: :cascade do |t| - t.string "queue_name", null: false - t.datetime "created_at", null: false - t.index ["queue_name"], name: "index_solid_queue_pauses_on_queue_name", unique: true - end - - create_table "solid_queue_processes", force: :cascade do |t| - t.string "kind", null: false - t.datetime "last_heartbeat_at", null: false - t.bigint "supervisor_id" - t.integer "pid", null: false - t.string "hostname" - t.text "metadata" - t.datetime "created_at", null: false - t.index ["last_heartbeat_at"], name: "index_solid_queue_processes_on_last_heartbeat_at" - t.index ["supervisor_id"], name: "index_solid_queue_processes_on_supervisor_id" - end - - create_table "solid_queue_ready_executions", force: :cascade do |t| - t.bigint "job_id", null: false - t.string "queue_name", null: false - t.integer "priority", default: 0, null: false - t.datetime "created_at", null: false - t.index ["job_id"], name: "index_solid_queue_ready_executions_on_job_id", unique: true - t.index ["priority", "job_id"], name: "index_solid_queue_poll_all" - t.index ["queue_name", "priority", "job_id"], name: "index_solid_queue_poll_by_queue" - end - - create_table "solid_queue_recurring_executions", force: :cascade do |t| - t.bigint "job_id", null: false - t.string "task_key", null: false - t.datetime "run_at", null: false - t.datetime "created_at", null: false - t.index ["job_id"], name: "index_solid_queue_recurring_executions_on_job_id", unique: true - t.index ["task_key", "run_at"], name: "index_solid_queue_recurring_executions_on_task_key_and_run_at", unique: true - end - - create_table "solid_queue_scheduled_executions", force: :cascade do |t| - t.bigint "job_id", null: false - t.string "queue_name", null: false - t.integer "priority", default: 0, null: false - t.datetime "scheduled_at", null: false - t.datetime "created_at", null: false - t.index ["job_id"], name: "index_solid_queue_scheduled_executions_on_job_id", unique: true - t.index ["scheduled_at", "priority", "job_id"], name: "index_solid_queue_dispatch_all" - end - - create_table "solid_queue_semaphores", force: :cascade do |t| - t.string "key", null: false - t.integer "value", default: 1, null: false - t.datetime "expires_at", null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["expires_at"], name: "index_solid_queue_semaphores_on_expires_at" - t.index ["key", "value"], name: "index_solid_queue_semaphores_on_key_and_value" - t.index ["key"], name: "index_solid_queue_semaphores_on_key", unique: true - end - - create_table "test_results", force: :cascade do |t| - t.bigint "model_version_id", null: false - t.bigint "prompt_id", null: false - t.text "result" - t.float "time" - t.integer "rating" - t.integer "status" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["model_version_id"], name: "index_test_results_on_model_version_id" - t.index ["prompt_id"], name: "index_test_results_on_prompt_id" - end - - create_table "users", force: :cascade do |t| - t.string "email", default: "", null: false - t.string "encrypted_password", default: "", null: false - t.string "reset_password_token" - t.datetime "reset_password_sent_at" - t.datetime "remember_created_at" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["email"], name: "index_users_on_email", unique: true - t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true - end - - add_foreign_key "messages", "chats" - add_foreign_key "model_versions", "models" - add_foreign_key "prompts", "users" - add_foreign_key "solid_queue_blocked_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade - add_foreign_key "solid_queue_claimed_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade - add_foreign_key "solid_queue_failed_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade - add_foreign_key "solid_queue_ready_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade - add_foreign_key "solid_queue_recurring_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade - add_foreign_key "solid_queue_scheduled_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade - add_foreign_key "test_results", "model_versions" - add_foreign_key "test_results", "prompts" + enable_extension 'plpgsql' + + create_table 'model_versions', force: :cascade do |t| + t.bigint 'model_id', null: false + t.json 'configuration' + t.text 'description' + t.date 'built_on' + t.string 'build_name' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + t.index ['model_id'], name: 'index_model_versions_on_model_id' + end + + create_table 'models', force: :cascade do |t| + t.string 'name' + t.string 'url' + t.bigint 'user_id' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + t.integer 'executor_type' + t.string 'api_key' + t.index ['user_id'], name: 'index_models_on_user_id' + end + + create_table 'prompts', force: :cascade do |t| + t.bigint 'user_id', null: false + t.text 'value' + t.string 'name' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + t.index ['user_id'], name: 'index_prompts_on_user_id' + end + + create_table 'solid_queue_blocked_executions', force: :cascade do |t| + t.bigint 'job_id', null: false + t.string 'queue_name', null: false + t.integer 'priority', default: 0, null: false + t.string 'concurrency_key', null: false + t.datetime 'expires_at', null: false + t.datetime 'created_at', null: false + t.index %w[concurrency_key priority job_id], name: 'index_solid_queue_blocked_executions_for_release' + t.index %w[expires_at concurrency_key], name: 'index_solid_queue_blocked_executions_for_maintenance' + t.index ['job_id'], name: 'index_solid_queue_blocked_executions_on_job_id', unique: true + end + + create_table 'solid_queue_claimed_executions', force: :cascade do |t| + t.bigint 'job_id', null: false + t.bigint 'process_id' + t.datetime 'created_at', null: false + t.index ['job_id'], name: 'index_solid_queue_claimed_executions_on_job_id', unique: true + t.index %w[process_id job_id], name: 'index_solid_queue_claimed_executions_on_process_id_and_job_id' + end + + create_table 'solid_queue_failed_executions', force: :cascade do |t| + t.bigint 'job_id', null: false + t.text 'error' + t.datetime 'created_at', null: false + t.index ['job_id'], name: 'index_solid_queue_failed_executions_on_job_id', unique: true + end + + create_table 'solid_queue_jobs', force: :cascade do |t| + t.string 'queue_name', null: false + t.string 'class_name', null: false + t.text 'arguments' + t.integer 'priority', default: 0, null: false + t.string 'active_job_id' + t.datetime 'scheduled_at' + t.datetime 'finished_at' + t.string 'concurrency_key' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + t.index ['active_job_id'], name: 'index_solid_queue_jobs_on_active_job_id' + t.index ['class_name'], name: 'index_solid_queue_jobs_on_class_name' + t.index ['finished_at'], name: 'index_solid_queue_jobs_on_finished_at' + t.index %w[queue_name finished_at], name: 'index_solid_queue_jobs_for_filtering' + t.index %w[scheduled_at finished_at], name: 'index_solid_queue_jobs_for_alerting' + end + + create_table 'solid_queue_pauses', force: :cascade do |t| + t.string 'queue_name', null: false + t.datetime 'created_at', null: false + t.index ['queue_name'], name: 'index_solid_queue_pauses_on_queue_name', unique: true + end + + create_table 'solid_queue_processes', force: :cascade do |t| + t.string 'kind', null: false + t.datetime 'last_heartbeat_at', null: false + t.bigint 'supervisor_id' + t.integer 'pid', null: false + t.string 'hostname' + t.text 'metadata' + t.datetime 'created_at', null: false + t.index ['last_heartbeat_at'], name: 'index_solid_queue_processes_on_last_heartbeat_at' + t.index ['supervisor_id'], name: 'index_solid_queue_processes_on_supervisor_id' + end + + create_table 'solid_queue_ready_executions', force: :cascade do |t| + t.bigint 'job_id', null: false + t.string 'queue_name', null: false + t.integer 'priority', default: 0, null: false + t.datetime 'created_at', null: false + t.index ['job_id'], name: 'index_solid_queue_ready_executions_on_job_id', unique: true + t.index %w[priority job_id], name: 'index_solid_queue_poll_all' + t.index %w[queue_name priority job_id], name: 'index_solid_queue_poll_by_queue' + end + + create_table 'solid_queue_recurring_executions', force: :cascade do |t| + t.bigint 'job_id', null: false + t.string 'task_key', null: false + t.datetime 'run_at', null: false + t.datetime 'created_at', null: false + t.index ['job_id'], name: 'index_solid_queue_recurring_executions_on_job_id', unique: true + t.index %w[task_key run_at], name: 'index_solid_queue_recurring_executions_on_task_key_and_run_at', unique: true + end + + create_table 'solid_queue_scheduled_executions', force: :cascade do |t| + t.bigint 'job_id', null: false + t.string 'queue_name', null: false + t.integer 'priority', default: 0, null: false + t.datetime 'scheduled_at', null: false + t.datetime 'created_at', null: false + t.index ['job_id'], name: 'index_solid_queue_scheduled_executions_on_job_id', unique: true + t.index %w[scheduled_at priority job_id], name: 'index_solid_queue_dispatch_all' + end + + create_table 'solid_queue_semaphores', force: :cascade do |t| + t.string 'key', null: false + t.integer 'value', default: 1, null: false + t.datetime 'expires_at', null: false + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + t.index ['expires_at'], name: 'index_solid_queue_semaphores_on_expires_at' + t.index %w[key value], name: 'index_solid_queue_semaphores_on_key_and_value' + t.index ['key'], name: 'index_solid_queue_semaphores_on_key', unique: true + end + + create_table 'test_results', force: :cascade do |t| + t.bigint 'model_version_id', null: false + t.bigint 'prompt_id', null: false + t.text 'result' + t.float 'time' + t.integer 'rating' + t.integer 'status' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + t.index ['model_version_id'], name: 'index_test_results_on_model_version_id' + t.index ['prompt_id'], name: 'index_test_results_on_prompt_id' + end + + create_table 'users', force: :cascade do |t| + t.string 'email', default: '', null: false + t.string 'encrypted_password', default: '', null: false + t.string 'reset_password_token' + t.datetime 'reset_password_sent_at' + t.datetime 'remember_created_at' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + t.index ['email'], name: 'index_users_on_email', unique: true + t.index ['reset_password_token'], name: 'index_users_on_reset_password_token', unique: true + end + + add_foreign_key 'model_versions', 'models' + add_foreign_key 'prompts', 'users' + add_foreign_key 'solid_queue_blocked_executions', 'solid_queue_jobs', column: 'job_id', on_delete: :cascade + add_foreign_key 'solid_queue_claimed_executions', 'solid_queue_jobs', column: 'job_id', on_delete: :cascade + add_foreign_key 'solid_queue_failed_executions', 'solid_queue_jobs', column: 'job_id', on_delete: :cascade + add_foreign_key 'solid_queue_ready_executions', 'solid_queue_jobs', column: 'job_id', on_delete: :cascade + add_foreign_key 'solid_queue_recurring_executions', 'solid_queue_jobs', column: 'job_id', on_delete: :cascade + add_foreign_key 'solid_queue_scheduled_executions', 'solid_queue_jobs', column: 'job_id', on_delete: :cascade + add_foreign_key 'test_results', 'model_versions' + add_foreign_key 'test_results', 'prompts' end diff --git a/db/seeds.rb b/db/seeds.rb index 4fbd6ed..0f16211 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This file should ensure the existence of records required to run the application in every environment (production, # development, test). The code here should be idempotent so that it can be executed at any point in every environment. # The data can then be loaded with the bin/rails db:seed command (or created alongside the database with db:setup). diff --git a/docker-compose.yml b/docker-compose.yml index 7dbeae5..5368769 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -18,7 +18,6 @@ services: BUNDLE_DEPLOYMENT: "1" BUNDLE_PATH: /usr/local/bundle BUNDLE_WITHOUT: development - SECRET_KEY_BASE: a20aff0f4264e4896b81c5377418b46f104fdb209ded3d58b521abf871853adcabd0d904c569def108a35345e29b5e1affad36cb6619f0b51738f7de5d59b528 DATABASE_PORT: 5432 DATABASE_HOST: postgres DATABASE_USERNAME: postgres diff --git a/public/favicon.ico b/public/favicon.ico index e69de29..a2788ca 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/logo.png b/public/logo.png new file mode 100644 index 0000000..a2788ca Binary files /dev/null and b/public/logo.png differ diff --git a/spec/controllers/model_versions_controller_spec.rb b/spec/controllers/model_versions_controller_spec.rb new file mode 100644 index 0000000..4f86d6d --- /dev/null +++ b/spec/controllers/model_versions_controller_spec.rb @@ -0,0 +1,138 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe ModelVersionsController, type: :controller do + let(:user) { create(:user) } + let(:model) { create(:model, user:) } + let(:model_version) { create(:model_version, model:) } + + before do + sign_in user + end + + describe 'GET #index' do + it 'assigns @model_versions' do + get :index, params: { model_id: model.id } + expect(assigns(:model_versions)).to eq(model.model_versions) + end + + it 'renders the index template' do + get :index, params: { model_id: model.id } + expect(response).to render_template(:index) + end + end + + describe 'GET #show' do + it 'assigns @model_version' do + get :show, params: { model_id: model.id, id: model_version.id } + expect(assigns(:model_version)).to eq(model_version) + end + + it 'renders the show template' do + get :show, params: { model_id: model.id, id: model_version.id } + expect(response).to render_template(:show) + end + end + + describe 'GET #new' do + it 'assigns a new model version' do + get :new, params: { model_id: model.id } + expect(assigns(:model_version)).to be_a_new(ModelVersion) + end + + it 'renders the new template' do + get :new, params: { model_id: model.id } + expect(response).to render_template(:new) + end + end + + describe 'GET #edit' do + it 'assigns @model_version' do + get :edit, params: { model_id: model.id, id: model_version.id } + expect(assigns(:model_version)).to eq(model_version) + end + + it 'renders the edit template' do + get :edit, params: { model_id: model.id, id: model_version.id } + expect(response).to render_template(:edit) + end + end + + describe 'POST #create' do + context 'with valid params' do + let(:valid_params) { { model_version: attributes_for(:model_version) } } + + it 'creates a new model version' do + expect do + post :create, params: { model_id: model.id, model_version: valid_params[:model_version] } + end.to change(ModelVersion, :count).by(1) + end + + it 'redirects to the created model version' do + post :create, params: { model_id: model.id, model_version: valid_params[:model_version] } + expect(response).to redirect_to(model_model_version_url(model, ModelVersion.last)) + end + end + + context 'with invalid params' do + let(:invalid_params) { { model_version: attributes_for(:model_version, configuration: 'invalid json') } } + + it 'does not create a new model version' do + expect do + post :create, params: { model_id: model.id, model_version: invalid_params[:model_version] } + end.to_not change(ModelVersion, :count) + end + + it 'renders the new template' do + post :create, params: { model_id: model.id, model_version: invalid_params[:model_version] } + expect(response).to render_template(:new) + end + end + end + + describe 'PATCH #update' do + context 'with valid params' do + let(:new_attributes) { { description: 'Updated Description' } } + + it 'updates the requested model version' do + patch :update, params: { model_id: model.id, id: model_version.id, model_version: new_attributes } + model_version.reload + expect(model_version.description).to eq('Updated Description') + end + + it 'redirects to the model version' do + patch :update, params: { model_id: model.id, id: model_version.id, model_version: new_attributes } + expect(response).to redirect_to(model_model_version_url(model, model_version)) + end + end + + context 'with invalid params' do + let(:invalid_attributes) { { configuration: 'invalid json' } } + + it 'does not update the model version' do + patch :update, params: { model_id: model.id, id: model_version.id, model_version: invalid_attributes } + expect(model_version.reload.configuration).to_not be_nil + end + + it 'renders the edit template' do + patch :update, params: { model_id: model.id, id: model_version.id, model_version: invalid_attributes } + expect(response).to render_template(:edit) + end + end + end + + describe 'DELETE #destroy' do + it 'destroys the requested model version' do + model_version # create the model version before the expect block + expect do + delete :destroy, params: { model_id: model.id, id: model_version.id } + end.to change(ModelVersion, :count).by(-1) + end + + it 'redirects to the model versions list' do + delete :destroy, params: { model_id: model.id, id: model_version.id } + expect(response).to redirect_to(model_model_versions_url(model)) + end + end +end diff --git a/spec/controllers/models_controller_spec.rb b/spec/controllers/models_controller_spec.rb new file mode 100644 index 0000000..f7a055f --- /dev/null +++ b/spec/controllers/models_controller_spec.rb @@ -0,0 +1,109 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe ModelsController, type: :controller do + let(:user) { create(:user) } + let(:model) { create(:model, user:) } + + before do + sign_in user + end + + describe 'GET #index' do + it 'assigns @models' do + get :index + expect(assigns(:models)).to eq(user.models) + end + + it 'renders the index template' do + get :index + expect(response).to render_template(:index) + end + end + + describe 'GET #show' do + it 'assigns @model and @model_versions' do + get :show, params: { id: model.id } + expect(assigns(:model)).to eq(model) + expect(assigns(:model_versions)).to eq(model.model_versions) + end + + it 'renders the show template' do + get :show, params: { id: model.id } + expect(response).to render_template(:show) + end + end + + describe 'GET #new' do + it 'assigns a new model' do + get :new + expect(assigns(:model)).to be_a_new(Model) + end + + it 'renders the new template' do + get :new + expect(response).to render_template(:new) + end + end + + describe 'GET #edit' do + it 'assigns @model' do + get :edit, params: { id: model.id } + expect(assigns(:model)).to eq(model) + end + + it 'renders the edit template' do + get :edit, params: { id: model.id } + expect(response).to render_template(:edit) + end + end + + describe 'POST #create' do + context 'with valid params' do + let(:valid_params) { { model: attributes_for(:model) } } + + it 'creates a new model' do + expect do + post :create, params: valid_params + end.to change(Model, :count).by(1) + end + + it 'redirects to the created model' do + post :create, params: valid_params + expect(response).to redirect_to(Model.last) + end + end + end + + describe 'PATCH #update' do + context 'with valid params' do + let(:new_attributes) { { name: 'Updated Name' } } + + it 'updates the requested model' do + patch :update, params: { id: model.id, model: new_attributes } + model.reload + expect(model.name).to eq('Updated Name') + end + + it 'redirects to the model' do + patch :update, params: { id: model.id, model: new_attributes } + expect(response).to redirect_to(model) + end + end + end + + describe 'DELETE #destroy' do + it 'destroys the requested model' do + model # create the model before the expect block + expect do + delete :destroy, params: { id: model.id } + end.to change(Model, :count).by(-1) + end + + it 'redirects to the models list' do + delete :destroy, params: { id: model.id } + expect(response).to redirect_to(models_url) + end + end +end diff --git a/spec/controllers/prompts_controller_spec.rb b/spec/controllers/prompts_controller_spec.rb new file mode 100644 index 0000000..4f5e9e2 --- /dev/null +++ b/spec/controllers/prompts_controller_spec.rb @@ -0,0 +1,83 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe PromptsController, type: :controller do + let(:user) { create(:user) } + let(:prompt) { create(:prompt, user:) } + let(:model) { create(:model, user:) } + let(:model_version) { create(:model_version, model:) } + let!(:test_result) { create(:test_result, prompt:, model_version:) } + + before do + sign_in user + end + + describe 'GET #index' do + it 'assigns @prompts' do + get :index + expect(assigns(:prompts)).to eq(user.prompts) + end + + it 'renders the index template' do + get :index + expect(response).to render_template(:index) + end + end + + describe 'GET #show' do + it 'assigns @prompt and @test_results' do + get :show, params: { id: prompt.id } + expect(assigns(:prompt)).to eq(prompt) + expect(assigns(:test_results)).to eq([test_result]) + end + + it 'renders the show template' do + get :show, params: { id: prompt.id } + expect(response).to render_template(:show) + end + end + + describe 'GET #new' do + it 'assigns a new prompt' do + get :new + expect(assigns(:prompt)).to be_a_new(Prompt) + end + + it 'renders the new template' do + get :new + expect(response).to render_template(:new) + end + end + + describe 'POST #create' do + context 'with valid params' do + let(:valid_params) { { prompt: attributes_for(:prompt) } } + + it 'creates a new prompt' do + expect do + post :create, params: valid_params + end.to change(Prompt, :count).by(1) + end + + it 'redirects to the created prompt' do + post :create, params: valid_params + expect(response).to redirect_to(prompt_url(Prompt.last)) + end + end + end + + describe 'DELETE #destroy' do + it 'destroys the requested prompt' do + prompt # create the prompt before the expect block + expect do + delete :destroy, params: { id: prompt.id } + end.to change(Prompt, :count).by(-1) + end + + it 'redirects to the prompts list' do + delete :destroy, params: { id: prompt.id } + expect(response).to redirect_to(prompts_url) + end + end +end diff --git a/spec/controllers/test_results_controller_spec.rb b/spec/controllers/test_results_controller_spec.rb new file mode 100644 index 0000000..a4dfc37 --- /dev/null +++ b/spec/controllers/test_results_controller_spec.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe TestResultsController, type: :controller do + let(:user) { create(:user) } + let(:model) { create(:model, user:) } + let(:model_version) { create(:model_version, model:) } + let(:prompt) { create(:prompt, user:) } + let!(:test_result) { create(:test_result, model_version:, prompt:) } + + before do + sign_in user + end + + describe 'PATCH #update' do + context 'with valid params' do + it 'updates the test result' do + patch :update, params: { id: test_result.id, test_result: { rating: 4 } }, format: :json + expect(response).to have_http_status(:ok) + expect(JSON.parse(response.body)).to eq({ 'success' => true, 'rating' => 4 }) + test_result.reload + expect(test_result.rating).to eq(4) + end + end + end + + describe 'GET #index' do + let(:model_2) { create(:model, user:) } + let(:model_version_2) { create(:model_version, model: model_2) } + let(:prompt_2) { create(:prompt, user:) } + let!(:test_result_2) { create(:test_result, model_version: model_version_2, prompt: prompt_2) } + + it 'returns all test_results' do + get :index + expect(response).to have_http_status(:ok) + expect(assigns(:test_results)).to match_array([test_result, test_result_2]) + end + + it 'filters test results by model_version_id and prompt_id' do + get :index, params: { model_version_id: model_version.id, prompt_id: prompt.id } + expect(response).to have_http_status(:ok) + expect(assigns(:test_results)).to match_array([test_result]) + end + end + + describe 'GET #show' do + it 'assigns @test_result' do + get :show, params: { id: test_result.id } + expect(response).to have_http_status(:ok) + expect(assigns(:test_result)).to eq(test_result) + end + end +end diff --git a/spec/controllers/test_runs_controller_spec.rb b/spec/controllers/test_runs_controller_spec.rb new file mode 100644 index 0000000..e5eec5b --- /dev/null +++ b/spec/controllers/test_runs_controller_spec.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe TestRunsController, type: :controller do + let(:user) { create(:user) } + let(:prompt) { create(:prompt, user:) } + let(:model_1) { create(:model, user:) } + let(:model_2) { create(:model, user:) } + let(:model_version1) { create(:model_version, model: model_1) } + let(:model_version2) { create(:model_version, model: model_2) } + + before do + sign_in user + end + + describe 'GET #new' do + it 'assigns @model_versions' do + get :new, params: { prompt_id: prompt.id } + expect(response).to have_http_status(:ok) + expect(assigns(:model_versions)).to match_array(user.model_versions.includes(:model)) + end + end + + describe 'POST #create' do + it 'creates test run jobs for selected model versions' do + model_version_ids = [model_version1.id, model_version2.id] + post :create, params: { prompt_id: prompt.id, model_version_ids: } + + expect(SolidQueue::Job).to receive(:enqueue).exactly(model_version_ids.size).times do |job_instance| + expect(job_instance.class).to eq(TestRunJob) + expect(job_instance.arguments).to include(model_version_ids.shift.to_s) + expect(job_instance.arguments).to include(prompt.id) + end + + post :create, params: { prompt_id: prompt.id, model_version_ids: } + + expect(response).to redirect_to(prompt_path(prompt)) + end + end +end diff --git a/spec/factories/model_versions.rb b/spec/factories/model_versions.rb new file mode 100644 index 0000000..18b9bf6 --- /dev/null +++ b/spec/factories/model_versions.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :model_version do + configuration { {} } + description { 'Default Description' } + built_on { Date.today } + build_name { 'Default Build' } + association :model, factory: :model + end +end diff --git a/spec/factories/models.rb b/spec/factories/models.rb new file mode 100644 index 0000000..359e291 --- /dev/null +++ b/spec/factories/models.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :model do + name { 'Test Model' } + url { 'http://example.com' } + executor_type { 'base' } + api_key { 'apikey' } + association :user + end +end diff --git a/spec/factories/promts.rb b/spec/factories/promts.rb new file mode 100644 index 0000000..703fe35 --- /dev/null +++ b/spec/factories/promts.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :prompt do + value { 'Default Value' } + name { 'Default Name' } + association :user, factory: :user + end +end diff --git a/spec/factories/test_results.rb b/spec/factories/test_results.rb new file mode 100644 index 0000000..59b2855 --- /dev/null +++ b/spec/factories/test_results.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :test_result do + association :model_version, factory: :model_version + association :prompt, factory: :prompt + end +end diff --git a/spec/factories/users.rb b/spec/factories/users.rb new file mode 100644 index 0000000..8b9045d --- /dev/null +++ b/spec/factories/users.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :user do + sequence(:email) { |n| "user#{n}@example.com" } + password { 'password' } + end +end diff --git a/spec/jobs/test_run_job_spec.rb b/spec/jobs/test_run_job_spec.rb new file mode 100644 index 0000000..3fb68af --- /dev/null +++ b/spec/jobs/test_run_job_spec.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe TestRunJob, type: :job do + let(:user) { create(:user) } + let(:model) { create(:model, user:) } + let(:model_version) { create(:model_version, model:) } + let(:prompt) { create(:prompt, user:) } + + describe '#perform' do + it 'creates a TestResult and updates it with model execution result' do + expect(ModelVersion).to receive(:find).with(model_version.id).and_return(model_version) + expect(Prompt).to receive(:find).with(prompt.id).and_return(prompt) + + model_executor_instance = instance_double(ModelExecutor) + allow(ModelExecutor).to receive(:new).with(model_version).and_return(model_executor_instance) + allow(model_executor_instance).to receive(:call).with(prompt.value).and_return({ accuracy: 0.95 }) + + expect(TestResult).to receive(:create).with(model_version:, prompt:).and_call_original + + expect_any_instance_of(TestResult).to receive(:update).with({ accuracy: 0.95, time: instance_of(Float) }) + + TestRunJob.perform_now(model_version.id, prompt.id) + end + end +end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb new file mode 100644 index 0000000..48e98bd --- /dev/null +++ b/spec/rails_helper.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +# This file is copied to spec/ when you run 'rails generate rspec:install' +require 'spec_helper' +ENV['RAILS_ENV'] ||= 'test' +require_relative '../config/environment' +# Prevent database truncation if the environment is production +abort('The Rails environment is running in production mode!') if Rails.env.production? +require 'rspec/rails' +# Add additional requires below this line. Rails is not loaded until this point! + +# Requires supporting ruby files with custom matchers and macros, etc, in +# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are +# run as spec files by default. This means that files in spec/support that end +# in _spec.rb will both be required and run as specs, causing the specs to be +# run twice. It is recommended that you do not name files matching this glob to +# end with _spec.rb. You can configure this pattern with the --pattern +# option on the command line or in ~/.rspec, .rspec or `.rspec-local`. +# +# The following line is provided for convenience purposes. It has the downside +# of increasing the boot-up time by auto-requiring all files in the support +# directory. Alternatively, in the individual `*_spec.rb` files, manually +# require only the support files necessary. +# +# Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f } + +# Checks for pending migrations and applies them before tests are run. +# If you are not using ActiveRecord, you can remove these lines. +begin + ActiveRecord::Migration.maintain_test_schema! +rescue ActiveRecord::PendingMigrationError => e + puts e.to_s.strip + exit 1 +end +RSpec.configure do |config| + # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures + config.fixture_path = "#{::Rails.root}/spec/fixtures" + + config.include Devise::Test::ControllerHelpers, type: :controller + config.include FactoryBot::Syntax::Methods + + # If you're not using ActiveRecord, or you'd prefer not to run each of your + # examples within a transaction, remove the following line or assign false + # instead of true. + config.use_transactional_fixtures = true + + config.render_views = true + + # You can uncomment this line to turn off ActiveRecord support entirely. + # config.use_active_record = false + + # RSpec Rails can automatically mix in different behaviours to your tests + # based on their file location, for example enabling you to call `get` and + # `post` in specs under `spec/controllers`. + # + # You can disable this behaviour by removing the line below, and instead + # explicitly tag your specs with their type, e.g.: + # + # RSpec.describe UsersController, type: :controller do + # # ... + # end + # + # The different available types are documented in the features, such as in + # https://relishapp.com/rspec/rspec-rails/docs + config.infer_spec_type_from_file_location! + + # Filter lines from Rails gems in backtraces. + config.filter_rails_from_backtrace! + # arbitrary gems may also be filtered via: + # config.filter_gems_from_backtrace("gem name") +end diff --git a/spec/services/executors/base_spec.rb b/spec/services/executors/base_spec.rb new file mode 100644 index 0000000..8c58953 --- /dev/null +++ b/spec/services/executors/base_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require 'rails_helper' +require 'webmock/rspec' + +RSpec.describe Executors::Base do + describe '#call' do + let(:model) { create(:model, url: 'http://example.com/model_endpoint') } + let(:model_version) { create(:model_version, model:, configuration: { param: 'value' }) } + let(:executor) { Executors::Base.new(model_version) } + let(:prompt) { 'Test prompt' } + + context 'when HTTP request is successful' do + before do + stub_request(:post, 'http://example.com/model_endpoint') + .with( + body: '{"param":"value","prompt":"This is a conversation between User and OLMo\\u003c|endoftext|\\u003e\\n\\nUser:\\nTest prompt\\n OLMo: "}', + headers: { + 'Accept' => '*/*', + 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', + 'Content-Type' => 'application/json', + 'User-Agent' => 'Ruby' + } + ) + .to_return(status: 200, body: '{"response": "Test response"}', headers: {}) + end + + it 'returns a completed status with result on successful response' do + expect(executor.call(prompt)).to eq({ status: :completed, result: '{"response": "Test response"}' }) + end + end + + context 'when HTTP request fails' do + before do + stub_request(:post, 'http://example.com/model_endpoint') + .to_return(status: 500, body: 'Internal Server Error') + end + + it 'returns a failed status' do + expect(executor.call(prompt)).to eq({ status: :failed, result: 'Internal Server Error' }) + end + end + + context 'when HTTP request times out' do + before do + stub_request(:post, 'http://example.com/model_endpoint') + .to_timeout + end + + it 'returns a failed status' do + expect(executor.call(prompt)).to eq({ status: :failed }) + end + end + end +end diff --git a/spec/services/executors/openai_spec.rb b/spec/services/executors/openai_spec.rb new file mode 100644 index 0000000..f8f3cf5 --- /dev/null +++ b/spec/services/executors/openai_spec.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Executors::Openai do + let(:model) { create(:model, api_key: 'test_api_key') } + let(:model_version) { create(:model_version, model:, configuration: { param: 'value' }) } + let(:executor) { Executors::Openai.new(model_version) } + let(:prompt) { 'Test prompt' } + + describe '#initialize' do + it 'initializes with an OpenAI client' do + expect(executor.instance_variable_get(:@client)).to be_an_instance_of(OpenAI::Client) + end + end + + describe '#call' do + context 'when OpenAI API call is successful' do + before do + allow_any_instance_of(OpenAI::Client).to receive(:chat).and_return({ response: 'Chat response' }) + end + + it 'returns a completed status with result on successful response' do + expect(executor.call(prompt)).to eq({ status: :completed, result: '{"response":"Chat response"}' }) + end + end + + context 'when OpenAI API call raises an error' do + before do + allow_any_instance_of(OpenAI::Client).to receive(:chat).and_raise(Faraday::ClientError.new('API error', + body: { error_message: 'API error' })) + end + + it 'returns a failed status with error result' do + expect(executor.call(prompt)).to eq({ status: :failed, result: '{"error_message":"API error"}' }) + end + end + end +end diff --git a/spec/services/model_executor_spec.rb b/spec/services/model_executor_spec.rb new file mode 100644 index 0000000..7ec678c --- /dev/null +++ b/spec/services/model_executor_spec.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe ModelExecutor do + describe '#call' do + context "when executor type is 'openai'" do + let(:model) { create(:model, executor_type: 'openai') } + let(:model_version) { create(:model_version, model:) } + let(:prompt) { 'Test prompt' } + let(:executor_instance) { instance_double(Executors::Openai) } + + before do + allow(Executors::Openai).to receive(:new).and_return(executor_instance) + allow(executor_instance).to receive(:call).with(prompt).and_return({ result: 'Test result' }) + end + + it 'calls the OpenAI executor' do + model_executor = ModelExecutor.new(model_version) + expect(model_executor.call(prompt)).to eq({ result: 'Test result' }) + end + end + + context "when executor type is 'base'" do + let(:model) { create(:model, executor_type: 'base') } + let(:model_version) { create(:model_version, model:) } + let(:prompt) { 'Test prompt' } + let(:executor_instance) { instance_double(Executors::Base) } + + before do + allow(Executors::Base).to receive(:new).and_return(executor_instance) + allow(executor_instance).to receive(:call).with(prompt).and_return({ result: 'Test result' }) + end + + it 'calls the default executor' do + model_executor = ModelExecutor.new(model_version) + expect(model_executor.call(prompt)).to eq({ result: 'Test result' }) + end + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..409c64b --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,94 @@ +# frozen_string_literal: true + +# This file was generated by the `rails generate rspec:install` command. Conventionally, all +# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. +# The generated `.rspec` file contains `--require spec_helper` which will cause +# this file to always be loaded, without a need to explicitly require it in any +# files. +# +# Given that it is always loaded, you are encouraged to keep this file as +# light-weight as possible. Requiring heavyweight dependencies from this file +# will add to the boot time of your test suite on EVERY test run, even for an +# individual file that may not need all of that loaded. Instead, consider making +# a separate helper file that requires the additional dependencies and performs +# the additional setup, and require it from the spec files that actually need +# it. +# +# See https://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration +RSpec.configure do |config| + # rspec-expectations config goes here. You can use an alternate + # assertion/expectation library such as wrong or the stdlib/minitest + # assertions if you prefer. + config.expect_with :rspec do |expectations| + # This option will default to `true` in RSpec 4. It makes the `description` + # and `failure_message` of custom matchers include text for helper methods + # defined using `chain`, e.g.: + # be_bigger_than(2).and_smaller_than(4).description + # # => "be bigger than 2 and smaller than 4" + # ...rather than: + # # => "be bigger than 2" + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + # rspec-mocks config goes here. You can use an alternate test double + # library (such as bogus or mocha) by changing the `mock_with` option here. + config.mock_with :rspec do |mocks| + # Prevents you from mocking or stubbing a method that does not exist on + # a real object. This is generally recommended, and will default to + # `true` in RSpec 4. + mocks.verify_partial_doubles = true + end + + # This option will default to `:apply_to_host_groups` in RSpec 4 (and will + # have no way to turn it off -- the option exists only for backwards + # compatibility in RSpec 3). It causes shared context metadata to be + # inherited by the metadata hash of host groups and examples, rather than + # triggering implicit auto-inclusion in groups with matching metadata. + config.shared_context_metadata_behavior = :apply_to_host_groups + + # The settings below are suggested to provide a good initial experience + # with RSpec, but feel free to customize to your heart's content. + # # This allows you to limit a spec run to individual examples or groups + # # you care about by tagging them with `:focus` metadata. When nothing + # # is tagged with `:focus`, all examples get run. RSpec also provides + # # aliases for `it`, `describe`, and `context` that include `:focus` + # # metadata: `fit`, `fdescribe` and `fcontext`, respectively. + # config.filter_run_when_matching :focus + # + # # Allows RSpec to persist some state between runs in order to support + # # the `--only-failures` and `--next-failure` CLI options. We recommend + # # you configure your source control system to ignore this file. + # config.example_status_persistence_file_path = "spec/examples.txt" + # + # # Limits the available syntax to the non-monkey patched syntax that is + # # recommended. For more details, see: + # # https://rspec.info/features/3-12/rspec-core/configuration/zero-monkey-patching-mode/ + # config.disable_monkey_patching! + # + # # Many RSpec users commonly either run the entire suite or an individual + # # file, and it's useful to allow more verbose output when running an + # # individual spec file. + # if config.files_to_run.one? + # # Use the documentation formatter for detailed output, + # # unless a formatter has already been configured + # # (e.g. via a command-line flag). + # config.default_formatter = "doc" + # end + # + # # Print the 10 slowest examples and example groups at the + # # end of the spec run, to help surface which specs are running + # # particularly slow. + # config.profile_examples = 10 + # + # # Run specs in random order to surface order dependencies. If you find an + # # order dependency and want to debug it, you can fix the order by providing + # # the seed, which is printed after each run. + # # --seed 1234 + # config.order = :random + # + # # Seed global randomization in this process using the `--seed` CLI option. + # # Setting this allows you to use `--seed` to deterministically reproduce + # # test failures related to randomization by passing the same `--seed` value + # # as the one that triggered the failure. + # Kernel.srand config.seed +end diff --git a/spec/support/database_cleaner.rb b/spec/support/database_cleaner.rb new file mode 100644 index 0000000..48fe7d6 --- /dev/null +++ b/spec/support/database_cleaner.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +RSpec.configure do |config| + config.before(:suite) do + DatabaseCleaner.clean_with(:truncation) + end + + config.before(:each) do + DatabaseCleaner.strategy = :transaction + end + + config.before(:each, js: true) do + DatabaseCleaner.strategy = :truncation + end + + config.before(:each) do + DatabaseCleaner.start + end + + config.after(:each) do + DatabaseCleaner.clean + end +end diff --git a/test/application_system_test_case.rb b/test/application_system_test_case.rb deleted file mode 100644 index b2170cb..0000000 --- a/test/application_system_test_case.rb +++ /dev/null @@ -1,7 +0,0 @@ -require "test_helper" - -class ApplicationSystemTestCase < ActionDispatch::SystemTestCase - driven_by :selenium, using: :chrome, screen_size: [1400, 1400] - - include Devise::Test::IntegrationHelpers -end diff --git a/test/channels/application_cable/connection_test.rb b/test/channels/application_cable/connection_test.rb deleted file mode 100644 index 6340bf9..0000000 --- a/test/channels/application_cable/connection_test.rb +++ /dev/null @@ -1,13 +0,0 @@ -require "test_helper" - -module ApplicationCable - class ConnectionTest < ActionCable::Connection::TestCase - # test "connects with cookies" do - # cookies.signed[:user_id] = 42 - # - # connect - # - # assert_equal connection.user_id, "42" - # end - end -end diff --git a/test/controllers/.keep b/test/controllers/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/test/controllers/chats_controller_test.rb b/test/controllers/chats_controller_test.rb deleted file mode 100644 index 18da30a..0000000 --- a/test/controllers/chats_controller_test.rb +++ /dev/null @@ -1,50 +0,0 @@ -require "test_helper" - -class ChatsControllerTest < ActionDispatch::IntegrationTest - setup do - sign_in users(:one) - - @chat = chats(:one) - end - - test "should get index" do - get chats_url - assert_response :success - end - - test "should get new" do - get new_chat_url - assert_response :success - end - - test "should create chat" do - assert_difference("Chat.count") do - post chats_url, params: { chat: { title: @chat.title } } - end - - assert_redirected_to chat_url(Chat.last) - end - - test "should show chat" do - get chat_url(@chat) - assert_response :success - end - - test "should get edit" do - get edit_chat_url(@chat) - assert_response :success - end - - test "should update chat" do - patch chat_url(@chat), params: { chat: { title: @chat.title } } - assert_redirected_to chat_url(@chat) - end - - test "should destroy chat" do - assert_difference("Chat.count", -1) do - delete chat_url(@chat) - end - - assert_redirected_to chats_url - end -end diff --git a/test/controllers/messages_controller_test.rb b/test/controllers/messages_controller_test.rb deleted file mode 100644 index f1da745..0000000 --- a/test/controllers/messages_controller_test.rb +++ /dev/null @@ -1,51 +0,0 @@ -require "test_helper" - -class MessagesControllerTest < ActionDispatch::IntegrationTest - setup do - sign_in users(:one) - - @message = messages(:one) - @chat = @message.chat - end - - test "should get index" do - get chat_messages_url(@chat) - assert_response :success - end - - test "should get new" do - get new_chat_message_url(@chat) - assert_response :success - end - - test "should create message" do - assert_difference("Message.count") do - post chat_messages_url(@chat), params: { message: { body: @message.body } } - end - - assert_redirected_to chat_message_url(@chat, Message.last) - end - - test "should show message" do - get chat_message_url(@chat, @message) - assert_response :success - end - - test "should get edit" do - get edit_chat_message_url(@chat, @message) - assert_response :success - end - - test "should update message" do - patch chat_message_url(@chat, @message), params: { message: { body: @message.body } } - assert_redirected_to chat_message_url(@chat, @message) - end - - test "should destroy message" do - assert_difference("Message.count", -1) do - delete chat_message_url(@chat, @message) - end - - assert_redirected_to chat_messages_url(@chat) - end -end diff --git a/test/controllers/model_versions_controller_test.rb b/test/controllers/model_versions_controller_test.rb deleted file mode 100644 index 9f34b9b..0000000 --- a/test/controllers/model_versions_controller_test.rb +++ /dev/null @@ -1,51 +0,0 @@ -require "test_helper" - -class ModelVersionsControllerTest < ActionDispatch::IntegrationTest - setup do - sign_in users(:one) - - @model = models(:one) - @model_version = model_versions(:one) - end - - test "should get index" do - get model_model_versions_url(@model) - assert_response :success - end - - test "should get new" do - get new_model_model_version_url(@model) - assert_response :success - end - - test "should create model_version" do - assert_difference("ModelVersion.count") do - post model_model_versions_url(@model), params: { model_version: { build_name: @model_version.build_name, built_on: @model_version.built_on, configuration: @model_version.configuration, description: @model_version.description, model_id: @model_version.model_id } } - end - - assert_redirected_to model_model_version_url(@model, ModelVersion.last) - end - - test "should show model_version" do - get model_model_version_url(@model, @model_version) - assert_response :success - end - - test "should get edit" do - get edit_model_model_version_url(@model, @model_version) - assert_response :success - end - - test "should update model_version" do - patch model_model_version_url(@model, @model_version), params: { model_version: { build_name: @model_version.build_name, built_on: @model_version.built_on, configuration: @model_version.configuration, description: @model_version.description, model_id: @model_version.model_id } } - assert_redirected_to model_model_version_url(@model, @model_version) - end - - test "should destroy model_version" do - assert_difference("ModelVersion.count", -1) do - delete model_model_version_url(@model, @model_version) - end - - assert_redirected_to model_model_versions_url(@model) - end -end diff --git a/test/controllers/models_controller_test.rb b/test/controllers/models_controller_test.rb deleted file mode 100644 index f4f3d54..0000000 --- a/test/controllers/models_controller_test.rb +++ /dev/null @@ -1,50 +0,0 @@ -require "test_helper" - -class ModelsControllerTest < ActionDispatch::IntegrationTest - setup do - sign_in users(:one) - - @model = models(:one) - end - - test "should get index" do - get models_url - assert_response :success - end - - test "should get new" do - get new_model_url - assert_response :success - end - - test "should create model" do - assert_difference("Model.count") do - post models_url, params: { model: { name: @model.name, url: @model.url } } - end - - assert_redirected_to model_url(Model.last) - end - - test "should show model" do - get model_url(@model) - assert_response :success - end - - test "should get edit" do - get edit_model_url(@model) - assert_response :success - end - - test "should update model" do - patch model_url(@model), params: { model: { name: @model.name, url: @model.url } } - assert_redirected_to model_url(@model) - end - - test "should destroy model" do - assert_difference("Model.count", -1) do - delete model_url(@model) - end - - assert_redirected_to models_url - end -end diff --git a/test/controllers/participants_controller_test.rb b/test/controllers/participants_controller_test.rb deleted file mode 100644 index dedc350..0000000 --- a/test/controllers/participants_controller_test.rb +++ /dev/null @@ -1,50 +0,0 @@ -require "test_helper" - -class ParticipantsControllerTest < ActionDispatch::IntegrationTest - setup do - sign_in users(:one) - - @participant = participants(:one) - end - - test "should get index" do - get participants_url - assert_response :success - end - - test "should get new" do - get new_participant_url - assert_response :success - end - - test "should create participant" do - assert_difference("Participant.count") do - post participants_url, params: { participant: { configuration: @participant.configuration, implementor: @participant.implementor, name: @participant.name } } - end - - assert_redirected_to participant_url(Participant.last) - end - - test "should show participant" do - get participant_url(@participant) - assert_response :success - end - - test "should get edit" do - get edit_participant_url(@participant) - assert_response :success - end - - test "should update participant" do - patch participant_url(@participant), params: { participant: { configuration: @participant.configuration, implementor: @participant.implementor, name: @participant.name } } - assert_redirected_to participant_url(@participant) - end - - test "should destroy participant" do - assert_difference("Participant.count", -1) do - delete participant_url(@participant) - end - - assert_redirected_to participants_url - end -end diff --git a/test/controllers/prompts_controller_test.rb b/test/controllers/prompts_controller_test.rb deleted file mode 100644 index f8ee1fb..0000000 --- a/test/controllers/prompts_controller_test.rb +++ /dev/null @@ -1,50 +0,0 @@ -require "test_helper" - -class PromptsControllerTest < ActionDispatch::IntegrationTest - setup do - sign_in users(:one) - - @prompt = prompts(:one) - end - - test "should get index" do - get prompts_url - assert_response :success - end - - test "should get new" do - get new_prompt_url - assert_response :success - end - - test "should create prompt" do - assert_difference("Prompt.count") do - post prompts_url, params: { prompt: { name: @prompt.name, user_id: @prompt.user_id, value: @prompt.value } } - end - - assert_redirected_to prompt_url(Prompt.last) - end - - test "should show prompt" do - get prompt_url(@prompt) - assert_response :success - end - - test "should get edit" do - get edit_prompt_url(@prompt) - assert_response :success - end - - test "should update prompt" do - patch prompt_url(@prompt), params: { prompt: { name: @prompt.name, user_id: @prompt.user_id, value: @prompt.value } } - assert_redirected_to prompt_url(@prompt) - end - - test "should destroy prompt" do - assert_difference("Prompt.count", -1) do - delete prompt_url(@prompt) - end - - assert_redirected_to prompts_url - end -end diff --git a/test/controllers/test_runs_controller_test.rb b/test/controllers/test_runs_controller_test.rb deleted file mode 100644 index aa312b4..0000000 --- a/test/controllers/test_runs_controller_test.rb +++ /dev/null @@ -1,7 +0,0 @@ -require "test_helper" - -class TestRunsControllerTest < ActionDispatch::IntegrationTest - # test "the truth" do - # assert true - # end -end diff --git a/test/fixtures/chats.yml b/test/fixtures/chats.yml deleted file mode 100644 index 64d88ef..0000000 --- a/test/fixtures/chats.yml +++ /dev/null @@ -1,7 +0,0 @@ -# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html - -one: - title: MyString - -two: - title: MyString diff --git a/test/fixtures/files/.keep b/test/fixtures/files/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/test/fixtures/messages.yml b/test/fixtures/messages.yml deleted file mode 100644 index 30940a0..0000000 --- a/test/fixtures/messages.yml +++ /dev/null @@ -1,7 +0,0 @@ -one: - chat: one - body: MyText - -two: - chat: two - body: MyText diff --git a/test/fixtures/model_versions.yml b/test/fixtures/model_versions.yml deleted file mode 100644 index 48d664e..0000000 --- a/test/fixtures/model_versions.yml +++ /dev/null @@ -1,15 +0,0 @@ -# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html - -one: - model: one - configuration: - description: MyText - built_on: 2024-07-10 - build_name: MyString - -two: - model: two - configuration: - description: MyText - built_on: 2024-07-10 - build_name: MyString diff --git a/test/fixtures/models.yml b/test/fixtures/models.yml deleted file mode 100644 index e719590..0000000 --- a/test/fixtures/models.yml +++ /dev/null @@ -1,11 +0,0 @@ -# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html - -one: - name: MyString - url: MyString - user: one - -two: - name: MyString - url: MyString - user: one diff --git a/test/fixtures/participants.yml b/test/fixtures/participants.yml deleted file mode 100644 index 403a8fd..0000000 --- a/test/fixtures/participants.yml +++ /dev/null @@ -1,11 +0,0 @@ -# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html - -one: - name: MyString - configuration: MyText - implementor: MyString - -two: - name: MyString - configuration: MyText - implementor: MyString diff --git a/test/fixtures/prompts.yml b/test/fixtures/prompts.yml deleted file mode 100644 index 13fbe39..0000000 --- a/test/fixtures/prompts.yml +++ /dev/null @@ -1,11 +0,0 @@ -# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html - -one: - user: one - value: MyText - name: MyString - -two: - user: two - value: MyText - name: MyString diff --git a/test/fixtures/test_results.yml b/test/fixtures/test_results.yml deleted file mode 100644 index 76f5918..0000000 --- a/test/fixtures/test_results.yml +++ /dev/null @@ -1,15 +0,0 @@ -# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html - -one: - model_version: one - prompt: one - result: MyText - time: 1.5 - rating: 1 - -two: - model_version: two - prompt: two - result: MyText - time: 1.5 - rating: 1 diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml deleted file mode 100644 index 06e4e18..0000000 --- a/test/fixtures/users.yml +++ /dev/null @@ -1,10 +0,0 @@ -# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html - -# This model initially had no columns defined. If you add columns to the -# model remove the "{}" from the fixture names and add the columns immediately -# below each fixture, per the syntax in the comments below -# -one: - email: one@example.com -two: - email: two@example.com diff --git a/test/helpers/.keep b/test/helpers/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/test/integration/.keep b/test/integration/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/test/mailers/.keep b/test/mailers/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/test/models/.keep b/test/models/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/test/models/chat_test.rb b/test/models/chat_test.rb deleted file mode 100644 index 69b9d2c..0000000 --- a/test/models/chat_test.rb +++ /dev/null @@ -1,7 +0,0 @@ -require "test_helper" - -class ChatTest < ActiveSupport::TestCase - # test "the truth" do - # assert true - # end -end diff --git a/test/models/message_test.rb b/test/models/message_test.rb deleted file mode 100644 index dd77afb..0000000 --- a/test/models/message_test.rb +++ /dev/null @@ -1,31 +0,0 @@ -require "test_helper" - -class MessageTest < ActiveSupport::TestCase - test "belongs to a chat" do - message = messages(:one) - message.chat = nil - - refute message.valid? - assert_includes message.errors[:chat], "must exist" - end - - test "requires a body" do - message = Message.new body: nil - - refute message.valid? - assert_includes message.errors[:body], "can't be blank" - end - - test "defaults to being from a user" do - message = Message.new body: "A message with no 'from' specified." - - assert_equal "user", message.from - end - - test "from must be present" do - message = Message.new body: "A message with no 'from' specified.", from: "" - - refute message.valid? - assert_includes message.errors[:from], "can't be blank" - end -end diff --git a/test/models/model_test.rb b/test/models/model_test.rb deleted file mode 100644 index 6fd66ea..0000000 --- a/test/models/model_test.rb +++ /dev/null @@ -1,7 +0,0 @@ -require "test_helper" - -class ModelTest < ActiveSupport::TestCase - # test "the truth" do - # assert true - # end -end diff --git a/test/models/model_version_test.rb b/test/models/model_version_test.rb deleted file mode 100644 index 6c23819..0000000 --- a/test/models/model_version_test.rb +++ /dev/null @@ -1,7 +0,0 @@ -require "test_helper" - -class ModelVersionTest < ActiveSupport::TestCase - # test "the truth" do - # assert true - # end -end diff --git a/test/models/participant_test.rb b/test/models/participant_test.rb deleted file mode 100644 index c5b12d4..0000000 --- a/test/models/participant_test.rb +++ /dev/null @@ -1,11 +0,0 @@ -require "test_helper" - -class ParticipantTest < ActiveSupport::TestCase - test "a name is required" do - participant = participants(:one) - participant.name = "" - - refute participant.valid? - assert_includes participant.errors[:name], "can't be blank" - end -end diff --git a/test/models/prompt_test.rb b/test/models/prompt_test.rb deleted file mode 100644 index b426f5e..0000000 --- a/test/models/prompt_test.rb +++ /dev/null @@ -1,7 +0,0 @@ -require "test_helper" - -class PromptTest < ActiveSupport::TestCase - # test "the truth" do - # assert true - # end -end diff --git a/test/models/test_result_test.rb b/test/models/test_result_test.rb deleted file mode 100644 index 0deac4d..0000000 --- a/test/models/test_result_test.rb +++ /dev/null @@ -1,7 +0,0 @@ -require "test_helper" - -class TestResultTest < ActiveSupport::TestCase - # test "the truth" do - # assert true - # end -end diff --git a/test/models/user_test.rb b/test/models/user_test.rb deleted file mode 100644 index 5c07f49..0000000 --- a/test/models/user_test.rb +++ /dev/null @@ -1,7 +0,0 @@ -require "test_helper" - -class UserTest < ActiveSupport::TestCase - # test "the truth" do - # assert true - # end -end diff --git a/test/system/.keep b/test/system/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/test/system/chats_test.rb b/test/system/chats_test.rb deleted file mode 100644 index 7e83f0c..0000000 --- a/test/system/chats_test.rb +++ /dev/null @@ -1,43 +0,0 @@ -require "application_system_test_case" - -class ChatsTest < ApplicationSystemTestCase - setup do - @chat = chats(:one) - - sign_in users(:one) - end - - test "visiting the index" do - visit chats_url - assert_selector "h1", text: "Chats" - end - - test "should create chat" do - visit chats_url - click_on "New chat" - - fill_in "Title", with: @chat.title - click_on "Create Chat" - - assert_text "Chat was successfully created" - click_on "Back" - end - - test "should update Chat" do - visit chat_url(@chat) - click_on "Edit this chat", match: :first - - fill_in "Title", with: @chat.title - click_on "Update Chat" - - assert_text "Chat was successfully updated" - click_on "Back" - end - - test "should destroy Chat" do - visit chat_url(@chat) - click_on "Destroy this chat", match: :first - - assert_text "Chat was successfully destroyed" - end -end diff --git a/test/system/messages_test.rb b/test/system/messages_test.rb deleted file mode 100644 index 44ad540..0000000 --- a/test/system/messages_test.rb +++ /dev/null @@ -1,33 +0,0 @@ -require "application_system_test_case" - -class MessagesTest < ApplicationSystemTestCase - setup do - @message = messages(:one) - @chat = @message.chat - - sign_in users(:one) - end - - test "visiting the index" do - visit chat_messages_url(@chat) - assert_selector "h1", text: "Messages" - end - - test "should update Message" do - visit chat_message_url(@chat, @message) - click_on "Edit this message", match: :first - - fill_in "Body", with: @message.body - click_on "Update Message" - - assert_text "Message was successfully updated" - click_on "Back" - end - - test "should destroy Message" do - visit chat_message_url(@chat, @message) - click_on "Destroy this message", match: :first - - assert_text "Message was successfully destroyed" - end -end diff --git a/test/system/model_versions_test.rb b/test/system/model_versions_test.rb deleted file mode 100644 index 75d9fab..0000000 --- a/test/system/model_versions_test.rb +++ /dev/null @@ -1,49 +0,0 @@ -require "application_system_test_case" - -class ModelVersionsTest < ApplicationSystemTestCase - setup do - @model_version = model_versions(:one) - end - - test "visiting the index" do - visit model_versions_url - assert_selector "h1", text: "Model versions" - end - - test "should create model version" do - visit model_versions_url - click_on "New model version" - - fill_in "Build name", with: @model_version.build_name - fill_in "Built on", with: @model_version.built_on - fill_in "Configuration", with: @model_version.configuration - fill_in "Description", with: @model_version.description - fill_in "Model", with: @model_version.model_id - click_on "Create Model version" - - assert_text "Model version was successfully created" - click_on "Back" - end - - test "should update Model version" do - visit model_version_url(@model_version) - click_on "Edit this model version", match: :first - - fill_in "Build name", with: @model_version.build_name - fill_in "Built on", with: @model_version.built_on - fill_in "Configuration", with: @model_version.configuration - fill_in "Description", with: @model_version.description - fill_in "Model", with: @model_version.model_id - click_on "Update Model version" - - assert_text "Model version was successfully updated" - click_on "Back" - end - - test "should destroy Model version" do - visit model_version_url(@model_version) - click_on "Destroy this model version", match: :first - - assert_text "Model version was successfully destroyed" - end -end diff --git a/test/system/models_test.rb b/test/system/models_test.rb deleted file mode 100644 index c11225c..0000000 --- a/test/system/models_test.rb +++ /dev/null @@ -1,45 +0,0 @@ -require "application_system_test_case" - -class ModelsTest < ApplicationSystemTestCase - setup do - @model = models(:one) - end - - test "visiting the index" do - visit models_url - assert_selector "h1", text: "Models" - end - - test "should create model" do - visit models_url - click_on "New model" - - fill_in "Configuration", with: @model.configuration - fill_in "Name", with: @model.name - fill_in "Url", with: @model.url - click_on "Create Model" - - assert_text "Model was successfully created" - click_on "Back" - end - - test "should update Model" do - visit model_url(@model) - click_on "Edit this model", match: :first - - fill_in "Configuration", with: @model.configuration - fill_in "Name", with: @model.name - fill_in "Url", with: @model.url - click_on "Update Model" - - assert_text "Model was successfully updated" - click_on "Back" - end - - test "should destroy Model" do - visit model_url(@model) - click_on "Destroy this model", match: :first - - assert_text "Model was successfully destroyed" - end -end diff --git a/test/system/participants_test.rb b/test/system/participants_test.rb deleted file mode 100644 index 5366b1c..0000000 --- a/test/system/participants_test.rb +++ /dev/null @@ -1,47 +0,0 @@ -require "application_system_test_case" - -class ParticipantsTest < ApplicationSystemTestCase - setup do - sign_in users(:one) - - @participant = participants(:one) - end - - test "visiting the index" do - visit participants_url - assert_selector "h1", text: "Participants" - end - - test "should create participant" do - visit participants_url - click_on "New participant" - - fill_in "Configuration", with: @participant.configuration - fill_in "Implementor", with: @participant.implementor - fill_in "Name", with: @participant.name - click_on "Create Participant" - - assert_text "Participant was successfully created" - click_on "Back" - end - - test "should update Participant" do - visit participant_url(@participant) - click_on "Edit this participant", match: :first - - fill_in "Configuration", with: @participant.configuration - fill_in "Implementor", with: @participant.implementor - fill_in "Name", with: @participant.name - click_on "Update Participant" - - assert_text "Participant was successfully updated" - click_on "Back" - end - - test "should destroy Participant" do - visit participant_url(@participant) - click_on "Destroy this participant", match: :first - - assert_text "Participant was successfully destroyed" - end -end diff --git a/test/system/prompts_test.rb b/test/system/prompts_test.rb deleted file mode 100644 index 86d9474..0000000 --- a/test/system/prompts_test.rb +++ /dev/null @@ -1,45 +0,0 @@ -require "application_system_test_case" - -class PromptsTest < ApplicationSystemTestCase - setup do - @prompt = prompts(:one) - end - - test "visiting the index" do - visit prompts_url - assert_selector "h1", text: "Prompts" - end - - test "should create prompt" do - visit prompts_url - click_on "New prompt" - - fill_in "Name", with: @prompt.name - fill_in "User", with: @prompt.user_id - fill_in "Value", with: @prompt.value - click_on "Create Prompt" - - assert_text "Prompt was successfully created" - click_on "Back" - end - - test "should update Prompt" do - visit prompt_url(@prompt) - click_on "Edit this prompt", match: :first - - fill_in "Name", with: @prompt.name - fill_in "User", with: @prompt.user_id - fill_in "Value", with: @prompt.value - click_on "Update Prompt" - - assert_text "Prompt was successfully updated" - click_on "Back" - end - - test "should destroy Prompt" do - visit prompt_url(@prompt) - click_on "Destroy this prompt", match: :first - - assert_text "Prompt was successfully destroyed" - end -end diff --git a/test/test_helper.rb b/test/test_helper.rb deleted file mode 100644 index faa3a9e..0000000 --- a/test/test_helper.rb +++ /dev/null @@ -1,21 +0,0 @@ -ENV["RAILS_ENV"] ||= "test" -require_relative "../config/environment" -require "rails/test_help" - -module ActiveSupport - class TestCase - # Run tests in parallel with specified workers - parallelize(workers: :number_of_processors) - - # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. - fixtures :all - - # Add more helper methods to be used by all tests here... - end -end - -module ActionDispatch - class IntegrationTest - include Devise::Test::IntegrationHelpers - end -end