Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 37 additions & 6 deletions MODULE.bazel.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ def mix_library(*args, **kwargs):
def mix_release(*args, **kwargs):
_mix_release(*args, **kwargs)

def mix_test(*args, **kwargs):
_mix_test(*args, **kwargs)
def mix_test(name, lib, **kwargs):
_mix_test(name = name, lib = lib, **kwargs)
22 changes: 22 additions & 0 deletions examples/basic/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ load("@rules_elixir//:ex_unit_test.bzl", "ex_unit_test")
load("@rules_erlang//:escript.bzl", "escript_archive")

load("@rules_elixir//:mix_library.bzl", "mix_library") # , "mix_release")
load("@rules_elixir//:mix_test.bzl", "mix_test")

# Production library
mix_library(
name = "basic",
# TODO: we should generate this target, and elicit this name from the mix
Expand All @@ -13,6 +15,26 @@ mix_library(
srcs = glob(['lib/**/*.ex']),
)

# Test library (compiled with MIX_ENV=test)
mix_library(
name = "basic_test_lib",
app_name = "main",
mix_env = "test",
mix_config = ":mix.exs",
srcs = glob(['lib/**/*.ex']),
)

# Test runner using pre-compiled artifacts
mix_test(
name = "basic_test",
lib = ":basic_test_lib",
data = glob(['lib/**/*.ex', 'test/**/*.exs']),
env = {
"ERL_COMPILER_OPTIONS": "deterministic",
"ELIXIR_ERL_OPTIONS": "+fnu",
},
)

# TODO: Migrate to elixir_release + elixir_release_bundle
# The new approach uses:
# 1. elixir_release to create the release with Elixir-specific processing
Expand Down
2 changes: 1 addition & 1 deletion examples/basic/test/helped_test.exs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
defmodule AssertionTest do
defmodule HelpedTest do
use ExUnit.Case, async: true
import TestHelper

Expand Down
26 changes: 0 additions & 26 deletions examples/internal-elixir/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -39,32 +39,6 @@ ex_unit_test(
},
)

# Example of running mix test on the entire project
mix_test(
name = "mix_test_all",
mix_config = "mix.exs",
deps = [":erlang_app"],
env = {
"ERL_COMPILER_OPTIONS": "deterministic",
"ELIXIR_ERL_OPTIONS": "+fnu",
},
)

# Example of running mix test on specific test files
mix_test(
name = "mix_test_specific",
srcs = [
"test/assertion_test.exs",
],
mix_config = "mix.exs",
deps = [":erlang_app"],
env = {
"ERL_COMPILER_OPTIONS": "deterministic",
"ELIXIR_ERL_OPTIONS": "+fnu",
},
mix_test_opts = ["--trace"],
)

