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
9 changes: 6 additions & 3 deletions .bazelrc
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# Java options
build --java_language_version="21"
build --java_runtime_version="remotejdk_21"
build --javacopt="-source 21 -target 21"
build --tool_java_language_version="21"
build --tool_java_runtime_version="remotejdk_21"

Expand All @@ -23,12 +22,16 @@ common --modify_execution_info=CppModuleMap=+supports-path-mapping
common --announce_rc
common --color=yes
common --disk_cache=.bazel_cache
common --@rules_scala_annex//rules/scala:scala-toolchain=zinc_3

# Use the prebuilt protobuf toolchain.
common --incompatible_enable_proto_toolchain_resolution
common --@protobuf//bazel/flags:prefer_prebuilt_protoc

# These are backwards incompatible options; we should check to see if their values have been flipped
# when upgrading to new major Bazel version.
common --incompatible_modify_execution_info_additive
common --incompatible_auto_exec_groups
# This is incompatible with the protobuf prebuilt toolchain. Turn it back on when that is fixed.
#common --incompatible_auto_exec_groups
common --incompatible_autoload_externally=sh_binary # sh_binary is used by rules_jvm_external
common --incompatible_config_setting_private_default_visibility
common --incompatible_disable_native_repo_rules
Expand Down
2 changes: 1 addition & 1 deletion .bazelversion
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8.5.0
8.7.0
16 changes: 11 additions & 5 deletions MODULE.bazel
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
module(name = "rules_twirl")

bazel_dep(name = "bazel_skylib", version = "1.8.1")
bazel_dep(name = "rules_java", version = "8.16.1")
bazel_dep(name = "bazel_skylib", version = "1.9.0")
bazel_dep(name = "rules_java", version = "9.6.1")
bazel_dep(name = "rules_jvm_external", version = "6.9")
bazel_dep(name = "protobuf", version = "35.0")
bazel_dep(name = "rules_scala_annex")

rules_scala_annex_version = "lucid_2025-10-03"
# TODO: update to release version before mergin
rules_scala_annex_version = "98c2bdd4bc4222b3099f1a69a1d8038676281ae2"

archive_override(
module_name = "rules_scala_annex",
integrity = "sha256-801JLX227kZgVc2QCzd1JZuQ3huVAOKOdYtCFiXQ/TI=",
integrity = "sha256-hI8a8HEaVRLxt4Z3hhEASI90j0YsKPliIg6hG1R145s=",
strip_prefix = "rules_scala-{}".format(rules_scala_annex_version),
urls = ["https://github.com/lucidsoftware/rules_scala/archive/{}.zip".format(rules_scala_annex_version)],
)

scala = use_extension("@rules_scala_annex//:extensions.bzl", "scala")
scala.defaults(scala_version = "3")
use_repo(scala, "rules_scala_annex_config")

bazel_dep(name = "buildifier_prebuilt", version = "8.2.1.1", dev_dependency = True)
bazel_dep(name = "rules_pkg", version = "1.1.0", dev_dependency = True)
bazel_dep(name = "stardoc", version = "0.8.0", dev_dependency = True)
Expand All @@ -34,7 +40,7 @@ scala_3_version = "3.3.7"

twirl_version = "2.0.9"

protobuf_version = "4.33.2"
protobuf_version = "4.35.0"

scopt_version = "4.1.0"

Expand Down
1,070 changes: 1,001 additions & 69 deletions MODULE.bazel.lock

Large diffs are not rendered by default.

