Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update docker infra and fix image building and publishing in CI #60

Merged
merged 1 commit into from
Apr 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 54 additions & 52 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,16 @@ jobs:
BUNDLE_JOBS: 3
BUNDLE_RETRY: 3
BUNDLE_PATH: vendor/bundle
PGHOST: 127.0.0.1
PGUSER: circleci-demo-ruby
PGPASSWORD: sekret
RAILS_ENV: test
NOKOGIRI_USE_SYSTEM_LIBRARIES: true
- image: circleci/postgres:11
environment:
POSTGRES_USER: postgres
POSTGRES_DB: suri
POSTGRES_PASSWORD: sekret

working_directory: ~/repo

Expand Down Expand Up @@ -47,25 +55,18 @@ jobs:
name: Which bundler?
command: bundle -v

- restore_cache:
keys:
- suri-rails-dependencies-{{ checksum "Gemfile.lock" }}
# fallback to using the latest cache if no exact match is found
- suri-rails-dependencies-

Comment on lines -50 to -55
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't want to cache because ...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ndushay Good question! This caching is messed up in a few ways. First, it uses different keys for restore and save (dor-services vs. suri-rails). Second, I don't believe the cache is persisted across runs. So, basically, I think this is copypasta from some of our other repos where caching has been useful (e.g., in our GoLang and React work), and I'm removing it from Ruby/Rails projects whenever I see it.

- run:
name: Install dependencies
command: bundle check || bundle install

- save_cache:
key: dor-services-app-bundle-v2-{{ checksum "Gemfile.lock" }}
paths:
- vendor/bundle

- run:
name: Run code linter & style checker
command: bundle exec rubocop

- run:
name: Wait for DB
command: dockerize -wait tcp://localhost:5432 -timeout 1m

- run:
name: Set up database
command: bin/rails db:test:prepare
Expand All @@ -88,51 +89,52 @@ jobs:
build-image:
executor: docker-publisher
steps:
- checkout
- setup_remote_docker
- run:
name: Build Docker image
command: |
docker build -t $IMAGE_NAME:latest .
- run:
name: Archive Docker image
command: |
docker save -o app_image.tar $IMAGE_NAME
- persist_to_workspace:
root: .
paths:
- ./app_image.tar
- checkout
- setup_remote_docker
- run:
name: Build Docker image
command: |
docker build -t $IMAGE_NAME:latest .
- run:
name: Archive Docker image
command: |
docker save -o app_image.tar $IMAGE_NAME
- persist_to_workspace:
root: .
paths:
- ./app_image.tar
publish-latest:
executor: docker-publisher
steps:
- attach_workspace:
at: /tmp/workspace
- setup_remote_docker
- run:
name: Load archived Docker image
command: |
docker load -i /tmp/workspace/app_image.tar
- run:
name: Publish Docker Image to Docker Hub
command: |
echo "$DOCKER_PASS" | docker login -u "$DOCKER_USER" --password-stdin
docker push $IMAGE_NAME:latest
- attach_workspace:
at: /tmp/workspace
- setup_remote_docker
- run:
name: Load archived Docker image
command: |
docker load -i /tmp/workspace/app_image.tar
- run:
name: Publish Docker Image to Docker Hub
command: |
echo "$DOCKER_PASS" | docker login -u "$DOCKER_USER" --password-stdin
docker push $IMAGE_NAME:latest
publish-tag:
executor: docker-publisher
steps:
- attach_workspace:
at: /tmp/workspace
- setup_remote_docker
- run:
name: Load archived Docker image
command: |
docker load -i /tmp/workspace/app_image.tar
- run:
name: Publish Docker Image to Docker Hub
command: |
echo "$DOCKER_PASS" | docker login -u "$DOCKER_USER" --password-stdin
docker tag $IMAGE_NAME:latest $IMAGE_NAME:$CIRCLE_TAG
docker push $IMAGE_NAME:$CIRCLE_TAG
- attach_workspace:
at: /tmp/workspace
- setup_remote_docker
- run:
name: Load archived Docker image
command: |
docker load -i /tmp/workspace/app_image.tar
- run:
name: Publish Docker Image to Docker Hub
command: |
echo "$DOCKER_PASS" | docker login -u "$DOCKER_USER" --password-stdin
docker tag $IMAGE_NAME:latest $IMAGE_NAME:$CIRCLE_TAG
docker push $IMAGE_NAME:$CIRCLE_TAG

workflows:
version: 2

Expand All @@ -148,7 +150,7 @@ workflows:
only: master
- publish-latest:
requires:
- build-image
- build-image
filters:
branches:
only: master
Expand All @@ -162,7 +164,7 @@ workflows:
ignore: /.*/
- publish-tag:
requires:
- build-image
- build-image
filters:
tags:
only: /^[0-9]+\.[0-9]+\.[0-9]+/
Expand Down
8 changes: 8 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.git
.dockerignore
.byebug_history
log
tmp
coverage
# Required for puma to have a place to put the pid file
!tmp/pids/.keep
23 changes: 23 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,36 @@ Metrics/BlockLength:
Exclude:
- 'spec/**/*.rb'

Metrics/MethodLength:
Exclude:
- 'bin/bundle'

