Skip to content
Draft
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
5 changes: 0 additions & 5 deletions Installer/Distribution/Defaults/deploy.php

This file was deleted.

31 changes: 23 additions & 8 deletions Installer/Distribution/Defaults/deploy.yaml
Original file line number Diff line number Diff line change
@@ -1,20 +1,35 @@
# To start a deployment or the
# installation run `dep deploy`

# The target domain
domain.tld:
# Put here the hostname
# https://dashboard.uberspace.de/dashboard/datasheet
hostname: __SERVER__.uberspace.de

# Put here the Uberspace username
user: __USER__
import: Build/Uberspace.Deployer/config.yaml

# If you put settings under config, these will be set as default for every host.
# Be aware that you can override these settings per host.
# The hostname has to be set under the hosts section.
config:
# Put here the ssh repository
repository: [email protected]:__OWNER__/__REPOSITORY__.git
# Put here the Uberspace username
remote_user: __USER__
# You can add labels to the deployment
# labels:
# stage: production

# Set this to true if you use ddev for local development
ddev: false

# Add here the slack webhook (optional)
# slack_webhook: https://hooks.slack.com/services/__YOUR/SLACK/WEBHOOK__

# The hosts section defines the hosts that will be deployed.
hosts:
# The target domain
domain.tld:
# Put here the hostname
# https://dashboard.uberspace.de/dashboard/datasheet
hostname: __SERVER__.uberspace.de

# You can override settings from config here, for example the labels
# This is very useful for staging and production environments
# labels:
# stage: production
178 changes: 178 additions & 0 deletions Task/Git.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
<?php

namespace Deployer;

use InvalidArgumentException;
use DateTime;
use DateTimeZone;
use function array_key_first;
use function count;
use function is_array;
use function is_string;
use function strpos;
use function substr;
use function wordwrap;

desc('Commit current changes to git');
task('git:commit', static function (): void {
$types = get('git_commit_types');
$pwd = get('local_pwd');
if (!is_array($types) || !count($types)) {
throw new InvalidArgumentException('`git_commit_types` should be an array and not empty');
}

if (!runLocally('git diff --name-only --cached', ['cwd' => $pwd])) {
writeln('');
if (!askConfirmationInput('There are no files staged. Do you want to add all files?')) {
exit(1);
}
runLocally('git add .');
}

$crop = 100;
writebox(
"Line 1 will be cropped at $crop characters. <br>All other lines will be wrapped after $crop characters.",
null
);
// Cropping is index based, so we need to add 2
$crop = $crop + 2;

$type = askChoiceln(
'Select the type of change that you\'re committing',
$types,
array_key_first($types)
);
writeCleanLine();
$type .= ':';
$short = askln('Write a short, imperative tense description of the change:', true, null, false, $type);
$long = askln('Provide a longer description of the change: (press enter to skip)');

$breaking = null;
if ($type !== 'Breaking:') {
$breaking = askConfirmationInput('Are there any breaking changes?', 'Describe the breaking changes:');
}
$issues = askConfirmationInput('Does this change affect any open issues?', 'Add issue references (e.g. "fix #123", "re #123".):');

$output = substr("$type $short", 0, $crop);
if (is_string($long)) {
$output .= "\n\n" . wordwrap($long, $crop);
}
if (is_string($breaking)) {
$output .= "\n\n" . wordwrap("BREAKING CHANGE: $breaking", $crop);
}
if (is_string($issues)) {
$output .= "\n\n" . wordwrap($issues, $crop);
}
$output = str_replace('"', '\"', $output);
runLocally("git commit -m \"$output\"", ['cwd' => $pwd]);

writeCleanLine();
})->once();

