Skip to content

Commit

Permalink
Merge cf37db3 into 9a9b50e
Browse files Browse the repository at this point in the history
  • Loading branch information
simonprev committed Jan 10, 2019
2 parents 9a9b50e + cf37db3 commit a4838a9
Show file tree
Hide file tree
Showing 25 changed files with 621 additions and 82 deletions.
12 changes: 12 additions & 0 deletions .dockerignore
@@ -0,0 +1,12 @@
_build/
.git/
webapp/node_modules/
priv/static/webapp
deps/
test/

.*
docker-compose.yml
Makefile
README.md
Dockerfile
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -25,4 +25,5 @@ test.json
priv/static/webapp
/webapp/node_modules
/webapp/tmp
/webapp/dist
.elixir_ls
77 changes: 77 additions & 0 deletions Dockerfile
@@ -0,0 +1,77 @@
#
# Step 1 - Build the OTP binary
#
FROM elixir:1.7.4-alpine AS builder

ARG APP_NAME
ARG APP_VERSION
ARG MIX_ENV=prod

ENV APP_NAME=${APP_NAME} \
APP_VERSION=${APP_VERSION} \
MIX_ENV=${MIX_ENV}

WORKDIR /build

# This step installs all the build tools we'll need
RUN apk update && \
apk upgrade --no-cache && \
apk add --no-cache nodejs npm git build-base python yaml-dev

RUN mix local.rebar --force && \
mix local.hex --force

# This copies our app source code into the build container
COPY mix.* ./
RUN mix deps.get --only ${MIX_ENV}
RUN mix deps.compile

COPY . .
RUN mix compile
RUN mix phx.digest

RUN mkdir -p /opt/build && \
mix release --verbose && \
cp _build/${MIX_ENV}/rel/${APP_NAME}/releases/${APP_VERSION}/${APP_NAME}.tar.gz /opt/build

RUN cd /opt/build && \
tar -xzf ${APP_NAME}.tar.gz && \
rm ${APP_NAME}.tar.gz

COPY webapp /opt/build/webapp

RUN cd /opt/build && \
npm ci --prefix webapp --no-audit --no-color

#
# Step 2 - Build a lean runtime container
#
FROM alpine:3.8

ARG APP_NAME
ARG APP_VERSION
ENV APP_NAME=${APP_NAME} \
APP_VERSION=${APP_VERSION}

# Update kernel and install runtime dependencies
RUN apk --no-cache update && \
apk --no-cache upgrade && \
apk --no-cache add bash openssl yaml-dev nodejs npm

WORKDIR /opt/accent

# Copy the OTP binary from the build step
COPY --from=builder /opt/build .

# Copy the entrypoint script
COPY priv/scripts/docker-entrypoint.sh /usr/local/bin
RUN chmod a+x /usr/local/bin/docker-entrypoint.sh

# Create a non-root user
RUN adduser -D accent && \
chown -R accent: /opt/accent

USER accent

ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["foreground"]
122 changes: 122 additions & 0 deletions Makefile
@@ -0,0 +1,122 @@
# Configuration
# -------------

APP_NAME ?= `grep 'app:' mix.exs | sed -e 's/\[//g' -e 's/ //g' -e 's/app://' -e 's/[:,]//g'`
APP_VERSION ?= `grep 'version:' mix.exs | cut -d '"' -f2`
DOCKER_IMAGE_TAG ?= latest
GIT_REVISION ?= `git rev-parse HEAD`

# Introspection targets
# ---------------------

.PHONY: help
help: header targets

.PHONY: header
header:
@echo "\033[34mEnvironment\033[0m"
@echo "\033[34m---------------------------------------------------------------\033[0m"
@printf "\033[33m%-23s\033[0m" "APP_NAME"
@printf "\033[35m%s\033[0m" $(APP_NAME)
@echo ""
@printf "\033[33m%-23s\033[0m" "APP_VERSION"
@printf "\033[35m%s\033[0m" $(APP_VERSION)
@echo ""
@printf "\033[33m%-23s\033[0m" "GIT_REVISION"
@printf "\033[35m%s\033[0m" $(GIT_REVISION)
@echo ""
@printf "\033[33m%-23s\033[0m" "DOCKER_IMAGE_TAG"
@printf "\033[35m%s\033[0m" $(DOCKER_IMAGE_TAG)
@echo "\n"

