Page MenuHomeDevCentral

No OneTemporary

diff --git a/app/Analyzers/PhabricatorGroupMapping.php b/app/Analyzers/PhabricatorGroupMapping.php
index 1765fb7..01e5e41 100644
--- a/app/Analyzers/PhabricatorGroupMapping.php
+++ b/app/Analyzers/PhabricatorGroupMapping.php
@@ -1,76 +1,76 @@
<?php
namespace Nasqueron\Notifications\Analyzers;
use Nasqueron\Notifications\Phabricator\PhabricatorStory;
class PhabricatorGroupMapping {
///
/// Properties
///
/**
* The group the mapped projects belong to
*
* @var string
*/
public $group;
/**
* An array of the projects, each item a string with the name of the
* project. The wildcard '*' is allowed to specify several projects.
*
* @var array
*/
public $projects;
/**
* An array of words, each item a string with a word to find in the story.
*
* @var array
*/
- public $words;
+ public $words = [];
///
/// Helper methods
///
/**
* Determines if the specified project matches a pattern
*
* @param string $pattern The pattern, with * allowed as wildcard character
* @param string $project The project name to compare with the pattern
* @return bool
*/
public static function doesProjectMatch ($pattern, $project) {
return str_is($pattern, $project);
}
/**
* Determines if the specified project belong to this mapping
*
* @return bool
*/
public function doesProjectBelong ($actualProject) {
foreach ($this->projects as $candidateProject) {
if (static::doesProjectMatch($candidateProject, $actualProject)) {
return true;
}
}
return false;
}
/**
* Determines if the specified story belong to this mapping
*
* @return bool
*/
public function doesStoryBelong (PhabricatorStory $story) {
foreach ($this->words as $word) {
if (strpos($story->text, $word) !== false) {
return true;
}
}
return false;
}
}
diff --git a/app/Analyzers/PhabricatorPayloadAnalyzer.php b/app/Analyzers/PhabricatorPayloadAnalyzer.php
index ed5ec6d..ba673ac 100644
--- a/app/Analyzers/PhabricatorPayloadAnalyzer.php
+++ b/app/Analyzers/PhabricatorPayloadAnalyzer.php
@@ -1,300 +1,300 @@
<?php
namespace Nasqueron\Notifications\Analyzers;
use Nasqueron\Notifications\Phabricator\PhabricatorStory;
use Config;
class PhabricatorPayloadAnalyzer {
///
/// Private members
///
/**
* The project name, used to load specific configuration and offer defaults
* @var string
*/
private $project;
/**
* The story
* @var PhabricatorStory
*/
private $story;
/**
* The projects associated to this story
* @var string[]
*/
private $projects;
/**
* The configuration for the payload analyzer
* @var PhabricatorPayloadAnalyzerConfiguration;
*/
private $configuration;
///
/// Constructor
///
/**
* Creates a new GitHubPayloadAnalyzer instance.
*
* @param string $project
* @param string $event
* @param stdClass $payload
*/
public function __construct($project, PhabricatorStory $story, $projects) {
$this->project = $project;
$this->story = $story;
$this->projects = $projects;
$this->loadConfiguration($project);
}
///
/// Configuration
///
const CONFIG_DEFAULT_FILE = 'default.json';
public function getConfigurationFileName () {
$dir = Config::get('services.phabricator.analyzer.configDir');
$filename = $dir . '/' . $this->project . '.json';
if (!file_exists($filename)) {
return $dir . '/' . static::CONFIG_DEFAULT_FILE;
}
return $filename;
}
public function loadConfiguration () {
$fileName = $this->getConfigurationFileName();
$mapper = new \JsonMapper();
$this->configuration = $mapper->map(
json_decode(file_get_contents($fileName)),
new PhabricatorPayloadAnalyzerConfiguration()
);
}
///
/// Qualification of the story
///
public function isAdministrativeEvent () {
//TODO: determine events who qualify as administrative
return false;
}
/**
* Gets the group for a specific story
*
* @return string the group, central part of the routing key
*/
public function getGroup () {
// Some events are organization-level only and can't be mapped
// to projects.
if ($this->isAdministrativeEvent()) {
return $this->configuration->administrativeGroup;
}
// If the payload is about some repository matching a table of
// symbols, we need to sort it to the right group.
foreach ($this->configuration->groupsMapping as $mapping) {
foreach ($this->projects as $project) {
if ($mapping->doesProjectBelong($project)) {
return $mapping->group;
}
}
}
// Words
foreach ($this->configuration->groupsMapping as $mapping) {
- if ($mapping->doesStoryBelong($story)) {
+ if ($mapping->doesStoryBelong($this->story)) {
return $mapping->group;
}
}
// By default, fallback group is the project name or a specified value.
if (empty($this->configuration->defaultGroup)) {
return strtolower($this->project);
}
return $this->configuration->defaultGroup;
}
///
/// Description of the payload
///
/**
* Gets repository and branch information
*
* @return string
*/
public function getWhere () {
$repo = $this->payload->repository->name;
$branch = $this->payload->ref;
return static::getRepositoryAndBranch($repo, $branch);
}
/**
* Gets a repository and branch information string
*
* @param string $repo The repository
* @param string $branch The branch
* @return string "<repo>" or "<repo> (branch <branch>)" when branch isn't master
*/
public static function getRepositoryAndBranch ($repo = "", $branch = "") {
if ($repo === "") {
return "";
}
if (starts_with($branch, "refs/heads/")) {
$branch = substr($branch, 11);
}
if ($branch === "" || $branch === "master") {
return $repo;
}
return "$repo (branch $branch)";
}
/**
* Gets the title of the head commit
*
* @return string
*/
private function getHeadCommitTitle () {
return static::getCommitTitle($this->payload->head_commit->message);
}
/**
* Extracts the commit title from the whole commit message.
*
* @param string $message The commit message
* @return string The commit title
*/
public static function getCommitTitle ($message) {
// Discards extra lines
$pos = strpos($message, "\n");
if ($pos > 0) {
$message = substr($message, 0, $pos);
}
// Short messages are returned as is
$len = strlen($message);
if ($len <= 72) {
return $message;
}
// Longer messages are truncated
return substr($message, 0, 71) . '…';
}
/**
* Gets the description text for the head commit.
*
* @return string
*/
private function getHeadCommitDescription () {
$commit = $this->payload->head_commit;
$title = $this->getHeadCommitTitle();
$committer = $commit->committer->username;
$author = $commit->author->username;
$message = "$committer committed $title";
if ($committer !== $author) {
$message .= " (authored by $author)";
}
return $message;
}
/**
* Gets a short textual description of the event
*
* @return string
*/
public function getDescription () {
switch ($this->event) {
case "create":
$repository = $this->payload->repository->full_name;
$type = $this->payload->ref_type;
$ref = $this->payload->ref;
if ($type == "tag" || $type == "branch") {
return "New $type on $repository: $ref";
}
return "Unknown create: $type $ref";
case "ping":
$quote = $this->payload->zen;
return "« $quote » — GitHub Webhooks ping zen aphorism.";
case "push":
$n = count($this->payload->commits);
if ($n == 1) {
return $this->getHeadCommitDescription();
}
$repoAndBranch = $this->getWhere();
$user = $this->payload->pusher->name;
return "$user pushed $n commits to $repoAndBranch";
case "repository":
$repository = $this->payload->repository->full_name;
$message = "New repository $repository";
if ($this->payload->repository->fork) {
$message .= " (fork)";
}
if ($description = $this->payload->repository->description) {
$message .= " — $description";
}
return $message;
default:
return "Some $this->event happened";
}
}
/**
* Gets a link to view the event on GitHub
*
* @return string The most relevant URL
*/
public function getLink () {
switch ($this->event) {
case "create":
$type = $this->payload->ref_type;
$ref = $this->payload->ref;
$url = $this->payload->repository->html_url;
if ($type == "tag") {
$url .= "/releases/tag/" . $ref;
} elseif ($type == "branch") {
$url .= "/tree/" . $ref;
}
return $url;
case "push":
$n = count($this->payload->commits);
if ($n == 1) {
return $this->payload->head_commit->url;
}
return $this->payload->compare;
case "repository":
return $this->payload->repository->html_url;
default:
return "";
}
}
}
diff --git a/app/Phabricator/PhabricatorStory.php b/app/Phabricator/PhabricatorStory.php
index ebb18d8..0d91dbd 100644
--- a/app/Phabricator/PhabricatorStory.php
+++ b/app/Phabricator/PhabricatorStory.php
@@ -1,186 +1,193 @@
<?php
namespace Nasqueron\Notifications\Phabricator;
class PhabricatorStory {
///
/// Properties
///
/**
* The Phabricator main URL
*
* @var string
*/
public $instance;
/**
* @var int
*/
public $id;
/**
* Type of story (e.g. PhabricatorApplicationTransactionFeedStory)
*
* @var string
*/
public $type;
/**
* @var Array
*/
public $data;
/**
* The person logged to Phabricator and triggering the event
*
* @var string
*/
public $authorPHID;
/**
* A short English textual description of the event
*
* @var string
*/
public $text;
/**
* The time the event occured
*
* @var int
*/
public $epoch;
///
/// Constructors
///
/**
* Initializes a new instance of the Phabricator story class
*
* @param string $instance The Phabricator main URL, without trailing slash
*/
public function __construct ($instance) {
$this->instance = $instance;
}
/**
* Initializes a new instance of PhabricatorStory from an array.
*
* This is intended to parse the feed.hooks payloads.
*
* @param string $phabricatorURL The Phabricator URL (e.g. http://secure.phabricator.com)
* @param string $payload The data submitted by Phabricator
* @return PhabricatorStory
*/
public static function loadFromArray ($phabricatorURL, $payload) {
$instance = new self($phabricatorURL);
foreach ($payload as $key => $value) {
$property = self::mapPhabricatorFeedKey($key);
$instance->$property = $value;
}
return $instance;
}
///
/// Helper methods
///
/**
* Gets object type (e.g. TASK for PHID-TASK-l34fw5wievp6n6rnvpuk)
*
* @return string The object type, as a 4 letters string (e.g. 'TASK')
*/
public function getObjectType () {
return substr($this->data['objectPHID'], 5, 4);
}
public function getProjectsPHIDs () {
$objectPHID = $this->data['objectPHID'];
$objectType = $this->getObjectType();
switch ($objectType) {
case 'DREV':
return $this->getItemProjectsPHIDs(
'repository.query',
$this->getRepositoryPHID('differential.query')
);
break;
case 'TASK':
return $this->getItemProjectsPHIDs(
'maniphest.query',
$objectPHID
);
case 'CMIT':
// TODO: call API, return projects PHIDs
return $this->getItemProjectsPHIDs(
'repository.query',
$this->getRepositoryPHID('diffusion.querycommits')
);
break;
default:
return [];
}
}
public function getRepositoryPHID ($method) {
$objectPHID = $this->data['objectPHID'];
$api = PhabricatorAPI::forInstance($this->instance);
$reply = $api->call(
$method,
[ 'phids[0]' => $objectPHID ]
);
+ if (!count($reply) || !property_exists($reply, $objectPHID)) {
+ return "";
+ }
return $reply->$objectPHID->repositoryPHID;
}
public function getItemProjectsPHIDs ($method, $objectPHID) {
+ if (!$objectPHID) {
+ return [];
+ }
+
$api = PhabricatorAPI::forInstance($this->instance);
$reply = $api->call(
$method,
[ 'phids[0]' => $objectPHID ]
);
return $reply->$objectPHID->projectPHIDs;
}
public function getProjects () {
$PHIDs = $this->getProjectsPHIDs();
if (count($PHIDs) == 0) {
// No project is attached to the story's object
return [];
}
$projects = [];
$map = ProjectsMap::load($this->instance);
foreach ($PHIDs as $PHID) {
$projects[] = $map->getProjectName($PHID);
}
return $projects;
}
///
/// Static helper methods
///
public static function mapPhabricatorFeedKey ($key) {
if ($key == "storyID") {
return "id";
}
if (starts_with($key, "story")) {
$key = substr($key, 5);
$key[0] = strtolower($key[0]); // lowercase
}
return $key;
}
}

File Metadata

Mime Type
text/x-diff
Expires
Mon, Nov 25, 18:45 (11 h, 48 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2260633
Default Alt Text
(15 KB)

Event Timeline