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

Deployment #3

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
88df093
Add books table with authors and books one to many association.
BrooklinJazz Dec 15, 2022
1bf5308
add book resources
BrooklinJazz Dec 18, 2022
0d46bc3
partially add authors to book form
BrooklinJazz Dec 18, 2022
dc49248
Finish seeding reading content
BrooklinJazz Dec 18, 2022
b3c01ea
Merge branch 'seeding' into book_form
BrooklinJazz Dec 18, 2022
090ee0e
add author field to book form
BrooklinJazz Dec 19, 2022
29fc985
generate tags resource with routes
BrooklinJazz Dec 21, 2022
2e5b1cf
Merge branch 'main' into one_to_many_authors_and_books and expand res…
BrooklinJazz Dec 21, 2022
e5d1b2b
alter order of author/book routes
BrooklinJazz Dec 21, 2022
88fff1a
Merge branch 'books' into tags. Add tag routes.
BrooklinJazz Dec 21, 2022
6bbb844
Many to many tags association
BrooklinJazz Dec 21, 2022
76d6b82
Complete book_content one-to-one association lesson
BrooklinJazz Dec 27, 2022
38e4be0
Deploy application with Fly.io
BrooklinJazz Dec 28, 2022
0486333
Add new homepage
BrooklinJazz Dec 28, 2022
5b46490
add Seeds file
BrooklinJazz Dec 28, 2022
b8363f5
draft tests CI yml file
BrooklinJazz Dec 28, 2022
858ca69
change otp and elixir versions for CI
BrooklinJazz Dec 28, 2022
598dcbe
use old github action for tests
BrooklinJazz Dec 28, 2022
e475d0e
use yml provided by setup-beam
BrooklinJazz Dec 28, 2022
7ffe228
strict otp and elixir version for CI
BrooklinJazz Dec 28, 2022
e0722f4
change otp version and fix failing page index test
BrooklinJazz Dec 28, 2022
0529951
add cd with fly
BrooklinJazz Dec 28, 2022
eee9e6e
change fly deployment branch
BrooklinJazz Dec 28, 2022
dfc3763
add page path link to book search heading
BrooklinJazz Dec 28, 2022
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
39 changes: 39 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# flyctl launch added from .elixir_ls/.gitignore
.elixir_ls/**/*

# flyctl launch added from .gitignore
# The directory Mix will write compiled artifacts to.
_build

# If you run "mix test --cover", coverage assets end up here.
cover

# The directory Mix downloads your dependencies sources to.
deps

# Where 3rd-party dependencies like ExDoc output generated docs.
doc

# Ignore .fetch files in case you like to edit your project deps locally.
.fetch

# If the VM crashes, it generates a dump, let's ignore it too.
**/erl_crash.dump

# Also ignore archive artifacts (built via "mix archive.build").
**/*.ez

# Ignore package tarball (built via "mix hex.build").
**/book_search-*.tar

# Ignore assets that are produced by build tools.
priv/static/assets

# Ignore digested assets cache.
priv/static/cache_manifest.json

# In case you use Node.js/npm, you want to ignore these.
**/npm-debug.log
assets/node_modules

fly.toml
15 changes: 15 additions & 0 deletions .github/workflows/fly.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: Fly Deploy
on:
push:
branches:
- deployment
env:
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
jobs:
deploy:
name: Deploy app
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: superfly/flyctl-actions/setup-flyctl@master
- run: flyctl deploy --remote-only
27 changes: 27 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
on: push

jobs:
test:
runs-on: ubuntu-latest

services:
db:
image: postgres:11
ports: ['5432:5432']
env:
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5

name: run tests
steps:
- uses: actions/checkout@v2
- uses: erlef/setup-beam@v1
with:
otp-version: '25.2'
elixir-version: '1.14.2'
- run: mix deps.get
- run: mix test
95 changes: 95 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Find eligible builder and runner images on Docker Hub. We use Ubuntu/Debian instead of
# Alpine to avoid DNS resolution issues in production.
#
# https://hub.docker.com/r/hexpm/elixir/tags?page=1&name=ubuntu
# https://hub.docker.com/_/ubuntu?tab=tags
#
#
# This file is based on these images:
#
# - https://hub.docker.com/r/hexpm/elixir/tags - for the build image
# - https://hub.docker.com/_/debian?tab=tags&page=1&name=bullseye-20210902-slim - for the release image
# - https://pkgs.org/ - resource for finding needed packages
# - Ex: hexpm/elixir:1.14.2-erlang-25.1.2-debian-bullseye-20210902-slim
#
ARG ELIXIR_VERSION=1.14.2
ARG OTP_VERSION=25.0.3
ARG DEBIAN_VERSION=bullseye-20210902-slim

ARG BUILDER_IMAGE="hexpm/elixir:${ELIXIR_VERSION}-erlang-${OTP_VERSION}-debian-${DEBIAN_VERSION}"
ARG RUNNER_IMAGE="debian:${DEBIAN_VERSION}"

FROM ${BUILDER_IMAGE} as builder

