When I run CircleCI, the first few tests fail due to Elasticsearch not being fully set up yet.
Usually I would use the dockerize library to wait for Elasticsearch to be finished, however this does not seem to detect Elasticsearch. Any ideas why? The dockerize command simply times out. However, the Elasticsearch container seems to be running because if I do not wait, eventually Elasticsearch starts to work with the tests.
Here is my docker file
version: 2
jobs:
build:
parallelism: 3
working_directory: ~/export-opportunities
docker:
- image: circleci/ruby:2.5.5-node
environment:
BUNDLE_JOBS: 3
BUNDLE_RETRY: 3
BUNDLE_PATH: vendor/bundle
PGHOST: localhost
PGUSER: user
RAILS_ENV: test
- image: circleci/postgres:latest
environment:
POSTGRES_USER: user
POSTGRES_DB: circle_test
POSTGRES_PASSWORD: $POSTGRES_PASSWORD
- image: circleci/redis:4.0.9
environment:
REDIS_URL: "redis://localhost:6379/"
- image: docker.elastic.co/elasticsearch/elasticsearch:6.3.2
environment:
cluster.name: elasticsearch
xpack.security.enabled: false
transport.host: localhost
network.host: 127.0.0.1
http.port: 9200
discovery.type: single-node
branches:
only: chore/XOT-597-circleci
steps:
- checkout # check out the code in the project directory
# restore bundle cache
- restore_cache:
keys:
- exops-{{ checksum "Gemfile.lock" }}
- run:
name: Bundle Install
command: bundle check || bundle install
# store bundle cache
- save_cache:
key: exops-{{ checksum "Gemfile.lock" }}
paths:
- vendor/bundle
# Database setup
- run:
name: install dockerize
command: wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz && sudo tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz && rm dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz
environment:
DOCKERIZE_VERSION: v0.3.0
- run:
name: Wait for DB
command: dockerize -wait tcp://localhost:5432 -timeout 1m
- run:
name: Database setup
command: |
bundle exec rake db:create
bundle exec rake db:migrate
# Redis setup
- run:
name: Wait for Redis
command: dockerize -wait tcp://localhost:6379 -timeout 1m
# DOES NOT WORK:
- run:
name: Wait for Elasticsearch
command: dockerize -wait http://localhost:9200 -timeout 2m
# Run rspec in parallel
- run: |
echo Running test ...
bundle exec rspec --profile 10 \
--format RspecJunitFormatter \
--out test_results/rspec.xml \
--format progress \
$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)
# Save test results for timing analysis
- store_test_results:
path: test_results
Note I've also tried dockerize -wait tcp://localhost:9200 -timeout 2m, and dockerize -wait http://127.0.0.1:9200 -timeout 2m, and dockerize -wait tcp://127.0.0.1:9200 -timeout 2m to no effect.
I tried adding sleep 10 and sleep 100 however the issue persisted.
The issue was that the tests were running before the index was created. The index creation was being triggered by the first test to run, but took a few seconds, so the first few tests always failed.
My solution with this was to add the following code to trigger building the index, if not present, in rails_helper.rb which runs on starting the rails environment. For most other environments, the indices do exist so it does not slow down other processes.
# Build initial indices if not present, e.g. CircleCI
[Opportunity, Subscription].each do |model|
unless model.__elasticsearch__.index_exists? index: model.__elasticsearch__.index_name
model.__elasticsearch__.create_index!(force: true)
sleep 2
end
end
Related
has anyone noticed that new Rails apps seem to fail on circleCI with this error:
Sprockets::Rails::Helper::AssetNotFound in Home#index
The asset "application.js" is not present in the asset pipeline.
steps to reproduce:
rails new --javascript=esbuild so it uses JSBundling with ESbuild
• Install rspec
• configure CircleCI
• add app to your circle CI pipeline.
• Add a basic hello world controller that simply prints "Hello world"
• Add the root route to the hello world controller
• Add a spec:
require 'rails_helper'
describe "can load the homepage" do
it "should load the homepage" do
visit "/"
expect(page).to have_content("Hello world")
end
end
there’s a file in app/assets/config/manifest.js which tells Sprockets where to load assets from. I tried adding this
//= link_directory ../../javascript .js
(notice that the default location of the javascript folder is in app/ not in app/assets)
the app works fine locally and deploys to Heroku just fine, I only see this error on CircleCi. Anyone seen this before?
my CircleCI config looks like this:
version: 2.1 # Use 2.1 to enable using orbs and other features.
# Declare the orbs that we'll use in our config.
# read more about orbs: https://circleci.com/docs/2.0/using-orbs/
orbs:
ruby: circleci/ruby#1.0
node: circleci/node#2
browser-tools: circleci/browser-tools#1.2.3
jobs:
build: # our first job, named "build"
docker:
- image: cimg/ruby:3.1.2-browsers # use a tailored CircleCI docker image.
auth:
username: mydockerhub-user
password: $DOCKERHUB_PASSWORD # context / project UI env-var reference
- image: redis:6.2.6
steps:
- checkout # pull down our git code.
- ruby/install-deps # use the ruby orb to install dependencies
# use the node orb to install our packages
# specifying that we use `yarn` and to cache dependencies with `yarn.lock`
# learn more: https://circleci.com/docs/2.0/caching/
- node/install-packages:
pkg-manager: yarn
cache-key: "yarn.lock"
- run:
name: Build assets
command: bundle exec rails assets:precompile
test: # our next job, called "test"
parallelism: 1
# here we set TWO docker images.
docker:
- image: cimg/ruby:3.1.2-browsers # this is our primary docker image, where step commands run.
auth:
username: mydockerhub-user
password: $DOCKERHUB_PASSWORD # context / project UI env-var reference
- image: redis:6.2.6
- image: circleci/postgres:9.5-alpine
auth:
username: mydockerhub-user
password: $DOCKERHUB_PASSWORD # context / project UI env-var reference
environment: # add POSTGRES environment variables.
POSTGRES_USER: circleci-demo-ruby
POSTGRES_DB: VDQApp_test
POSTGRES_PASSWORD: ""
# environment variables specific to Ruby/Rails, applied to the primary container.
environment:
BUNDLE_JOBS: "3"
BUNDLE_RETRY: "3"
PGHOST: 127.0.0.1
PGUSER: circleci-demo-ruby
PGPASSWORD: ""
RAILS_ENV: test
# A series of steps to run, some are similar to those in "build".
steps:
- browser-tools/install-chrome
- browser-tools/install-chromedriver
- checkout
- ruby/install-deps
- node/install-packages:
pkg-manager: yarn
cache-key: "yarn.lock"
# Here we make sure that the secondary container boots
# up before we run operations on the database.
- run:
name: Wait for DB
command: dockerize -wait tcp://localhost:5432 -timeout 1m
- run:
name: Load schema
command: bin/rails db:schema:load RAILS_ENV=test
# Run rspec in parallel
- ruby/rspec-test
# We use workflows to orchestrate the jobs that we declared above.
workflows:
version: 2
build_and_test: # The name of our workflow is "build_and_test"
jobs: # The list of jobs we run as part of this workflow.
- build # Run build first.
- test: # Then run test,
requires: # Test requires that build passes for it to run.
- build # Finally, run the build job.
Ok I figured this out.
The Circle CI config must told to execute the esbuild, whih is done like so:
esbuild app/javascript/*.* --bundle --sourcemap --outdir=app/assets/builds --public-path=assets
that command lives in your yarn package script, so you can run it as yarn build
In the .circleci/config file, look for the jobs > test > steps stanza
You will want to add this step for yarn build after the step for node/install-packages
- run:
name: Yarn build
command: yarn build
steps:
- browser-tools/install-chrome
- browser-tools/install-chromedriver
- checkout
- ruby/install-deps
- node/install-packages:
pkg-manager: yarn
cache-key: "yarn.lock"
- run:
name: yarn build
command: yarn build
# Here we make sure that the secondary container boots
# up before we run operations on the database.
- run:
name: Wait for DB
command: dockerize -wait tcp://localhost:5432 -timeout 1m
- run:
name: Load schema
command: bin/rails db:schema:load RAILS_ENV=test
# Run rspec in parallel
- ruby/rspec-test
I'm trying to use parallel_tests in my github action to run my test suite but I was not able to find a proper solution.
The official docs has one but it is for gitlab:
https://github.com/grosser/parallel_tests/wiki/Distributed-Parallel-Tests-on-CI-systems
Any help would be appreciated thanks!
Here's a sample workflow you can drop into .github/workflows/tests.yml:
name: Rails Tests
on: push
env:
PGHOST: localhost
PGUSER: postgres
RAILS_ENV: test
jobs:
build:
runs-on: ubuntu-latest
strategy:
fail-fast: true
matrix:
# Set N number of parallel jobs you want to run
# Remember to update ci_node_index below to 0..N-1
ci_node_total: [6]
# set N-1 indexes for parallel jobs
# When you run 2 parallel jobs then first job will have index 0, the second job will have index 1 etc
ci_node_index: [0, 1, 2, 3, 4, 5]
services:
postgres:
image: postgres:11.5
ports: ["5432:5432"]
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
redis:
image: redis:5
ports: ["6379:6379"]
steps:
- uses: actions/checkout#v1
- uses: ruby/setup-ruby#v1
with:
bundler-cache: true
- name: Set node version (from .tool-versions)
run: echo "NODE_VERSION=$(cat .tool-versions | grep nodejs | sed 's/^nodejs //')" >> $GITHUB_ENV
- uses: actions/setup-node#v2
with:
node-version: ${{ env.NODE_VERSION }}
- uses: bahmutov/npm-install#v1
- name: Install PostgreSQL client
run: |
sudo apt-get -yqq install libpq-dev postgresql-client
- name: Test Prep
env:
CI_NODE_INDEX: ${{ matrix.ci_node_index }}
run: |
bundle exec rake parallel:create["1"] parallel:load_schema["1"]
- name: Run tests
env:
RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
CI_NODE_TOTAL: ${{ matrix.ci_node_total }}
CI_NODE_INDEX: ${{ matrix.ci_node_index }}
run : |
bundle exec parallel_test spec/ -n $CI_NODE_TOTAL --only-group $CI_NODE_INDEX --type rspec
This was what I used to get it solved. Note: There are some other omitted parts such as the setup for ruby, postgresql, sqlite, etc.
name: "Lint and Test"
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 30
services:
redis:
image: redis
ports: ["6379:6379"]
postgres:
ports: ["5432:5432"]
steps:
//omitted setups
- name: Setup Parallel Database
env:
RAILS_ENV: test
PGHOST: localhost
PGUSER: postgres
run: |
cp config/database.yml.example config/database.yml
bundle exec rake parallel:create
bundle exec rake parallel:rake[db:schema:load] || true
- name: Build and test with rspec
env:
RAILS_ENV: test
PGHOST: localhost
PGUSER: postgres
APP_REDIS_URL: redis://localhost:6379
MINIMUM_COVERAGE: 80
run: |
bundle exec parallel_rspec --verbose spec
Since multiple databases is still a relatively fresh topic on Rails I wasn't able to find good resources on how to integrate them with my github actions. As long as I had single database in my app those configs we correct:
name: CI
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:11
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: root
POSTGRES_DB: db_test
ports: ['5432:5432']
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout#v1
- name: Set up Ruby 2.6
uses: actions/setup-ruby#v1
with:
ruby-version: 2.6.x
- name: Build and test with Rake
env:
PGHOST: 127.0.0.1
PGUSER: postgres
PGPASSWORD: root
RAILS_ENV: test
run: |
sudo apt-get -yqq install libpq-dev
gem install bundler
bundle install --jobs 4 --retry 3
bundle exec rake db:test:prepare
bundle exec rails test
However after implementing a second db I got this error:
TypeError: no implicit conversion of nil into String
/opt/hostedtoolcache/Ruby/2.6.6/x64/bin/bundle:23:in load' /opt/hostedtoolcache/Ruby/2.6.6/x64/bin/bundle:23:in ' Tasks:
TOP => db:test:load => db:test:purge (See full trace by running task
with --trace) Error: Process completed with exit code 1.
I'm almost 100% positive that this error is related to the lack of credentials for the second db in my github action file. How can I fix it and include both my dbs there?
I am trying to use GitHub Actions to fire up a Postgres container for my tests. I have a script called build.sh that gets called when npm run build is called via GitHub actions. This script calls upon restore-schema.sh (shown below).
The issue here is when restore-schema.sh gets ran, I keep getting Error: no such container: postgres. GitHub actions is naming the container some arbitrary string. Is there not a way I can run docker exec on an image or somehow name the postgres container that GitHub actions is creating? I've looked through both documentations to no avail.
How should I go about this? I noticed that in the Docker run ps screenshot, it shows command docker-entrypoint.sh. Should I use this instead? Do I specify the Dockerfile inside .github/workflows/?
I tried to include as much relevant information as possible - comment if you need any other information please.
Screenshots from GitHub Actions
Initialize containers
Docker run ps <- docker ps showing name postgres
Run npm run build --if-present <- WHERE THE ISSUE IS OCCURING
build.sh
#!/bin/sh
# Import core db schema
./.deploy/postgres/restore-schema.sh
.deploy/postgres/restore-schema.sh
#!/bin/sh
docker exec -it postgres psql \
--username postgres \
--password dev \
coredb < .deploy/postgres/db-schema.sql
.github/workflows/test-api-gateway.yml
name: API Gateway CI
on:
push:
branches: [ master ]
pull_request:
branches: [ master, develop ]
jobs:
build:
runs-on: ubuntu-latest
services: # Serivce containers to run with `container-job`
# Label used to access the service container
postgres:
# Docker Hub image
image: postgres
# Provide the password for postgres
env:
POSTGRES_USER: postgres
POSTGRES_DB: coredb
POSTGRES_PASSWORD: dev
# Set health checks to wait until postgres has started
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
strategy:
matrix:
node-version: [14.x]
steps:
- uses: actions/checkout#v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node#v1
with:
node-version: ${{ matrix.node-version }}
- run: docker ps
- run: chmod +x build.sh .deploy/postgres/restore-schema.sh
- run: npm ci
- run: npm run build --if-present
- run: npm test
Try the --name option
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
--name postgres
https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idservices
jobs.<job_id>.services.options: Additional Docker container resource options. For a list of options, see "docker create options."
Another solution I've seen is using last created container
docker exec -it $(docker ps --latest --quiet) bash
I have RSpec test suite which passes on my local machine.
However, when I run specs on CircleCI, it fails.
Here are the outputs:
1) Articles GET /articles/:id when article exists when article feedbacked behaves like success response and template behaves like normal request returns 200
Failure/Error: = javascript_pack_tag 'personal_comment/index'
ActionView::Template::Error:
Webpacker can't find personal_comment/index in /home/circleci/project/public/packs-test/manifest.json. Possible causes:
1. You want to set webpacker.yml value of compile to true for your environment
unless you are using the `webpack -w` or the webpack-dev-server.
2. webpack has not yet re-run to reflect updates.
3. You have misconfigured Webpacker's config/webpacker.yml file.
4. Your webpack configuration is not creating a manifest.
Your manifest contains:
{
}
Shared Example Group: "normal request" called from ./spec/support/requests/request_macros.rb:14
Shared Example Group: "success response and template" called from ./spec/requests/articles_spec.rb:19
# ./app/views/articles/feedbacked/show.html.haml:37:in `_app_views_articles_feedbacked_show_html_haml___803483453260433823_47067249050920'
It says our manifest is empty, but as far as I can confirm on my local machine it is not empty.
Here's our config file for CircleCI:
version: 2.1
references:
default_docker_ruby_executor: &default_docker_ruby_executor
image: circleci/ruby:2.6.5-stretch-node
environment:
BUNDLE_JOBS: 3
BUNDLE_RETRY: 3
BUNDLE_PATH: vendor/bundle
PGHOST: 127.0.0.1
PGUSER: root
PGPASSWORD: ""
RAILS_ENV: test
postgres: &postgres
image: circleci/postgres:11.6-alpine
environment:
POSTGRES_USER: root
POSTGRES_DB: app_test
POSTGRES_PASSWORD: ""
jobs:
build:
docker:
- *default_docker_ruby_executor
steps:
- checkout
# bundle cache
- restore_cache:
keys:
- app-bundle-v2-{{ checksum "Gemfile.lock" }}
- app-bundle-v2-
- run:
name: Bundle Install
command: bundle check || bundle install
# Store bundle cache
- save_cache:
key: rewrites-bundle-v2-{{ checksum "Gemfile.lock" }}
paths:
- vendor/bundle
# Only necessary if app uses webpacker or yarn in some other way
- restore_cache:
keys:
- app-yarn-{{ checksum "yarn.lock" }}
- app-yarn-
- run:
name: Yarn Install
command: yarn install --cache-folder ~/.cache/yarn
# Store yarn / webpacker cache
- save_cache:
key: app-yarn-{{ checksum "yarn.lock" }}
paths:
- ~/.cache/yarn
test:
parallelism: 2
docker:
- *default_docker_ruby_executor
- *postgres
steps:
- checkout
- restore_cache:
keys:
- app-bundle-v2-{{ checksum "Gemfile.lock" }}
- app-bundle-v2-
- run:
name: Bundle Install
command: bundle check || bundle install
- restore_cache:
keys:
- rewrites-yarn-{{ checksum "yarn.lock" }}
- rewrites-yarn-
- run:
name: Wait for DB
command: dockerize -wait tcp://localhost:5432 -timeout 1m
- run:
name: Database setup
command: bundle exec rails db:schema:load --trace
# Run rspec in parallel
- run:
command: |
mkdir /tmp/test-results
TESTFILES=$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)
bundle exec rspec $TESTFILES --profile 10 --format RspecJunitFormatter --out /tmp/test-results/rspec.xml --format progress
- store_test_results:
path: /tmp/test-results
- store_artifacts:
path: /tmp/test-results
destination: test-results
workflows:
version: 2
build_and_test:
jobs:
- build
- test:
requires:
- build
I think this is something related to Webpacker, but don't know what to do.
It seems like assets are not being compiled in CircleCI.
You may need to set NODE_ENV=test at the top, and another step to compile assets (which happen automatically in development, by default):
- run:
name: Build assets
command: bundle exec rails assets:precompile
This will run webpacker:compile in addition to some other tasks to configure youur environment correctly. Note, you will need config/webpack/test.js and a test section in config/webpacker.yaml. Looks like this documentation is not recorded here: https://circleci.com/docs/2.0/language-ruby/.
Some helpful links:
https://github.com/rails/webpacker#custom-rails-environments
https://prathamesh.tech/2019/08/26/understanding-webpacker-in-rails-6/