config: format expiry dates quietly

Move the logic for formatting expiry date config values into a helper method and use quiet parsing when needed. Note that git_config_expiry_date() will show an error on a bad parse and not die() like most other git_config...() parsers. Thus, we use 'quietly' here instead of 'gently'. There is an unfortunate asymmetry in these two parsing methods, but we need to treat a positive response from parse_expiry_date() as an error or we will get incorrect values. This updates the behavior of 'git config list --type=expiry-date' to be quiet when attempting parsing on non-date values. Signed-off-by: Derrick Stolee <stolee@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Derrick Stolee committed Feb 23, 2026 at 12:26 UTC 9cb4a5e1ba3e586e77b1c026d509f284b4c55764
2 files changed +22 -16
builtin/config.c
+21 -6
@@ -3,6 +3,7 @@
3 #include "abspath.h"
4 #include "config.h"
5 #include "color.h"
6 +#include "date.h"
7 #include "editor.h"
8 #include "environment.h"
9 #include "gettext.h"
@@ -333,6 +334,23 @@ static int format_config_path(struct strbuf *buf,
334 return 0;
335 }
336
337 +static int format_config_expiry_date(struct strbuf *buf,
338 + const char *key_,
339 + const char *value_,
340 + int quietly)
341 +{
342 + timestamp_t t;
343 + if (quietly) {
344 + if (parse_expiry_date(value_, &t))
345 + return -1;
346 + } else if (git_config_expiry_date(&t, key_, value_) < 0) {
347 + return -1;
348 + }
349 +
350 + strbuf_addf(buf, "%"PRItime, t);
351 + return 0;
352 +}
353 +
354 /*
355 * Format the configuration key-value pair (`key_`, `value_`) and
356 * append it into strbuf `buf`. Returns a negative value on failure,
@@ -368,12 +386,9 @@ static int format_config(const struct config_display_options *opts,
386 res = format_config_bool_or_str(buf, value_);
387 else if (opts->type == TYPE_PATH)
388 res = format_config_path(buf, key_, value_, gently);
371 - else if (opts->type == TYPE_EXPIRY_DATE) {
372 - timestamp_t t;
373 - if (git_config_expiry_date(&t, key_, value_) < 0)
374 - return -1;
375 - strbuf_addf(buf, "%"PRItime, t);
376 - } else if (opts->type == TYPE_COLOR) {
389 + else if (opts->type == TYPE_EXPIRY_DATE)
390 + res = format_config_expiry_date(buf, key_, value_, gently);
391 + else if (opts->type == TYPE_COLOR) {
392 char v[COLOR_MAXLEN];
393 if (git_config_color(v, key_, value_) < 0)
394 return -1;
t/t1300-config.sh
+1 -10
@@ -2562,15 +2562,6 @@ test_expect_success 'list --type=path shows only canonicalizable path values' '
2562 '
2563
2564 test_expect_success 'list --type=expiry-date shows only canonicalizable dates' '
2565 - cat >expecterr <<-EOF &&
2566 - error: '\''True'\'' for '\''section.foo'\'' is not a valid timestamp
2567 - error: '\''~/dir'\'' for '\''section.path'\'' is not a valid timestamp
2568 - error: '\''red'\'' for '\''section.red'\'' is not a valid timestamp
2569 - error: '\''Blue'\'' for '\''section.blue'\'' is not a valid timestamp
2570 - error: '\'':(optional)no-such-path'\'' for '\''section.missing'\'' is not a valid timestamp
2571 - error: '\'':(optional)expect'\'' for '\''section.exists'\'' is not a valid timestamp
2572 - EOF
2573 -
2565 git config ${mode_prefix}list --type=expiry-date >actual 2>err &&
2566
2567 # section.number and section.big parse as relative dates that could
@@ -2578,7 +2569,7 @@ test_expect_success 'list --type=expiry-date shows only canonicalizable dates' '
2569 test_grep section.big actual &&
2570 test_grep section.number actual &&
2571 test_grep "section.date=$(git config --type=expiry-date section.$key)" actual &&
2581 - test_cmp expecterr err
2572 + test_must_be_empty err
2573 '
2574
2575 test_expect_success 'list --type=color shows only canonicalizable color values' '