templates: add self.trailers().contains_key(key)

as a simpler and more readable alternative to

    self.trailers().filter(|t| t.key() == "Change-Id")
This commit is contained in:
Gaëtan Lehmann 2025-04-27 23:17:50 +02:00 committed by Gaëtan Lehmann
parent b7489aac81
commit 2c4a0328f9
4 changed files with 54 additions and 13 deletions

View File

@ -74,6 +74,7 @@ use crate::diff_util::DiffStats;
use crate::formatter::Formatter;
use crate::revset_util;
use crate::template_builder;
use crate::template_builder::expect_plain_text_expression;
use crate::template_builder::merge_fn_map;
use crate::template_builder::BuildContext;
use crate::template_builder::CoreTemplateBuildFnTable;
@ -341,6 +342,14 @@ impl<'repo> TemplateLanguage<'repo> for CommitTemplateLanguage<'repo> {
}
CommitTemplatePropertyKind::TrailerList(property) => {
// TODO: migrate to table?
if function.name == "contains_key" {
let [key_node] = function.expect_exact_arguments()?;
let key_property =
expect_plain_text_expression(self, diagnostics, build_ctx, key_node)?;
let out_property = (property, key_property)
.map(|(trailers, key)| trailers.iter().any(|t| t.key == key));
Ok(Self::wrap_boolean(out_property))
} else {
template_builder::build_formattable_list_method(
self,
diagnostics,
@ -354,6 +363,7 @@ impl<'repo> TemplateLanguage<'repo> for CommitTemplateLanguage<'repo> {
}
}
}
}
// If we need to add multiple languages that support Commit types, this can be
// turned into a trait which extends TemplateLanguage.

View File

@ -1709,4 +1709,22 @@ fn test_log_format_trailers() {
"-r@",
]);
insta::assert_snapshot!(output, @"Test User <test.user@example.com> I6a6a69649a45c67d3e96a7e5007c110ede34dec5[EOF]");
let output = work_dir.run_jj([
"log",
"--no-graph",
"-T",
r#"self.trailers().contains_key("Signed-off-by")"#,
"-r@",
]);
insta::assert_snapshot!(output, @"true[EOF]");
let output = work_dir.run_jj([
"log",
"--no-graph",
"-T",
r#"self.trailers().contains_key("foo")"#,
"-r@",
]);
insta::assert_snapshot!(output, @"false[EOF]");
}

View File

@ -240,14 +240,15 @@ is ignored.
### Commit trailers
Trailers may be automatically added to the commit description with the
`commit_trailers` template.
You can configure automatic addition of trailers to commit descriptions using
the `commit_trailers` template. Trailers defined in this template will only be
added if they are not already present in the description.
```toml
[templates]
commit_trailers = '''
"Signed-off-by: " ++ committer ++ "\n"
'''
format_signed_off_by_trailer(self)
++ if(!trailers.contains_key("Change-Id"), format_gerrit_change_id_trailer(self))'''
```
Some ready-to-use trailer templates are available for frequently used trailers:
@ -256,6 +257,11 @@ Some ready-to-use trailer templates are available for frequently used trailers:
* `format_gerrit_change_id_trailer(commit)` creates a "Change-Id" trailer
suitable to be used with Gerrit. It is based Jujutsu's change id.
The `trailers.contains_key(key)` method can be used within the template to
conditionally add a trailer if no other trailer with the same key exists.
Existing trailers are also accessible via `commit.trailers()`.
### Diff colors and styles
In color-words and git diffs, word-level hunks are rendered with underline. You

View File

@ -248,6 +248,13 @@ defined.
* `.map(|item| expression) -> ListTemplate`: Apply template `expression`
to each element. Example: `parents.map(|c| c.commit_id().short())`
### List<Trailer> type
The following methods are defined. See also the `List` type.
* `.contains_key(key: Template) -> Boolean`: True if the commit description
contains at least one trailer with the key `key`.
### ListTemplate type
The following methods are defined. See also the `List` type.