├── .dockerignore ├── .gitattributes ├── .gitignore ├── .idea ├── misc.xml ├── modules.xml └── vcs.xml ├── .ruby-version ├── Dockerfile ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── Procfile.dev ├── README.md ├── Rakefile ├── app ├── assets │ ├── builds │ │ └── .keep │ ├── config │ │ └── manifest.js │ ├── images │ │ ├── .keep │ │ ├── logo.png │ │ ├── logo_email.png │ │ ├── logo_white.png │ │ └── screenshot.png │ └── stylesheets │ │ ├── application.css │ │ └── application.tailwind.css ├── channels │ └── application_cable │ │ ├── channel.rb │ │ └── connection.rb ├── controllers │ ├── application_controller.rb │ ├── concerns │ │ └── .keep │ └── repos_controller.rb ├── helpers │ ├── application_helper.rb │ ├── heroicon_helper.rb │ └── repos_helper.rb ├── javascript │ ├── application.js │ └── controllers │ │ ├── application.js │ │ ├── hello_controller.js │ │ └── index.js ├── jobs │ ├── application_job.rb │ └── process_repo_job.rb ├── lib │ └── clone.rb ├── mailers │ ├── application_mailer.rb │ └── repo_mailer.rb ├── models │ ├── application_record.rb │ ├── concerns │ │ └── .keep │ └── repo.rb └── views │ ├── layouts │ ├── application.html.erb │ ├── mailer.html.erb │ └── mailer.text.erb │ ├── repo_mailer │ └── repo_created.html.erb │ └── repos │ ├── action.html.erb │ └── index.html.erb ├── bin ├── bundle ├── dev ├── docker-entrypoint ├── importmap ├── rails ├── rake └── setup ├── config.ru ├── config ├── application.rb ├── boot.rb ├── cable.yml ├── credentials.yml.enc ├── database.yml ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ └── test.rb ├── importmap.rb ├── initializers │ ├── assets.rb │ ├── content_security_policy.rb │ ├── filter_parameter_logging.rb │ ├── heroicon.rb │ ├── inflections.rb │ ├── permissions_policy.rb │ └── sidekiq.rb ├── locales │ └── en.yml ├── puma.rb ├── routes.rb ├── storage.yml └── tailwind.config.js ├── db ├── migrate │ ├── 20231120202359_create_repos.rb │ └── 20231124113955_create_active_storage_tables.active_storage.rb ├── schema.rb └── seeds.rb ├── lib ├── assets │ └── .keep └── tasks │ └── .keep ├── log └── .keep ├── public ├── 404.html ├── 422.html ├── 500.html ├── apple-touch-icon-precomposed.png ├── apple-touch-icon.png ├── favicon.ico └── robots.txt ├── storage └── .keep ├── test ├── application_system_test_case.rb ├── channels │ └── application_cable │ │ └── connection_test.rb ├── controllers │ ├── .keep │ └── repos_controller_test.rb ├── fixtures │ ├── files │ │ └── .keep │ └── repos.yml ├── helpers │ └── .keep ├── integration │ └── .keep ├── jobs │ └── process_repo_job_test.rb ├── mailers │ ├── .keep │ ├── previews │ │ └── repo_mailer_preview.rb │ └── repo_mailer_test.rb ├── models │ ├── .keep │ └── repo_test.rb ├── system │ └── .keep └── test_helper.rb ├── tmp ├── .keep ├── pids │ └── .keep └── storage │ └── .keep └── vendor ├── .keep └── javascript └── .keep /.dockerignore: -------------------------------------------------------------------------------- 1 | # See https://docs.docker.com/engine/reference/builder/#dockerignore-file for more about ignoring files. 2 | 3 | # Ignore git directory. 4 | /.git/ 5 | 6 | # Ignore bundler config. 7 | /.bundle 8 | 9 | # Ignore all environment files (except templates). 10 | /.env* 11 | !/.env*.erb 12 | 13 | # Ignore all default key files. 14 | /config/master.key 15 | /config/credentials/*.key 16 | 17 | # Ignore all logfiles and tempfiles. 18 | /log/* 19 | /tmp/* 20 | !/log/.keep 21 | !/tmp/.keep 22 | 23 | # Ignore pidfiles, but keep the directory. 24 | /tmp/pids/* 25 | !/tmp/pids/.keep 26 | 27 | # Ignore storage (uploaded files in development and any SQLite databases). 28 | /storage/* 29 | !/storage/.keep 30 | /tmp/storage/* 31 | !/tmp/storage/.keep 32 | 33 | # Ignore assets. 34 | /node_modules/ 35 | /app/assets/builds/* 36 | !/app/assets/builds/.keep 37 | /public/assets 38 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # See https://git-scm.com/docs/gitattributes for more about git attribute files. 2 | 3 | # Mark the database schema as having been generated. 4 | db/schema.rb linguist-generated 5 | 6 | # Mark any vendored files as having been vendored. 7 | vendor/* linguist-vendored 8 | config/credentials/*.yml.enc diff=rails_credentials 9 | config/credentials.yml.enc diff=rails_credentials 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile '~/.gitignore_global' 6 | 7 | # Ignore bundler config. 8 | /.bundle 9 | 10 | # Ignore all environment files (except templates). 11 | /.env* 12 | !/.env*.erb 13 | 14 | # Ignore all logfiles and tempfiles. 15 | /log/* 16 | /tmp/* 17 | !/log/.keep 18 | !/tmp/.keep 19 | 20 | # Ignore pidfiles, but keep the directory. 21 | /tmp/pids/* 22 | !/tmp/pids/ 23 | !/tmp/pids/.keep 24 | 25 | # Ignore storage (uploaded files in development and any SQLite databases). 26 | /storage/* 27 | !/storage/.keep 28 | /tmp/storage/* 29 | !/tmp/storage/ 30 | !/tmp/storage/.keep 31 | 32 | /public/assets 33 | 34 | # Ignore master key for decrypting credentials and more. 35 | /config/master.key 36 | 37 | /app/assets/builds/* 38 | !/app/assets/builds/.keep 39 | 40 | .DS_Store 41 | .idea 42 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | ruby-3.2.2 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax = docker/dockerfile:1 2 | 3 | # Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile 4 | ARG RUBY_VERSION=3.2.2 5 | FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim as base 6 | 7 | # Rails app lives here 8 | WORKDIR /rails 9 | 10 | # Set production environment 11 | ENV RAILS_ENV="production" \ 12 | BUNDLE_DEPLOYMENT="1" \ 13 | BUNDLE_PATH="/usr/local/bundle" \ 14 | BUNDLE_WITHOUT="development" 15 | 16 | 17 | # Throw-away build stage to reduce size of final image 18 | FROM base as build 19 | 20 | # Install packages needed to build gems 21 | RUN apt-get update -qq && \ 22 | apt-get install --no-install-recommends -y build-essential git libvips pkg-config libpq-dev 23 | 24 | # Install application gems 25 | COPY Gemfile Gemfile.lock ./ 26 | RUN bundle install && \ 27 | rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \ 28 | bundle exec bootsnap precompile --gemfile 29 | 30 | # Copy application code 31 | COPY . . 32 | 33 | # Precompile bootsnap code for faster boot times 34 | RUN bundle exec bootsnap precompile app/ lib/ 35 | 36 | # Precompiling assets for production without requiring secret RAILS_MASTER_KEY 37 | RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile 38 | 39 | 40 | # Final stage for app image 41 | FROM base 42 | 43 | # Install packages needed for deployment 44 | RUN apt-get update -qq && \ 45 | apt-get install --no-install-recommends -y curl git libsqlite3-0 libpq-dev libvips && \ 46 | rm -rf /var/lib/apt/lists /var/cache/apt/archives 47 | 48 | # Copy built artifacts: gems, application 49 | COPY --from=build /usr/local/bundle /usr/local/bundle 50 | COPY --from=build /rails /rails 51 | 52 | # Run and own only the runtime files as a non-root user for security 53 | RUN useradd rails --create-home --shell /bin/bash && \ 54 | chown -R rails:rails db log storage tmp 55 | USER rails:rails 56 | 57 | # Entrypoint prepares the database. 58 | ENTRYPOINT ["/rails/bin/docker-entrypoint"] 59 | 60 | # Start the server by default, this can be overwritten at runtime 61 | EXPOSE 3000 62 | CMD ["./bin/rails", "server"] 63 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | ruby "3.2.2" 4 | 5 | # Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main" 6 | gem "rails", "~> 7.1.3" 7 | 8 | # The original asset pipeline for Rails [https://github.com/rails/sprockets-rails] 9 | gem "sprockets-rails" 10 | 11 | # Use sqlite3 as the database for Active Record 12 | gem "sqlite3", "~> 1.4" 13 | 14 | # Use the Puma web server [https://github.com/puma/puma] 15 | gem "puma", ">= 5.0" 16 | 17 | # Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails] 18 | gem "importmap-rails" 19 | 20 | # Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev] 21 | gem "turbo-rails" 22 | 23 | # Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev] 24 | gem "stimulus-rails" 25 | 26 | # Use Tailwind CSS [https://github.com/rails/tailwindcss-rails] 27 | gem "tailwindcss-rails" 28 | 29 | # Build JSON APIs with ease [https://github.com/rails/jbuilder] 30 | gem "jbuilder" 31 | 32 | # Use Redis adapter to run Action Cable in production 33 | gem "redis", ">= 4.0.1" 34 | 35 | # Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis] 36 | # gem "kredis" 37 | 38 | # Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword] 39 | # gem "bcrypt", "~> 3.1.7" 40 | 41 | # Windows does not include zoneinfo files, so bundle the tzinfo-data gem 42 | gem "tzinfo-data", platforms: %i[ windows jruby ] 43 | 44 | # Reduces boot times through caching; required in config/boot.rb 45 | gem "bootsnap", require: false 46 | 47 | # Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images] 48 | # gem "image_processing", "~> 1.2" 49 | 50 | group :development, :test do 51 | # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem 52 | gem "debug", platforms: %i[ mri windows ] 53 | end 54 | 55 | group :development do 56 | # Use console on exceptions pages [https://github.com/rails/web-console] 57 | gem "web-console" 58 | 59 | # Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler] 60 | # gem "rack-mini-profiler" 61 | 62 | # Speed up commands on slow machines / big apps [https://github.com/rails/spring] 63 | # gem "spring" 64 | gem "letter_opener" 65 | end 66 | 67 | group :test do 68 | # Use system testing [https://guides.rubyonrails.org/testing.html#system-testing] 69 | gem "capybara" 70 | gem "selenium-webdriver" 71 | end 72 | 73 | gem "git", "~> 1.18" 74 | 75 | gem "aws-sdk-s3", "~> 1.139" 76 | 77 | gem "heroicon", "~> 1.0" 78 | 79 | gem 'pg' 80 | gem 'postmark-rails' 81 | 82 | 83 | gem "sidekiq", "~> 7.2" 84 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | actioncable (7.1.3.1) 5 | actionpack (= 7.1.3.1) 6 | activesupport (= 7.1.3.1) 7 | nio4r (~> 2.0) 8 | websocket-driver (>= 0.6.1) 9 | zeitwerk (~> 2.6) 10 | actionmailbox (7.1.3.1) 11 | actionpack (= 7.1.3.1) 12 | activejob (= 7.1.3.1) 13 | activerecord (= 7.1.3.1) 14 | activestorage (= 7.1.3.1) 15 | activesupport (= 7.1.3.1) 16 | mail (>= 2.7.1) 17 | net-imap 18 | net-pop 19 | net-smtp 20 | actionmailer (7.1.3.1) 21 | actionpack (= 7.1.3.1) 22 | actionview (= 7.1.3.1) 23 | activejob (= 7.1.3.1) 24 | activesupport (= 7.1.3.1) 25 | mail (~> 2.5, >= 2.5.4) 26 | net-imap 27 | net-pop 28 | net-smtp 29 | rails-dom-testing (~> 2.2) 30 | actionpack (7.1.3.1) 31 | actionview (= 7.1.3.1) 32 | activesupport (= 7.1.3.1) 33 | nokogiri (>= 1.8.5) 34 | racc 35 | rack (>= 2.2.4) 36 | rack-session (>= 1.0.1) 37 | rack-test (>= 0.6.3) 38 | rails-dom-testing (~> 2.2) 39 | rails-html-sanitizer (~> 1.6) 40 | actiontext (7.1.3.1) 41 | actionpack (= 7.1.3.1) 42 | activerecord (= 7.1.3.1) 43 | activestorage (= 7.1.3.1) 44 | activesupport (= 7.1.3.1) 45 | globalid (>= 0.6.0) 46 | nokogiri (>= 1.8.5) 47 | actionview (7.1.3.1) 48 | activesupport (= 7.1.3.1) 49 | builder (~> 3.1) 50 | erubi (~> 1.11) 51 | rails-dom-testing (~> 2.2) 52 | rails-html-sanitizer (~> 1.6) 53 | activejob (7.1.3.1) 54 | activesupport (= 7.1.3.1) 55 | globalid (>= 0.3.6) 56 | activemodel (7.1.3.1) 57 | activesupport (= 7.1.3.1) 58 | activerecord (7.1.3.1) 59 | activemodel (= 7.1.3.1) 60 | activesupport (= 7.1.3.1) 61 | timeout (>= 0.4.0) 62 | activestorage (7.1.3.1) 63 | actionpack (= 7.1.3.1) 64 | activejob (= 7.1.3.1) 65 | activerecord (= 7.1.3.1) 66 | activesupport (= 7.1.3.1) 67 | marcel (~> 1.0) 68 | activesupport (7.1.3.1) 69 | base64 70 | bigdecimal 71 | concurrent-ruby (~> 1.0, >= 1.0.2) 72 | connection_pool (>= 2.2.5) 73 | drb 74 | i18n (>= 1.6, < 2) 75 | minitest (>= 5.1) 76 | mutex_m 77 | tzinfo (~> 2.0) 78 | addressable (2.8.5) 79 | public_suffix (>= 2.0.2, < 6.0) 80 | aws-eventstream (1.3.0) 81 | aws-partitions (1.856.0) 82 | aws-sdk-core (3.188.0) 83 | aws-eventstream (~> 1, >= 1.0.2) 84 | aws-partitions (~> 1, >= 1.651.0) 85 | aws-sigv4 (~> 1.5) 86 | jmespath (~> 1, >= 1.6.1) 87 | aws-sdk-kms (1.73.0) 88 | aws-sdk-core (~> 3, >= 3.188.0) 89 | aws-sigv4 (~> 1.1) 90 | aws-sdk-s3 (1.139.0) 91 | aws-sdk-core (~> 3, >= 3.188.0) 92 | aws-sdk-kms (~> 1) 93 | aws-sigv4 (~> 1.6) 94 | aws-sigv4 (1.7.0) 95 | aws-eventstream (~> 1, >= 1.0.2) 96 | base64 (0.2.0) 97 | bigdecimal (3.1.7) 98 | bindex (0.8.1) 99 | bootsnap (1.17.0) 100 | msgpack (~> 1.2) 101 | builder (3.2.4) 102 | capybara (3.39.2) 103 | addressable 104 | matrix 105 | mini_mime (>= 0.1.3) 106 | nokogiri (~> 1.8) 107 | rack (>= 1.6.0) 108 | rack-test (>= 0.6.3) 109 | regexp_parser (>= 1.5, < 3.0) 110 | xpath (~> 3.2) 111 | concurrent-ruby (1.2.3) 112 | connection_pool (2.4.1) 113 | crass (1.0.6) 114 | date (3.3.4) 115 | debug (1.8.0) 116 | irb (>= 1.5.0) 117 | reline (>= 0.3.1) 118 | drb (2.2.1) 119 | erubi (1.12.0) 120 | git (1.18.0) 121 | addressable (~> 2.8) 122 | rchardet (~> 1.8) 123 | globalid (1.2.1) 124 | activesupport (>= 6.1) 125 | heroicon (1.0.0) 126 | rails (>= 5.2) 127 | i18n (1.14.4) 128 | concurrent-ruby (~> 1.0) 129 | importmap-rails (1.2.3) 130 | actionpack (>= 6.0.0) 131 | activesupport (>= 6.0.0) 132 | railties (>= 6.0.0) 133 | io-console (0.7.2) 134 | irb (1.12.0) 135 | rdoc 136 | reline (>= 0.4.2) 137 | jbuilder (2.11.5) 138 | actionview (>= 5.0.0) 139 | activesupport (>= 5.0.0) 140 | jmespath (1.6.2) 141 | json (2.6.3) 142 | launchy (2.5.2) 143 | addressable (~> 2.8) 144 | letter_opener (1.8.1) 145 | launchy (>= 2.2, < 3) 146 | loofah (2.22.0) 147 | crass (~> 1.0.2) 148 | nokogiri (>= 1.12.0) 149 | mail (2.8.1) 150 | mini_mime (>= 0.1.1) 151 | net-imap 152 | net-pop 153 | net-smtp 154 | marcel (1.0.4) 155 | matrix (0.4.2) 156 | mini_mime (1.1.5) 157 | minitest (5.22.3) 158 | msgpack (1.7.2) 159 | mutex_m (0.2.0) 160 | net-imap (0.4.10) 161 | date 162 | net-protocol 163 | net-pop (0.1.2) 164 | net-protocol 165 | net-protocol (0.2.2) 166 | timeout 167 | net-smtp (0.5.0) 168 | net-protocol 169 | nio4r (2.7.1) 170 | nokogiri (1.16.3-aarch64-linux) 171 | racc (~> 1.4) 172 | nokogiri (1.16.3-arm64-darwin) 173 | racc (~> 1.4) 174 | nokogiri (1.16.3-x86_64-linux) 175 | racc (~> 1.4) 176 | pg (1.5.4) 177 | postmark (1.25.0) 178 | json 179 | postmark-rails (0.22.1) 180 | actionmailer (>= 3.0.0) 181 | postmark (>= 1.21.3, < 2.0) 182 | psych (5.1.2) 183 | stringio 184 | public_suffix (5.0.4) 185 | puma (6.4.2) 186 | nio4r (~> 2.0) 187 | racc (1.7.3) 188 | rack (3.0.11) 189 | rack-session (2.0.0) 190 | rack (>= 3.0.0) 191 | rack-test (2.1.0) 192 | rack (>= 1.3) 193 | rackup (2.1.0) 194 | rack (>= 3) 195 | webrick (~> 1.8) 196 | rails (7.1.3.1) 197 | actioncable (= 7.1.3.1) 198 | actionmailbox (= 7.1.3.1) 199 | actionmailer (= 7.1.3.1) 200 | actionpack (= 7.1.3.1) 201 | actiontext (= 7.1.3.1) 202 | actionview (= 7.1.3.1) 203 | activejob (= 7.1.3.1) 204 | activemodel (= 7.1.3.1) 205 | activerecord (= 7.1.3.1) 206 | activestorage (= 7.1.3.1) 207 | activesupport (= 7.1.3.1) 208 | bundler (>= 1.15.0) 209 | railties (= 7.1.3.1) 210 | rails-dom-testing (2.2.0) 211 | activesupport (>= 5.0.0) 212 | minitest 213 | nokogiri (>= 1.6) 214 | rails-html-sanitizer (1.6.0) 215 | loofah (~> 2.21) 216 | nokogiri (~> 1.14) 217 | railties (7.1.3.1) 218 | actionpack (= 7.1.3.1) 219 | activesupport (= 7.1.3.1) 220 | irb 221 | rackup (>= 1.0.0) 222 | rake (>= 12.2) 223 | thor (~> 1.0, >= 1.2.2) 224 | zeitwerk (~> 2.6) 225 | rake (13.2.0) 226 | rchardet (1.8.0) 227 | rdoc (6.6.3.1) 228 | psych (>= 4.0.0) 229 | redis (5.0.8) 230 | redis-client (>= 0.17.0) 231 | redis-client (0.22.1) 232 | connection_pool 233 | regexp_parser (2.8.2) 234 | reline (0.5.0) 235 | io-console (~> 0.5) 236 | rexml (3.2.6) 237 | rubyzip (2.3.2) 238 | selenium-webdriver (4.15.0) 239 | rexml (~> 3.2, >= 3.2.5) 240 | rubyzip (>= 1.2.2, < 3.0) 241 | websocket (~> 1.0) 242 | sidekiq (7.2.4) 243 | concurrent-ruby (< 2) 244 | connection_pool (>= 2.3.0) 245 | rack (>= 2.2.4) 246 | redis-client (>= 0.19.0) 247 | sprockets (4.2.1) 248 | concurrent-ruby (~> 1.0) 249 | rack (>= 2.2.4, < 4) 250 | sprockets-rails (3.4.2) 251 | actionpack (>= 5.2) 252 | activesupport (>= 5.2) 253 | sprockets (>= 3.0.0) 254 | sqlite3 (1.6.8-aarch64-linux) 255 | sqlite3 (1.6.8-arm64-darwin) 256 | sqlite3 (1.6.8-x86_64-linux) 257 | stimulus-rails (1.3.0) 258 | railties (>= 6.0.0) 259 | stringio (3.1.0) 260 | tailwindcss-rails (2.0.32-aarch64-linux) 261 | railties (>= 6.0.0) 262 | tailwindcss-rails (2.0.32-arm64-darwin) 263 | railties (>= 6.0.0) 264 | tailwindcss-rails (2.0.32-x86_64-linux) 265 | railties (>= 6.0.0) 266 | thor (1.3.1) 267 | timeout (0.4.1) 268 | turbo-rails (1.5.0) 269 | actionpack (>= 6.0.0) 270 | activejob (>= 6.0.0) 271 | railties (>= 6.0.0) 272 | tzinfo (2.0.6) 273 | concurrent-ruby (~> 1.0) 274 | web-console (4.2.1) 275 | actionview (>= 6.0.0) 276 | activemodel (>= 6.0.0) 277 | bindex (>= 0.4.0) 278 | railties (>= 6.0.0) 279 | webrick (1.8.1) 280 | websocket (1.2.10) 281 | websocket-driver (0.7.6) 282 | websocket-extensions (>= 0.1.0) 283 | websocket-extensions (0.1.5) 284 | xpath (3.2.0) 285 | nokogiri (~> 1.8) 286 | zeitwerk (2.6.13) 287 | 288 | PLATFORMS 289 | aarch64-linux 290 | arm64-darwin-22 291 | x86_64-linux 292 | 293 | DEPENDENCIES 294 | aws-sdk-s3 (~> 1.139) 295 | bootsnap 296 | capybara 297 | debug 298 | git (~> 1.18) 299 | heroicon (~> 1.0) 300 | importmap-rails 301 | jbuilder 302 | letter_opener 303 | pg 304 | postmark-rails 305 | puma (>= 5.0) 306 | rails (~> 7.1.3) 307 | redis (>= 4.0.1) 308 | selenium-webdriver 309 | sidekiq (~> 7.2) 310 | sprockets-rails 311 | sqlite3 (~> 1.4) 312 | stimulus-rails 313 | tailwindcss-rails 314 | turbo-rails 315 | tzinfo-data 316 | web-console 317 | 318 | RUBY VERSION 319 | ruby 3.2.2p53 320 | 321 | BUNDLED WITH 322 | 2.4.17 323 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Context.ai 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Procfile.dev: -------------------------------------------------------------------------------- 1 | web: env RUBY_DEBUG_OPEN=true bin/rails server -p 3000 2 | css: bin/rails tailwindcss:watch 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CodebaseChat 2 | _Made in London by [Context.ai](https://context.ai?utm_source=codebasechat&utm_medium=github)_ 3 | 4 | Create a GPT chatbot for any GitHub Repo in just 30 Seconds! 5 | 6 | Blog post: https://context.ai/post/codebasechat 7 | 8 | Have a question about this repo? We built [a GPT](https://chat.openai.com/g/g-6eEQn0yBn-chat-with-my-codebase) you can chat with: 9 | [![gpt-screenshot](https://github.com/contextco/codebasechat/assets/146003115/8bf289e4-4529-4e06-969d-2b710ed169d5)](https://chat.openai.com/g/g-6eEQn0yBn-chat-with-my-codebase) 10 | 11 | ## Instructions 12 | 1. Go to [CodebaseChat.com](https://codebasechat.com) 13 | 2. Paste the URL to any public GitHub repo and enter your email 14 | 3. CodebaseChat will send you a `repo.md` file 15 | 4. Go to OpenAI's [GPT editor](https://chat.openai.com/gpts/editor) and click "Configure" 16 | 1. If you don't ChatGPT Plus you can use the [Assistants Playground](https://platform.openai.com/playground) 17 | 5. Upload `repo.md` and enter some instructions to the LLM (CodebaseChat provides a suggested starting point) 18 | 6. Use your chatbot to answer questions about the codebase 19 | 20 | ## Contributing 21 | Have an idea for improving this project? Feel free to send us a PR! 22 | 23 | ## Chatbot Analytics 24 | If you're building a conversational AI or LLM product, you'll want to have analytics. [Context.ai](https://context.ai?utm_source=codebasechat&utm_medium=github) can help you understand user behavior and track LLM performance. It takes < 30 mins to set up and start generating product insights. To learn more, request a demo at [Context.ai/demo](https://context.ai/demo?utm_source=codebasechat&utm_medium=github). 25 | 26 | [![logo-color](https://github.com/contextco/codebasechat/assets/146003115/d6dd0e31-6453-4785-905d-a64f73c2e236)](https://context.ai?utm_source=codebasechat&utm_medium=github) 27 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require_relative "config/application" 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /app/assets/builds/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contextco/codebasechat/db4edca1f60b0b577722874e62442d9bdb414c58/app/assets/builds/.keep -------------------------------------------------------------------------------- /app/assets/config/manifest.js: -------------------------------------------------------------------------------- 1 | //= link_tree ../images 2 | //= link_directory ../stylesheets .css 3 | //= link_tree ../../javascript .js 4 | //= link_tree ../../../vendor/javascript .js 5 | //= link_tree ../builds 6 | -------------------------------------------------------------------------------- /app/assets/images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contextco/codebasechat/db4edca1f60b0b577722874e62442d9bdb414c58/app/assets/images/.keep -------------------------------------------------------------------------------- /app/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contextco/codebasechat/db4edca1f60b0b577722874e62442d9bdb414c58/app/assets/images/logo.png -------------------------------------------------------------------------------- /app/assets/images/logo_email.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contextco/codebasechat/db4edca1f60b0b577722874e62442d9bdb414c58/app/assets/images/logo_email.png -------------------------------------------------------------------------------- /app/assets/images/logo_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contextco/codebasechat/db4edca1f60b0b577722874e62442d9bdb414c58/app/assets/images/logo_white.png -------------------------------------------------------------------------------- /app/assets/images/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contextco/codebasechat/db4edca1f60b0b577722874e62442d9bdb414c58/app/assets/images/screenshot.png -------------------------------------------------------------------------------- /app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS (and SCSS, if configured) file within this directory, lib/assets/stylesheets, or any plugin's 6 | * vendor/assets/stylesheets directory can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the 9 | * compiled file so the styles you add here take precedence over styles defined in any other CSS 10 | * files in this directory. Styles in this file should be added after the last require_* statement. 11 | * It is generally better to create a new file per style scope. 12 | * 13 | *= require_tree . 14 | *= require_self 15 | */ 16 | 17 | @import url('https://fonts.googleapis.com/css2?family=Noto+Serif&display=swap'); 18 | 19 | .noto-serif { 20 | /*font-family: 'Noto Serif', serif;*/ 21 | } 22 | -------------------------------------------------------------------------------- /app/assets/stylesheets/application.tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | /* 6 | 7 | @layer components { 8 | .btn-primary { 9 | @apply py-2 px-4 bg-blue-200; 10 | } 11 | } 12 | 13 | */ 14 | 15 | .highlight { 16 | @apply hover:text-slate-50 duration-200; 17 | } 18 | 19 | .question { 20 | @apply flex flex-col gap-2 21 | } -------------------------------------------------------------------------------- /app/channels/application_cable/channel.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Channel < ActionCable::Channel::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /app/channels/application_cable/connection.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Connection < ActionCable::Connection::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | end 3 | -------------------------------------------------------------------------------- /app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contextco/codebasechat/db4edca1f60b0b577722874e62442d9bdb414c58/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /app/controllers/repos_controller.rb: -------------------------------------------------------------------------------- 1 | class ReposController < ApplicationController 2 | 3 | def index 4 | end 5 | 6 | def action 7 | @repo = Repo.new(url: params[:repo], email: params[:email]) 8 | render and return unless @repo.valid? 9 | 10 | @repo.save! 11 | ProcessRepoJob.perform_later(@repo) 12 | end 13 | 14 | def async_load_repo 15 | @clone = Clone.new(params[:repo]) 16 | @file = @clone.file_from_repo 17 | send_data @file, filename: 'repo.md' 18 | 19 | 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/heroicon_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module HeroiconHelper 4 | include Heroicon::Engine.helpers 5 | end -------------------------------------------------------------------------------- /app/helpers/repos_helper.rb: -------------------------------------------------------------------------------- 1 | module ReposHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/javascript/application.js: -------------------------------------------------------------------------------- 1 | // Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails 2 | import "@hotwired/turbo-rails" 3 | import "controllers" 4 | -------------------------------------------------------------------------------- /app/javascript/controllers/application.js: -------------------------------------------------------------------------------- 1 | import { Application } from "@hotwired/stimulus" 2 | 3 | const application = Application.start() 4 | 5 | // Configure Stimulus development experience 6 | application.debug = false 7 | window.Stimulus = application 8 | 9 | export { application } 10 | -------------------------------------------------------------------------------- /app/javascript/controllers/hello_controller.js: -------------------------------------------------------------------------------- 1 | import { Controller } from "@hotwired/stimulus" 2 | 3 | export default class extends Controller { 4 | connect() { 5 | this.element.textContent = "Hello World!" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /app/javascript/controllers/index.js: -------------------------------------------------------------------------------- 1 | // Import and register all your controllers from the importmap under controllers/* 2 | 3 | import { application } from "controllers/application" 4 | 5 | // Eager load all controllers defined in the import map under controllers/**/*_controller 6 | import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading" 7 | eagerLoadControllersFrom("controllers", application) 8 | 9 | // Lazy load controllers as they appear in the DOM (remember not to preload controllers in import map!) 10 | // import { lazyLoadControllersFrom } from "@hotwired/stimulus-loading" 11 | // lazyLoadControllersFrom("controllers", application) 12 | -------------------------------------------------------------------------------- /app/jobs/application_job.rb: -------------------------------------------------------------------------------- 1 | class ApplicationJob < ActiveJob::Base 2 | # Automatically retry jobs that encountered a deadlock 3 | # retry_on ActiveRecord::Deadlocked 4 | 5 | # Most jobs are safe to ignore if the underlying records are no longer available 6 | # discard_on ActiveJob::DeserializationError 7 | end 8 | -------------------------------------------------------------------------------- /app/jobs/process_repo_job.rb: -------------------------------------------------------------------------------- 1 | class ProcessRepoJob < ApplicationJob 2 | queue_as :default 3 | 4 | def perform(repo, *args) 5 | file = Clone.new(repo.url).file_from_repo 6 | repo.indexed_repo_file.attach(io: file, filename: 'repo.md') 7 | 8 | RepoMailer.repo_created(repo).deliver_later 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /app/lib/clone.rb: -------------------------------------------------------------------------------- 1 | 2 | class Clone 3 | 4 | FILE = Struct.new(:path, :content) 5 | 6 | def initialize(repo) 7 | @repo = repo 8 | @randomdir = SecureRandom.hex(RANDOM_LENGTH) 9 | @directory = File.join(ENV.fetch('REPOS_BASE_PATH', Rails.root.join('tmp')), @randomdir) 10 | end 11 | 12 | def file_from_repo 13 | files = generate_files 14 | 15 | combine_files(files) 16 | end 17 | 18 | private 19 | 20 | RANDOM_LENGTH = 10 21 | 22 | def combine_files(files) 23 | f = StringIO.new 24 | 25 | files.each do |file| 26 | f << "## #{file.path}\n\n" 27 | f << "```\n" 28 | f << file.content 29 | f << "```\n\n\n" 30 | end 31 | 32 | f.rewind 33 | f 34 | end 35 | 36 | def generate_files 37 | repo = Git.clone(@repo, @directory) 38 | 39 | readme = nil 40 | files = [] 41 | 42 | # Iterate through all files in the repository 43 | Dir.glob(File.join(@directory, '**', '*')).each do |file| 44 | next if File.directory?(file) 45 | next unless allowed_extensions.include?(File.extname(file)) 46 | 47 | if File.basename(file).downcase == 'readme.md' 48 | readme = FILE.new(file.delete_prefix(@randomdir), File.read(file)) 49 | next 50 | end 51 | 52 | files << FILE.new(file.delete_prefix(@randomdir), File.read(file)) 53 | end 54 | 55 | files.prepend(readme) if readme 56 | 57 | FileUtils.rm_rf(@directory) 58 | 59 | files 60 | end 61 | 62 | def allowed_extensions 63 | %w(.py .js .jsx .html .css .java .c .cpp .cs .php .rb .go .rs .ts .tsx .swift .kt .lua .pl .sh .sql .json .md) 64 | end 65 | end -------------------------------------------------------------------------------- /app/mailers/application_mailer.rb: -------------------------------------------------------------------------------- 1 | class ApplicationMailer < ActionMailer::Base 2 | default from: "from@example.com" 3 | layout "mailer" 4 | end 5 | -------------------------------------------------------------------------------- /app/mailers/repo_mailer.rb: -------------------------------------------------------------------------------- 1 | class RepoMailer < ApplicationMailer 2 | def repo_created(repo) 3 | @repo = repo 4 | attachments.inline['logo.png'] = File.read(Rails.root.join('app/assets/images/logo_email.png')) 5 | mail(from: 'CodebaseChat ', to: repo.email, subject: 'Your codebase GPT is ready to be created.') 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | class ApplicationRecord < ActiveRecord::Base 2 | primary_abstract_class 3 | end 4 | -------------------------------------------------------------------------------- /app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contextco/codebasechat/db4edca1f60b0b577722874e62442d9bdb414c58/app/models/concerns/.keep -------------------------------------------------------------------------------- /app/models/repo.rb: -------------------------------------------------------------------------------- 1 | class Repo < ApplicationRecord 2 | has_one_attached :indexed_repo_file 3 | 4 | HUMANIZED_ATTRIBUTES = { 5 | :email => "E-mail address", 6 | :url => "Github Repository URL" 7 | } 8 | 9 | validates :url, format: { 10 | with: /\Ahttps:\/\/github\.com\/[a-zA-Z0-9._-]+\/[a-zA-Z0-9._-]+\z/, 11 | message: 'must be valid and present.' 12 | } 13 | validates :email, format: { with: URI::MailTo::EMAIL_REGEXP, message: 'address string must be present and valid.' } 14 | 15 | def self.human_attribute_name(attr, options = {}) 16 | HUMANIZED_ATTRIBUTES[attr.to_sym] || super 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CodebaseChat 5 | 6 | <%= csrf_meta_tags %> 7 | <%= csp_meta_tag %> 8 | <%= stylesheet_link_tag "tailwind", "inter-font", "data-turbo-track": "reload" %> 9 | 10 | 11 | <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %> 12 | <%= javascript_importmap_tags %> 13 | 14 | 15 | 16 | <%= yield %> 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/views/layouts/mailer.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | <%= yield %> 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/views/layouts/mailer.text.erb: -------------------------------------------------------------------------------- 1 | <%= yield %> 2 | -------------------------------------------------------------------------------- /app/views/repo_mailer/repo_created.html.erb: -------------------------------------------------------------------------------- 1 | Hi,