platform(
name = "erlang_internal_platform",
constraint_values = [
Expand Down
19 changes: 15 additions & 4 deletions examples/plug-sample/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ load("@rules_erlang//:escript.bzl", "escript_archive")
load("@rules_elixir//:mix_library.bzl", "mix_library") # , "mix_release")
load("@rules_elixir//:mix_test.bzl", "mix_test")

# Production library
mix_library(
name = "lib",
# TODO: we should generate this target, and elicit this name from the mix
Expand All @@ -17,6 +18,18 @@ mix_library(
],
)

# Test library (compiled with MIX_ENV=test)
mix_library(
name = "lib_test",
app_name = "plug_sample",
mix_env = "test",
mix_config = ":mix.exs",
srcs = glob(['lib/**/*.ex']),
deps = [
"@plug_cryptoasdasd//:plug_crypto"
],
)

# TODO: Migrate to elixir_release + elixir_release_bundle
# The new approach uses:
# 1. elixir_release to create the release with Elixir-specific processing
Expand All @@ -43,13 +56,11 @@ mix_library(
# command_line_args = ["--no-halt"],
# )

# Test runner using pre-compiled artifacts
mix_test(
name = "plug_sample_test",
mix_config = ":mix.exs",
lib = ":lib_test",
data = glob(['lib/**/*.ex', 'test/**/*.exs']),
deps = [
"@plug_cryptoasdasd//:plug_crypto"
],
env = {
"ERL_COMPILER_OPTIONS": "deterministic",
"ELIXIR_ERL_OPTIONS": "+fnu",
Expand Down
33 changes: 20 additions & 13 deletions mix_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@ load(
_mix_test = "mix_test",
)

def mix_test(**kwargs):
"""Run mix test on an Elixir project.
def mix_test(name, lib, **kwargs):
"""Run mix test using pre-compiled artifacts from a mix_library.

This rule runs `mix test` on a Mix project, executing the project's test suite.
This rule runs `mix test` on a Mix project using pre-compiled artifacts
from a mix_library target. The library must be compiled with mix_env="test".

Args:
name: The name of the test target
mix_config: The mix.exs configuration file (default: ":mix.exs")
lib: The mix_library target containing the compiled application.
Must be compiled with mix_env="test".
srcs: Optional list of specific test files to run. If empty, runs all tests in test/
data: Additional data files needed for tests
deps: Dependencies required for the tests (must provide ErlangAppInfo)
data: Additional data files needed for tests (include test/**/*.exs here)
ez_deps: Erlang/Elixir archive dependencies (.ez files)
tools: Additional tools needed for tests
env: Environment variables to set during test execution
Expand All @@ -23,15 +24,21 @@ def mix_test(**kwargs):

Example:
```python
# First, create a test library compiled with MIX_ENV=test
mix_library(
name = "my_app_test_lib",
app_name = "my_app",
mix_env = "test",
srcs = glob(["lib/**/*.ex"]),
)

# Then create the test target
mix_test(
name = "my_project_test",
mix_config = "mix.exs",
deps = [":my_app"],
env = {
"MIX_ENV": "test",
},
name = "my_app_test",
lib = ":my_app_test_lib",
data = glob(["test/**/*.exs"]),
mix_test_opts = ["--trace"],
)
```
"""
_mix_test(**kwargs)
_mix_test(name = name, lib = lib, **kwargs)
1 change: 1 addition & 0 deletions private/mix_info.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ MixProjectInfo = provider(
# ErlangAppInfo
# 'app_name': 'Name of the OTP application',
"mix_config": "Path to the mix.exs file of this Mix project",
"mix_env": "The MIX_ENV used to compile this project (prod, test, dev)",
# 'ebin': 'Directory containing built libs(???)',
# # TODO: find out how elixir works
# 'consolidated': 'Directory containing...consolidated...stuff??? how does elixir work?',
Expand Down
54 changes: 27 additions & 27 deletions private/mix_library.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def _mix_library_impl(ctx):
# - confirm if we need a secondary one of these for non-runtime deps
# (or maybe we just construct a combination classpath?)
erl_libs_path = ""
if len(erl_libs_files) > 0:
if erl_libs_files:
erl_libs_path = path_join(
ctx.bin_dir.path,
ctx.label.workspace_root,
Expand All @@ -93,33 +93,26 @@ def _mix_library_impl(ctx):
priv_copy_commands = ""
priv_copy_to_build_dir = ""
if priv_dir:
# Commands to copy priv files to build directory (for Mix to access during compilation)
priv_copy_to_build_dir = "\n# Copy priv files to build directory for Mix access\n"
for priv_file in ctx.files.priv:
rel_path = _priv_file_dest_relative_path(ctx.label, priv_file)
priv_copy_to_build_dir += " mkdir -p \"priv/$(dirname {})\"\n".format(rel_path)
# Only copy if source and destination are different (avoid "same file" errors)
priv_copy_to_build_dir += " if [[ \"$ORIG_PWD/{}\" != \"$(pwd)/priv/{}\" ]]; then\n".format(
priv_file.path,
rel_path
)
priv_copy_to_build_dir += " cp -L \"$ORIG_PWD/{}\" \"priv/{}\"\n".format(
priv_file.path,
rel_path
)
priv_copy_to_build_dir += " fi\n"

# Commands to copy priv files to output directory (for ErlangAppInfo provider)
priv_copy_commands = "\n# Copy priv files to output directory preserving directory structure\n"
priv_copy_commands += "mkdir -p \"$ABS_OUT_PRIV_DIR\"\n"
build_dir_cmds = []
output_dir_cmds = []

for priv_file in ctx.files.priv:
rel_path = _priv_file_dest_relative_path(ctx.label, priv_file)
priv_copy_commands += "mkdir -p \"$ABS_OUT_PRIV_DIR/$(dirname {})\"\n".format(rel_path)
priv_copy_commands += "cp -L \"$ORIG_PWD/{}\" \"$ABS_OUT_PRIV_DIR/{}\"\n".format(
priv_file.path,
rel_path
)
src_path = priv_file.path

# Commands to copy priv files to build directory (for Mix to access during compilation)
build_dir_cmds.append(' mkdir -p "priv/$(dirname {})"'.format(rel_path))
# Conditional to avoid same-file errors
build_dir_cmds.append(' if [[ "$ORIG_PWD/{}" != "$(pwd)/priv/{}" ]]; then'.format(src_path, rel_path))
build_dir_cmds.append(' cp -L "$ORIG_PWD/{}" "priv/{}"'.format(src_path, rel_path))
build_dir_cmds.append(" fi")

# Commands to copy priv files to output directory (for ErlangAppInfo provider)
output_dir_cmds.append('mkdir -p "$ABS_OUT_PRIV_DIR/$(dirname {})"'.format(rel_path))
output_dir_cmds.append('cp -L "$ORIG_PWD/{}" "$ABS_OUT_PRIV_DIR/{}"'.format(src_path, rel_path))

priv_copy_to_build_dir = "\n# Copy priv files to build directory for Mix access\n" + "\n".join(build_dir_cmds) + "\n"
priv_copy_commands = "\n# Copy priv files to output directory preserving directory structure\nmkdir -p \"$ABS_OUT_PRIV_DIR\"\n" + "\n".join(output_dir_cmds) + "\n"

# TODO: confirm if we need to use include dir from other modules, or if
# that's just a way for elixir to expose and interface to erlang.
Expand Down Expand Up @@ -171,7 +164,7 @@ if [[ -n "$ERL_LIBS_PATH" ]]; then
done
fi

MIX_ENV=prod \\
MIX_ENV={mix_env} \\
MIX_BUILD_ROOT=_output \\
MIX_HOME=/tmp \\
MIX_OFFLINE=true \\
Expand All @@ -190,7 +183,7 @@ mkdir -p "$ABS_OUT_DIR"

# NOTE: this directory can contain files other than .app and .beam, but we only
# want to keep these in our build output.
cp _output/prod/lib/{app_name}/ebin/*.beam _output/prod/lib/{app_name}/ebin/*.app "$ABS_OUT_DIR/"
cp _output/{mix_env}/lib/{app_name}/ebin/*.beam _output/{mix_env}/lib/{app_name}/ebin/*.app "$ABS_OUT_DIR/"

# Set priv output directory if priv files exist
if [[ -n "{priv_out_dir}" ]]; then
Expand All @@ -210,6 +203,7 @@ fi
erl_libs_path = erl_libs_path,
build_dir = ctx.file.mix_config.dirname,
name = ctx.label.name,
mix_env = ctx.attr.mix_env,
# env = env,
# setup = ctx.attr.setup,
out_dir = ebin.path,
Expand Down Expand Up @@ -252,6 +246,7 @@ fi
MixProjectInfo(
# app_name = ctx.attr.app_name,
mix_config = ctx.file.mix_config,
mix_env = ctx.attr.mix_env,
# ebin = '/'.join([ebin.path, 'ebin', 'lib', ctx.attr.app_name, 'ebin']),
# TODO: should we actually keep this, or should be just YEET the
# consolidated directory? it seems only have dependencies
Expand Down Expand Up @@ -293,6 +288,11 @@ mix_library = rule(
implementation = _mix_library_impl,
attrs = {
"app_name": attr.string(),
"mix_env": attr.string(
default = "prod",
values = ["prod", "test", "dev"],
doc = "The MIX_ENV to use when compiling (default: prod)",
),
"mix_config": attr.label(
allow_single_file = [".exs"],
default = ":mix.exs",
Expand Down
Loading
Loading