Initial port from my network

This commit is contained in:
Graham Christensen 2017-10-29 17:10:26 -04:00
commit 0c7b2f252e
No known key found for this signature in database
GPG key ID: ACA1C1D120C83D5C
16 changed files with 3461 additions and 0 deletions

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
config.php
vendor
*.log
test.php

57
README.md Normal file
View file

@ -0,0 +1,57 @@
# grahamcofborg
1. All github events go in to web/index.php, which sends the event to
an exchange named for the full name of the repo (ex: nixos/nixpkgs)
in lower case. The exchange is set to "fanout"
2. build-filter.php creates a queue called build-inputs and binds it
to the nixos/nixpkgs exchange. It also creates an exchange,
build-jobs, set to fan out. It listens for messages on the
build-inputs queue. Issue comments from authorized users on
PRs get tokenized and turned in to build instructions. These jobs
are then written to the build-jobs exchange.
3. builder.php creates a queue called `build-inputs-x86_64-linux`, and
binds it to the build-jobs exchange. It then listens for build
instructions on the `build-inputs-x86_64-linux` queue. For each
job, it uses nix-build to run the build instructions. The status
result (pass/fail) and the last ten lines of output are then placed
in to the `build-results` queue.
4. poster.php declares the build-results queue, and listens for
messages on it. It posts the build status and text output on the PR
the build is from.
The conspicuously missing config.php looks like:
```php
<?php
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPSSLConnection;
use PhpAmqpLib\Message\AMQPMessage;
function rabbitmq_conn() {
$connection = new AMQPSSLConnection(
'events.nix.gsc.io', 5671,
eventsuser, eventspasswordd, '/', array(
'verify_peer' => true,
'verify_peer_name' => true,
'peer_name' => 'events.nix.gsc.io',
'verify_depth' => 10,
'ca_file' => '/etc/ssl/certs/ca-certificates.crt'
)
);
return $connection;
}
function gh_client() {
$client = new \Github\Client();
$client->authenticate('githubusername',
'githubpassword',
Github\Client::AUTH_HTTP_PASSWORD);
return $client;
}
```

118
build-filter.php Normal file
View file

@ -0,0 +1,118 @@
<?php
require __DIR__ . '/config.php';
use PhpAmqpLib\Message\AMQPMessage;
# define('AMQP_DEBUG', true);
$connection = rabbitmq_conn();
$channel = $connection->channel();
$channel->basic_qos(null, 1, true);
$channel->exchange_declare('build-jobs', 'fanout', false, true, false);
list($queueName, , ) = $channel->queue_declare('build-inputs',
false, true, false, false);
$channel->queue_bind($queueName, 'nixos/nixpkgs');
$channel->queue_bind($queueName, 'grahamc/elm-stuff');
function runner($msg) {
$in = json_decode($msg->body);
try {
$etype = \GHE\EventClassifier::classifyEvent($in);
if ($etype != "issue_comment") {
echo "Skipping event type: $etype\n";
return true;
}
} catch (\GHE\EventClassifierUnknownException $e) {
echo "Skipping unknown event type\n";
print_r($in);
return true;
}
if (!\GHE\ACL::isUserAuthorized($in->comment->user->login)) {
echo "Commenter not authorized (" . $in->comment->user->login . ")\n";
return true;
}
if (!\GHE\ACL::isRepoEligible($in->repository->full_name)) {
echo "Repo not authorized (" . $in->repository->full_name . ")\n";
return true;
}
if (!isset($in->issue->pull_request)) {
echo "not a PR\n";
return true;
}
# // We don't get a useful pull_request here, we'd have to fetch it
# to know if it is open
#if ($in->issue->pull_request->state != "open") {
# var_dump($in->issue->pull_request);
# echo "PR isn't open\n";
# return true;
# }
$cmt = explode(' ', strtolower($in->comment->body));
if (!in_array('@grahamcofborg', $cmt)) {
echo "not a borgpr\n";
return true;
}
$cmt = explode(' ', $in->comment->body);
$tokens = array_map(function($term) { return trim($term); },
array_filter($cmt,
function($term) {
return !in_array(strtolower($term), [
"@grahamcofborg",
"",
]);
}
)
);
if (count($tokens) == 1 && implode("", $tokens) == "default") {
echo "default support is blocked\n";
return true;
$forward = [
'payload' => $in,
'build_default' => true,
'attrs' => [],
];
} else {
$forward = [
'payload' => $in,
'build_default' => false,
'attrs' => $tokens,
];
}
echo "forwarding to build-jobs :)\n";
$message = new AMQPMessage(json_encode($forward),
array('content_type' => 'application/json'));
$msg->delivery_info['channel']->basic_publish($message, 'build-jobs');
return true;
}
function outrunner($msg) {
try {
if (runner($msg) === true) {
$msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
}
} catch (\GHE\ExecException $e) {
var_dump($e->getMessage());
var_dump($e->getCode());
var_dump($e->getOutput());
}
}
$consumerTag = 'consumer' . getmypid();
$channel->basic_consume($queueName, $consumerTag, false, false, false, false, 'outrunner');
while(count($channel->callbacks)) {
$channel->wait();
}

