I recently wanted to setup GitHub Actions on one of my personal Rails 6.x projects. I realized I’d been paying for 3,000 minutes / month, and not using them on my personal accounts! Yet once I started setting up actions, I ran into a few issues getting Rails + MySQL working correctly. If you’ve had this issue, you may find this bit of info useful. I provide a light break-down the changes I had to make to each file in my github repo.
config/database.yml
Not that I use ENV.fetch('MYSQL_HOST', 'db')
because locally, when testing, I have a docker service setup at hostname db
that is used, but within GitHub Actions, that is not available, so I first check the MYSQL_HOST
environment var, which I setup insode my ci.yml
file (see below).
...snip
test:
<<: *default
host: <%= ENV.fetch('MYSQL_HOST', 'db') %>
port: <%= ENV.fetch('MYSQL_PORT', 3306) %>
database: 'my_app_test'
...snip
.github/workflows/ci.yml
This is a fairly standare workflow YAML file, but the one caveat is that you’ll see my MYSQL_*
ENV vars declared twice. Once in the top-level env:
, which should be shared across all jobs/services, but then again underneath the db:
service. Before I’d duplicated the top-most env:
vars into the db:
service, MySQL would fail to start, and those healthchecks failed every single time. I do not know why this is.
Additionally, I use the local, loopback IP (127.0.0.1) for the MYSQL_HOST
, as this seemed to work over using the service name db
. Not sure why db
is not working, but it’s not, have to use the IP.
name: Continuous integration
env:
RUBY_VERSION: 2.7.4
BUNDLER_VERSION: 2.2.0
RAILS_ENV: test
MYSQL_USERNAME: root
MYSQL_PASSWORD: password
MYSQL_ROOT_PASSWORD: password
MYSQL_HOST: 127.0.0.1
MYSQL_PORT: 3307
MYSQL_DATABASE: my_app_test
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
name: "RSpec Tests"
runs-on: ubuntu-latest
services:
db:
image: mysql:5.7
env:
MYSQL_USERNAME: root
MYSQL_PASSWORD: password
MYSQL_ROOT_PASSWORD: password
MYSQL_HOST: 127.0.0.1
MYSQL_PORT: 3307
MYSQL_DATABASE: my_app_test
ports:
- 3307:3306
options: >-
--health-cmd="mysqladmin ping"
--health-interval=10s
--health-timeout=5s
--health-retries=5
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 1
- name: Setup Ruby
uses: actions/setup-ruby@v1
with:
ruby-version: ${{ env.RUBY_VERSION }}
- name: Install dependencies
run: |
sudo apt-get -yqq install default-libmysqlclient-dev default-mysql-client
- name: Restore bundle cache
uses: actions/cache@v2
with:
path: vendor/bundle
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: |
${{ runner.os }}-gems-
- name: Bundle
env:
RAILS_ENV: test
run: |
gem install bundler:${{ env.BUNDLER_VERSION }}
bundle config path vendor/bundle
bundle install --jobs 4 --retry 3 --path vendor/bundle
- name: Setup Database
run: |
bundle exec rake db:prepare
- name: Run tests
run: bundle exec rspec
config/environment/test.rb
I also found that since I was using an older version of MySQL (5.7 versus the latest 8.x), I had to tell Rails to NOT dump the schema after running db:migrate
, or else it would fail with this error:
mysqldump: Couldn't execute
SELECT COLUMN_NAME,
JSON_EXTRACT(HISTOGRAM, '$."number-of-buckets-specified"')
FROM information_schema.COLUMN_STATISTICS
WHERE SCHEMA_NAME = 'my_app_test'
AND TABLE_NAME = 'active_storage_attachments';
: Unknown table 'COLUMN_STATISTICS' in information_schema (1109)
rake aborted!
failed to execute: `mysqldump`
Please check the output above for any errors and make sure that `mysqldump`
is installed in your PATH and has proper permissions.
You can read this Serverfault post to understand it a bit more, but my workaround of disabling the mysqldump
fixes this, but the short answer was:
This is due to a new flag that is enabled by default in mysqldump 8. You can disable it by adding
--column-statistics=0
.
Since I cannot pass that parameter to mysqldump
during rails db:prepare
, simply disabling mysqldump
entirely while RAILS_ENV == test
will work for my purposes.
#...snip
Rails.application.configure do
#...snip
config.active_record.dump_schema_after_migration = false
#...snip
end
It works!
Once I had all of the above set, my github actions began to run! Every commit to a PR would cause the “ci.yml” action to run, and it would run my rspec tests, and output failures when they happened. Lovely.