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> / hooks / update (67b8cf360932c9c64363daf519e852816be27b98) (4,102B) (mode 100755) [raw]
#!/usr/bin/php
<?php

//
// This is called by 'update' hook
// Inspired by update.sample in git package
// TODO: what we receive when a tag will be created?
//

error_reporting(E_ALL);
ini_set("track_errors", "On");

$_start = microtime(TRUE);

require_once("/etc/rocketgit/config.php");

$INC = $rg_scripts . "/inc";
require_once($INC . "/util.inc.php");
require_once($INC . "/log.inc.php");
require_once($INC . "/sql.inc.php");
require_once($INC . "/repo.inc.php");

rg_log_set_file("/var/log/rocketgit/hook_update.log");

$uid = @sprintf("%u", getenv("ROCKETGIT_UID"));
$rights = getenv("ROCKETGIT_RIGHTS");

rg_log("Start uid=$uid, rights=[$rights]...");
rg_log("_SERVER: " . print_r($_SERVER, TRUE));

umask(0022);


$refname = @rg_git_reference($_SERVER['argv'][1]);
$old_rev = rg_git_rev(@$_SERVER['argv'][2]);
$new_rev = rg_git_rev(@$_SERVER['argv'][3]);
rg_log("refname=$refname old_rev=$old_rev new_rev=$new_rev.");

if (empty($refname) || empty($old_rev) || empty($new_rev))
	rg_fatal("Invalid parameters [$refname $old_rev $new_rev]!");

if (strcmp($new_rev, $rg_git_zero) == 0)
	$new_rev_type = "delete";
else
	$new_rev_type = rg_git_type($new_rev);
rg_log("new_rev_type=$new_rev_type.");

if (strcmp($new_rev_type, "commit") == 0) {
	rg_log("It's a commit...");

	if (strcmp($old_rev, $rg_git_zero) != 0) {
		rg_log("This is a reference update...");

		// check non fast-forward update
		if (!rg_rights_allow($rights, "O")) {
			$merge_base = rg_git_merge_base($old_rev, $new_rev);
			if ($merge_base === FALSE) {
				rg_log("Error: " . rg_git_error());
				rg_fatal("Internal error! Try again later!");
			}

			if (strcmp($merge_base, $old_rev) != 0)
				rg_fatal("Non fast-forward is not allowed for $refname!");
		}
	}

	if (strncmp($refname, "refs/tags/", 10) == 0) {
		rg_log("Un-annotated tag...");
		if (strcmp($old_rev, $rg_git_zero) == 0) {
			if (!rg_rights_allow($rights, "Y"))
				rg_fatal("No rights to create an un-annotated tag!");
		} else { //change
			if (!rg_rights_allow($rights, "U"))
				rg_fatal("No rights to change an un-annotated tag!");
		}
	} else if (strncmp($refname, "refs/heads/", 11) == 0) {
		if (strcmp($old_rev, $rg_git_zero) == 0) {
			rg_log("Creating a branch...");
			if (!rg_rights_allow($rights, "C"))
				rg_fatal("You have no rights to create a branch!");
		} else if (rg_git_rev_ok($new_rev . "^2")) {
			rg_log("Merge commit...");
			if (!rg_rights_allow($rights, "M"))
				rg_fatal("You have no rights to push merge commits!");
		} else {
			rg_log("Normal commit...");
			if (!rg_rights_allow($rights, "W")) {
				if (!rg_git_whitespace_ok($old_rev, $new_rev))
					rg_fatal("Bad whitespace is not allowed!");
			}
		}
	} else {
		rg_fatal("Unknown refname provided!");
	}

	// TODO: refs/remotes/*
} else if (strcmp($new_rev_type, "delete") == 0) {
	rg_log("It's a delete...");
	if (strncmp($refname, "refs/tags/", 10) == 0) {
		rg_log("Deleting an un-annotated tag...");
		if (!rg_rights_allow($rights, "u"))
			rg_fatal("You have no rights to delete a tag!");
	} else if (strncmp($refname, "refs/heads/", 11) == 0) {
		rg_log("Deleting a branch...");
		if (!rg_rights_allow($rights, "D"))
			rg_fatal("You have no rights to delete a branch!");
	} else if (strncmp($refname, "refs/remotes/", 13) == 0) {
		rg_log("Deleting a tracking branch...");
		if (!rg_rights_allow($rights, "D"))
			rg_fatal("You have no rights to delete a tracking branch!");
	}
} else if (strcmp($new_rev_type, "tag") == 0) {
	rg_log("It's an annotated tag...");
	if (strncmp($refname, "refs/tags/", 10) == 0) {
		rg_log("Modify tag...");
		if (!rg_rights_allow($rights, "S"))
			rg_fatal("You have no rights to modify a tag!");
	}
} else {
	rg_log("Invalid new_rev type!");
	rg_fatal("Internal error!");
}


$diff = sprintf("%u", (microtime(TRUE) - $_start) * 1000);
rg_log("Took " . $diff . "ms.");

@file_put_contents($repo_path . "/rg/hook-update",
	"repo: " . $repo . " ($repo_path)"
	. "\nat: " . sprintf("%u", $_start)
	. "\nuid: " . $uid
	. "\npara: $refname $old_rev $new_rev"
	. "\nTook: " . $diff . "ms"
	. "\n_SERVER: " . print_r($_SERVER, TRUE));
?>
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