107
builder.php Normal file
View file

@ -0,0 +1,107 @@
<?php
require __DIR__ . '/config.php';
use PhpAmqpLib\Message\AMQPMessage;
# define('AMQP_DEBUG', true);
$connection = rabbitmq_conn();
$channel = $connection->channel();
$channel->basic_qos(null, 1, true);
list($queueName, , ) = $channel->queue_declare('build-results',
false, true, false, false);
list($queueName, , ) = $channel->queue_declare('build-inputs-x86_64-linux',
false, true, false, false);
$channel->queue_bind($queueName, 'build-jobs');
function runner($msg) {
echo "got a job!\n";
$body = json_decode($msg->body);
$in = $body->payload;
$co = new GHE\Checkout("/home/grahamc/.nix-test", "builder");
$pname = $co->checkOutRef($in->repository->full_name,
$in->repository->clone_url,
$in->issue->number,
"origin/master"
);
$patch_url = $in->issue->pull_request->patch_url;
echo "Building $patch_url\n";
$co->applyPatches($pname, $patch_url);
if ($body->build_default) {
echo "building via nix-build .\n";
$cmd = 'NIX_PATH=nixpkgs=%s nix-build --option restrict-eval true --keep-going .';
$args = [$pname];
} else {
echo "building via nix-build . -A\n";
$attrs = array_intersperse(array_values((array)$body->attrs), '-A');
var_dump($attrs);
$fillers = implode(" ", array_fill(0, count($attrs), '%s'));
$cmd = 'NIX_PATH=nixpkgs=%s nix-build --option restrict-eval true --keep-going . ' . $fillers;
$args = $attrs;
array_unshift($args, $pname);
}
try {
$output = GHE\Exec::exec($cmd, $args);
$pass = true;
} catch (GHE\ExecException $e) {
$output = $e->getOutput();
$pass = false;
}
$lastlines = array_reverse(
array_slice(
array_reverse($output),
0, 10
)
);
$forward = [
'payload' => $in,
'output' => $lastlines,
'success' => $pass,
];
$message = new AMQPMessage(json_encode($forward),
array('content_type' => 'application/json'));
$msg->delivery_info['channel']->basic_publish($message, '', 'build-results');
$msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
echo "finished\n";
}
function array_intersperse($array, $val) {
return array_reduce($array,
function($c, $elem) use ($val) {
$c[] = $val;
$c[] = $elem;
return $c;
},
array());
}
function outrunner($msg) {
try {
return runner($msg);
} catch (ExecException $e) {
var_dump($e->getMessage());
var_dump($e->getCode());
var_dump($e->getOutput());
}
}
$consumerTag = 'consumer' . getmypid();
$channel->basic_consume($queueName, $consumerTag, false, false, false, false, 'outrunner');
while(count($channel->callbacks)) {
$channel->wait();
}

14
composer.json Normal file
View file

@ -0,0 +1,14 @@
{
"require": {
"php-amqplib/php-amqplib": ">=2.6.1",
"knplabs/github-api": "^2.6@dev",
"php-http/guzzle6-adapter": "^1.2@dev"
},
"minimum-stability": "dev",
"autoload": {
"psr-4": {"GHE\\": "src/"}
},
"require-dev": {
"phpunit/phpunit": "^6.4"
}
}

2461
composer.lock generated Normal file

File diff suppressed because it is too large Load diff

191
mass-rebuilder.php Normal file
View file

