public function handleHosting(PhabricatorRepository $repository) { $request = $this->getRequest(); $user = $request->getUser(); $v_hosting = $repository->isHosted(); $edit_uri = $this->getRepositoryControllerURI($repository, 'edit/'); $next_uri = $this->getRepositoryControllerURI($repository, 'edit/serve/'); if ($request->isFormPost()) { $v_hosting = $request->getBool('hosting'); $xactions = array(); $template = id(new PhabricatorRepositoryTransaction()); $type_hosting = PhabricatorRepositoryTransaction::TYPE_HOSTING; $xactions[] = id(clone $template)->setTransactionType($type_hosting)->setNewValue($v_hosting); id(new PhabricatorRepositoryEditor())->setContinueOnNoEffect(true)->setContentSourceFromRequest($request)->setActor($user)->applyTransactions($repository, $xactions); return id(new AphrontRedirectResponse())->setURI($next_uri); } $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Edit Hosting')); $title = pht('Edit Hosting (%s)', $repository->getName()); $hosted_control = id(new AphrontFormRadioButtonControl())->setName('hosting')->setLabel(pht('Hosting'))->addButton(true, pht('Host Repository on Phabricator'), pht('Phabricator will host this repository. Users will be able to ' . 'push commits to Phabricator. Phabricator will not pull ' . 'changes from elsewhere.'))->addButton(false, pht('Host Repository Elsewhere'), pht('Phabricator will pull updates to this repository from a master ' . 'repository elsewhere (for example, on GitHub or Bitbucket). ' . 'Users will not be able to push commits to this repository.'))->setValue($v_hosting); $doc_href = PhabricatorEnv::getDoclink('Diffusion User Guide: Repository Hosting'); $form = id(new AphrontFormView())->setUser($user)->appendRemarkupInstructions(pht('Phabricator can host repositories, or it can track repositories ' . 'hosted elsewhere (like on GitHub or Bitbucket). For information ' . 'on configuring hosting, see [[ %s | Diffusion User Guide: ' . 'Repository Hosting]]', $doc_href))->appendChild($hosted_control)->appendChild(id(new AphrontFormSubmitControl())->setValue(pht('Save and Continue'))->addCancelButton($edit_uri)); $object_box = id(new PHUIObjectBoxView())->setHeaderText($title)->setForm($form); return $this->buildApplicationPage(array($crumbs, $object_box), array('title' => $title)); }
public function createMenuItem(PhabricatorUser $viewer, DifferentialRevision $revision, PhabricatorRepository $repository) { $vcs = $repository->getVersionControlSystem(); if ($vcs !== PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL) { return; } if (!$repository->isHosted()) { return; } return $this->createActionView($revision, pht('Land to Hosted Repository')); }
public function createMenuItem(PhabricatorUser $viewer, DifferentialRevision $revision, PhabricatorRepository $repository) { $vcs = $repository->getVersionControlSystem(); if ($vcs !== PhabricatorRepositoryType::REPOSITORY_TYPE_GIT) { return; } if (!$repository->isHosted()) { return; } if (!$repository->isWorkingCopyBare()) { return; } // TODO: This temporarily disables this action, because it doesn't work // and is confusing to users. If you want to use it, comment out this line // for now and we'll provide real support eventually. return; return $this->createActionView($revision, pht('Land to Hosted Repository')); }
/** * returns PhabricatorActionView or an array of PhabricatorActionView or null. */ public function createMenuItem(PhabricatorUser $viewer, DifferentialRevision $revision, PhabricatorRepository $repository) { $vcs = $repository->getVersionControlSystem(); if ($vcs !== PhabricatorRepositoryType::REPOSITORY_TYPE_GIT) { return; } if ($repository->isHosted()) { return; } try { // These throw when failing. $this->init($viewer, $repository); $this->findGitHubRepo($repository); } catch (Exception $e) { return; } return $this->createActionView($revision, pht('Land to GitHub'))->setIcon('fa-cloud-upload'); }
/** * Creates and/or cleans a workspace for the requested repo. * * return ArcanistGitAPI */ public static function getCleanGitWorkspace(PhabricatorRepository $repo) { $origin_path = $repo->getLocalPath(); $path = rtrim($origin_path, '/'); $path = $path . '__workspace'; if (!Filesystem::pathExists($path)) { $repo->execxLocalCommand('clone -- file://%s %s', $origin_path, $path); if (!$repo->isHosted()) { id(new ArcanistGitAPI($path))->execxLocal('remote set-url origin %s', $repo->getRemoteURI()); } } $workspace = new ArcanistGitAPI($path); $workspace->execxLocal('clean -f -d'); $workspace->execxLocal('checkout master'); $workspace->execxLocal('fetch'); $workspace->execxLocal('reset --hard origin/master'); $workspace->reloadWorkingCopy(); return $workspace; }
/** * Returns PhabricatorActionView or an array of PhabricatorActionView or null. */ public function createMenuItem(PhabricatorUser $viewer, DifferentialRevision $revision, PhabricatorRepository $repository) { // TODO: This temporarily disables this action, because it doesn't work // and is confusing to users. If you want to use it, comment out this line // for now and we'll provide real support eventually. return; $vcs = $repository->getVersionControlSystem(); if ($vcs !== PhabricatorRepositoryType::REPOSITORY_TYPE_GIT) { return; } if ($repository->isHosted()) { return; } try { // These throw when failing. $this->init($viewer, $repository); $this->findGitHubRepo($repository); } catch (Exception $e) { return; } return $this->createActionView($revision, pht('Land to GitHub'))->setIcon('fa-cloud-upload'); }
private function renderCloneCommand(PhabricatorRepository $repository, $uri, $serve_mode = null, $manage_uri = null) { require_celerity_resource('diffusion-icons-css'); Javelin::initBehavior('select-on-click'); switch ($repository->getVersionControlSystem()) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: $command = csprintf('git clone %R', $uri); break; case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: $command = csprintf('hg clone %R', $uri); break; case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: if ($repository->isHosted()) { $command = csprintf('svn checkout %R %R', $uri, $repository->getCloneName()); } else { $command = csprintf('svn checkout %R', $uri); } break; } $input = javelin_tag('input', array('type' => 'text', 'value' => (string) $command, 'class' => 'diffusion-clone-uri', 'sigil' => 'select-on-click', 'readonly' => 'true')); $extras = array(); if ($serve_mode) { if ($serve_mode === PhabricatorRepository::SERVE_READONLY) { $extras[] = pht('(Read Only)'); } } if ($manage_uri) { if ($this->getRequest()->getUser()->isLoggedIn()) { $extras[] = phutil_tag('a', array('href' => $manage_uri), pht('Manage Credentials')); } } if ($extras) { $extras = phutil_implode_html(' ', $extras); $extras = phutil_tag('div', array('class' => 'diffusion-clone-extras'), $extras); } return array($input, $extras); }
private function buildRepositoryStatus(PhabricatorRepository $repository) { $viewer = $this->getRequest()->getUser(); $is_cluster = $repository->getAlmanacServicePHID(); $view = new PHUIStatusListView(); $messages = id(new PhabricatorRepositoryStatusMessage())->loadAllWhere('repositoryID = %d', $repository->getID()); $messages = mpull($messages, null, 'getStatusType'); if ($repository->isTracked()) { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')->setTarget(pht('Repository Active'))); } else { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'bluegrey')->setTarget(pht('Repository Inactive'))->setNote(pht('Activate this repository to begin or resume import.'))); return $view; } $binaries = array(); $svnlook_check = false; switch ($repository->getVersionControlSystem()) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: $binaries[] = 'git'; break; case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: $binaries[] = 'svn'; break; case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: $binaries[] = 'hg'; break; } if ($repository->isHosted()) { if ($repository->getServeOverHTTP() != PhabricatorRepository::SERVE_OFF) { switch ($repository->getVersionControlSystem()) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: $binaries[] = 'git-http-backend'; break; case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: $binaries[] = 'svnserve'; $binaries[] = 'svnadmin'; $binaries[] = 'svnlook'; $svnlook_check = true; break; case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: $binaries[] = 'hg'; break; } } if ($repository->getServeOverSSH() != PhabricatorRepository::SERVE_OFF) { switch ($repository->getVersionControlSystem()) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: $binaries[] = 'git-receive-pack'; $binaries[] = 'git-upload-pack'; break; case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: $binaries[] = 'svnserve'; $binaries[] = 'svnadmin'; $binaries[] = 'svnlook'; $svnlook_check = true; break; case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: $binaries[] = 'hg'; break; } } } $binaries = array_unique($binaries); if (!$is_cluster) { // We're only checking for binaries if we aren't running with a cluster // configuration. In theory, we could check for binaries on the // repository host machine, but we'd need to make this more complicated // to do that. foreach ($binaries as $binary) { $where = Filesystem::resolveBinary($binary); if (!$where) { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')->setTarget(pht('Missing Binary %s', phutil_tag('tt', array(), $binary)))->setNote(pht("Unable to find this binary in the webserver's PATH. You may " . "need to configure %s.", $this->getEnvConfigLink()))); } else { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')->setTarget(pht('Found Binary %s', phutil_tag('tt', array(), $binary)))->setNote(phutil_tag('tt', array(), $where))); } } // This gets checked generically above. However, for svn commit hooks, we // need this to be in environment.append-paths because subversion strips // PATH. if ($svnlook_check) { $where = Filesystem::resolveBinary('svnlook'); if ($where) { $path = substr($where, 0, strlen($where) - strlen('svnlook')); $dirs = PhabricatorEnv::getEnvConfig('environment.append-paths'); $in_path = false; foreach ($dirs as $dir) { if (Filesystem::isDescendant($path, $dir)) { $in_path = true; break; } } if (!$in_path) { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')->setTarget(pht('Missing Binary %s', phutil_tag('tt', array(), $binary)))->setNote(pht('Unable to find this binary in `%s`. ' . 'You need to configure %s and include %s.', 'environment.append-paths', $this->getEnvConfigLink(), $path))); } } } } $doc_href = PhabricatorEnv::getDocLink('Managing Daemons with phd'); $daemon_instructions = pht('Use %s to start daemons. See %s.', phutil_tag('tt', array(), 'bin/phd start'), phutil_tag('a', array('href' => $doc_href), pht('Managing Daemons with phd'))); $pull_daemon = id(new PhabricatorDaemonLogQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE)->withDaemonClasses(array('PhabricatorRepositoryPullLocalDaemon'))->setLimit(1)->execute(); if ($pull_daemon) { // TODO: In a cluster environment, we need a daemon on this repository's // host, specifically, and we aren't checking for that right now. This // is a reasonable proxy for things being more-or-less correctly set up, // though. $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')->setTarget(pht('Pull Daemon Running'))); } else { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')->setTarget(pht('Pull Daemon Not Running'))->setNote($daemon_instructions)); } $task_daemon = id(new PhabricatorDaemonLogQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE)->withDaemonClasses(array('PhabricatorTaskmasterDaemon'))->setLimit(1)->execute(); if ($task_daemon) { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')->setTarget(pht('Task Daemon Running'))); } else { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')->setTarget(pht('Task Daemon Not Running'))->setNote($daemon_instructions)); } if ($is_cluster) { // Just omit this status check for now in cluster environments. We // could make a service call and pull it from the repository host // eventually. } else { if ($repository->usesLocalWorkingCopy()) { $local_parent = dirname($repository->getLocalPath()); if (Filesystem::pathExists($local_parent)) { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')->setTarget(pht('Storage Directory OK'))->setNote(phutil_tag('tt', array(), $local_parent))); } else { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')->setTarget(pht('No Storage Directory'))->setNote(pht('Storage directory %s does not exist, or is not readable by ' . 'the webserver. Create this directory or make it readable.', phutil_tag('tt', array(), $local_parent)))); return $view; } $local_path = $repository->getLocalPath(); $message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_INIT); if ($message) { switch ($message->getStatusCode()) { case PhabricatorRepositoryStatusMessage::CODE_ERROR: $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')->setTarget(pht('Initialization Error'))->setNote($message->getParameter('message'))); return $view; case PhabricatorRepositoryStatusMessage::CODE_OKAY: if (Filesystem::pathExists($local_path)) { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')->setTarget(pht('Working Copy OK'))->setNote(phutil_tag('tt', array(), $local_path))); } else { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')->setTarget(pht('Working Copy Error'))->setNote(pht('Working copy %s has been deleted, or is not ' . 'readable by the webserver. Make this directory ' . 'readable. If it has been deleted, the daemons should ' . 'restore it automatically.', phutil_tag('tt', array(), $local_path)))); return $view; } break; case PhabricatorRepositoryStatusMessage::CODE_WORKING: $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_CLOCK, 'green')->setTarget(pht('Initializing Working Copy'))->setNote(pht('Daemons are initializing the working copy.'))); return $view; default: $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')->setTarget(pht('Unknown Init Status'))->setNote($message->getStatusCode())); return $view; } } else { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_CLOCK, 'orange')->setTarget(pht('No Working Copy Yet'))->setNote(pht('Waiting for daemons to build a working copy.'))); return $view; } } } $message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_FETCH); if ($message) { switch ($message->getStatusCode()) { case PhabricatorRepositoryStatusMessage::CODE_ERROR: $message = $message->getParameter('message'); $suggestion = null; if (preg_match('/Permission denied \\(publickey\\)./', $message)) { $suggestion = pht('Public Key Error: This error usually indicates that the ' . 'keypair you have configured does not have permission to ' . 'access the repository.'); } $message = phutil_escape_html_newlines($message); if ($suggestion !== null) { $message = array(phutil_tag('strong', array(), $suggestion), phutil_tag('br'), phutil_tag('br'), phutil_tag('em', array(), pht('Raw Error')), phutil_tag('br'), $message); } $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')->setTarget(pht('Update Error'))->setNote($message)); return $view; case PhabricatorRepositoryStatusMessage::CODE_OKAY: $ago = PhabricatorTime::getNow() - $message->getEpoch(); $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')->setTarget(pht('Updates OK'))->setNote(pht('Last updated %s (%s ago).', phabricator_datetime($message->getEpoch(), $viewer), phutil_format_relative_time_detailed($ago)))); break; } } else { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_CLOCK, 'orange')->setTarget(pht('Waiting For Update'))->setNote(pht('Waiting for daemons to read updates.'))); } if ($repository->isImporting()) { $progress = queryfx_all($repository->establishConnection('r'), 'SELECT importStatus, count(*) N FROM %T WHERE repositoryID = %d GROUP BY importStatus', id(new PhabricatorRepositoryCommit())->getTableName(), $repository->getID()); $done = 0; $total = 0; foreach ($progress as $row) { $total += $row['N'] * 4; $status = $row['importStatus']; if ($status & PhabricatorRepositoryCommit::IMPORTED_MESSAGE) { $done += $row['N']; } if ($status & PhabricatorRepositoryCommit::IMPORTED_CHANGE) { $done += $row['N']; } if ($status & PhabricatorRepositoryCommit::IMPORTED_OWNERS) { $done += $row['N']; } if ($status & PhabricatorRepositoryCommit::IMPORTED_HERALD) { $done += $row['N']; } } if ($total) { $percentage = 100 * ($done / $total); } else { $percentage = 0; } // Cap this at "99.99%", because it's confusing to users when the actual // fraction is "99.996%" and it rounds up to "100.00%". if ($percentage > 99.98999999999999) { $percentage = 99.98999999999999; } $percentage = sprintf('%.2f%%', $percentage); $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_CLOCK, 'green')->setTarget(pht('Importing'))->setNote(pht('%s Complete', $percentage))); } else { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')->setTarget(pht('Fully Imported'))); } if (idx($messages, PhabricatorRepositoryStatusMessage::TYPE_NEEDS_UPDATE)) { $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_UP, 'indigo')->setTarget(pht('Prioritized'))->setNote(pht('This repository will be updated soon!'))); } return $view; }
private function getObservedVersion(PhabricatorRepository $repository) { if ($repository->isHosted()) { return null; } if ($repository->isGit()) { return $this->getGitObservedVersion($repository); } return null; }