28 changes: 14 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,11 @@ archive_override(
)
```

By default, the Scala 3 version of the Twirl compiler will be used. To change the default to
Scala 2.13, add the `--@rules_twirl//twirl-toolchain=twirl-2-13` flag to your `.bazelrc` file.
The Twirl toolchain is selected automatically based on the `scala_version` attribute on
`twirl_templates` targets (see [Selecting the Scala version](#selecting-the-scala-version) below).
When `scala_version` is unset, the default Scala version for the project is used:
`scala.defaults(scala_version = …)` from the `rules_scala_annex` module extension, which this repo
sets to Scala 3.

If you want to use a custom Twirl compiler, you can set up a custom toolchain like so:

Expand All @@ -49,24 +52,23 @@ load("@rules_twirl//twirl-toolchain:create-toolchain.bzl", "create_twirl_toolcha

create_twirl_toolchain(
name = "twirl-custom",
scala_version = "3",
twirl_compiler = "<label of your custom Twirl templates compiler>",
)
```

Then, register your toolchain with Bazel and set it as the default in your `.bazelrc` file:
If you register more than one custom toolchain for the same `scala_version`, set the `prefix`
attribute to disambiguate them, e.g., `prefix = "custom"` on the Twirl toolchain and
`scala_version = "custom_3"` on the `twirl_templates` target.

Then, register your toolchain with Bazel:

*/MODULE.bazel*

```starlark
register_toolchains("//:twirl-custom")
```

*/.bazelrc*

```
common --@rules_twirl//twirl-toolchain=twirl-custom
```

You can find the available versions of the Twirl Compiler CLI on maven:
https://mvnrepository.com/artifact/com.lucidchart/twirl-compiler-cli.

Expand Down Expand Up @@ -95,10 +97,8 @@ scala_binary(

### Overriding the default Twirl compiler

To override the default Twirl compiler for a single target, you can change the
`twirl_toolchain_name` attribute on the `twirl_routes` target. That attribute can be set to the name
of any `twirl_toolchain` registered with `twirl_register_toolchains` (and created using
`create_twirl_toolchain`). By default `twirl-3` and `twirl-2-13` are valid values.
To select which Twirl compiler to use, set the `scala_version` attribute on the `twirl_templates`
target. By default, `"3"` and `"2.13"` are valid values.

For example:

Expand All @@ -110,7 +110,7 @@ twirl_templates(
+ glob(["app/**/*.scala.xml"])
+ glob(["app/**/*.scala.js"])
+ glob(["app/**/*.scala.txt"]),
twirl_toolchain_name = "twirl-2-13",
scala_version = "2.13",
)
```

Expand Down
8 changes: 5 additions & 3 deletions docs/stardoc/twirl.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<!-- Generated with Stardoc: http://skydoc.bazel.build -->

Twirl Template rules

Bazel rules for running the [Twirl Template Compiler](https://github.com/playframework/twirl) on Twirl Template Files

<a id="twirl_templates"></a>

Expand All @@ -9,8 +11,8 @@
<pre>
load("@rules_twirl//twirl:twirl.bzl", "twirl_templates")

twirl_templates(<a href="#twirl_templates-name">name</a>, <a href="#twirl_templates-srcs">srcs</a>, <a href="#twirl_templates-additional_imports">additional_imports</a>, <a href="#twirl_templates-include_play_imports">include_play_imports</a>, <a href="#twirl_templates-source_directory">source_directory</a>,
<a href="#twirl_templates-template_formats">template_formats</a>, <a href="#twirl_templates-twirl_toolchain_name">twirl_toolchain_name</a>)
twirl_templates(<a href="#twirl_templates-name">name</a>, <a href="#twirl_templates-srcs">srcs</a>, <a href="#twirl_templates-additional_imports">additional_imports</a>, <a href="#twirl_templates-include_play_imports">include_play_imports</a>, <a href="#twirl_templates-scala_version">scala_version</a>,
<a href="#twirl_templates-source_directory">source_directory</a>, <a href="#twirl_templates-template_formats">template_formats</a>)
</pre>

Compiles Twirl templates to Scala sources files.
Expand All @@ -24,8 +26,8 @@ Compiles Twirl templates to Scala sources files.
| <a id="twirl_templates-srcs"></a>srcs | The actual template files contained in the source_directory. | <a href="https://bazel.build/concepts/labels">List of labels</a> | required | |
| <a id="twirl_templates-additional_imports"></a>additional_imports | Additional imports to import to the Twirl templates. | List of strings | optional | `[]` |
| <a id="twirl_templates-include_play_imports"></a>include_play_imports | If true, include the imports the Play project includes by default. | Boolean | optional | `False` |
| <a id="twirl_templates-scala_version"></a>scala_version | The Scala version to use for this target, e.g., '3', '2.13'. | String | optional | `""` |
| <a id="twirl_templates-source_directory"></a>source_directory | Directories where Twirl template files are located. | <a href="https://bazel.build/concepts/labels">Label</a> | required | |
| <a id="twirl_templates-template_formats"></a>template_formats | Formatter types for file extensions.<br><br>The default formats are <pre><code>"html" -&gt; "play.twirl.api.HtmlFormat",&#10;"txt" -&gt; "play.twirl.api.TxtFormat",&#10;"xml" -&gt; "play.twirl.api.XmlFormat",&#10;"js" -&gt; "play.twirl.api.JavaScriptFormat"</code></pre> | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | optional | `{}` |
| <a id="twirl_templates-twirl_toolchain_name"></a>twirl_toolchain_name | The name of the Twirl toolchain to use for this target | String | optional | `""` |


13 changes: 13 additions & 0 deletions test/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
load("//twirl-toolchain:create-toolchain.bzl", "create_twirl_toolchain")
load(":twirl-compiler-test.bzl", "generate_twirl_test_targets")
load(":twirl-jvm-flags-test.bzl", "twirl_jvm_flags_test_suite")

# Check twirlroutes-compiler-test.bzl for the actual test definitions
generate_twirl_test_targets(scala_version = "3")

generate_twirl_test_targets(scala_version = "2.13")

# Test-only toolchain for testing jvm_flags propagation.
create_twirl_toolchain(
name = "twirl-jvm-flags",
jvm_flags = ["-Drules_twirl.test=1"],
prefix = "jvmflagtest",
scala_version = "3",
twirl_compiler = "//twirl-compiler-cli:twirl-compiler-cli-3",
)

twirl_jvm_flags_test_suite(name = "twirl-jvm-flags-test")
15 changes: 4 additions & 11 deletions test/twirl-compiler-test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,6 @@ def generate_twirl_test_targets(scala_version):
# For example 2.13 -> 2-13 or 2_13
scala_version_dash = scala_version.replace(".", "-")
scala_version_underscore = scala_version.replace(".", "_")
scala = "zinc_{}".format(scala_version_underscore)

if scala_version == "3":
twirl_toolchain_name = "twirl-3"
elif scala_version == "2.13":
twirl_toolchain_name = "twirl-2-13"
else:
fail("Unsupported Scala version when generating test targets")

twirl_templates(
name = "twirl-test-templates-basic-{}".format(scala_version_dash),
Expand All @@ -22,8 +14,8 @@ def generate_twirl_test_targets(scala_version):
"twirl-templates/twirl/com/foo/views/hello.scala.txt",
"twirl-templates/twirl/com/foo/views/hello.scala.xml",
],
scala_version = scala_version,
source_directory = "twirl-templates",
twirl_toolchain_name = twirl_toolchain_name,
visibility = ["//visibility:public"],
)

Expand All @@ -33,8 +25,8 @@ def generate_twirl_test_targets(scala_version):
"twirl-templates/twirl/com/foo/views/addImports.scala.txt",
],
additional_imports = ["rulestwirl.test.Person"],
scala_version = scala_version,
source_directory = "twirl-templates",
twirl_toolchain_name = twirl_toolchain_name,
visibility = ["//visibility:public"],
)

Expand All @@ -44,11 +36,11 @@ def generate_twirl_test_targets(scala_version):
"twirl-templates/twirl/com/foo/views/customFormatter.scala.txt",
],
additional_imports = ["rulestwirl.test.Person"],
scala_version = scala_version,
source_directory = "twirl-templates",
template_formats = {
"txt": "rulestwirl.test.StrangeTxtFormat",
},
twirl_toolchain_name = twirl_toolchain_name,
visibility = ["//visibility:public"],
)