desc('Create release tag on git');
task('git:tag', static function (): void {
$latest = 'git describe --tags $(git rev-list --tags --max-count=1)';
if (!testLocally($latest . '>/dev/null 2>&1')) {
$tag = askln('Please enter a tag name', true);
} else {
$latest = runLocally($latest);
$type = askChoiceln("Latest tag is $latest. Choose type of release", [
"Patch",
"Minor",
"Major"
]);
$prefix = '';
// Check if $latest starts with an "v"
if (strpos($latest, 'v') === 0) {
$prefix = 'v';
$latest = substr($latest, 1);
}

$split = explode('.', $latest);
$patch = (int) array_pop($split);
$minor = (int) array_pop($split);
$major = (int) array_pop($split);

switch ($type) {
case 'Patch':
$patch++;
break;
case 'Minor':
$patch = 0;
$minor++;
break;
case 'Major':
$patch = 0;
$minor = 0;
$major++;
break;
}
$tag = sprintf('%s%d.%d.%d', $prefix, $major, $minor, $patch);
}

$gh = get('local/gh');

$date = (new DateTime('now', new DateTimeZone('UTC')))->format(DateTime::RFC850);
$description = askln(
'Add a description for the tag',
false,
"Deployment on $date"
);
runLocally("git tag -a -m '$description' '$tag'");
runLocally('git push origin --tags');
if ($gh) {
runLocally("$gh release create $tag --generate-notes");
}
})->once();

desc('Set the know host for the SSH_KNOWN_HOSTS secret');
task('git:ssh:know_hosts', static function (): void {
$gh = get('local/gh');
secretFeedback('SSH_KNOWN_HOSTS', (bool)$gh);
$keys = '';
foreach (getAllHostnames() as $hostname) {
$key = trim(runLocally("ssh-keyscan $hostname"));
$keys .= $key;
writeCleanLine("<info>$key</info>");
}
var_dump(timestamp());

if ($gh) {
// runLocally("$gh secret set SSH_KNOWN_HOSTS --body '$keys'");
}
})->once();

desc('Set the private key for SSH_PRIVATE_KEY secret and upload public key to host');
task('git:ssh:key', static function (): void {
$gh = get('local/gh');
runLocally('ssh-keygen -q -t rsa -b 4096 -N "" -C "Github Actions" -f __temp_ssh_key');
$private = runLocally('cat __temp_ssh_key');
$public = runLocally('cat __temp_ssh_key.pub');
secretFeedback('SSH_PRIVATE_KEY', (bool)$gh);
if ($gh) {
runLocally("$gh secret set SSH_PRIVATE_KEY --body '$private'");
}
writeln("<info>$private</info>");
on(Deployer::get()->hosts, function () use ($public) {
$file = run("cat ~/.ssh/authorized_keys");
if (strpos($file, $public) === false) {
run("echo '$public' >> ~/.ssh/authorized_keys");
writebox('The public key was added to authorized_keys on the host {{alias}}');
}
});
runLocally('rm -f __temp_ssh_key __temp_ssh_key.pub');
})->once();

/**
* @param string $key
* @param boolean $hasGithubCLI
* @return void
*/
function secretFeedback(string $key, bool $hasGithubCLI): void
{
if ($hasGithubCLI) {
writebox("Follow entry was made as <strong>$key</strong> secret on github:");
return;
}
writebox("Put this value as <strong>$key</strong> secret on github:");
}
165 changes: 165 additions & 0 deletions Task/Server.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
<?php

namespace Deployer;

use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Output\OutputInterface;
use function array_diff;
use function array_values;
use function explode;
use function implode;
use function preg_match;
use function sizeof;
use function str_replace;
use function substr_count;

desc('Edit the cronjobs');
task('server:cronjob', static function (): void {
ttyRun('crontab -e');
});

desc('Restart PHP');
task('server:php:restart', static function (): void {
run('uberspace tools restart php');
});

desc('Set the PHP version on the server');
task('server:php:version', static function (): void {
preg_match('/(PHP [\d\.]+)/', run('php -v'), $currentVersion);
$currentVersion = $currentVersion[0];

preg_match('/(\d\.\d)/', $currentVersion, $currentVersionShort);
$currentVersionShort = $currentVersionShort[0];

writebox("<strong>Set PHP version on uberspace</strong><br><br><strong>Current version:</strong><br>$currentVersion");

$availableVersions = run('uberspace tools version list php');
$versionsList = explode(\PHP_EOL, str_replace('- ', '', $availableVersions));
$version = askChoiceln('Please choose the desired version', $versionsList);

if ($version !== $currentVersionShort) {
$output = run("uberspace tools version use php $version");
writebox($output, 'bgSuccess');
return;
}
writebox("As PHP is already set to $version,<br>no configuration was changed");
});