Metrics/CyclomaticComplexity:
Exclude:
- 'bin/bundle'

Metrics/PerceivedComplexity:
Exclude:
- 'bin/bundle'

Metrics/AbcSize:
Exclude:
- 'bin/bundle'

Layout/LineLength:
Exclude:
- 'bin/bundle'

Style/MixinUsage:
Exclude:
- 'bin/**/*'

RSpec/MultipleExpectations:
Max: 5

RSpec/ExampleLength:
Enabled: false

Style/HashEachMethods:
Enabled: true

Expand Down
26 changes: 17 additions & 9 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
FROM ruby:2.7.0-alpine
FROM ruby:2.7.1-alpine

LABEL maintainer="Stanford Libraries Infrastructure Team <[email protected]>"

RUN apk update && apk add build-base sqlite-dev tzdata git
RUN apk add --update --no-cache \
build-base \
git \
postgresql-dev \
postgresql-client \
libxml2-dev \
libxslt-dev \
tzdata

RUN mkdir /app
WORKDIR /app

COPY Gemfile Gemfile.lock ./
RUN gem install bundler -v 2.0.2
RUN bundle install
RUN gem update --system && \
gem install bundler && \
bundle config build.nokogiri --use-system-libraries

COPY . .
COPY Gemfile Gemfile.lock ./

RUN bundle exec rails db:setup
RUN bundle config set without 'production' && bundle install

LABEL maintainer="Justin Coyne <[email protected]>"
COPY . .

CMD puma -C config/puma.rb
CMD ["./docker/invoke.sh"]
2 changes: 0 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ group :development, :test do
gem 'rubocop-performance'
gem 'rubocop-rails'
gem 'rubocop-rspec'
# Use sqlite3 as the database for Active Record
gem 'simplecov', '~> 0.17.1' # 0.18 breaks reporting https://github.com/codeclimate/test-reporter/issues/418
gem 'sqlite3', '~> 1.4'
end

group :development do
Expand Down
2 changes: 0 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,6 @@ GEM
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
sqlite3 (1.4.2)
sshkit (1.21.0)
net-scp (>= 1.1.2)
net-ssh (>= 2.8.0)
Expand Down Expand Up @@ -273,7 +272,6 @@ DEPENDENCIES
simplecov (~> 0.17.1)
spring
spring-watcher-listen (~> 2.0.0)
sqlite3 (~> 1.4)

BUNDLED WITH
2.1.4
32 changes: 20 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ NOTE: This is currently used for running specs; we still use https://github.com/

Clone the repository

$ git clone [email protected]:sul-dlss/suri_rails.git
$ git clone [email protected]:sul-dlss/suri-rails.git

Change directories into the app and install dependencies

Expand All @@ -32,27 +32,35 @@ Start the development server

## Testing

First, ensure the database container is spun up:

$ docker-compose up db # use -d to daemonize/run in background

And if you haven't yet prepared the test database, run:

$ bin/rails db:setup

The test suite (with RuboCop style enforcement) will be run with the default rake task (also run on CI).

$ rake
$ bin/rake

The specs can be run without RuboCop enforcement

$ rake spec
$ bin/rake spec

The RuboCop style enforcement can be run without running the tests

$ rake rubocop
$ bin/rake rubocop

## Building for Docker

```shell
$ docker build -t suldlss/suri-rails:latest .
```
Spin up the application and its database:

$ docker-compose up --build

## Updating Docker Image

Then run as:
```shell
$ docker run -d -p 127.0.0.1:3002:3000 suldlss/suri-rails:latest
```
Note that CI is configured to automatically update the image hosted on DockerHub on every commit to `master`. If you want to build and push an image manually, run:

Note that CI is configured to automatically update the image hosted on DockerHub on every commit to `master`.
$ docker build -t suldlss/suri-rails:latest .
$ docker push suldlss/suri-rails:latest
30 changes: 25 additions & 5 deletions app/controllers/identifiers_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,49 @@

class IdentifiersController < ApplicationController
# GET /identifiers
# GET /identifiers.json
def index
@identifiers = Identifier.all

render json: @identifiers
end

# GET /identifiers/1
# GET /identifiers/1.json
def show
@identifier = Identifier.find_by(identifier: params[:id])
@identifier = Identifier.find_by!(identifier: params[:id])
render json: @identifier
rescue ActiveRecord::RecordNotFound
render build_error("Identifier not found: #{params[:id]}", :not_found)
end

# POST /identifiers
# POST /identifiers.json
def create
@identifier = Identifier.mint

if @identifier
render plain: @identifier.identifier, status: :created, location: @identifier
else
render json: { error: 'Unable to mint a druid' }, status: :internal_server_error
render build_error('Unable to mint a druid', :internal_server_error)
end
end

private

# rubocop:disable Metrics/MethodLength
# JSON-API error response
def build_error(msg, status)
{
json: {
errors: [
{
"status": Rack::Utils::SYMBOL_TO_STATUS_CODE[status].to_s,
"title": msg,
"detail": msg
}
]
},
content_type: 'application/vnd.api+json',
status: status
}
end
# rubocop:enable Metrics/MethodLength
end
Loading