Expand All @@ -62,6 +54,7 @@ def generate_twirl_test_targets(scala_version):
":twirl-test-templates-basic-{}".format(scala_version_dash),
":twirl-test-templates-custom-formatter-{}".format(scala_version_dash),
],
scala_version = scala_version,
deps = [
"@twirl_test_{}//:org_playframework_twirl_twirl_api_{}".format(scala_version_underscore, scala_version_underscore),
"@twirl_test_{}//:org_specs2_specs2_common_{}".format(scala_version_underscore, scala_version_underscore),
Expand Down
58 changes: 58 additions & 0 deletions test/twirl-jvm-flags-test.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
load("//twirl:twirl.bzl", "twirl_templates")

# This flag is set on the test-only "twirl-jvm-flags" toolchain in test/BUILD.bazel. The test
# asserts it propagates to the TwirlCompile action's command line as `--jvm_flag=<flag>`. The
# jvm_flags are intentionally kept out of the params file, so they appear inline in argv.
_EXPECTED_JVM_FLAG = "--jvm_flag=-Drules_twirl.test=1"

def _jvm_flags_propagated_test_impl(ctx):
env = analysistest.begin(ctx)

twirl_actions = [
action
for action in analysistest.target_actions(env)
if action.mnemonic == "TwirlCompile"
]
asserts.true(
env,
len(twirl_actions) > 0,
"expected at least one TwirlCompile action",
)
for action in twirl_actions:
asserts.true(
env,
_EXPECTED_JVM_FLAG in action.argv,
"expected {} in the TwirlCompile command line, got: {}".format(
_EXPECTED_JVM_FLAG,
action.argv,
),
)

return analysistest.end(env)

jvm_flags_propagated_test = analysistest.make(
_jvm_flags_propagated_test_impl,
config_settings = {
"//command_line_option:extra_toolchains": ["//test:twirl-jvm-flags"],
},
)

def twirl_jvm_flags_test_suite(name):
"""Verifies that a Twirl toolchain's jvm_flags reach the TwirlCompile action.

Args:
name: Name of the generated analysis test target.
"""
twirl_templates(
name = "twirl-jvm-flags-templates",
srcs = ["twirl-templates/twirl/com/foo/views/hello.scala.html"],
scala_version = "jvmflagtest_3",
source_directory = "twirl-templates",
tags = ["manual"],
)

jvm_flags_propagated_test(
name = name,
target_under_test = ":twirl-jvm-flags-templates",
)
1 change: 1 addition & 0 deletions test/twirl_compiler_bazel_e2e_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ set -euxo pipefail

bazel test //test:twirl-compiler-test-2-13
bazel test //test:twirl-compiler-test-3
bazel test //test:twirl-jvm-flags-test
2 changes: 1 addition & 1 deletion twirl-compiler-cli/twirl-compiler-cli.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def generate_twirl_compiler_targets(scala_version):
"@rules_scala_annex//src/main/scala/higherkindness/rules_scala/common/sandbox",
"@rules_scala_annex//src/main/scala/higherkindness/rules_scala/common/worker",
],
scala_toolchain_name = "zinc_{}".format(scala_version_underscore),
scala_version = scala_version,
)

