total rebase
[anni] / lib / mix / tasks / pleroma / openapi_spec.ex
old mode 100755 (executable)
new mode 100644 (file)
index 884f931..1ea4684
@@ -6,7 +6,70 @@ defmodule Mix.Tasks.Pleroma.OpenapiSpec do
   def run([path]) do
     # Load Pleroma application to get version info
     Application.load(:pleroma)
-    spec = Pleroma.Web.ApiSpec.spec(server_specific: false) |> Jason.encode!()
-    File.write(path, spec)
+
+    spec_json = Pleroma.Web.ApiSpec.spec(server_specific: false) |> Jason.encode!()
+    # to get rid of the structs
+    spec_regened = spec_json |> Jason.decode!()
+
+    check_specs!(spec_regened)
+
+    File.write(path, spec_json)
+  end
+
+  defp check_specs!(spec) do
+    with :ok <- check_specs(spec) do
+      :ok
+    else
+      {_, errors} ->
+        IO.puts(IO.ANSI.format([:red, :bright, "Spec check failed, errors:"]))
+        Enum.map(errors, &IO.puts/1)
+
+        raise "Spec check failed"
+    end
+  end
+
+  def check_specs(spec) do
+    errors =
+      spec["paths"]
+      |> Enum.flat_map(fn {path, %{} = endpoints} ->
+        Enum.map(
+          endpoints,
+          fn {method, endpoint} ->
+            with :ok <- check_endpoint(spec, endpoint) do
+              :ok
+            else
+              error ->
+                "#{endpoint["operationId"]} (#{method} #{path}): #{error}"
+            end
+          end
+        )
+        |> Enum.reject(fn res -> res == :ok end)
+      end)
+
+    if errors == [] do
+      :ok
+    else
+      {:error, errors}
+    end
+  end
+
+  defp check_endpoint(spec, endpoint) do
+    valid_tags = available_tags(spec)
+
+    with {_, [_ | _] = tags} <- {:tags, endpoint["tags"]},
+         {_, []} <- {:unavailable, Enum.reject(tags, &(&1 in valid_tags))} do
+      :ok
+    else
+      {:tags, _} ->
+        "No tags specified"
+
+      {:unavailable, tags} ->
+        "Tags #{inspect(tags)} not available. Please add it in \"x-tagGroups\" in Pleroma.Web.ApiSpec"
+    end
+  end
+
+  defp available_tags(spec) do
+    spec["x-tagGroups"]
+    |> Enum.flat_map(fn %{"tags" => tags} -> tags end)
   end
 end