xaizek / rocketgit (License: AGPLv3+) (since 2018-12-09)
Light and fast Git hosting solution suitable to serve both as a hub or as a personal code storage with its tickets, pull requests, API and much more.
<root> / inc / mr.inc.php (d4c3748a9d630bf8d8bc9d81bcdb8576a9394636) (4,499B) (mode 100644) [raw]
<?php
// Merge requests

require_once($INC . "/util.inc.php");
require_once($INC . "/sql.inc.php");
require_once($INC . "/events.inc.php");

$rg_mr_env_q = getenv("ROCKETGIT_MR_QUEUE");
if (empty($rg_mr_env_q))
	$rg_mr_queue = $rg_state_dir . "/q_merge_requests";
else
	$rg_mr_queue = $rg_mr_env_q;

$rg_mr_error = "";

function rg_mr_set_error($str)
{
	global $rg_mr_error;
	$rg_mr_error = $str;
	rg_log($str);
}

function rg_mr_error()
{
	global $rg_mr_error;
	return $rg_mr_error;
}

/*
 * Events functions
 */
$rg_mr_functions = array(
	7000 => 'rg_mr_event_new',
	7001 => 'rg_mr_event_add_to_db'
);
rg_event_register_functions($rg_mr_functions);

/*
 * This is called when a new pull request is done
 */
function rg_mr_event_new($db, $ev)
{
	$ret = array();

	// Insert it into database
	$ret[] = array_merge($ev,
		array('category' => 7001, 'prio' => 100));

	// TODO: Notify admins of the repo

	// TODO: Call a webhook

	return $ret;
}

/*
 * Add a merge request file to database
 */
function rg_mr_event_add_to_db($db, $a)
{
	rg_log_ml('mr_add_to_db: a: ' . print_r($a, TRUE));

	$now = time();
	$sql = "INSERT INTO merge_requests (repo_id, itime, namespace"
		. ", refname, old_rev, new_rev, done, ip)"
		. " VALUES (@@repo_id@@, @@itime@@, @@namespace@@, @@refname@@"
		. ", @@old_rev@@, @@new_rev@@, 0, @@ip@@)";
	$res = rg_sql_query_params($db, $sql, $a);
	if ($res === FALSE) {
		rg_mr_set_error("cannot insert merge request"
			. " (" . rg_sql_error() . ")");
		return FALSE;
	}

	rg_sql_free_result($res);

	return array();
}

/*
 * Loads info from a merge request file
 */
function rg_mr_queue_load_file($file)
{
	global $php_errormsg;

	$ret = array();
	$ret['ok'] = 0;

	$c = @file_get_contents($file);
	if ($c === FALSE) {
		rg_mr_set_error("cannot load a merge request from $file ($php_errormsg)");
		return $ret;
	}

	$tokens = explode(" ", trim($c));
	foreach ($tokens as $token) {
		$p = explode("=", $token);
		$ret[$p[0]] = $p[1];
	}

	$ret['ok'] = 1;
	return $ret;
}

/*
 * Process merge requests queue
 */
function rg_mr_queue_process($db)
{
	global $php_errormsg;
	global $rg_mr_queue;

	rg_prof_start("mr_queue_process");

	$ret = TRUE;
	$dir = @opendir($rg_mr_queue);
	if ($dir === FALSE) {
		rg_mr_set_error("cannot open dir $rg_mr_queue ($php_errormsg)!");
		return FALSE;
	}

	while (($file = readdir($dir))) {
		if (strncmp($file, "mr-", 3) != 0)
			continue;

		$path = $rg_mr_queue . "/" . $file;
		rg_log("Loading merge request from $path...");
		$d = rg_mr_queue_load_file($path);
		if ($d['ok'] != 1) {
			$ret = FALSE;
			break;
		}

		$r = rg_mr_create($db, $d['repo_id'], $d['namespace'],
			$d['old_rev'], $d['new_rev'], $d['refname'], $d['ip']);
		if ($r != TRUE) {
			rename($path, $rg_mr_queue . "/BAD-" . $file);
		} else {
			if (@unlink($path) !== TRUE)
				rg_log("Warn: Cannot unlink file $path!");
			// TODO: Verify it exists in database
		}
	}
	closedir($dir);

	rg_prof_end("mr_queue_process");
	return $ret;
}

/*
 * Helper to condiment mr data
 */
function rg_mr_condiment(&$row)
{
	$row['date_utc'] = gmdate("Y-m-d H:i", $row['itime']);
	$row['old_rev_short'] = substr($row['old_rev'], 0, 7);
	$row['new_rev_short'] = substr($row['new_rev'], 0, 7);
}

/*
 * Loads merge requests
 * @limit = 0 => no limit
 */
function rg_mr_load($db, $repo_id, $limit)
{
	rg_log("mr_load: repo_id=$repo_id limit=$limit");

	$params = array("repo_id" => $repo_id);
	$sql = "SELECT * FROM merge_requests"
		. " WHERE repo_id = @@repo_id@@"
		. " AND done = 0"
		. " ORDER BY itime";
	if ($limit > 0)
		$sql .= " LIMIT " . $limit;
	$res = rg_sql_query_params($db, $sql, $params);
	if ($res === FALSE) {
		rg_mr_set_error("Cannot load merge requests (" . rg_sql_error() . ")");
		return FALSE;
	}

	$ret = array();
	while (($row = rg_sql_fetch_array($res))) {
		rg_mr_condiment($row);
		$ret[] = $row;
	}
	rg_sql_free_result($res);

	return $ret;
}

/*
 * Loads a merge request
 */
function rg_mr_load_one($db, $repo_id, $namespace)
{
	rg_log("mr_load_one: repo_id=$repo_id namespace=$namespace");

	$params = array("repo_id" => $repo_id, "namespace" => $namespace);
	$sql = "SELECT * FROM merge_requests"
		. " WHERE repo_id = @@repo_id@@"
		. " AND namespace = @@namespace@@";
	$res = rg_sql_query_params($db, $sql, $params);
	if ($res === FALSE) {
		rg_mr_set_error("cannot load a merge request"
			. " (" . rg_sql_error() . ")");
		return FALSE;
	}

	$row = rg_sql_fetch_array($res);
	rg_mr_condiment($row);

	rg_sql_free_result($res);

	return $row;
}

?>
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/rocketgit

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/rocketgit

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master