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

Compability, Versioning and Upgrading Penthouse and Using Docker & CircleCI for Developer Experience #16

Merged
merged 12 commits into from
Jul 21, 2020
Merged
26 changes: 26 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
version: 2
jobs:
build:
docker:
- image: circleci/ruby:2.4.1

- image: circleci/postgres:9.6.2-alpine
name: postgres

steps:
- checkout

- run: bundle install
- run: bundle exec standardrb
- run: rm Gemfile.lock

- run: RUBY_VERSION=2.4.1 RAILS_VERSION=4.2.11.1 PG_VERSION=0.21.0 bundle install
- run: RUBY_VERSION=2.4.1 RAILS_VERSION=4.2.11.1 PG_VERSION=0.21.0 bundle exec rspec
- run: rm Gemfile.lock

- run: RUBY_VERSION=2.4.1 RAILS_VERSION=5.1.7 PG_VERSION=0.21.0 bundle install
- run: RUBY_VERSION=2.4.1 RAILS_VERSION=5.1.7 PG_VERSION=0.21.0 bundle exec rspec
- run: rm Gemfile.lock

- run: RUBY_VERSION=2.4.1 RAILS_VERSION=5.2.3 PG_VERSION=0.21.0 bundle install
- run: RUBY_VERSION=2.4.1 RAILS_VERSION=5.2.3 PG_VERSION=0.21.0 bundle exec rspec
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Gemfile.lock
1 change: 0 additions & 1 deletion .ruby-version

This file was deleted.

22 changes: 22 additions & 0 deletions Dockerfile.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
ARG RUBY_VERSION="2.5"

FROM ruby:$RUBY_VERSION-alpine

ARG RUBY_VERSION="2.5"
ARG RAILS_VERSION="5.1.4"
ARG PG_VERSION="1.1.4"

RUN apk add --update build-base postgresql-dev tzdata git

WORKDIR /app
ADD ./ /app/

RUN gem install bundler -v '1.17'

ENV RUBY_VERSION=$RUBY_VERSION
ENV RAILS_VERSION=$RAILS_VERSION
ENV PG_VERSION=$PG_VERSION

RUN RUBY_VERSION=$RUBY_VERSION RAILS_VERSION=$RAILS_VERSION PG_VERSION=$PG_VERSION bundle install --jobs=4 --no-cache

ENTRYPOINT ["bundle", "exec", "rspec"]
11 changes: 9 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
source 'https://rubygems.org'
ruby '2.5.7'
source "https://rubygems.org"
ruby ENV.fetch("RUBY_VERSION", "2.3.0")

group :test do
gem "activesupport", ENV.fetch("RAILS_VERSION", "4.2.2").to_s
gem "activerecord", ENV.fetch("RAILS_VERSION", "4.2.2").to_s
gem "pg", ENV.fetch("PG_VERSION", "0.19.0").to_s
end

gemspec
18 changes: 9 additions & 9 deletions Guardfile
Original file line number Diff line number Diff line change
Expand Up @@ -41,26 +41,26 @@ guard :rspec, cmd: "bundle exec rspec", failed_mode: :focus do
dsl.watch_spec_files_for(ruby.lib_files)

# Rails files
rails = dsl.rails(view_extensions: %w(erb haml slim))
rails = dsl.rails(view_extensions: %w[erb haml slim])
dsl.watch_spec_files_for(rails.app_files)
dsl.watch_spec_files_for(rails.views)

watch(rails.controllers) do |m|
[
rspec.spec.("routing/#{m[1]}_routing"),
rspec.spec.("controllers/#{m[1]}_controller"),
rspec.spec.("acceptance/#{m[1]}")
rspec.spec.call("routing/#{m[1]}_routing"),
rspec.spec.call("controllers/#{m[1]}_controller"),
rspec.spec.call("acceptance/#{m[1]}")
]
end

# Rails config changes
watch(rails.spec_helper) { rspec.spec_dir }
watch(rails.routes) { "#{rspec.spec_dir}/routing" }
watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" }
watch(rails.spec_helper) { rspec.spec_dir }
watch(rails.routes) { "#{rspec.spec_dir}/routing" }
watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" }

# Capybara features specs
watch(rails.view_dirs) { |m| rspec.spec.("features/#{m[1]}") }
watch(rails.layouts) { |m| rspec.spec.("features/#{m[1]}") }
watch(rails.view_dirs) { |m| rspec.spec.call("features/#{m[1]}") }
watch(rails.layouts) { |m| rspec.spec.call("features/#{m[1]}") }

# Turnip features and steps
watch(%r{^spec/acceptance/(.+)\.feature$})
Expand Down
21 changes: 21 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
test-4.2.11.1: # Test rails 4 LTS
RUBY_VERSION=2.3.0 RAILS_VERSION=4.2.11.1 PG_VERSION=0.21.0 docker-compose build
RUBY_VERSION=2.3.0 RAILS_VERSION=4.2.11.1 PG_VERSION=0.21.0 docker-compose run penthouse