2 | 3 | Your Git repository has been processed and your GPT is ready to be created.

4 | 5 | Download your knowledge retrieval file <%= link_to "here", @repo.indexed_repo_file.url %> and follow the additional instructions at CodebaseChat. 6 | 7 |

8 | Thanks,
9 | Alex and the CodebaseChat team 10 | 11 |

12 | 13 | PS: Building on top of LLMs? Context.ai is an evaluation and analytics platform for LLM powered products. 14 |

15 | <%= image_tag attachments['logo.png'].url, style: 'height: 30px;' %> 16 | -------------------------------------------------------------------------------- /app/views/repos/action.html.erb: -------------------------------------------------------------------------------- 1 | <%= turbo_frame_tag 'result' do %> 2 | <% if @repo.valid? %> 3 |
4 | <%= heroicon 'check-circle', variant: :outline, options: { class: 'w-8 h-8'} %> 5 | 6 |
Success!
7 |
8 | Your indexed repo is being processed and will be emailed to you shortly. 9 |
10 |
11 |
12 | <% else %> 13 |
14 | <%= heroicon 'x-circle', variant: :outline, options: { class: 'w-8 h-8'} %> 15 | 16 |
Invalid submission.
17 |
18 | <%= @repo.errors.full_messages.first %> 19 |
20 |
21 |
22 | <% end %> 23 | <% end %> -------------------------------------------------------------------------------- /app/views/repos/index.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 | Made in London by 4 |
5 | <%= link_to 'http://context.ai/?utm_source=codebasechat&utm_medium=site' do %> 6 | <%= image_tag 'logo_white.png', class: 'h-full' %> 7 | <% end %> 8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Create a GPT chatbot for any GitHub repo in 19 |
20 |
21 |
30 seconds
22 |
23 |
24 | 25 |
26 |
27 |
28 | Every major programming language supported: 29 |
30 | 31 |
32 | 33 | 34 | 35 | 36 | 37 | 38 |
...and more
39 |
40 |
41 |
42 | 43 |
44 |
45 |
1
46 |
47 |
Enter your GitHub repository URL:
48 |
We will crawl your repo and email you an index file you can upload directly to your GPT.
49 | <%= turbo_frame_tag 'form' do %> 50 | <%= form_with url: action_repos_path, data: { 'turbo-frame': 'result' } do |form| %> 51 |
52 |
53 |
GitHub Repo Link
54 | <%= form.text_field :repo, placeholder: 'https://github.com/tldraw/tldraw', class: 'rounded border-slate-500 bg-slate-600 text-slate-100 placeholder:text-slate-400 w-full' %> 55 |
56 | 57 |
58 |
Email
59 | <%= form.text_field :email, placeholder: 'alex@example.com', class: 'rounded border-slate-500 bg-slate-600 text-slate-100 placeholder:text-slate-400' %> 60 |
61 | 62 | 63 |
64 |
65 | <%= form.submit "Submit", class: 'border-slate-500 border p-2 rounded my-4 cursor-pointer' %> 66 | 67 | <%= turbo_frame_tag 'result', class: 'grow' %> 68 |
69 | <% end %> 70 | <% end %> 71 |
72 |
73 | 74 |
75 |
2
76 |
77 |
Upload your GPT codebase file:
78 | 79 |
You will receive an email with a link to a file repo.md. You can then upload that file to OpenAI to create your custom codebase GPT.
80 | 81 |
82 |
83 |
84 | 85 |
86 |
87 | 88 |
89 |
90 |
91 |
Frequently Asked Questions
92 | 93 |
94 |
95 | How does this work? 96 |
97 |
98 | CodebaseChat clones and crawls your repo to create a file that you can upload to OpenAI's new GPTs or Assistants. OpenAI GPTs and Assistants currently have a 20 file limit when using the retrieval features, so for now you need to upload a single indexed file to allow them to operate over large amounts of data. 99 |
100 |
101 | 102 |
103 |
104 | How should I prompt my GPT or assistant to make full use of the file? 105 |
106 |
107 | We recommend using a prompt that tells the GPT about the contents of your codebase. 108 | 109 | For example, at Context.ai we use the following prompt in our GPT: 110 | 111 |
112 |
113 | You are a code assistant for the Git repo of Context AI. Context AI is a startup that is building product analytics software for natural language interfaces where users are interacting with LLMs. The product ingests transcripts of its customers, then provides analytics about those interactions, such as topics, sentiment analysis, languages spoken and more. The contents of the codebase are stored in repo.md, with the contents of each file under a new Markdown header. 114 |
115 |
116 | 117 |
118 |
119 | Can I modify the code or suggest changes to CodebaseChat? 120 |
121 |
122 | Yes! CodebaseChat is open-source and we welcome contributions. You can find the repo here. 123 |
124 |
125 | 126 |
127 |
128 | I don't have ChatGPT Plus, can I still use this? 129 |
130 |
131 | Yes, you can instead upload the repo file in the OpenAI Assistants Playground and ask questions of your repo with the GPT API free tier. 132 |
133 |
134 | 135 |
136 |
137 | Do you support private repos? 138 |
139 |
140 | We don't yet support private repos. Contact us here if you'd like to be notified when we launch this. 141 |
142 |
143 | 144 |
145 |
146 | I have another feature request, how can I contact you? 147 |
148 |
149 | You can add your feature requests here. 150 |
151 |
152 |
153 |
154 |
155 |
156 | 157 | 158 |
159 | -------------------------------------------------------------------------------- /bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'bundle' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "rubygems" 12 | 13 | m = Module.new do 14 | module_function 15 | 16 | def invoked_as_script? 17 | File.expand_path($0) == File.expand_path(__FILE__) 18 | end 19 | 20 | def env_var_version 21 | ENV["BUNDLER_VERSION"] 22 | end 23 | 24 | def cli_arg_version 25 | return unless invoked_as_script? # don't want to hijack other binstubs 26 | return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update` 27 | bundler_version = nil 28 | update_index = nil 29 | ARGV.each_with_index do |a, i| 30 | if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN 31 | bundler_version = a 32 | end 33 | next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/ 34 | bundler_version = $1 35 | update_index = i 36 | end 37 | bundler_version 38 | end 39 | 40 | def gemfile 41 | gemfile = ENV["BUNDLE_GEMFILE"] 42 | return gemfile if gemfile && !gemfile.empty? 43 | 44 | File.expand_path("../Gemfile", __dir__) 45 | end 46 | 47 | def lockfile 48 | lockfile = 49 | case File.basename(gemfile) 50 | when "gems.rb" then gemfile.sub(/\.rb$/, ".locked") 51 | else "#{gemfile}.lock" 52 | end 53 | File.expand_path(lockfile) 54 | end 55 | 56 | def lockfile_version 57 | return unless File.file?(lockfile) 58 | lockfile_contents = File.read(lockfile) 59 | return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/ 60 | Regexp.last_match(1) 61 | end 62 | 63 | def bundler_requirement 64 | @bundler_requirement ||= 65 | env_var_version || 66 | cli_arg_version || 67 | bundler_requirement_for(lockfile_version) 68 | end 69 | 70 | def bundler_requirement_for(version) 71 | return "#{Gem::Requirement.default}.a" unless version 72 | 73 | bundler_gem_version = Gem::Version.new(version) 74 | 75 | bundler_gem_version.approximate_recommendation 76 | end 77 | 78 | def load_bundler! 79 | ENV["BUNDLE_GEMFILE"] ||= gemfile 80 | 81 | activate_bundler 82 | end 83 | 84 | def activate_bundler 85 | gem_error = activation_error_handling do 86 | gem "bundler", bundler_requirement 87 | end 88 | return if gem_error.nil? 89 | require_error = activation_error_handling do 90 | require "bundler/version" 91 | end 92 | return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION)) 93 | 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}'`" 94 | exit 42 95 | end 96 | 97 | def activation_error_handling 98 | yield 99 | nil 100 | rescue StandardError, LoadError => e 101 | e 102 | end 103 | end 104 | 105 | m.load_bundler! 106 | 107 | if m.invoked_as_script? 108 | load Gem.bin_path("bundler", "bundle") 109 | end 110 | -------------------------------------------------------------------------------- /bin/dev: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | if ! gem list foreman -i --silent; then 4 | echo "Installing foreman..." 5 | gem install foreman 6 | fi 7 | 8 | exec foreman start -f Procfile.dev "$@" 9 | -------------------------------------------------------------------------------- /bin/docker-entrypoint: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # If running the rails server then create or migrate existing database 4 | if [ "${1}" == "./bin/rails" ] && [ "${2}" == "server" ]; then 5 | ./bin/rails db:prepare 6 | fi 7 | 8 | exec "${@}" 9 | -------------------------------------------------------------------------------- /bin/importmap: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require_relative "../config/application" 4 | require "importmap/commands" 5 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path("../config/application", __dir__) 3 | require_relative "../config/boot" 4 | require "rails/commands" 5 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative "../config/boot" 3 | require "rake" 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require "fileutils" 3 | 4 | # path to your application root. 5 | APP_ROOT = File.expand_path("..", __dir__) 6 | 7 | def system!(*args) 8 | system(*args, exception: true) 9 | end 10 | 11 | FileUtils.chdir APP_ROOT do 12 | # This script is a way to set up or update your development environment automatically. 13 | # This script is idempotent, so that you can run it at any time and get an expectable outcome. 14 | # Add necessary setup steps to this file. 15 | 16 | puts "== Installing dependencies ==" 17 | system! "gem install bundler --conservative" 18 | system("bundle check") || system!("bundle install") 19 | 20 | # puts "\n== Copying sample files ==" 21 | # unless File.exist?("config/database.yml") 22 | # FileUtils.cp "config/database.yml.sample", "config/database.yml" 23 | # end 24 | 25 | puts "\n== Preparing database ==" 26 | system! "bin/rails db:prepare" 27 | 28 | puts "\n== Removing old logs and tempfiles ==" 29 | system! "bin/rails log:clear tmp:clear" 30 | 31 | puts "\n== Restarting application server ==" 32 | system! "bin/rails restart" 33 | end 34 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require_relative "config/environment" 4 | 5 | run Rails.application 6 | Rails.application.load_server 7 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | require_relative "boot" 2 | 3 | require "rails/all" 4 | 5 | # Require the gems listed in Gemfile, including any gems 6 | # you've limited to :test, :development, or :production. 7 | Bundler.require(*Rails.groups) 8 | 9 | module GitQuestion 10 | class Application < Rails::Application 11 | # Initialize configuration defaults for originally generated Rails version. 12 | config.load_defaults 7.1 13 | 14 | # Please, add to the `ignore` list any other `lib` subdirectories that do 15 | # not contain `.rb` files, or that should not be reloaded or eager loaded. 16 | # Common ones are `templates`, `generators`, or `middleware`, for example. 17 | config.autoload_lib(ignore: %w(assets tasks)) 18 | 19 | # Configuration for the application, engines, and railties goes here. 20 | # 21 | # These settings can be overridden in specific environments using the files 22 | # in config/environments, which are processed later. 23 | # 24 | # config.time_zone = "Central Time (US & Canada)" 25 | # config.eager_load_paths << Rails.root.join("extras") 26 | config.active_job.queue_adapter = :sidekiq 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) 2 | 3 | require "bundler/setup" # Set up gems listed in the Gemfile. 4 | require "bootsnap/setup" # Speed up boot time by caching expensive operations. 5 | -------------------------------------------------------------------------------- /config/cable.yml: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: redis 3 | url: redis://localhost:6379/1 4 | 5 | test: 6 | adapter: test 7 | 8 | production: 9 | adapter: redis 10 | url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> 11 | channel_prefix: git_question_production 12 | -------------------------------------------------------------------------------- /config/credentials.yml.enc: -------------------------------------------------------------------------------- 1 | HMXYlA15gIYxFdolJM+NJEDvse7FZpJMmQo17g4T0hYCJLF1b7rXRRop6iuAJAEwvTn8fC9KxUNLuvnwXYKzo5txNTqNJ75IgioOlvJvU/UGmhBDc2Q3EWBo4+XHtOQKUPGLgi8JmBHuraTJ2ZYMn0aD/Bd2dt9MpT4zntyfzkQLsYcw47Mgiost+3G6SF/r7AV6rzM6cteAhTb8JC3I43qqdiE7qp3T6VEbL//TjurAUkSYf4nBKE7bJDDEI/0HdeHJemulf7rWoL4/4KFkUAAyfzcLxIVqyY+ZQJImCLGdn0YL+BBsV8nX9H+PifpTjd06c0ckOTYcuC3FyjAiA092e9X2O943wm9U4++M/WKAmBhqWD02t0zduoNVmhaNkjm+fJE81SsgMRW9NJSaNu5GDumoQiW8ibpMSej4EvQVeWg3R4TUBprPIRIA3Vt1tJG3KmpgzwSNR+IQNH7W2PE5BIRe7+igjqBe8pJFRQrHCR5TWydQl5pjdBNAS6/6xJtkE+PnXDgFSjiQfvk07y2ZeJL7ivy6Bp5WDi1B7gVAvjJg6ffuMXpi/bVPCeUn/5CrVv8wTcO9nU84hQ==--+8ziRBTP3T7IVcDv--FPNCEt6DNDCSCtvWYOA5mA== -------------------------------------------------------------------------------- /config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite. Versions 3.8.0 and up are supported. 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem "sqlite3" 6 | # 7 | default: &default 8 | adapter: postgresql 9 | encoding: unicode 10 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> 11 | url: <%= ENV['DATABASE_URL'] %> 12 | timeout: 5000 13 | 14 | development: 15 | <<: *default 16 | database: codebasechat_dev 17 | 18 | # Warning: The database defined as "test" will be erased and 19 | # re-generated from your development database when you run "rake". 20 | # Do not set this db to the same as development or production. 21 | test: 22 | <<: *default 23 | database: codebasechat_test 24 | 25 | production: 26 | <<: *default 27 | database: codebasechat_prod -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative "application" 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /config/environments/development.rb: -------------------------------------------------------------------------------- 1 | require "active_support/core_ext/integer/time" 2 | 3 | Rails.application.configure do 4 | # Settings specified here will take precedence over those in config/application.rb. 5 | 6 | # In the development environment your application's code is reloaded any time 7 | # it changes. This slows down response time but is perfect for development 8 | # since you don't have to restart the web server when you make code changes. 9 | config.enable_reloading = true 10 | 11 | # Do not eager load code on boot. 12 | config.eager_load = false 13 | 14 | # Show full error reports. 15 | config.consider_all_requests_local = true 16 | 17 | # Enable server timing 18 | config.server_timing = true 19 | 20 | # Enable/disable caching. By default caching is disabled. 21 | # Run rails dev:cache to toggle caching. 22 | if Rails.root.join("tmp/caching-dev.txt").exist? 23 | config.action_controller.perform_caching = true 24 | config.action_controller.enable_fragment_cache_logging = true 25 | 26 | config.cache_store = :memory_store 27 | config.public_file_server.headers = { 28 | "Cache-Control" => "public, max-age=#{2.days.to_i}" 29 | } 30 | else 31 | config.action_controller.perform_caching = false 32 | 33 | config.cache_store = :null_store 34 | end 35 | 36 | # Store uploaded files on the local file system (see config/storage.yml for options). 37 | config.active_storage.service = :cloudflare 38 | 39 | # Don't care if the mailer can't send. 40 | config.action_mailer.raise_delivery_errors = false 41 | 42 | config.action_mailer.perform_caching = false 43 | 44 | # Print deprecation notices to the Rails logger. 45 | config.active_support.deprecation = :log 46 | 47 | # Raise exceptions for disallowed deprecations. 48 | config.active_support.disallowed_deprecation = :raise 49 | 50 | # Tell Active Support which deprecation messages to disallow. 51 | config.active_support.disallowed_deprecation_warnings = [] 52 | 53 | # Raise an error on page load if there are pending migrations. 54 | config.active_record.migration_error = :page_load 55 | 56 | # Highlight code that triggered database queries in logs. 57 | config.active_record.verbose_query_logs = true 58 | 59 | # Highlight code that enqueued background job in logs. 60 | config.active_job.verbose_enqueue_logs = true 61 | 62 | # Suppress logger output for asset requests. 63 | config.assets.quiet = true 64 | 65 | # Raises error for missing translations. 66 | # config.i18n.raise_on_missing_translations = true 67 | 68 | # Annotate rendered view with file names. 69 | # config.action_view.annotate_rendered_view_with_filenames = true 70 | 71 | # Uncomment if you wish to allow Action Cable access from any origin. 72 | # config.action_cable.disable_request_forgery_protection = true 73 | 74 | # Raise error when a before_action's only/except options reference missing actions 75 | config.action_controller.raise_on_missing_callback_actions = true 76 | 77 | config.action_mailer.delivery_method = :letter_opener 78 | config.action_mailer.perform_deliveries = true 79 | end 80 | -------------------------------------------------------------------------------- /config/environments/production.rb: -------------------------------------------------------------------------------- 1 | require "active_support/core_ext/integer/time" 2 | 3 | Rails.application.configure do 4 | # Settings specified here will take precedence over those in config/application.rb. 5 | 6 | # Code is not reloaded between requests. 7 | config.enable_reloading = false 8 | 9 | # Eager load code on boot. This eager loads most of Rails and 10 | # your application in memory, allowing both threaded web servers 11 | # and those relying on copy on write to perform better. 12 | # Rake tasks automatically ignore this option for performance. 13 | config.eager_load = true 14 | 15 | # Full error reports are disabled and caching is turned on. 16 | config.consider_all_requests_local = false 17 | config.action_controller.perform_caching = true 18 | 19 | # Ensures that a master key has been made available in ENV["RAILS_MASTER_KEY"], config/master.key, or an environment 20 | # key such as config/credentials/production.key. This key is used to decrypt credentials (and other encrypted files). 21 | # config.require_master_key = true 22 | 23 | # Disable serving static files from `public/`, relying on NGINX/Apache to do so instead. 24 | # config.public_file_server.enabled = false 25 | 26 | # Compress CSS using a preprocessor. 27 | # config.assets.css_compressor = :sass 28 | 29 | # Do not fallback to assets pipeline if a precompiled asset is missed. 30 | config.assets.compile = false 31 | 32 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 33 | # config.asset_host = "http://assets.example.com" 34 | 35 | # Specifies the header that your server uses for sending files. 36 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache 37 | # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX 38 | 39 | # Store uploaded files on the local file system (see config/storage.yml for options). 40 | config.active_storage.service = :cloudflare 41 | 42 | # Mount Action Cable outside main process or domain. 43 | # config.action_cable.mount_path = nil 44 | # config.action_cable.url = "wss://example.com/cable" 45 | # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] 46 | 47 | # Assume all access to the app is happening through a SSL-terminating reverse proxy. 48 | # Can be used together with config.force_ssl for Strict-Transport-Security and secure cookies. 49 | # config.assume_ssl = true 50 | 51 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 52 | config.force_ssl = true 53 | 54 | # Log to STDOUT by default 55 | config.logger = ActiveSupport::Logger.new(STDOUT) 56 | .tap { |logger| logger.formatter = ::Logger::Formatter.new } 57 | .then { |logger| ActiveSupport::TaggedLogging.new(logger) } 58 | 59 | # Prepend all log lines with the following tags. 60 | config.log_tags = [ :request_id ] 61 | 62 | # Info include generic and useful information about system operation, but avoids logging too much 63 | # information to avoid inadvertent exposure of personally identifiable information (PII). If you 64 | # want to log everything, set the level to "debug". 65 | config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "info") 66 | 67 | # Use a different cache store in production. 68 | # config.cache_store = :mem_cache_store 69 | 70 | # Use a real queuing backend for Active Job (and separate queues per environment). 71 | # config.active_job.queue_adapter = :resque 72 | # config.active_job.queue_name_prefix = "git_question_production" 73 | 74 | config.action_mailer.perform_caching = false 75 | 76 | # Ignore bad email addresses and do not raise email delivery errors. 77 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 78 | # config.action_mailer.raise_delivery_errors = false 79 | 80 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 81 | # the I18n.default_locale when a translation cannot be found). 82 | config.i18n.fallbacks = true 83 | 84 | # Don't log any deprecations. 85 | config.active_support.report_deprecations = false 86 | 87 | # Do not dump schema after migrations. 88 | config.active_record.dump_schema_after_migration = false 89 | 90 | # Enable DNS rebinding protection and other `Host` header attacks. 91 | # config.hosts = [ 92 | # "example.com", # Allow requests from example.com 93 | # /.*\.example\.com/ # Allow requests from subdomains like `www.example.com` 94 | # ] 95 | # Skip DNS rebinding protection for the default health check endpoint. 96 | # config.host_authorization = { exclude: ->(request) { request.path == "/up" } } 97 | 98 | config.action_mailer.delivery_method = :postmark 99 | config.action_mailer.postmark_settings = { :api_token => ENV["POSTMARK_TOKEN"] } 100 | end 101 | -------------------------------------------------------------------------------- /config/environments/test.rb: -------------------------------------------------------------------------------- 1 | require "active_support/core_ext/integer/time" 2 | 3 | # The test environment is used exclusively to run your application's 4 | # test suite. You never need to work with it otherwise. Remember that 5 | # your test database is "scratch space" for the test suite and is wiped 6 | # and recreated between test runs. Don't rely on the data there! 7 | 8 | Rails.application.configure do 9 | # Settings specified here will take precedence over those in config/application.rb. 10 | 11 | # While tests run files are not watched, reloading is not necessary. 12 | config.enable_reloading = false 13 | 14 | # Eager loading loads your entire application. When running a single test locally, 15 | # this is usually not necessary, and can slow down your test suite. However, it's 16 | # recommended that you enable it in continuous integration systems to ensure eager 17 | # loading is working properly before deploying your code. 18 | config.eager_load = ENV["CI"].present? 19 | 20 | # Configure public file server for tests with Cache-Control for performance. 21 | config.public_file_server.enabled = true 22 | config.public_file_server.headers = { 23 | "Cache-Control" => "public, max-age=#{1.hour.to_i}" 24 | } 25 | 26 | # Show full error reports and disable caching. 27 | config.consider_all_requests_local = true 28 | config.action_controller.perform_caching = false 29 | config.cache_store = :null_store 30 | 31 | # Render exception templates for rescuable exceptions and raise for other exceptions. 32 | config.action_dispatch.show_exceptions = :rescuable 33 | 34 | # Disable request forgery protection in test environment. 35 | config.action_controller.allow_forgery_protection = false 36 | 37 | # Store uploaded files on the local file system in a temporary directory. 38 | config.active_storage.service = :test 39 | 40 | config.action_mailer.perform_caching = false 41 | 42 | # Tell Action Mailer not to deliver emails to the real world. 43 | # The :test delivery method accumulates sent emails in the 44 | # ActionMailer::Base.deliveries array. 45 | config.action_mailer.delivery_method = :test 46 | 47 | # Print deprecation notices to the stderr. 48 | config.active_support.deprecation = :stderr 49 | 50 | # Raise exceptions for disallowed deprecations. 51 | config.active_support.disallowed_deprecation = :raise 52 | 53 | # Tell Active Support which deprecation messages to disallow. 54 | config.active_support.disallowed_deprecation_warnings = [] 55 | 56 | # Raises error for missing translations. 57 | # config.i18n.raise_on_missing_translations = true 58 | 59 | # Annotate rendered view with file names. 60 | # config.action_view.annotate_rendered_view_with_filenames = true 61 | 62 | # Raise error when a before_action's only/except options reference missing actions 63 | config.action_controller.raise_on_missing_callback_actions = true 64 | end 65 | -------------------------------------------------------------------------------- /config/importmap.rb: -------------------------------------------------------------------------------- 1 | # Pin npm packages by running ./bin/importmap 2 | 3 | pin "application", preload: true 4 | pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true 5 | pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true 6 | pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true 7 | pin_all_from "app/javascript/controllers", under: "controllers" 8 | -------------------------------------------------------------------------------- /config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = "1.0" 5 | 6 | # Add additional assets to the asset load path. 7 | # Rails.application.config.assets.paths << Emoji.images_path 8 | 9 | # Precompile additional assets. 10 | # application.js, application.css, and all non-JS/CSS in the app/assets 11 | # folder are already added. 12 | # Rails.application.config.assets.precompile += %w( admin.js admin.css ) 13 | -------------------------------------------------------------------------------- /config/initializers/content_security_policy.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Define an application-wide content security policy. 4 | # See the Securing Rails Applications Guide for more information: 5 | # https://guides.rubyonrails.org/security.html#content-security-policy-header 6 | 7 | # Rails.application.configure do 8 | # config.content_security_policy do |policy| 9 | # policy.default_src :self, :https 10 | # policy.font_src :self, :https, :data 11 | # policy.img_src :self, :https, :data 12 | # policy.object_src :none 13 | # policy.script_src :self, :https 14 | # policy.style_src :self, :https 15 | # # Specify URI for violation reports 16 | # # policy.report_uri "/csp-violation-report-endpoint" 17 | # end 18 | # 19 | # # Generate session nonces for permitted importmap, inline scripts, and inline styles. 20 | # config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s } 21 | # config.content_security_policy_nonce_directives = %w(script-src style-src) 22 | # 23 | # # Report violations without enforcing the policy. 24 | # # config.content_security_policy_report_only = true 25 | # end 26 | -------------------------------------------------------------------------------- /config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure parameters to be partially matched (e.g. passw matches password) and filtered from the log file. 4 | # Use this to limit dissemination of sensitive information. 5 | # See the ActiveSupport::ParameterFilter documentation for supported notations and behaviors. 6 | Rails.application.config.filter_parameters += [ 7 | :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn 8 | ] 9 | -------------------------------------------------------------------------------- /config/initializers/heroicon.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Heroicon.configure do |config| 4 | config.variant = :solid # Options are :solid, :outline and :mini 5 | 6 | ## 7 | # You can set a default class, which will get applied to every icon with 8 | # the given variant. To do so, un-comment the line below. 9 | # config.default_class = {solid: "h-5 w-5", outline: "h-6 w-6", mini: "h-4 w-4"} 10 | end 11 | -------------------------------------------------------------------------------- /config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, "\\1en" 8 | # inflect.singular /^(ox)en/i, "\\1" 9 | # inflect.irregular "person", "people" 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym "RESTful" 16 | # end 17 | -------------------------------------------------------------------------------- /config/initializers/permissions_policy.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Define an application-wide HTTP permissions policy. For further 4 | # information see: https://developers.google.com/web/updates/2018/06/feature-policy 5 | 6 | # Rails.application.config.permissions_policy do |policy| 7 | # policy.camera :none 8 | # policy.gyroscope :none 9 | # policy.microphone :none 10 | # policy.usb :none 11 | # policy.fullscreen :self 12 | # policy.payment :self, "https://secure.example.com" 13 | # end 14 | -------------------------------------------------------------------------------- /config/initializers/sidekiq.rb: -------------------------------------------------------------------------------- 1 | require 'sidekiq' 2 | require 'sidekiq/web' 3 | 4 | Sidekiq::Web.use(Rack::Auth::Basic) do |user, password| 5 | # Protect against timing attacks: 6 | # - See https://codahale.com/a-lesson-in-timing-attacks/ 7 | # - See https://thisdata.com/blog/timing-attacks-against-string-comparison/ 8 | # - Use & (do not use &&) so that it doesn't short circuit. 9 | # - Use digests to stop length information leaking 10 | Rack::Utils.secure_compare(::Digest::SHA256.hexdigest(user), ::Digest::SHA256.hexdigest(ENV["SIDEKIQ_USER"])) & 11 | Rack::Utils.secure_compare(::Digest::SHA256.hexdigest(password), ::Digest::SHA256.hexdigest(ENV["SIDEKIQ_PASSWORD"])) 12 | end -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization and 2 | # are automatically loaded by Rails. If you want to use locales other than 3 | # English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t "hello" 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t("hello") %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # To learn more about the API, please read the Rails Internationalization guide 20 | # at https://guides.rubyonrails.org/i18n.html. 21 | # 22 | # Be aware that YAML interprets the following case-insensitive strings as 23 | # booleans: `true`, `false`, `on`, `off`, `yes`, `no`. Therefore, these strings 24 | # must be quoted to be interpreted as strings. For example: 25 | # 26 | # en: 27 | # "yes": yup 28 | # enabled: "ON" 29 | 30 | en: 31 | hello: "Hello world" 32 | -------------------------------------------------------------------------------- /config/puma.rb: -------------------------------------------------------------------------------- 1 | # This configuration file will be evaluated by Puma. The top-level methods that 2 | # are invoked here are part of Puma's configuration DSL. For more information 3 | # about methods provided by the DSL, see https://puma.io/puma/Puma/DSL.html. 4 | 5 | # Puma can serve each request in a thread from an internal thread pool. 6 | # The `threads` method setting takes two numbers: a minimum and maximum. 7 | # Any libraries that use thread pools should be configured to match 8 | # the maximum value specified for Puma. Default is set to 5 threads for minimum 9 | # and maximum; this matches the default thread size of Active Record. 10 | max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } 11 | min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } 12 | threads min_threads_count, max_threads_count 13 | 14 | # Specifies that the worker count should equal the number of processors in production. 15 | if ENV["RAILS_ENV"] == "production" 16 | require "concurrent-ruby" 17 | worker_count = Integer(ENV.fetch("WEB_CONCURRENCY") { Concurrent.physical_processor_count }) 18 | workers worker_count if worker_count > 1 19 | end 20 | 21 | # Specifies the `worker_timeout` threshold that Puma will use to wait before 22 | # terminating a worker in development environments. 23 | worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" 24 | 25 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000. 26 | port ENV.fetch("PORT") { 3000 } 27 | 28 | # Specifies the `environment` that Puma will run in. 29 | environment ENV.fetch("RAILS_ENV") { "development" } 30 | 31 | # Specifies the `pidfile` that Puma will use. 32 | pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } 33 | 34 | # Allow puma to be restarted by `bin/rails restart` command. 35 | plugin :tmp_restart 36 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | require 'sidekiq/web' 2 | 3 | Rails.application.routes.draw do 4 | mount Sidekiq::Web => "/sidekiq" 5 | 6 | resources :repos, only: [:index] do 7 | collection do 8 | post :action 9 | end 10 | end 11 | 12 | # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html 13 | 14 | # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500. 15 | # Can be used by load balancers and uptime monitors to verify that the app is live. 16 | get "up" => "rails/health#show", as: :rails_health_check 17 | 18 | # Defines the root path route ("/") 19 | root "repos#index" 20 | end 21 | -------------------------------------------------------------------------------- /config/storage.yml: -------------------------------------------------------------------------------- 1 | test: 2 | service: Disk 3 | root: <%= Rails.root.join("tmp/storage") %> 4 | 5 | local: 6 | service: Disk 7 | root: <%= Rails.root.join("storage") %> 8 | 9 | cloudflare: 10 | service: S3 11 | endpoint: https://24c86fc9f4d7d81c7bbaadbd801a2a67.r2.cloudflarestorage.com 12 | access_key_id: <%= Rails.application.credentials.dig(:r2, :access_key_id) %> 13 | secret_access_key: <%= Rails.application.credentials.dig(:r2, :secret_access_key) %> 14 | region: auto 15 | bucket: repogpt 16 | 17 | # Remember not to checkin your GCS keyfile to a repository 18 | # google: 19 | # service: GCS 20 | # project: your_project 21 | # credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> 22 | # bucket: your_own_bucket-<%= Rails.env %> 23 | 24 | # Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) 25 | # microsoft: 26 | # service: AzureStorage 27 | # storage_account_name: your_account_name 28 | # storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> 29 | # container: your_container_name-<%= Rails.env %> 30 | 31 | # mirror: 32 | # service: Mirror 33 | # primary: local 34 | # mirrors: [ amazon, google, microsoft ] 35 | -------------------------------------------------------------------------------- /config/tailwind.config.js: -------------------------------------------------------------------------------- 1 | const defaultTheme = require('tailwindcss/defaultTheme') 2 | 3 | module.exports = { 4 | content: [ 5 | './public/*.html', 6 | './app/helpers/**/*.rb', 7 | './app/javascript/**/*.js', 8 | './app/views/**/*.{erb,haml,html,slim}' 9 | ], 10 | theme: { 11 | extend: { 12 | fontFamily: { 13 | sans: ['Inter var', ...defaultTheme.fontFamily.sans], 14 | }, 15 | }, 16 | }, 17 | plugins: [ 18 | require('@tailwindcss/forms'), 19 | require('@tailwindcss/aspect-ratio'), 20 | require('@tailwindcss/typography'), 21 | require('@tailwindcss/container-queries'), 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /db/migrate/20231120202359_create_repos.rb: -------------------------------------------------------------------------------- 1 | class CreateRepos < ActiveRecord::Migration[7.1] 2 | def change 3 | create_table :repos do |t| 4 | t.string :url 5 | t.string :email 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20231124113955_create_active_storage_tables.active_storage.rb: -------------------------------------------------------------------------------- 1 | # This migration comes from active_storage (originally 20170806125915) 2 | class CreateActiveStorageTables < ActiveRecord::Migration[7.0] 3 | def change 4 | # Use Active Record's configured type for primary and foreign keys 5 | primary_key_type, foreign_key_type = primary_and_foreign_key_types 6 | 7 | create_table :active_storage_blobs, id: primary_key_type do |t| 8 | t.string :key, null: false 9 | t.string :filename, null: false 10 | t.string :content_type 11 | t.text :metadata 12 | t.string :service_name, null: false 13 | t.bigint :byte_size, null: false 14 | t.string :checksum 15 | 16 | if connection.supports_datetime_with_precision? 17 | t.datetime :created_at, precision: 6, null: false 18 | else 19 | t.datetime :created_at, null: false 20 | end 21 | 22 | t.index [ :key ], unique: true 23 | end 24 | 25 | create_table :active_storage_attachments, id: primary_key_type do |t| 26 | t.string :name, null: false 27 | t.references :record, null: false, polymorphic: true, index: false, type: foreign_key_type 28 | t.references :blob, null: false, type: foreign_key_type 29 | 30 | if connection.supports_datetime_with_precision? 31 | t.datetime :created_at, precision: 6, null: false 32 | else 33 | t.datetime :created_at, null: false 34 | end 35 | 36 | t.index [ :record_type, :record_id, :name, :blob_id ], name: :index_active_storage_attachments_uniqueness, unique: true 37 | t.foreign_key :active_storage_blobs, column: :blob_id 38 | end 39 | 40 | create_table :active_storage_variant_records, id: primary_key_type do |t| 41 | t.belongs_to :blob, null: false, index: false, type: foreign_key_type 42 | t.string :variation_digest, null: false 43 | 44 | t.index [ :blob_id, :variation_digest ], name: :index_active_storage_variant_records_uniqueness, unique: true 45 | t.foreign_key :active_storage_blobs, column: :blob_id 46 | end 47 | end 48 | 49 | private 50 | def primary_and_foreign_key_types 51 | config = Rails.configuration.generators 52 | setting = config.options[config.orm][:primary_key_type] 53 | primary_key_type = setting || :primary_key 54 | foreign_key_type = setting || :bigint 55 | [primary_key_type, foreign_key_type] 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /db/schema.rb: -------------------------------------------------------------------------------- 1 | # This file is auto-generated from the current state of the database. Instead 2 | # of editing this file, please use the migrations feature of Active Record to 3 | # incrementally modify your database, and then regenerate this schema definition. 4 | # 5 | # This file is the source Rails uses to define your schema when running `bin/rails 6 | # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to 7 | # be faster and is potentially less error prone than running all of your 8 | # migrations from scratch. Old migrations may fail to apply correctly if those 9 | # migrations use external dependencies or application code. 10 | # 11 | # It's strongly recommended that you check this file into your version control system. 12 | 13 | ActiveRecord::Schema[7.1].define(version: 2023_11_24_113955) do 14 | create_table "active_storage_attachments", force: :cascade do |t| 15 | t.string "name", null: false 16 | t.string "record_type", null: false 17 | t.bigint "record_id", null: false 18 | t.bigint "blob_id", null: false 19 | t.datetime "created_at", null: false 20 | t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id" 21 | t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true 22 | end 23 | 24 | create_table "active_storage_blobs", force: :cascade do |t| 25 | t.string "key", null: false 26 | t.string "filename", null: false 27 | t.string "content_type" 28 | t.text "metadata" 29 | t.string "service_name", null: false 30 | t.bigint "byte_size", null: false 31 | t.string "checksum" 32 | t.datetime "created_at", null: false 33 | t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true 34 | end 35 | 36 | create_table "active_storage_variant_records", force: :cascade do |t| 37 | t.bigint "blob_id", null: false 38 | t.string "variation_digest", null: false 39 | t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true 40 | end 41 | 42 | create_table "repos", force: :cascade do |t| 43 | t.string "url" 44 | t.string "email" 45 | t.datetime "created_at", null: false 46 | t.datetime "updated_at", null: false 47 | end 48 | 49 | add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id" 50 | add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id" 51 | end 52 | -------------------------------------------------------------------------------- /db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should ensure the existence of records required to run the application in every environment (production, 2 | # development, test). The code here should be idempotent so that it can be executed at any point in every environment. 3 | # The data can then be loaded with the bin/rails db:seed command (or created alongside the database with db:setup). 4 | # 5 | # Example: 6 | # 7 | # ["Action", "Comedy", "Drama", "Horror"].each do |genre_name| 8 | # MovieGenre.find_or_create_by!(name: genre_name) 9 | # end 10 | -------------------------------------------------------------------------------- /lib/assets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contextco/codebasechat/db4edca1f60b0b577722874e62442d9bdb414c58/lib/assets/.keep -------------------------------------------------------------------------------- /lib/tasks/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contextco/codebasechat/db4edca1f60b0b577722874e62442d9bdb414c58/lib/tasks/.keep -------------------------------------------------------------------------------- /log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contextco/codebasechat/db4edca1f60b0b577722874e62442d9bdb414c58/log/.keep -------------------------------------------------------------------------------- /public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The page you were looking for doesn't exist.