.PHONY: targets
targets:
@echo "\033[34mTargets\033[0m"
@echo "\033[34m---------------------------------------------------------------\033[0m"
@perl -nle'print $& if m{^[a-zA-Z_-]+:.*?## .*$$}' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-22s\033[0m %s\n", $$1, $$2}'

# Build targets
# -------------

.PHONY: dependencies
dependencies: dependencies-mix dependencies-npm ## Install dependencies required by the application

.PHONY: dependencies-mix
dependencies-mix:
mix deps.get --force

.PHONY: dependencies-npm
dependencies-npm:
npm install --prefix webapp

.PHONY: build
build: ## Build the Docker image for the OTP release
docker build --build-arg APP_NAME=$(APP_NAME) --build-arg APP_VERSION=$(APP_VERSION) --rm --tag $(APP_NAME):$(DOCKER_IMAGE_TAG) .

# CI targets
# ----------

.PHONY: lint
lint: lint-compile lint-format lint-credo lint-eslint lint-stylelint lint-prettier ## Run lint tools on the code

.PHONY: lint-compile
lint-compile:
mix compile --warnings-as-errors --force

.PHONY: lint-format
lint-format:
mix format --dry-run --check-formatted

.PHONY: lint-credo
lint-credo:
mix credo --strict

.PHONY: lint-eslint
lint-eslint:
./assets/node_modules/.bin/eslint --ignore-path webapp/.eslintignore --config webapp/.eslintrc webapp

.PHONY: lint-stylelint
lint-stylelint:
./assets/node_modules/.bin/stylelint --syntax scss --config webapp/.stylelintrc webapp/css

.PHONY: lint-prettier
lint-prettier:
./assets/node_modules/.bin/prettier --single-quote --list-different --no-bracket-spacing --print-width 130 './webapp/app/**/*.{js,gql}'

.PHONY: test
test: ## Run the test suite
mix test

.PHONY: test-coverage
test-coverage: ## Generate the code coverage report
mix coveralls

.PHONY: format
format: format-elixir format-prettier ## Run formatting tools on the code

.PHONY: format-elixir
format-elixir:
mix format

.PHONY: format-prettier
format-prettier:
./assets/node_modules/.bin/prettier --single-quote --write --no-bracket-spacing --print-width 130 './webapp/app/**/*.{js,gql}'

# Development targets
# -------------------

.PHONY: dev-start-postgresql
dev-start-postgresql: ## Run a PostgreSQL server inside of a Docker Compose environment
docker-compose up --detach postgresql

.PHONY: dev-start-application
dev-start-application: ## Run the OTP release inside of a Docker Compose environment
docker-compose up application

.PHONY: dev-start
dev-start: ## Start every service of in the Docker Compose environment
docker-compose up

.PHONY: dev-stop
dev-stop: ## Stop every service of in the Docker Compose environment
docker-compose down
43 changes: 31 additions & 12 deletions README.md
Expand Up @@ -18,15 +18,15 @@ The Accent API provides a powerful abstraction around the process of translating

## Contents

| Section | Description |
|---------------------------------------------------------|------------------------------------------------------------------------|
| [🚧 Requirements](#-requirements) | Dependencies required to run Accent’ stack |
| [🎛 Mix commands](#-executing-mix-commands) | How to execute mix task with the Twelve-Factor pattern |
| [🏎 Quickstart](#-quickstart) | Steps to run the project, from API to webapp |
| [🌳 Environment variables](#-environment-variables) | Required and optional env var used |
| [✅ Tests](#-tests) | How to run the extensive tests suite |
| [🚀 Heroku](#-heroku) | Easy deployment setup with Heroku |
| [🌎 Contribute](#-contribute) | How to contribute to this repo |
| Section | Description |
|---------------------------------------------------------|---------------------------------------------------------------------------|
| [🚧 Requirements](#-requirements) | Dependencies required to run Accent’ stack |
| [🎛 Mix commands](#-executing-mix-commands) | How to execute mix task with the Twelve-Factor pattern |
| [🏎 Quickstart](#-quickstart) | Steps to run the project, from API to webapp, with or without Docker |
| [🌳 Environment variables](#-environment-variables) | Required and optional env var used |
| [✅ Tests](#-tests) | How to run the extensive tests suite |
| [🚀 Heroku](#-heroku) | Easy deployment setup with Heroku |
| [🌎 Contribute](#-contribute) | How to contribute to this repo |

## 🚧 Requirements

Expand Down Expand Up @@ -56,15 +56,34 @@ $ nv .env mix <mix command>

## 🏎 Quickstart

_This is the full development setup. To simply run the app, see the *Docker* instructions_

1. If you don’t already have it, install `nodejs` with `brew install nodejs`
2. If you don’t already have it, install `elixir` with `brew install elixir`
3. If you don’t already have it, install `libyaml` with `brew install libyaml`
4. If you don’t already have it, install `postgres` with `brew install postgres` or the [macOS app](https://postgresapp.com/)
5. Install dependencies with `mix deps.get` and `npm --prefix webapp install`
5. Install dependencies with `make dependencies`
6. Create and migrate your database with `mix ecto.setup`
7. Start Phoenix endpoint with `mix phx.server`
8. Start Ember server with `npm --prefix webapp run start`
9. That’s it!
8. Start Ember server with `npm run start --prefix webapp`

*That’s it!*

### Makefile

The Makefile should be the main entry for common tasks such as tests, linting, Docker, etc. This simplify the developpement process since you don’t have to search for which service provides which command. `mix`, `npm`, `prettier`, `docker`, `stylelint`, etc are all used in the Makefile.

### Docker

For the production setup, we use Docker to build an OTP release of the app. With docker-compose, you can run the image locally. Here are the steps to have a working app running locally with Docker:

_When running the production env, you need to provide a valid GOOGLE_API_CLIENT_ID in the `docker-compose.yml` file._

1. Run `make build` to build the OTP release with Docker
2. Run `make dev-start-postgresql` to start an instance of Postgresql. The instance will run on port 5432 with the `postgres` user. You can change those values in the `docker-compose.yml` file.
3. Run `make dev-start-application` to start the app! The release hook of the release will execute migrations and seeds before starting the webserver on port 4000 (again you can change the settings in `docker-compose.yml`)

*That’s it! You now have a working Accent instance without installing Elixir or Node!*

## 🌳 Environment variables

Expand Down
62 changes: 2 additions & 60 deletions config/config.exs
@@ -1,65 +1,7 @@
use Mix.Config

defmodule Utilities do
def string_to_boolean("true"), do: true
def string_to_boolean("1"), do: true
def string_to_boolean(_), do: false
end

# Used to extract schema json with the absinthe’s mix task
config :absinthe, :schema, Accent.GraphQL.Schema

# Configures the endpoint
config :accent, Accent.Endpoint,
root: Path.expand("..", __DIR__),
http: [port: System.get_env("PORT")],
url: [host: System.get_env("CANONICAL_HOST") || "localhost"],
secret_key_base: System.get_env("SECRET_KEY_BASE"),
render_errors: [accepts: ~w(json)],
pubsub: [name: Accent.PubSub, adapter: Phoenix.PubSub.PG2]

# Configure your database
config :accent, :ecto_repos, [Accent.Repo]

config :accent, Accent.Repo,
adapter: Ecto.Adapters.Postgres,
timeout: 30_000,
url: System.get_env("DATABASE_URL") || "postgres://localhost/accent_development"

config :accent,
force_ssl: Utilities.string_to_boolean(System.get_env("FORCE_SSL")),
hook_broadcaster: Accent.Hook.Broadcaster,
dummy_provider_enabled: true,
restricted_domain: System.get_env("RESTRICTED_DOMAIN")

# Configures canary custom handlers and repo
config :canary,
repo: Accent.Repo,
unauthorized_handler: {Accent.ErrorController, :handle_unauthorized},
not_found_handler: {Accent.ErrorController, :handle_not_found}

# Configures Elixir's Logger
config :logger, :console,
format: "$time $metadata[$level] $message\n",
metadata: [:request_id]

# Configure Phoenix
config :phoenix, Accent.Router, host: System.get_env("CANONICAL_HOST")
config :phoenix, :json_library, Jason

config :phoenix, :generators,
migration: true,
binary_id: false

# Configures sentry to report errors
config :sentry,
dsn: System.get_env("SENTRY_DSN"),
environment_name: System.get_env("SENTRY_ENVIRONMENT_NAME") || Mix.env(),
included_environments: [:prod],
root_source_code_path: File.cwd!()

# Configure mailer
import_config "mailer.exs"
# Import release config
import_config "../rel/config/config.exs"

# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
Expand Down
7 changes: 6 additions & 1 deletion config/prod.exs
@@ -1,6 +1,11 @@
use Mix.Config

config :accent, Accent.Endpoint, check_origin: false
config :accent, Accent.Endpoint,
check_origin: false,
server: true,
root: ".",
cache_static_manifest: "priv/static/cache_manifest.json"

config :accent, dummy_provider_enabled: false

config :logger, level: :info
5 changes: 5 additions & 0 deletions coveralls.json
@@ -0,0 +1,5 @@
{
"skip_files": [
"lib/accent/release_tasks.ex"
]
}
24 changes: 24 additions & 0 deletions docker-compose.yml
@@ -0,0 +1,24 @@
version: '3.3'
services:
application:
image: accent
container_name: accent
ports:
- 4000:4000
depends_on:
- postgresql
environment:
- PORT=4000
- DATABASE_URL=postgres://postgres@postgresql:5432/accent_development
- GOOGLE_API_CLIENT_ID=xxxxxxxx.apps.googleusercontent.com
postgresql:
image: postgres:10.3
container_name: accent-postgres
environment:
- POSTGRES_DB=accent_development
ports:
- 5432:5432
volumes:
- accent_psql:/var/lib/postgresql/data
volumes:
accent_psql:

0 comments on commit a4838a9

Please sign in to comment.