diff --git a/src/applications/repository/worker/commitchangeparser/svn/PhabricatorRepositorySvnCommitChangeParserWorker.php b/src/applications/repository/worker/commitchangeparser/svn/PhabricatorRepositorySvnCommitChangeParserWorker.php index bb92e0e9c0..0965aaef9d 100644 --- a/src/applications/repository/worker/commitchangeparser/svn/PhabricatorRepositorySvnCommitChangeParserWorker.php +++ b/src/applications/repository/worker/commitchangeparser/svn/PhabricatorRepositorySvnCommitChangeParserWorker.php @@ -502,7 +502,53 @@ class PhabricatorRepositorySvnCommitChangeParserWorker $repository->getID(), $commits); - return ipull($commit_data, 'id', 'commitIdentifier'); + $commit_map = ipull($commit_data, 'id', 'commitIdentifier'); + + $need = array(); + foreach ($commits as $commit) { + if (empty($commit_map[$commit])) { + $need[] = $commit; + } + } + + // If we are parsing a Subversion repository and have been configured to + // import only some subdirectory of it, we may find commits which reference + // other foreign commits outside of the directory (for instance, because of + // a move or copy). Rather than trying to execute full parses on them, just + // create stub commits and identify the stubs as foreign commits. + if ($need) { + $subpath = $repository->getDetail('svn-subpath'); + if (!$subpath) { + $commits = implode(', ', $need); + throw new Exception( + "Missing commits ({$need}) in a SVN repository which is not ". + "configured for subdirectory-only parsing!"); + } + foreach ($need as $foreign_commit) { + $commit = new PhabricatorRepositoryCommit(); + $commit->setRepositoryID($repository->getID()); + $commit->setCommitIdentifier($foreign_commit); + $commit->setEpoch(0); + $commit->save(); + + $data = new PhabricatorRepositoryCommitData(); + $data->setCommitID($commit->getID()); + $data->setAuthorName(''); + $data->setCommitMessage(''); + $data->setCommitDetails( + array( + 'foreign-svn-stub' => true, + // Denormalize this to make it easier to debug cases where someone + // did half a parse and then changed the subdirectory or something + // like that. + 'svn-subpath' => $subpath, + )); + $data->save(); + $commit_map[$foreign_commit] = $commit->getID(); + } + } + + return $commit_map; } private function lookupPathFileType( diff --git a/src/applications/repository/worker/commitchangeparser/svn/__init__.php b/src/applications/repository/worker/commitchangeparser/svn/__init__.php index 27bd1250dc..88eb272294 100644 --- a/src/applications/repository/worker/commitchangeparser/svn/__init__.php +++ b/src/applications/repository/worker/commitchangeparser/svn/__init__.php @@ -8,6 +8,7 @@ phutil_require_module('phabricator', 'applications/differential/constants/changetype'); phutil_require_module('phabricator', 'applications/repository/storage/commit'); +phutil_require_module('phabricator', 'applications/repository/storage/commitdata'); phutil_require_module('phabricator', 'applications/repository/storage/repository'); phutil_require_module('phabricator', 'applications/repository/worker/commitchangeparser/base'); phutil_require_module('phabricator', 'storage/qsprintf');