Skip to content

Commit

Permalink
Merge pull request #58 from felipelincoln/dev
Browse files Browse the repository at this point in the history
Release v0.8.0
  • Loading branch information
felipelincoln authored May 29, 2021
2 parents 4a02b51 + 0b9aec7 commit e46d040
Show file tree
Hide file tree
Showing 61 changed files with 2,480 additions and 225 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/_build/
/deps/
/cover/

2 changes: 2 additions & 0 deletions .iex.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
alias Publishing.Repo
alias Publishing.{Article, Blog}
6 changes: 2 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ WORKDIR /branchpage

RUN mix do local.hex --force, local.rebar --force

RUN apk add inotify-tools
RUN apk add npm inotify-tools


# -----------------
Expand All @@ -23,6 +23,7 @@ ENV MIX_ENV=$MIX_ENV
# install mix dependencies
COPY mix.exs mix.lock ./
COPY apps/web/mix.exs apps/web/mix.exs
COPY apps/publishing/mix.exs apps/publishing/mix.exs
COPY config config
RUN mix do deps.get, deps.compile --skip-umbrella-children

Expand All @@ -36,8 +37,6 @@ RUN mix compile
# -----------------
FROM build AS release

RUN apk add npm

# install node dependencies
RUN npm ci --prefix ./apps/web/assets --no-audit

Expand All @@ -59,7 +58,6 @@ FROM alpine:3.13.3
WORKDIR /branchpage

ARG MIX_ENV=prod
ENV MIX_ENV=$MIX_ENV

# install dependencies
RUN apk add ncurses-libs curl
Expand Down
5 changes: 5 additions & 0 deletions apps/publishing/.formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Used by "mix format"
[
import_deps: [:ecto, :phoenix],
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
24 changes: 24 additions & 0 deletions apps/publishing/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# 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 third-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").
blog-*.tar

21 changes: 21 additions & 0 deletions apps/publishing/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Publishing

**TODO: Add description**

## Installation

If [available in Hex](https://hex.pm/docs/publish), the package can be installed
by adding `publishing` to your list of dependencies in `mix.exs`:

```elixir
def deps do
[
{:publishing, "~> 0.1.0"}
]
end
```

Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
be found at [https://hexdocs.pm/publishing](https://hexdocs.pm/publishing).

11 changes: 11 additions & 0 deletions apps/publishing/coveralls.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"skip_files": [
"lib/publishing/application.ex",
"lib/publishing/release.ex",
"lib/publishing/repo.ex",
"test/support"
],
"coverage_options": {
"treat_no_relevant_lines_as_covered": true
}
}
11 changes: 11 additions & 0 deletions apps/publishing/lib/publishing/application.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
defmodule Publishing.Application do
@moduledoc false

use Application

def start(_type, _args) do
children = [Publishing.Repo]

Supervisor.start_link(children, strategy: :one_for_one, name: Publishing.Supervisor)
end
end
34 changes: 34 additions & 0 deletions apps/publishing/lib/publishing/helper.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
defmodule Publishing.Helper do
@moduledoc """
Helpers for the publishing application.
"""

@current_year Date.utc_today().year
@last_year @current_year - 1

@doc """
Formats a datetime into "Month. day" format
Examples
iex> format_date(~D[2021-06-15])
"Jun 15"
iex> format_date(~D[2020-06-21])
"Last year"
iex> format_date(~D[2019-12-12])
"2 years ago"
"""
def format_date(%{year: @current_year} = datetime) do
Timex.format!(datetime, "%b %e", :strftime)
end

def format_date(%{year: @last_year}) do
"Last year"
end

def format_date(%{year: year}) do
n = @current_year - year
"#{n} years ago"
end
end
32 changes: 32 additions & 0 deletions apps/publishing/lib/publishing/integration.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
defmodule Publishing.Integration do
@moduledoc """
Integrations modules extract information from code hosting platforms.
"""

alias Publishing.Integration.Github

@callback get_content(String.t()) :: {:ok, String.t()} | {:error, integer}
@callback get_username(String.t()) :: {:ok, String.t() | {:error, :username}}
@callback get_blog_data(String.t()) :: {:ok, map} | {:error, :blog}

@doc """
Returns the `url`'s integration module.
## Currently supported integrations
* Github: `Publishing.Integration.Github`
Examples:
iex> service("https://github.com/teste")
{:ok, Publishing.Integration.Github}
iex> service("https://gitlab.com/teste")
{:error, :integration}
"""
@spec service(String.t()) :: {:ok, module} | {:error, :integration}
def service(url) do
case URI.parse(url) do
%URI{host: "github.com"} -> {:ok, Github}
_ -> {:error, :integration}
end
end
end
102 changes: 102 additions & 0 deletions apps/publishing/lib/publishing/integration/github.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
defmodule Publishing.Integration.Github do
@moduledoc """
Integrates with github.
"""

use Tesla

@behaviour Publishing.Integration

plug Tesla.Middleware.BaseUrl, "https://api.github.com/"
plug Tesla.Middleware.Headers, [{"Authorization", "Bearer #{token()}"}]
plug Tesla.Middleware.Headers, [{"User-Agent", "branchpage"}]
plug Tesla.Middleware.JSON

defp token, do: Application.get_env(:publishing, __MODULE__)[:token]

def get_blog_data(username) do
body = %{
query: "query($login: String!){user(login: $login){bio name avatarUrl}}",
variables: %{login: username}
}

case post("graphql", body) do
{:ok, %{status: 200, body: response}} ->
%{
"data" => %{
"user" => %{
"name" => name,
"bio" => bio,
"avatarUrl" => avatar_url
}
}
} = response

data = %{fullname: name, bio: bio, avatar_url: avatar_url}

{:ok, data}

_ ->
{:error, :blog}
end
end

@doc """
Returns the GitHub username from the `url`.
Examples:
iex> get_username("https://github.com/felipelincoln/branchpage/blob/main/README.md")
{:ok, "felipelincoln"}
iex> get_username("https://github.com/")
{:error, :username}
"""
@spec get_username(String.t()) :: {:ok, String.t()} | {:error, :username}
def get_username(url) when is_binary(url) do
case decompose(url) do
[username, _] -> {:ok, username}
[] -> {:error, :username}
end
end

@doc """
Retrieve the raw content of a resource's `url` from github.
"""
@spec get_content(String.t()) :: {:ok, Stream.t()} | {:error, integer}
def get_content(""), do: {:error, 404}

def get_content(url) when is_binary(url) do
raw =
url
|> decompose()
|> raw_url()

case Tesla.get(raw) do
{:ok, %{status: 200, body: body}} ->
{:ok, body}

{:ok, %{status: code}} ->
{:error, code}
end
end

defp decompose(url) do
with %URI{path: path} when is_binary(path) <- URI.parse(url),
["", username, repository, "blob" | tail] <- String.split(path, "/"),
resource <- Enum.join([repository] ++ tail, "/"),
true <- not_empty_string(username),
true <- not_empty_string(resource) do
[username, resource]
else
_ -> []
end
end

defp raw_url([username, resource]) do
"https://raw.githubusercontent.com/#{username}/#{resource}"
end

defp raw_url([]), do: ""

defp not_empty_string(str), do: is_binary(str) and str != ""
end
Loading

0 comments on commit e46d040

Please sign in to comment.