@ -0,0 +1,191 @@
<?php
require __DIR__ . '/config.php';
use PhpAmqpLib\Message\AMQPMessage;
# define('AMQP_DEBUG', true);
$connection = rabbitmq_conn();
$channel = $connection->channel();
$channel->basic_qos(null, 1, true);
list($queueName, , ) = $channel->queue_declare('mass-rebuild-checks',
false, true, false, false);
$channel->queue_bind($queueName, 'nixos/nixpkgs');
echo "hi\n";
function outrunner($msg) {
try {
$ret = runner($msg);
var_dump($ret);
if ($ret === true) {
echo "cool\n";
echo "acking\n";
$r = $msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
var_dump($r);
echo "acked\n";
} else {
echo "Not acking?\n";
}
} catch (\GHE\ExecException $e) {
var_dump($msg);
var_dump($e->getMessage());
var_dump($e->getCode());
var_dump($e->getOutput());
}
}
function runner($msg) {
$in = json_decode($msg->body);
try {
$etype = \GHE\EventClassifier::classifyEvent($in);
if ($etype != "pull_request") {
echo "Skipping event type: $etype\n";
return true;
}
} catch (\GHE\EventClassifierUnknownException $e) {
echo "Skipping unknown event type\n";
print_r($in);
return true;
}
if (!\GHE\ACL::isRepoEligible($in->repository->full_name)) {
echo "Repo not authorized (" . $in->repository->full_name . ")\n";
return true;
}
if ($in->pull_request->state != "open") {
echo "PR isn't open\n";
return true;
}
$ok_events = [
'created',
'edited',
'synchronize',
];
if (!in_array($in->action, $ok_events)) {
echo "Uninteresting event " . $in->action . "\n";
return true;
}
$r = $msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
var_dump($r);
echo "acked\n";
$against_name = "origin/" . $in->pull_request->base->ref;
echo "Building against $against_name\n";
$co = new GHE\Checkout("/home/grahamc/.nix-test", "mr-est");
$pname = $co->checkOutRef($in->repository->full_name,
$in->repository->clone_url,
$in->number,
$against_name
);
$against = GHE\Exec::exec('git rev-parse %s', [$against_name]);
echo " $against_name is $against[0]\n";
try {
$co->applyPatches($pname, $in->pull_request->patch_url);
} catch (GHE\ExecException $e) {
echo "Received ExecException applying patches, likely due to conflicts:\n";
var_dump($e->getCode());
var_dump($e->getMessage());
var_dump($e->getArgs());
var_dump($e->getOutput());
return false;
}
$current = GHE\Exec::exec('git rev-parse HEAD');
echo " currently at ${current[0]}\n";
reply_to_issue($in, $against[0], $current[0]);
$msg->delivery_info['channel']->basic_cancel($msg->delivery_info['consumer_tag']);
return false;
}
function reply_to_issue($issue, $prev, $current) {
$client = gh_client();
echo "current labels:\n";
$already_there = $client->api('issue')->labels()->all(
$issue->repository->owner->login,
$issue->repository->name,
$issue->number);
$already_there = array_map(function($val) { return $val['name']; }, $already_there);
var_dump($already_there);
$output = GHE\Exec::exec('$(nix-instantiate --eval -E %s) %s %s',
[
'<nixpkgs/maintainers/scripts/rebuild-amount.sh>',
$prev,
$current
]
);
$labels = [];
foreach ($output as $line) {
if (preg_match('/^\s*(\d+) (.*)$/', $line, $matches)) {
var_dump($matches);
# TODO: separate out the rebuild ranges from the rebuild platform and
# splice the string together, rather than this ugliness
if ($matches[1] > 500) {
if ($matches[2] == "x86_64-darwin") {
$labels[] = "10.rebuild-darwin: 501+";
} else {
$labels[] = "10.rebuild-linux: 501+";
}
} else if ($matches[1] > 100 && $matches[1] <= 500) {
if ($matches[2] == "x86_64-darwin") {
$labels[] = "10.rebuild-darwin: 101-500";
} else {
$labels[] = "10.rebuild-linux: 101-500";
}
} else if ($matches[1] > 10 && $matches[1] <= 100) {
if ($matches[2] == "x86_64-darwin") {
$labels[] = "10.rebuild-darwin: 11-100";
} else {
$labels[] = "10.rebuild-linux: 11-100";
}
} else if ($matches[1] <= 10) {
if ($matches[2] == "x86_64-darwin") {
$labels[] = "10.rebuild-darwin: 1-10";
} else {
$labels[] = "10.rebuild-linux: 1-10";
}
}
}
}
foreach ($labels as $label) {
if (in_array($label, $already_there)) {
echo "already labeled $label\n";
continue;
} else {
echo "will label +$label\n";
}
$client->api('issue')->labels()->add(
$issue->repository->owner->login,
$issue->repository->name,
$issue->number,
$label);
}
}
$consumerTag = 'consumer' . getmypid();
$channel->basic_consume($queueName, $consumerTag, false, true, false, false, 'outrunner');
while(count($channel->callbacks)) {
$channel->wait();
}
echo "Bye\n";

