defmodule Mix.Tasks.Rulestead.CodeRefs do @moduledoc false # Scans application code for Rulestead flag references and pushes them to the Rulestead API. # ## Examples # mix rulestead.code_refs --token secret_token # mix rulestead.code_refs --dir lib --url http://example.com/api/webhooks/rulestead/code_refs use Mix.Task alias Rulestead.CodeRefs.Scanner @shortdoc "Scans application code for Rulestead flag references and pushes them to the Rulestead API" @switches [dir: :string, url: :string, token: :string] @impl Mix.Task def run(args) do # Ensure dependencies are available (like Jason and Req/HTTPoison/inets) Application.ensure_all_started(:inets) Application.ensure_all_started(:ssl) {opts, _argv, _invalid} = OptionParser.parse(args, strict: @switches) dir = Keyword.get(opts, :dir, "lib") url = Keyword.get(opts, :url) || System.get_env("RULESTEAD_API_URL") || "http://localhost:4000/api/webhooks/rulestead/code_refs" token = Keyword.get(opts, :token) || System.get_env("RULESTEAD_CI_TOKEN") if is_nil(token) do Mix.raise( "A CI token is required. Pass --token or set RULESTEAD_CI_TOKEN environment variable." ) end shell = Mix.shell() shell.info("Scanning #{dir} for Rulestead flag references...") references = Scanner.scan_dir(dir) shell.info("Found #{length(references)} references. Pushing to #{url}...") payload = Jason.encode!(%{references: references}) headers = [ {~c"content-type", ~c"application/json"}, {~c"authorization", String.to_charlist("Bearer #{token}")} ] case :httpc.request( :post, {String.to_charlist(url), headers, ~c"application/json", payload}, [], [] ) do {:ok, {{_, status_code, _}, _, _response_body}} when status_code in 200..299 -> shell.info("Successfully pushed references to Rulestead!") {:ok, {{_, status_code, _}, _, response_body}} -> Mix.raise( "Failed to push references. Server returned status #{status_code}: #{response_body}" ) {:error, reason} -> Mix.raise("Failed to connect to Rulestead API: #{inspect(reason)}") end end end