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 / wh / cloud.inc.php (3d2eb99c53f1aa9dc4ab4a1c82c90eec658a606e) (6,782B) (mode 100644) [raw]
<?php
require_once($INC . "/util.inc.php");
require_once($INC . "/log.inc.php");
require_once($INC . "/sql.inc.php");
require_once($INC . "/prof.inc.php");
require_once($INC . "/events.inc.php");
require_once($INC . "/wh/core.inc.php");
require_once($INC . "/wh/amazon.inc.php");

$rg_wh_cloud_functions = array(
	'wh_cloud_send' => 'rg_wh_cloud_send',
	'rg_wh_cloud_send_one' => 'rg_wh_cloud_send_one', // obsolete
	'wh_cloud_send_one' => 'rg_wh_cloud_send_one'
);
rg_event_register_functions($rg_wh_cloud_functions);


/*
 * Helper for rg_wh_cloud_send
 */
function rg_wh_cloud_send_one($db, $ev)
{
	rg_prof_start('wh_cloud_send_one');
	rg_log_ml('wh_cloud_send_one: event: ' . print_r($ev, TRUE));

	$ret = FALSE;

	$wh = &$ev['wh'];

	$xid = rg_id(8);
	$f = 'wh-' . $ev['ui']['uid'] . '-' . $wh['id'] . '-' . $xid . '.zip';
	$path = rg_tmp_path($f);

	$last_output = '';
	while (1) {
		// TODO: cache the output?
		// generate archive (TODO: specify branch)
		// TODO: the id of the commit should be passed to the hook, else another
		// push will "destroy" the reference.
		$r = rg_git_archive($ev['repo_path'], $ev['new_rev'],
			$path, 'zip');
		if ($r === FALSE) {
			$last_output .= rg_git_error();
			break;
		}

		// replace ##tags##
		rg_wh_replace_tags($ev);

		// store to s3
		$wh['idata']['content_type'] = 'application/zip';
		// we need to copy 'flags' because we pass idata
		$wh['idata']['flags'] = $wh['flags'];
		$c = @file_get_contents($path);
		if ($c === FALSE) {
			$last_output .= 'missing archive; very strange!';
			break;
		}
		$r = rg_amazon_s3_put_object($wh['idata'], $c);
		if ($r['ok'] != 1) {
			$last_output .= $r['errmsg'];
			break;
		}
		$last_output .= $r['answer'];

		// c = skip the CodeDeploy step
		if (!strchr($wh['flags'], 'c')) {
			// Do the code deploy
			$r = rg_amazon_codedeploy_create($wh['idata']);
			if ($r['ok'] != 1) {
				$last_output .= $r['errmsg'];
				break;
			}

			$last_output .= $r['answer'];
		}

		$ret = array();
		break;
	}
	@unlink($path);

	rg_wh_set_last_output($db, $ev['ui']['uid'], $wh['id'],
		substr($last_output, 0, 4096));

	if ($ev['debug'] == 1)
		rg_cache_set('DEBUG::' . $ev['ui']['uid']
			. '::webhooks::' . $wh['id'], $last_output,
			RG_SOCKET_NO_WAIT);

	rg_prof_end('wh_cloud_send_one');
	return $ret;
}

/*
 * Generic function which will be called when a webhook must be posted
 */
function rg_wh_cloud_send($db, $ev)
{
	rg_prof_start('wh_cloud_send');
	rg_log_ml('wh_cloud_send: event: ' . print_r($ev, TRUE));

	$ret = array();

	// First, get the list of hooks
	$r = rg_wh_list($db, $ev['ui']['uid']);
	if ($r['ok'] != 1)
		return FALSE;

	// Filter
	foreach ($r['list'] as $id => $wh) {
		if (strcmp($wh['htype'], 'cloud') != 0)
			continue;

		if (strchr($wh['flags'], 'D')) {
			rg_log('DEBUG: hook is disabled');
			continue;
		}

		// If the web hook does not contain our type, skip it
		if (!strchr($wh['idata']['events'], $ev['wh_event'])) {
			rg_log('DEBUG: ' . $ev['wh_event']
				. ' is not present in '
				. $wh['idata']['events']);
			continue;
		}

		if (!rg_repo_compare_refs($wh['repo'], $ev['ri']['name'])) {
			rg_log('hook is not for this ref');
			continue;
		}

		if (!rg_repo_compare_refs($wh['refname'], $ev['refname'])) {
			rg_log('hook is not for this ref');
			continue;
		}

		$x = $ev;
		$x['category'] = 'wh_cloud_send_one';
		$x['wh'] = $wh;
		$ret[] = $x;
	}

	rg_prof_end('wh_cloud_send');
	return $ret;
}