java_binary(
Expand Down
17 changes: 5 additions & 12 deletions twirl-toolchain/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,33 +1,26 @@
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
load("@bazel_skylib//rules:common_settings.bzl", "string_flag", "string_setting")
load(":create-toolchain.bzl", "create_twirl_toolchain")

toolchain_type(name = "toolchain_type")

string_setting(
name = "original-twirl-toolchain",
build_setting_default = "",
visibility = ["//visibility:public"],
)

string_flag(
name = "twirl-toolchain",
build_setting_default = "twirl-3",
toolchain_type(
name = "toolchain_type",
visibility = ["//visibility:public"],
)

create_twirl_toolchain(
name = "twirl-3",
scala_version = "3",
twirl_compiler = "//twirl-compiler-cli:twirl-compiler-cli-3",
)

create_twirl_toolchain(
name = "twirl-2-13",
scala_version = "2.13",
twirl_compiler = "//twirl-compiler-cli:twirl-compiler-cli-2-13",
)

bzl_library(
name = "bzl",
srcs = glob(["*.bzl"]),
visibility = ["//visibility:public"],
deps = ["@rules_scala_annex//rules:scala-rules"],
)
34 changes: 21 additions & 13 deletions twirl-toolchain/create-toolchain.bzl
Original file line number Diff line number Diff line change
@@ -1,24 +1,32 @@
load("@rules_scala_annex//rules:register_toolchain.bzl", "create_version_config_settings")
load(":twirl-toolchain.bzl", "twirl_toolchain")

def create_twirl_toolchain(name, twirl_compiler):
twirl_toolchain_name = "{}-toolchain".format(name)
config_setting_name = "{}-toolchain-setting".format(name)
def create_twirl_toolchain(name, twirl_compiler, scala_version, jvm_flags = [], prefix = ""):
"""Defines and configures a Twirl toolchain selected by Scala version.

Args:
name: Name of the generated `toolchain` target. Register it with `register_toolchains`.
twirl_compiler: Label of the executable Twirl templates compiler to use.
scala_version: Scala version this toolchain serves, e.g. "3", "2.13". A `twirl_templates`
target is matched to this toolchain when its `scala_version` attribute matches
hierarchically. For example, "3" matches a target requesting "3.3.7".
jvm_flags: JVM options passed to the Twirl compiler at JVM startup.
prefix: Optional namespace to disambiguate multiple toolchains that share a
`scala_version`. A target selects a prefixed toolchain by setting
`scala_version = "<prefix>_<version>"`.
"""
toolchain_name = "{}-toolchain".format(name)
twirl_toolchain(
name = twirl_toolchain_name,
name = toolchain_name,
twirl_compiler = twirl_compiler,
jvm_flags = jvm_flags,
)

native.config_setting(
name = config_setting_name,
flag_values = {
"//twirl-toolchain": name,
},
)
scala_version_settings_group_name = create_version_config_settings(name, scala_version, prefix)

native.toolchain(
name = name,
toolchain = twirl_toolchain_name,
toolchain_type = ":toolchain_type",
target_settings = [config_setting_name],
toolchain = toolchain_name,
toolchain_type = "@rules_twirl//twirl-toolchain:toolchain_type",
target_settings = [":{}".format(scala_version_settings_group_name)],
)
Loading
Loading