Skip to content
Merged
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
71 changes: 70 additions & 1 deletion src/Jira/Api.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@

use chobie\Jira\Api\Authentication\AuthenticationInterface;
use chobie\Jira\Api\Client\ClientInterface;
use chobie\Jira\Api\Result;
use chobie\Jira\Api\Client\CurlClient;
use chobie\Jira\Api\Result;

class Api
{
Expand Down Expand Up @@ -222,6 +222,7 @@ public function getRoleDetails($projectKey, $roleId)
* @param $issuetypeIds array Combined with issuetypeNames, lists the issue types with which to filter the results.
* If null, all issue types are returned. Specifiying an issue type that does not exist is
* not an error.
*
* @param $issuetypeNames array Combined with issuetypeIds, lists the issue types with which to filter the results.
* If null, all issue types are returned. This parameter can be specified multiple times,
* but is NOT interpreted as a comma-separated list. Specifiying an issue type that does
Expand Down Expand Up @@ -346,6 +347,33 @@ public function getVersions($projectKey)
return $this->api(self::REQUEST_GET, "/rest/api/2/project/{$projectKey}/versions", array(), true);
}

/**
* Helper method to find a specific version based on the name of the version.
*
* @param string $projectKey Project Key
* @param string $name The version name to match on
*
* @return int|null VersionId on match or null when there is no match
*/
public function findVersionByName($projectKey, $name)
Copy link
Member

Choose a reason for hiding this comment

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

I recommend setting private scope for new methods, that you don't plan to expose in the API yet.

Adding all stuff public by default work create more problems down the road, when we release 2.0 version and need to maintain that API to avoid BC breaks.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This method is meant to be public. (and is not used internally in the lib yet)
I'm using it in a project to search the corresponding release based on a git tag :)

Copy link
Member

Choose a reason for hiding this comment

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

Ah, then maybe other 2 should not be.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think we should add these methods since they are pretty basic functionality for anyone who wants to automate the release process using using JIRA Versions/Releases.

Copy link
Member

Choose a reason for hiding this comment

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

OK. But in either case until 2.0.0 release all methods not present in 1.x release are subject to removal if such need arises.

{
// Fetch all versions of this project
$versions = $this->getVersions($projectKey);

// Filter results on the name
$matching_versions = array_filter($versions, function (array $version) use ($name) {
return $version['name'] == $name;
});

// Early out for no results
if (empty($matching_versions)) {
return null;
}

// Multiple results should not happen since name is unique
return reset($matching_versions);
}

/**
* Get available priorities
*
Expand Down Expand Up @@ -485,6 +513,47 @@ public function createVersion($projectId, $name, $options = array())
return $this->api(self::REQUEST_POST, '/rest/api/2/version', $options);
}

/**
* Update JIRA Version
*
* https://docs.atlassian.com/jira/REST/latest/#api/2/version-updateVersion
*
* @param int $versionId Version identifier
* @param array $params Key->Value list to update the version with.
*
* @return Result|false
Copy link
Member

Choose a reason for hiding this comment

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

Are you sure, that Result object is ever returned on PUT requests?

Copy link
Collaborator Author

@jpastoor jpastoor May 2, 2016

Choose a reason for hiding this comment

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

Yep, a struct like

class chobie\Jira\Api\Result#5 (5) {
  protected $expand =>
  NULL
  protected $startAt =>
  NULL
  protected $maxResults =>
  NULL
  protected $total =>
  NULL
  protected $result =>
  array(8) {
    'self' =>
    string(56) "https://xxx.atlassian.net/rest/api/2/version/14206"
    'id' =>
    string(5) "14206"
    'name' =>
    string(6) "3.63.0"
    'archived' =>
    bool(false)
    'released' =>
    bool(true)
    'releaseDate' =>
    string(10) "2016-05-02"
    'userReleaseDate' =>
    string(9) "02/May/16"
    'projectId' =>
    int(10100)
  }
}

Copy link
Member

Choose a reason for hiding this comment

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

OK.

*/
public function updateVersion($versionId, $params = array())
{
return $this->api(self::REQUEST_PUT, sprintf('/rest/api/2/version/%d', $versionId), $params);
}

/**
* Shorthand to mark a version as Released
*
* @param int $versionId Version identifier
* @param string|null $releaseDate Date in Y-m-d format. Defaults to today
* @param array $params Optionally extra parameters.
*
* @return Result|false
*/
public function releaseVersion($versionId, $releaseDate = null, $params = array())
{
if(!$releaseDate) {
$releaseDate = date('Y-m-d');
}

$params = array_merge(
array(
'releaseDate' => $releaseDate,
'released' => true
),
$params
);

return $this->updateVersion($versionId, $params);
}

