Skip to content

Commit

Permalink
Allow --output argument in "mix sentry.package_source_code" (#691)
Browse files Browse the repository at this point in the history
  • Loading branch information
razielgn authored Feb 24, 2024
1 parent 1ac4b93 commit 4f111f6
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 9 deletions.
32 changes: 30 additions & 2 deletions lib/mix/tasks/sentry.package_source_code.ex
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,34 @@ defmodule Mix.Tasks.Sentry.PackageSourceCode do
> source-context-related options in compile-time config files (like `config/config.exs`
> or `config/prod.exs`).
> #### Building with Nix {: .tip}
>
> If you build your application using nixpkgs' `mixRelease`,
> `mix sentry.package_source_code` will fail, because Sentry's source is read-only.
>
> To fix this, you can use the `--output` option to write the map file to a writable location,
> then copy it to Sentry's `priv` in the final OTP release.
>
> Example:
>
> ```nix
> mixRelease {
> preBuild = ''
> mix sentry.package_source_code --output sentry.map
> '';
>
> postInstall = ''
> sentryPrivDir="$(find $out/lib -maxdepth 1 -name "sentry-*")/priv"
> mkdir "$sentryPrivDir"
> cp -a sentry.map "$sentryPrivDir"
> '';
> }
> ```
## Options
* `--debug` - print more information about collecting and encoding source code
* `--output path` - write file to the given path. Example: `path/to/sentry.map`
"""

Expand All @@ -59,7 +84,10 @@ defmodule Mix.Tasks.Sentry.PackageSourceCode do
@bytes_in_mb 1024 * 1024
@bytes_in_gb 1024 * 1024 * 1024

@switches [debug: :boolean]
@switches [
debug: :boolean,
output: :string
]

@impl true
def run(args) do
Expand All @@ -83,7 +111,7 @@ defmodule Mix.Tasks.Sentry.PackageSourceCode do
{elapsed, contents} = :timer.tc(fn -> Sources.encode_source_code_map(source_map) end)
log_debug(opts, "Encoded source code map in #{format_time(elapsed)}")

output_path = Sources.path_of_packaged_source_code()
output_path = Keyword.get_lazy(opts, :output, &Sources.path_of_packaged_source_code/0)
File.mkdir_p!(Path.dirname(output_path))
File.write!(output_path, contents)

Expand Down
22 changes: 22 additions & 0 deletions lib/sentry/config.ex
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@ defmodule Sentry.Config do
The name of the server running the application. Not used by default.
"""
],
source_code_map_path: [
type: {:custom, __MODULE__, :__validate_path__, []},
default: nil,
type_doc: "`t:Path.t/0` or `nil`",
doc: """
The path to the map file when mix task `sentry.package_source_code` was invoked with
`--output path/to/file.map`
"""
],
sample_rate: [
type: {:custom, __MODULE__, :__validate_sample_rate__, []},
default: 1.0,
Expand Down Expand Up @@ -399,6 +408,9 @@ defmodule Sentry.Config do
@spec server_name() :: String.t() | nil
def server_name, do: get(:server_name)

@spec source_code_map_path() :: Path.t() | nil
def source_code_map_path, do: get(:source_code_map_path)

@spec filter() :: module()
def filter, do: fetch!(:filter)

Expand Down Expand Up @@ -528,6 +540,16 @@ defmodule Sentry.Config do
:persistent_term.get({:sentry_config, key}, nil)
end

def __validate_path__(nil), do: {:ok, nil}

def __validate_path__(path) when is_binary(path) do
if File.exists?(path) do
{:ok, path}
else
{:error, "path does not exist"}
end
end

def __validate_sample_rate__(float) do
if is_float(float) and float >= 0.0 and float <= 1.0 do
{:ok, float}
Expand Down
4 changes: 3 additions & 1 deletion lib/sentry/sources.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ defmodule Sentry.Sources do

# Default argument is here for testing.
@spec load_source_code_map_if_present(Path.t()) :: {:loaded, source_map()} | {:error, term()}
def load_source_code_map_if_present(path \\ path_of_packaged_source_code()) do
def load_source_code_map_if_present(
path \\ Config.source_code_map_path() || path_of_packaged_source_code()
) do
path = Path.relative_to_cwd(path)

with {:ok, contents} <- File.read(path),
Expand Down
33 changes: 27 additions & 6 deletions test/mix/sentry.package_source_code_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,24 @@ defmodule Mix.Tasks.Sentry.PackageSourceCodeTest do

assert :ok = Mix.Task.rerun("sentry.package_source_code")

assert_receive {:mix_shell, :info, ["Wrote " <> _ = message]}
assert message =~ expected_path
validate_map_file!(expected_path)
end

assert {:ok, contents} = File.read(expected_path)
@tag :tmp_dir
test "packages source code into custom path", %{tmp_dir: tmp_dir} do
put_test_config(
root_source_code_paths: [File.cwd!()],
enable_source_code_context: true
)

assert %{"version" => 1, "files_map" => source_map} =
:erlang.binary_to_term(contents, [:safe])
expected_path =
[tmp_dir, "sentry.map"]
|> Path.join()
|> Path.relative_to_cwd()

assert Map.has_key?(source_map, "lib/mix/tasks/sentry.package_source_code.ex")
assert :ok = Mix.Task.rerun("sentry.package_source_code", ["--output", expected_path])

validate_map_file!(expected_path)
end

test "supports the --debug option" do
Expand All @@ -51,4 +60,16 @@ defmodule Mix.Tasks.Sentry.PackageSourceCodeTest do
{:mix_shell, :info, ["Wrote " <> _]}
]} = Process.info(self(), :messages)
end

defp validate_map_file!(path) do
assert_receive {:mix_shell, :info, ["Wrote " <> _ = message]}
assert message =~ path

assert {:ok, contents} = File.read(path)

assert %{"version" => 1, "files_map" => source_map} =
:erlang.binary_to_term(contents, [:safe])

assert Map.has_key?(source_map, "lib/mix/tasks/sentry.package_source_code.ex")
end
end
16 changes: 16 additions & 0 deletions test/sentry/config_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,22 @@ defmodule Sentry.ConfigTest do
end
end

@tag :tmp_dir
test ":source_code_map_path from option", %{tmp_dir: tmp_dir} do
source_code_map_path = Path.join([tmp_dir, "test.map"])

assert Config.validate!(source_code_map_path: nil)[:source_code_map_path] == nil

assert_raise ArgumentError, ~r/path does not exist/, fn ->
assert Config.validate!(source_code_map_path: source_code_map_path)
end

File.touch!(source_code_map_path)

assert Config.validate!(source_code_map_path: source_code_map_path)[:source_code_map_path] ==
source_code_map_path
end

test ":release from option" do
assert Config.validate!(release: "1.0.0")[:release] == "1.0.0"
end
Expand Down

0 comments on commit 4f111f6

Please sign in to comment.