chore: Update ex_cldr

This commit is contained in:
Robert Prehn 2021-08-04 20:10:16 -05:00
commit 1333be352f
61 changed files with 13556 additions and 14815 deletions

3
.dialyzer_ignore.exs Normal file
View file

@ -0,0 +1,3 @@
[
{"lib/i18n.ex:1:pattern_match_cov The pattern pattern <_@1, _@2, _@3> can never match the type, because it is covered by previous clauses."}
]

View file

@ -2,3 +2,4 @@ cover
.elixir_ls .elixir_ls
*.dump *.dump
.journal-* .journal-*
.git

3
.gitignore vendored
View file

@ -44,3 +44,6 @@ config/*.secret.exs
# Temporary CI build file # Temporary CI build file
build.env build.env
# CI metrics file
metrics.txt

View file

@ -26,7 +26,7 @@ variables:
- name: postgres:12 - name: postgres:12
script: script/cibuild script: script/cibuild
test: test_1.10.4:
<<: *test_template <<: *test_template
image: "elixir:1.10.4-alpine" image: "elixir:1.10.4-alpine"
@ -34,15 +34,55 @@ test_1.11.4:
<<: *test_template <<: *test_template
image: "elixir:1.11.4-alpine" image: "elixir:1.11.4-alpine"
test_1.12.1: test:
<<: *test_template <<: *test_template
image: "elixir:1.12.1-alpine" image: "elixir:1.12.1-alpine"
script:
- script/cibuild covered
artifacts:
paths:
- cover/excoveralls.json
credo:
stage: test
image: "elixir:1.12.1-alpine"
cache:
key: "test_1.12.1"
paths:
- _build/
- deps/
script:
- mix local.hex --force
- mix local.rebar --force
- mix deps.get
- mix credo --all
stylelint:
stage: test
image: "node:16"
script:
- cd apps/app/assets/
- npm install
- npx stylelint **/*.css
prettier:
stage: test
image: "node:16"
script:
- cd apps/app/assets/
- npm install
- npx prettier --check **/*.js
build_image_for_commit: build_image_for_commit:
stage: test stage: test
image: "docker:20.10" image: "docker:20.10"
only: rules:
- master - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
when: on_success
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
changes:
- Dockerfile
when: on_success
services: services:
- name: docker:20.10-dind - name: docker:20.10-dind
before_script: before_script:
@ -51,6 +91,19 @@ build_image_for_commit:
script: script:
- script/ci-docker-build - script/ci-docker-build
report_coverage:
stage: deploy_tags
needs: ['test']
image: "elixir:1.12.1-alpine"
script:
- mix local.hex --force
- script/coverage-json-to-metrics
- script/coverage-json-to-cobertura
artifacts:
reports:
metrics: metrics.txt
cobertura: cover/cobertura.xml
# If tests pass, tag the commit and update package versions # If tests pass, tag the commit and update package versions
deploy_to_tags: deploy_to_tags:
stage: deploy_tags stage: deploy_tags

View file

@ -1,3 +1,3 @@
erlang 23.0.2 erlang 23.0.2
elixir 1.10.3-otp-23 elixir 1.12.1
nodejs 14.5.0 nodejs 14.5.0

View file

@ -1,4 +1,4 @@
FROM elixir:1.10.4-alpine AS elixir-builder FROM elixir:1.12.2-alpine AS elixir-builder
RUN apk add git RUN apk add git
@ -29,7 +29,7 @@ RUN mix deps.get
# Leave off here so that we can built assets and compile the elixir app in parallel # Leave off here so that we can built assets and compile the elixir app in parallel
FROM node:16.3.0 AS asset-builder FROM node:16.6.0 AS asset-builder
# Build assets in a node container # Build assets in a node container
ADD ./apps/app/assets/ /root/app/apps/app/assets/ ADD ./apps/app/assets/ /root/app/apps/app/assets/

View file

@ -1,4 +1,9 @@
defmodule Legendary.Admin.Routes do defmodule Legendary.Admin.Routes do
@moduledoc """
Routes from the admin app. Use like:
use Legendary.Admin.Routes
"""
defmacro __using__(_opts \\ []) do defmacro __using__(_opts \\ []) do
quote do quote do
use Kaffy.Routes, scope: "/admin", pipe_through: [:require_admin] use Kaffy.Routes, scope: "/admin", pipe_through: [:require_admin]

View file

@ -1,4 +1,8 @@
defmodule Legendary.Admin.Telemetry do defmodule Legendary.Admin.Telemetry do
@moduledoc """
Collect metrics from the admin app.
"""
use Supervisor use Supervisor
import Telemetry.Metrics import Telemetry.Metrics

View file

@ -1,4 +1,8 @@
defmodule Legendary.Admin.Kaffy.Config do defmodule Legendary.Admin.Kaffy.Config do
@moduledoc """
Pull in the resource list for the admin from the application config.
"""
def create_resources(_conn) do def create_resources(_conn) do
config = Application.get_env(:admin, Legendary.Admin) config = Application.get_env(:admin, Legendary.Admin)

View file

@ -1,4 +1,9 @@
defmodule Legendary.Admin.Kaffy.EditorExtension do defmodule Legendary.Admin.Kaffy.EditorExtension do
@moduledoc """
Bring in additional CSS and JS for the admin interface e.g. the
markdown editor library.
"""
def stylesheets(_conn) do def stylesheets(_conn) do
[ [
{:safe, ~s(<link rel="stylesheet" href="/css/content-editor.css" />)}, {:safe, ~s(<link rel="stylesheet" href="/css/content-editor.css" />)},

View file

@ -1,7 +1,7 @@
defmodule Legendary.Admin.MixProject do defmodule Legendary.Admin.MixProject do
use Mix.Project use Mix.Project
@version "2.10.0" @version "3.1.2"
def project do def project do
[ [

View file

@ -1,5 +1,3 @@
{ {
"presets": [ "presets": ["@babel/preset-env"]
"@babel/preset-env"
]
} }

View file

@ -1 +1,2 @@
node_modules node_modules
css/phoenix.css

View file

@ -1,11 +1,7 @@
@import "tailwindcss/base"; @import "tailwindcss/base";
@import "tailwindcss/components"; @import "tailwindcss/components";
@import "tailwindcss/utilities"; @import "tailwindcss/utilities";
@import "@fortawesome/fontawesome-free/css/all.css"; @import "@fortawesome/fontawesome-free/css/all.css";
@import "blog"; @import "blog";
@import "code"; @import "code";
@ -14,27 +10,28 @@ body {
} }
input[type="checkbox"]::after { input[type="checkbox"]::after {
content: ""; display: inline-flex;
color: currentColor; justify-content: center;
width: 100%; width: 100%;
height: 100%; height: 100%;
display: inline-flex; color: currentColor;
align-items: center; align-items: center;
justify-content: center; content: "";
} }
input[type="checkbox"]:checked::after { input[type="checkbox"]:checked::after {
content: "✓"; content: "✓";
} }
.hidden-options-toggle:checked+.hidden { .hidden-options-toggle:checked + .hidden {
display: block; display: block;
} }
.password-revealer { .password-revealer {
@apply absolute; @apply absolute;
height: 45px;
width: 45px;
right: 0; right: 0;
bottom: 0; bottom: 0;
width: 45px;
height: 45px;
} }

View file

@ -57,7 +57,7 @@
.hljs { .hljs {
@apply mt-6 mb-12 border-l-4 border-indigo-900 font-mono; @apply mt-6 mb-12 border-l-4 border-indigo-900 font-mono;
--background-color: theme("colors.indigo.100"); --background-color: theme("colors.indigo.100"); /* stylelint-disable-line custom-property-empty-line-before */
--attribute-color: theme("colors.orange.700"); --attribute-color: theme("colors.orange.700");
--section-color: theme("colors.teal.700"); --section-color: theme("colors.teal.700");
--string-color: theme("colors.green.700"); --string-color: theme("colors.green.700");

View file

@ -1,7 +1,7 @@
// We need to import the CSS so that webpack will load it. // We need to import the CSS so that webpack will load it.
// The MiniCssExtractPlugin is used to separate it out into // The MiniCssExtractPlugin is used to separate it out into
// its own CSS file. // its own CSS file.
import "../css/app.css" import "../css/app.css";
// webpack automatically bundles all modules in your // webpack automatically bundles all modules in your
// entry points. Those entry points can be configured // entry points. Those entry points can be configured
@ -12,48 +12,46 @@ import "../css/app.css"
// import {Socket} from "phoenix" // import {Socket} from "phoenix"
// import socket from "./socket" // import socket from "./socket"
// //
import "phoenix_html" import "phoenix_html";
import "alpinejs" import "alpinejs";
import "./live" import "./live";
import { ready } from "./utils" import { ready } from "./utils";
function togglePasswordFieldVisibility() var bloop;
{
const passwordFields = document.querySelectorAll('[name="user[password]"]') function togglePasswordFieldVisibility() {
const passwordFields = document.querySelectorAll('[name="user[password]"]');
passwordFields.forEach((el) => { passwordFields.forEach((el) => {
if (el.type == 'password') if (el.type == "password") {
{ el.type = "text";
el.type = 'text' } else {
el.type = "password";
} }
else });
{
el.type = 'password'
}
})
} }
const toggleSidebar = (event) => { const toggleSidebar = (event) => {
document.querySelectorAll('.sidebar').forEach((el) => { document.querySelectorAll(".sidebar").forEach((el) => {
el.classList.toggle('visible') el.classList.toggle("visible");
}) });
} };
ready(() => { ready(() => {
(document.getElementById('nav-toggle') ||{}).onclick = function(){ (document.getElementById("nav-toggle") || {}).onclick = function () {
document.getElementById("nav-content").classList.toggle("hidden"); document.getElementById("nav-content").classList.toggle("hidden");
} };
document.querySelectorAll('.js-passwordRevealer').forEach((el) => { document.querySelectorAll(".js-passwordRevealer").forEach((el) => {
el.addEventListener('click', togglePasswordFieldVisibility) el.addEventListener("click", togglePasswordFieldVisibility);
}) });
document.querySelectorAll('.js-SidebarOpener').forEach((el) => { document.querySelectorAll(".js-SidebarOpener").forEach((el) => {
el.addEventListener('click', toggleSidebar) el.addEventListener("click", toggleSidebar);
}) });
document.querySelectorAll('.js-flash-closer').forEach((el) => { document.querySelectorAll(".js-flash-closer").forEach((el) => {
el.addEventListener('click', () => { el.addEventListener("click", () => {
el.closest('.js-flash').remove() el.closest(".js-flash").remove();
}) });
}) });
}) });

View file

@ -1,34 +1,33 @@
import { ready } from "./utils" import { ready } from "./utils";
import SimpleMDE from "simplemde" import SimpleMDE from "simplemde";
import "simplemde/dist/simplemde.min.css" import "simplemde/dist/simplemde.min.css";
import "../css/content-editor-overrides.css" import "../css/content-editor-overrides.css";
const requestPreview = (plainText, previewContainer) => { const requestPreview = (plainText, previewContainer) => {
let request = new XMLHttpRequest() let request = new XMLHttpRequest();
const postForm = previewContainer.closest('form') const postForm = previewContainer.closest("form");
let formData = new FormData(postForm) let formData = new FormData(postForm);
formData.set('post[content]', plainText) formData.set("post[content]", plainText);
request.addEventListener('load', function(event) { request.addEventListener("load", function (event) {
previewContainer.innerHTML = event.target.responseText previewContainer.innerHTML = event.target.responseText;
}) });
request.open('POST', '/pages/posts/preview', true) request.open("POST", "/posts/preview", true);
request.send(formData) request.send(formData);
} };
ready(() => { ready(() => {
document.querySelectorAll('[data-simplemde]').forEach(el => { document.querySelectorAll("[data-simplemde]").forEach((el) => {
new SimpleMDE({ new SimpleMDE({
element: el, element: el,
previewRender: (plainText, previewContainer) => { previewRender: (plainText, previewContainer) => {
requestPreview(plainText, previewContainer) requestPreview(plainText, previewContainer);
return previewContainer.innerHTML return previewContainer.innerHTML;
}, },
}) });
}) });
}) });

