Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F97219358
ConduitAPI_diffusion_getcommits_Method.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
Fri, Jan 3, 13:32
Size
8 KB
Mime Type
text/x-php
Expires
Sun, Jan 5, 13:32 (2 d)
Engine
blob
Format
Raw Data
Handle
23357245
Attached To
rPH Phabricator
ConduitAPI_diffusion_getcommits_Method.php
View Options
<?php
/**
* @group conduit
*/
final
class
ConduitAPI_diffusion_getcommits_Method
extends
ConduitAPI_diffusion_Method
{
public
function
getMethodDescription
()
{
return
pht
(
'Retrieve Diffusion commit information.'
);
}
public
function
getMethodStatus
()
{
return
self
::
METHOD_STATUS_DEPRECATED
;
}
public
function
getMethodStatusDescription
()
{
return
pht
(
'Obsoleted by diffusion.querycommits.'
);
}
public
function
defineParamTypes
()
{
return
array
(
'commits'
=>
'required list<string>'
,
);
}
public
function
defineReturnType
()
{
return
'nonempty list<dict<string, wild>>'
;
}
public
function
defineErrorTypes
()
{
return
array
(
);
}
protected
function
execute
(
ConduitAPIRequest
$request
)
{
$results
=
array
();
$commits
=
$request
->
getValue
(
'commits'
);
$commits
=
array_fill_keys
(
$commits
,
array
());
foreach
(
$commits
as
$name
=>
$info
)
{
$matches
=
null
;
if
(!
preg_match
(
'/^r([A-Z]+)([0-9a-f]+)
\z
/'
,
$name
,
$matches
))
{
$results
[
$name
]
=
array
(
'error'
=>
'ERR-UNPARSEABLE'
,
);
unset
(
$commits
[
$name
]);
continue
;
}
$commits
[
$name
]
=
array
(
'callsign'
=>
$matches
[
1
],
'commitIdentifier'
=>
$matches
[
2
],
);
}
if
(!
$commits
)
{
return
$results
;
}
$callsigns
=
ipull
(
$commits
,
'callsign'
);
$callsigns
=
array_unique
(
$callsigns
);
$repos
=
id
(
new
PhabricatorRepositoryQuery
())
->
setViewer
(
$request
->
getUser
())
->
withCallsigns
(
$callsigns
)
->
execute
();
$repos
=
mpull
(
$repos
,
null
,
'getCallsign'
);
foreach
(
$commits
as
$name
=>
$info
)
{
$repo
=
idx
(
$repos
,
$info
[
'callsign'
]);
if
(!
$repo
)
{
$results
[
$name
]
=
$info
+
array
(
'error'
=>
'ERR-UNKNOWN-REPOSITORY'
,
);
unset
(
$commits
[
$name
]);
continue
;
}
$commits
[
$name
]
+=
array
(
'repositoryPHID'
=>
$repo
->
getPHID
(),
'repositoryID'
=>
$repo
->
getID
(),
);
}
if
(!
$commits
)
{
return
$results
;
}
// Execute a complicated query to figure out the primary commit information
// for each referenced commit.
$cdata
=
$this
->
queryCommitInformation
(
$commits
,
$repos
);
// We've built the queries so that each row also has the identifier we used
// to select it, which might be a git prefix rather than a full identifier.
$ref_map
=
ipull
(
$cdata
,
'commitIdentifier'
,
'commitRef'
);
$cobjs
=
id
(
new
PhabricatorRepositoryCommit
())->
loadAllFromArray
(
$cdata
);
$cobjs
=
mgroup
(
$cobjs
,
'getRepositoryID'
,
'getCommitIdentifier'
);
foreach
(
$commits
as
$name
=>
$commit
)
{
// Expand short git names into full identifiers. For SVN this map is just
// the identity.
$full_identifier
=
idx
(
$ref_map
,
$commit
[
'commitIdentifier'
]);
$repo_id
=
$commit
[
'repositoryID'
];
unset
(
$commits
[
$name
][
'repositoryID'
]);
if
(
empty
(
$full_identifier
)
||
empty
(
$cobjs
[
$commit
[
'repositoryID'
]][
$full_identifier
]))
{
$results
[
$name
]
=
$commit
+
array
(
'error'
=>
'ERR-UNKNOWN-COMMIT'
,
);
unset
(
$commits
[
$name
]);
continue
;
}
$cobj_arr
=
$cobjs
[
$commit
[
'repositoryID'
]][
$full_identifier
];
$cobj
=
head
(
$cobj_arr
);
$commits
[
$name
]
+=
array
(
'epoch'
=>
$cobj
->
getEpoch
(),
'commitPHID'
=>
$cobj
->
getPHID
(),
'commitID'
=>
$cobj
->
getID
(),
);
// Upgrade git short references into full commit identifiers.
$identifier
=
$cobj
->
getCommitIdentifier
();
$commits
[
$name
][
'commitIdentifier'
]
=
$identifier
;
$callsign
=
$commits
[
$name
][
'callsign'
];
$uri
=
"/r{$callsign}{$identifier}"
;
$commits
[
$name
][
'uri'
]
=
PhabricatorEnv
::
getProductionURI
(
$uri
);
}
if
(!
$commits
)
{
return
$results
;
}
$commits
=
$this
->
addRepositoryCommitDataInformation
(
$commits
);
$commits
=
$this
->
addDifferentialInformation
(
$commits
);
$commits
=
$this
->
addManiphestInformation
(
$commits
);
foreach
(
$commits
as
$name
=>
$commit
)
{
$results
[
$name
]
=
$commit
;
}
return
$results
;
}
/**
* Retrieve primary commit information for all referenced commits.
*/
private
function
queryCommitInformation
(
array
$commits
,
array
$repos
)
{
assert_instances_of
(
$repos
,
'PhabricatorRepository'
);
$conn_r
=
id
(
new
PhabricatorRepositoryCommit
())->
establishConnection
(
'r'
);
$repos
=
mpull
(
$repos
,
null
,
'getID'
);
$groups
=
array
();
foreach
(
$commits
as
$name
=>
$commit
)
{
$groups
[
$commit
[
'repositoryID'
]][]
=
$commit
[
'commitIdentifier'
];
}
// NOTE: MySQL goes crazy and does a massive table scan if we build a more
// sensible version of this query. Make sure the query plan is OK if you
// attempt to reduce the craziness here. METANOTE: The addition of prefix
// selection for Git further complicates matters.
$query
=
array
();
$commit_table
=
id
(
new
PhabricatorRepositoryCommit
())->
getTableName
();
foreach
(
$groups
as
$repository_id
=>
$identifiers
)
{
$vcs
=
$repos
[
$repository_id
]->
getVersionControlSystem
();
$is_git
=
(
$vcs
==
PhabricatorRepositoryType
::
REPOSITORY_TYPE_GIT
);
if
(
$is_git
)
{
foreach
(
$identifiers
as
$identifier
)
{
if
(
strlen
(
$identifier
)
<
7
)
{
// Don't bother with silly stuff like 'rX2', which will select
// 1/16th of all commits. Note that with length 7 we'll still get
// collisions in repositories at the tens-of-thousands-of-commits
// scale.
continue
;
}
$query
[]
=
qsprintf
(
$conn_r
,
'SELECT %T.*, %s commitRef
FROM %T WHERE repositoryID = %d
AND commitIdentifier LIKE %>'
,
$commit_table
,
$identifier
,
$commit_table
,
$repository_id
,
$identifier
);
}
}
else
{
$query
[]
=
qsprintf
(
$conn_r
,
'SELECT %T.*, commitIdentifier commitRef
FROM %T WHERE repositoryID = %d
AND commitIdentifier IN (%Ls)'
,
$commit_table
,
$commit_table
,
$repository_id
,
$identifiers
);
}
}
return
queryfx_all
(
$conn_r
,
'%Q'
,
implode
(
' UNION ALL '
,
$query
));
}
/**
* Enhance the commit list with RepositoryCommitData information.
*/
private
function
addRepositoryCommitDataInformation
(
array
$commits
)
{
$commit_ids
=
ipull
(
$commits
,
'commitID'
);
$data
=
id
(
new
PhabricatorRepositoryCommitData
())->
loadAllWhere
(
'commitID in (%Ld)'
,
$commit_ids
);
$data
=
mpull
(
$data
,
null
,
'getCommitID'
);
foreach
(
$commits
as
$name
=>
$commit
)
{
if
(
isset
(
$data
[
$commit
[
'commitID'
]]))
{
$dobj
=
$data
[
$commit
[
'commitID'
]];
$commits
[
$name
]
+=
array
(
'commitMessage'
=>
$dobj
->
getCommitMessage
(),
'commitDetails'
=>
$dobj
->
getCommitDetails
(),
);
}
// Remove this information so we don't expose it via the API since
// external services shouldn't be storing internal Commit IDs.
unset
(
$commits
[
$name
][
'commitID'
]);
}
return
$commits
;
}
/**
* Enhance the commit list with Differential information.
*/
private
function
addDifferentialInformation
(
array
$commits
)
{
$commit_phids
=
ipull
(
$commits
,
'commitPHID'
);
// TODO: (T603) This should be policy checked, either by moving to
// DifferentialRevisionQuery or by doing a followup query to make sure
// the matched objects are visible.
$rev_conn_r
=
id
(
new
DifferentialRevision
())->
establishConnection
(
'r'
);
$revs
=
queryfx_all
(
$rev_conn_r
,
'SELECT r.id id, r.phid phid, c.commitPHID commitPHID FROM %T r JOIN %T c
ON r.id = c.revisionID
WHERE c.commitPHID in (%Ls)'
,
id
(
new
DifferentialRevision
())->
getTableName
(),
DifferentialRevision
::
TABLE_COMMIT
,
$commit_phids
);
$revs
=
ipull
(
$revs
,
null
,
'commitPHID'
);
foreach
(
$commits
as
$name
=>
$commit
)
{
if
(
isset
(
$revs
[
$commit
[
'commitPHID'
]]))
{
$rev
=
$revs
[
$commit
[
'commitPHID'
]];
$commits
[
$name
]
+=
array
(
'differentialRevisionID'
=>
'D'
.
$rev
[
'id'
],
'differentialRevisionPHID'
=>
$rev
[
'phid'
],
);
}
}
return
$commits
;
}
/**
* Enhances the commits list with Maniphest information.
*/
private
function
addManiphestInformation
(
array
$commits
)
{
$task_type
=
PhabricatorEdgeConfig
::
TYPE_COMMIT_HAS_TASK
;
$commit_phids
=
ipull
(
$commits
,
'commitPHID'
);
$edge_query
=
id
(
new
PhabricatorEdgeQuery
())
->
withSourcePHIDs
(
$commit_phids
)
->
withEdgeTypes
(
array
(
$task_type
));
$edges
=
$edge_query
->
execute
();
foreach
(
$commits
as
$name
=>
$commit
)
{
$task_phids
=
$edge_query
->
getDestinationPHIDs
(
array
(
$commit
[
'commitPHID'
]),
array
(
$task_type
));
$commits
[
$name
]
+=
array
(
'taskPHIDs'
=>
$task_phids
,
);
}
return
$commits
;
}
}
Event Timeline
Log In to Comment