Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

External Deploy Initial Commit #143

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions external_deploy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#** External Deploy via phploy (https://github.com/banago/PHPloy/) **

This script allows you to deploy your repo to an external server via ftp/sftp

Instructions

1. Copy the following files to the root of your repository.
* phploy
* phploy.ini

2. Edit phploy.ini with the basic (s)ftp details

3. Create and upload secrets.json with the following information
* username
* password
* slack_url (optional)
* slack_channel (optional)

4. Add the example scripts `external_deploy.php`, `slack_notification.php`, and `get_secrets.inc` private directory in the root of your site's codebase, that is under version control. Note this is a different private directory than where the secrets.json is stored.

5. Add Quicksilver operations to your `pantheon.yml`

6. If you already have your code deployed to your external server, initial your external server to match your current revision, run `phploy --sync` from your local computer
69 changes: 69 additions & 0 deletions external_deploy/external_deploy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

include_once 'get_secrets.inc';

$env = 'test';
if (isset($_ENV['PANTHEON_ENVIRONMENT']) && $_ENV['PANTHEON_ENVIRONMENT'] == 'live') {
$env = 'live';
}

if ($env != 'live') {
print "only need to git deploy for live deploy\n";
return;
}

// Load our hidden credentials.
// See the README.md for instructions on storing secrets.
$secrets = _get_secrets(array('username', 'password'));

$cwd = getcwd();
// If we're running from private/scripts, set current dir down to root.
if (strpos($cwd, 'private') !== FALSE && strpos($cwd, 'scripts') !== FALSE) {
chdir('../../');
}

$spawned = getenv('DEPLOY_SPAWNED');
if (empty($spawned)) {
putenv('DEPLOY_SPAWNED=1');
// Re-run this in the background, providing more time to deploy and notify.
exec_in_background('php private/scripts/external_deploy.php');
}
else {
$command = '';
if ($env == 'live') {
$command = 'php phploy --debug -s live';
}

// Run the actual deploy if we have the commands set.
if ($command) {
putenv('PHPLOY_USER=' . trim($secrets['username']));
putenv('PHPLOY_PASS=' . trim($secrets['password']));
$output = array();
exec($command, $output);
// Send slack notification after git deploy completion.
$action = 'finish';

// Post the results to slack.
if (!empty($secrets['slack_url']) && !empty($secrets['slack_channel'])) {
// Add the returned values from phploy to the notification.
$deploy_text = implode("\n", $output);

include_once 'slack_notification.php';
}
}
}

/**
* Execute a command in the background.
*
* @param string $cmd
* The command to execute.
*/
function exec_in_background($cmd) {
if (substr(php_uname(), 0, 7) == "Windows") {
pclose(popen("start /B ". $cmd, "r"));
}
else {
exec($cmd . " > /dev/null &");
}
}
32 changes: 32 additions & 0 deletions external_deploy/get_secrets.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

/**
* Get secrets from secrets file.
*
* @param array $requiredKeys
* List of keys in secrets file that must exist.
* @param array $defaults
* List of default values.
*/
function _get_secrets($requiredKeys, $defaults = array()) {
if (empty($_ENV['PANTHEON_ENVIRONMENT'])) {
$secretsFile = 'private/secrets.json';
}
else {
$secretsFile = $_SERVER['HOME'] . '/files/private/secrets.json';
}
if (!file_exists($secretsFile)) {
die('No secrets file found. Aborting!');
}
$secretsContents = file_get_contents($secretsFile);
$secrets = json_decode($secretsContents, 1);
if ($secrets == FALSE) {
die('Could not parse json in secrets file. Aborting!');
}
$secrets += $defaults;
$missing = array_diff($requiredKeys, array_keys($secrets));
if (!empty($missing)) {
die('Missing required keys in json secrets file: ' . implode(',', $missing) . '. Aborting!');
}
return $secrets;
}
Binary file added external_deploy/phploy
Binary file not shown.
11 changes: 11 additions & 0 deletions external_deploy/phploy.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
; NOTE: If non-alphanumeric characters are present, enclose in value in quotes.

