Added quick-deploy

This commit is contained in:
Marcel Kapfer 2020-04-12 20:27:04 +02:00
parent fbb2cbb524
commit f481da3ee8
5 changed files with 308 additions and 0 deletions

View file

@ -0,0 +1,3 @@
# 0.0.1
- Initial release

7
quick-deploy/LICENSE.md Normal file
View file

@ -0,0 +1,7 @@
Copyright 2020 Marcel Kapfer <opensource@mmk2410.org>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

35
quick-deploy/README.md Normal file
View file

@ -0,0 +1,35 @@
# Quick Deploy
Quick Deploy is a simple and dirty script-based solution for continous delivery.
## Basic idea
You have a Git server (like [Gitea](https://gitea.io), but just a bare repo should also work) where you host a repo that you want to deploy somewhere. The somewhere (same or other server) has a Web Server with PHP capabilities running (my use case: I develop a TYPO3 site package, TYPO3 runs on PHP). In your Git repo (server-side) you define post-receive Git hook which just sends a simple HTTP GET request your deploy-server (over HTTTPS, of course) like https://example.com/quick-deploy.php?secret=YOUR_SECRET. Where your secret is known to you, your git post-receive hook and the quick-deploy script. If the given secret matches the predefinded than a pull request in the given repository is attempted. It git fails, a 500 error will be returned. Additionally the git output will be printed.
## Setup
1. Download the `quick-deploy.php` script and the `config.example.json` in a public accesible folder on your server where you want to deploy your code.
1. Create a secret. For example run `openssl rand -base64 42`
1. Copy (or rename) the `config.example.json` and edit it to your liking. You can find a list of options and their requirement later. Remove the example file afterwards.
1. Set correct permissions on `config.json`. It needs to be readable by the `quick-deploy.php` script (presumably run by the user `www-data`) but must not be accessible over the web. Otherwise your secret is no longer one. `chmod 600 config.json` should do that.
1. Create g Git post-receive-hook in your Git repository like the following:
```
#!/bin/sh
curl https://your.deploy.server?secret=YOUR_SECRET
```
## Configuration variables
Here is a alphabetically list of possible configuration variables and if it is necessary that their set.
| Key | Default | Required | Description |
| --- | ------- | -------- | ----------- |
| `branch` | `master` | No | Branch which should be used |
| `local-path` | N/A | Yes | Path of the deployed git repository |
| `remote-path` | N/A | Yes | Path or URL of the remote Git repository |
| `secret` | N/A | Yes | Secret which is exchanged as GET paramter |
## Contribute
Feel free to contribute if you want to.

View file

@ -0,0 +1,6 @@
{
"remote-path": "git@git.example.com:yourname/somerepo",
"branch": "develop",
"local-path": "/var/www/html/",
"secret": "YOUR-SECRET"
}

View file

@ -0,0 +1,257 @@
<?php
/**
* Quick and dirty deploy script for Git repositories.
*
* Basic idea: you have a Git server (like Gitea, but just a bare repo should
* also work) where you host a repo that you want to deploy somewhere. The
* somewhere (same or other server) has a Web Server with PHP capabilities
* running (my use case: I develop a TYPO3 site package, TYPO3 runs on PHP).
* In your Git repo (server-side) you define post-receive git hook which just
* sends a simple HTTP GET request your deploy-server (over HTTTPS, of course)
* like https://example.com/quick-deploy.php?s=YOUR_SECRET. Where your secret
* is known to you, your git post-receive hook and the quick-deploy script.
* If the given secret matches the predefinded than a pull request in the given
* repository is attempted. It git fails, a 500 error will be returned.
* Additionally the git output will be printed.
*
* For the configuration look at config.example.json. Copy it and ajust it for
* a working setup.
*
* PHP version 7
*
* @package QuickDeploy
* @author Marcel Kapfer <opensource@mmk2410.org>
* @copyright 2020 Marcel Kapfer
* @license https://opensource.org/licenses/MIT MIT License
* @version v0.0.1
*/
/**
* Position of the configuration JSON file.
*/
define("CONFIG_FILE", "config.json");
/**
* Parse and print Git output.
*
* The output of a git command with the --progress flag is a little bit
* hard to parse. The progress messages need to be splited first and
* then printed.
*
* @param string $output output of a git command execution
*
* @return void
*/
function print_git_output($output)
{
foreach ($output as &$line) {
$line = preg_split("/\r\n|\n|\r/", $line);
foreach ($line as &$subline) {
echo($subline . "<br>");
}
}
}
/**
* Print something bold (<b></b>) and end with newline.
*
* Handy wrapper of the echo function which prints the text wrapped with a
* "<b></b>" tag and end with a <br>.
*
* @param string $output string to print in bold
*
* @return void
*/
function print_bold($output)
{
echo("<b>" . $output . "</b><br>");
}
/**
* Handle shell exit status.
*
* Checks if the exist status is zero or not and prints $action combined with a
* status message (failed or successful) as bold text.
*
* @param int $return_var exit code of called command
* @param string $action name/description of tried action
*
* @return void
*/
function handle_status($return_var, $action)
{
if ($return_var != 0) {
handle_error($action . " failed");
} else {
print_bold($action . " successful");
}
}
/**
* Print error and set HTTP status code.
*
* Print a error message in bold and set a 500 HTTP Error status. Additionally
* it exits the process.
*
* @param string $error_msg Error message that should be printed.
*
* @return void
*/
function handle_error($error_msg)
{
print_bold($error_msg);
http_response_code(500);
exit();
}
/**
* Read and parse configuration.
*
* Read the JSON configuration defined in CONFIG_FILE and parse it.
*
* @return array|null configuration
*/
function parse_config()
{
if (is_readable(CONFIG_FILE)) {
$config_data = file_get_contents(CONFIG_FILE);
return json_decode($config_data, true);
} else {
handle_error("Config file not found or not readable");
}
}
/**
* Verify and complete config.
*
* The configuration values "secret", "local-path" and "remote-path" are
* checked for existence and "branch" is set to "master" if not defined.
*
* @param array $config configuration array
*
* @return void
*/
function verify_config(&$config)
{
# Check if secret is set (config and GET parameter).
if (!isset($_GET["secret"])) {
handle_error("No secret given.");
}
# Check if local path is set
if (!isset($config["local-path"])) {
handle_error("No local path given.");
}
# Check if remote path is set
if (!isset($config["remote-path"])) {
handle_error("No remote path given.");
}
# Define branch name
if (!isset($config["branch"])) {
$config["branch"] = master;
}
}
/**
* Authenticate using the given secrets.
*
* Compares the secret stored in the configuration and the one given as secret
* get parameter.
*
* @param string $secret secret defined in the configuration
*
* @return void
*/
function authenticate($secret)
{
# Check if secret is set (config and GET parameter).
if (!isset($_GET["secret"])) {
handle_error("No secret as GET parameter given.");
}
# Compare given secrets
if (strcmp($secret, htmlspecialchars($_GET["secret"])) == 0) {
print_bold("Authentication sucessfull!");
} else {
handle_error("Authentication failed!");
}
}
/**
* Run git fetch and git checkout in the local repository.
*
* The changes for the specified branch will be fetched and the branch checked
* out.
*
* @param string $local_path path of the local repository
* @param string $branch branch name that should be checked out
*
* @return void
*/
function git_pull($local_path, $branch)
{
if (is_writable($local_path . "/.git")) {
# Switch to local repository
chdir($local_path);
# Fetch changes for pre-configured branch
print_bold("Fetching " . $branch . " branch.");
exec("git fetch --progress origin " . $branch . " 2>&1", $output, $return_var);
print_git_output($output);
handle_status($return_var, "Fetching");
# Switch to pre-configured branch
print_bold("Switching to " . $branch . " branch");
exec("git checkout --progress " . $branch . " 2>&1", $output, $return_var);
print_git_output($output);
handle_status($return_var, "Checkout");
} else {
handle_error("No .git directory found, but directory already exists.");
}
}
/**
* Run git clone in the local path.
*
* If the git repository is not yet created the given branch will be cloned.
*
* @param string $local_path Path of local repository
* @param string $remote_path Path/URL of remote repository
* @param string $branch Name of working branch
*
* @return void
*/
function git_clone($local_path, $remote_path, $branch)
{
# Clone remote repository into local path
print_bold("Repository doesn't exists. Trying to clone.");
exec("git clone --progress --branch=" . $branch . " " . $remote_path . " " . $local_path . " 2>&1", $output, $return_var);
print_git_output($output);
handle_status($return_var, "Cloning");
}
/**
* Main entry function.
*
* @return void
*/
function main()
{
# Preparations
$config = parse_config();
verify_config($config);
authenticate($config["secret"]);
# Actual deploy operations
if (is_writable($config["local-path"])) {
git_pull($config["local-path"], $config["branch"]);
} elseif (is_writable(dirname($config["local-path"]))) {
git_clone($config["local-path"], $config["remote-path"], $config["branch"]);
} else {
handle_error("Path doesn't exists, can't created or is not writable");
}
}
main();