git pull

I've been asked to create a script to permit people with no direct access to a server to perform pulls from a git repository for specific applications, using their own credentials (to avoid leaving plain-text passwords or valid SSH keys around), so to publish their own changes on-demand (and without periodic automatic pulls, nor branches to mess with).

Probably buried on the Internet there are already many similar scripts, but I found quicker and easier to write my own. And I'm here to share.

Drop the following file on the repository root or in a child folder (it is meant to work also for applications which DocumentRoot is not the repository root, such as the /public folder in Laravel), and retrieve it opening the browser. Fill username and password, and submit. Of course the user running the web server needs full write permissions on the full tree.

<?php

$config_paths = array(
	'.git/config' => './',
	'../.git/config' => '../',
);

$conf_file = null;

foreach($config_paths as $test_conf => $path) {
	if(file_exists($test_conf)) {
		$conf_file = $test_conf;
		$conf_path = $path;
		break;
	}
}

if ($conf_file == null) {
	echo "ERROR: configuration not found!";
	exit();
}

$conf = file_get_contents($conf_file);
preg_match_all('/url = (?P<url>[^\n]*)\n/', $conf, $matches);
if (isset($matches['url']) == false || empty($matches['url']) || empty($matches['url'][0])) {
	echo "ERROR: configuration not found!";
	exit();
}

$url = $matches['url'][0];

$at = strpos($url, '@');
if ($at !== false)
	$url = 'https://' . substr($url, $at + 1);

if (isset($_POST['run'])) {
	$username = $_POST['username'];
	$password = $_POST['password'];

	$auth_string = sprintf("%s:%s@", $username, $password);
	$url = str_replace('https://', 'https://' . $auth_string, $url);

	$descriptorspec = array(
		1 => array("pipe", "w"),
		2 => array("pipe", "w")
	);

	chdir($conf_path);

	$process = proc_open("git pull $url", $descriptorspec, $pipes);
	if (is_resource($process)) {
		$stdout = stream_get_contents($pipes[1]);
		$stderr = stream_get_contents($pipes[2]);
		foreach ($pipes as $pipe)
			fclose($pipe);

		echo nl2br($stdout);
		echo nl2br($stderr);
	}
	else {
		echo "Error executing `git pull`";
	}

	exit();
}

?>

<html>
	<head>
		<title>Auto Pull</title>
		
		<script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
		
		<script>
		$(document).ready(function() {
			$('form').submit(function(e) {
				e.preventDefault();

				var action = $(this).attr('action');
				var username = $(this).find('input[name=username]').val();
				var password = $(this).find('input[name=password]').val();
			
				if (username == '' || password == '') {
					alert('Missing username or password');
					return false;
				}

				$('.response').empty().append('Wait...');
			
				$.post(action, {username: username, password: password, run: 1}, function(data) {
					$('.response').empty().append(data);
				});

				return false;
			});
		});
		</script>
	</head>
	
	<body>
		<h3>Pulling repository at <?php echo $url ?></h3>

		<br/>

		<form method="POST" action="">
			<p><input type="text" name="username" placeholder="Username"></p>
			<p><input type="password" name="password" placeholder="Password"></p>
			<p><input type="submit" value="git pull!"></p>
		</form>
		
		<br/>
		
		<p class="response">
		</p>
	</body>
</html>