使用 PHP WebHook 实现 BitBucket 服务器自动部署

使用 PHP WebHook 实现 BitBucket 服务器自动部署

我做了一些研究,并试图重现与 JONATHAN NICOL 博客文章类似的内容,“从 Bitbucket 自动进行 git 部署“。

问题更新

我已启用函数输出的记录功能,并在命令末尾exec()添加了。2>&1

当我打印返回到 deploy.log 的内容时,我收到以下内容:

//从exec('cd /home/apache/www.websitename.org.git && git fetch 2>&1');

(
    [0] => fatal: Not a git repository (or any parent up to mount point /home)
    [1] => Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).
)

//输出自exec('cd /home/apache/www.websitename.org.git && GIT_WORK_TREE=/var/www/html/www.websitename.org /usr/bin/git checkout -f');

Array
(
    [0] => fatal: Not a git repository (or any parent up to mount point /home)
    [1] => Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).
)

问题描述:

exec()如果我复制引用的 PHP Web Hook 脚本中包含的函数内执行的命令的输出,feature branch则合并时对文件所做的更改dev将复制到相应的目录中。我的问题是我想确保exec()函数内运行的命令确实正在执行。

起初我以为这是由于权限问题,但我从 shell 发出的命令与通过 PHPexec()函数发出命令的同一用户发出的命令相同。

我似乎无法弄清楚为什么 Web Hook 脚本生成的命令在 apache 用户的 shell 中有效,但在由作为 apache 运行并生成它们的 PHP 执行时却不起作用。

环境描述:

我在 RedHat 7.2 机器上运行 BitBucket 服务器 v4.7.1。该服务器还包含一个开发环境,我希望在合并特定分支时自动部署文件。

我的 Web 根目录是 /var/www/html,apache 可以访问它。当我执行时,<?php echo exec('whoami'); ?>输出是apache

我正在运行 PHP 5.6.23,并且可以从 php 脚本执行 shell 命令。

我的php用户是apache,apache也有一个连接到该用户的shell。

我在 GIT 中的默认分支是master,我还有devstaging分支。典型的工作流程是创建一个分支master并将更改提交到功能分支。然后将该功能分支合并到dev,然后staging最终合并回master

使用 Nicol 博客文章的结构和修改后的 BitBucket Repo 以用于 bitbucket.org,我能够复制以下内容:

使用以下命令将 GIT 存储库克隆为镜像:

作为 Apache 用户:

cd /home/apache/
git clone --mirror ssh://[email protected]:7999/wn/www.websitename.org.git

然后:

cd /home/apache/www.websitename.org.git
GIT_WORK_TREE=/var/www/html/www.websitename.org git checkout -f dev

Apache 对 .git repo 具有适当的权限,apache 有权访问git$PATH,并且 apache 拥有/var/www/html/www.websitename.org

我在此场景中检查,dev因为 BitBucket 中的 Web Hook 设置为在功能分支合并到devBitBucket 并推送到 BitBucket 时做出响应。

Bitbucket Server Web Post Hooks 插件调用的 PHP 脚本如下所示:

更新的代码示例

    <?php

//$repo_name = $_GET['repoName'];
//$client = $_GET['client'];


//for debug
//file_put_contents('deploy.log', serialize($_POST['payload']), FILE_APPEND);
//file_put_contents('deploy.log', $_GET['client'], FILE_APPEND);
//file_put_contents('deploy.log', $_GET['repoName'], FILE_APPEND);

//file_put_contents('deploy.log', print_r($_POST), FILE_APPEND);

// Full path to git binary is required if git is not in your PHP user's path. Otherwise just use 'git'.
$git_bin_path = '/usr/bin/git';


echo getcwd() . "\n";


$update = false;


// Parse data from Bitbucket hook payload
//$payload = json_decode($_POST['payload']);

if ( isset($_POST['payload']) ) { // old method
    $payload = $_POST['payload'];
} else { // new method
    $payload = json_decode(file_get_contents('php://input'),false);
}

