Skip to content

Commit

Permalink
Merge pull request #408 from Art4/add-customfield-listnames
Browse files Browse the repository at this point in the history
Add `CustomField::listNames()` method as replacement for `CustomField::listing()`
  • Loading branch information
Art4 authored Jun 28, 2024
2 parents b118039 + f4bd056 commit 35bb710
Show file tree
Hide file tree
Showing 9 changed files with 450 additions and 10 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- New method `Redmine\Api\CustomField::listNames()` for listing the ids and names of all custom fields.
- New method `Redmine\Api\Group::listNames()` for listing the ids and names of all groups.
- New method `Redmine\Api\IssueCategory::listNamesByProject()` for listing the ids and names of all issue categories of a project.

### Deprecated

- `Redmine\Api\CustomField::listing()` is deprecated, use `\Redmine\Api\CustomField::listNames()` instead.
- `Redmine\Api\Group::listing()` is deprecated, use `\Redmine\Api\Group::listNames()` instead.
- `Redmine\Api\IssueCategory::listing()` is deprecated, use `\Redmine\Api\IssueCategory::listNamesByProject()` instead.

Expand Down
31 changes: 31 additions & 0 deletions src/Redmine/Api/CustomField.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ class CustomField extends AbstractApi
{
private $customFields = [];

private $customFieldNames = null;

/**
* List custom fields.
*
Expand All @@ -37,6 +39,30 @@ final public function list(array $params = []): array
}
}

/**
* Returns an array of all custom fields with id/name pairs.
*
* @return array<int,string> list of custom fields (id => name)
*/
final public function listNames(): array
{
if ($this->customFieldNames !== null) {
return $this->customFieldNames;
}

$this->customFieldNames = [];

$list = $this->list();

if (array_key_exists('custom_fields', $list)) {
foreach ($list['custom_fields'] as $customField) {
$this->customFieldNames[(int) $customField['id']] = (string) $customField['name'];
}
}

return $this->customFieldNames;
}

/**
* List custom fields.
*
Expand Down Expand Up @@ -73,13 +99,18 @@ public function all(array $params = [])
/**
* Returns an array of custom fields with name/id pairs.
*
* @deprecated v2.7.0 Use listNames() instead.
* @see CustomField::listNames()
*
* @param bool $forceUpdate to force the update of the custom fields var
* @param array $params optional parameters to be passed to the api (offset, limit, ...)
*
* @return array list of custom fields (id => name)
*/
public function listing($forceUpdate = false, array $params = [])
{
@trigger_error('`' . __METHOD__ . '()` is deprecated since v2.7.0, use `' . __CLASS__ . '::listNames()` instead.', E_USER_DEPRECATED);

if (empty($this->customFields) || $forceUpdate) {
$this->customFields = $this->list($params);
}
Expand Down
74 changes: 74 additions & 0 deletions tests/Behat/Bootstrap/CustomFieldContextTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?php

declare(strict_types=1);

namespace Redmine\Tests\Behat\Bootstrap;

use Redmine\Api\CustomField;

trait CustomFieldContextTrait
{
/**
* @Given I create a custom field for issues with the name :customFieldName
*/
public function iCreateACustomFieldForIssuesWithTheName($customFieldName)
{
// support for creating custom fields via REST API is missing
$this->redmine->excecuteDatabaseQuery(
'INSERT INTO custom_fields(type, name, field_format, is_required, is_for_all, position) VALUES(:type, :name, :field_format, :is_required, :is_for_all, :position);',
[],
[
':type' => 'IssueCustomField',
':name' => $customFieldName,
':field_format' => 'string',
':is_required' => 0,
':is_for_all' => 1,
':position' => 1,
],
);
}

/**
* @Given I enable the tracker with ID :trackerId for custom field with ID :customFieldId
*/
public function iEnableTheTrackerWithIdForCustomFieldWithId($trackerId, $customFieldId)
{
// support for enabling custom fields for trackers via REST API is missing
$this->redmine->excecuteDatabaseQuery(
'INSERT INTO custom_fields_trackers(custom_field_id, tracker_id) VALUES(:custom_field_id, :tracker_id);',
[],
[
':custom_field_id' => $customFieldId,
':tracker_id' => $trackerId,
],
);
}

/**
* @When I list all custom fields
*/
public function iListAllCustomFields()
{
/** @var CustomField */
$api = $this->getNativeCurlClient()->getApi('custom_fields');

$this->registerClientResponse(
$api->list(),
$api->getLastResponse(),
);
}

/**
* @When I list all custom field names
*/
public function iListAllCustomFieldNames()
{
/** @var CustomField */
$api = $this->getNativeCurlClient()->getApi('custom_fields');

$this->registerClientResponse(
$api->listNames(),
$api->getLastResponse(),
);
}
}
1 change: 1 addition & 0 deletions tests/Behat/Bootstrap/FeatureContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
final class FeatureContext extends TestCase implements Context
{
use AttachmentContextTrait;
use CustomFieldContextTrait;
use GroupContextTrait;
use IssueCategoryContextTrait;
use IssueContextTrait;
Expand Down
31 changes: 21 additions & 10 deletions tests/Behat/Bootstrap/IssueContextTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,7 @@ trait IssueContextTrait
*/
public function iCreateAnIssueWithTheFollowingData(TableNode $table)
{
$data = [];

foreach ($table as $row) {
$data[$row['property']] = $row['value'];
}
$data = $this->prepareIssueData($table);

/** @var Issue */
$api = $this->getNativeCurlClient()->getApi('issue');
Expand All @@ -35,11 +31,7 @@ public function iCreateAnIssueWithTheFollowingData(TableNode $table)
*/
public function iUpdateTheIssueWithIdAndTheFollowingData($issueId, TableNode $table)
{
$data = [];

foreach ($table as $row) {
$data[$row['property']] = $row['value'];
}
$data = $this->prepareIssueData($table);

/** @var Issue */
$api = $this->getNativeCurlClient()->getApi('issue');
Expand Down Expand Up @@ -105,4 +97,23 @@ public function iRemoveTheIssueWithId($issueId)
$api->getLastResponse(),
);
}

private function prepareIssueData(TableNode $table): array
{
$data = [];

foreach ($table as $row) {
$key = $row['property'];
$value = $row['value'];

// Support for json in custom_fields
if ($key === 'custom_fields') {
$value = json_decode($value, true);
}

$data[$key] = $value;
}

return $data;
}
}
117 changes: 117 additions & 0 deletions tests/Behat/features/custom_field.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
@custom_field
Feature: Interacting with the REST API for custom fields
In order to interact with REST API for custom fields
As a user
I want to make sure the Redmine server replies with the correct response

Scenario: Listing of zero custom fields
Given I have a "NativeCurlClient" client
When I list all custom fields
Then the response has the status code "200"
And the response has the content type "application/json"
And the returned data has only the following properties
"""
custom_fields
"""
And the returned data "custom_fields" property is an array
And the returned data "custom_fields" property contains "0" items

Scenario: Listing of multiple custom fields
Given I have a "NativeCurlClient" client
And I create a custom field for issues with the name "Note B"
And I create a custom field for issues with the name "Note A"
When I list all custom fields
Then the response has the status code "200"
And the response has the content type "application/json"
And the returned data has only the following properties
"""
custom_fields
"""
And the returned data "custom_fields" property is an array
And the returned data "custom_fields" property contains "2" items
# field 'description' was added in Redmine 5.1.0, see https://www.redmine.org/issues/37617
And the returned data "custom_fields.0" property contains the following data with Redmine version ">= 5.1.0"
| property | value |
| id | 1 |
| name | Note B |
| description | null |
| customized_type | issue |
| field_format | string |
| regexp | |
| min_length | null |
| max_length | null |
| is_required | false |
| is_filter | false |
| searchable | false |
| multiple | false |
| default_value | null |
| visible | true |
| trackers | [] |
| roles | [] |
But the returned data "custom_fields.0" property contains the following data with Redmine version "< 5.1.0"
| property | value |
| id | 1 |
| name | Note B |
| customized_type | issue |
| field_format | string |
| regexp | |
| min_length | null |
| max_length | null |
| is_required | false |
| is_filter | false |
| searchable | false |
| multiple | false |
| default_value | null |
| visible | true |
| trackers | [] |
| roles | [] |
# field 'description' was added in Redmine 5.1.0, see https://www.redmine.org/issues/37617
And the returned data "custom_fields.1" property contains the following data with Redmine version ">= 5.1.0"
| property | value |
| id | 2 |
| name | Note A |
| description | null |
| customized_type | issue |
| field_format | string |
| regexp | |
| min_length | null |
| max_length | null |
| is_required | false |
| is_filter | false |
| searchable | false |
| multiple | false |
| default_value | null |
| visible | true |
| trackers | [] |
| roles | [] |
But the returned data "custom_fields.1" property contains the following data with Redmine version "< 5.1.0"
| property | value |
| id | 2 |
| name | Note A |
| customized_type | issue |
| field_format | string |
| regexp | |
| min_length | null |
| max_length | null |
| is_required | false |
| is_filter | false |
| searchable | false |
| multiple | false |
| default_value | null |
| visible | true |
| trackers | [] |
| roles | [] |

Scenario: Listing of multiple custom field names
Given I have a "NativeCurlClient" client
And I create a custom field for issues with the name "Note B"
And I create a custom field for issues with the name "Note A"
When I list all custom field names
Then the response has the status code "200"
And the response has the content type "application/json"
And the returned data is an array
And the returned data contains "2" items
And the returned data contains the following data
| property | value |
| 1 | Note B |
| 2 | Note A |
64 changes: 64 additions & 0 deletions tests/Behat/features/issue.feature
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,70 @@ Feature: Interacting with the REST API for issues
| id | 1 |
| name | Redmine Admin |

@custom_field
Scenario: Creating an issue with custom field
Given I have a "NativeCurlClient" client
And I have an issue status with the name "New"
And I have an issue priority with the name "Normal"
And I have a tracker with the name "Defect" and default status id "1"
And I create a project with name "Test Project" and identifier "test-project"
And I create a custom field for issues with the name "Note"
And I enable the tracker with ID "1" for custom field with ID "1"
When I create an issue with the following data
| property | value |
| subject | issue subject |
| project | Test Project |
| tracker | Defect |
| priority | Normal |
| status | New |
| custom_fields | [{"id":1,"value":"Note for custom field"}] |
Then the response has the status code "201"
And the response has the content type "application/xml"
And the returned data is an instance of "SimpleXMLElement"
And the returned data has only the following properties
"""
id
project
tracker
status
priority
author
subject
description
start_date
due_date
done_ratio
is_private
estimated_hours
total_estimated_hours
custom_fields
created_on
updated_on
closed_on
"""
And the returned data has proterties with the following data
| property | value |
| id | 1 |
| subject | issue subject |
| description | [] |
| due_date | [] |
| done_ratio | 0 |
| is_private | false |
| estimated_hours | [] |
| total_estimated_hours | [] |
And the returned data "custom_fields.custom_field" property has only the following properties
"""
@attributes
value
"""
And the returned data "custom_fields.custom_field.@attributes" property contains the following data
| property | value |
| id | 1 |
| name | Note |
And the returned data "custom_fields.custom_field" property contains the following data
| property | value |
| value | Note for custom field |

Scenario: Updating an issue
Given I have a "NativeCurlClient" client
And I have an issue status with the name "New"
Expand Down
Loading

0 comments on commit 35bb710

Please sign in to comment.