[哈菜系列二] Git@Oschina + 本地 Homestead + 阿里云 Server 代码半自动部署
好吧。。我又来了。。。
连续奋战了10+个小时之后,才搞定的,请允许我来显摆下- -
痛点:
菜鸟爱折腾,正好最近在看微信相关的开发,需要频繁发布到阿里云上做调试,(再加上系统部署成这样了,懒得重新搞),于是就估摸着如何按照自己的环境搞一个半自动发布。(就是自己这边push之后,对端也部署完成的环境)。
翻阅论坛时,发现大神们已经对自动部署有了自己的方式,@summerblue和@lijinma都有在这里讨论,在此感谢@lijinma的指导^^。
应用环境:
本地开发:Mac + Homestead + Laravel 5
Git仓库:OSChina
远端服务器:阿里云 CentOS + Apache
涉及知识:
-
Laravel 5 :
Console Command,Route,Middleware -
OSChina:
Hook -
CentOS:
SSH
遇到的坑:
- Laravel 5 Csrf自动拦截入站请求。解决方法:自己写一个Middleware把Csrf验证替换下。
- Json知识薄弱,在读取OSChina传过来的值的时候纠结了很久。
- Apache权限问题。解决方法:参考老外的方式,用户组赋权。传送门
You should think carefully about the security implications of either choice, but the second option is probably easiest. If you don't already have such a group, you can create it with:
addgroup gitwriters... and then add yourself and the Apache user to this group:
adduser [yourusername] gitwriters adduser apache gitwritersThen you can follow the instructions in another question to change the permissions on the repository. To reiterate those with some slight variations:
Recursively, set the group ownership of every file and directory of your repository:
chgrp -R gitwriters /path/to/your/repoRecursively, make every file and directory of your repository readable and writable
by the group:chmod -R g+rw /path/to/your/repoRecursively, set the setgid of every directory in the repository. The setgid bit
on directories means that files created in the directory will have the same group
ownership as the directory.find /path/to/your/repo -type d -print0 | xargs -0 chmod g+sThen hopefully your git pull should work.
- SSH权限问题。最最坑爹的地方,反复调试了很久,结果是在OSChina没有设置对应的Apache ssh key导致的。对于apache这种nologin的用户,请使用sudo -u apache ssh-keygen -t rsa "xxx@xxx.com"的形式生成rsa文件。
源代码及设置:
请打开OSChina的相关项目的管理->PUSH钩子。
并设置相应的网址和密码,这里用了http://www.abc.com/git 密码为password。
app/Http/routes.php
//for OSChina git
Route::post('/git', 'Misc\GitController@git');
app/Http/Misc/GitController.php
<?php namespace app\Http\Controllers\Misc;
use Illuminate\Http\Request;
use app\Http\Controllers\Controller;
class GitController extends Controller {
function git(Request $request)
{
$r = json_decode($request->get('hook'));
$exitCode = \Artisan::call('git', ['password' => $r->password]);
}
}
app/Console/Commands/Git.php
<?php namespace app\Console\Commands;
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputArgument;
class Git extends Command {
/**
* The console command name.
*
* @var string
*/
protected $name = 'git';
/**
* The console command description.
*
* @var string
*/
protected $description = 'git pull for OSCHINA Post.';
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function fire()
{
//
if ($this->argument('password') == 'password')
{
$result = shell_exec('cd /mnt/www/app && git pull');
\Log::info('Git Push Result: ' . $result);
}
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
['password', InputArgument::REQUIRED, 'An example argument.'],
];
}
}
app/Http/Middleware/CheckInBound.php
<?php namespace app\Http\Middleware;
use Closure;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
/**
* Class CheckInBound
* used to determine the inbound data flow
*
* by yyf
*
* @package scms\Http\Middleware
*/
class CheckInBound extends BaseVerifier {
private $safePath=[
'wechat', //微信
'git' //OSChina Git push
];
private $safeHead=[];
/**
* Handle an incoming request and do the VerifyCsrfToken jobs.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$type=$request->path();
\Log::info($request->all()); // log the request
if(in_array($type,$this->safePath)){
return parent::addCookieToResponse($request, $next($request));
}
return parent::handle($request, $next);
}
}
app/Http/Kernel.php
...
//'app\Http\Middleware\VerifyCsrfToken', //use CheckInBound instead by yyf
'app\Http\Middleware\CheckInBound',
...
历史遗留问题
感谢各位大侠看到这里,大侠请留步,小弟还有一事不懂,还请指教。
俗话说没有Bug的程序不是好程序...
目前Middleware在调用完Artisan Command之后,会返回错误:
production.ERROR: exception 'ErrorException' with message 'Argument 1 passed to Illuminate\Session\Middleware\StartSession::addCookieToResponse() must be an instance of Symfony\Component\HttpFoundation\Response, null given, called in /mnt/www/xxx/vendor/compiled.php on line 10877
一般这种是return个OK了事呢,还是又更好的写法呢?求大师们指点。^^
已修复~ 参见@lijinma大神回复。。
关于 LearnKu
推荐文章: