Skip to content

Commit

Permalink
Separate Appraisal runs from primary test runs
Browse files Browse the repository at this point in the history
With Rails 8, the minimum version of Ruby becomes 3.2. Unless we drop
support for prior Ruby versions (and also Rails versions), the way in
which we were approaching CI can't work. Maintaining support for older
Rails is not difficult because of Administrate itself, but how we
approach testing so it feels unreasonable to drop support (which if we
didn't test against it, we would effectively be doing) because it made
CI harder to do. And we _can_ make it work, so we will.

Previously, we ran the setup for the project as usual, and then ran
setup for the Appraisals. This served two functions:

1. Make Appraisal available in the bundle,
2. Setup the database for running tests against

However, in the CI matrix, we support multiple different versions of
Ruby (3.0 and up to 3.3). As we try and add Rails 8.0, this means we
can't run `bundle install` on those versions of Ruby below 3.2 as it's a
dependency constraint on Rails itself.

From experiments, we also can't:

1. Install Appraisal outside of the bundle, because it references gems
   in a way that Bundler is there to solve,
2. Load newer `schema.rb` files in older versions of Rails. Rails 7
   introduced versioned schemas, and future schema versions can't be run
   with older versions of Rails.

Instead, what we _can_ do is run the project setup inside a container
configured to use the database in the CI environment, then manually do
what Appraisal is doing to avoid issues bundling.

This container will always use the current development version of Ruby
(3.2.2, at the time of this commit) taken from the `.ruby-version` file,
in which we run just enough to setup the database and ensure the later
tests can run against it.

It's unlikely that Administrate would do something which wasn't
supported at the database level, but not impossible. However these tests
would catch that (from experience: Rails falls back to a string on
unknown types, so it's even less likely to fail).

We also need to remove the Ruby version specification from the generated
Appraisal gemfiles, as otherwise these won't install. Whilst they seemed
to be valid outside of this way of running things, here, they are not.
We just use `sed` to remove it in place, as it can be discarded later
and removing it would cause problems with Heroku deployment of the demo
app.

Finally, we inline the previously extracted Action from #2524. The
intent was to reduce duplication, but the order of operations are now so
different it's not worth it and it would only be used in one place.

Extracted from #2705.
  • Loading branch information
nickcharlton committed Nov 21, 2024
1 parent d504990 commit 9030fe2
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 42 deletions.
38 changes: 0 additions & 38 deletions .github/actions/setup/action.yml

This file was deleted.

50 changes: 46 additions & 4 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on:
push:
branches:
- 'main'
- 'nc-prepare-ci-for-rails-8'
pull_request:
types: [opened, synchronize, reopened]

Expand Down Expand Up @@ -34,9 +35,28 @@ jobs:
--health-retries 5
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup
- name: Set up Ruby ${{ matrix.ruby }}
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true
- name: Set up JS
uses: actions/setup-node@v4
with:
cache: yarn
- name: Install Ruby dependencies
run: bundle install
- name: Install Appraisal dependencies
run: bundle exec appraisal install
- name: Install JS dependencies
run: yarn install
- name: Setup the environment
run: cp .sample.env .env
- run: cp spec/example_app/config/database.yml.sample spec/example_app/config/database.yml
- name: Setup the database
run: bundle exec rake db:setup
- name: Build assets
run: yarn run build && yarn run build:css
- name: Run tests
run: bundle exec rspec

Expand Down Expand Up @@ -70,8 +90,30 @@ jobs:
--health-retries 5
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup
- name: Setup the environment
run: cp .sample.env .env
- run: cp spec/example_app/config/database.yml.sample spec/example_app/config/database.yml
- name: Prepare main database schema
run: bin/generate-database-schema
- name: Set up Ruby ${{ matrix.ruby }}
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
- name: Appraise Rails ${{ matrix.appraisal }}
run: bundle exec appraisal ${{ matrix.appraisal }} rspec
- name: Set up JS
uses: actions/setup-node@v4
with:
cache: yarn
- name: Remove Ruby version specification
run: sed -i 's/^ruby\(.*\)//g' gemfiles/${{ matrix.appraisal }}.gemfile
- name: Install Ruby dependencies
run: bundle install
env:
BUNDLE_GEMFILE: gemfiles/${{ matrix.appraisal }}.gemfile
- name: Install JS dependencies
run: yarn install
- name: Build assets
run: yarn run build && yarn run build:css
- name: Run tests
run: bundle exec rspec
env:
BUNDLE_GEMFILE: gemfiles/${{ matrix.appraisal }}.gemfile
37 changes: 37 additions & 0 deletions bin/generate-database-schema
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/bin/sh

set -e

run_in_container() {
container_id=$1
shift
cmd=$*

docker exec --workdir /app "$container_id" bash -c "$cmd"
}

ruby_version=$(cat .ruby-version)
owner=$(whoami)

echo "Starting container using Ruby $ruby_version..."
container_id=$(
docker run --network="host" \
--env PGHOST --env PGUSER --env PGPASSWORD \
-d -v .:/app ruby:"$ruby_version" sleep infinity
)

echo "Check the environment is correct..."
run_in_container "$container_id" "env"

echo "Run bundle install..."
run_in_container "$container_id" "bundle install"

echo "Running db:setup..."
run_in_container "$container_id" "bundle exec rake db:setup"

echo "Tidying up container..."
docker stop "$container_id" > /dev/null
docker rm "$container_id" > /dev/null

echo "Restoring file permissions..."
sudo chown -R "$owner" .

0 comments on commit 9030fe2

Please sign in to comment.