# install build dependencies
RUN apt-get update -y && apt-get install -y build-essential git \
&& apt-get clean && rm -f /var/lib/apt/lists/*_*

# prepare build dir
WORKDIR /app

# install hex + rebar
RUN mix local.hex --force && \
mix local.rebar --force

# set build ENV
ENV MIX_ENV="prod"

# install mix dependencies
COPY mix.exs mix.lock ./
RUN mix deps.get --only $MIX_ENV
RUN mkdir config

# copy compile-time config files before we compile dependencies
# to ensure any relevant config change will trigger the dependencies
# to be re-compiled.
COPY config/config.exs config/${MIX_ENV}.exs config/
RUN mix deps.compile

COPY priv priv

COPY lib lib

COPY assets assets

# compile assets
RUN mix assets.deploy

# Compile the release
RUN mix compile

# Changes to config/runtime.exs don't require recompiling the code
COPY config/runtime.exs config/

COPY rel rel
RUN mix release

# start a new build stage so that the final image will only contain
# the compiled release and other runtime necessities
FROM ${RUNNER_IMAGE}

RUN apt-get update -y && apt-get install -y libstdc++6 openssl libncurses5 locales \
&& apt-get clean && rm -f /var/lib/apt/lists/*_*

# Set the locale
RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen

ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8

WORKDIR "/app"
RUN chown nobody /app

# set runner ENV
ENV MIX_ENV="prod"

# Only copy the final release from the build stage
COPY --from=builder --chown=nobody:root /app/_build/${MIX_ENV}/rel/book_search ./

USER nobody

CMD ["/app/bin/server"]
# Appended by flyctl
ENV ECTO_IPV6 true
ENV ERL_AFLAGS "-proto_dist inet6_tcp"
3 changes: 2 additions & 1 deletion config/prod.exs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import Config
# manifest is generated by the `mix phx.digest` task,
# which you should run after static files are built and
# before starting your production server.
config :book_search, BookSearchWeb.Endpoint, cache_static_manifest: "priv/static/cache_manifest.json"
config :book_search, BookSearchWeb.Endpoint,
cache_static_manifest: "priv/static/cache_manifest.json"

# Do not print debug messages in production
config :logger, level: :info
Expand Down
43 changes: 43 additions & 0 deletions fly.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# fly.toml file generated for booksearch on 2022-12-27T18:49:21-08:00

app = "booksearch"
kill_signal = "SIGTERM"
kill_timeout = 5
processes = []

[deploy]
release_command = "/app/bin/migrate"

[env]
PHX_HOST = "booksearch.fly.dev"
PORT = "8080"

[experimental]
allowed_public_ports = []
auto_rollback = true

[[services]]
http_checks = []
internal_port = 8080
processes = ["app"]
protocol = "tcp"
script_checks = []
[services.concurrency]
hard_limit = 25
soft_limit = 20
type = "connections"

[[services.ports]]
force_https = true
handlers = ["http"]
port = 80

[[services.ports]]
handlers = ["tls", "http"]
port = 443

[[services.tcp_checks]]
grace_period = "1s"
interval = "15s"
restart_limit = 0
timeout = "2s"
1 change: 1 addition & 0 deletions lib/book_search/authors/author.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ defmodule BookSearch.Authors.Author do

schema "authors" do
field :name, :string
has_many :books, BookSearch.Books.Book

timestamps()
end
Expand Down
105 changes: 105 additions & 0 deletions lib/book_search/books.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
defmodule BookSearch.Books do
@moduledoc """
The Books context.
"""

import Ecto.Query, warn: false
alias BookSearch.Repo

alias BookSearch.Books.Book

@doc """
Returns the list of books.

## Examples

iex> list_books()
[%Book{}, ...]

"""
def list_books do
Repo.all(Book) |> Repo.preload(:tags)
end

@doc """
Gets a single book.

Raises `Ecto.NoResultsError` if the Book does not exist.

## Examples

iex> get_book!(123)
%Book{}

iex> get_book!(456)
** (Ecto.NoResultsError)

"""
def get_book!(id), do: Repo.get!(Book, id) |> Repo.preload(:tags)

@doc """
Creates a book.

## Examples

iex> create_book(%{field: value})
{:ok, %Book{}}

iex> create_book(%{field: bad_value})
{:error, %Ecto.Changeset{}}

"""
def create_book(attrs \\ %{}, tags \\ []) do
%Book{}
|> Book.changeset(attrs, tags)
|> Repo.insert()
end

@doc """
Updates a book.

## Examples

iex> update_book(book, %{field: new_value})
{:ok, %Book{}}

iex> update_book(book, %{field: bad_value})
{:error, %Ecto.Changeset{}}

"""
def update_book(%Book{} = book, attrs, tags \\ []) do
book
|> Repo.preload(:book_content)
|> Book.changeset(attrs, tags)
|> Repo.update()
end

@doc """
Deletes a book.

## Examples

iex> delete_book(book)
{:ok, %Book{}}

iex> delete_book(book)
{:error, %Ecto.Changeset{}}

"""
def delete_book(%Book{} = book) do
Repo.delete(book)
end

@doc """
Returns an `%Ecto.Changeset{}` for tracking book changes.

## Examples

iex> change_book(book)
%Ecto.Changeset{data: %Book{}}

"""
def change_book(%Book{} = book, attrs \\ %{}) do
Book.changeset(book, attrs)
end
end
22 changes: 22 additions & 0 deletions lib/book_search/books/book.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
defmodule BookSearch.Books.Book do
use Ecto.Schema
import Ecto.Changeset

schema "books" do
field :title, :string
belongs_to :author, BookSearch.Authors.Author
has_one :book_content, BookSearch.Books.BookContent
many_to_many :tags, BookSearch.Tags.Tag, join_through: "book_tags", on_replace: :delete

timestamps()
end

@doc false
def changeset(book, attrs, tags \\ []) do
book
|> cast(attrs, [:title, :author_id])
|> validate_required([:title])
|> put_assoc(:tags, tags)
|> cast_assoc(:book_content)
end
end
18 changes: 18 additions & 0 deletions lib/book_search/books/book_content.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
defmodule BookSearch.Books.BookContent do
use Ecto.Schema
import Ecto.Changeset

schema "book_content" do
field :full_text, :string
belongs_to :book, BookSearch.Books.Book

timestamps()
end

@doc false
def changeset(book_content, attrs) do
book_content
|> cast(attrs, [:full_text])
|> validate_required([:full_text])
end
end
Loading