/*
 * Some cosmetics applied to a webhook
 */
function rg_wh_cloud_cosmetic_pre(&$row)
{
	rg_wh_amazon_cosmetic($row);
}

/*
 * Some cosmetics applied to a webhook
 */
function rg_wh_cloud_cosmetic_post(&$row)
{
	$row['idata']['HTML:private'] = rg_template(
		'user/settings/wh/cloud/show.html', $row['idata'], TRUE /*xss*/);
}

/*
 * Fill private data based on parameters passed
 */
function rg_wh_cloud_fill_vars(&$rg)
{
	$a = &$rg['wh']['idata'];
	rg_wh_amazon_fill_vars($a);
	$a['application_name'] = trim(rg_var_str('wh::idata::application_name'));
	$a['deployment_group_name'] = trim(rg_var_str('wh::idata::deployment_group_name'));
	$a['deployment_config_name'] = trim(rg_var_str('wh::idata::deployment_config_name'));
	$a['bucket'] = trim(rg_var_str('wh::idata::bucket'));
	$a['file'] = trim(rg_var_str('wh::idata::file'));
}

/*
 * Validate parameters passed
 */
function rg_wh_cloud_validate_vars($rg, &$errmsg)
{
	global $rg_wh_cloud_itypes;

	$a = $rg['wh'];

	$ret = FALSE;
	while (1) {
		if (!rg_wh_amazon_validate_vars($a['idata'], $errmsg))
			break;

		if (empty($a['idata']['bucket'])) {
			$errmsg[] = rg_template('user/settings/wh/cloud/inv_bucket.txt',
				$rg, TRUE /*xss*/);
			break;
		}

		// c = skip the CodeDeploy step
		if (strchr($a['flags'], 'c')) {
			$ret = TRUE;
			break;
		}

		if (empty($a['idata']['application_name'])) {
			$errmsg[] = rg_template('user/settings/wh/cloud/inv_app_name.txt',
				$rg, TRUE /*xss*/);
			break;
		}

		if (empty($a['idata']['deployment_group_name'])) {
			$errmsg[] = rg_template('user/settings/wh/cloud/inv_group_name.txt',
				$rg, TRUE /*xss*/);
			break;
		}

		$ret = TRUE;
		break;
	}

	return $ret;
}

/*
 * Transfers to $rg the custom parameters - used when showing the form
 */
function rg_wh_cloud_add_form_pre($db, &$rg)
{
	$a = $rg['wh']['idata'];
	rg_wh_amazon_default_paras($a);

	if (!isset($a['application_name']))
		$a['application_name'] = '';

	if (!isset($a['deployment_group_name']))
		$a['deployment_group_name'] = '';

	if (!isset($a['deployment_config_name']))
		$a['deployment_config_name'] = '';

	if (!isset($a['bucket']))
		$a['bucket'] = '';

	if (!isset($a['file']))
		$a['file'] = '';

	$rg['wh']['idata'] = $a;
}

/*
 * Transfers to $rg the custom parameters - used when showing the form
 */
function rg_wh_cloud_add_form_post($db, &$rg)
{
	$rg['HTML:custom_form'] = rg_template('user/settings/wh/cloud/form.html',
		$rg, TRUE /*xss*/);
}

/*
 * Add custom hints
 */
function rg_wh_cloud_fill_hints($rg, &$hints)
{
	$hints[]['HTML:hint'] = rg_template('user/settings/wh/cloud/hints.html',
		$rg, TRUE /*xss*/);
}



$info = array(
	'htype' => 'cloud',
	'description' => 'Stores your repo files into Amazon S3 and (optionally) does a CodeDeploy',
	'cb' => array(
		'cosmetic_pre' => 'rg_wh_cloud_cosmetic_pre',
		'cosmetic_post' => 'rg_wh_cloud_cosmetic_post',
		'fill_vars' => 'rg_wh_cloud_fill_vars',
		'validate_vars' => 'rg_wh_cloud_validate_vars',
		'add_form_pre' => 'rg_wh_cloud_add_form_pre',
		'add_form_post' => 'rg_wh_cloud_add_form_post',
		'fill_hints' => 'rg_wh_cloud_fill_hints',
	),
	'have_events' => FALSE,
	'flags' => array(
		'I' => 'Ignore application stop failures',
		'c' => 'Skip the CodeDeploy step'
	)
);
rg_wh_register_type('cloud', $info);

$cb = array();
rg_wh_register_subtype('cloud', 'generic', 'Generic', $cb);
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