├── LICENSE ├── README.md ├── composer.json ├── config └── gitdeploy.php ├── routes └── web.php └── src ├── Events └── GitDeployed.php ├── GitDeployServiceProvider.php ├── Http └── GitDeployController.php └── views └── email.blade.php /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Orphans 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deployment of Laravel projects using Git webhooks 2 | 3 | git-deploy-laravel allows for automated deployment using webhook requests from your repository's server, and automatically pulls project code using the local Git binary. 4 | 5 | This should work out-of-the-box with Laravel 5.x using with webhooks from GitHub and GitLab servers. 6 | 7 | This is an internal tool to help with our common workflow pattern but please feel free to borrow, change and improve. 8 | 9 | ## Installation 10 | 11 | 12 | ### Step 1 13 | 14 | Add the following to your `composer.json` file then update your composer as normal: 15 | 16 | { 17 | "require" : { 18 | "orphans/git-deploy-laravel" : "dev-master" 19 | } 20 | } 21 | 22 | Or run: 23 | 24 | composer require orphans/git-deploy-laravel 25 | 26 | ### Step 2 27 | 28 | Add the _/git-deploy_ route to CSRF exceptions so your repo's host can send messages to your project. 29 | 30 | 31 | In file in `app/Http/Middleware/VerifyCsrfToken.php` add: 32 | 33 | protected $except = [ 34 | 'git-deploy', 35 | ]; 36 | 37 | ### Step 3 Optional 38 | In case you need additional action after a successful commit, you can add you own Event Listener. 39 | For example you can write your own update script to run migrations etc. 40 | 41 | **1)** Create a Listener to perform action when a git deployment is done. 42 | Open the `App/Listeners` directory (or create it if it doesn't exist). Now create a new file and call it `GitDeployedListener.php`. Paste in this code: 43 | 44 | ```php 45 | [ 90 | \App\Listeners\GitDeployedListener::class 91 | ] 92 | ]; 93 | 94 | // ... 95 | ``` 96 | 97 | 98 | ## Usage 99 | 100 | Add a webhook for http://your.website.url/git-deploy to your project in GitHub/GitLab and this package will take care of the rest. The webhook should fire on push-events. 101 | 102 | Your website will automatically receive POST messages from the repo manager and perform a Git pull. 103 | 104 | ## Configuration 105 | 106 | In most cases the package will find the correct Git repository and Git executable but we advise publishing our config anyway because it will let you enable extra security options and email notifications. 107 | 108 | To add custom configuration run: 109 | 110 | php artisan vendor:publish --provider="Orphans\GitDeploy\GitDeployServiceProvider" 111 | 112 | Then edit `/config/gitdeploy.php` to suit your needs. 113 | 114 | ```php 115 | 'Joe Bloggs', 'address' => 'email@example1.com'], 129 | | ['name' => 'Jane Doe', 'address' => 'email@example2.com'], 130 | | ... 131 | | ] 132 | | 133 | */ 134 | 135 | 'email_recipients' => [], 136 | 137 | /* 138 | |-------------------------------------------------------------------------- 139 | | Email sender 140 | |-------------------------------------------------------------------------- 141 | | 142 | | The email address and name that notification emails will be sent from. 143 | | This will default to the sender in config(mail.from) if left null. 144 | | 145 | */ 146 | 147 | 'email_sender' => ['address' => null, 'name' => null], 148 | 149 | /* 150 | |-------------------------------------------------------------------------- 151 | | Repository path 152 | |-------------------------------------------------------------------------- 153 | | 154 | | This the root path of the Git repository that will be pulled. If this 155 | | is left empty the script will try to determine the directory itself 156 | | but looking for the project's .env file it's nearby .git directory. 157 | | 158 | | No trailing slash 159 | | 160 | */ 161 | 162 | 'repo_path' => '', 163 | 164 | /* 165 | |-------------------------------------------------------------------------- 166 | | Allowed sources 167 | |-------------------------------------------------------------------------- 168 | | 169 | | A request will be ignored unless it comes from an IP listed in this 170 | | array. Leave the array empty to allow all sources. 171 | | 172 | | This is useful for a little extra security if you run your own Git 173 | | repo server. 174 | | 175 | | Relies on the REMOTE_ADDR of the connecting client matching a value 176 | | in the array below. So if using IPv6 on both the server and the 177 | | notifing git server, then make sure to add it to the array. If your git 178 | | server listens on IPv4 and IPv6 it would be safest to add both. 179 | | 180 | | e.g. 181 | | 182 | | 'allowed_sources' => ['192.160.0.1', '::1'], 183 | | 184 | */ 185 | 186 | 'allowed_sources' => [], 187 | 188 | /* 189 | |-------------------------------------------------------------------------- 190 | | Remote name 191 | |-------------------------------------------------------------------------- 192 | | 193 | | The name of the remote repository to pull the changes from 194 | | 195 | */ 196 | 197 | 'remote' => 'origin', 198 | 199 | /* 200 | |-------------------------------------------------------------------------- 201 | | Git binary path 202 | |-------------------------------------------------------------------------- 203 | | 204 | | The full path to the system git binary. e.g. /usr/bin/git 205 | | 206 | | Leave blank to let the system detect using the current PATH variable 207 | | 208 | */ 209 | 210 | 'git_path' => '', 211 | 212 | /* 213 | |-------------------------------------------------------------------------- 214 | | Maintenance mode 215 | |-------------------------------------------------------------------------- 216 | | 217 | | Allow the git hook to put the site into maintenance mode before doing 218 | | the pull from the remote server. 219 | | 220 | | After a successful pull the site will be switched back to normal 221 | | operations. This does leave a possibility of the site remaining in 222 | | maintenance mode should an error occur during the pull. 223 | | 224 | */ 225 | 226 | 'maintenance_mode' => true, 227 | 228 | /* 229 | |-------------------------------------------------------------------------- 230 | | Fire Event 231 | |-------------------------------------------------------------------------- 232 | | 233 | | Allow the git hook to fire a event "GitDeployed" so that everybody can listen to that event. 234 | | See readme how to create a nice listener on that. 235 | | 236 | */ 237 | 'fire_event' => true, 238 | 239 | /* 240 | |-------------------------------------------------------------------------- 241 | | Secret signature 242 | |-------------------------------------------------------------------------- 243 | | 244 | | Allow webhook requests to be signed with a secret signature. 245 | | 246 | | If 'secret' is set to true, Gitdeploy will deny requests where the 247 | | signature does not match. If set to false it will ignore any signature 248 | | headers it recieves. 249 | | 250 | | For Gitlab servers, you probably want the settings below: 251 | | 252 | | 'secret_type' => 'plain', 253 | | 'secret_header' => 'X-Gitlab-Token', 254 | | 255 | | For Github, use something like the below (untested): 256 | | 257 | | 'secret_type' => 'hmac', 258 | | 'secret_header' => 'X-Hub-Signature', 259 | */ 260 | 261 | 'secret' => false, 262 | 263 | /** 264 | * plain|hmac 265 | */ 266 | 'secret_type' => 'plain', 267 | 268 | /** 269 | * X-Gitlab-Token|X-Hub-Signature 270 | */ 271 | 'secret_header' => 'X-Gitlab-Token', 272 | 273 | /** 274 | * The key you specified in the pushing client 275 | */ 276 | 'secret_key' => '', 277 | 278 | ]; 279 | 280 | ``` 281 | 282 | ## Future Plans 283 | 284 | * Email report on code conflicts that prevent a pull 285 | * Support for performing `composer install` after deployment 286 | * Support for restarting laravel queues after deployment with `artisan queue:restart` 287 | * Support for running custom artisan commands after successful pulls 288 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "orphans/git-deploy-laravel", 3 | "description": "Helps automate the deployment of projects onto servers by utilising Git web hooks.", 4 | "license": "MIT", 5 | "autoload": { 6 | "psr-4": { 7 | "Orphans\\GitDeploy\\": "src" 8 | } 9 | }, 10 | "require": { 11 | "illuminate/support": "^5.5|^6.0|^7.0|^8.0" 12 | }, 13 | "extra": { 14 | "laravel": { 15 | "providers": [ 16 | "Orphans\\GitDeploy\\GitDeployServiceProvider" 17 | ] 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /config/gitdeploy.php: -------------------------------------------------------------------------------- 1 | 'Joe Bloggs', 'address' => 'email@example1.com'], 15 | | ['name' => 'Jane Doe', 'address' => 'email@example2.com'], 16 | | ... 17 | | ] 18 | | 19 | */ 20 | 21 | 'email_recipients' => [], 22 | 23 | /* 24 | |-------------------------------------------------------------------------- 25 | | Email sender 26 | |-------------------------------------------------------------------------- 27 | | 28 | | The email address and name that notification emails will be sent from. 29 | | This will default to the sender in config(mail.from) if left null. 30 | | 31 | */ 32 | 33 | 'email_sender' => ['address' => null, 'name' => null], 34 | 35 | /* 36 | |-------------------------------------------------------------------------- 37 | | Email template 38 | |-------------------------------------------------------------------------- 39 | | 40 | | We have a good email template but if you need to change the view, create your own email template and change it here. 41 | | Default is 'gitdeploy::email' 42 | | 43 | */ 44 | 'email_template' => 'gitdeploy::email', 45 | /* 46 | |-------------------------------------------------------------------------- 47 | | Repository path 48 | |-------------------------------------------------------------------------- 49 | | 50 | | This the root path of the Git repository that will be pulled. If this 51 | | is left empty the script will try to determine the directory itself 52 | | but looking for the project's .env file it's nearby .git directory. 53 | | 54 | | No trailing slash 55 | | 56 | */ 57 | 58 | 'repo_path' => '', 59 | 60 | /* 61 | |-------------------------------------------------------------------------- 62 | | Allowed sources 63 | |-------------------------------------------------------------------------- 64 | | 65 | | A request will be ignored unless it comes from an IP listed in this 66 | | array. Leave the array empty to allow all sources. 67 | | 68 | | This is useful for a little extra security if you run your own Git 69 | | repo server. 70 | | 71 | | Relies on the REMOTE_ADDR of the connecting client matching a value 72 | | in the array below. So if using IPv6 on both the server and the 73 | | notifing git server, then make sure to add it to the array. If your git 74 | | server listens on IPv4 and IPv6 it would be safest to add both. 75 | | 76 | | e.g. 77 | | 78 | | 'allowed_sources' => ['192.160.0.1', '::1'], 79 | | 80 | */ 81 | 82 | 'allowed_sources' => [], 83 | 84 | /* 85 | |-------------------------------------------------------------------------- 86 | | Remote name 87 | |-------------------------------------------------------------------------- 88 | | 89 | | The name of the remote repository to pull the changes from 90 | | 91 | */ 92 | 93 | 'remote' => 'origin', 94 | 95 | /* 96 | |-------------------------------------------------------------------------- 97 | | Git binary path 98 | |-------------------------------------------------------------------------- 99 | | 100 | | The full path to the system git binary. e.g. /usr/bin/git 101 | | 102 | | Leave blank to let the system detect using the current PATH variable 103 | | 104 | */ 105 | 106 | 'git_path' => '', 107 | 108 | /* 109 | |-------------------------------------------------------------------------- 110 | | Maintenance mode 111 | |-------------------------------------------------------------------------- 112 | | 113 | | Allow the git hook to put the site into maintenance mode before doing 114 | | the pull from the remote server. 115 | | 116 | | After a successful pull the site will be switched back to normal 117 | | operations. This does leave a possibility of the site remaining in 118 | | maintenance mode should an error occur during the pull. 119 | | 120 | */ 121 | 122 | 'maintenance_mode' => true, 123 | 124 | /* 125 | |-------------------------------------------------------------------------- 126 | | Fire Event 127 | |-------------------------------------------------------------------------- 128 | | 129 | | Allow the git hook to fire a event "GitDeployed" so that everybody can listen to that event. 130 | | See readme how to create a nice listener on that. 131 | | 132 | */ 133 | 'fire_event' => true, 134 | 135 | /* 136 | |-------------------------------------------------------------------------- 137 | | Secret signature 138 | |-------------------------------------------------------------------------- 139 | | 140 | | Allow webhook requests to be signed with a secret signature. 141 | | 142 | | If 'secret' is set to true, Gitdeploy will deny requests where the 143 | | signature does not match. If set to false it will ignore any signature 144 | | headers it recieves. 145 | | 146 | | For Gitlab servers, you probably want the settings below: 147 | | 148 | | 'secret_type' => 'plain', 149 | | 'secret_header' => 'X-Gitlab-Token', 150 | | 151 | | For Github, use something like the below (untested): 152 | | 153 | | 'secret_type' => 'hmac', 154 | | 'secret_header' => 'X-Hub-Signature', 155 | */ 156 | 157 | 'secret' => false, 158 | 159 | /** 160 | * plain|hmac 161 | */ 162 | 'secret_type' => 'plain', 163 | 164 | /** 165 | * X-Gitlab-Token|X-Hub-Signature 166 | */ 167 | 'secret_header' => 'X-Gitlab-Token', 168 | 169 | /** 170 | * The key you specified in the pushing client 171 | */ 172 | 'secret_key' => '', 173 | 174 | ]; 175 | -------------------------------------------------------------------------------- /routes/web.php: -------------------------------------------------------------------------------- 1 | commits = $commits; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/GitDeployServiceProvider.php: -------------------------------------------------------------------------------- 1 | publishes([ 17 | __dir__ . '/../config/gitdeploy.php' => config_path('gitdeploy.php') 18 | ], 'config'); 19 | $this->loadRoutesFrom(__dir__ . '/../routes/web.php'); 20 | $this->loadViewsFrom(__dir__ . '/views', 'gitdeploy'); 21 | 22 | } 23 | 24 | /** 25 | * Register the application services. 26 | * 27 | * @return void 28 | */ 29 | public function register() 30 | { 31 | $this->mergeConfigFrom(__dir__ . '/../config/gitdeploy.php', 'gitdeploy'); 32 | $this->app->bind('git_deploy', function ($app) { 33 | return new GitDeploy; 34 | }); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Http/GitDeployController.php: -------------------------------------------------------------------------------- 1 | pushHandler(new StreamHandler(storage_path('logs/gitdeploy.log'), Logger::WARNING)); 26 | 27 | $git_path = !empty(config('gitdeploy.git_path')) ? config('gitdeploy.git_path') : 'git'; 28 | $git_remote = !empty(config('gitdeploy.remote')) ? config('gitdeploy.remote') : 'origin'; 29 | 30 | // Limit to known servers 31 | if (!empty(config('gitdeploy.allowed_sources'))) { 32 | 33 | $remote_ip = $this->formatIPAddress($_SERVER['REMOTE_ADDR']); 34 | $allowed_sources = array_map([$this, 'formatIPAddress'], config('gitdeploy.allowed_sources')); 35 | 36 | if (!in_array($remote_ip, $allowed_sources)) { 37 | $log->addError('Request must come from an approved IP'); 38 | return Response::json([ 39 | 'success' => false, 40 | 'message' => 'Request must come from an approved IP', 41 | ], 401); 42 | } 43 | } 44 | 45 | // Collect the posted data 46 | $postdata = json_decode($request->getContent(), TRUE); 47 | if (empty($postdata)) { 48 | $log->addError('Web hook data does not look valid'); 49 | return Response::json([ 50 | 'success' => false, 51 | 'message' => 'Web hook data does not look valid', 52 | ], 500); 53 | } 54 | 55 | // Check the config's directory 56 | $repo_dir = config('gitdeploy.repo_path'); 57 | if (!empty($repo_dir) && !file_exists($repo_dir.'/.git/config')) { 58 | $log->addError('Invalid repo path in config'); 59 | return Response::json([ 60 | 'success' => false, 61 | 'message' => 'Invalid repo path in config', 62 | ], 500); 63 | } 64 | 65 | // Try to determine Laravel's directory going up paths until we find a .env 66 | if (empty($repo_dir)) { 67 | $checked[] = $repo_dir; 68 | $repo_dir = __DIR__; 69 | do { 70 | $repo_dir = dirname($repo_dir); 71 | } while ($repo_dir !== '/' && !file_exists($repo_dir.'/.env')); 72 | } 73 | 74 | // This is not necessarily the repo's root so go up more paths if necessary 75 | if ($repo_dir !== '/') { 76 | while ($repo_dir !== '/' && !file_exists($repo_dir.'/.git/config')) { 77 | $repo_dir = dirname($repo_dir); 78 | } 79 | } 80 | 81 | // So, do we have something valid? 82 | if ($repo_dir === '/' || !file_exists($repo_dir.'/.git/config')) { 83 | $log->addError('Could not determine the repo path'); 84 | return Response::json([ 85 | 'success' => false, 86 | 'message' => 'Could not determine the repo path', 87 | ], 500); 88 | } 89 | 90 | // Check signatures 91 | if (!empty(config('gitdeploy.secret'))) { 92 | $header = config('gitdeploy.secret_header'); 93 | $header_data = $request->header($header); 94 | 95 | /** 96 | * Check for valid header 97 | */ 98 | if (!$header_data) { 99 | $log->addError('Could not find header with name ' . $header); 100 | return Response::json([ 101 | 'success' => false, 102 | 'message' => 'Could not find header with name ' . $header, 103 | ], 401); 104 | } 105 | 106 | /** 107 | * Sanity check for key 108 | */ 109 | if (empty(config('gitdeploy.secret_key'))) { 110 | $log->addError('Secret was set to true but no secret_key specified in config'); 111 | return Response::json([ 112 | 'success' => false, 113 | 'message' => 'Secret was set to true but no secret_key specified in config', 114 | ], 500); 115 | } 116 | 117 | /** 118 | * Check plain secrets (Gitlab) 119 | */ 120 | if (config('gitdeploy.secret_type') == 'plain') { 121 | if ($header_data !== config('gitdeploy.secret_key')) { 122 | $log->addError('Secret did not match'); 123 | return Response::json([ 124 | 'success' => false, 125 | 'message' => 'Secret did not match', 126 | ], 401); 127 | } 128 | } 129 | 130 | /** 131 | * Check hmac secrets (Github) 132 | */ 133 | else if (config('gitdeploy.secret_type') == 'mac') { 134 | if (!hash_equals('sha1=' . hash_hmac('sha1', $request->getContent(), config('gitdeploy.secret')))){ 135 | $log->addError('Secret did not match'); 136 | return Response::json([ 137 | 'success' => false, 138 | 'message' => 'Secret did not match', 139 | ], 401); 140 | } 141 | } 142 | 143 | /** 144 | * Catch all for anything odd in config 145 | */ 146 | else { 147 | $log->addError('Unsupported secret type'); 148 | return Response::json([ 149 | 'success' => false, 150 | 'message' => 'Unsupported secret type', 151 | ], 500); 152 | } 153 | 154 | // If we get this far then the secret matched, lets go ahead! 155 | } 156 | 157 | // Get current branch this repository is on 158 | $cmd = escapeshellcmd($git_path) . ' --git-dir=' . escapeshellarg($repo_dir . '/.git') . ' --work-tree=' . escapeshellarg($repo_dir) . ' rev-parse --abbrev-ref HEAD'; 159 | $current_branch = trim(exec($cmd)); //Alternativly shell_exec 160 | 161 | // Get branch this webhook is for 162 | $pushed_branch = explode('/', $postdata['ref']); 163 | $pushed_branch = trim($pushed_branch[2]); 164 | 165 | // If the refs don't matchthis branch, then no need to do a git pull 166 | if ($current_branch !== $pushed_branch){ 167 | $log->addWarning('Pushed refs do not match current branch'); 168 | return Response::json([ 169 | 'success' => false, 170 | 'message' => 'Pushed refs do not match current branch', 171 | ], 500); 172 | } 173 | 174 | // At this point we're happy everything is OK to pull, lets put Laravel into Maintenance mode. 175 | if (!empty(config('gitdeploy.maintenance_mode'))) { 176 | Log::info('Gitdeploy: putting site into maintenance mode'); 177 | Artisan::call('down'); 178 | } 179 | 180 | // git pull 181 | Log::info('Gitdeploy: Pulling latest code on to server'); 182 | $cmd = escapeshellcmd($git_path) . ' --git-dir=' . escapeshellarg($repo_dir . '/.git') . ' --work-tree=' . escapeshellarg($repo_dir) . ' pull ' . escapeshellarg($git_remote) . ' ' . escapeshellarg($current_branch) . ' > ' . escapeshellarg($repo_dir . '/storage/logs/gitdeploy.log'); 183 | 184 | $server_response = [ 185 | 'cmd' => $cmd, 186 | 'user' => shell_exec('whoami'), 187 | 'response' => shell_exec($cmd), 188 | ]; 189 | 190 | // Put site back up and end maintenance mode 191 | if (!empty(config('gitdeploy.maintenance_mode'))) { 192 | Artisan::call('up'); 193 | Log::info('Gitdeploy: taking site out of maintenance mode'); 194 | } 195 | 196 | // Fire Event that git were deployed 197 | if (!empty(config('gitdeploy.fire_event'))) { 198 | event(new GitDeployed($postdata['commits'])); 199 | Log::debug('Gitdeploy: Event GitDeployed fired'); 200 | } 201 | 202 | if (!empty(config('gitdeploy.email_recipients'))) { 203 | 204 | // Humanise the commit log 205 | foreach ($postdata['commits'] as $commit_key => $commit) { 206 | 207 | // Split message into subject + description (Assumes Git's recommended standard where first line is the main summary) 208 | $subject = strtok($commit['message'], "\n"); 209 | $description = ''; 210 | 211 | // Beautify date 212 | $date = new \DateTime($commit['timestamp']); 213 | $date_str = $date->format('d/m/Y, g:ia'); 214 | 215 | $postdata['commits'][$commit_key]['human_id'] = substr($commit['id'], 0, 9); 216 | $postdata['commits'][$commit_key]['human_subject'] = $subject; 217 | $postdata['commits'][$commit_key]['human_description'] = $description; 218 | $postdata['commits'][$commit_key]['human_date'] = $date_str; 219 | } 220 | 221 | // Standardise formats for Gitlab / Github payload differences 222 | if (isset($postdata['pusher']) && !empty($postdata['pusher'])) { 223 | $postdata['user_name'] = $postdata['pusher']['name']; 224 | $postdata['user_email'] = $postdata['pusher']['email']; 225 | } 226 | 227 | // Use package's own sender or the project default? 228 | $addressdata['sender_name'] = config('mail.from.name'); 229 | $addressdata['sender_address'] = config('mail.from.address'); 230 | if (config('gitdeploy.email_sender.address') !== null) { 231 | $addressdata['sender_name'] = config('gitdeploy.email_sender.name'); 232 | $addressdata['sender_address'] = config('gitdeploy.email_sender.address'); 233 | } 234 | 235 | // Recipients 236 | $addressdata['recipients'] = config('gitdeploy.email_recipients'); 237 | 238 | // Template 239 | $emailTemplate = config('gitdeploy.email_template', 'gitdeploy::email'); 240 | 241 | // Todo: Put Mail send into queue to improve performance 242 | \Mail::send($emailTemplate , [ 'server' => $server_response, 'git' => $postdata ], function($message) use ($postdata, $addressdata) { 243 | $message->from($addressdata['sender_address'], $addressdata['sender_name']); 244 | foreach ($addressdata['recipients'] as $recipient) { 245 | $message->to($recipient['address'], $recipient['name']); 246 | } 247 | $message->subject('Repo: ' . $postdata['repository']['name'] . ' updated'); 248 | }); 249 | 250 | } 251 | 252 | return Response::json(true); 253 | } 254 | 255 | 256 | /** 257 | * Make sure we're comparing like for like IP address formats. 258 | * Since IPv6 can be supplied in short hand or long hand formats. 259 | * 260 | * e.g. ::1 is equalvent to 0000:0000:0000:0000:0000:0000:0000:0001 261 | * 262 | * @param string $ip Input IP address to be formatted 263 | * @return string Formatted IP address 264 | */ 265 | private function formatIPAddress(string $ip) { 266 | return inet_ntop(inet_pton($ip)); 267 | } 268 | 269 | } 270 | -------------------------------------------------------------------------------- /src/views/email.blade.php: -------------------------------------------------------------------------------- 1 |
The Git repository has just been updated by {{ $git['user_name'] }} via the web hook.
4 |System user | 7 |{{ $server['user'] }} | 8 |
Command | 11 |{{ $server['cmd'] }} | 12 |
Response | 15 |{{ $server['response'] }} | 16 |
Repository | 21 |{{ $git['repository']['name'] }} {{ $git['repository']['description'] }} |
22 |
Ref | 25 |{{ $git['ref'] }} | 26 |
Before | 29 |{{ $git['before'] }} |
30 |
After | 33 |{{ $git['after'] }} |
34 |
URL | 37 |{{ $git['repository']['url'] }} | 38 |
Homepage | 41 |{{ $git['repository']['homepage'] }} | 42 |
Date | 49 |Subject | 50 |Author | 51 |Commit | 52 |
---|---|---|---|
{{ $commit['human_date'] }} | 58 |{{ $commit['human_subject'] }} | 59 |{{ $commit['author']['name'] }} | 60 |{{ $commit['human_id'] }} |
61 |