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
17 changes: 12 additions & 5 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.
Comment thread
Xzzz marked this conversation as resolved.
push(@{$fields->{create}}, $field->name);
push(@{$fields->{update}}, $field->name);
}
Expand Down Expand Up @@ -1893,9 +1893,16 @@ sub _format_cf_value {
if ($field->type == FIELD_TYPE_BUG_ID) {
return $self->type('int', $value);
}
elsif ($field->type == FIELD_TYPE_DATETIME || $field->type == FIELD_TYPE_DATE) {
elsif ($field->type == FIELD_TYPE_DATETIME) {
return defined($value) ? $self->type('dateTime', $value) : undef;
}
elsif ($field->type == FIELD_TYPE_DATE) {

# Date-only fields are returned as YYYY-MM-DD, the same format they are
# accepted in, like deadline. Converting them to dateTime would append
# a time and time zone that the value does not have.
return defined($value) ? $self->type('string', $value) : undef;
}
elsif ($field->type == FIELD_TYPE_MULTI_SELECT) {
return [map { $self->type('string', $_) } @{$value}];
}
Expand Down
4 changes: 3 additions & 1 deletion docs/en/rst/api/core/v1/bug.rst
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ field name in ``include_fields``.
* Bug ID Fields: (int)
* Multiple-Selection Fields: (array of strings)
* Date/Time Fields: (datetime)
* Date Fields: (string) In the format ``YYYY-MM-DD``.

**Errors**

Expand Down Expand Up @@ -1013,7 +1014,8 @@ work_time double The number of hours worked on this bug as part

You can also set the value of any custom field by passing its name as
a parameter, and the value to set the field to. For multiple-selection
fields, the value should be an array of strings.
fields, the value should be an array of strings. For date fields, the value
should be a string in the format ``YYYY-MM-DD``.

Flag change object:

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
120 changes: 120 additions & 0 deletions qa/t/rest_bug_date_fields.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#!/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 and returned in that same format, so a value read from the API
# can be sent back unchanged. FIELD_TYPE_DATETIME custom fields must still be
# converted from and to ISO 8601 by the REST server. See bug 2074690.

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

use Bugzilla;
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();

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, $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)
Comment thread
Xzzz marked this conversation as resolved.
->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');

# ISO 8601 with a time is rejected too. Date fields are returned as plain
# YYYY-MM-DD, so this is not a value a client would read back from the API.
$t->put_ok($url
. "rest/bug/$bug_id" => api_headers($api_key) => json =>
{DATE_FIELD, '2026-03-01T00:00:00Z'})->status_is(400)
->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 ISO 8601 update');

##########################################
# Read-modify-write round trip is stable #
##########################################

my $read_url = $url . "rest/bug/$bug_id?include_fields=" . DATE_FIELD;
$t->get_ok($read_url => api_headers($api_key))->status_is(200);
my $read_back = $t->tx->res->json->{bugs}->[0]->{+DATE_FIELD};
ok(defined $read_back, 'Date field value was read back from the API');

$t->put_ok($url
. "rest/bug/$bug_id" => api_headers($api_key) => json =>
{DATE_FIELD, $read_back})->status_is(200);

check_bug_dates($bug_id, '2026-02-20', '2026-02-20T08:45:00Z',
'After writing back the value read from the API');

done_testing();
Loading