Initial commit
This commit is contained in:
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
/vendor/
|
||||
composer.lock
|
||||
.phpunit.result.cache
|
||||
.phpunit.cache
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Zura
|
||||
|
||||
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.
|
||||
195
README.md
Normal file
195
README.md
Normal file
@@ -0,0 +1,195 @@
|
||||
# Laravel Hostinger Deploy
|
||||
|
||||
A Laravel package for automated deployment to Hostinger shared hosting with GitHub Actions support.
|
||||
|
||||
## Features
|
||||
|
||||
- 🚀 **One-command deployment** to Hostinger shared hosting
|
||||
- 🔄 **GitHub Actions integration** for automated deployments
|
||||
- 🔑 **Automatic SSH key management** for secure connections
|
||||
- 📦 **Laravel-specific optimizations** (composer, migrations, storage links)
|
||||
- ⚙️ **Configurable deployment options** via config file
|
||||
|
||||
## Installation
|
||||
|
||||
Install the package via Composer:
|
||||
|
||||
```bash
|
||||
composer require zura/laravel-hostinger-deploy --dev
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### 1. Environment Variables
|
||||
|
||||
Add the following variables to your `.env` file:
|
||||
|
||||
```env
|
||||
# Hostinger Deployment Configuration
|
||||
HOSTINGER_SSH_HOST=your-server-ip
|
||||
HOSTINGER_SSH_USERNAME=your-username
|
||||
HOSTINGER_SSH_PORT=22
|
||||
HOSTINGER_SITE_DIR=your-website-folder
|
||||
```
|
||||
|
||||
### 2. Publish Configuration (Optional)
|
||||
|
||||
Publish the configuration file to customize deployment options:
|
||||
|
||||
```bash
|
||||
php artisan vendor:publish --tag=hostinger-deploy-config
|
||||
```
|
||||
|
||||
This will create `config/hostinger-deploy.php` with customizable options.
|
||||
|
||||
## Usage
|
||||
|
||||
### 1. Deploy to Hostinger
|
||||
|
||||
Deploy your Laravel application to Hostinger shared hosting:
|
||||
|
||||
```bash
|
||||
php artisan hostinger:deploy-shared
|
||||
```
|
||||
|
||||
**Options:**
|
||||
- `--fresh`: Delete existing files and clone fresh repository
|
||||
- `--site-dir=`: Override site directory from config
|
||||
|
||||
### 2. Publish GitHub Actions Workflow
|
||||
|
||||
Create a GitHub Actions workflow file for automated deployments:
|
||||
|
||||
```bash
|
||||
php artisan hostinger:publish-workflow
|
||||
```
|
||||
|
||||
**Options:**
|
||||
- `--branch=`: Override default branch (default: auto-detect)
|
||||
- `--php-version=`: Override PHP version (default: 8.3)
|
||||
|
||||
### 3. Setup Automated Deployment
|
||||
|
||||
Configure SSH keys and display GitHub secrets for automated deployment:
|
||||
|
||||
```bash
|
||||
php artisan hostinger:auto-deploy
|
||||
```
|
||||
|
||||
This command will:
|
||||
- Generate SSH keys on your Hostinger server
|
||||
- Display all required GitHub secrets and variables
|
||||
- Provide step-by-step instructions for GitHub setup
|
||||
|
||||
## GitHub Actions Setup
|
||||
|
||||
After running `php artisan hostinger:auto-deploy`, you'll need to add the following to your GitHub repository:
|
||||
|
||||
### Secrets (Repository Settings → Secrets and variables → Actions → Secrets)
|
||||
|
||||
- `SSH_HOST`: Your Hostinger server IP address
|
||||
- `SSH_USERNAME`: Your Hostinger SSH username
|
||||
- `SSH_PORT`: Your Hostinger SSH port (usually 22)
|
||||
- `SSH_KEY`: Your private SSH key (displayed by the command)
|
||||
|
||||
### Variables (Repository Settings → Secrets and variables → Actions → Variables)
|
||||
|
||||
- `WEBSITE_FOLDER`: Your Hostinger website folder name
|
||||
|
||||
### Deploy Keys (Repository Settings → Deploy keys)
|
||||
|
||||
Add the public SSH key displayed by the `auto-deploy` command as a deploy key.
|
||||
|
||||
## Workflow
|
||||
|
||||
The generated GitHub Actions workflow will:
|
||||
|
||||
1. **Checkout code** from your repository
|
||||
2. **Setup PHP** environment
|
||||
3. **Install dependencies** via Composer
|
||||
4. **Generate application key** and create storage link
|
||||
5. **Run database migrations**
|
||||
6. **Deploy to Hostinger** via SSH
|
||||
7. **Update code** on the server and run optimizations
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### SSH Settings
|
||||
|
||||
```php
|
||||
'ssh' => [
|
||||
'host' => env('HOSTINGER_SSH_HOST'),
|
||||
'username' => env('HOSTINGER_SSH_USERNAME'),
|
||||
'port' => env('HOSTINGER_SSH_PORT', 22),
|
||||
'timeout' => 30,
|
||||
],
|
||||
```
|
||||
|
||||
### Deployment Settings
|
||||
|
||||
```php
|
||||
'deployment' => [
|
||||
'site_dir' => env('HOSTINGER_SITE_DIR'),
|
||||
'composer_flags' => '--no-dev --optimize-autoloader',
|
||||
'run_migrations' => true,
|
||||
'run_storage_link' => true,
|
||||
'run_config_cache' => false,
|
||||
'run_route_cache' => false,
|
||||
'run_view_cache' => false,
|
||||
],
|
||||
```
|
||||
|
||||
### GitHub Actions Settings
|
||||
|
||||
```php
|
||||
'github' => [
|
||||
'workflow_file' => '.github/workflows/hostinger-deploy.yml',
|
||||
'php_version' => '8.3',
|
||||
'default_branch' => 'main',
|
||||
],
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
- PHP ^8.2
|
||||
- Laravel ^11.0|^12.0
|
||||
- SSH access to Hostinger server
|
||||
- Git repository with GitHub integration
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### SSH Connection Issues
|
||||
|
||||
1. Verify your SSH credentials in `.env`
|
||||
2. Test SSH connection manually: `ssh -p PORT USERNAME@HOST`
|
||||
3. Ensure SSH key authentication is working
|
||||
|
||||
### GitHub Actions Issues
|
||||
|
||||
1. Verify all secrets and variables are correctly set
|
||||
2. Check that the deploy key is added to your repository
|
||||
3. Ensure the workflow file is committed and pushed
|
||||
|
||||
### Deployment Issues
|
||||
|
||||
1. Check that your Hostinger server has Composer installed
|
||||
2. Verify the site directory exists and is writable
|
||||
3. Ensure your Laravel application is properly configured
|
||||
|
||||
## Security Notes
|
||||
|
||||
- SSH keys are generated on the server and should be kept secure
|
||||
- Private keys are displayed for GitHub setup - copy them carefully
|
||||
- The package uses SSH key authentication for secure deployments
|
||||
|
||||
## License
|
||||
|
||||
This package is open-sourced software licensed under the [MIT license](LICENSE).
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome! Please feel free to submit a Pull Request.
|
||||
|
||||
## Support
|
||||
|
||||
If you encounter any issues or have questions, please open an issue on GitHub.
|
||||
52
composer.json
Normal file
52
composer.json
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"name": "zura/laravel-hostinger-deploy",
|
||||
"description": "Laravel package for automated Hostinger deployment with GitHub Actions support",
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"laravel",
|
||||
"hostinger",
|
||||
"deployment",
|
||||
"github-actions",
|
||||
"ssh"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Zura",
|
||||
"email": "zura@example.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^8.2",
|
||||
"illuminate/support": "^11.0|^12.0",
|
||||
"illuminate/console": "^11.0|^12.0",
|
||||
"illuminate/process": "^11.0|^12.0",
|
||||
"symfony/console": "^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^10.0",
|
||||
"orchestra/testbench": "^8.0|^9.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Zura\\HostingerDeploy\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Zura\\HostingerDeploy\\Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Zura\\HostingerDeploy\\HostingerDeployServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"minimum-stability": "stable",
|
||||
"prefer-stable": true,
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
}
|
||||
}
|
||||
235
src/Commands/AutoDeployCommand.php
Normal file
235
src/Commands/AutoDeployCommand.php
Normal file
@@ -0,0 +1,235 @@
|
||||
<?php
|
||||
|
||||
namespace Zura\HostingerDeploy\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Zura\HostingerDeploy\Services\SshConnectionService;
|
||||
use Zura\HostingerDeploy\Services\GitHubActionsService;
|
||||
|
||||
class AutoDeployCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*/
|
||||
protected $signature = 'hostinger:auto-deploy';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*/
|
||||
protected $description = 'Setup SSH keys and display GitHub secrets for automated deployment';
|
||||
|
||||
protected SshConnectionService $ssh;
|
||||
protected GitHubActionsService $github;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->github = new GitHubActionsService();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
$this->info('🔧 Setting up automated deployment...');
|
||||
|
||||
// Validate configuration
|
||||
if (!$this->validateConfiguration()) {
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
// Get repository information
|
||||
$repoInfo = $this->getRepositoryInfo();
|
||||
if (!$repoInfo) {
|
||||
$this->error('❌ Could not detect repository information. Please run this command from a Git repository.');
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$this->info("📦 Repository: {$repoInfo['owner']}/{$repoInfo['name']}");
|
||||
|
||||
// Setup SSH connection
|
||||
$this->setupSshConnection();
|
||||
|
||||
// Test SSH connection
|
||||
if (!$this->ssh->testConnection()) {
|
||||
$this->error('❌ SSH connection failed. Please check your SSH configuration.');
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$this->info('✅ SSH connection successful');
|
||||
|
||||
// Setup SSH keys
|
||||
if (!$this->setupSshKeys()) {
|
||||
$this->error('❌ Failed to setup SSH keys');
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
// Display GitHub secrets
|
||||
$this->displayGitHubSecrets($repoInfo);
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate required configuration.
|
||||
*/
|
||||
protected function validateConfiguration(): bool
|
||||
{
|
||||
$required = [
|
||||
'HOSTINGER_SSH_HOST' => config('hostinger-deploy.ssh.host'),
|
||||
'HOSTINGER_SSH_USERNAME' => config('hostinger-deploy.ssh.username'),
|
||||
'HOSTINGER_SITE_DIR' => config('hostinger-deploy.deployment.site_dir'),
|
||||
];
|
||||
|
||||
foreach ($required as $key => $value) {
|
||||
if (empty($value)) {
|
||||
$this->error("❌ Missing required environment variable: {$key}");
|
||||
$this->info("Please add {$key} to your .env file");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get repository information.
|
||||
*/
|
||||
protected function getRepositoryInfo(): ?array
|
||||
{
|
||||
if (!$this->github->isGitRepository()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->github->getRepositoryInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup SSH connection service.
|
||||
*/
|
||||
protected function setupSshConnection(): void
|
||||
{
|
||||
$this->ssh = new SshConnectionService(
|
||||
config('hostinger-deploy.ssh.host'),
|
||||
config('hostinger-deploy.ssh.username'),
|
||||
config('hostinger-deploy.ssh.port', 22),
|
||||
config('hostinger-deploy.ssh.timeout', 30)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup SSH keys on the server.
|
||||
*/
|
||||
protected function setupSshKeys(): bool
|
||||
{
|
||||
try {
|
||||
// Generate SSH keys if they don't exist
|
||||
if (!$this->ssh->sshKeyExists()) {
|
||||
$this->info('🔑 Generating SSH keys on server...');
|
||||
if (!$this->ssh->generateSshKey()) {
|
||||
$this->error('❌ Failed to generate SSH keys');
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$this->info('🔑 SSH keys already exist on server');
|
||||
}
|
||||
|
||||
// Get the public key
|
||||
$publicKey = $this->ssh->getPublicKey();
|
||||
if (!$publicKey) {
|
||||
$this->error('❌ Could not retrieve public key from server');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add public key to authorized_keys
|
||||
$this->info('🔐 Adding public key to authorized_keys...');
|
||||
if (!$this->ssh->addToAuthorizedKeys($publicKey)) {
|
||||
$this->error('❌ Failed to add public key to authorized_keys');
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->info('✅ SSH keys setup completed');
|
||||
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
$this->error("SSH keys setup error: " . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display GitHub secrets and variables for manual setup.
|
||||
*/
|
||||
protected function displayGitHubSecrets(array $repoInfo): void
|
||||
{
|
||||
$this->line('');
|
||||
$this->info('🔒 GitHub Secrets and Variables Setup');
|
||||
$this->line('');
|
||||
|
||||
// Get private key
|
||||
$privateKey = $this->ssh->getPrivateKey();
|
||||
if (!$privateKey) {
|
||||
$this->error('❌ Could not retrieve private key from server');
|
||||
return;
|
||||
}
|
||||
|
||||
// Display secrets
|
||||
$this->warn('📋 Add these secrets to your GitHub repository:');
|
||||
$this->line('Go to: ' . $repoInfo['secrets_url']);
|
||||
$this->line('');
|
||||
|
||||
$secrets = [
|
||||
'SSH_HOST' => config('hostinger-deploy.ssh.host'),
|
||||
'SSH_USERNAME' => config('hostinger-deploy.ssh.username'),
|
||||
'SSH_PORT' => (string) config('hostinger-deploy.ssh.port', 22),
|
||||
'SSH_KEY' => $privateKey,
|
||||
];
|
||||
|
||||
foreach ($secrets as $name => $value) {
|
||||
$this->line("🔑 {$name}:");
|
||||
if ($name === 'SSH_KEY') {
|
||||
$this->line(' [Copy the private key below]');
|
||||
$this->line('');
|
||||
$this->line(' ' . str_repeat('-', 50));
|
||||
$this->line($value);
|
||||
$this->line(' ' . str_repeat('-', 50));
|
||||
} else {
|
||||
$this->line(" {$value}");
|
||||
}
|
||||
$this->line('');
|
||||
}
|
||||
|
||||
// Display variables
|
||||
$this->warn('📊 Add this variable to your GitHub repository:');
|
||||
$this->line('Go to: ' . $repoInfo['variables_url']);
|
||||
$this->line('');
|
||||
|
||||
$this->line("📊 WEBSITE_FOLDER:");
|
||||
$this->line(" " . config('hostinger-deploy.deployment.site_dir'));
|
||||
$this->line('');
|
||||
|
||||
// Display deploy key information
|
||||
$this->warn('🔑 Deploy Key Information:');
|
||||
$this->line('Go to: ' . $repoInfo['deploy_keys_url']);
|
||||
$this->line('');
|
||||
|
||||
$publicKey = $this->ssh->getPublicKey();
|
||||
$this->line('Add this public key as a Deploy Key:');
|
||||
$this->line('');
|
||||
$this->line(' ' . str_repeat('-', 50));
|
||||
$this->line($publicKey);
|
||||
$this->line(' ' . str_repeat('-', 50));
|
||||
$this->line('');
|
||||
|
||||
// Display next steps
|
||||
$this->info('🎉 Setup completed! Next steps:');
|
||||
$this->line('');
|
||||
$this->line('1. Add all the secrets and variables shown above to GitHub');
|
||||
$this->line('2. Add the deploy key to your repository');
|
||||
$this->line('3. Run: php artisan hostinger:publish-workflow');
|
||||
$this->line('4. Push your changes to trigger the workflow');
|
||||
$this->line('');
|
||||
$this->info('🚀 Your repository will now automatically deploy on push!');
|
||||
}
|
||||
}
|
||||
237
src/Commands/DeploySharedCommand.php
Normal file
237
src/Commands/DeploySharedCommand.php
Normal file
@@ -0,0 +1,237 @@
|
||||
<?php
|
||||
|
||||
namespace Zura\HostingerDeploy\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Zura\HostingerDeploy\Services\SshConnectionService;
|
||||
use Zura\HostingerDeploy\Services\GitHubActionsService;
|
||||
|
||||
class DeploySharedCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*/
|
||||
protected $signature = 'hostinger:deploy-shared
|
||||
{--fresh : Delete and clone fresh repository}
|
||||
{--site-dir= : Override site directory from config}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*/
|
||||
protected $description = 'Deploy Laravel application to Hostinger shared hosting';
|
||||
|
||||
protected SshConnectionService $ssh;
|
||||
protected GitHubActionsService $github;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->github = new GitHubActionsService();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
$this->info('🚀 Starting Hostinger deployment...');
|
||||
|
||||
// Validate configuration
|
||||
if (!$this->validateConfiguration()) {
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
// Get repository URL
|
||||
$repoUrl = $this->getRepositoryUrl();
|
||||
if (!$repoUrl) {
|
||||
$this->error('❌ Could not detect Git repository URL. Please run this command from a Git repository.');
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$this->info("📦 Repository: {$repoUrl}");
|
||||
|
||||
// Setup SSH connection
|
||||
$this->setupSshConnection();
|
||||
|
||||
// Test SSH connection
|
||||
if (!$this->ssh->testConnection()) {
|
||||
$this->error('❌ SSH connection failed. Please check your SSH configuration.');
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$this->info('✅ SSH connection successful');
|
||||
|
||||
// Deploy to server
|
||||
if (!$this->deployToServer($repoUrl)) {
|
||||
$this->error('❌ Deployment failed');
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$this->info('🎉 Deployment completed successfully!');
|
||||
$this->info("🌐 Your Laravel application is now live at: https://{$this->getSiteDir()}");
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate required configuration.
|
||||
*/
|
||||
protected function validateConfiguration(): bool
|
||||
{
|
||||
$required = [
|
||||
'HOSTINGER_SSH_HOST' => config('hostinger-deploy.ssh.host'),
|
||||
'HOSTINGER_SSH_USERNAME' => config('hostinger-deploy.ssh.username'),
|
||||
'HOSTINGER_SITE_DIR' => $this->getSiteDir(),
|
||||
];
|
||||
|
||||
foreach ($required as $key => $value) {
|
||||
if (empty($value)) {
|
||||
$this->error("❌ Missing required environment variable: {$key}");
|
||||
$this->info("Please add {$key} to your .env file");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get repository URL from Git.
|
||||
*/
|
||||
protected function getRepositoryUrl(): ?string
|
||||
{
|
||||
$repoUrl = $this->github->getRepositoryUrl();
|
||||
|
||||
if (!$repoUrl) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->info("✅ Detected Git repository: {$repoUrl}");
|
||||
|
||||
if (!$this->confirm('Use this repository for deployment?')) {
|
||||
$repoUrl = $this->ask('Enter your Git repository URL');
|
||||
}
|
||||
|
||||
return $repoUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup SSH connection service.
|
||||
*/
|
||||
protected function setupSshConnection(): void
|
||||
{
|
||||
$this->ssh = new SshConnectionService(
|
||||
config('hostinger-deploy.ssh.host'),
|
||||
config('hostinger-deploy.ssh.username'),
|
||||
config('hostinger-deploy.ssh.port', 22),
|
||||
config('hostinger-deploy.ssh.timeout', 30)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deploy application to server.
|
||||
*/
|
||||
protected function deployToServer(string $repoUrl): bool
|
||||
{
|
||||
$siteDir = $this->getSiteDir();
|
||||
$isFresh = $this->option('fresh');
|
||||
|
||||
try {
|
||||
// Setup SSH keys if needed
|
||||
$this->setupSshKeys();
|
||||
|
||||
// Prepare deployment commands
|
||||
$commands = $this->buildDeploymentCommands($repoUrl, $siteDir, $isFresh);
|
||||
|
||||
// Execute deployment
|
||||
$this->info('📦 Deploying application...');
|
||||
$this->ssh->executeMultiple($commands);
|
||||
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
$this->error("Deployment error: " . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup SSH keys on server if needed.
|
||||
*/
|
||||
protected function setupSshKeys(): void
|
||||
{
|
||||
if (!$this->ssh->sshKeyExists()) {
|
||||
$this->info('🔑 Generating SSH keys on server...');
|
||||
$this->ssh->generateSshKey();
|
||||
|
||||
$publicKey = $this->ssh->getPublicKey();
|
||||
if ($publicKey) {
|
||||
$this->warn('🔑 Add this SSH key to your GitHub repository:');
|
||||
$this->warn(' Settings → Deploy keys → Add deploy key');
|
||||
$this->line('');
|
||||
$this->line($publicKey);
|
||||
$this->line('');
|
||||
|
||||
if (!$this->confirm('Press ENTER after adding the key to GitHub...')) {
|
||||
throw new \Exception('SSH key setup cancelled');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->info('🔑 SSH keys already configured');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build deployment commands.
|
||||
*/
|
||||
protected function buildDeploymentCommands(string $repoUrl, string $siteDir, bool $isFresh): array
|
||||
{
|
||||
$commands = [];
|
||||
|
||||
// Navigate to site directory
|
||||
$commands[] = "mkdir -p domains/{$siteDir}";
|
||||
$commands[] = "cd domains/{$siteDir}";
|
||||
|
||||
// Remove public_html if exists
|
||||
$commands[] = "rm -rf public_html";
|
||||
|
||||
if ($isFresh) {
|
||||
// Fresh deployment - delete everything and clone
|
||||
$commands[] = "rm -rf * .[^.]* 2>/dev/null || true";
|
||||
$commands[] = "git clone {$repoUrl} .";
|
||||
} else {
|
||||
// Check if repository exists
|
||||
$commands[] = "if [ -d .git ]; then git pull; else git clone {$repoUrl} .; fi";
|
||||
}
|
||||
|
||||
// Install dependencies
|
||||
$composerFlags = config('hostinger-deploy.deployment.composer_flags', '--no-dev --optimize-autoloader');
|
||||
$commands[] = "composer install {$composerFlags}";
|
||||
|
||||
// Copy .env.example to .env
|
||||
$commands[] = "if [ -f .env.example ]; then cp .env.example .env; fi";
|
||||
|
||||
// Create symbolic link for Laravel public folder
|
||||
$commands[] = "if [ -d public ]; then ln -s public public_html; fi";
|
||||
|
||||
// Laravel setup
|
||||
$commands[] = "php artisan key:generate --quiet";
|
||||
|
||||
if (config('hostinger-deploy.deployment.run_migrations', true)) {
|
||||
$commands[] = "echo 'yes' | php artisan migrate --quiet";
|
||||
}
|
||||
|
||||
if (config('hostinger-deploy.deployment.run_storage_link', true)) {
|
||||
$commands[] = "php artisan storage:link --quiet";
|
||||
}
|
||||
|
||||
return $commands;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get site directory from option or config.
|
||||
*/
|
||||
protected function getSiteDir(): string
|
||||
{
|
||||
return $this->option('site-dir') ?: config('hostinger-deploy.deployment.site_dir');
|
||||
}
|
||||
}
|
||||
155
src/Commands/PublishWorkflowCommand.php
Normal file
155
src/Commands/PublishWorkflowCommand.php
Normal file
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
|
||||
namespace Zura\HostingerDeploy\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Zura\HostingerDeploy\Services\GitHubActionsService;
|
||||
|
||||
class PublishWorkflowCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*/
|
||||
protected $signature = 'hostinger:publish-workflow
|
||||
{--branch= : Override default branch}
|
||||
{--php-version= : Override PHP version}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*/
|
||||
protected $description = 'Publish GitHub Actions workflow file for automated deployment';
|
||||
|
||||
protected GitHubActionsService $github;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->github = new GitHubActionsService();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
$this->info('📄 Publishing GitHub Actions workflow...');
|
||||
|
||||
// Check if we're in a Git repository
|
||||
if (!$this->github->isGitRepository()) {
|
||||
$this->error('❌ Not in a Git repository. Please run this command from a Git repository.');
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
// Get repository information
|
||||
$repoInfo = $this->github->getRepositoryInfo();
|
||||
if (!$repoInfo) {
|
||||
$this->error('❌ Could not detect repository information.');
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$this->info("📦 Repository: {$repoInfo['owner']}/{$repoInfo['name']}");
|
||||
$this->info("🌿 Branch: {$repoInfo['branch']}");
|
||||
|
||||
// Get configuration
|
||||
$branch = $this->option('branch') ?: $this->getBranch();
|
||||
$phpVersion = $this->option('php-version') ?: config('hostinger-deploy.github.php_version', '8.3');
|
||||
$workflowFile = config('hostinger-deploy.github.workflow_file', '.github/workflows/hostinger-deploy.yml');
|
||||
|
||||
// Create .github/workflows directory if it doesn't exist
|
||||
$workflowDir = dirname($workflowFile);
|
||||
if (!File::exists($workflowDir)) {
|
||||
File::makeDirectory($workflowDir, 0755, true);
|
||||
$this->info("📁 Created directory: {$workflowDir}");
|
||||
}
|
||||
|
||||
// Generate workflow content
|
||||
$workflowContent = $this->generateWorkflowContent($branch, $phpVersion);
|
||||
|
||||
// Write workflow file
|
||||
if (File::put($workflowFile, $workflowContent)) {
|
||||
$this->info("✅ Workflow file created: {$workflowFile}");
|
||||
} else {
|
||||
$this->error("❌ Failed to create workflow file: {$workflowFile}");
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
// Display next steps
|
||||
$this->displayNextSteps($repoInfo);
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the branch to use for the workflow.
|
||||
*/
|
||||
protected function getBranch(): string
|
||||
{
|
||||
$currentBranch = $this->github->getCurrentBranch();
|
||||
$defaultBranch = config('hostinger-deploy.github.default_branch', 'main');
|
||||
|
||||
if ($currentBranch && $currentBranch !== $defaultBranch) {
|
||||
if ($this->confirm("Use current branch '{$currentBranch}' for the workflow? (default: {$defaultBranch})")) {
|
||||
return $currentBranch;
|
||||
}
|
||||
}
|
||||
|
||||
return $defaultBranch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate workflow content with placeholders replaced.
|
||||
*/
|
||||
protected function generateWorkflowContent(string $branch, string $phpVersion): string
|
||||
{
|
||||
$stubPath = __DIR__ . '/../../stubs/hostinger-deploy.yml';
|
||||
|
||||
if (!File::exists($stubPath)) {
|
||||
throw new \Exception("Workflow stub not found: {$stubPath}");
|
||||
}
|
||||
|
||||
$content = File::get($stubPath);
|
||||
|
||||
// Replace placeholders
|
||||
$content = str_replace('{{BRANCH}}', $branch, $content);
|
||||
$content = str_replace('{{PHP_VERSION}}', $phpVersion, $content);
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display next steps for the user.
|
||||
*/
|
||||
protected function displayNextSteps(array $repoInfo): void
|
||||
{
|
||||
$this->line('');
|
||||
$this->info('🎉 GitHub Actions workflow published successfully!');
|
||||
$this->line('');
|
||||
$this->warn('📋 Next steps:');
|
||||
$this->line('');
|
||||
$this->line('1. Add the following secrets to your GitHub repository:');
|
||||
$this->line(' Go to: ' . $repoInfo['secrets_url']);
|
||||
$this->line('');
|
||||
$this->line(' Required secrets:');
|
||||
$this->line(' - SSH_HOST: Your Hostinger server IP address');
|
||||
$this->line(' - SSH_USERNAME: Your Hostinger SSH username');
|
||||
$this->line(' - SSH_PORT: Your Hostinger SSH port (usually 22)');
|
||||
$this->line(' - SSH_KEY: Your private SSH key');
|
||||
$this->line('');
|
||||
$this->line('2. Add the following variable to your GitHub repository:');
|
||||
$this->line(' Go to: ' . $repoInfo['variables_url']);
|
||||
$this->line('');
|
||||
$this->line(' Required variable:');
|
||||
$this->line(' - WEBSITE_FOLDER: Your Hostinger website folder name');
|
||||
$this->line('');
|
||||
$this->line('3. Run the auto-deploy command to get your SSH keys:');
|
||||
$this->line(' php artisan hostinger:auto-deploy');
|
||||
$this->line('');
|
||||
$this->line('4. Push changes to trigger the workflow:');
|
||||
$this->line(' git add .');
|
||||
$this->line(' git commit -m "Add Hostinger deployment workflow"');
|
||||
$this->line(' git push');
|
||||
$this->line('');
|
||||
$this->info('🚀 Your repository will now automatically deploy on push!');
|
||||
}
|
||||
}
|
||||
43
src/HostingerDeployServiceProvider.php
Normal file
43
src/HostingerDeployServiceProvider.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Zura\HostingerDeploy;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Zura\HostingerDeploy\Commands\DeploySharedCommand;
|
||||
use Zura\HostingerDeploy\Commands\PublishWorkflowCommand;
|
||||
use Zura\HostingerDeploy\Commands\AutoDeployCommand;
|
||||
|
||||
class HostingerDeployServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register services.
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
$this->mergeConfigFrom(
|
||||
__DIR__.'/config/hostinger-deploy.php', 'hostinger-deploy'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap services.
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
if ($this->app->runningInConsole()) {
|
||||
$this->commands([
|
||||
DeploySharedCommand::class,
|
||||
PublishWorkflowCommand::class,
|
||||
AutoDeployCommand::class,
|
||||
]);
|
||||
|
||||
$this->publishes([
|
||||
__DIR__.'/config/hostinger-deploy.php' => config_path('hostinger-deploy.php'),
|
||||
], 'hostinger-deploy-config');
|
||||
|
||||
$this->publishes([
|
||||
__DIR__.'/../stubs/hostinger-deploy.yml' => base_path('.github/workflows/hostinger-deploy.yml'),
|
||||
], 'hostinger-deploy-workflow');
|
||||
}
|
||||
}
|
||||
}
|
||||
138
src/Services/GitHubActionsService.php
Normal file
138
src/Services/GitHubActionsService.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
namespace Zura\HostingerDeploy\Services;
|
||||
|
||||
use Illuminate\Support\Facades\Process;
|
||||
|
||||
class GitHubActionsService
|
||||
{
|
||||
/**
|
||||
* Get the current Git repository URL.
|
||||
*/
|
||||
public function getRepositoryUrl(): ?string
|
||||
{
|
||||
try {
|
||||
$result = Process::run('git config --get remote.origin.url');
|
||||
|
||||
if (!$result->successful()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return trim($result->output());
|
||||
} catch (\Exception $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current branch name.
|
||||
*/
|
||||
public function getCurrentBranch(): string
|
||||
{
|
||||
try {
|
||||
$result = Process::run('git branch --show-current');
|
||||
|
||||
if (!$result->successful()) {
|
||||
return 'main';
|
||||
}
|
||||
|
||||
$branch = trim($result->output());
|
||||
return $branch ?: 'main';
|
||||
} catch (\Exception $e) {
|
||||
return 'main';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract repository owner and name from Git URL.
|
||||
*/
|
||||
public function parseRepositoryUrl(string $url): ?array
|
||||
{
|
||||
// Handle SSH URLs: git@github.com:owner/repo.git
|
||||
if (preg_match('/git@github\.com:([^\/]+)\/([^\/]+)\.git/', $url, $matches)) {
|
||||
return [
|
||||
'owner' => $matches[1],
|
||||
'name' => $matches[2],
|
||||
'url' => "https://github.com/{$matches[1]}/{$matches[2]}"
|
||||
];
|
||||
}
|
||||
|
||||
// Handle HTTPS URLs: https://github.com/owner/repo.git
|
||||
if (preg_match('/https:\/\/github\.com\/([^\/]+)\/([^\/]+)\.git/', $url, $matches)) {
|
||||
return [
|
||||
'owner' => $matches[1],
|
||||
'name' => $matches[2],
|
||||
'url' => "https://github.com/{$matches[1]}/{$matches[2]}"
|
||||
];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get GitHub repository settings URL for secrets.
|
||||
*/
|
||||
public function getSecretsUrl(string $owner, string $name): string
|
||||
{
|
||||
return "https://github.com/{$owner}/{$name}/settings/secrets/actions";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get GitHub repository settings URL for variables.
|
||||
*/
|
||||
public function getVariablesUrl(string $owner, string $name): string
|
||||
{
|
||||
return "https://github.com/{$owner}/{$name}/settings/variables/actions";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get GitHub repository settings URL for deploy keys.
|
||||
*/
|
||||
public function getDeployKeysUrl(string $owner, string $name): string
|
||||
{
|
||||
return "https://github.com/{$owner}/{$name}/settings/keys";
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we're in a Git repository.
|
||||
*/
|
||||
public function isGitRepository(): bool
|
||||
{
|
||||
try {
|
||||
$result = Process::run('git rev-parse --git-dir');
|
||||
return $result->successful();
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get repository information for display.
|
||||
*/
|
||||
public function getRepositoryInfo(): ?array
|
||||
{
|
||||
if (!$this->isGitRepository()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$url = $this->getRepositoryUrl();
|
||||
if (!$url) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$parsed = $this->parseRepositoryUrl($url);
|
||||
if (!$parsed) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'url' => $url,
|
||||
'owner' => $parsed['owner'],
|
||||
'name' => $parsed['name'],
|
||||
'branch' => $this->getCurrentBranch(),
|
||||
'secrets_url' => $this->getSecretsUrl($parsed['owner'], $parsed['name']),
|
||||
'variables_url' => $this->getVariablesUrl($parsed['owner'], $parsed['name']),
|
||||
'deploy_keys_url' => $this->getDeployKeysUrl($parsed['owner'], $parsed['name']),
|
||||
];
|
||||
}
|
||||
}
|
||||
153
src/Services/SshConnectionService.php
Normal file
153
src/Services/SshConnectionService.php
Normal file
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
namespace Zura\HostingerDeploy\Services;
|
||||
|
||||
use Illuminate\Support\Facades\Process;
|
||||
use Illuminate\Process\Exceptions\ProcessFailedException;
|
||||
|
||||
class SshConnectionService
|
||||
{
|
||||
protected string $host;
|
||||
protected string $username;
|
||||
protected int $port;
|
||||
protected int $timeout;
|
||||
|
||||
public function __construct(string $host, string $username, int $port = 22, int $timeout = 30)
|
||||
{
|
||||
$this->host = $host;
|
||||
$this->username = $username;
|
||||
$this->port = $port;
|
||||
$this->timeout = $timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a command on the remote server via SSH.
|
||||
*/
|
||||
public function execute(string $command): string
|
||||
{
|
||||
$sshCommand = $this->buildSshCommand($command);
|
||||
|
||||
try {
|
||||
$result = Process::timeout($this->timeout)
|
||||
->run($sshCommand);
|
||||
|
||||
if (!$result->successful()) {
|
||||
throw new ProcessFailedException($result);
|
||||
}
|
||||
|
||||
return $result->output();
|
||||
} catch (ProcessFailedException $e) {
|
||||
throw new \Exception("SSH command failed: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute multiple commands on the remote server.
|
||||
*/
|
||||
public function executeMultiple(array $commands): string
|
||||
{
|
||||
$combinedCommand = implode(' && ', $commands);
|
||||
return $this->execute($combinedCommand);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if SSH connection is working.
|
||||
*/
|
||||
public function testConnection(): bool
|
||||
{
|
||||
try {
|
||||
$this->execute('echo "SSH connection test successful"');
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the public key from the server.
|
||||
*/
|
||||
public function getPublicKey(): ?string
|
||||
{
|
||||
try {
|
||||
return trim($this->execute('cat ~/.ssh/id_rsa.pub 2>/dev/null || echo ""'));
|
||||
} catch (\Exception $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the private key from the server.
|
||||
*/
|
||||
public function getPrivateKey(): ?string
|
||||
{
|
||||
try {
|
||||
return trim($this->execute('cat ~/.ssh/id_rsa 2>/dev/null || echo ""'));
|
||||
} catch (\Exception $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate SSH key pair on the server if it doesn't exist.
|
||||
*/
|
||||
public function generateSshKey(): bool
|
||||
{
|
||||
try {
|
||||
$this->execute('ssh-keygen -t rsa -b 4096 -C "github-deploy-key" -N "" -f ~/.ssh/id_rsa');
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a public key to authorized_keys.
|
||||
*/
|
||||
public function addToAuthorizedKeys(string $publicKey): bool
|
||||
{
|
||||
try {
|
||||
$this->execute("echo '{$publicKey}' >> ~/.ssh/authorized_keys");
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if SSH key exists on the server.
|
||||
*/
|
||||
public function sshKeyExists(): bool
|
||||
{
|
||||
try {
|
||||
$result = $this->execute('test -f ~/.ssh/id_rsa && echo "exists" || echo "not_exists"');
|
||||
return trim($result) === 'exists';
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the SSH command string.
|
||||
*/
|
||||
protected function buildSshCommand(string $command): string
|
||||
{
|
||||
$sshOptions = [
|
||||
'-p ' . $this->port,
|
||||
'-o ConnectTimeout=' . $this->timeout,
|
||||
'-o StrictHostKeyChecking=no',
|
||||
'-o UserKnownHostsFile=/dev/null',
|
||||
];
|
||||
|
||||
$sshCommand = 'ssh ' . implode(' ', $sshOptions) . ' ' . $this->username . '@' . $this->host . ' "' . addslashes($command) . '"';
|
||||
|
||||
return $sshCommand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get connection details for display.
|
||||
*/
|
||||
public function getConnectionString(): string
|
||||
{
|
||||
return "ssh -p {$this->port} {$this->username}@{$this->host}";
|
||||
}
|
||||
}
|
||||
65
src/config/hostinger-deploy.php
Normal file
65
src/config/hostinger-deploy.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| SSH Connection Settings
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| These settings are used for SSH connections to your Hostinger server.
|
||||
| You can override these in your .env file.
|
||||
|
|
||||
*/
|
||||
'ssh' => [
|
||||
'host' => env('HOSTINGER_SSH_HOST'),
|
||||
'username' => env('HOSTINGER_SSH_USERNAME'),
|
||||
'port' => env('HOSTINGER_SSH_PORT', 22),
|
||||
'timeout' => 30,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Deployment Settings
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Configuration for the deployment process.
|
||||
|
|
||||
*/
|
||||
'deployment' => [
|
||||
'site_dir' => env('HOSTINGER_SITE_DIR'),
|
||||
'composer_flags' => '--no-dev --optimize-autoloader',
|
||||
'run_migrations' => true,
|
||||
'run_storage_link' => true,
|
||||
'run_config_cache' => false,
|
||||
'run_route_cache' => false,
|
||||
'run_view_cache' => false,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| GitHub Actions Settings
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Configuration for GitHub Actions workflow generation.
|
||||
|
|
||||
*/
|
||||
'github' => [
|
||||
'workflow_file' => '.github/workflows/hostinger-deploy.yml',
|
||||
'php_version' => '8.3',
|
||||
'default_branch' => 'main',
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Server Paths
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Default paths on the Hostinger server.
|
||||
|
|
||||
*/
|
||||
'paths' => [
|
||||
'domains' => 'domains',
|
||||
'public_html' => 'public_html',
|
||||
'public' => 'public',
|
||||
],
|
||||
];
|
||||
51
stubs/hostinger-deploy.yml
Normal file
51
stubs/hostinger-deploy.yml
Normal file
@@ -0,0 +1,51 @@
|
||||
name: Hostinger Deploy
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ {{BRANCH}} ]
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: '{{PHP_VERSION}}'
|
||||
|
||||
- name: Create .env
|
||||
run: cp .env.example .env
|
||||
|
||||
- name: Install composer Dependencies
|
||||
run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
|
||||
|
||||
- name: Set Application Encryption Key
|
||||
run: php artisan key:generate --ansi
|
||||
|
||||
- name: Create Storage Link
|
||||
run: php artisan storage:link
|
||||
|
||||
- name: Run Migrations
|
||||
run: php artisan migrate --force
|
||||
|
||||
- name: Deploy to Hostinger Server
|
||||
if: ${{ success() }}
|
||||
uses: appleboy/ssh-action@master
|
||||
with:
|
||||
host: ${{ secrets.SSH_HOST }}
|
||||
username: ${{ secrets.SSH_USERNAME }}
|
||||
port: ${{ secrets.SSH_PORT }}
|
||||
key: ${{ secrets.SSH_KEY }}
|
||||
script: |
|
||||
cd domains/${{ vars.WEBSITE_FOLDER }}
|
||||
git checkout {{BRANCH}}
|
||||
git pull
|
||||
composer install --no-dev --optimize-autoloader
|
||||
php artisan migrate --force
|
||||
php artisan config:cache
|
||||
php artisan route:cache
|
||||
php artisan view:cache
|
||||
Reference in New Issue
Block a user