[live]
scheme = ftp
host = example.com
port = 21
branch = master
exclude[] = 'private/*'
exclude[] = 'phploy'
exclude[] = 'phploy.ini'
logger = off
117 changes: 117 additions & 0 deletions external_deploy/slack_notification.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<?php

include_once 'get_secrets.inc';

// Important constants :)
$pantheon_yellow = '#EFD01B';
// Default values for parameters - this will assume the channel you define the webhook for.
// The full Slack Message API allows you to specify other channels and enhance the messagge further
// if you like: https://api.slack.com/docs/messages/builder
$defaults = array(
'slack_username' => 'Pantheon-Quicksilver',
'always_show_text' => false
);

if (empty($secrets['slack_url'])) {
$secrets = _get_secrets(array('username', 'password', 'slack_url', 'slack_channel'), $defaults);
}
else {
$secrets = array_merge($secrets, $defaults);
}

if (empty($action)) {
$action = 'finish';
}

if (empty($deploy_text)) {
$deploy_text = '';
}

// Ensure the channel starts with #.
if (substr($secrets['slack_channel'], 0, 1) != '#') {
$secrets['slack_channel'] = '#' . $secrets['slack_channel'];
}

// Add the user_email to the ENV, if set.
if (!empty($_POST['user_email']) && empty($_ENV['USER_EMAIL'])) {
putenv('USER_EMAIL=' . $_POST['user_email']);
}
$_ENV['USER_EMAIL'] = getenv('USER_EMAIL');

// Build an array of fields to be rendered with Slack Attachments as a table
// attachment-style formatting:
// https://api.slack.com/docs/attachments
$fields = array(
array(
'title' => 'Site',
'value' => $_ENV['PANTHEON_SITE_NAME'],
'short' => true,
),
// Render Environment name with link to site, <http://{ENV}-{SITENAME}.pantheon.io|{ENV}>.
array(
'title' => 'Environment',
'value' => '<http://' . $_ENV['PANTHEON_ENVIRONMENT'] . '-' . $_ENV['PANTHEON_SITE_NAME'] . '.pantheonsite.io|' . $_ENV['PANTHEON_ENVIRONMENT'] . '>',
'short' => true,
),
// Render Name with link to Email from Commit message.
array(
'title' => 'By',
'value' => $_ENV['USER_EMAIL'],
'short' => false,
),
);

// Find out what tag we are on and get the annotation.
$deploy_tag = `git describe --tags`;
// Prepare the slack payload as per:
// https://api.slack.com/incoming-webhooks
$text = ucwords($action) . ' deploy to external server by ' . $_ENV['USER_EMAIL'] . ' completed!';
// Build an array of fields to be rendered with Slack Attachments as a table
// attachment-style formatting:
// https://api.slack.com/docs/attachments
$fields[] = array(
'title' => 'Details',
'value' => $text . "\n" . $deploy_text,
'short' => false,
);
$attachment = array(
'fallback' => $text,
'pretext' => 'Deploying :rocket:',
'color' => $pantheon_yellow, // Can either be one of 'good', 'warning', 'danger', or any hex color code
'fields' => $fields,
);

_slack_notification($secrets['slack_url'], $secrets['slack_channel'], $secrets['slack_username'], $text, $attachment, $secrets['always_show_text']);


/**
* Send a notification to slack
*/
function _slack_notification($slack_url, $channel, $username, $text, $attachment, $alwaysShowText = FALSE) {
$attachment['fallback'] = $text;
$post = array(
'username' => $username,
'channel' => $channel,
'icon_emoji' => ':lightning_cloud:',
'attachments' => array($attachment)
);
if ($alwaysShowText) {
$post['text'] = $text;
}
$payload = json_encode($post);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $slack_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
// Watch for messages with `terminus workflows watch --site=SITENAME`
print("\n==== Posting to Slack ====\n");
$result = curl_exec($ch);
print("RESULT: $result");
// $payload_pretty = json_encode($post,JSON_PRETTY_PRINT); // Uncomment to debug JSON
// print("JSON: $payload_pretty"); // Uncomment to Debug JSON
print("\n===== Post Complete! =====\n");
curl_close($ch);
}