desc('Add a domain to uberspace');
task('server:domain:add', static function (): void {
writebox('Get list of domains, please wait...', null);
$currentEntry = run('uberspace web domain list');
$alias = parse('alias');
writebox("<strong>Add a domain to uberspace</strong>
If you have multiple domains, you will be asked
after every entry if you wand to add another domain.

<strong>Current entry:</strong>
$currentEntry

To cancel enter <strong>exit</strong> as answer");
// Check if the alias seems to have a subdomain
$wwwDomain = 'www.' . $alias;
$defaultDomain = substr_count($alias, '.') > 1 ? $alias : $wwwDomain;
$suggestions = [$alias, $wwwDomain];
$firstDomain = askDomain('Please enter the domain', $defaultDomain, $suggestions);
if ($firstDomain === 'exit') {
return;
}
$domains = [
$firstDomain
];
writeln('');
while ($domain = askDomain('Please enter another domain or press enter to continue', null, $suggestions)) {
if ($domain === 'exit') {
return;
}
if ($domain) {
$domains[] = $domain;
}
writeln('');
}
$outputDomains = implode("\n", $domains);
$ip = '';
writebox('Adding domains, please wait...');
foreach ($domains as $domain) {
$ip = run("uberspace web domain add $domain");
}
writebox("<strong>Following entries are added:</strong><br><br>$outputDomains<br><br>$ip", 'green');
});

desc('Remove a domain from uberspace');
task('server:domain:remove', static function (): void {
writebox('Get list of domains, please wait...', null);
$currentEntry = run('uberspace web domain list');

if ($currentEntry == parse('{{remote_user}}.uber.space')) {
writebox('<strong>No domains to remove</strong>');
return;
}

writebox("<strong>Remove a domain from uberspace</strong>
If you have multiple domains, you will be asked
after every entry if you wand to remove another domain.

<strong>Current entry:</strong>
$currentEntry

To finish the setup, press enter or choose the last entry");

$currentEntriesArray = explode(\PHP_EOL, $currentEntry);
$currentEntriesArray[] = 'Finish setup';
$domains = [];

while ($domain = askChoiceln('Please choose the domain you want to remove', $currentEntriesArray, sizeof($currentEntriesArray) - 1)) {
if ($domain === 'Finish setup') {
break;
}
$currentEntriesArray = array_values(array_diff($currentEntriesArray, [$domain]));
$domains[] = $domain;
}
if (sizeof($domains)) {
$outputDomains = implode("\n", $domains);
writebox('Removing domains, please wait...');
foreach ($domains as $domain) {
run("uberspace web domain del $domain");
}
writebox('<strong>Following entries are removed:</strong><br><br>' . $outputDomains, 'bgSuccess');
} else {
writebox('<strong>No Domains where removed</strong>', 'error');
}
});

desc('List all domains and subdomains');
task('server:domain:list', static function (): void {
writebox('Get list of domains, please wait...', null);
$currentEntry = run('uberspace web domain list');
writebox("<strong>Registered domains on the uberspace account \"{{remote_user}}\"</strong>

$currentEntry");
});

desc('Create and/or read the deployment key');
task('server:ssh_key', static function (): void {
if (!test('[ -f ~/.ssh/{{ssh_key}}.pub ]')) {
// -q Silence key generation
// -t Set algorithm
// -b Specifies the number of bits in the key
// -N Set the passphrase
// -C Comment for the key
// -f Specifies name of the file in which to store the created key
run('cat /dev/zero | ssh-keygen -q -t rsa -b 4096 -N "" -C "$(hostname -f)" -f ~/.ssh/{{ssh_key}}');
}

// We dont use `ssh-keygen -y` because we also want to output the comment
writebox('The public key ({{ssh_key}}.pub) from <strong>{{alias}} </strong> is:');
writeln('<info>' . run('cat ~/.ssh/{{ssh_key}}.pub') . '</info>');
writeln('');

$sshKnowHostsFile = '~/.ssh/known_hosts';
$repoHost = get('repository_url_parts')['host'];

if (!test("grep -q '$repoHost' $sshKnowHostsFile")) {
run("ssh-keyscan $repoHost >> $sshKnowHostsFile");
}
});
Loading