Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F1957789
UpdateJIRAStatusDoorkeeperFeedWorker.php
No One
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Authored By
avivey
Nov 24 2016, 1:19 AM
2016-11-24 01:19:45 (UTC+0)
Size
6 KB
Referenced Files
None
Subscribers
None
UpdateJIRAStatusDoorkeeperFeedWorker.php
View Options
<?php
/*
This does 2 things:
- Adds a label to the JIRA ticket with the repository name
- Puts the JIRA ticket in "In Progress" state, if possible.
*/
final
class
UpdateJIRAStatusDoorkeeperFeedWorker
extends
DoorkeeperFeedWorker
{
private
$provider
;
public
function
isEnabled
()
{
return
(
bool
)
PhabricatorJIRAAuthProvider
::
getJIRAProvider
();
}
protected
function
publishFeedStory
()
{
$story
=
$this
->
getFeedStory
();
$viewer
=
$this
->
getViewer
();
$provider
=
$this
->
getProvider
();
$object
=
$this
->
getStoryObject
();
$publisher
=
$this
->
getPublisher
();
if
(!
$object
instanceof
DifferentialRevision
)
{
return
;
}
$jira_issue_phids
=
PhabricatorEdgeQuery
::
loadDestinationPHIDs
(
$object
->
getPHID
(),
PhabricatorJiraIssueHasObjectEdgeType
::
EDGECONST
);
if
(!
$jira_issue_phids
)
{
$this
->
log
(
"%s
\n
"
,
pht
(
'Story is about an object with no linked JIRA issues.'
));
return
;
}
$xobjs
=
id
(
new
DoorkeeperExternalObjectQuery
())
->
setViewer
(
$viewer
)
->
withPHIDs
(
$jira_issue_phids
)
->
execute
();
if
(!
$xobjs
)
{
$this
->
log
(
"%s
\n
"
,
pht
(
'Story object has no corresponding external JIRA objects.'
));
return
;
}
$try_users
=
$this
->
findUsersToPossess
();
if
(!
$try_users
)
{
$this
->
log
(
"%s
\n
"
,
pht
(
'No users to act on linked JIRA objects.'
));
return
;
}
$xobjs
=
mgroup
(
$xobjs
,
'getApplicationDomain'
);
foreach
(
$xobjs
as
$domain
=>
$xobj_list
)
{
$accounts
=
id
(
new
PhabricatorExternalAccountQuery
())
->
setViewer
(
$viewer
)
->
withUserPHIDs
(
$try_users
)
->
withAccountTypes
(
array
(
$provider
->
getProviderType
()))
->
withAccountDomains
(
array
(
$domain
))
->
requireCapabilities
(
array
(
PhabricatorPolicyCapability
::
CAN_VIEW
,
PhabricatorPolicyCapability
::
CAN_EDIT
,
))
->
execute
();
// Reorder accounts in the original order.
// TODO: This needs to be adjusted if/when we allow you to link multiple
// accounts.
$accounts
=
mpull
(
$accounts
,
null
,
'getUserPHID'
);
$accounts
=
array_select_keys
(
$accounts
,
$try_users
);
foreach
(
$xobj_list
as
$xobj
)
{
foreach
(
$accounts
as
$account
)
{
try
{
$jira_key
=
$xobj
->
getObjectID
();
$this
->
addRepositoryToTicket
(
$account
,
$jira_key
);
if
(!
$publisher
->
isObjectClosed
(
$object
))
{
// Closed revisions don't need to mark the ticket "In Progress".
$this
->
moveTicketToInProgress
(
$account
,
$jira_key
);
}
break
;
}
catch
(
HTTPFutureResponseStatus
$ex
)
{
phlog
(
$ex
);
$this
->
log
(
"%s
\n
"
,
pht
(
'Failed to update object %s using user %s.'
,
$xobj
->
getObjectID
(),
$account
->
getUserPHID
()));
}
}
}
}
}
/**
* This action is idempotent, so just make the extra call.
*/
private
function
addRepositoryToTicket
(
$account
,
$jira_key
)
{
$provider
=
$this
->
getProvider
();
$revision
=
$this
->
getStoryObject
();
$publisher
=
$this
->
getPublisher
();
// Repositories are always loaded for revisions because of visibility policy
$repository
=
$revision
->
getRepository
();
if
(!
$repository
)
{
// but it may be null.
return
;
}
$label
=
'repo_'
.
$repository
->
getCloneName
();
$provider
->
newJIRAFuture
(
$account
,
'rest/api/2/issue/'
.
$jira_key
,
'PUT'
,
array
(
'update'
=>
array
(
'labels'
=>
array
(
array
(
'add'
=>
$label
),
),
),
))->
resolve
();
}
/**
* This action is slow because we're making 2 calls - one to learn how to do
* what we want, and one to do it. JIRA doesn't have a concept of "set status
* to something", it has "transitions".
*
* There's also something about permissions, so some accounts may be able to
* see and do a transition and some won't; I'm not going to handle that.
*/
private
function
moveTicketToInProgress
(
$account
,
$jira_key
)
{
$provider
=
$this
->
getProvider
();
$object
=
$this
->
getStoryObject
();
$publisher
=
$this
->
getPublisher
();
$transitions
=
$provider
->
newJIRAFuture
(
$account
,
'rest/api/2/issue/'
.
$jira_key
.
'/transitions'
,
'GET'
)->
resolveJSON
();
$transitions
=
idx
(
$transitions
,
'transitions'
);
$transition_id
=
null
;
foreach
(
$transitions
as
$transition
)
{
$destination
=
idxv
(
$transition
,
array
(
'to'
,
'name'
));
if
(
$destination
==
'In Progress'
)
{
$transition_id
=
idx
(
$transition
,
'id'
);
break
;
}
}
if
(
$transition_id
==
null
)
{
$this
->
log
(
'Found no transition to "In Progress"'
);
return
;
}
$provider
->
newJIRAFuture
(
$account
,
'rest/api/2/issue/'
.
$jira_key
.
'/transitions'
,
'POST'
,
array
(
'transition'
=>
$transition_id
,
))->
resolve
();
}
/* -( Internals )---------------------------------------------------------- */
/**
* Get the active JIRA provider.
*
* @return PhabricatorJIRAAuthProvider Active JIRA auth provider.
* @task internal
*/
private
function
getProvider
()
{
if
(!
$this
->
provider
)
{
$provider
=
PhabricatorJIRAAuthProvider
::
getJIRAProvider
();
if
(!
$provider
)
{
throw
new
PhabricatorWorkerPermanentFailureException
(
pht
(
'No JIRA provider configured.'
));
}
$this
->
provider
=
$provider
;
}
return
$this
->
provider
;
}
/**
* Get a list of users to act as when publishing into JIRA.
*
* @return list<phid> Candidate user PHIDs to act as when publishing this
* story.
* @task internal
*/
private
function
findUsersToPossess
()
{
$object
=
$this
->
getStoryObject
();
$publisher
=
$this
->
getPublisher
();
$data
=
$this
->
getFeedStory
()->
getStoryData
();
// Figure out all the users related to the object. Users go into one of
// four buckets. For JIRA integration, we don't care about which bucket
// a user is in, since we just want to publish an update to linked objects.
$owner_phid
=
$publisher
->
getOwnerPHID
(
$object
);
$active_phids
=
$publisher
->
getActiveUserPHIDs
(
$object
);
$passive_phids
=
$publisher
->
getPassiveUserPHIDs
(
$object
);
$follow_phids
=
$publisher
->
getCCUserPHIDs
(
$object
);
$all_phids
=
array_merge
(
array
(
$owner_phid
),
$active_phids
,
$passive_phids
,
$follow_phids
);
$all_phids
=
array_unique
(
array_filter
(
$all_phids
));
// Even if the actor isn't a reviewer, etc., try to use their account so
// we can post in the correct voice. If we miss, we'll try all the other
// related users.
$try_users
=
array_merge
(
array
(
$data
->
getAuthorPHID
()),
$all_phids
);
$try_users
=
array_filter
(
$try_users
);
return
$try_users
;
}
}
File Metadata
Details
Attached
Mime Type
text/plain; charset=utf-8
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
335691
Default Alt Text
UpdateJIRAStatusDoorkeeperFeedWorker.php (6 KB)
Attached To
Mode
P2019 UpdateJIRAStatusDoorkeeperFeedWorker.php
Attached
Detach File
Event Timeline
Log In to Comment