68
poster.php Normal file
View file

@ -0,0 +1,68 @@
<?php
require __DIR__ . '/config.php';
use PhpAmqpLib\Message\AMQPMessage;
# define('AMQP_DEBUG', true);
$connection = rabbitmq_conn();
$channel = $connection->channel();
$channel->basic_qos(null, 1, true);
list($queueName, , ) = $channel->queue_declare('build-results',
false, true, false, false);
function runner($msg) {
$body = json_decode($msg->body);
$in = $body->payload;
$num = $in->issue->number;
if ($body->success) {
echo "yay! $num passed!\n";
} else {
echo "Yikes, $num failede\n";
}
reply_to_issue($in, implode("\n", $body->output), $body->success);
var_dump($body->success);
$msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
}
function reply_to_issue($issue, $output, $success) {
$client = gh_client();
$pr = $client->api('pull_request')->show(
$issue->repository->owner->login,
$issue->repository->name,
$issue->issue->number
);
$sha = $pr['head']['sha'];
$client->api('pull_request')->reviews()->create(
$issue->repository->owner->login,
$issue->repository->name,
$issue->issue->number,
array(
'body' => "```\n$output\n```",
'event' => $success ? 'APPROVE' : 'COMMENT',
'commit_id' => $sha,
));
}
function outrunner($msg) {
try {
return runner($msg);
} catch (ExecException $e) {
var_dump($e->getMessage());
var_dump($e->getCode());
var_dump($e->getOutput());
}
}
$consumerTag = 'consumer' . getmypid();
$channel->basic_consume($queueName, $consumerTag, false, false, false, false, 'outrunner');
while(count($channel->callbacks)) {
$channel->wait();
}

15
shell.nix Normal file
View file

@ -0,0 +1,15 @@
let
pkgs = import <nixpkgs> {};
inherit (pkgs) stdenv;
in stdenv.mkDerivation rec {
name = "gh-event-forwarder";
src = ./.;
buildInputs = with pkgs; [
php
phpPackages.composer
];
HISTFILE = "${src}/.bash_hist";
}

37
src/ACL.php Normal file
View file

@ -0,0 +1,37 @@
<?php
namespace GHE;
class ACL {
static public function getRepos() {
return [
'grahamc/elm-stuff',
'nixos/nixpkgs',
];
}
static public function getUsers() {
return [
'copumpkin',
'domenkozar',
'fpletz',
'fridh',
'globin',
'grahamc',
'lnl7',
'mic92',
'shlevy',
];
}
static public function isRepoEligible($repo) {
return in_array(strtolower($repo), self::getRepos());
}
static public function isUserAuthorized($user) {
return in_array(strtolower($user), self::getUsers());
}
static public function authorizeUserRepo($user, $repo) {
return self::isRepoEligible($repo) && self::isUserAuthorized($user);
}
}

117
src/Checkout.php Normal file
View file

