[ Index ]

PHP Cross Reference of Phabricator

title

Body

[close]

/src/applications/diffusion/herald/ -> HeraldPreCommitContentAdapter.php (source)

   1  <?php
   2  
   3  final class HeraldPreCommitContentAdapter extends HeraldPreCommitAdapter {
   4  
   5    private $changesets;
   6    private $commitRef;
   7    private $fields;
   8    private $revision = false;
   9  
  10    public function getAdapterContentName() {
  11      return pht('Commit Hook: Commit Content');
  12    }
  13  
  14    public function getAdapterSortOrder() {
  15      return 2500;
  16    }
  17  
  18    public function getAdapterContentDescription() {
  19      return pht(
  20        "React to commits being pushed to hosted repositories.\n".
  21        "Hook rules can block changes and send push summary mail.");
  22    }
  23  
  24    public function getFields() {
  25      return array_merge(
  26        array(
  27          self::FIELD_BODY,
  28          self::FIELD_AUTHOR,
  29          self::FIELD_AUTHOR_RAW,
  30          self::FIELD_COMMITTER,
  31          self::FIELD_COMMITTER_RAW,
  32          self::FIELD_BRANCHES,
  33          self::FIELD_DIFF_FILE,
  34          self::FIELD_DIFF_CONTENT,
  35          self::FIELD_DIFF_ADDED_CONTENT,
  36          self::FIELD_DIFF_REMOVED_CONTENT,
  37          self::FIELD_DIFF_ENORMOUS,
  38          self::FIELD_REPOSITORY,
  39          self::FIELD_REPOSITORY_PROJECTS,
  40          self::FIELD_PUSHER,
  41          self::FIELD_PUSHER_PROJECTS,
  42          self::FIELD_PUSHER_IS_COMMITTER,
  43          self::FIELD_DIFFERENTIAL_REVISION,
  44          self::FIELD_DIFFERENTIAL_ACCEPTED,
  45          self::FIELD_DIFFERENTIAL_REVIEWERS,
  46          self::FIELD_DIFFERENTIAL_CCS,
  47          self::FIELD_IS_MERGE_COMMIT,
  48        ),
  49        parent::getFields());
  50    }
  51  
  52    public function getHeraldName() {
  53      return pht('Push Log (Content)');
  54    }
  55  
  56    public function getHeraldField($field) {
  57      $log = $this->getObject();
  58      switch ($field) {
  59        case self::FIELD_BODY:
  60          return $this->getCommitRef()->getMessage();
  61        case self::FIELD_AUTHOR:
  62          return $this->getAuthorPHID();
  63        case self::FIELD_AUTHOR_RAW:
  64          return $this->getAuthorRaw();
  65        case self::FIELD_COMMITTER:
  66          return $this->getCommitterPHID();
  67        case self::FIELD_COMMITTER_RAW:
  68          return $this->getCommitterRaw();
  69        case self::FIELD_BRANCHES:
  70          return $this->getBranches();
  71        case self::FIELD_DIFF_FILE:
  72          return $this->getDiffContent('name');
  73        case self::FIELD_DIFF_CONTENT:
  74          return $this->getDiffContent('*');
  75        case self::FIELD_DIFF_ADDED_CONTENT:
  76          return $this->getDiffContent('+');
  77        case self::FIELD_DIFF_REMOVED_CONTENT:
  78          return $this->getDiffContent('-');
  79        case self::FIELD_DIFF_ENORMOUS:
  80          $this->getDiffContent('*');
  81          return ($this->changesets instanceof Exception);
  82        case self::FIELD_REPOSITORY:
  83          return $this->getHookEngine()->getRepository()->getPHID();
  84        case self::FIELD_REPOSITORY_PROJECTS:
  85          return $this->getHookEngine()->getRepository()->getProjectPHIDs();
  86        case self::FIELD_PUSHER:
  87          return $this->getHookEngine()->getViewer()->getPHID();
  88        case self::FIELD_PUSHER_PROJECTS:
  89          return $this->getHookEngine()->loadViewerProjectPHIDsForHerald();
  90        case self::FIELD_DIFFERENTIAL_REVISION:
  91          $revision = $this->getRevision();
  92          if (!$revision) {
  93            return null;
  94          }
  95          return $revision->getPHID();
  96        case self::FIELD_DIFFERENTIAL_ACCEPTED:
  97          $revision = $this->getRevision();
  98          if (!$revision) {
  99            return null;
 100          }
 101          $status_accepted = ArcanistDifferentialRevisionStatus::ACCEPTED;
 102          if ($revision->getStatus() != $status_accepted) {
 103            return null;
 104          }
 105          return $revision->getPHID();
 106        case self::FIELD_DIFFERENTIAL_REVIEWERS:
 107          $revision = $this->getRevision();
 108          if (!$revision) {
 109            return array();
 110          }
 111          return $revision->getReviewers();
 112        case self::FIELD_DIFFERENTIAL_CCS:
 113          $revision = $this->getRevision();
 114          if (!$revision) {
 115            return array();
 116          }
 117          return $revision->getCCPHIDs();
 118        case self::FIELD_IS_MERGE_COMMIT:
 119          return $this->getIsMergeCommit();
 120        case self::FIELD_PUSHER_IS_COMMITTER:
 121          $pusher_phid = $this->getHookEngine()->getViewer()->getPHID();
 122          return ($this->getCommitterPHID() == $pusher_phid);
 123      }
 124  
 125      return parent::getHeraldField($field);
 126    }
 127  
 128    private function getDiffContent($type) {
 129      if ($this->changesets === null) {
 130        try {
 131          $this->changesets = $this->getHookEngine()->loadChangesetsForCommit(
 132            $this->getObject()->getRefNew());
 133        } catch (Exception $ex) {
 134          $this->changesets = $ex;
 135        }
 136      }
 137  
 138      if ($this->changesets instanceof Exception) {
 139        $ex_class = get_class($this->changesets);
 140        $ex_message = $this->changesets->getmessage();
 141        if ($type === 'name') {
 142          return array("<{$ex_class}: {$ex_message}>");
 143        } else {
 144          return array("<{$ex_class}>" => $ex_message);
 145        }
 146      }
 147  
 148      $result = array();
 149      if ($type === 'name') {
 150        foreach ($this->changesets as $change) {
 151          $result[] = $change->getFilename();
 152        }
 153      } else {
 154        foreach ($this->changesets as $change) {
 155          $lines = array();
 156          foreach ($change->getHunks() as $hunk) {
 157            switch ($type) {
 158              case '-':
 159                $lines[] = $hunk->makeOldFile();
 160                break;
 161              case '+':
 162                $lines[] = $hunk->makeNewFile();
 163                break;
 164              case '*':
 165              default:
 166                $lines[] = $hunk->makeChanges();
 167                break;
 168            }
 169          }
 170          $result[$change->getFilename()] = implode('', $lines);
 171        }
 172      }
 173  
 174      return $result;
 175    }
 176  
 177    private function getCommitRef() {
 178      if ($this->commitRef === null) {
 179        $this->commitRef = $this->getHookEngine()->loadCommitRefForCommit(
 180          $this->getObject()->getRefNew());
 181      }
 182      return $this->commitRef;
 183    }
 184  
 185    private function getAuthorPHID() {
 186      $repository = $this->getHookEngine()->getRepository();
 187      $vcs = $repository->getVersionControlSystem();
 188      switch ($vcs) {
 189        case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
 190        case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
 191          $ref = $this->getCommitRef();
 192          $author = $ref->getAuthor();
 193          if (!strlen($author)) {
 194            return null;
 195          }
 196          return $this->lookupUser($author);
 197        case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
 198          // In Subversion, the pusher is always the author.
 199          return $this->getHookEngine()->getViewer()->getPHID();
 200      }
 201    }
 202  
 203    private function getCommitterPHID() {
 204      $repository = $this->getHookEngine()->getRepository();
 205      $vcs = $repository->getVersionControlSystem();
 206      switch ($vcs) {
 207        case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
 208        case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
 209          // If there's no committer information, we're going to return the
 210          // author instead. However, if there's committer information and we
 211          // can't resolve it, return `null`.
 212          $ref = $this->getCommitRef();
 213          $committer = $ref->getCommitter();
 214          if (!strlen($committer)) {
 215            return $this->getAuthorPHID();
 216          }
 217          return $this->lookupUser($committer);
 218        case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
 219          // In Subversion, the pusher is always the committer.
 220          return $this->getHookEngine()->getViewer()->getPHID();
 221      }
 222    }
 223  
 224    private function getAuthorRaw() {
 225      $repository = $this->getHookEngine()->getRepository();
 226      $vcs = $repository->getVersionControlSystem();
 227      switch ($vcs) {
 228        case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
 229        case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
 230          $ref = $this->getCommitRef();
 231          return $ref->getAuthor();
 232        case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
 233          // In Subversion, the pusher is always the author.
 234          return $this->getHookEngine()->getViewer()->getUsername();
 235      }
 236    }
 237  
 238    private function getCommitterRaw() {
 239      $repository = $this->getHookEngine()->getRepository();
 240      $vcs = $repository->getVersionControlSystem();
 241      switch ($vcs) {
 242        case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
 243        case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
 244          // Here, if there's no committer, we're going to return the author
 245          // instead.
 246          $ref = $this->getCommitRef();
 247          $committer = $ref->getCommitter();
 248          if (strlen($committer)) {
 249            return $committer;
 250          }
 251          return $ref->getAuthor();
 252        case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
 253          // In Subversion, the pusher is always the committer.
 254          return $this->getHookEngine()->getViewer()->getUsername();
 255      }
 256    }
 257  
 258    private function lookupUser($author) {
 259      return id(new DiffusionResolveUserQuery())
 260        ->withName($author)
 261        ->execute();
 262    }
 263  
 264    private function getCommitFields() {
 265      if ($this->fields === null) {
 266        $this->fields = id(new DiffusionLowLevelCommitFieldsQuery())
 267          ->setRepository($this->getHookEngine()->getRepository())
 268          ->withCommitRef($this->getCommitRef())
 269          ->execute();
 270      }
 271      return $this->fields;
 272    }
 273  
 274    private function getRevision() {
 275      if ($this->revision === false) {
 276        $fields = $this->getCommitFields();
 277        $revision_id = idx($fields, 'revisionID');
 278        if (!$revision_id) {
 279          $this->revision = null;
 280        } else {
 281          $this->revision = id(new DifferentialRevisionQuery())
 282            ->setViewer(PhabricatorUser::getOmnipotentUser())
 283            ->withIDs(array($revision_id))
 284            ->needRelationships(true)
 285            ->executeOne();
 286        }
 287      }
 288  
 289      return $this->revision;
 290    }
 291  
 292    private function getIsMergeCommit() {
 293      $repository = $this->getHookEngine()->getRepository();
 294      $vcs = $repository->getVersionControlSystem();
 295      switch ($vcs) {
 296        case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
 297        case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
 298          $parents = id(new DiffusionLowLevelParentsQuery())
 299            ->setRepository($repository)
 300            ->withIdentifier($this->getObject()->getRefNew())
 301            ->execute();
 302  
 303          return (count($parents) > 1);
 304        case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
 305          // NOTE: For now, we ignore "svn:mergeinfo" at all levels. We might
 306          // change this some day, but it's not nearly as clear a signal as
 307          // ancestry is in Git/Mercurial.
 308          return false;
 309      }
 310    }
 311  
 312    private function getBranches() {
 313      return $this->getHookEngine()->loadBranches(
 314        $this->getObject()->getRefNew());
 315    }
 316  
 317  }


Generated: Sun Nov 30 09:20:46 2014 Cross-referenced by PHPXref 0.7.1