62 |

You may have mistyped the address or the page may have moved.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The change you wanted was rejected.

62 |

Maybe you tried to change something you didn't have access to.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

We're sorry, but something went wrong.

62 |
63 |

If you are the application owner check the logs for more information.

64 |
65 | 66 | 67 | -------------------------------------------------------------------------------- /public/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contextco/codebasechat/db4edca1f60b0b577722874e62442d9bdb414c58/public/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contextco/codebasechat/db4edca1f60b0b577722874e62442d9bdb414c58/public/apple-touch-icon.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contextco/codebasechat/db4edca1f60b0b577722874e62442d9bdb414c58/public/favicon.ico -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | -------------------------------------------------------------------------------- /storage/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contextco/codebasechat/db4edca1f60b0b577722874e62442d9bdb414c58/storage/.keep -------------------------------------------------------------------------------- /test/application_system_test_case.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class ApplicationSystemTestCase < ActionDispatch::SystemTestCase 4 | driven_by :selenium, using: :chrome, screen_size: [1400, 1400] 5 | end 6 | -------------------------------------------------------------------------------- /test/channels/application_cable/connection_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | module ApplicationCable 4 | class ConnectionTest < ActionCable::Connection::TestCase 5 | # test "connects with cookies" do 6 | # cookies.signed[:user_id] = 42 7 | # 8 | # connect 9 | # 10 | # assert_equal connection.user_id, "42" 11 | # end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /test/controllers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contextco/codebasechat/db4edca1f60b0b577722874e62442d9bdb414c58/test/controllers/.keep -------------------------------------------------------------------------------- /test/controllers/repos_controller_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class ReposControllerTest < ActionDispatch::IntegrationTest 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | -------------------------------------------------------------------------------- /test/fixtures/files/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contextco/codebasechat/db4edca1f60b0b577722874e62442d9bdb414c58/test/fixtures/files/.keep -------------------------------------------------------------------------------- /test/fixtures/repos.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html 2 | 3 | # This model initially had no columns defined. If you add columns to the 4 | # model remove the "{}" from the fixture names and add the columns immediately 5 | # below each fixture, per the syntax in the comments below 6 | # 7 | one: {} 8 | # column: value 9 | # 10 | two: {} 11 | # column: value 12 | -------------------------------------------------------------------------------- /test/helpers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contextco/codebasechat/db4edca1f60b0b577722874e62442d9bdb414c58/test/helpers/.keep -------------------------------------------------------------------------------- /test/integration/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contextco/codebasechat/db4edca1f60b0b577722874e62442d9bdb414c58/test/integration/.keep -------------------------------------------------------------------------------- /test/jobs/process_repo_job_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class ProcessRepoJobTest < ActiveJob::TestCase 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | -------------------------------------------------------------------------------- /test/mailers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contextco/codebasechat/db4edca1f60b0b577722874e62442d9bdb414c58/test/mailers/.keep -------------------------------------------------------------------------------- /test/mailers/previews/repo_mailer_preview.rb: -------------------------------------------------------------------------------- 1 | # Preview all emails at http://localhost:3000/rails/mailers/repo_mailer 2 | class RepoMailerPreview < ActionMailer::Preview 3 | def repo_created 4 | repo = Repo.new( 5 | email: 'alex@context.ai' 6 | ) 7 | repo.indexed_repo_file.attach(io: StringIO.new("Hi"), filename: 'repo.md') 8 | RepoMailer.repo_created(repo) 9 | end 10 | 11 | end 12 | -------------------------------------------------------------------------------- /test/mailers/repo_mailer_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class RepoMailerTest < ActionMailer::TestCase 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | -------------------------------------------------------------------------------- /test/models/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contextco/codebasechat/db4edca1f60b0b577722874e62442d9bdb414c58/test/models/.keep -------------------------------------------------------------------------------- /test/models/repo_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class RepoTest < ActiveSupport::TestCase 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | -------------------------------------------------------------------------------- /test/system/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contextco/codebasechat/db4edca1f60b0b577722874e62442d9bdb414c58/test/system/.keep -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | ENV["RAILS_ENV"] ||= "test" 2 | require_relative "../config/environment" 3 | require "rails/test_help" 4 | 5 | module ActiveSupport 6 | class TestCase 7 | # Run tests in parallel with specified workers 8 | parallelize(workers: :number_of_processors) 9 | 10 | # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. 11 | fixtures :all 12 | 13 | # Add more helper methods to be used by all tests here... 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /tmp/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contextco/codebasechat/db4edca1f60b0b577722874e62442d9bdb414c58/tmp/.keep -------------------------------------------------------------------------------- /tmp/pids/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contextco/codebasechat/db4edca1f60b0b577722874e62442d9bdb414c58/tmp/pids/.keep -------------------------------------------------------------------------------- /tmp/storage/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contextco/codebasechat/db4edca1f60b0b577722874e62442d9bdb414c58/tmp/storage/.keep -------------------------------------------------------------------------------- /vendor/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contextco/codebasechat/db4edca1f60b0b577722874e62442d9bdb414c58/vendor/.keep -------------------------------------------------------------------------------- /vendor/javascript/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/contextco/codebasechat/db4edca1f60b0b577722874e62442d9bdb414c58/vendor/javascript/.keep --------------------------------------------------------------------------------