@ -0,0 +1,117 @@
<?php
namespace GHE;
class Checkout {
protected $root;
protected $type;
function __construct($root, $type) {
$this->root = $root;
$this->type = $type;
}
function checkOutRef($repo_name, $clone_url, $id, $ref) {
$this->prefetchRepoCache($repo_name, $clone_url);
$pname = $this->pathToRepoCache($repo_name);
$bname = $this->pathToBuildDir($repo_name, $id);
$guard = $this->guard($bname);
if (!is_dir($bname)) {
echo "Cloning " . $id . " to $bname\n";
Exec::exec('git clone --reference-if-able %s %s %s',
[
$pname,
$clone_url,
$bname
]);
}
if (!chdir($bname)) {
throw new CoFailedException("Failed to chdir to $bname\n");
}
echo "fetching " . $id . " in $bname\n";
Exec::exec('git fetch origin');
try {
Exec::exec('git am --abort');
} catch (ExecException $e) {
// non-zero exit if no am is in progress
}
Exec::exec('git reset --hard %s', [$ref]);
$this->release($guard);
return $bname;
}
function applyPatches($bname, $patch_url) {
if (!chdir($bname)) {
throw new CoFailedException("Failed to chdir to $bname\n");
}
$guard = $this->guard($pname);
Exec::exec('curl -L %s | git am --no-gpg-sign -', [$patch_url]);
$this->release($guard);
}
function prefetchRepoCache($name, $clone_url) {
if (!chdir($this->root)) {
throw new CoFailedException("Failed to chdir to " . $this->root);
}
$pname = $this->pathToRepoCache($name);
$guard = $this->guard($pname);
if (!is_dir($pname)) {
echo "Cloning " . $name . " to $pname\n";
Exec::exec('git clone --bare %s %s',
[
$clone_url,
$pname
]);
}
$this->release($guard);
if (!chdir($pname)) {
throw new CoFailedException("Failed to chdir to $pname");
}
echo "Fetching $name to $pname\n";
Exec::exec('git fetch origin');
}
function pathToRepoCache($name) {
return $this->root . "/repo-" . md5($name);
}
function pathToBuildDir($repo, $id_number) {
$id = (int) $id_number;
$repo_hash = md5($repo);
$type = $this->type;
return $this->root . "/$type-$repo_hash-$id";
}
function guard($path) {
$res = fopen("$path.lock", 'c');
while (!flock($res, LOCK_EX)) {
echo "waiting for lock on $path...\n";
sleep(1);
}
return $res;
}
function release($res) {
fclose($res);
}
}
class CoFailedException extends \Exception {}

132
src/EventClassifier.php Normal file
View file

@ -0,0 +1,132 @@
<?php
namespace GHE;
class EventClassifier {
public static function classifyEvent($payload) {
if (self::isIssuesEvent($payload)) {
return "issues";
}
if (self::isIssueComment($payload)) {
return "issue_comment";
}
if (self::isCommitComment($payload)) {
return "commit_comment";
}
if (self::isPullRequestReviewComment($payload)) {
return "pull_request_review_comment";
}
if (self::isPullRequestReviewEvent($payload)) {
return "pull_request_review";
}
if (self::isPullRequestEvent($payload)) {
return "pull_request";
}
if (self::isStatusEvent($payload)) {
return "status";
}
if (self::isPushEvent($payload)) {
return "push";
}
if (self::isWatchEvent($payload)) {
return "watch";
}
if (self::isForkEvent($payload)) {
return "fork";
}
throw new EventClassifierUnknownException();
}
public static function isIssuesEvent($payload) {
return isset($payload->issue)
&& !isset($payload->comment)
&& isset($payload->action)
&& in_array($payload->action,
[ "assigned", "unassigned", "labeled",
"unlabeled", "opened", "edited",
"milestoned", "demilestoned", "closed",
"reopened" ]);
}
public static function isIssueComment($payload) {
return isset($payload->issue)
&& isset($payload->comment)
&& isset($payload->action)
&& in_array($payload->action,
['created', 'edited', 'deleted']);
}
public static function isCommitComment($payload) {
return !isset($payload->issue)
&& !isset($payload->pull_request)
&& isset($payload->comment)
&& isset($payload->action);
}
public static function isPullRequestReviewComment($payload) {
return !isset($payload->issue)
&& isset($payload->pull_request)
&& isset($payload->comment)
&& isset($payload->action)
&& in_array($payload->action,
['created', 'edited', 'deleted']);
}
public static function isPullRequestReviewEvent($payload) {
return isset($payload->review)
&& isset($payload->pull_request)
&& isset($payload->action)
&& in_array($payload->action,
['submitted', 'edited', 'dismissed']);
}
public static function isPullRequestEvent($payload) {
return isset($payload->number)
&& isset($payload->pull_request)
&& isset($payload->action)
&& in_array($payload->action,
[ "assigned", "unassigned",
"review_requested",
"review_request_removed", "labeled",
"unlabeled", "opened", "edited", "closed",
"reopened", "synchronize" ]);
}
public static function isStatusEvent($payload) {
return isset($payload->sha)
&& isset($payload->commit)
&& isset($payload->state)
&& in_array($payload->state,
['pending', 'success', 'failure', 'error']);
}
public static function isPushEvent($payload) {
return isset($payload->head_commit)
&& isset($payload->commits)
&& isset($payload->compare)
&& isset($payload->forced);
}
public static function isWatchEvent($payload) {
return isset($payload->action)
&& $payload->action == "started";
}
public static function isForkEvent($payload) {
return isset($payload->forkee);
}
}
class EventClassifierUnknownException extends \Exception{};