/*if(function_exists('exec')) {
file_put_contents('deploy.log', print_r("exec enabled",true), FILE_APPEND);
}else{
    file_put_contents('deploy.log', print_r("exec NOT enabled",true), FILE_APPEND);
}

if(function_exists('chdir')) {
file_put_contents('deploy.log', print_r("chdir enabled",true), FILE_APPEND);
}else{
    file_put_contents('deploy.log', print_r("chdir NOT enabled",true), FILE_APPEND);
}

file_put_contents('deploy.log', print_r($payload,true), FILE_APPEND);*/

//set repo name
$repo_name = $payload->repository->slug;

file_put_contents('/var/www/html/deploy/deploy.log', print_r($repo_name.":",true), FILE_APPEND);

$web_root_dir = '/var/www/html/lt/'.$repo_name;
$repo_dir = '/home/apache/'.$repo_name.'.git';


$dir = getcwd();
file_put_contents('/var/www/html/deploy/deploy.log',print_r("BEFORECHDIR:".$dir."CHDIRBEFORE\r\n"), FILE_APPEND);
file_put_contents('/var/www/html/deploy/deploy.log', print_r("repo".$repo_dir."repo\r\n",true), FILE_APPEND);

chdir($repo_dir);

file_put_contents('/var/www/html/deploy/deploy.log', print_r("DIR:repo".getcwd()."repo:DIR \r\n",true), FILE_APPEND);

$test = chdir($repo_dir);

file_put_contents('/var/www/html/deploy/deploy.log', print_r($test,true), FILE_APPEND);

if(count($payload->refChanges) == '0'){
    $update = false;
}elseif($payload->refChanges[0]->refId == 'refs/heads/dev' ){
    $update = true;
}

file_put_contents('/var/www/html/deploy/deploy.log', print_r("This is the update:".$update.": this ends update \r\n",true), FILE_APPEND);

if ($update) {
    file_put_contents('/var/www/html/deploy/deploy.log', print_r("It's an update",true), FILE_APPEND);
    // Do a git checkout to the web root

    $cmd1 = $git_bin_path  . ' fetch';
    $cmd2 = 'GIT_WORK_TREE=' . $web_root_dir . ' ' . $git_bin_path  . ' checkout -f ';

file_put_contents('/var/www/html/deploy/deploy.log', print_r($cmd1,true), FILE_APPEND);
file_put_contents('/var/www/html/deploy/deploy.log', print_r($cmd2,true), FILE_APPEND);

    $test = chdir($repo_dir);
    file_put_contents('/var/www/html/deploy/deploy.log', print_r($test,true), FILE_APPEND);


    exec("cd ".$repo_dir." && ". $cmd1 ." 2>&1",$out1,$outtest);
    if($outtest !==0 ){
        file_put_contents('/var/www/html/deploy/deploy.log', print_r($out1,true), FILE_APPEND);
    }

    exec("cd ".$repo_dir." && ". $cmd2 ." 2>&1",$out2,$outtest1);
    if($outtest1 !==0 ){
        file_put_contents('/var/www/html/deploy/deploy.log', print_r($out2,true), FILE_APPEND);
    }

    file_put_contents('/var/www/html/deploy/deploy.log', print_r("made it past exec",true), FILE_APPEND);
    //$test = shell_exec($cmd1);
    //$test2 = shell_exec($cmd2);

    file_put_contents('/var/www/html/deploy/deploy.log', print_r($cmd1,true), FILE_APPEND);
    file_put_contents('/var/www/html/deploy/deploy.log', print_r($cmd2,true), FILE_APPEND);



    // Log the deployment
    $commit_hash = exec('cd ' . $repo_dir . ' && ' .$git_bin_path  . ' rev-parse --short HEAD');
    file_put_contents('/var/www/html/deploy/deploy.log', date('m/d/Y h:i:s a') . " Deployed branch: " .  $branch . " Commit: " . $commit_hash . "\n", FILE_APPEND);

}
?>

我可能忽略了什么会导致 PHPexec()函数在使用时以不足的权限执行,exec()而不是直接从 php 用户的 shell 执行?

答案1

结果是 RedHat 7.2 下的 apache 用户的 SELinux 权限问题。

我创建了另一个用户并添加了一个 bash 脚本来执行 git fetch 和 checkout。

我还修改了我的 sudoers 文件,以允许 apache 以新创建的用户身份运行 bash 脚本。

相关内容