Page MenuHomePhorge

No OneTemporary

Size
26 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/mix/tasks/pleroma/frontend.ex b/lib/mix/tasks/pleroma/frontend.ex
index bc048014e..b3b3caa9b 100644
--- a/lib/mix/tasks/pleroma/frontend.ex
+++ b/lib/mix/tasks/pleroma/frontend.ex
@@ -1,264 +1,313 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Mix.Tasks.Pleroma.Frontend do
use Mix.Task
import Mix.Pleroma
@shortdoc "Manages bundled Pleroma frontends"
@moduledoc File.read!("docs/administration/CLI_tasks/frontend.md")
@frontends %{
"admin" => %{"project" => "pleroma/admin-fe"},
"kenoma" => %{"project" => "lambadalambda/kenoma"},
"mastodon" => %{"project" => "pleroma/mastofe"},
"pleroma" => %{"project" => "pleroma/pleroma-fe"},
"fedi" => %{"project" => "dockyard/fedi-fe"}
}
@known_frontends Map.keys(@frontends)
@ref_local "__local__"
@ref_develop "__develop__"
@ref_stable "__stable__"
@pleroma_gitlab_host "git.pleroma.social"
def run(["install", "none" | _args]) do
shell_info("Skipping frontend installation because none was requested")
"none"
end
- def run(["install", "all"]) do
+ def run(["install", "all" | options]) do
start_pleroma()
configs = Pleroma.Config.get(:frontends, %{})
with config when not is_nil(config) <- configs[:primary],
ref when ref != "none" <- config["ref"] do
- run(["install", config["name"], "--ref", ref])
+ run(["install", config["name"], "--ref", ref | options])
end
with config when not is_nil(config) <- configs[:mastodon],
ref when ref != "none" <- config["ref"] do
- run(["install", "mastodon", "--ref", ref])
+ run(["install", "mastodon", "--ref", ref | options])
end
with config when not is_nil(config) <- configs[:admin],
ref when ref != "none" <- config["ref"] do
- run(["install", "admin", "--ref", ref])
+ run(["install", "admin", "--ref", ref | options])
end
end
def run(["install", unknown_fe | _args]) when unknown_fe not in @known_frontends do
shell_error(
"Frontend \"#{unknown_fe}\" is not known. Known frontends are: #{
Enum.join(@known_frontends, ", ")
}"
)
end
def run(["install", frontend | args]) do
log_level = Logger.level()
Logger.configure(level: :warn)
start_pleroma()
{options, [], []} =
OptionParser.parse(
args,
strict: [
ref: :string,
path: :string,
develop: :boolean,
static_dir: :string
]
)
instance_static_dir =
with nil <- options[:static_dir] do
Pleroma.Config.get!([:instance, :static_dir])
end
ref =
case options[:path] do
nil ->
ref0 =
cond do
options[:ref] -> options[:ref]
options[:develop] -> @ref_develop
true -> @ref_stable
end
web_frontend_ref(frontend, ref0)
path ->
local_path_frontend_ref(path)
end
dest =
Path.join([
instance_static_dir,
"frontends",
frontend,
ref
])
fe_label = "#{frontend} (#{ref})"
- from =
+ {from, proceed?} =
with nil <- options[:path] do
- Pleroma.Utils.command_required!("yarn")
+ tmp_dir = Path.join(dest, "tmp/src")
- url = archive_url(frontend, ref)
+ shell_info("Downloading pre-built bundle for #{fe_label}")
- tmp_dir = Path.join(dest, "tmp/src")
+ proceed? =
+ with {:error, error} <- download_frontend(frontend, ref, tmp_dir, :build) do
+ shell_info("Could not download pre-built bundle: #{inspect(error)}.")
+ shell_info("Falling back to building locally from source")
+
+ download_and_build = fn callback ->
+ case Pleroma.Utils.command_available?("yarn") do
+ false ->
+ message =
+ "To build frontend #{fe_label} from sources, `yarn` command is required. Please install it before continue. ([C]ontinue/[A]bort)"
+
+ case String.downcase(shell_prompt(message, "C")) do
+ abort when abort in ["a", "abort"] ->
+ false
+
+ _continue ->
+ callback.(callback)
+ end
+
+ _ ->
+ shell_info("Downloading #{fe_label} sources to #{tmp_dir}")
+ :ok = download_frontend(frontend, ref, tmp_dir, :source)
+
+ shell_info("Building #{fe_label} (this will take some time)")
+ :ok = build_frontend(frontend, tmp_dir)
+ end
+ end
- shell_info("Downloading #{fe_label} to #{tmp_dir}")
- :ok = download_frontend(url, tmp_dir)
+ download_and_build.(download_and_build)
+ else
+ _ ->
+ true
+ end
- shell_info("Building #{fe_label} (this will take some time)")
- :ok = build_frontend(frontend, tmp_dir)
- tmp_dir
+ {tmp_dir, proceed?}
+ else
+ path ->
+ {path, true}
end
- shell_info("Installing #{fe_label} to #{dest}")
+ if proceed? do
+ shell_info("Installing #{fe_label} to #{dest}")
+
+ :ok = install_frontend(frontend, from, dest)
- :ok = install_frontend(frontend, from, dest)
+ shell_info("Frontend #{fe_label} installed to #{dest}")
+ end
- shell_info("Frontend #{fe_label} installed to #{dest}")
Logger.configure(level: log_level)
ref
end
- defp download_frontend(url, dest) do
+ defp download_frontend(frontend, ref, dest, kind) do
+ url = frontend_url(frontend, ref, kind)
+
with {:ok, %{status: 200, body: zip_body}} <-
Pleroma.HTTP.get(url, [], timeout: 120_000, recv_timeout: 120_000),
{:ok, unzipped} <- :zip.unzip(zip_body, [:memory]) do
File.rm_rf!(dest)
File.mkdir_p!(dest)
Enum.each(unzipped, fn {filename, data} ->
- [_root | paths] = Path.split(filename)
- path = Enum.join(paths, "/")
+ path =
+ case kind do
+ :source ->
+ filename
+ |> Path.split()
+ |> Enum.drop(1)
+ |> Enum.join("/")
+
+ :build ->
+ filename
+ end
+
new_file_path = Path.join(dest, path)
new_file_path
|> Path.dirname()
|> File.mkdir_p!()
File.write!(new_file_path, data)
end)
else
{:ok, %{status: 404}} ->
- {:error, "Bundle not found"}
-
- false ->
- {:error, "Zip archive must contain \"dist\" folder"}
+ {:error, "Zip archive with frontend #{kind} not found at #{url}"}
error ->
{:error, error}
end
end
defp build_frontend("admin", path) do
yarn = Pleroma.Config.get(:yarn, "yarn")
{_out, 0} = System.cmd(yarn, [], cd: path)
{_out, 0} = System.cmd(yarn, ["build:prod"], cd: path)
:ok
end
defp build_frontend(_frontend, path) do
yarn = Pleroma.Config.get(:yarn, "yarn")
{_out, 0} = System.cmd(yarn, [], cd: path)
{_out, 0} = System.cmd(yarn, ["build"], cd: path)
:ok
end
defp web_frontend_ref(frontend, @ref_develop) do
url = project_url(frontend) <> "/repository/branches"
{:ok, %{status: 200, body: body}} =
Pleroma.HTTP.get(url, [], timeout: 120_000, recv_timeout: 120_000)
json = Jason.decode!(body)
%{"commit" => %{"short_id" => last_commit_ref}} = Enum.find(json, & &1["default"])
last_commit_ref
end
# fallback to develop version if compatible stable ref is not defined in
# mix.exs for the given frontend
defp web_frontend_ref(frontend, @ref_stable) do
case Map.get(Pleroma.Application.frontends(), frontend) do
nil ->
web_frontend_ref(frontend, @ref_develop)
ref ->
ref
end
end
defp web_frontend_ref(_frontend, ref), do: ref
defp project_url(frontend),
do:
"https://#{@pleroma_gitlab_host}/api/v4/projects/#{
URI.encode_www_form(@frontends[frontend]["project"])
}"
- defp archive_url(frontend, ref),
+ defp source_url(frontend, ref),
do: "https://#{@pleroma_gitlab_host}/#{@frontends[frontend]["project"]}/-/archive/#{ref}.zip"
+ defp build_url(frontend, ref),
+ do:
+ "https://#{@pleroma_gitlab_host}/#{@frontends[frontend]["project"]}/-/jobs/artifacts/#{ref}/download?job=build"
+
+ defp frontend_url(frontend, ref, :source), do: source_url(frontend, ref)
+ defp frontend_url(frontend, ref, :build), do: build_url(frontend, ref)
+
defp local_path_frontend_ref(path) do
path
|> Path.join("package.json")
|> File.read()
|> case do
{:ok, bin} ->
bin
|> Jason.decode!()
|> Map.get("version", @ref_local)
_ ->
@ref_local
end
end
defp post_install("mastodon", path) do
File.rename!("#{path}/assets/sw.js", "#{path}/sw.js")
{:ok, files} = File.ls(path)
Enum.each(files, fn file ->
with false <- file in ~w(packs sw.js) do
[path, file]
|> Path.join()
|> File.rm_rf!()
end
end)
end
defp post_install(_frontend, _path) do
:ok
end
defp install_frontend(frontend, source, dest) do
from =
case frontend do
"mastodon" ->
"public"
"kenoma" ->
"build"
_ ->
"dist"
end
File.mkdir_p!(dest)
File.cp_r!(Path.join([source, from]), dest)
post_install(frontend, dest)
end
end
diff --git a/lib/mix/tasks/pleroma/instance.ex b/lib/mix/tasks/pleroma/instance.ex
index f57053a4c..0355b8881 100644
--- a/lib/mix/tasks/pleroma/instance.ex
+++ b/lib/mix/tasks/pleroma/instance.ex
@@ -1,336 +1,321 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Mix.Tasks.Pleroma.Instance do
use Mix.Task
import Mix.Pleroma
alias Pleroma.Config
@shortdoc "Manages Pleroma instance"
@moduledoc File.read!("docs/administration/CLI_tasks/instance.md")
def run(["gen" | rest]) do
{options, [], []} =
OptionParser.parse(
rest,
strict: [
force: :boolean,
output: :string,
output_psql: :string,
domain: :string,
instance_name: :string,
admin_email: :string,
notify_email: :string,
dbhost: :string,
dbname: :string,
dbuser: :string,
dbpass: :string,
rum: :string,
indexable: :string,
db_configurable: :string,
uploads_dir: :string,
static_dir: :string,
listen_ip: :string,
listen_port: :string,
fe_primary: :string,
fe_mastodon: :string,
fe_admin: :string,
fe_static: :string
],
aliases: [
o: :output,
f: :force
]
)
paths =
[config_path, psql_path] = [
Keyword.get(options, :output, "config/generated_config.exs"),
Keyword.get(options, :output_psql, "config/setup_db.psql")
]
will_overwrite = Enum.filter(paths, &File.exists?/1)
proceed? = Enum.empty?(will_overwrite) or Keyword.get(options, :force, false)
if proceed? do
[domain, port | _] =
String.split(
get_option(
options,
:domain,
"What domain will your instance use? (e.g pleroma.soykaf.com)"
),
":"
) ++ [443]
name =
get_option(
options,
:instance_name,
"What is the name of your instance? (e.g. The Corndog Emporium)",
domain
)
email = get_option(options, :admin_email, "What is your admin email address?")
notify_email =
get_option(
options,
:notify_email,
"What email address do you want to use for sending email notifications?",
email
)
indexable =
get_option(
options,
:indexable,
"Do you want search engines to index your site? (y/n)",
"y"
) === "y"
db_configurable? =
get_option(
options,
:db_configurable,
"Do you want to store the configuration in the database (allows controlling it from admin-fe)? (y/n)",
"n"
) === "y"
dbhost = get_option(options, :dbhost, "What is the hostname of your database?", "localhost")
dbname = get_option(options, :dbname, "What is the name of your database?", "pleroma")
dbuser =
get_option(
options,
:dbuser,
"What is the user used to connect to your database?",
"pleroma"
)
dbpass =
get_option(
options,
:dbpass,
"What is the password used to connect to your database?",
:crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64),
"autogenerated"
)
rum_enabled =
get_option(
options,
:rum,
"Would you like to use RUM indices?",
"n"
) === "y"
listen_port =
get_option(
options,
:listen_port,
"What port will the app listen to (leave it if you are using the default setup with nginx)?",
4000
)
listen_ip =
get_option(
options,
:listen_ip,
"What ip will the app listen to (leave it if you are using the default setup with nginx)?",
"127.0.0.1"
)
uploads_dir =
get_option(
options,
:uploads_dir,
"What directory should media uploads go in (when using the local uploader)?",
Config.get([Pleroma.Uploaders.Local, :uploads])
)
|> Path.expand()
static_dir =
get_option(
options,
:static_dir,
"What directory should custom public files be read from (custom emojis, frontend bundle overrides, robots.txt, etc.)?",
Config.get([:instance, :static_dir])
)
|> Path.expand()
install_fe =
case Mix.env() do
:test ->
- fn _, _ -> "42" end
+ fn _ -> "42" end
_ ->
- fn frontend, callback ->
- case Pleroma.Utils.command_available?("yarn") do
- false when frontend != "none" ->
- message =
- "To install #{frontend} frontend, `yarn` command is required. Please install it before continue. ([C]ontinue/[A]bort)"
-
- case String.downcase(shell_prompt(message, "C")) do
- abort when abort in ["a", "abort"] ->
- "none"
-
- _continue ->
- callback.(frontend, callback)
- end
-
- _ ->
- Mix.Tasks.Pleroma.Frontend.run([
- "install",
- frontend,
- "--static-dir",
- static_dir
- ])
- end
+ fn frontend ->
+ Mix.Tasks.Pleroma.Frontend.run([
+ "install",
+ frontend,
+ "--static-dir",
+ static_dir
+ ])
end
end
fe_primary =
get_option(
options,
:fe_primary,
"Choose primary frontend for your instance (available: pleroma/kenoma/none)",
"pleroma"
)
- fe_primary_ref = install_fe.(fe_primary, install_fe)
+ fe_primary_ref = install_fe.(fe_primary)
enable_static_fe? =
get_option(
options,
:fe_static,
"Would you like to enable Static frontend (render profiles and posts using server-generated HTML that is viewable without using JavaScript)?",
"y"
) === "y"
install_mastodon_fe? =
get_option(
options,
:fe_mastodon,
"Would you like to install Mastodon frontend?",
"y"
) === "y"
fe_mastodon_ref =
case install_mastodon_fe? do
true ->
- install_fe.("mastodon", install_fe)
+ install_fe.("mastodon")
false ->
"none"
end
install_admin_fe? =
get_option(
options,
:fe_admin,
"Would you like to install Admin frontend?",
"y"
) === "y"
fe_admin_ref =
case install_admin_fe? do
- true -> install_fe.("admin", install_fe)
+ true -> install_fe.("admin")
false -> "none"
end
secret = :crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64)
jwt_secret = :crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64)
signing_salt = :crypto.strong_rand_bytes(8) |> Base.encode64() |> binary_part(0, 8)
{web_push_public_key, web_push_private_key} = :crypto.generate_key(:ecdh, :prime256v1)
template_dir = Application.app_dir(:pleroma, "priv") <> "/templates"
result_config =
EEx.eval_file(
template_dir <> "/sample_config.eex",
domain: domain,
port: port,
email: email,
notify_email: notify_email,
name: name,
dbhost: dbhost,
dbname: dbname,
dbuser: dbuser,
dbpass: dbpass,
secret: secret,
jwt_secret: jwt_secret,
signing_salt: signing_salt,
web_push_public_key: Base.url_encode64(web_push_public_key, padding: false),
web_push_private_key: Base.url_encode64(web_push_private_key, padding: false),
db_configurable?: db_configurable?,
static_dir: static_dir,
uploads_dir: uploads_dir,
rum_enabled: rum_enabled,
listen_ip: listen_ip,
listen_port: listen_port,
fe_primary: %{"name" => fe_primary, "ref" => fe_primary_ref},
fe_mastodon: %{"name" => "mastodon", "ref" => fe_mastodon_ref},
fe_admin: %{"name" => "admin", "ref" => fe_admin_ref},
enable_static_fe?: enable_static_fe?
)
result_psql =
EEx.eval_file(
template_dir <> "/sample_psql.eex",
dbname: dbname,
dbuser: dbuser,
dbpass: dbpass,
rum_enabled: rum_enabled
)
shell_info("Writing config to #{config_path}.")
File.write(config_path, result_config)
shell_info("Writing the postgres script to #{psql_path}.")
File.write(psql_path, result_psql)
write_robots_txt(static_dir, indexable, template_dir)
shell_info(
"\n All files successfully written! Refer to the installation instructions for your platform for next steps."
)
if db_configurable? do
shell_info(
" Please transfer your config to the database after running database migrations. Refer to \"Transfering the config to/from the database\" section of the docs for more information."
)
end
else
shell_error(
"The task would have overwritten the following files:\n" <>
(Enum.map(paths, &"- #{&1}\n") |> Enum.join("")) <>
"Rerun with `--force` to overwrite them."
)
end
end
defp write_robots_txt(static_dir, indexable, template_dir) do
robots_txt =
EEx.eval_file(
template_dir <> "/robots_txt.eex",
indexable: indexable
)
unless File.exists?(static_dir) do
File.mkdir_p!(static_dir)
end
robots_txt_path = Path.join(static_dir, "robots.txt")
if File.exists?(robots_txt_path) do
File.cp!(robots_txt_path, "#{robots_txt_path}.bak")
shell_info("Backing up existing robots.txt to #{robots_txt_path}.bak")
end
File.write(robots_txt_path, robots_txt)
shell_info("Writing #{robots_txt_path}.")
end
end
diff --git a/test/fixtures/tesla_mock/fe-build.zip b/test/fixtures/tesla_mock/fe-build.zip
new file mode 100644
index 000000000..fbe460dbf
Binary files /dev/null and b/test/fixtures/tesla_mock/fe-build.zip differ
diff --git a/test/fixtures/tesla_mock/fe-bundle.zip b/test/fixtures/tesla_mock/fe-source.zip
similarity index 100%
rename from test/fixtures/tesla_mock/fe-bundle.zip
rename to test/fixtures/tesla_mock/fe-source.zip
diff --git a/test/tasks/frontend_test.exs b/test/tasks/frontend_test.exs
index fb5da2d30..5e2e9405d 100644
--- a/test/tasks/frontend_test.exs
+++ b/test/tasks/frontend_test.exs
@@ -1,151 +1,174 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Mix.Tasks.Pleroma.FrontendTest do
use ExUnit.Case
use Pleroma.Tests.Helpers
import Tesla.Mock, only: [mock_global: 1, json: 1]
- @bundle_zip_path Path.absname("test/fixtures/tesla_mock/fe-bundle.zip")
+ @fe_source_zip_path Path.absname("test/fixtures/tesla_mock/fe-source.zip")
+ @fe_build_zip_path Path.absname("test/fixtures/tesla_mock/fe-build.zip")
@tmp "test/tmp"
@dir "#{@tmp}/instance_static"
setup_all do
Mix.shell(Mix.Shell.Process)
on_exit(fn ->
Mix.shell(Mix.Shell.IO)
end)
:ok
end
setup do
mock_global(fn
%{method: :get, url: "https://git.pleroma.social/api/v4/projects/" <> rest} ->
if String.ends_with?(rest, "repository/branches") do
"test/fixtures/tesla_mock/gitlab-api-pleroma-fe-branches.json"
else
"test/fixtures/tesla_mock/gitlab-api-pleroma-fe-releases.json"
end
|> Path.absname()
|> File.read!()
|> Jason.decode!()
|> json()
- %{method: :get, url: _download_url} ->
- %Tesla.Env{status: 200, body: File.read!(@bundle_zip_path)}
+ %{method: :get, url: download_url} ->
+ cond do
+ String.contains?(download_url, "test-bundle") ->
+ %Tesla.Env{status: 200, body: File.read!(@fe_build_zip_path)}
+
+ String.ends_with?(download_url, "job=build") ->
+ %Tesla.Env{status: 404}
+
+ true ->
+ %Tesla.Env{status: 200, body: File.read!(@fe_source_zip_path)}
+ end
end)
File.mkdir_p!(@dir)
on_exit(fn -> File.rm_rf(@dir) end)
clear_config([:instance, :static_dir], @dir)
:ok
end
describe "Installations from local path" do
test "Frontends with standard dist structure" do
~w(pleroma kenoma admin)
|> Enum.each(fn frontend ->
path = "test/fixtures/frontends/#{frontend}"
Mix.Tasks.Pleroma.Frontend.run(~w(install #{frontend} --path #{path}))
assert File.exists?("#{@dir}/frontends/#{frontend}/42/index.html")
refute File.exists?("#{@dir}/frontends/#{frontend}/42/package.json")
end)
end
test "Mastodon" do
path = "test/fixtures/frontends/mastodon"
Mix.Tasks.Pleroma.Frontend.run(~w(install mastodon --path #{path}))
assert File.exists?("#{@dir}/frontends/mastodon/__local__/sw.js")
assert File.exists?("#{@dir}/frontends/mastodon/__local__/packs/locales.js")
refute File.exists?("#{@dir}/frontends/mastodon/__local__/unused_file")
refute File.exists?("#{@dir}/frontends/mastodon/__local__/unused_dir")
end
end
- describe "Installation from web source" do
+ describe "Installation from source" do
test "develop" do
if Pleroma.Utils.command_available?("yarn") do
Mix.Tasks.Pleroma.Frontend.run([
"install",
"pleroma",
"--develop"
])
assert File.exists?(Path.join([@dir, "frontends/pleroma/d5457c32/index.html"]))
end
end
test "stable" do
if Pleroma.Utils.command_available?("yarn") do
Mix.Tasks.Pleroma.Frontend.run(["install", "pleroma"])
assert File.exists?(Path.join([@dir, "frontends/pleroma/5d49edc8/index.html"]))
end
end
test "ref" do
if Pleroma.Utils.command_available?("yarn") do
Mix.Tasks.Pleroma.Frontend.run([
"install",
"pleroma",
"--ref",
"1.2.3"
])
assert File.exists?(Path.join([@dir, "frontends/pleroma/1.2.3/index.html"]))
end
end
end
+ describe "Installation from pre-built bundle" do
+ test "Installs pleroma" do
+ Mix.Tasks.Pleroma.Frontend.run([
+ "install",
+ "pleroma",
+ "--ref",
+ "test-bundle-1.2.3"
+ ])
+
+ assert File.exists?(Path.join([@dir, "frontends/pleroma/test-bundle-1.2.3/index.html"]))
+ end
+ end
+
describe "Install all" do
test "Normal config" do
if Pleroma.Utils.command_available?("yarn") do
config = [
- primary: %{"name" => "pleroma", "ref" => "1.2.3"},
+ primary: %{"name" => "pleroma", "ref" => "test-bundle-1.2.3"},
mastodon: %{"name" => "mastodon", "ref" => "2.3.4"},
admin: %{"name" => "admin", "ref" => "3.4.5"}
]
clear_config(:frontends, config)
Mix.Tasks.Pleroma.Frontend.run(["install", "all"])
- assert File.exists?(Path.join([@dir, "frontends/pleroma/1.2.3/index.html"]))
+ assert File.exists?(Path.join([@dir, "frontends/pleroma/test-bundle-1.2.3/index.html"]))
assert File.exists?(Path.join([@dir, "frontends/mastodon/2.3.4/sw.js"]))
assert File.exists?(Path.join([@dir, "frontends/admin/3.4.5/index.html"]))
end
end
test "Unconfigured frontends" do
if Pleroma.Utils.command_available?("yarn") do
config = [
primary: %{"name" => "none", "ref" => "1.2.3"},
mastodon: %{"name" => "mastodon", "ref" => "none"},
admin: %{"name" => "admin", "ref" => "none"}
]
clear_config(:frontends, config)
Mix.Tasks.Pleroma.Frontend.run(["install", "all"])
assert {:ok, []} == File.ls(@dir)
end
end
test "Missing configs" do
if Pleroma.Utils.command_available?("yarn") do
clear_config(:frontends, [])
Mix.Tasks.Pleroma.Frontend.run(["install", "all"])
assert {:ok, []} == File.ls(@dir)
end
end
end
end

File Metadata

Mime Type
text/x-diff
Expires
Sat, Sep 19, 3:11 PM (20 h, 22 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1769587
Default Alt Text
(26 KB)

Event Timeline