test-5.1.7: # Test rails 5 before migration context
RUBY_VERSION=2.4.0 RAILS_VERSION=5.1.7 PG_VERSION=0.21.0 docker-compose build
RUBY_VERSION=2.4.0 RAILS_VERSION=5.1.7 PG_VERSION=0.21.0 docker-compose run penthouse

test-5.2.3: # Test rails 5 with migration context
RUBY_VERSION=2.5.0 RAILS_VERSION=5.2.3 PG_VERSION=1.1.4 docker-compose build
RUBY_VERSION=2.5.0 RAILS_VERSION=5.2.3 PG_VERSION=1.1.4 docker-compose run penthouse

test-6.0.0: # Test rails 6
RUBY_VERSION=2.6.0 RAILS_VERSION=6.0.0 PG_VERSION=1.1.4 docker-compose build
RUBY_VERSION=2.6.0 RAILS_VERSION=6.0.0 PG_VERSION=1.1.4 docker-compose run penthouse

test:
make test-4.2.11.1
make test-5.1.7
make test-5.2.3
make test-6.0.0
50 changes: 50 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
# Penthouse

[![Codeship Status](https://codeship.com/projects/c6513ab0-cc05-0133-94c6-0666c337ff82/status?branch=master)](https://codeship.com/projects/140114) [![Code Climate](https://codeclimate.com/github/ryantownsend/penthouse/badges/gpa.svg)](https://codeclimate.com/github/ryantownsend/penthouse) [![RubyDocs](https://img.shields.io/badge/rubydocs-click_here-blue.svg)](http://www.rubydoc.info/github/ryantownsend/penthouse)

Penthouse is an alternative to the excellent [Apartment gem](https://github.com/influitive/apartment) – however Penthouse is more of a framework for multi-tenancy than a library, in that it provides less out-of-the-box functionality, but should make for easier customisation.

- [Penthouse](#penthouse)
- [Installation](#installation)
- [Basic Usage](#basic-usage)
- [Octopus (shard) Usage](#octopus-shard-usage)
- [ActiveJob](#activejob)
- [Sidekiq](#sidekiq)
- [Dictionary](#dictionary)
- [Contributing](#contributing)
- [Testing](#testing)
- [CI/Local](#cilocal)
- [Without Circle](#without-circle)

## Installation

Add this line to your application's Gemfile:
Expand Down Expand Up @@ -80,3 +94,39 @@ require 'penthouse/sidekiq'
## Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/ryantownsend/penthouse.

## Testing

### CI/Local

We use circle,a dn it can be used locally with docker. See:

- [running circle locally](https://circleci.com/docs/2.0/local-cli/)
- [Using postgres with circle](https://circleci.com/docs/2.0/postgres-config/)

```bash
echo <circle-api-token> | circleci setup
circleci local execute
```

### Without Circle

Docker is used for isolated testing. To test all supported versions run:

```bash
make test
```

For specific versions see the `Makefile`.

Alternatively you can tets any version locally with:

```
export RUBY_VERSION=2.5.0
rbenv local $RUBY_VERSION

RUBY_VERSION=$RUBY_VERSION RAILS_VERSION=4.2.11.1 PG_VERSION=0.21.0 bundle install
RUBY_VERSION=$RUBY_VERSION RAILS_VERSION=4.2.11.1 PG_VERSION=0.21.0 bundle exec rsepc
```


30 changes: 30 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
version: '3.5'

services:
postgres:
image: postgres:10.5-alpine
ports:
- 5432
networks:
penthouse:
default:

penthouse:
build:
context: .
dockerfile: Dockerfile.test
args:
RUBY_VERSION: ${RUBY_VERSION:-2.5.0}
RAILS_VERSION: ${RAILS_VERSION:-5.1.7}
PG_VERSION: ${PG_VERSION:-1.1.4}
RAILS_ENV: test
networks:
penthouse:
default:
depends_on:
- postgres

networks:
penthouse:
driver: bridge
name: penthouse
16 changes: 8 additions & 8 deletions lib/penthouse.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

module Penthouse
class TenantNotFound < RuntimeError; end
CURRENT_TENANT_KEY = 'penthouse_tenant'.freeze
CURRENT_TENANT_KEY = "penthouse_tenant".freeze

class << self
# Retrieves the currently active tenant identifier
Expand All @@ -29,7 +29,7 @@ def tenant=(tenant_identifier)
# @param block [Block] the code to execute
# @yield [String, Symbol] the identifier for the tenant
# @return [void]
def with_tenant(tenant_identifier:, default_tenant: self.tenant, &block)
def with_tenant(tenant_identifier:, default_tenant: tenant, &block)
self.tenant = tenant_identifier
block.yield(tenant_identifier)
ensure
Expand All @@ -43,7 +43,7 @@ def with_tenant(tenant_identifier:, default_tenant: self.tenant, &block)
# @param block [Block] the code to execute
# @yield [String, Symbol] the identifier for the tenant
# @return [void]
def each_tenant(tenant_identifiers: self.tenant_identifiers, runner: self.configuration.runner, &block)
def each_tenant(tenant_identifiers: self.tenant_identifiers, runner: configuration.runner, &block)
tenant_identifiers.each do |tenant_identifier|
switch(tenant_identifier: tenant_identifier, runner: runner, &block)
end
Expand All @@ -55,15 +55,15 @@ def each_tenant(tenant_identifiers: self.tenant_identifiers, runner: self.config
# @param block [Block] the code to execute
# @yield [Penthouse::Tenants::BaseTenant] the tenant instance
# @return [void]
def switch(tenant_identifier:, runner: self.configuration.runner, &block)
def switch(tenant_identifier:, runner: configuration.runner, &block)
runner.call(tenant_identifier: tenant_identifier, &block)
end

# Loads the tenant and creates their data store
# @param tenant_identifier [String, Symbol] the identifier for the tenant
# @see Penthouse::Tenants::BaseTenant#delete
# @return [void]
def create(tenant_identifier:, runner: self.configuration.runner, **options)
def create(tenant_identifier:, runner: configuration.runner, **options)
switch(tenant_identifier: tenant_identifier, runner: runner) do |tenant|
tenant.create(**options)
end
Expand All @@ -73,7 +73,7 @@ def create(tenant_identifier:, runner: self.configuration.runner, **options)
# @param tenant_identifier [String, Symbol] the identifier for the tenant
# @see Penthouse::Tenants::BaseTenant#delete
# @return [void]
def delete(tenant_identifier:, runner: self.configuration.runner, **options)
def delete(tenant_identifier:, runner: configuration.runner, **options)
switch(tenant_identifier: tenant_identifier, runner: runner) do |tenant|
tenant.delete(**options)
end
Expand All @@ -84,9 +84,9 @@ def delete(tenant_identifier:, runner: self.configuration.runner, **options)
# @return [void]
def configure(&block)
# allow the configuration by the block
block.yield(self.configuration)
block.yield(configuration)
# prevent modification of configuration once set
self.configuration.freeze
configuration.freeze
end

# Returns the current configuration of Penthouse
Expand Down
4 changes: 2 additions & 2 deletions lib/penthouse/active_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ module ActiveJob

class_methods do
def execute(job_data)
Penthouse.switch(job_data['tenant']) do
Penthouse.switch(job_data["tenant"]) do
super
end
end
end

def serialize
super.merge('tenant' => Penthouse.tenant)
super.merge("tenant" => Penthouse.tenant)
end
end
end
2 changes: 1 addition & 1 deletion lib/penthouse/app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
# application within that tenant.
#

require 'rack/request'
require "rack/request"

module Penthouse
class App
Expand Down
14 changes: 7 additions & 7 deletions lib/penthouse/migrator.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
require 'active_record'
require 'active_support/core_ext/module/aliasing'
require "active_record"
require "active_support/core_ext/module/aliasing"

module Penthouse
module Migration
Expand All @@ -19,7 +19,7 @@ def announce_with_penthouse(message)
end

def current_tenant
"Tenant: #{Penthouse.tenant || '*** global ***'}"
"Tenant: #{Penthouse.tenant || "*** global ***"}"
end
end
end
Expand All @@ -45,9 +45,9 @@ class << self

# override any new Octopus methods with the new Penthouse ones
alias_method :migrate_with_octopus, :migrate_with_penthouse
alias_method :up_with_octopus, :up_with_penthouse
alias_method :down_with_octopus, :down_with_penthouse
alias_method :run_with_octopus, :run_with_penthouse
alias_method :up_with_octopus, :up_with_penthouse
alias_method :down_with_octopus, :down_with_penthouse
alias_method :run_with_octopus, :run_with_penthouse
end

alias_method :migrate_without_penthouse, :migrate
Expand All @@ -57,7 +57,7 @@ class << self
alias_method :migrations, :migrations_with_penthouse

# override any new Octopus methods with the new Penthouse ones
alias_method :migrate_with_octopus, :migrate_with_penthouse
alias_method :migrate_with_octopus, :migrate_with_penthouse
alias_method :migrations_with_octopus, :migrations_with_penthouse
end
end
Expand Down
2 changes: 0 additions & 2 deletions lib/penthouse/routers/base_router.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,13 @@
module Penthouse
module Routers
class BaseRouter

# @abstract typically used by the App to receive a request and return a tenant that can be switched to
# @param request [Rack::Request] The request from the Rack app, used to determine the tenant
# @return [String, Symbol] A tenant identifier
# @raise [Penthouse::TenantNotFound] if the tenant cannot be found/switched to
def self.call(request)
raise NotImplementedError
end

end
end
end
2 changes: 0 additions & 2 deletions lib/penthouse/routers/subdomain_router.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,12 @@
module Penthouse
module Routers
class SubdomainRouter < BaseRouter

# Determines the tenant identifier based on the sub-domain of the request
# @param request [Rack::Request] The request from the Rack app, used to determine the tenant
# @return [String, Symbol] A tenant identifier
def self.call(request)
request.host.split(".").first
end

end
end
end
Loading