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
8 changes: 4 additions & 4 deletions Bugzilla/WebService/Bug.pm
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,11 @@ sub DATE_FIELDS {
update => []
};

# Add date related custom fields
# Add datetime custom fields. Date-only fields are left out so they are
# passed through as YYYY-MM-DD, since converting them would append a time
# component that _check_date_field rejects.
foreach my $field (Bugzilla->active_custom_fields({skip_extensions => 1})) {
next
unless ($field->type == FIELD_TYPE_DATETIME
|| $field->type == FIELD_TYPE_DATE);
next unless $field->type == FIELD_TYPE_DATETIME;
Comment thread
dklawren marked this conversation as resolved.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_format_cf_value (line 1896) still routes FIELD_TYPE_DATE through type('dateTime', ...), so the field comes back as 2026-01-15T00:00:00Z and that exact value is refused on input; only a bare YYYY-MM-DD is accepted. Read-modify-write over a bug breaks on it.

Suggest splitting that branch the way this one is split: YYYY-MM-DD for FIELD_TYPE_DATE, dateTime for FIELD_TYPE_DATETIME, as deadline already does at line 1850.

Flagging rather than requesting, since reading these fields already worked and changing the output is breaking for anything parsing the current form. Worth being a decision either way.

push(@{$fields->{create}}, $field->name);
push(@{$fields->{update}}, $field->name);
}
Expand Down
20 changes: 20 additions & 0 deletions qa/config/generate_test_data.pl
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,26 @@ BEGIN
obsolete => 0,
values => [qw(one two three)],
},
{
name => 'cf_qa_date',
description => 'QA Date',
type => FIELD_TYPE_DATE,
sortkey => 300,
mailhead => 0,
enter_bug => 1,
custom => 1,
obsolete => 0,
},
{
name => 'cf_qa_datetime',
description => 'QA DateTime',
type => FIELD_TYPE_DATETIME,
sortkey => 400,
mailhead => 0,
enter_bug => 1,
custom => 1,
obsolete => 0,
},
);

print "creating custom fields...\n";
Expand Down
101 changes: 101 additions & 0 deletions qa/t/rest_bug_date_fields.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#!/usr/bin/env perl
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.

#####################################################
# Test for REST Bug.create() and Bug.update() with #
# DATE and DATETIME custom fields #
# POST /rest/bug #
# PUT /rest/bug/<id> #
#####################################################

# FIELD_TYPE_DATE custom fields must be passed through to the Bug object as
# YYYY-MM-DD. FIELD_TYPE_DATETIME custom fields must still be converted from
# ISO 8601 by the REST server before reaching the Bug object. See bug 2074690.

use 5.10.1;
use strict;
use warnings;
use lib qw(lib ../../lib ../../local/lib/perl5);

use Bugzilla;
use Bugzilla::Util qw(datetime_from);
use QA::Util qw(get_config);
use QA::Tests qw(create_bug_fields);
use QA::REST::Util qw(api_headers);

use Test::Mojo;
use Test::More;

use constant DATE_FIELD => 'cf_qa_date';
use constant DATETIME_FIELD => 'cf_qa_datetime';

my $config = get_config();
my $api_key = $config->{editbugs_user_api_key};
my $url = Bugzilla->localconfig->urlbase;

my $t = Test::Mojo->new();

# The REST API always returns dates as ISO 8601 in UTC with a trailing 'Z'.
# A date-only value is stored without a time zone, so compute the expected
# output the same way the server does rather than assuming it runs in UTC.
sub expected_iso8601 {
my ($value) = @_;
return datetime_from($value, 'UTC')->iso8601() . 'Z';
}

sub check_bug_dates {
my ($bug_id, $date, $datetime, $desc) = @_;
my $fields = join(',', DATE_FIELD, DATETIME_FIELD);
$t->get_ok(
$url . "rest/bug/$bug_id?include_fields=$fields" => api_headers($api_key))
->status_is(200)
->json_is('/bugs/0/' . DATE_FIELD, expected_iso8601($date),
"$desc: date field has the right value")
->json_is('/bugs/0/' . DATETIME_FIELD, $datetime,
"$desc: datetime field has the right value");
}

###############################
# Create with both field types #
###############################

my $new_bug = create_bug_fields($config);
$new_bug->{+DATE_FIELD} = '2026-01-15';
$new_bug->{+DATETIME_FIELD} = '2026-01-15T12:15:00Z';

$t->post_ok($url . 'rest/bug' => api_headers($api_key) => json => $new_bug)
->status_is(200)->json_has('/id');
my $bug_id = $t->tx->res->json->{id};

check_bug_dates($bug_id, '2026-01-15', '2026-01-15T12:15:00Z', 'After create');

###############################
# Update with both field types #
###############################

$t->put_ok($url
. "rest/bug/$bug_id" => api_headers($api_key) => json =>
{DATE_FIELD, '2026-02-20', DATETIME_FIELD, '2026-02-20T08:45:00Z'})
->status_is(200);

check_bug_dates($bug_id, '2026-02-20', '2026-02-20T08:45:00Z', 'After update');

#############################################
# Date fields still reject a time component #
#############################################

$t->put_ok($url
. "rest/bug/$bug_id" => api_headers($api_key) => json =>
{DATE_FIELD, '2026-03-01 10:00:00'})->status_is(400)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth adding 2026-03-01T00:00:00Z next to the space-separated form. That is what the endpoint returns for this field, so it is the value a client is most likely to send back, and it is rejected too. Pinning it makes the contract explicit whichever way the question on Bug.pm goes.

->json_is('/code' => 56)
->json_like('/message' => qr/is not a legal date/);

check_bug_dates($bug_id, '2026-02-20', '2026-02-20T08:45:00Z',
'After rejected update');

done_testing();
Loading