42
src/Exec.php Normal file
View file

@ -0,0 +1,42 @@
<?php
namespace GHE;
class Exec {
public static function exec($cmd, $args = array()) {
$safeArgs = array_map('escapeshellarg', $args);
$interiorCmd = vsprintf($cmd, $safeArgs);
$exteriorCmd = sprintf('/bin/sh -o pipefail -euc %s 2>&1',
escapeshellarg($interiorCmd));
exec($exteriorCmd, $output, $return);
if ($return > 0) {
throw new ExecException($cmd, $args, $output, $return);
}
return $output;
}
}
class ExecException extends \Exception {
protected $args;
protected $output;
public function __construct($cmd, $args, $output, $return) {
$this->args = $args;
$this->output = $output;
parent::__construct("Error calling $cmd", $return);
}
public function getArgs() {
return $this->args;
}
public function getOutput() {
return $this->output;
}
}

3
src/NixBuild.php Normal file
View file

@ -0,0 +1,3 @@
<?php
namespace GHE;

68
src/TestExec.php Normal file
View file

@ -0,0 +1,68 @@
<?php
namespace GHE;
class TestExec extends \PHPUnit\Framework\TestCase
{
/** Exec::exec('curl -L %s | git am --no-gpg-sign -');
*/
function testExecBasic() {
$this->assertEquals(
['oof'],
Exec::exec('echo foo | rev')
);
}
function testExecArgs() {
$this->assertEquals(
['rab'],
Exec::exec('echo %s | rev', ['bar'])
);
}
function testExecArgsDangerous() {
$this->assertEquals(
['$(whoami)'],
Exec::exec('echo %s', ['$(whoami)'])
);
}
function testExecFailureExceptions() {
$this->expectException(ExecException::class);
$this->expectExceptionCode(123);
$this->expectExceptionMessage("Error calling exit 123");
Exec::exec('exit 123');
}
function testExecFailureExceptionsOutput() {
try {
Exec::exec('echo %s; exit %s', ["heya", 10]);
$this->assertFalse(true, "Should have excepted!");
} catch (ExecException $e) {
$this->assertEquals(10, $e->getCode());
$this->assertEquals(["heya", 10], $e->getArgs());
$this->assertEquals(["heya"], $e->getOutput());
}
}
function testExecFailureExceptionPipefailEnd() {
try {
var_dump(Exec::exec('echo "foo" | (exit 2);'));
$this->assertFalse(true, "Should have excepted!");
} catch (ExecException $e) {
$this->assertEquals(2, $e->getCode());
}
}
function testExecFailureExceptionPipefailStart() {
try {
var_dump(Exec::exec('(echo "foo"; exit 3) | rev;'));
$this->assertFalse(true, "Should have excepted!");
} catch (ExecException $e) {
$this->assertEquals(3, $e->getCode());
}
}
}

27
web/index.php Normal file
View file

@ -0,0 +1,27 @@
<?php
require_once __DIR__ . '/../config.php';
use PhpAmqpLib\Message\AMQPMessage;
$connection = rabbitmq_conn();
$channel = $connection->channel();
$input = json_decode(file_get_contents('php://input'), true);
if (!isset($input['repository']['full_name'])) {
echo "no full_name set?";
exit(0);
}
$name = strtolower($input['repository']['full_name']);
if (!GHE\ACL::isRepoEligible($name)) {
echo "repo not in ok name list";
exit(1);
}
$channel->exchange_declare($name, 'fanout', false, true, false);
$message = new AMQPMessage(json_encode($input),
array('content_type' => 'application/json'));
$channel->basic_publish($message, $name);