/**
* Create JIRA Attachment
*
Expand Down
98 changes: 98 additions & 0 deletions tests/Jira/ApiTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,102 @@ public function testSetEndpointTrailingSlash()
$api->setEndPoint($url);
$this->assertEquals($url, $api->getEndpoint());
}

/**
* Tests that the updateVersion call constructs the correct api call
*/
public function testUpdateVersion()
{
$params = array(
'released' => true,
'releaseDate' => '2010-07-06',
);

// Stub the api method and keep the rest intact
/** @var Api|\PHPUnit_Framework_MockObject_MockObject $api */
$api = $this->getMockBuilder('\chobie\Jira\Api')->setMethods(array('api'))->disableOriginalConstructor()->getMock();
Copy link
Member

Choose a reason for hiding this comment

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

We can use Prophecy now, so why not use it for mock creation.

Copy link
Member

@aik099 aik099 May 2, 2016

Choose a reason for hiding this comment

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

This test doesn't really test anything except our internal cross-class interactions 😄

You can keep it of course, but ideally I would like to see #74 implemented at some point.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Not sure why that is better than using the native phpunit way?

Copy link
Member

@aik099 aik099 May 2, 2016

Choose a reason for hiding this comment

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

You know that PHPUnitMocks isn't that powerful and has it's own limitations. Since PHPUnit 4.8 the built-in support for Prophecy was added and people are encouraged to use it for mock creation.

It also encourages good architecture by at least not allowing to partially mock objects (e.g. api method call gets mocked, while others are not as you did above).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Agreed.

$api->expects($this->once())->method('api')->with(
$this->equalTo(Api::REQUEST_PUT),
$this->equalTo('/rest/api/2/version/111000'),
$this->equalTo($params)
);

$api->updateVersion(111000, $params);
}

/**
* Tests that the releaseVersion call constructs the correct api call
*/
public function testReleaseVersion()
{
$params = array(
'released' => true,
'releaseDate' => date('Y-m-d'),
);

// Stub the api method and keep the rest intact
/** @var Api|\PHPUnit_Framework_MockObject_MockObject $api */
$api = $this->getMockBuilder('\chobie\Jira\Api')->setMethods(array('api'))->disableOriginalConstructor()->getMock();
$api->expects($this->once())->method('api')->with(
$this->equalTo(Api::REQUEST_PUT),
$this->equalTo('/rest/api/2/version/111000'),
$this->equalTo($params)
);

$api->releaseVersion(111000);
}

/**
* Tests that the releaseVersion call constructs the correct api call with overriden release data and params
*/
public function testReleaseVersionAdvanced()
{
$releaseDate = '2010-07-06';

$params = array(
'released' => true,
'releaseDate' => $releaseDate,
'test' => 'extra'
);

// Stub the api method and keep the rest intact
/** @var Api|\PHPUnit_Framework_MockObject_MockObject $api */
$api = $this->getMockBuilder('\chobie\Jira\Api')->setMethods(array('api'))->disableOriginalConstructor()->getMock();
$api->expects($this->once())->method('api')->with(
$this->equalTo(Api::REQUEST_PUT),
$this->equalTo('/rest/api/2/version/111000'),
$this->equalTo($params)
);

$api->releaseVersion(111000, $releaseDate, array('test' => 'extra'));
}

/**
* Tests FindVersionByName
*/
public function testFindVersionByName()
{
$name = '3.36.0';
$versionId = '14206';
$projectKey = 'POR';

$versions = array(
array('id' => '14205', 'name' => '3.62.0'),
array('id' => $versionId, 'name' => $name),
array('id' => '14207', 'name' => '3.66.0'),
);

// Stub the getVersions method and keep the rest intact
/** @var Api|\PHPUnit_Framework_MockObject_MockObject $api */
$api = $this->getMockBuilder('\chobie\Jira\Api')->setMethods(array('getVersions'))->disableOriginalConstructor()->getMock();
$api->expects($this->exactly(2))->method('getVersions')->with(
$this->equalTo($projectKey)
)->willReturn($versions);

// He should find this one
$this->assertEquals(array('id' => $versionId, 'name' => $name), $api->findVersionByName($projectKey, $name));

// And there should be no result for this one
$this->assertNull($api->findVersionByName($projectKey, 'i_do_not_exist'));
}
}