Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F97611672
DifferentialTransaction.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sun, Jan 5, 17:18
Size
20 KB
Mime Type
text/x-php
Expires
Tue, Jan 7, 17:18 (2 d)
Engine
blob
Format
Raw Data
Handle
23366188
Attached To
rPH Phabricator
DifferentialTransaction.php
View Options
<?php
final
class
DifferentialTransaction
extends
PhabricatorModularTransaction
{
private
$isCommandeerSideEffect
;
const
TYPE_INLINE
=
'differential:inline'
;
const
TYPE_UPDATE
=
'differential:update'
;
const
TYPE_ACTION
=
'differential:action'
;
const
MAILTAG_REVIEWERS
=
'differential-reviewers'
;
const
MAILTAG_CLOSED
=
'differential-committed'
;
const
MAILTAG_CC
=
'differential-cc'
;
const
MAILTAG_COMMENT
=
'differential-comment'
;
const
MAILTAG_UPDATED
=
'differential-updated'
;
const
MAILTAG_REVIEW_REQUEST
=
'differential-review-request'
;
const
MAILTAG_OTHER
=
'differential-other'
;
public
function
getBaseTransactionClass
()
{
return
'DifferentialRevisionTransactionType'
;
}
protected
function
newFallbackModularTransactionType
()
{
// TODO: This allows us to render modern strings for older transactions
// without doing a migration. At some point, we should do a migration and
// throw this away.
// NOTE: Old reviewer edits are raw edge transactions. They could be
// migrated to modular transactions when the rest of this migrates.
$xaction_type
=
$this
->
getTransactionType
();
if
(
$xaction_type
==
PhabricatorTransactions
::
TYPE_CUSTOMFIELD
)
{
switch
(
$this
->
getMetadataValue
(
'customfield:key'
))
{
case
'differential:title'
:
return
new
DifferentialRevisionTitleTransaction
();
case
'differential:test-plan'
:
return
new
DifferentialRevisionTestPlanTransaction
();
case
'differential:repository'
:
return
new
DifferentialRevisionRepositoryTransaction
();
}
}
return
parent
::
newFallbackModularTransactionType
();
}
public
function
setIsCommandeerSideEffect
(
$is_side_effect
)
{
$this
->
isCommandeerSideEffect
=
$is_side_effect
;
return
$this
;
}
public
function
getIsCommandeerSideEffect
()
{
return
$this
->
isCommandeerSideEffect
;
}
public
function
getApplicationName
()
{
return
'differential'
;
}
public
function
getApplicationTransactionType
()
{
return
DifferentialRevisionPHIDType
::
TYPECONST
;
}
public
function
getApplicationTransactionCommentObject
()
{
return
new
DifferentialTransactionComment
();
}
public
function
getApplicationTransactionViewObject
()
{
return
new
DifferentialTransactionView
();
}
public
function
shouldHide
()
{
$old
=
$this
->
getOldValue
();
$new
=
$this
->
getNewValue
();
switch
(
$this
->
getTransactionType
())
{
case
self
::
TYPE_UPDATE
:
// Older versions of this transaction have an ID for the new value,
// and/or do not record the old value. Only hide the transaction if
// the new value is a PHID, indicating that this is a newer style
// transaction.
if
(
$old
===
null
)
{
if
(
phid_get_type
(
$new
)
==
DifferentialDiffPHIDType
::
TYPECONST
)
{
return
true
;
}
}
break
;
case
DifferentialRevisionRequestReviewTransaction
::
TRANSACTIONTYPE
:
// Don't hide the initial "X requested review: ..." transaction from
// mail or feed even when it occurs during creation. We need this
// transaction to survive so we'll generate mail and feed stories when
// revisions immediately leave the draft state. See T13035 for
// discussion.
return
false
;
}
return
parent
::
shouldHide
();
}
public
function
shouldHideForMail
(
array
$xactions
)
{
switch
(
$this
->
getTransactionType
())
{
case
DifferentialRevisionReviewersTransaction
::
TRANSACTIONTYPE
:
// Don't hide the initial "X added reviewers: ..." transaction during
// object creation from mail. See T12118 and PHI54.
return
false
;
}
return
parent
::
shouldHideForMail
(
$xactions
);
}
public
function
isInlineCommentTransaction
()
{
switch
(
$this
->
getTransactionType
())
{
case
self
::
TYPE_INLINE
:
return
true
;
}
return
parent
::
isInlineCommentTransaction
();
}
public
function
getRequiredHandlePHIDs
()
{
$phids
=
parent
::
getRequiredHandlePHIDs
();
$old
=
$this
->
getOldValue
();
$new
=
$this
->
getNewValue
();
switch
(
$this
->
getTransactionType
())
{
case
self
::
TYPE_ACTION
:
if
(
$new
==
DifferentialAction
::
ACTION_CLOSE
&&
$this
->
getMetadataValue
(
'isCommitClose'
))
{
$phids
[]
=
$this
->
getMetadataValue
(
'commitPHID'
);
if
(
$this
->
getMetadataValue
(
'committerPHID'
))
{
$phids
[]
=
$this
->
getMetadataValue
(
'committerPHID'
);
}
if
(
$this
->
getMetadataValue
(
'authorPHID'
))
{
$phids
[]
=
$this
->
getMetadataValue
(
'authorPHID'
);
}
}
break
;
case
self
::
TYPE_UPDATE
:
if
(
$new
)
{
$phids
[]
=
$new
;
}
break
;
}
return
$phids
;
}
public
function
getActionStrength
()
{
switch
(
$this
->
getTransactionType
())
{
case
self
::
TYPE_ACTION
:
return
3
;
case
self
::
TYPE_UPDATE
:
return
2
;
}
return
parent
::
getActionStrength
();
}
public
function
getActionName
()
{
switch
(
$this
->
getTransactionType
())
{
case
self
::
TYPE_INLINE
:
return
pht
(
'Commented On'
);
case
self
::
TYPE_UPDATE
:
$old
=
$this
->
getOldValue
();
if
(
$old
===
null
)
{
return
pht
(
'Request'
);
}
else
{
return
pht
(
'Updated'
);
}
case
self
::
TYPE_ACTION
:
$map
=
array
(
DifferentialAction
::
ACTION_ACCEPT
=>
pht
(
'Accepted'
),
DifferentialAction
::
ACTION_REJECT
=>
pht
(
'Requested Changes To'
),
DifferentialAction
::
ACTION_RETHINK
=>
pht
(
'Planned Changes To'
),
DifferentialAction
::
ACTION_ABANDON
=>
pht
(
'Abandoned'
),
DifferentialAction
::
ACTION_CLOSE
=>
pht
(
'Closed'
),
DifferentialAction
::
ACTION_REQUEST
=>
pht
(
'Requested A Review Of'
),
DifferentialAction
::
ACTION_RESIGN
=>
pht
(
'Resigned From'
),
DifferentialAction
::
ACTION_ADDREVIEWERS
=>
pht
(
'Added Reviewers'
),
DifferentialAction
::
ACTION_CLAIM
=>
pht
(
'Commandeered'
),
DifferentialAction
::
ACTION_REOPEN
=>
pht
(
'Reopened'
),
);
$name
=
idx
(
$map
,
$this
->
getNewValue
());
if
(
$name
!==
null
)
{
return
$name
;
}
break
;
}
return
parent
::
getActionName
();
}
public
function
getMailTags
()
{
$tags
=
array
();
switch
(
$this
->
getTransactionType
())
{
case
PhabricatorTransactions
::
TYPE_SUBSCRIBERS
;
$tags
[]
=
self
::
MAILTAG_CC
;
break
;
case
self
::
TYPE_ACTION
:
switch
(
$this
->
getNewValue
())
{
case
DifferentialAction
::
ACTION_CLOSE
:
$tags
[]
=
self
::
MAILTAG_CLOSED
;
break
;
}
break
;
case
self
::
TYPE_UPDATE
:
$old
=
$this
->
getOldValue
();
if
(
$old
===
null
)
{
$tags
[]
=
self
::
MAILTAG_REVIEW_REQUEST
;
}
else
{
$tags
[]
=
self
::
MAILTAG_UPDATED
;
}
break
;
case
PhabricatorTransactions
::
TYPE_COMMENT
:
case
self
::
TYPE_INLINE
:
$tags
[]
=
self
::
MAILTAG_COMMENT
;
break
;
case
DifferentialRevisionReviewersTransaction
::
TRANSACTIONTYPE
:
$tags
[]
=
self
::
MAILTAG_REVIEWERS
;
break
;
case
DifferentialRevisionCloseTransaction
::
TRANSACTIONTYPE
:
$tags
[]
=
self
::
MAILTAG_CLOSED
;
break
;
}
if
(!
$tags
)
{
$tags
[]
=
self
::
MAILTAG_OTHER
;
}
return
$tags
;
}
public
function
getTitle
()
{
$author_phid
=
$this
->
getAuthorPHID
();
$author_handle
=
$this
->
renderHandleLink
(
$author_phid
);
$old
=
$this
->
getOldValue
();
$new
=
$this
->
getNewValue
();
switch
(
$this
->
getTransactionType
())
{
case
self
::
TYPE_INLINE
:
return
pht
(
'%s added inline comments.'
,
$author_handle
);
case
self
::
TYPE_UPDATE
:
if
(
$this
->
getMetadataValue
(
'isCommitUpdate'
))
{
return
pht
(
'This revision was automatically updated to reflect the '
.
'committed changes.'
);
}
else
if
(
$new
)
{
// TODO: Migrate to PHIDs and use handles here?
if
(
phid_get_type
(
$new
)
==
DifferentialDiffPHIDType
::
TYPECONST
)
{
return
pht
(
'%s updated this revision to %s.'
,
$author_handle
,
$this
->
renderHandleLink
(
$new
));
}
else
{
return
pht
(
'%s updated this revision.'
,
$author_handle
);
}
}
else
{
return
pht
(
'%s updated this revision.'
,
$author_handle
);
}
case
self
::
TYPE_ACTION
:
switch
(
$new
)
{
case
DifferentialAction
::
ACTION_CLOSE
:
if
(!
$this
->
getMetadataValue
(
'isCommitClose'
))
{
return
DifferentialAction
::
getBasicStoryText
(
$new
,
$author_handle
);
}
$commit_name
=
$this
->
renderHandleLink
(
$this
->
getMetadataValue
(
'commitPHID'
));
$committer_phid
=
$this
->
getMetadataValue
(
'committerPHID'
);
$author_phid
=
$this
->
getMetadataValue
(
'authorPHID'
);
if
(
$this
->
getHandleIfExists
(
$committer_phid
))
{
$committer_name
=
$this
->
renderHandleLink
(
$committer_phid
);
}
else
{
$committer_name
=
$this
->
getMetadataValue
(
'committerName'
);
}
if
(
$this
->
getHandleIfExists
(
$author_phid
))
{
$author_name
=
$this
->
renderHandleLink
(
$author_phid
);
}
else
{
$author_name
=
$this
->
getMetadataValue
(
'authorName'
);
}
if
(
$committer_name
&&
(
$committer_name
!=
$author_name
))
{
return
pht
(
'Closed by commit %s (authored by %s, committed by %s).'
,
$commit_name
,
$author_name
,
$committer_name
);
}
else
{
return
pht
(
'Closed by commit %s (authored by %s).'
,
$commit_name
,
$author_name
);
}
break
;
default
:
return
DifferentialAction
::
getBasicStoryText
(
$new
,
$author_handle
);
}
break
;
}
return
parent
::
getTitle
();
}
public
function
renderExtraInformationLink
()
{
if
(
$this
->
getMetadataValue
(
'revisionMatchData'
))
{
$details_href
=
'/differential/revision/closedetails/'
.
$this
->
getPHID
().
'/'
;
$details_link
=
javelin_tag
(
'a'
,
array
(
'href'
=>
$details_href
,
'sigil'
=>
'workflow'
,
),
pht
(
'Explain Why'
));
return
$details_link
;
}
return
parent
::
renderExtraInformationLink
();
}
public
function
getTitleForFeed
()
{
$author_phid
=
$this
->
getAuthorPHID
();
$object_phid
=
$this
->
getObjectPHID
();
$old
=
$this
->
getOldValue
();
$new
=
$this
->
getNewValue
();
$author_link
=
$this
->
renderHandleLink
(
$author_phid
);
$object_link
=
$this
->
renderHandleLink
(
$object_phid
);
switch
(
$this
->
getTransactionType
())
{
case
self
::
TYPE_INLINE
:
return
pht
(
'%s added inline comments to %s.'
,
$author_link
,
$object_link
);
case
self
::
TYPE_UPDATE
:
return
pht
(
'%s updated the diff for %s.'
,
$author_link
,
$object_link
);
case
self
::
TYPE_ACTION
:
switch
(
$new
)
{
case
DifferentialAction
::
ACTION_ACCEPT
:
return
pht
(
'%s accepted %s.'
,
$author_link
,
$object_link
);
case
DifferentialAction
::
ACTION_REJECT
:
return
pht
(
'%s requested changes to %s.'
,
$author_link
,
$object_link
);
case
DifferentialAction
::
ACTION_RETHINK
:
return
pht
(
'%s planned changes to %s.'
,
$author_link
,
$object_link
);
case
DifferentialAction
::
ACTION_ABANDON
:
return
pht
(
'%s abandoned %s.'
,
$author_link
,
$object_link
);
case
DifferentialAction
::
ACTION_CLOSE
:
if
(!
$this
->
getMetadataValue
(
'isCommitClose'
))
{
return
pht
(
'%s closed %s.'
,
$author_link
,
$object_link
);
}
else
{
$commit_name
=
$this
->
renderHandleLink
(
$this
->
getMetadataValue
(
'commitPHID'
));
$committer_phid
=
$this
->
getMetadataValue
(
'committerPHID'
);
$author_phid
=
$this
->
getMetadataValue
(
'authorPHID'
);
if
(
$this
->
getHandleIfExists
(
$committer_phid
))
{
$committer_name
=
$this
->
renderHandleLink
(
$committer_phid
);
}
else
{
$committer_name
=
$this
->
getMetadataValue
(
'committerName'
);
}
if
(
$this
->
getHandleIfExists
(
$author_phid
))
{
$author_name
=
$this
->
renderHandleLink
(
$author_phid
);
}
else
{
$author_name
=
$this
->
getMetadataValue
(
'authorName'
);
}
// Check if the committer and author are the same. They're the
// same if both resolved and are the same user, or if neither
// resolved and the text is identical.
if
(
$committer_phid
&&
$author_phid
)
{
$same_author
=
(
$committer_phid
==
$author_phid
);
}
else
if
(!
$committer_phid
&&
!
$author_phid
)
{
$same_author
=
(
$committer_name
==
$author_name
);
}
else
{
$same_author
=
false
;
}
if
(
$committer_name
&&
!
$same_author
)
{
return
pht
(
'%s closed %s by committing %s (authored by %s).'
,
$author_link
,
$object_link
,
$commit_name
,
$author_name
);
}
else
{
return
pht
(
'%s closed %s by committing %s.'
,
$author_link
,
$object_link
,
$commit_name
);
}
}
break
;
case
DifferentialAction
::
ACTION_REQUEST
:
return
pht
(
'%s requested review of %s.'
,
$author_link
,
$object_link
);
case
DifferentialAction
::
ACTION_RECLAIM
:
return
pht
(
'%s reclaimed %s.'
,
$author_link
,
$object_link
);
case
DifferentialAction
::
ACTION_RESIGN
:
return
pht
(
'%s resigned from %s.'
,
$author_link
,
$object_link
);
case
DifferentialAction
::
ACTION_CLAIM
:
return
pht
(
'%s commandeered %s.'
,
$author_link
,
$object_link
);
case
DifferentialAction
::
ACTION_REOPEN
:
return
pht
(
'%s reopened %s.'
,
$author_link
,
$object_link
);
}
break
;
}
return
parent
::
getTitleForFeed
();
}
public
function
getIcon
()
{
switch
(
$this
->
getTransactionType
())
{
case
self
::
TYPE_INLINE
:
return
'fa-comment'
;
case
self
::
TYPE_UPDATE
:
return
'fa-refresh'
;
case
self
::
TYPE_ACTION
:
switch
(
$this
->
getNewValue
())
{
case
DifferentialAction
::
ACTION_CLOSE
:
return
'fa-check'
;
case
DifferentialAction
::
ACTION_ACCEPT
:
return
'fa-check-circle-o'
;
case
DifferentialAction
::
ACTION_REJECT
:
return
'fa-times-circle-o'
;
case
DifferentialAction
::
ACTION_ABANDON
:
return
'fa-plane'
;
case
DifferentialAction
::
ACTION_RETHINK
:
return
'fa-headphones'
;
case
DifferentialAction
::
ACTION_REQUEST
:
return
'fa-refresh'
;
case
DifferentialAction
::
ACTION_RECLAIM
:
case
DifferentialAction
::
ACTION_REOPEN
:
return
'fa-bullhorn'
;
case
DifferentialAction
::
ACTION_RESIGN
:
return
'fa-flag'
;
case
DifferentialAction
::
ACTION_CLAIM
:
return
'fa-flag'
;
}
case
PhabricatorTransactions
::
TYPE_EDGE
:
switch
(
$this
->
getMetadataValue
(
'edge:type'
))
{
case
DifferentialRevisionHasReviewerEdgeType
::
EDGECONST
:
return
'fa-user'
;
}
}
return
parent
::
getIcon
();
}
public
function
shouldDisplayGroupWith
(
array
$group
)
{
// Never group status changes with other types of actions, they're indirect
// and don't make sense when combined with direct actions.
if
(
$this
->
isStatusTransaction
(
$this
))
{
return
false
;
}
foreach
(
$group
as
$xaction
)
{
if
(
$this
->
isStatusTransaction
(
$xaction
))
{
return
false
;
}
}
return
parent
::
shouldDisplayGroupWith
(
$group
);
}
private
function
isStatusTransaction
(
$xaction
)
{
$status_type
=
DifferentialRevisionStatusTransaction
::
TRANSACTIONTYPE
;
if
(
$xaction
->
getTransactionType
()
==
$status_type
)
{
return
true
;
}
return
false
;
}
public
function
getColor
()
{
switch
(
$this
->
getTransactionType
())
{
case
self
::
TYPE_UPDATE
:
return
PhabricatorTransactions
::
COLOR_SKY
;
case
self
::
TYPE_ACTION
:
switch
(
$this
->
getNewValue
())
{
case
DifferentialAction
::
ACTION_CLOSE
:
return
PhabricatorTransactions
::
COLOR_INDIGO
;
case
DifferentialAction
::
ACTION_ACCEPT
:
return
PhabricatorTransactions
::
COLOR_GREEN
;
case
DifferentialAction
::
ACTION_REJECT
:
return
PhabricatorTransactions
::
COLOR_RED
;
case
DifferentialAction
::
ACTION_ABANDON
:
return
PhabricatorTransactions
::
COLOR_INDIGO
;
case
DifferentialAction
::
ACTION_RETHINK
:
return
PhabricatorTransactions
::
COLOR_RED
;
case
DifferentialAction
::
ACTION_REQUEST
:
return
PhabricatorTransactions
::
COLOR_SKY
;
case
DifferentialAction
::
ACTION_RECLAIM
:
return
PhabricatorTransactions
::
COLOR_SKY
;
case
DifferentialAction
::
ACTION_REOPEN
:
return
PhabricatorTransactions
::
COLOR_SKY
;
case
DifferentialAction
::
ACTION_RESIGN
:
return
PhabricatorTransactions
::
COLOR_ORANGE
;
case
DifferentialAction
::
ACTION_CLAIM
:
return
PhabricatorTransactions
::
COLOR_YELLOW
;
}
}
return
parent
::
getColor
();
}
public
function
getNoEffectDescription
()
{
switch
(
$this
->
getTransactionType
())
{
case
self
::
TYPE_ACTION
:
switch
(
$this
->
getNewValue
())
{
case
DifferentialAction
::
ACTION_CLOSE
:
return
pht
(
'This revision is already closed.'
);
case
DifferentialAction
::
ACTION_ABANDON
:
return
pht
(
'This revision has already been abandoned.'
);
case
DifferentialAction
::
ACTION_RECLAIM
:
return
pht
(
'You can not reclaim this revision because his revision is '
.
'not abandoned.'
);
case
DifferentialAction
::
ACTION_REOPEN
:
return
pht
(
'You can not reopen this revision because this revision is '
.
'not closed.'
);
case
DifferentialAction
::
ACTION_RETHINK
:
return
pht
(
'This revision already requires changes.'
);
case
DifferentialAction
::
ACTION_CLAIM
:
return
pht
(
'You can not commandeer this revision because you already own '
.
'it.'
);
}
break
;
}
return
parent
::
getNoEffectDescription
();
}
public
function
renderAsTextForDoorkeeper
(
DoorkeeperFeedStoryPublisher
$publisher
,
PhabricatorFeedStory
$story
,
array
$xactions
)
{
$body
=
parent
::
renderAsTextForDoorkeeper
(
$publisher
,
$story
,
$xactions
);
$inlines
=
array
();
foreach
(
$xactions
as
$xaction
)
{
if
(
$xaction
->
getTransactionType
()
==
self
::
TYPE_INLINE
)
{
$inlines
[]
=
$xaction
;
}
}
// TODO: This is a bit gross, but far less bad than it used to be. It
// could be further cleaned up at some point.
if
(
$inlines
)
{
$engine
=
PhabricatorMarkupEngine
::
newMarkupEngine
(
array
())
->
setConfig
(
'viewer'
,
new
PhabricatorUser
())
->
setMode
(
PhutilRemarkupEngine
::
MODE_TEXT
);
$body
.=
"
\n\n
"
;
$body
.=
pht
(
'Inline Comments'
);
$body
.=
"
\n
"
;
$changeset_ids
=
array
();
foreach
(
$inlines
as
$inline
)
{
$changeset_ids
[]
=
$inline
->
getComment
()->
getChangesetID
();
}
$changesets
=
id
(
new
DifferentialChangeset
())->
loadAllWhere
(
'id IN (%Ld)'
,
$changeset_ids
);
foreach
(
$inlines
as
$inline
)
{
$comment
=
$inline
->
getComment
();
$changeset
=
idx
(
$changesets
,
$comment
->
getChangesetID
());
if
(!
$changeset
)
{
continue
;
}
$filename
=
$changeset
->
getDisplayFilename
();
$linenumber
=
$comment
->
getLineNumber
();
$inline_text
=
$engine
->
markupText
(
$comment
->
getContent
());
$inline_text
=
rtrim
(
$inline_text
);
$body
.=
"{$filename}:{$linenumber} {$inline_text}
\n
"
;
}
}
return
$body
;
}
}
Event Timeline
Log In to Comment