1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-26 16:52:41 +01:00

Add very basic tag support to Diffusion

Summary: Lists the 25 most recent tags on the "Repository" page.

Test Plan: Looked at a git repository with a tag, saw it. Looked at HG/SVN repos, they didn't break.

Reviewers: davidreuss, 20after4, btrahan, vrana, jungejason

Reviewed By: davidreuss

CC: aran

Maniphest Tasks: T1130

Differential Revision: https://secure.phabricator.com/D2255
This commit is contained in:
epriestley 2012-04-18 08:02:08 -07:00
parent 091248ebe6
commit dec8acd803
20 changed files with 541 additions and 19 deletions

View file

@ -321,6 +321,7 @@ phutil_register_library_map(array(
'DiffusionGitLastModifiedQuery' => 'applications/diffusion/query/lastmodified/git',
'DiffusionGitMergedCommitsQuery' => 'applications/diffusion/query/mergedcommits/git',
'DiffusionGitRequest' => 'applications/diffusion/request/git',
'DiffusionGitTagListQuery' => 'applications/diffusion/query/taglist/git',
'DiffusionHistoryController' => 'applications/diffusion/controller/history',
'DiffusionHistoryQuery' => 'applications/diffusion/query/history/base',
'DiffusionHistoryTableView' => 'applications/diffusion/view/historytable',
@ -338,6 +339,7 @@ phutil_register_library_map(array(
'DiffusionMercurialLastModifiedQuery' => 'applications/diffusion/query/lastmodified/mercurial',
'DiffusionMercurialMergedCommitsQuery' => 'applications/diffusion/query/mergedcommits/mercurial',
'DiffusionMercurialRequest' => 'applications/diffusion/request/mercurial',
'DiffusionMercurialTagListQuery' => 'applications/diffusion/query/taglist/mercurial',
'DiffusionMergedCommitsQuery' => 'applications/diffusion/query/mergedcommits/base',
'DiffusionPathChange' => 'applications/diffusion/data/pathchange',
'DiffusionPathChangeQuery' => 'applications/diffusion/query/pathchange/base',
@ -349,6 +351,7 @@ phutil_register_library_map(array(
'DiffusionQuery' => 'applications/diffusion/query/base',
'DiffusionRepositoryController' => 'applications/diffusion/controller/repository',
'DiffusionRepositoryPath' => 'applications/diffusion/data/repositorypath',
'DiffusionRepositoryTag' => 'applications/diffusion/tag',
'DiffusionRequest' => 'applications/diffusion/request/base',
'DiffusionSvnBrowseQuery' => 'applications/diffusion/query/browse/svn',
'DiffusionSvnCommitParentsQuery' => 'applications/diffusion/query/parents/svn',
@ -359,8 +362,11 @@ phutil_register_library_map(array(
'DiffusionSvnLastModifiedQuery' => 'applications/diffusion/query/lastmodified/svn',
'DiffusionSvnMergedCommitsQuery' => 'applications/diffusion/query/mergedcommits/svn',
'DiffusionSvnRequest' => 'applications/diffusion/request/svn',
'DiffusionSvnTagListQuery' => 'applications/diffusion/query/taglist/svn',
'DiffusionSymbolController' => 'applications/diffusion/controller/symbol',
'DiffusionSymbolQuery' => 'applications/diffusion/query/symbol',
'DiffusionTagListQuery' => 'applications/diffusion/query/taglist/base',
'DiffusionTagListView' => 'applications/diffusion/view/taglist',
'DiffusionURITestCase' => 'applications/diffusion/request/base/__tests__',
'DiffusionView' => 'applications/diffusion/view/base',
'DrydockAllocator' => 'applications/drydock/allocator/resource',
@ -1273,6 +1279,7 @@ phutil_register_library_map(array(
'DiffusionGitLastModifiedQuery' => 'DiffusionLastModifiedQuery',
'DiffusionGitMergedCommitsQuery' => 'DiffusionMergedCommitsQuery',
'DiffusionGitRequest' => 'DiffusionRequest',
'DiffusionGitTagListQuery' => 'DiffusionTagListQuery',
'DiffusionHistoryController' => 'DiffusionController',
'DiffusionHistoryQuery' => 'DiffusionQuery',
'DiffusionHistoryTableView' => 'DiffusionView',
@ -1290,6 +1297,7 @@ phutil_register_library_map(array(
'DiffusionMercurialLastModifiedQuery' => 'DiffusionLastModifiedQuery',
'DiffusionMercurialMergedCommitsQuery' => 'DiffusionMergedCommitsQuery',
'DiffusionMercurialRequest' => 'DiffusionRequest',
'DiffusionMercurialTagListQuery' => 'DiffusionTagListQuery',
'DiffusionMergedCommitsQuery' => 'DiffusionQuery',
'DiffusionPathCompleteController' => 'DiffusionController',
'DiffusionPathQueryTestCase' => 'PhabricatorTestCase',
@ -1304,7 +1312,10 @@ phutil_register_library_map(array(
'DiffusionSvnLastModifiedQuery' => 'DiffusionLastModifiedQuery',
'DiffusionSvnMergedCommitsQuery' => 'DiffusionMergedCommitsQuery',
'DiffusionSvnRequest' => 'DiffusionRequest',
'DiffusionSvnTagListQuery' => 'DiffusionTagListQuery',
'DiffusionSymbolController' => 'DiffusionController',
'DiffusionTagListQuery' => 'DiffusionQuery',
'DiffusionTagListView' => 'DiffusionView',
'DiffusionURITestCase' => 'ArcanistPhutilTestCase',
'DiffusionView' => 'AphrontView',
'DrydockAllocatorWorker' => 'PhabricatorWorker',

View file

@ -93,6 +93,8 @@ final class DiffusionRepositoryController extends DiffusionController {
$content[] = $browse_panel;
$content[] = $this->buildTagListTable($drequest);
if ($drequest->getBranch() !== null) {
$branch_query = DiffusionBranchQuery::newFromDiffusionRequest($drequest);
$branches = $branch_query->loadBranches();
@ -152,4 +154,37 @@ final class DiffusionRepositoryController extends DiffusionController {
return $panel;
}
private function buildTagListTable(DiffusionRequest $drequest) {
$query = DiffusionTagListQuery::newFromDiffusionRequest($drequest);
$query->setLimit(25);
$tags = $query->loadTags();
if (!$tags) {
return null;
}
$commits = id(new PhabricatorAuditCommitQuery())
->withIdentifiers(
$drequest->getRepository()->getID(),
mpull($tags, 'getCommitIdentifier'))
->needCommitData(true)
->execute();
$view = new DiffusionTagListView();
$view->setDiffusionRequest($drequest);
$view->setTags($tags);
$view->setUser($this->getRequest()->getUser());
$view->setCommits($commits);
$phids = $view->getRequiredHandlePHIDs();
$handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
$view->setHandles($handles);
$panel = new AphrontPanelView();
$panel->setHeader('Tags');
$panel->appendChild($view);
return $panel;
}
}

View file

@ -6,13 +6,16 @@
phutil_require_module('phabricator', 'applications/audit/query/commit');
phutil_require_module('phabricator', 'applications/diffusion/controller/base');
phutil_require_module('phabricator', 'applications/diffusion/query/branch/base');
phutil_require_module('phabricator', 'applications/diffusion/query/browse/base');
phutil_require_module('phabricator', 'applications/diffusion/query/history/base');
phutil_require_module('phabricator', 'applications/diffusion/query/taglist/base');
phutil_require_module('phabricator', 'applications/diffusion/view/branchtable');
phutil_require_module('phabricator', 'applications/diffusion/view/browsetable');
phutil_require_module('phabricator', 'applications/diffusion/view/historytable');
phutil_require_module('phabricator', 'applications/diffusion/view/taglist');
phutil_require_module('phabricator', 'applications/phid/handle/data');
phutil_require_module('phabricator', 'applications/repository/constants/repositorytype');
phutil_require_module('phabricator', 'view/control/table');

View file

@ -0,0 +1,41 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
abstract class DiffusionTagListQuery extends DiffusionQuery {
private $limit;
public function setLimit($limit) {
$this->limit = $limit;
return $this;
}
protected function getLimit() {
return $this->limit;
}
final public static function newFromDiffusionRequest(
DiffusionRequest $request) {
return self::newQueryObject(__CLASS__, $request);
}
final public function loadTags() {
return $this->executeQuery();
}
}

View file

@ -0,0 +1,12 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'applications/diffusion/query/base');
phutil_require_source('DiffusionTagListQuery.php');

View file

@ -0,0 +1,73 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
final class DiffusionGitTagListQuery extends DiffusionTagListQuery {
protected function executeQuery() {
$drequest = $this->getRequest();
$repository = $drequest->getRepository();
$limit = $this->getLimit();
list($stdout) = $repository->execxLocalCommand(
'for-each-ref %C --sort=-creatordate --format=%s refs/tags',
$limit ? '--count='.(int)$limit : null,
'%(objectname) %(objecttype) %(refname) %(*objectname) %(*objecttype) '.
'%(subject)%01%(creator)'
);
$stdout = trim($stdout);
if (!strlen($stdout)) {
return array();
}
$tags = array();
foreach (explode("\n", $stdout) as $line) {
list($info, $creator) = explode("\1", $line);
list(
$objectname,
$objecttype,
$refname,
$refobjectname,
$refobjecttype,
$description) = explode(' ', $info, 6);
$matches = null;
if (!preg_match('/^(.*) ([0-9]+) ([0-9+-]+)$/', $creator, $matches)) {
throw new Exception(
"Unparseable output from 'git for-each-ref': {$line}");
}
$author = $matches[1];
$epoch = $matches[2];
$tag = new DiffusionRepositoryTag();
$tag->setAuthor($author);
$tag->setEpoch($epoch);
$tag->setCommitIdentifier(nonempty($refobjectname, $objectname));
$tag->setName(preg_replace('@^refs/tags/@', '', $refname));
$tag->setDescription($description);
$tag->setType('git/'.$objecttype);
$tags[] = $tag;
}
return $tags;
}
}

View file

@ -0,0 +1,15 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'applications/diffusion/query/taglist/base');
phutil_require_module('phabricator', 'applications/diffusion/tag');
phutil_require_module('phutil', 'utils');
phutil_require_source('DiffusionGitTagListQuery.php');

View file

@ -0,0 +1,26 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
final class DiffusionMercurialTagListQuery extends DiffusionTagListQuery {
protected function executeQuery() {
// TODO: Implement this for Mercurial.
return array();
}
}

View file

@ -0,0 +1,12 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'applications/diffusion/query/taglist/base');
phutil_require_source('DiffusionMercurialTagListQuery.php');

View file

@ -0,0 +1,26 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
final class DiffusionSvnTagListQuery extends DiffusionTagListQuery {
protected function executeQuery() {
// Nothing meaningful to be done in Subversion.
return array();
}
}

View file

@ -0,0 +1,12 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'applications/diffusion/query/taglist/base');
phutil_require_source('DiffusionSvnTagListQuery.php');

View file

@ -0,0 +1,82 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
final class DiffusionRepositoryTag {
private $author;
private $epoch;
private $commitIdentifier;
private $name;
private $description;
private $type;
public function setType($type) {
$this->type = $type;
return $this;
}
public function getType() {
return $this->type;
}
public function setDescription($description) {
$this->description = $description;
return $this;
}
public function getDescription() {
return $this->description;
}
public function setName($name) {
$this->name = $name;
return $this;
}
public function getName() {
return $this->name;
}
public function setCommitIdentifier($commit_identifier) {
$this->commitIdentifier = $commit_identifier;
return $this;
}
public function getCommitIdentifier() {
return $this->commitIdentifier;
}
public function setEpoch($epoch) {
$this->epoch = $epoch;
return $this;
}
public function getEpoch() {
return $this->epoch;
}
public function setAuthor($author) {
$this->author = $author;
return $this;
}
public function getAuthor() {
return $this->author;
}
}

View file

@ -0,0 +1,10 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_source('DiffusionRepositoryTag.php');

View file

@ -39,7 +39,7 @@ final class DiffusionBranchTableView extends DiffusionView {
array(
'href' => $drequest->generateURI(
array(
'action' => 'branch',
'action' => 'browse',
'branch' => $branch->getName(),
)),
),
@ -64,6 +64,7 @@ final class DiffusionBranchTableView extends DiffusionView {
));
$view->setColumnClasses(
array(
'pri',
'wide',
));
$view->setRowClasses($rowc);

View file

@ -0,0 +1,134 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
final class DiffusionTagListView extends DiffusionView {
private $tags;
private $user;
private $commits = array();
private $handles = array();
public function setUser($user) {
$this->user = $user;
return $this;
}
public function setTags($tags) {
$this->tags = $tags;
return $this;
}
public function setCommits(array $commits) {
$this->commits = mpull($commits, null, 'getCommitIdentifier');
return $this;
}
public function setHandles(array $handles) {
$this->handles = $handles;
return $this;
}
public function getRequiredHandlePHIDs() {
return array_filter(mpull($this->commits, 'getAuthorPHID'));
}
public function render() {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$rows = array();
foreach ($this->tags as $tag) {
$commit = idx($this->commits, $tag->getCommitIdentifier());
$tag_link = phutil_render_tag(
'a',
array(
'href' => $drequest->generateURI(
array(
'action' => 'browse',
'commit' => $tag->getCommitIdentifier(),
)),
),
phutil_escape_html($tag->getName()));
$commit_link = phutil_render_tag(
'a',
array(
'href' => $drequest->generateURI(
array(
'action' => 'commit',
'commit' => $tag->getCommitIdentifier(),
)),
),
phutil_escape_html(
$repository->formatCommitName(
$tag->getCommitIdentifier())));
$author = null;
if ($commit && $commit->getAuthorPHID()) {
$author = $this->handles[$commit->getAuthorPHID()]->renderLink();
} else if ($commit && $commit->getCommitData()) {
$author = phutil_escape_html($commit->getCommitData()->getAuthorName());
} else {
$author = phutil_escape_html($tag->getAuthor());
}
$description = null;
if ($tag->getType() == 'git/tag') {
// In Git, a tag may be a "real" tag, or just a reference to a commit.
// If it's a real tag, use the message on the tag, since this may be
// unique data which isn't otherwise available.
$description = $tag->getDescription();
} else {
if ($commit && $commit->getCommitData()) {
$description = $commit->getCommitData()->getSummary();
} else {
$description = $tag->getDescription();
}
}
$description = phutil_escape_html($description);
$rows[] = array(
$tag_link,
$commit_link,
$description,
$author,
phabricator_datetime($tag->getEpoch(), $this->user),
);
}
$table = new AphrontTableView($rows);
$table->setHeaders(
array(
'Tag',
'Commit',
'Description',
'Author',
'Created',
));
$table->setColumnClasses(
array(
'pri',
'',
'wide',
));
return $table->render();
}
}

View file

@ -0,0 +1,17 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'applications/diffusion/view/base');
phutil_require_module('phabricator', 'view/control/table');
phutil_require_module('phabricator', 'view/utils');
phutil_require_module('phutil', 'markup');
phutil_require_module('phutil', 'utils');
phutil_require_source('DiffusionTagListView.php');

View file

@ -265,22 +265,9 @@ final class PhabricatorObjectHandleData {
// In case where the repository for the commit was deleted,
// we don't have have info about the repository anymore.
if ($repository) {
$vcs = $repository->getVersionControlSystem();
$type_git = PhabricatorRepositoryType::REPOSITORY_TYPE_GIT;
$type_hg = PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL;
$is_git = ($vcs == $type_git);
$is_hg = ($vcs == $type_hg);
if ($is_git || $is_hg) {
$short_identifier = substr($commit_identifier, 0, 12);
} else {
$short_identifier = $commit_identifier;
}
$handle->setName('r'.$callsign.$short_identifier);
$name = $repository->formatCommitName($commit_identifier);
$handle->setName($name);
} else {
$handle->setName('Commit '.'r'.$callsign.$commit_identifier);
}

View file

@ -16,7 +16,6 @@ phutil_require_module('phabricator', 'applications/phid/handle');
phutil_require_module('phabricator', 'applications/phid/handle/const/status');
phutil_require_module('phabricator', 'applications/phid/utils');
phutil_require_module('phabricator', 'applications/phriction/storage/document');
phutil_require_module('phabricator', 'applications/repository/constants/repositorytype');
phutil_require_module('phabricator', 'applications/repository/storage/repository');
phutil_require_module('phabricator', 'infrastructure/env');
phutil_require_module('phabricator', 'storage/queryfx');

View file

@ -358,4 +358,21 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO {
return true;
}
public function formatCommitName($commit_identifier) {
$vcs = $this->getVersionControlSystem();
$type_git = PhabricatorRepositoryType::REPOSITORY_TYPE_GIT;
$type_hg = PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL;
$is_git = ($vcs == $type_git);
$is_hg = ($vcs == $type_hg);
if ($is_git || $is_hg) {
$short_identifier = substr($commit_identifier, 0, 12);
} else {
$short_identifier = $commit_identifier;
}
return 'r'.$this->getCallsign().$short_identifier;
}
}

View file

@ -57,7 +57,7 @@ function phabricator_time($epoch, $user) {
'g:i A');
}
function phabricator_datetime($epoch, $user) {
function phabricator_datetime($epoch, $user) {
return phabricator_format_local_time(
$epoch,
$user,
@ -103,7 +103,16 @@ function phabricator_format_local_time($epoch, $user, $format) {
// constructor, it ignores it if the date string includes timezone
// information. Further, it treats epoch timestamps ("@946684800") as having
// a UTC timezone. Set the timezone explicitly after constructing the object.
$date = new DateTime('@'.$epoch);
try {
$date = new DateTime('@'.$epoch);
} catch (Exception $ex) {
// NOTE: DateTime throws an empty exception if the format is invalid,
// just replace it with a useful one.
throw new Exception(
"Construction of a DateTime() with epoch '{$epoch}' ".
"raised an exception.");
}
$date->setTimeZone($zone);
return $date->format($format);