View file

@ -1,18 +1,25 @@
import {Socket} from "phoenix" import { Socket } from "phoenix";
import LiveSocket from "phoenix_live_view" import LiveSocket from "phoenix_live_view";
import topbar from "topbar" import topbar from "topbar";
let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content") let csrfToken = document
.querySelector("meta[name='csrf-token']")
.getAttribute("content");
let liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}}) let liveSocket = new LiveSocket("/live", Socket, {
params: { _csrf_token: csrfToken },
});
// Show progress bar on live navigation and form submits // Show progress bar on live navigation and form submits
topbar.config({barColors: {0: "#3B82F6"}, shadowColor: "rgba(0, 0, 0, .3)"}) topbar.config({
window.addEventListener("phx:page-loading-start", info => topbar.show()) barColors: { 0: "#3B82F6" },
window.addEventListener("phx:page-loading-stop", info => topbar.hide()) shadowColor: "rgba(0, 0, 0, .3)",
});
window.addEventListener("phx:page-loading-start", (info) => topbar.show());
window.addEventListener("phx:page-loading-stop", (info) => topbar.hide());
// Connect if there are any LiveViews on the page // Connect if there are any LiveViews on the page
liveSocket.connect() liveSocket.connect();
// Expose liveSocket on window for web console debug logs and latency simulation: // Expose liveSocket on window for web console debug logs and latency simulation:
// >> liveSocket.enableDebug() // >> liveSocket.enableDebug()
@ -20,4 +27,4 @@ liveSocket.connect()
// The latency simulator is enabled for the duration of the browser session. // The latency simulator is enabled for the duration of the browser session.
// Call disableLatencySim() to disable: // Call disableLatencySim() to disable:
// >> liveSocket.disableLatencySim() // >> liveSocket.disableLatencySim()
window.liveSocket = liveSocket window.liveSocket = liveSocket;

View file

@ -6,9 +6,9 @@
// //
// Pass the token on params as below. Or remove it // Pass the token on params as below. Or remove it
// from the params if you are not using authentication. // from the params if you are not using authentication.
import {Socket} from "phoenix" import { Socket } from "phoenix";
let socket = new Socket("/socket", {params: {token: window.userToken}}) let socket = new Socket("/socket", { params: { token: window.userToken } });
// When you connect, you'll often need to authenticate the client. // When you connect, you'll often need to authenticate the client.
// For example, imagine you have an authentication plug, `MyAuth`, // For example, imagine you have an authentication plug, `MyAuth`,
@ -52,12 +52,17 @@ let socket = new Socket("/socket", {params: {token: window.userToken}})
// end // end
// //
// Finally, connect to the socket: // Finally, connect to the socket:
socket.connect() socket.connect();
// Now that you are connected, you can join channels with a topic: // Now that you are connected, you can join channels with a topic:
let channel = socket.channel("topic:subtopic", {}) let channel = socket.channel("topic:subtopic", {});
channel.join() channel
.receive("ok", resp => { console.log("Joined successfully", resp) }) .join()
.receive("error", resp => { console.log("Unable to join", resp) }) .receive("ok", (resp) => {
console.log("Joined successfully", resp);
})
.receive("error", (resp) => {
console.log("Unable to join", resp);
});
export default socket export default socket;

View file

@ -1,10 +1,9 @@
const ready = (fn) => { const ready = (fn) => {
if (document.readyState != 'loading') { if (document.readyState != "loading") {
fn() fn();
} else { } else {
document.addEventListener('DOMContentLoaded', fn) document.addEventListener("DOMContentLoaded", fn);
} }
} };
export { ready } export { ready };

File diff suppressed because it is too large Load diff

View file

@ -5,20 +5,23 @@
"scripts": { "scripts": {
"deploy": "webpack --mode production", "deploy": "webpack --mode production",
"watch": "webpack --mode development --watch", "watch": "webpack --mode development --watch",
"profile": "webpack --mode development --plugin webpack/lib/debug/ProfilingPlugin" "profile": "webpack --mode development --plugin webpack/lib/debug/ProfilingPlugin",
"preinstall": "npx npm-force-resolutions"
}, },
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-free": "^5.14.0", "@fortawesome/fontawesome-free": "^5.14.0",
"alpinejs": "^2.8.1", "alpinejs": "^2.8.1",
"autoprefixer": "^9.8.6", "autoprefixer": "^9.8.6",
"csswring": "^7.0.0",
"glob": "^7.1.6", "glob": "^7.1.6",
"npm-force-resolutions": "^0.0.10",
"phoenix": "file:/../../../deps/phoenix", "phoenix": "file:/../../../deps/phoenix",
"phoenix_html": "file:/../../../deps/phoenix_html", "phoenix_html": "file:/../../../deps/phoenix_html",
"phoenix_live_view": "file:../../../deps/phoenix_live_view", "phoenix_live_view": "file:../../../deps/phoenix_live_view",
"postcss-clean": "^1.2.2",
"postcss-color-function": "^4.1.0", "postcss-color-function": "^4.1.0",
"simplemde": "^1.11.2", "simplemde": "^1.11.2",
"tailwindcss": "^1.7.3", "squeak": "^1.3.0",
"tailwindcss": "^2.2.6",
"topbar": "^1.0.1" "topbar": "^1.0.1"
}, },
"devDependencies": { "devDependencies": {
@ -29,24 +32,28 @@
"css-loader": "^3.4.2", "css-loader": "^3.4.2",
"css-minimizer-webpack-plugin": "^3.0.2", "css-minimizer-webpack-plugin": "^3.0.2",
"file-loader": "^6.0.0", "file-loader": "^6.0.0",
"image-webpack-loader": "^6.0.0", "image-webpack-loader": "^7.0.1",
"less": "^3.11.3", "less": "^3.11.3",
"less-loader": "^6.2.0", "less-loader": "^6.2.0",
"mini-css-extract-plugin": "^1.6.2", "mini-css-extract-plugin": "^1.6.2",
"postcss-css-variables": "^0.17.0", "postcss-css-variables": "^0.17.0",
"postcss-import": "^12.0.1", "postcss-import": "^12.0.1",
"postcss-loader": "^6.1.0", "postcss-loader": "^6.1.0",
"prettier": "2.3.2",
"sass": "^1.35.1", "sass": "^1.35.1",
"sass-loader": "^8.0.2", "sass-loader": "^8.0.2",
"style-loader": "^1.2.1", "style-loader": "^1.2.1",
"stylelint": "^13.13.1", "stylelint": "^13.8.0",
"stylelint-config-standard": "^22.0.0", "stylelint-config-standard": "^20.0.0",
"stylelint-order": "^4.1.0", "stylelint-order": "^4.1.0",
"terser-webpack-plugin": "^2.3.2", "terser-webpack-plugin": "^5.1.4",
"webpack": "^5.1.0", "webpack": "^5.1.0",
"webpack-cli": "^4.7.2" "webpack-cli": "^4.7.2",
"yargs-parser": "^20.2.9"
}, },
"resolutions": { "resolutions": {
"graceful-fs": "4.2.3" "graceful-fs": "4.2.3",
"meow": "9.0.0",
"tempfile": "4.0.0"
} }
} }

View file

@ -1,13 +1,11 @@
module.exports = { module.exports = {
plugins: [ plugins: [
require('postcss-import')({ require("postcss-import")({
plugins: [ plugins: [require("stylelint")()],
require('stylelint')(),
]
}), }),
require('tailwindcss'), require("tailwindcss"),
require('autoprefixer'), require("autoprefixer"),
require('csswring')(), require("postcss-clean")(),
require('postcss-color-function')() require("postcss-color-function")(),
], ],
} };

View file

@ -1,23 +1,163 @@
const yargsParser = require("yargs-parser");
const cliArgs = yargsParser(process.argv);
const mode = process.env.NODE_ENV || cliArgs.mode || "development";
module.exports = { module.exports = {
future: {
removeDeprecatedGapUtilities: true,
},
purge: { purge: {
enabled: true, enabled: mode == "production",
layers: ['base', 'components', 'utilities'], layers: ["base", "components", "utilities"],
content: [ content: [
'../../../**/views/*.ex', "../../../**/views/*.ex",
'../../../**/*.html.eex', "../../../**/*.html.eex",
'../../../**/*.html.leex', "../../../**/*.html.leex",
'../../../**/*.html.heex', "../../../**/*.html.heex",
'./js/**/*.js' "./js/**/*.js",
] ],
}, },
theme: { theme: {
extend: {}, colors: {
transparent: "transparent",
current: "currentColor",
black: "#000",
white: "#fff",
gray: {
100: "#f7fafc",
200: "#edf2f7",
300: "#e2e8f0",
400: "#cbd5e0",
500: "#a0aec0",
600: "#718096",
700: "#4a5568",
800: "#2d3748",
900: "#1a202c",
},
red: {
100: "#fff5f5",
200: "#fed7d7",
300: "#feb2b2",
400: "#fc8181",
500: "#f56565",
600: "#e53e3e",
700: "#c53030",
800: "#9b2c2c",
900: "#742a2a",
},
orange: {
100: "#fffaf0",
200: "#feebc8",
300: "#fbd38d",
400: "#f6ad55",
500: "#ed8936",
600: "#dd6b20",
700: "#c05621",
800: "#9c4221",
900: "#7b341e",
},
yellow: {
100: "#fffff0",
200: "#fefcbf",
300: "#faf089",
400: "#f6e05e",
500: "#ecc94b",
600: "#d69e2e",
700: "#b7791f",
800: "#975a16",
900: "#744210",
},
green: {
100: "#f0fff4",
200: "#c6f6d5",
300: "#9ae6b4",
400: "#68d391",
500: "#48bb78",
600: "#38a169",
700: "#2f855a",
800: "#276749",
900: "#22543d",
},
teal: {
100: "#e6fffa",
200: "#b2f5ea",
300: "#81e6d9",
400: "#4fd1c5",
500: "#38b2ac",
600: "#319795",
700: "#2c7a7b",
800: "#285e61",
900: "#234e52",
},
blue: {
100: "#ebf8ff",
200: "#bee3f8",
300: "#90cdf4",
400: "#63b3ed",
500: "#4299e1",
600: "#3182ce",
700: "#2b6cb0",
800: "#2c5282",
900: "#2a4365",
},
indigo: {
100: "#ebf4ff",
200: "#c3dafe",
300: "#a3bffa",
400: "#7f9cf5",
500: "#667eea",
600: "#5a67d8",
700: "#4c51bf",
800: "#434190",
900: "#3c366b",
},
purple: {
100: "#faf5ff",
200: "#e9d8fd",
300: "#d6bcfa",
400: "#b794f4",
500: "#9f7aea",
600: "#805ad5",
700: "#6b46c1",
800: "#553c9a",
900: "#44337a",
},
pink: {
100: "#fff5f7",
200: "#fed7e2",
300: "#fbb6ce",
400: "#f687b3",
500: "#ed64a6",
600: "#d53f8c",
700: "#b83280",
800: "#97266d",
900: "#702459",
},
},
fontSize: {
xs: "0.75rem",
sm: "0.875rem",
base: "1rem",
lg: "1.125rem",
xl: "1.25rem",
"2xl": "1.5rem",
"3xl": "1.875rem",
"4xl": "2.25rem",
"5xl": "3rem",
"6xl": "4rem",
},
extend: {
boxShadow: {
xs: "0 0 0 1px rgba(0, 0, 0, 0.05)",
outline: "0 0 0 3px rgba(66, 153, 225, 0.5)",
},
},
}, },
variants: { variants: {
backgroundColor: ['responsive', 'hover', 'focus', 'checked'], backgroundColor: ["responsive", "hover", "focus", "checked"],
extend: {
fontWeight: ["hover", "focus"],
},
}, },
plugins: [], plugins: [],
} };

