diff --git a/CHANGELOG.md b/CHANGELOG.md index cab1d42b..9a8125f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - New method `Redmine\Api\Project::listNames()` for listing the ids and names of all projects. - New method `Redmine\Api\Role::listNames()` for listing the ids and names of all roles. - New method `Redmine\Api\TimeEntryActivity::listNames()` for listing the ids and names of all time entry activities. +- New method `Redmine\Api\Tracker::listNames()` for listing the ids and names of all trackers. - New method `Redmine\Api\User::listLogins()` for listing the ids and logins of all users. ### Deprecated @@ -27,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `Redmine\Api\Project::listing()` is deprecated, use `\Redmine\Api\Project::listNames()` instead. - `Redmine\Api\Role::listing()` is deprecated, use `\Redmine\Api\Role::listNames()` instead. - `Redmine\Api\TimeEntryActivity::listing()` is deprecated, use `\Redmine\Api\TimeEntryActivity::listNames()` instead. +- `Redmine\Api\Tracker::listing()` is deprecated, use `\Redmine\Api\Tracker::listNames()` instead. - `Redmine\Api\User::listing()` is deprecated, use `\Redmine\Api\User::listLogins()` instead. ## [v2.6.0](https://github.com/kbsali/php-redmine-api/compare/v2.5.0...v2.6.0) - 2024-03-25 diff --git a/src/Redmine/Api/Tracker.php b/src/Redmine/Api/Tracker.php index 107c090c..1babf0d3 100644 --- a/src/Redmine/Api/Tracker.php +++ b/src/Redmine/Api/Tracker.php @@ -17,6 +17,8 @@ class Tracker extends AbstractApi { private $trackers = []; + private $trackerNames = null; + /** * List trackers. * @@ -37,6 +39,29 @@ final public function list(array $params = []): array } } + /** + * Returns an array of all trackers with id/name pairs. + * + * @return array list of trackers (id => name) + */ + final public function listNames(): array + { + if ($this->trackerNames !== null) { + return $this->trackerNames; + } + + $this->trackerNames = []; + $list = $this->list(); + + if (array_key_exists('trackers', $list)) { + foreach ($list['trackers'] as $role) { + $this->trackerNames[(int) $role['id']] = $role['name']; + } + } + + return $this->trackerNames; + } + /** * List trackers. * @@ -73,12 +98,17 @@ public function all(array $params = []) /** * Returns an array of trackers with name/id pairs. * + * @deprecated v2.7.0 Use listNames() instead. + * @see Tracker::listNames() + * * @param bool $forceUpdate to force the update of the trackers var * * @return array list of trackers (id => name) */ public function listing($forceUpdate = false) { + @trigger_error('`' . __METHOD__ . '()` is deprecated since v2.7.0, use `' . __CLASS__ . '::listNames()` instead.', E_USER_DEPRECATED); + if (empty($this->trackers) || $forceUpdate) { $this->trackers = $this->list(); } diff --git a/tests/Behat/Bootstrap/TrackerContextTrait.php b/tests/Behat/Bootstrap/TrackerContextTrait.php index d44f2e46..5fa15029 100644 --- a/tests/Behat/Bootstrap/TrackerContextTrait.php +++ b/tests/Behat/Bootstrap/TrackerContextTrait.php @@ -4,6 +4,8 @@ namespace Redmine\Tests\Behat\Bootstrap; +use Redmine\Api\Tracker; + trait TrackerContextTrait { /** @@ -24,4 +26,32 @@ public function iHaveATrackerWithTheNameAndDefaultStatusId(string $trackerName, ], ); } + + /** + * @When I list all trackers + */ + public function iListAllTrackers() + { + /** @var Tracker */ + $api = $this->getNativeCurlClient()->getApi('tracker'); + + $this->registerClientResponse( + $api->list(), + $api->getLastResponse(), + ); + } + + /** + * @When I list all tracker names + */ + public function iListAllTrackerNames() + { + /** @var Tracker */ + $api = $this->getNativeCurlClient()->getApi('tracker'); + + $this->registerClientResponse( + $api->listNames(), + $api->getLastResponse(), + ); + } } diff --git a/tests/Behat/features/tracker.feature b/tests/Behat/features/tracker.feature new file mode 100644 index 00000000..a8a888e1 --- /dev/null +++ b/tests/Behat/features/tracker.feature @@ -0,0 +1,94 @@ +@tracker +Feature: Interacting with the REST API for trackers + In order to interact with REST API for trackers + As a user + I want to make sure the Redmine server replies with the correct response + + Scenario: Listing of zero trackers + Given I have a "NativeCurlClient" client + When I list all trackers + 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 + """ + trackers + """ + And the returned data "trackers" property is an array + And the returned data "trackers" property contains "0" items + + Scenario: Listing of multiple trackers + Given I have a "NativeCurlClient" client + And I have an issue status with the name "New" + And I have a tracker with the name "Feature" and default status id "1" + And I have a tracker with the name "Defect" and default status id "1" + When I list all trackers + 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 + """ + trackers + """ + And the returned data "trackers" property is an array + And the returned data "trackers" property contains "2" items + And the returned data "trackers.0" property is an array + And the returned data "trackers.0" property has only the following properties with Redmine version ">= 5.0.0" + """ + id + name + default_status + description + enabled_standard_fields + """ + But the returned data "trackers.0" property has only the following properties with Redmine version "< 5.0.0" + """ + id + name + default_status + description + """ + And the returned data "trackers.0" property contains the following data + | property | value | + | id | 1 | + | name | Feature | + | description | null | + And the returned data "trackers.0.default_status" property contains the following data + | property | value | + | id | 1 | + | name | New | + And the returned data "trackers.0.enabled_standard_fields" property contains the following data with Redmine version ">= 5.1.0" + | property | value | + | 0 | assigned_to_id | + | 1 | category_id | + | 2 | fixed_version_id | + | 3 | parent_issue_id | + | 4 | start_date | + | 5 | due_date | + | 6 | estimated_hours | + | 7 | done_ratio | + | 8 | description | + | 9 | priority_id | + But the returned data "trackers.0.enabled_standard_fields" property contains the following data with Redmine version ">= 5.0.0" + | property | value | + | 0 | assigned_to_id | + | 1 | category_id | + | 2 | fixed_version_id | + | 3 | parent_issue_id | + | 4 | start_date | + | 5 | due_date | + | 6 | estimated_hours | + | 7 | done_ratio | + | 8 | description | + + Scenario: Listing of multiple tracker names + Given I have a "NativeCurlClient" client + And I have an issue status with the name "New" + And I have a tracker with the name "Feature" and default status id "1" + And I have a tracker with the name "Defect" and default status id "1" + When I list all tracker names + Then the response has the status code "200" + And the response has the content type "application/json" + And the returned data contains "2" items + And the returned data contains the following data + | property | value | + | 1 | Feature | + | 2 | Defect | diff --git a/tests/Unit/Api/Tracker/ListNamesTest.php b/tests/Unit/Api/Tracker/ListNamesTest.php new file mode 100644 index 00000000..6b3db066 --- /dev/null +++ b/tests/Unit/Api/Tracker/ListNamesTest.php @@ -0,0 +1,108 @@ +assertSame($expectedResponse, $api->listNames()); + } + + public static function getListNamesData(): array + { + return [ + 'test without trackers' => [ + '/trackers.json', + 201, + << [ + '/trackers.json', + 201, + << "Tracker 3", + 8 => "Tracker 2", + 9 => "Tracker 1", + ], + ], + ]; + } + + public function testListNamesCallsHttpClientOnlyOnce() + { + $client = AssertingHttpClient::create( + $this, + [ + 'GET', + '/trackers.json', + 'application/json', + '', + 200, + 'application/json', + <<assertSame([1 => 'Tracker 1'], $api->listNames()); + $this->assertSame([1 => 'Tracker 1'], $api->listNames()); + $this->assertSame([1 => 'Tracker 1'], $api->listNames()); + } +} diff --git a/tests/Unit/Api/TrackerTest.php b/tests/Unit/Api/TrackerTest.php index 70c3bda7..dc46e170 100644 --- a/tests/Unit/Api/TrackerTest.php +++ b/tests/Unit/Api/TrackerTest.php @@ -215,6 +215,38 @@ public function testListingCallsGetEveryTimeWithForceUpdate() $this->assertSame($expectedReturn, $api->listing(true)); } + /** + * Test listing(). + */ + public function testListingTriggersDeprecationWarning() + { + $client = $this->createMock(Client::class); + $client->method('requestGet') + ->willReturn(true); + $client->method('getLastResponseBody') + ->willReturn('{"trackers":[{"id":1,"name":"Tracker 1"},{"id":5,"name":"Tracker 5"}]}'); + $client->method('getLastResponseContentType') + ->willReturn('application/json'); + + $api = new Tracker($client); + + // PHPUnit 10 compatible way to test trigger_error(). + set_error_handler( + function ($errno, $errstr): bool { + $this->assertSame( + '`Redmine\Api\Tracker::listing()` is deprecated since v2.7.0, use `Redmine\Api\Tracker::listNames()` instead.', + $errstr, + ); + + restore_error_handler(); + return true; + }, + E_USER_DEPRECATED, + ); + + $api->listing(); + } + /** * Test getIdByName(). */