View file

@ -1,32 +1,31 @@
const path = require('path'); const path = require("path");
const glob = require('glob'); const glob = require("glob");
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const TerserPlugin = require('terser-webpack-plugin'); const TerserPlugin = require("terser-webpack-plugin");
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const CopyWebpackPlugin = require('copy-webpack-plugin'); const CopyWebpackPlugin = require("copy-webpack-plugin");
const nodeModulesPath = path.resolve(__dirname, 'node_modules') const nodeModulesPath = path.resolve(__dirname, "node_modules");
module.exports = (env, options) => { module.exports = (env, options) => {
const devMode = options.mode !== 'production'; const devMode = options.mode !== "production";
return { return {
optimization: { optimization: {
minimizer: [ minimizer: [
new TerserPlugin({ cache: true, parallel: true, sourceMap: devMode }), new TerserPlugin({ parallel: true }),
new CssMinimizerPlugin(), new CssMinimizerPlugin(),
] ],
}, },
mode: options.mode, mode: options.mode,
devtool: devMode ? 'source-map' : undefined, devtool: devMode ? "source-map" : undefined,
entry: { entry: {
'app': glob.sync('./vendor/**/*.js').concat(['./js/app.js']), app: glob.sync("./vendor/**/*.js").concat(["./js/app.js"]),
'content-editor': ['./js/content-editor.js'], "content-editor": ["./js/content-editor.js"],
'tailwind': ['./tailwind.config.js'],
}, },
output: { output: {
filename: 'js/[name].js', filename: "js/[name].js",
path: path.resolve(__dirname, '../priv/static/') path: path.resolve(__dirname, "../priv/static/"),
}, },
module: { module: {
rules: [ rules: [
@ -34,9 +33,9 @@ module.exports = (env, options) => {
{ {
test: /\.(jpg|jpeg|gif|png)$/, test: /\.(jpg|jpeg|gif|png)$/,
use: [ use: [
'file-loader', "file-loader",
{ {
loader: 'image-webpack-loader', loader: "image-webpack-loader",
options: { options: {
disable: devMode, disable: devMode,
}, },
@ -45,61 +44,108 @@ module.exports = (env, options) => {
}, },
{ {
test: /\.(woff2?|ttf|eot|svg)(\?[a-z0-9\=\.]+)?$/, test: /\.(woff2?|ttf|eot|svg)(\?[a-z0-9\=\.]+)?$/,
loader: 'file-loader', loader: "file-loader",
options: { options: {
publicPath: '/fonts', publicPath: "/fonts",
outputPath: (url, resourcePath, context) => { outputPath: (url, resourcePath, context) => {
return `/fonts/${url}`; return `/fonts/${url}`;
}, },
} },
}, },
{ {
test: /\.js$/, test: /\.js$/,
exclude: /node_modules/, exclude: /node_modules/,
use: { use: {
loader: 'babel-loader' loader: "babel-loader",
} },
}, },
{ {
test: /\.css$/, test: /\.css$/,
use: [ use: [
{loader: MiniCssExtractPlugin.loader}, { loader: MiniCssExtractPlugin.loader },
{loader: 'css-loader', options: {sourceMap: true}}, { loader: "css-loader", options: { sourceMap: true } },
{loader: 'postcss-loader', options: {sourceMap: true}}, { loader: "postcss-loader", options: { sourceMap: true } },
], ],
}, },
] ],
}, },
plugins: [ plugins: [
new MiniCssExtractPlugin({ new MiniCssExtractPlugin({
filename: 'css/[name].css', filename: "css/[name].css",
chunkFilename: '[id].css', chunkFilename: "[id].css",
}),
new CopyWebpackPlugin({
patterns: [
{
from: path.resolve(__dirname, "static"),
to: path.resolve(__dirname, "../priv/static"),
},
],
}), }),
new CopyWebpackPlugin({patterns: [
{
from: path.resolve(__dirname, 'static'),
to: path.resolve(__dirname, '../priv/static'),
},
]}),
], ],
resolve: { resolve: {
alias: { alias: {
"../webfonts/fa-brands-400.eot": path.resolve(__dirname, "node_modules/@fortawesome/fontawesome-free/webfonts/fa-brands-400.eot"), "../webfonts/fa-brands-400.eot": path.resolve(
"../webfonts/fa-brands-400.woff2": path.resolve(__dirname, "node_modules/@fortawesome/fontawesome-free/webfonts/fa-brands-400.woff2"), __dirname,
"../webfonts/fa-brands-400.woff": path.resolve(__dirname, "node_modules/@fortawesome/fontawesome-free/webfonts/fa-brands-400.woff"), "node_modules/@fortawesome/fontawesome-free/webfonts/fa-brands-400.eot"
"../webfonts/fa-brands-400.ttf": path.resolve(__dirname, "node_modules/@fortawesome/fontawesome-free/webfonts/fa-brands-400.ttf"), ),
"../webfonts/fa-brands-400.svg": path.resolve(__dirname, "node_modules/@fortawesome/fontawesome-free/webfonts/fa-brands-400.svg"), "../webfonts/fa-brands-400.woff2": path.resolve(
"../webfonts/fa-regular-400.eot": path.resolve(__dirname, "node_modules/@fortawesome/fontawesome-free/webfonts/fa-regular-400.eot"), __dirname,
"../webfonts/fa-regular-400.woff2": path.resolve(__dirname, "node_modules/@fortawesome/fontawesome-free/webfonts/fa-regular-400.woff2"), "node_modules/@fortawesome/fontawesome-free/webfonts/fa-brands-400.woff2"
"../webfonts/fa-regular-400.woff": path.resolve(__dirname, "node_modules/@fortawesome/fontawesome-free/webfonts/fa-regular-400.woff"), ),
"../webfonts/fa-regular-400.ttf": path.resolve(__dirname, "node_modules/@fortawesome/fontawesome-free/webfonts/fa-regular-400.ttf"), "../webfonts/fa-brands-400.woff": path.resolve(
"../webfonts/fa-regular-400.svg": path.resolve(__dirname, "node_modules/@fortawesome/fontawesome-free/webfonts/fa-regular-400.svg"), __dirname,
"../webfonts/fa-solid-900.eot": path.resolve(__dirname, "node_modules/@fortawesome/fontawesome-free/webfonts/fa-solid-900.eot"), "node_modules/@fortawesome/fontawesome-free/webfonts/fa-brands-400.woff"
"../webfonts/fa-solid-900.woff2": path.resolve(__dirname, "node_modules/@fortawesome/fontawesome-free/webfonts/fa-solid-900.woff2"), ),
"../webfonts/fa-solid-900.woff": path.resolve(__dirname, "node_modules/@fortawesome/fontawesome-free/webfonts/fa-solid-900.woff"), "../webfonts/fa-brands-400.ttf": path.resolve(
"../webfonts/fa-solid-900.ttf": path.resolve(__dirname, "node_modules/@fortawesome/fontawesome-free/webfonts/fa-solid-900.ttf"), __dirname,
"../webfonts/fa-solid-900.svg": path.resolve(__dirname, "node_modules/@fortawesome/fontawesome-free/webfonts/fa-solid-900.svg"), "node_modules/@fortawesome/fontawesome-free/webfonts/fa-brands-400.ttf"
} ),
"../webfonts/fa-brands-400.svg": path.resolve(
__dirname,
"node_modules/@fortawesome/fontawesome-free/webfonts/fa-brands-400.svg"
),
"../webfonts/fa-regular-400.eot": path.resolve(
__dirname,
"node_modules/@fortawesome/fontawesome-free/webfonts/fa-regular-400.eot"
),
"../webfonts/fa-regular-400.woff2": path.resolve(
__dirname,
"node_modules/@fortawesome/fontawesome-free/webfonts/fa-regular-400.woff2"
),
"../webfonts/fa-regular-400.woff": path.resolve(
__dirname,
"node_modules/@fortawesome/fontawesome-free/webfonts/fa-regular-400.woff"
),
"../webfonts/fa-regular-400.ttf": path.resolve(
__dirname,
"node_modules/@fortawesome/fontawesome-free/webfonts/fa-regular-400.ttf"
),
"../webfonts/fa-regular-400.svg": path.resolve(
__dirname,
"node_modules/@fortawesome/fontawesome-free/webfonts/fa-regular-400.svg"
),
"../webfonts/fa-solid-900.eot": path.resolve(
__dirname,
"node_modules/@fortawesome/fontawesome-free/webfonts/fa-solid-900.eot"
),
"../webfonts/fa-solid-900.woff2": path.resolve(
__dirname,
"node_modules/@fortawesome/fontawesome-free/webfonts/fa-solid-900.woff2"
),
"../webfonts/fa-solid-900.woff": path.resolve(
__dirname,
"node_modules/@fortawesome/fontawesome-free/webfonts/fa-solid-900.woff"
),
"../webfonts/fa-solid-900.ttf": path.resolve(
__dirname,
"node_modules/@fortawesome/fontawesome-free/webfonts/fa-solid-900.ttf"
),
"../webfonts/fa-solid-900.svg": path.resolve(
__dirname,
"node_modules/@fortawesome/fontawesome-free/webfonts/fa-solid-900.svg"
),
},
}, },
} };
}; };

View file

@ -4,10 +4,6 @@ defmodule AppWeb.LiveHelpers do
""" """
import Phoenix.LiveView import Phoenix.LiveView
alias Legendary.Auth.User
alias Pow.Store.CredentialsCache
alias AppWeb.Pow.Routes
def assign_defaults(socket, session) do def assign_defaults(socket, session) do
assign_new(socket, :current_user, fn -> get_user(socket, session) end) assign_new(socket, :current_user, fn -> get_user(socket, session) end)
end end
@ -16,7 +12,7 @@ defmodule AppWeb.LiveHelpers do
if socket.assigns.current_user do if socket.assigns.current_user do
socket socket
else else
redirect(socket, to: Routes.after_sign_out_path(%Plug.Conn{})) redirect(socket, to: "/")
end end
end end

View file

@ -1,4 +1,8 @@
defmodule AppWeb.Telemetry do defmodule AppWeb.Telemetry do
@moduledoc """
Collect metrics on your app.
"""
use Supervisor use Supervisor
import Telemetry.Metrics import Telemetry.Metrics

View file

@ -7,12 +7,11 @@ defmodule Legendary.Content.Application do
# See https://hexdocs.pm/elixir/Application.html # See https://hexdocs.pm/elixir/Application.html
# for more information on OTP Applications # for more information on OTP Applications
def start(_type, _args) do def start(_type, _args) do
import Supervisor.Spec
# Define workers and child supervisors to be supervised # Define workers and child supervisors to be supervised
children = [ children = [
# Start the Ecto repository # Start the Ecto repository
supervisor(Legendary.Content.Repo, []), Legendary.Content.Repo,
# Start the endpoint when the application starts # Start the endpoint when the application starts
# Start your own worker by calling: Legendary.Content.Worker.start_link(arg1, arg2, arg3) # Start your own worker by calling: Legendary.Content.Worker.start_link(arg1, arg2, arg3)
# worker(Legendary.Content.Worker, [arg1, arg2, arg3]), # worker(Legendary.Content.Worker, [arg1, arg2, arg3]),

View file

@ -1,4 +1,8 @@
defmodule Legendary.Content.CommentAdmin do defmodule Legendary.Content.CommentAdmin do
@moduledoc """
Custom admin logic for blog post comments.
"""
def index(_) do def index(_) do
[ [
id: nil, id: nil,

View file

@ -1,4 +1,8 @@
defmodule Legendary.Content.MarkupField do defmodule Legendary.Content.MarkupField do
@moduledoc """
Custom field type definition for markdown fields. Currently uses simplemde
to provide a markdown editing GUI.
"""
use Ecto.Type use Ecto.Type
def type, do: :string def type, do: :string

View file

@ -1,4 +1,8 @@
defmodule Legendary.Content.PostAdmin do defmodule Legendary.Content.PostAdmin do
@moduledoc """
Custom admin logic for content posts and pages.
"""
import Ecto.Query, only: [from: 2] import Ecto.Query, only: [from: 2]
def singular_name(_) do def singular_name(_) do

View file

@ -4,7 +4,7 @@ defmodule Legendary.Content.TermRelationship do
""" """
use Ecto.Schema use Ecto.Schema
import Ecto.Changeset import Ecto.Changeset
alias Legendary.Content.{Post} alias Legendary.Content.Post
@primary_key {:object_id, :integer, []} @primary_key {:object_id, :integer, []}
@primary_key {:term_taxonomy_id, :integer, []} @primary_key {:term_taxonomy_id, :integer, []}

View file

@ -42,7 +42,7 @@ defmodule Legendary.Content do
def process_content(text) do def process_content(text) do
text text
|> Earmark.as_html!(encode: false) |> Earmark.as_html!()
end end
# Include shared imports and aliases for views # Include shared imports and aliases for views

View file

@ -87,11 +87,12 @@ defmodule Legendary.Content.PostsController do
end end
# The static page we're looking for is missing, so this is just a 404 # The static page we're looking for is missing, so this is just a 404
# credo:disable-for-next-line
raise Phoenix.Router.NoRouteError.exception(conn: conn, router: router) raise Phoenix.Router.NoRouteError.exception(conn: conn, router: router)
_ -> _ ->
# We aren't missing the static page, we're missing a partial. This is probably # We aren't missing the static page, we're missing a partial. This is probably
# a developer error, so bubble it up # a developer error, so bubble it up
raise e reraise e, System.stacktrace
end end
end end
end end

View file

@ -1,4 +1,8 @@
defmodule Legendary.Content.Routes do defmodule Legendary.Content.Routes do
@moduledoc """
Routes for the content engine, including blog posts, feeds, and pages.
"""
defmacro __using__(_opts \\ []) do defmacro __using__(_opts \\ []) do
quote do quote do
pipeline :feed do pipeline :feed do

View file

@ -1,7 +1,7 @@
defmodule Legendary.Content.MixProject do defmodule Legendary.Content.MixProject do
use Mix.Project use Mix.Project
@version "2.10.0" @version "3.1.2"
def project do def project do
[ [
@ -42,7 +42,7 @@ defmodule Legendary.Content.MixProject do
defp deps do defp deps do
[ [
{:core, in_umbrella: true}, {:core, in_umbrella: true},
{:earmark, "1.4.3"}, {:earmark, "1.4.15"},
{:excoveralls, "~> 0.10", only: [:dev, :test]}, {:excoveralls, "~> 0.10", only: [:dev, :test]},
{:floki, ">= 0.30.0"}, {:floki, ">= 0.30.0"},
{:gettext, "~> 0.11"}, {:gettext, "~> 0.11"},
@ -57,7 +57,7 @@ defmodule Legendary.Content.MixProject do
{:phoenix_html_sanitizer, "~> 1.1.0"}, {:phoenix_html_sanitizer, "~> 1.1.0"},
{:phoenix_live_reload, "~> 1.2", only: :dev}, {:phoenix_live_reload, "~> 1.2", only: :dev},
{:phoenix_live_dashboard, "~> 0.4.0"}, {:phoenix_live_dashboard, "~> 0.4.0"},
{:php_serializer, "~> 0.9.0"}, {:php_serializer, "~> 2.0.0"},
{:plug_cowboy, "~> 2.0"}, {:plug_cowboy, "~> 2.0"},
{:sitemap, "~> 1.1"}, {:sitemap, "~> 1.1"},
{:slugger, "~> 0.3"}, {:slugger, "~> 0.3"},

View file

@ -52,7 +52,7 @@ defmodule Legendary.Content.PostsTest do
test "delete_posts/1", %{public_post: post} do test "delete_posts/1", %{public_post: post} do
assert Enum.count(Posts.list_posts()) == 1 assert Enum.count(Posts.list_posts()) == 1
assert {:ok, _} = Posts.delete_posts(post) assert {:ok, _} = Posts.delete_posts(post)
assert Enum.count(Posts.list_posts()) == 0 assert Enum.empty?(Posts.list_posts())
end end
test "change_posts/1", %{public_post: post} do test "change_posts/1", %{public_post: post} do

View file

@ -0,0 +1,31 @@
# Linters
Legendary ships with a set of reasonable default linter configurations to help
enforce consistent code style in your application. This is particularly valuable
when working together as a team. However, even when working solo, linters will
find some errors in your code and help you to avoid needless changes in the future.
Included linters:
- *credo* for Elixir
- *prettier* for JavaScript
- *stylelint* for CSS
## Pre-commit hooks
If you would like to lint your code before every commit, you can use
[lefthook](https://github.com/evilmartians/lefthook) to do so. We include a
lefthook.yml that runs credo, prettier, and stylelint for you.
First, if you do not have it installed already, you will need to
[install lefthook](https://github.com/evilmartians/lefthook/blob/master/docs/other.md#installation).
On the Mac with Homebrew, this is as simple as `brew install lefthook`. Instructions
for other environments are available in the lefthook documentation linked above.
Then you can install the hooks via `lefthook install`. You can test them without
committing by running `lefthook run pre-commit`.
## Linters in CI
The included `.gitlab-ci.yml` runs credo, prettier, and stylelint in CI as an
additional consistency check.

View file

@ -301,7 +301,7 @@ We also need to filter the items shown based on the current user. In inventory.e
```elixir ```elixir
def list_items(user_id) do def list_items(user_id) do
Item Item
|> where(owner_id: user_id) |> where(owner_id: ^user_id)
|> Repo.all() |> Repo.all()
end end
``` ```

View file

@ -1,4 +1,9 @@
defmodule Legendary.Auth.MnesiaClusterSupervisor do defmodule Legendary.Auth.MnesiaClusterSupervisor do
@moduledoc """
Manages the cache in Mnesia for Pow. This allows users to remain logged in
even if their traffic is hitting different nodes in the cluster.
"""
use Supervisor use Supervisor
def start_link(init_arg) do def start_link(init_arg) do

View file

@ -1,7 +1,12 @@
defmodule Legendary.Auth.Roles do defmodule Legendary.Auth.Roles do
@moduledoc """
Functions for working with roles on users, such as testing whether a user has
a role.
"""
def has_role?(userlike, role) when is_atom(role), do: has_role?(userlike, Atom.to_string(role)) def has_role?(userlike, role) when is_atom(role), do: has_role?(userlike, Atom.to_string(role))
def has_role?(nil, _), do: false def has_role?(nil, _), do: false
def has_role?(user = %Legendary.Auth.User{}, role) do def has_role?(%Legendary.Auth.User{} = user, role) do
Enum.any?(user.roles || [], & &1 == role) Enum.any?(user.roles || [], & &1 == role)
end end
end end

View file

@ -40,7 +40,7 @@ defmodule Legendary.Auth.User do
|> pow_extension_changeset(attrs) |> pow_extension_changeset(attrs)
end end
def reset_password_changeset(user = %Legendary.Auth.User{}, params) do def reset_password_changeset(%Legendary.Auth.User{} = user, params) do
user user
|> new_password_changeset(params, @pow_config) |> new_password_changeset(params, @pow_config)
|> Changeset.validate_required([:password]) |> Changeset.validate_required([:password])

View file

@ -1,9 +1,15 @@
defmodule Legendary.Auth.UserAdmin do defmodule Legendary.Auth.UserAdmin do
@moduledoc """
Custom admin login for user records.
"""
import Ecto.Query, only: [from: 2] import Ecto.Query, only: [from: 2]
alias Legendary.Auth.User alias Legendary.Auth.User
alias Legendary.Core.Repo alias Legendary.Core.Repo
def custom_links(_schema) do def custom_links(_schema) do
# We add the funwithflags admin URL under this custom admin because kaffy
# doesn't have global custom links that work in this way and user is the
# closest fit.
[ [
%{name: "Feature Flags", url: "/admin/feature-flags", order: 2, location: :top, icon: "flag"}, %{name: "Feature Flags", url: "/admin/feature-flags", order: 2, location: :top, icon: "flag"},
] ]

View file

@ -24,8 +24,14 @@ defmodule AuthWeb.Pow.ControllerCallbacks do
end end
def before_respond(Pow.Phoenix.SessionController, :delete, {:ok, conn}, config) do def before_respond(Pow.Phoenix.SessionController, :delete, {:ok, conn}, config) do
live_socket_id = Conn.get_session(conn, :live_socket_id) case Conn.get_session(conn, :live_socket_id) do
AppWeb.Endpoint.broadcast(live_socket_id, "disconnect", %{}) nil ->
nil
live_socket_id ->
%{private: %{phoenix_endpoint: endpoint}} = conn
apply(endpoint, :broadcast, [live_socket_id, "disconnect", %{}])
end
conn = conn =
conn conn

View file

@ -1,6 +1,10 @@
defmodule Legendary.AuthWeb.Helpers do defmodule Legendary.AuthWeb.Helpers do
def current_user(socket = %Phoenix.LiveView.Socket{assigns: %{current_user: user}}), do: user @moduledoc """
def current_user(socket = %Phoenix.LiveView.Socket{assigns: %{__assigns__: %{current_user: user}}}), do: user Utility functions for working with users and roles.
"""
def current_user(%Phoenix.LiveView.Socket{assigns: %{current_user: user}}), do: user
def current_user(%Phoenix.LiveView.Socket{assigns: %{__assigns__: %{current_user: user}}}), do: user
def current_user(%Phoenix.LiveView.Socket{}), do: nil def current_user(%Phoenix.LiveView.Socket{}), do: nil
def current_user(conn), do: Pow.Plug.current_user(conn) def current_user(conn), do: Pow.Plug.current_user(conn)

View file

@ -7,7 +7,7 @@ defmodule Legendary.Core.MapUtils do
Map.merge(base, override, &deep_value/3) Map.merge(base, override, &deep_value/3)
end end
defp deep_value(_key, base = %{}, override = %{}) do defp deep_value(_key, %{} = base, %{} = override) do
deep_merge(base, override) deep_merge(base, override)
end end

View file

@ -18,7 +18,11 @@ defmodule Legendary.Core.SharedDBConnectionPool do
def child_spec({mod, opts}) do def child_spec({mod, opts}) do
opts = Keyword.put_new(opts, :name, key(opts)) opts = Keyword.put_new(opts, :name, key(opts))
Supervisor.Spec.worker(Legendary.Core.SharedDBConnectionPool, [{mod, opts}])
%{
id: __MODULE__,
start: {Legendary.Core.SharedDBConnectionPool, :start_link, [{mod, opts}]}
}
end end
defp key(opts) do defp key(opts) do

View file

@ -1,4 +1,10 @@
defmodule Legendary.Core.Routes do defmodule Legendary.Core.Routes do
@moduledoc """
Router module that brings in core framework routes, such as the feature flag
admin interface. Can be included like:
use Legendary.Core.Routes
"""
defmacro __using__(_opts \\ []) do defmacro __using__(_opts \\ []) do
quote do quote do
scope path: "/admin/feature-flags" do scope path: "/admin/feature-flags" do

View file

@ -119,8 +119,8 @@ defmodule Legendary.CoreWeb.Helpers do
defp default_classes_for_type(type) when type in [:date_select, :time_select, :datetime_select] do defp default_classes_for_type(type) when type in [:date_select, :time_select, :datetime_select] do
"bg-white shadow rounded p-3" "bg-white shadow rounded p-3"
end end
defp default_classes_for_type(:checkbox), do: "appearance-none h-10 w-10 bg-white checked:bg-gray-500 rounded shadow focus:outline-none focus:shadow-outline text-white text-xl font-bold mb-2" defp default_classes_for_type(:checkbox), do: "appearance-none h-10 w-10 bg-white checked:bg-gray-500 rounded shadow focus:outline-none focus:ring text-white text-xl font-bold mb-2"
defp default_classes_for_type(_), do: "px-4 py-3 placeholder-gray-400 text-gray-700 bg-white rounded text-sm shadow focus:outline-none focus:shadow-outline w-full" defp default_classes_for_type(_), do: "px-4 py-3 placeholder-gray-400 text-gray-700 bg-white rounded text-sm shadow focus:outline-none focus:ring w-full"
def styled_button(text) do def styled_button(text) do
~E""" ~E"""

View file

@ -1,4 +1,8 @@
defmodule Mix.Legendary do defmodule Mix.Legendary do
@moduledoc """
Parent module for all Legendary framework mix tasks. Provides some helpers
used by tasks and generators.
"""
alias Mix.Phoenix.{Schema} alias Mix.Phoenix.{Schema}
@doc false @doc false

View file

@ -1,7 +1,7 @@
defmodule Legendary.Core.MixProject do defmodule Legendary.Core.MixProject do
use Mix.Project use Mix.Project
@version "2.10.0" @version "3.1.2"
def project do def project do
[ [
@ -61,6 +61,7 @@ defmodule Legendary.Core.MixProject do
"guides/features/feature-flags.md", "guides/features/feature-flags.md",
"guides/features/i18n.md", "guides/features/i18n.md",
"guides/features/tasks-and-scripts.md", "guides/features/tasks-and-scripts.md",
"guides/features/linters.md",
] ]
end end
@ -137,6 +138,7 @@ defmodule Legendary.Core.MixProject do
{:bamboo, "~> 1.5"}, {:bamboo, "~> 1.5"},
{:bamboo_smtp, "~> 3.0"}, {:bamboo_smtp, "~> 3.0"},
{:credo, "~> 1.4", only: [:dev, :test], runtime: false}, {:credo, "~> 1.4", only: [:dev, :test], runtime: false},
{:dialyxir, "~> 1.0", only: [:dev], runtime: false},
{:ex_cldr, "~> 2.23.0"}, {:ex_cldr, "~> 2.23.0"},
{:ex_doc, "~> 0.24", only: :dev, runtime: false}, {:ex_doc, "~> 0.24", only: :dev, runtime: false},
{:excoveralls, "~> 0.10", only: [:dev, :test]}, {:excoveralls, "~> 0.10", only: [:dev, :test]},
@ -145,7 +147,7 @@ defmodule Legendary.Core.MixProject do
{:phoenix, "~> 1.5.8"}, {:phoenix, "~> 1.5.8"},
{:phoenix_ecto, "~> 4.1"}, {:phoenix_ecto, "~> 4.1"},
{:ecto_sql, "~> 3.4"}, {:ecto_sql, "~> 3.4"},
{:ex_prompt, "~> 0.1.5"}, {:ex_prompt, "~> 0.2.0"},
{:linguist, git: "https://github.com/change/linguist.git", ref: "d67b60fd597bfe894c69773efd05ad690dad8663"}, {:linguist, git: "https://github.com/change/linguist.git", ref: "d67b60fd597bfe894c69773efd05ad690dad8663"},
{:postgrex, ">= 0.0.0"}, {:postgrex, ">= 0.0.0"},
{:phoenix_html, "~> 2.11"}, {:phoenix_html, "~> 2.11"},

View file

@ -26,6 +26,7 @@ use Mix.Config
"development", "development",
"--watch", "--watch",
"--watch-options-stdin", "--watch-options-stdin",
"--progress",
cd: Path.expand("../apps/#{otp_app}/assets", __DIR__) cd: Path.expand("../apps/#{otp_app}/assets", __DIR__)
] ]
] ]

View file

@ -20,7 +20,7 @@ spec:
spec: spec:
containers: containers:
- name: app - name: app
image: registry.gitlab.com/mythic-insight/legendary:2.10.0 image: registry.gitlab.com/mythic-insight/legendary:3.1.2
command: ["elixir"] command: ["elixir"]
args: args:
- "--name" - "--name"

13
lefthook.yml Normal file
View file

@ -0,0 +1,13 @@
pre-commit:
parallel: true
commands:
credo:
runner: mix credo diff master
stylelint:
root: "apps/app/assets/"
glob: "*.{css}"
runner: npx stylelint {staged_files}
prettier:
root: "apps/app/assets/"
glob: "*.{js}"
runner: npx prettier --check {staged_files}

21
mix.exs
View file

@ -1,7 +1,7 @@
defmodule Legendary.Mixfile do defmodule Legendary.Mixfile do
use Mix.Project use Mix.Project
@version "2.10.0" @version "3.1.2"
def project do def project do
[ [
@ -11,9 +11,20 @@ defmodule Legendary.Mixfile do
build_embedded: Mix.env() == :prod, build_embedded: Mix.env() == :prod,
start_permanent: Mix.env() == :prod, start_permanent: Mix.env() == :prod,
deps: deps(), deps: deps(),
aliases: aliases(),
test_coverage: [tool: ExCoveralls], test_coverage: [tool: ExCoveralls],
preferred_cli_env: [coveralls: :test, "coveralls.detail": :test, "coveralls.post": :test, "coveralls.html": :test], aliases: aliases(),
dialyzer: [
plt_add_apps: [:mix],
ignore_warnings: ".dialyzer_ignore.exs"
],
preferred_cli_env: [
coveralls: :test,
"coveralls.detail": :test,
"coveralls.post": :test,
"coveralls.html": :test,
"coveralls.json": :test,
"coveralls.xml": :test
],
] ]
end end
@ -24,10 +35,8 @@ defmodule Legendary.Mixfile do
defp aliases do defp aliases do
[ [
"deps.get": ["cmd mix deps.get"], "deps.get": ["cmd mix deps.get"],
"coveralls.html": ["cmd mix coveralls.html"],
"ecto.migrate": ["cmd mix ecto.migrate"], "ecto.migrate": ["cmd mix ecto.migrate"],
"npm.install": ["cmd mix npm.install"], "npm.install": ["cmd mix npm.install"]
test: ["cmd mix test"]
] ]
end end
end end

View file

@ -3,7 +3,7 @@
"bamboo_smtp": {:hex, :bamboo_smtp, "3.0.0", "b7f0c371af96a1cb7131908918b02abb228f9db234910bf10cf4fb177c083259", [:mix], [{:bamboo, "~> 1.2", [hex: :bamboo, repo: "hexpm", optional: false]}, {:gen_smtp, "~> 0.15.0", [hex: :gen_smtp, repo: "hexpm", optional: false]}], "hexpm", "77cb1fa3076b24109e54df622161fe1e5619376b4ecf86d8b99b46f327acc49f"}, "bamboo_smtp": {:hex, :bamboo_smtp, "3.0.0", "b7f0c371af96a1cb7131908918b02abb228f9db234910bf10cf4fb177c083259", [:mix], [{:bamboo, "~> 1.2", [hex: :bamboo, repo: "hexpm", optional: false]}, {:gen_smtp, "~> 0.15.0", [hex: :gen_smtp, repo: "hexpm", optional: false]}], "hexpm", "77cb1fa3076b24109e54df622161fe1e5619376b4ecf86d8b99b46f327acc49f"},
"bcrypt_elixir": {:hex, :bcrypt_elixir, "1.1.1", "6b5560e47a02196ce5f0ab3f1d8265db79a23868c137e973b27afef928ed8006", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "10f658be786bd2daaadcd45cc5b598da01d5bbc313da4d0e3efb2d6a511d896d"}, "bcrypt_elixir": {:hex, :bcrypt_elixir, "1.1.1", "6b5560e47a02196ce5f0ab3f1d8265db79a23868c137e973b27afef928ed8006", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "10f658be786bd2daaadcd45cc5b598da01d5bbc313da4d0e3efb2d6a511d896d"},
"bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"}, "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"},
"certifi": {:hex, :certifi, "2.5.2", "b7cfeae9d2ed395695dd8201c57a2d019c0c43ecaf8b8bcb9320b40d6662f340", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm", "3b3b5f36493004ac3455966991eaf6e768ce9884693d9968055aeeeb1e575040"}, "certifi": {:hex, :certifi, "2.6.1", "dbab8e5e155a0763eea978c913ca280a6b544bfa115633fa20249c3d396d9493", [:rebar3], [], "hexpm", "524c97b4991b3849dd5c17a631223896272c6b0af446778ba4675a1dff53bb7e"},
"cldr_utils": {:hex, :cldr_utils, "2.16.0", "5abd1835151e264f6f9a285ab8c7419954a45eec5ca5a356dea592faa23e80b9", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: true]}, {:decimal, "~> 1.9 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "3ef5dc0fdfe566a5a4b8bda726cf760ebada69c0600affc4cb02b5e8ae7f7b47"}, "cldr_utils": {:hex, :cldr_utils, "2.16.0", "5abd1835151e264f6f9a285ab8c7419954a45eec5ca5a356dea592faa23e80b9", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: true]}, {:decimal, "~> 1.9 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "3ef5dc0fdfe566a5a4b8bda726cf760ebada69c0600affc4cb02b5e8ae7f7b47"},
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"}, "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
"comeonin": {:hex, :comeonin, "4.1.2", "3eb5620fd8e35508991664b4c2b04dd41e52f1620b36957be837c1d7784b7592", [:mix], [{:argon2_elixir, "~> 1.2", [hex: :argon2_elixir, repo: "hexpm", optional: true]}, {:bcrypt_elixir, "~> 0.12.1 or ~> 1.0", [hex: :bcrypt_elixir, repo: "hexpm", optional: true]}, {:pbkdf2_elixir, "~> 0.12", [hex: :pbkdf2_elixir, repo: "hexpm", optional: true]}], "hexpm", "d8700a0ca4dbb616c22c9b3f6dd539d88deaafec3efe66869d6370c9a559b3e9"}, "comeonin": {:hex, :comeonin, "4.1.2", "3eb5620fd8e35508991664b4c2b04dd41e52f1620b36957be837c1d7784b7592", [:mix], [{:argon2_elixir, "~> 1.2", [hex: :argon2_elixir, repo: "hexpm", optional: true]}, {:bcrypt_elixir, "~> 0.12.1 or ~> 1.0", [hex: :bcrypt_elixir, repo: "hexpm", optional: true]}, {:pbkdf2_elixir, "~> 0.12", [hex: :pbkdf2_elixir, repo: "hexpm", optional: true]}], "hexpm", "d8700a0ca4dbb616c22c9b3f6dd539d88deaafec3efe66869d6370c9a559b3e9"},
@ -11,20 +11,20 @@
"cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"}, "cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"},
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.3.1", "ebd1a1d7aff97f27c66654e78ece187abdc646992714164380d8a041eda16754", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3a6efd3366130eab84ca372cbd4a7d3c3a97bdfcfb4911233b035d117063f0af"}, "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.3.1", "ebd1a1d7aff97f27c66654e78ece187abdc646992714164380d8a041eda16754", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3a6efd3366130eab84ca372cbd4a7d3c3a97bdfcfb4911233b035d117063f0af"},
"cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"}, "cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"},
"credo": {:hex, :credo, "1.4.0", "92339d4cbadd1e88b5ee43d427b639b68a11071b6f73854e33638e30a0ea11f5", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "1fd3b70dce216574ce3c18bdf510b57e7c4c85c2ec9cad4bff854abaf7e58658"}, "credo": {:hex, :credo, "1.5.6", "e04cc0fdc236fefbb578e0c04bd01a471081616e741d386909e527ac146016c6", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "4b52a3e558bd64e30de62a648518a5ea2b6e3e5d2b164ef5296244753fc7eb17"},
"crontab": {:hex, :crontab, "1.1.10", "dc9bb1f4299138d47bce38341f5dcbee0aa6c205e864fba7bc847f3b5cb48241", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "1347d889d1a0eda997990876b4894359e34bfbbd688acbb0ba28a2795ca40685"}, "crontab": {:hex, :crontab, "1.1.10", "dc9bb1f4299138d47bce38341f5dcbee0aa6c205e864fba7bc847f3b5cb48241", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "1347d889d1a0eda997990876b4894359e34bfbbd688acbb0ba28a2795ca40685"},
"db_connection": {:hex, :db_connection, "2.2.2", "3bbca41b199e1598245b716248964926303b5d4609ff065125ce98bcd368939e", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm", "642af240d8a8affb93b4ba5a6fcd2bbcbdc327e1a524b825d383711536f8070c"}, "db_connection": {:hex, :db_connection, "2.2.2", "3bbca41b199e1598245b716248964926303b5d4609ff065125ce98bcd368939e", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm", "642af240d8a8affb93b4ba5a6fcd2bbcbdc327e1a524b825d383711536f8070c"},
"decimal": {:hex, :decimal, "1.9.0", "83e8daf59631d632b171faabafb4a9f4242c514b0a06ba3df493951c08f64d07", [:mix], [], "hexpm", "b1f2343568eed6928f3e751cf2dffde95bfaa19dd95d09e8a9ea92ccfd6f7d85"}, "decimal": {:hex, :decimal, "1.9.0", "83e8daf59631d632b171faabafb4a9f4242c514b0a06ba3df493951c08f64d07", [:mix], [], "hexpm", "b1f2343568eed6928f3e751cf2dffde95bfaa19dd95d09e8a9ea92ccfd6f7d85"},
"dialyxir": {:hex, :dialyxir, "1.0.0", "6a1fa629f7881a9f5aaf3a78f094b2a51a0357c843871b8bc98824e7342d00a5", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "aeb06588145fac14ca08d8061a142d52753dbc2cf7f0d00fc1013f53f8654654"}, "dialyxir": {:hex, :dialyxir, "1.0.0", "6a1fa629f7881a9f5aaf3a78f094b2a51a0357c843871b8bc98824e7342d00a5", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "aeb06588145fac14ca08d8061a142d52753dbc2cf7f0d00fc1013f53f8654654"},
"earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm", "8cf8a291ebf1c7b9539e3cddb19e9cef066c2441b1640f13c34c1d3cfc825fec"}, "earmark": {:hex, :earmark, "1.4.15", "2c7f924bf495ec1f65bd144b355d0949a05a254d0ec561740308a54946a67888", [:mix], [{:earmark_parser, ">= 1.4.13", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "3b1209b85bc9f3586f370f7c363f6533788fb4e51db23aa79565875e7f9999ee"},
"earmark_parser": {:hex, :earmark_parser, "1.4.12", "b245e875ec0a311a342320da0551da407d9d2b65d98f7a9597ae078615af3449", [:mix], [], "hexpm", "711e2cc4d64abb7d566d43f54b78f7dc129308a63bc103fbd88550d2174b3160"}, "earmark_parser": {:hex, :earmark_parser, "1.4.13", "0c98163e7d04a15feb62000e1a891489feb29f3d10cb57d4f845c405852bbef8", [:mix], [], "hexpm", "d602c26af3a0af43d2f2645613f65841657ad6efc9f0e361c3b6c06b578214ba"},
"ecto": {:hex, :ecto, "3.4.6", "08f7afad3257d6eb8613309af31037e16c36808dfda5a3cd0cb4e9738db030e4", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6f13a9e2a62e75c2dcfc7207bfc65645ab387af8360db4c89fee8b5a4bf3f70b"}, "ecto": {:hex, :ecto, "3.4.6", "08f7afad3257d6eb8613309af31037e16c36808dfda5a3cd0cb4e9738db030e4", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6f13a9e2a62e75c2dcfc7207bfc65645ab387af8360db4c89fee8b5a4bf3f70b"},
"ecto_sql": {:hex, :ecto_sql, "3.4.4", "d28bac2d420f708993baed522054870086fd45016a9d09bb2cd521b9c48d32ea", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.4.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.3.0 or ~> 0.4.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.0", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "edb49af715dd72f213b66adfd0f668a43c17ed510b5d9ac7528569b23af57fe8"}, "ecto_sql": {:hex, :ecto_sql, "3.4.4", "d28bac2d420f708993baed522054870086fd45016a9d09bb2cd521b9c48d32ea", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.4.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.3.0 or ~> 0.4.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.0", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "edb49af715dd72f213b66adfd0f668a43c17ed510b5d9ac7528569b23af57fe8"},
"elixir_make": {:hex, :elixir_make, "0.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm", "d522695b93b7f0b4c0fcb2dfe73a6b905b1c301226a5a55cb42e5b14d509e050"}, "elixir_make": {:hex, :elixir_make, "0.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm", "d522695b93b7f0b4c0fcb2dfe73a6b905b1c301226a5a55cb42e5b14d509e050"},
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
"ex_cldr": {:hex, :ex_cldr, "2.23.0", "16aa883c3388a0b27485a810ae2a60d815968a473b5315454ebe2b5264e92a80", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: true]}, {:cldr_utils, "~> 2.15", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.13", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "7c9dad3115e2622a4902390591d9c4a2f7c5333bd73f02a02f7b4190394c7347"}, "ex_cldr": {:hex, :ex_cldr, "2.23.0", "16aa883c3388a0b27485a810ae2a60d815968a473b5315454ebe2b5264e92a80", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: true]}, {:cldr_utils, "~> 2.15", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.13", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "7c9dad3115e2622a4902390591d9c4a2f7c5333bd73f02a02f7b4190394c7347"},
"ex_doc": {:hex, :ex_doc, "0.24.0", "2df14354835afaabdf87cb2971ea9485d8a36ff590e4b6c250b4f60c8fdf9143", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "a0f4bcff21ceebea48414e49885d2a3e542200f76a2facf3f8faa54935eeb721"}, "ex_doc": {:hex, :ex_doc, "0.24.0", "2df14354835afaabdf87cb2971ea9485d8a36ff590e4b6c250b4f60c8fdf9143", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "a0f4bcff21ceebea48414e49885d2a3e542200f76a2facf3f8faa54935eeb721"},
"ex_prompt": {:hex, :ex_prompt, "0.1.5", "b136642d0962f8ea37b3c9fa185ad1f42c71c3b9c6c3950f0358d7f3d2db2970", [:mix], [], "hexpm", "ad19a404708c9c7b05d36090b2d074ceafbed248a8de1a22d45a05ebe6994b83"}, "ex_prompt": {:hex, :ex_prompt, "0.2.0", "4030424e9a7710e1939d81eea4a82af2e0a1826065adb28d59bc01e919af4a60", [:mix], [], "hexpm", "220ac023d87d529457b87c9db4b40ce542bff93ae2de16c582808c6822dfe3e8"},
"excoveralls": {:hex, :excoveralls, "0.13.0", "4e1b7cc4e0351d8d16e9be21b0345a7e165798ee5319c7800b9138ce17e0b38e", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "fe2a56c8909564e2e6764765878d7d5e141f2af3bc8ff3b018a68ee2a218fced"}, "excoveralls": {:hex, :excoveralls, "0.13.0", "4e1b7cc4e0351d8d16e9be21b0345a7e165798ee5319c7800b9138ce17e0b38e", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "fe2a56c8909564e2e6764765878d7d5e141f2af3bc8ff3b018a68ee2a218fced"},
"file_system": {:hex, :file_system, "0.2.8", "f632bd287927a1eed2b718f22af727c5aeaccc9a98d8c2bd7bff709e851dc986", [:mix], [], "hexpm", "97a3b6f8d63ef53bd0113070102db2ce05352ecf0d25390eb8d747c2bde98bca"}, "file_system": {:hex, :file_system, "0.2.8", "f632bd287927a1eed2b718f22af727c5aeaccc9a98d8c2bd7bff709e851dc986", [:mix], [], "hexpm", "97a3b6f8d63ef53bd0113070102db2ce05352ecf0d25390eb8d747c2bde98bca"},
"floki": {:hex, :floki, "0.31.0", "f05ee8a8e6a3ced4e62beeb2c79a63bc8e12ab98fbaaf6e6a3d9b76b1278e23f", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm", "b05afa372f5c345a5bf240ac25ea1f0f3d5fcfd7490ac0beeb4a203f9444891e"}, "floki": {:hex, :floki, "0.31.0", "f05ee8a8e6a3ced4e62beeb2c79a63bc8e12ab98fbaaf6e6a3d9b76b1278e23f", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm", "b05afa372f5c345a5bf240ac25ea1f0f3d5fcfd7490ac0beeb4a203f9444891e"},
@ -34,15 +34,15 @@
"gen_stage": {:hex, :gen_stage, "1.0.0", "51c8ae56ff54f9a2a604ca583798c210ad245f415115453b773b621c49776df5", [:mix], [], "hexpm", "1d9fc978db5305ac54e6f5fec7adf80cd893b1000cf78271564c516aa2af7706"}, "gen_stage": {:hex, :gen_stage, "1.0.0", "51c8ae56ff54f9a2a604ca583798c210ad245f415115453b773b621c49776df5", [:mix], [], "hexpm", "1d9fc978db5305ac54e6f5fec7adf80cd893b1000cf78271564c516aa2af7706"},
"gen_state_machine": {:hex, :gen_state_machine, "2.1.0", "a38b0e53fad812d29ec149f0d354da5d1bc0d7222c3711f3a0bd5aa608b42992", [:mix], [], "hexpm", "ae367038808db25cee2f2c4b8d0531522ea587c4995eb6f96ee73410a60fa06b"}, "gen_state_machine": {:hex, :gen_state_machine, "2.1.0", "a38b0e53fad812d29ec149f0d354da5d1bc0d7222c3711f3a0bd5aa608b42992", [:mix], [], "hexpm", "ae367038808db25cee2f2c4b8d0531522ea587c4995eb6f96ee73410a60fa06b"},
"gettext": {:hex, :gettext, "0.18.2", "7df3ea191bb56c0309c00a783334b288d08a879f53a7014341284635850a6e55", [:mix], [], "hexpm", "f9f537b13d4fdd30f3039d33cb80144c3aa1f8d9698e47d7bcbcc8df93b1f5c5"}, "gettext": {:hex, :gettext, "0.18.2", "7df3ea191bb56c0309c00a783334b288d08a879f53a7014341284635850a6e55", [:mix], [], "hexpm", "f9f537b13d4fdd30f3039d33cb80144c3aa1f8d9698e47d7bcbcc8df93b1f5c5"},
"hackney": {:hex, :hackney, "1.16.0", "5096ac8e823e3a441477b2d187e30dd3fff1a82991a806b2003845ce72ce2d84", [:rebar3], [{:certifi, "2.5.2", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.1", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.0", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.6", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "3bf0bebbd5d3092a3543b783bf065165fa5d3ad4b899b836810e513064134e18"}, "hackney": {:hex, :hackney, "1.17.4", "99da4674592504d3fb0cfef0db84c3ba02b4508bae2dff8c0108baa0d6e0977c", [:rebar3], [{:certifi, "~>2.6.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "de16ff4996556c8548d512f4dbe22dd58a587bf3332e7fd362430a7ef3986b16"},
"html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"}, "html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"},
"html_sanitize_ex": {:hex, :html_sanitize_ex, "1.4.1", "e8a67da405fe9f0d1be121a40a60f70811192033a5b8d00a95dddd807f5e053e", [:mix], [{:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm", "68d92656f47cd73598c45ad2394561f025c8c65d146001b955fd7b517858962a"}, "html_sanitize_ex": {:hex, :html_sanitize_ex, "1.4.1", "e8a67da405fe9f0d1be121a40a60f70811192033a5b8d00a95dddd807f5e053e", [:mix], [{:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm", "68d92656f47cd73598c45ad2394561f025c8c65d146001b955fd7b517858962a"},
"idna": {:hex, :idna, "6.0.1", "1d038fb2e7668ce41fbf681d2c45902e52b3cb9e9c77b55334353b222c2ee50c", [:rebar3], [{:unicode_util_compat, "0.5.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a02c8a1c4fd601215bb0b0324c8a6986749f807ce35f25449ec9e69758708122"}, "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
"jason": {:hex, :jason, "1.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"}, "jason": {:hex, :jason, "1.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"},
"kaffy": {:hex, :kaffy, "0.9.0", "bef34c9729f6a3af4d0dea8eede8bcb9e11371a83ac9a8b393991bce81839517", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.11", [hex: :phoenix_html, repo: "hexpm", optional: false]}], "hexpm", "d18ff57b8e68feb433aed11e71510cd357abc7034e75358af5deff7d0d4c6ed3"}, "kaffy": {:hex, :kaffy, "0.9.0", "bef34c9729f6a3af4d0dea8eede8bcb9e11371a83ac9a8b393991bce81839517", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.11", [hex: :phoenix_html, repo: "hexpm", optional: false]}], "hexpm", "d18ff57b8e68feb433aed11e71510cd357abc7034e75358af5deff7d0d4c6ed3"},
"libcluster": {:hex, :libcluster, "3.3.0", "f7d45ff56d88e9fb4c30aee662480cbab69ebc0e7f7da4ad8d01b1e4f7492da8", [:mix], [{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "ecdcdc88334ec8eb18b10a13a1d5f22a3319a970b5b1e66cfe71c7719a4ab6cc"}, "libcluster": {:hex, :libcluster, "3.3.0", "f7d45ff56d88e9fb4c30aee662480cbab69ebc0e7f7da4ad8d01b1e4f7492da8", [:mix], [{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "ecdcdc88334ec8eb18b10a13a1d5f22a3319a970b5b1e66cfe71c7719a4ab6cc"},
"libring": {:hex, :libring, "1.5.0", "44313eb6862f5c9168594a061e9d5f556a9819da7c6444706a9e2da533396d70", [:mix], [], "hexpm", "04e843d4fdcff49a62d8e03778d17c6cb2a03fe2d14020d3825a1761b55bd6cc"}, "libring": {:hex, :libring, "1.5.0", "44313eb6862f5c9168594a061e9d5f556a9819da7c6444706a9e2da533396d70", [:mix], [], "hexpm", "04e843d4fdcff49a62d8e03778d17c6cb2a03fe2d14020d3825a1761b55bd6cc"},
"linguist": {:hex, :linguist, "0.3.1", "8ce81114691be8ef4a122e7f57bd1842bc96b1f5650b66b246d7035238cab69d", [:mix], [{:ex_cldr, "~> 2.0", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.0", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "5b06f97912e298f60dd00bc6a588b1fe1ec8838b268e4fdbf4443a25511f0614"}, "linguist": {:git, "https://github.com/change/linguist.git", "d67b60fd597bfe894c69773efd05ad690dad8663", [ref: "d67b60fd597bfe894c69773efd05ad690dad8663"]},
"makeup": {:hex, :makeup, "1.0.5", "d5a830bc42c9800ce07dd97fa94669dfb93d3bf5fcf6ea7a0c67b2e0e4a7f26c", [:mix], [{:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cfa158c02d3f5c0c665d0af11512fed3fba0144cf1aadee0f2ce17747fba2ca9"}, "makeup": {:hex, :makeup, "1.0.5", "d5a830bc42c9800ce07dd97fa94669dfb93d3bf5fcf6ea7a0c67b2e0e4a7f26c", [:mix], [{:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cfa158c02d3f5c0c665d0af11512fed3fba0144cf1aadee0f2ce17747fba2ca9"},
"makeup_elixir": {:hex, :makeup_elixir, "0.15.1", "b5888c880d17d1cc3e598f05cdb5b5a91b7b17ac4eaf5f297cb697663a1094dd", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "db68c173234b07ab2a07f645a5acdc117b9f99d69ebf521821d89690ae6c6ec8"}, "makeup_elixir": {:hex, :makeup_elixir, "0.15.1", "b5888c880d17d1cc3e598f05cdb5b5a91b7b17ac4eaf5f297cb697663a1094dd", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "db68c173234b07ab2a07f645a5acdc117b9f99d69ebf521821d89690ae6c6ec8"},
"makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"},
@ -55,7 +55,7 @@
"neotomex": {:hex, :neotomex, "0.1.7", "64f76513653aa87ea7abdde0fd600e56955d838020a13d88f2bf334c88ac3e7a", [:mix], [], "hexpm", "4b87b8f614d1cd89dc8ba80ba0e559bedb3ebf6f6d74cd774fcfdd215e861445"}, "neotomex": {:hex, :neotomex, "0.1.7", "64f76513653aa87ea7abdde0fd600e56955d838020a13d88f2bf334c88ac3e7a", [:mix], [], "hexpm", "4b87b8f614d1cd89dc8ba80ba0e559bedb3ebf6f6d74cd774fcfdd215e861445"},
"nimble_parsec": {:hex, :nimble_parsec, "1.1.0", "3a6fca1550363552e54c216debb6a9e95bd8d32348938e13de5eda962c0d7f89", [:mix], [], "hexpm", "08eb32d66b706e913ff748f11694b17981c0b04a33ef470e33e11b3d3ac8f54b"}, "nimble_parsec": {:hex, :nimble_parsec, "1.1.0", "3a6fca1550363552e54c216debb6a9e95bd8d32348938e13de5eda962c0d7f89", [:mix], [], "hexpm", "08eb32d66b706e913ff748f11694b17981c0b04a33ef470e33e11b3d3ac8f54b"},
"oban": {:hex, :oban, "2.1.0", "034144686f7e76a102b5d67731f098d98a9e4a52b07c25ad580a01f83a7f1cf5", [:mix], [{:ecto_sql, ">= 3.4.3", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c6f067fa3b308ed9e0e6beb2b34277c9c4e48bf95338edabd8f4a757a26e04c2"}, "oban": {:hex, :oban, "2.1.0", "034144686f7e76a102b5d67731f098d98a9e4a52b07c25ad580a01f83a7f1cf5", [:mix], [{:ecto_sql, ">= 3.4.3", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c6f067fa3b308ed9e0e6beb2b34277c9c4e48bf95338edabd8f4a757a26e04c2"},
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"}, "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
"phoenix": {:hex, :phoenix, "1.5.9", "a6368d36cfd59d917b37c44386e01315bc89f7609a10a45a22f47c007edf2597", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 2.13 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.1.2 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7e4bce20a67c012f1fbb0af90e5da49fa7bf0d34e3a067795703b74aef75427d"}, "phoenix": {:hex, :phoenix, "1.5.9", "a6368d36cfd59d917b37c44386e01315bc89f7609a10a45a22f47c007edf2597", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 2.13 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.1.2 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7e4bce20a67c012f1fbb0af90e5da49fa7bf0d34e3a067795703b74aef75427d"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.1.0", "a044d0756d0464c5a541b4a0bf4bcaf89bffcaf92468862408290682c73ae50d", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "c5e666a341ff104d0399d8f0e4ff094559b2fde13a5985d4cb5023b2c2ac558b"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.1.0", "a044d0756d0464c5a541b4a0bf4bcaf89bffcaf92468862408290682c73ae50d", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "c5e666a341ff104d0399d8f0e4ff094559b2fde13a5985d4cb5023b2c2ac558b"},
"phoenix_html": {:hex, :phoenix_html, "2.14.3", "51f720d0d543e4e157ff06b65de38e13303d5778a7919bcc696599e5934271b8", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "efd697a7fff35a13eeeb6b43db884705cba353a1a41d127d118fda5f90c8e80f"}, "phoenix_html": {:hex, :phoenix_html, "2.14.3", "51f720d0d543e4e157ff06b65de38e13303d5778a7919bcc696599e5934271b8", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "efd697a7fff35a13eeeb6b43db884705cba353a1a41d127d118fda5f90c8e80f"},
@ -64,7 +64,7 @@
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.2.4", "940c0344b1d66a2e46eef02af3a70e0c5bb45a4db0bf47917add271b76cd3914", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "38f9308357dea4cc77f247e216da99fcb0224e05ada1469167520bed4cb8cccd"}, "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.2.4", "940c0344b1d66a2e46eef02af3a70e0c5bb45a4db0bf47917add271b76cd3914", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "38f9308357dea4cc77f247e216da99fcb0224e05ada1469167520bed4cb8cccd"},
"phoenix_live_view": {:hex, :phoenix_live_view, "0.15.7", "09720b8e5151b3ca8ef739cd7626d4feb987c69ba0b509c9bbdb861d5a365881", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.5.7", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 0.5", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3a756cf662420272d0f1b3b908cce5222163b5a95aa9bab404f9d29aff53276e"}, "phoenix_live_view": {:hex, :phoenix_live_view, "0.15.7", "09720b8e5151b3ca8ef739cd7626d4feb987c69ba0b509c9bbdb861d5a365881", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.5.7", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 0.5", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3a756cf662420272d0f1b3b908cce5222163b5a95aa9bab404f9d29aff53276e"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.0.0", "a1ae76717bb168cdeb10ec9d92d1480fec99e3080f011402c0a2d68d47395ffb", [:mix], [], "hexpm", "c52d948c4f261577b9c6fa804be91884b381a7f8f18450c5045975435350f771"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.0.0", "a1ae76717bb168cdeb10ec9d92d1480fec99e3080f011402c0a2d68d47395ffb", [:mix], [], "hexpm", "c52d948c4f261577b9c6fa804be91884b381a7f8f18450c5045975435350f771"},
"php_serializer": {:hex, :php_serializer, "0.9.2", "59c5fd6bd3096671fd89358fb8229341ac7423b50ad8d45a15213b02ea2edab2", [:mix], [], "hexpm", "34eb835a460944f7fc216773b363c02e7dcf8ac0390c9e9ccdbd92b31a7ca59a"}, "php_serializer": {:hex, :php_serializer, "2.0.0", "b43f31aca22ed7321f32da2b94fe2ddf9b6739a965cb51541969119e572e821d", [:mix], [], "hexpm", "61e402e99d9062c0225a3f4fcf7e43b4cba1b8654944c0e7c139c3ca9de481da"},
"plug": {:hex, :plug, "1.12.1", "645678c800601d8d9f27ad1aebba1fdb9ce5b2623ddb961a074da0b96c35187d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d57e799a777bc20494b784966dc5fbda91eb4a09f571f76545b72a634ce0d30b"}, "plug": {:hex, :plug, "1.12.1", "645678c800601d8d9f27ad1aebba1fdb9ce5b2623ddb961a074da0b96c35187d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d57e799a777bc20494b784966dc5fbda91eb4a09f571f76545b72a634ce0d30b"},
"plug_cowboy": {:hex, :plug_cowboy, "2.5.1", "7cc96ff645158a94cf3ec9744464414f02287f832d6847079adfe0b58761cbd0", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "107d0a5865fa92bcb48e631cc0729ae9ccfa0a9f9a1bd8f01acb513abf1c2d64"}, "plug_cowboy": {:hex, :plug_cowboy, "2.5.1", "7cc96ff645158a94cf3ec9744464414f02287f832d6847079adfe0b58761cbd0", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "107d0a5865fa92bcb48e631cc0729ae9ccfa0a9f9a1bd8f01acb513abf1c2d64"},
"plug_crypto": {:hex, :plug_crypto, "1.2.2", "05654514ac717ff3a1843204b424477d9e60c143406aa94daf2274fdd280794d", [:mix], [], "hexpm", "87631c7ad914a5a445f0a3809f99b079113ae4ed4b867348dd9eec288cecb6db"}, "plug_crypto": {:hex, :plug_crypto, "1.2.2", "05654514ac717ff3a1843204b424477d9e60c143406aa94daf2274fdd280794d", [:mix], [], "hexpm", "87631c7ad914a5a445f0a3809f99b079113ae4ed4b867348dd9eec288cecb6db"},
@ -79,9 +79,9 @@
"telemetry": {:hex, :telemetry, "0.4.3", "a06428a514bdbc63293cd9a6263aad00ddeb66f608163bdec7c8995784080818", [:rebar3], [], "hexpm", "eb72b8365ffda5bed68a620d1da88525e326cb82a75ee61354fc24b844768041"}, "telemetry": {:hex, :telemetry, "0.4.3", "a06428a514bdbc63293cd9a6263aad00ddeb66f608163bdec7c8995784080818", [:rebar3], [], "hexpm", "eb72b8365ffda5bed68a620d1da88525e326cb82a75ee61354fc24b844768041"},
"telemetry_metrics": {:hex, :telemetry_metrics, "0.6.0", "da9d49ee7e6bb1c259d36ce6539cd45ae14d81247a2b0c90edf55e2b50507f7b", [:mix], [{:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5cfe67ad464b243835512aa44321cee91faed6ea868d7fb761d7016e02915c3d"}, "telemetry_metrics": {:hex, :telemetry_metrics, "0.6.0", "da9d49ee7e6bb1c259d36ce6539cd45ae14d81247a2b0c90edf55e2b50507f7b", [:mix], [{:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5cfe67ad464b243835512aa44321cee91faed6ea868d7fb761d7016e02915c3d"},
"telemetry_poller": {:hex, :telemetry_poller, "0.5.1", "21071cc2e536810bac5628b935521ff3e28f0303e770951158c73eaaa01e962a", [:rebar3], [{:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4cab72069210bc6e7a080cec9afffad1b33370149ed5d379b81c7c5f0c663fd4"}, "telemetry_poller": {:hex, :telemetry_poller, "0.5.1", "21071cc2e536810bac5628b935521ff3e28f0303e770951158c73eaaa01e962a", [:rebar3], [{:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4cab72069210bc6e7a080cec9afffad1b33370149ed5d379b81c7c5f0c663fd4"},
"timex": {:hex, :timex, "3.6.2", "845cdeb6119e2fef10751c0b247b6c59d86d78554c83f78db612e3290f819bc2", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5 or ~> 1.0.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "26030b46199d02a590be61c2394b37ea25a3664c02fafbeca0b24c972025d47a"}, "timex": {:hex, :timex, "3.7.5", "3eca56e23bfa4e0848f0b0a29a92fa20af251a975116c6d504966e8a90516dfd", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "a15608dca680f2ef663d71c95842c67f0af08a0f3b1d00e17bbd22872e2874e4"},
"tzdata": {:hex, :tzdata, "1.0.3", "73470ad29dde46e350c60a66e6b360d3b99d2d18b74c4c349dbebbc27a09a3eb", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a6e1ee7003c4d04ecbd21dd3ec690d4c6662db5d3bbdd7262d53cdf5e7c746c1"}, "tzdata": {:hex, :tzdata, "1.1.0", "72f5babaa9390d0f131465c8702fa76da0919e37ba32baa90d93c583301a8359", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "18f453739b48d3dc5bcf0e8906d2dc112bb40baafe2c707596d89f3c8dd14034"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.5.0", "8516502659002cec19e244ebd90d312183064be95025a319a6c7e89f4bccd65b", [:rebar3], [], "hexpm", "d48d002e15f5cc105a696cf2f1bbb3fc72b4b770a184d8420c8db20da2674b38"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
"xml_builder": {:hex, :xml_builder, "2.1.2", "90cb9ad382958934c78c6ddfbe6d385a8ce147d84b61cbfa83ec93a169d0feab", [:mix], [], "hexpm", "b89046041da2fbc1d51d31493ba31b9d5fc6223c93384bf513a1a9e1df9ec081"}, "xml_builder": {:hex, :xml_builder, "2.1.2", "90cb9ad382958934c78c6ddfbe6d385a8ce147d84b61cbfa83ec93a169d0feab", [:mix], [], "hexpm", "b89046041da2fbc1d51d31493ba31b9d5fc6223c93384bf513a1a9e1df9ec081"},
"yamerl": {:hex, :yamerl, "0.8.1", "07da13ffa1d8e13948943789665c62ccd679dfa7b324a4a2ed3149df17f453a4", [:rebar3], [], "hexpm", "96cb30f9d64344fed0ef8a92e9f16f207de6c04dfff4f366752ca79f5bceb23f"}, "yamerl": {:hex, :yamerl, "0.8.1", "07da13ffa1d8e13948943789665c62ccd679dfa7b324a4a2ed3149df17f453a4", [:rebar3], [], "hexpm", "96cb30f9d64344fed0ef8a92e9f16f207de6c04dfff4f366752ca79f5bceb23f"},
"yaml_elixir": {:hex, :yaml_elixir, "2.8.0", "c7ff0034daf57279c2ce902788ce6fdb2445532eb4317e8df4b044209fae6832", [:mix], [{:yamerl, "~> 0.8", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm", "4b674bd881e373d1ac6a790c64b2ecb69d1fd612c2af3b22de1619c15473830b"}, "yaml_elixir": {:hex, :yaml_elixir, "2.8.0", "c7ff0034daf57279c2ce902788ce6fdb2445532eb4317e8df4b044209fae6832", [:mix], [{:yamerl, "~> 0.8", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm", "4b674bd881e373d1ac6a790c64b2ecb69d1fd612c2af3b22de1619c15473830b"},

16
package-lock.json generated
View file

@ -1,12 +1,12 @@
{ {
"name": "@mythic-insight/legendary", "name": "@mythic-insight/legendary",
"version": "2.9.1", "version": "2.12.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@mythic-insight/legendary", "name": "@mythic-insight/legendary",
"version": "2.9.1", "version": "2.12.0",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@google/semantic-release-replace-plugin": "^1.0.2", "@google/semantic-release-replace-plugin": "^1.0.2",
@ -5035,9 +5035,9 @@
} }
}, },
"node_modules/hosted-git-info": { "node_modules/hosted-git-info": {
"version": "2.8.8", "version": "2.8.9",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
"integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
"dev": true "dev": true
}, },
"node_modules/http-proxy": { "node_modules/http-proxy": {
@ -10844,9 +10844,9 @@
"dev": true "dev": true
}, },
"hosted-git-info": { "hosted-git-info": {
"version": "2.8.8", "version": "2.8.9",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
"integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
"dev": true "dev": true
}, },
"http-proxy": { "http-proxy": {

View file

@ -1,6 +1,6 @@
{ {
"name": "@mythic-insight/legendary", "name": "@mythic-insight/legendary",
"version": "2.10.0", "version": "3.1.2",
"private": true, "private": true,
"description": "The Legendary Phoenix Boilerplate.", "description": "The Legendary Phoenix Boilerplate.",
"main": "index.js", "main": "index.js",

View file

@ -12,6 +12,10 @@ mix deps.get
mix ecto.create mix ecto.create
mix ecto.migrate mix ecto.migrate
mix test if [ $1 == 'covered' ]; then
mix coveralls.json --umbrella
else
mix test
fi;
script/restore-timestamps script/restore-timestamps

124
script/coverage-json-to-cobertura Executable file
View file

@ -0,0 +1,124 @@
#!/usr/bin/env elixir
Mix.install([
{:jason, "~> 1.0"},
{:xml_builder, "~> 2.1"}
])
%{"source_files" => data} =
"cover/excoveralls.json"
|> File.read!()
|> Jason.decode!()
{total_covered, total_total} =
data
|> Enum.reduce({0,0}, fn %{"coverage" => cover}, {covered, total} ->
file_covered =
cover
|> Enum.reduce(0, &(if is_integer(&1) && &1 > 0, do: &2 + 1, else: &2))
file_total =
cover
|> Enum.reduce(0, &(if is_nil(&1), do: &2, else: &2 + 1))
{covered + file_covered, total + file_total}
end)
ratio = total_covered / total_total
files =
data
|> Enum.map(fn %{"coverage" => cover, "name" => name} ->
file_covered =
cover
|> Enum.reduce(0, &(if is_integer(&1) && &1 > 0, do: &2 + 1, else: &2))
file_total =
cover
|> Enum.reduce(0, &(if is_nil(&1), do: &2, else: &2 + 1))
lines =
cover
|> Enum.with_index
|> Enum.map(fn
{nil, _index} ->
nil
{line, index} ->
{:line, %{"number" => index, "hits" => line}, []}
end)
|> Enum.reject(&is_nil/1)
ratio =
if file_total == 0 do
1.0
else
file_covered / file_total
end
{
:class,
%{"filename" => name, "line-rate" => ratio},
[
{
:lines,
%{},
lines
}
]
}
end)
source =
if System.get_env("CI_PROJECT_NAME") do
"#{System.get_env("CI_BUILDS_DIR")}/#{System.get_env("CI_PROJECT_NAMESPACE")}/#{System.get_env("CI_PROJECT_NAME")}"
else
File.cwd!
end
buffer =
XmlBuilder.document([
XmlBuilder.doctype(
"coverage",
system: ["http://cobertura.sourceforge.net/xml/coverage-03.dtd"]
),
{
:coverage,
%{
"line-rate" => ratio,
},
[
{
:sources,
%{},
[
{
:source,
%{},
source
}
]
},
{
:packages,
%{},
[
{
:package,
%{"name" => "", "line-rate" => ratio},
[
{
:classes,
%{},
files
}
]
}
]
}
]
}
])
|> XmlBuilder.generate
File.write!("cover/cobertura.xml", buffer)

30
script/coverage-json-to-metrics Executable file
View file

@ -0,0 +1,30 @@
#!/usr/bin/env elixir
Mix.install([
{:jason, "~> 1.0"}
])
%{"source_files" => data} =
"cover/excoveralls.json"
|> File.read!()
|> Jason.decode!()
{total_covered, total_total} =
data
|> Enum.reduce({0,0}, fn %{"coverage" => cover}, {covered, total} ->
file_covered =
cover
|> Enum.reduce(0, &(if is_integer(&1) && &1 > 0, do: &2 + 1, else: &2))
file_total =
cover
|> Enum.reduce(0, &(if is_nil(&1), do: &2, else: &2 + 1))
{covered + file_covered, total + file_total}
end)
ratio =
(total_covered / total_total)
|> Float.round(3)
File.write!("metrics.txt", "coverage #{ratio}")