From 4c327e71d0349d3f7740ce91ebb730da6cad120f Mon Sep 17 00:00:00 2001 From: hahn <axel.hahn@iml.unibe.ch> Date: Tue, 15 Oct 2013 16:35:41 +0200 Subject: [PATCH] initial - temp checkin 5 --- .../deployment/classes/project.class.php | 180 +++++++++++++----- .../deployment/config/inc_projects_config.php | 18 +- .../config/sshkeys/git@gitlab.iml.unibe.ch | 27 +++ .../sshkeys/git@gitlab.iml.unibe.ch.pub | 1 + shellscripts/gitsshwrapper.sh | 14 ++ 5 files changed, 188 insertions(+), 52 deletions(-) create mode 100644 public_html/deployment/config/sshkeys/git@gitlab.iml.unibe.ch create mode 100644 public_html/deployment/config/sshkeys/git@gitlab.iml.unibe.ch.pub create mode 100644 shellscripts/gitsshwrapper.sh diff --git a/public_html/deployment/classes/project.class.php b/public_html/deployment/classes/project.class.php index 54d87d1e..800388c5 100644 --- a/public_html/deployment/classes/project.class.php +++ b/public_html/deployment/classes/project.class.php @@ -8,13 +8,35 @@ class project { // ---------------------------------------------------------------------- // CONFIG // ---------------------------------------------------------------------- + + /** + * config file + * @var type + */ + private $_sCfgfile="../config/inc_projects_config.php"; + + /** + * configuration ($aConfig in the config file) + * @var array + */ private $_aConfig = array(); + + /** + * configuration of the project (= $aProjects[ID] in the config file) + * @var array + */ + private $_aPrjConfig = array(); + + /** + * version infos of all phases + * @var type + */ private $_aData = array(); - private $_sWorkDir = false; - private $_sPackageDir = false; - private $_aPhases=array(); - private $_sCfgfile="../config/inc_projects_config.php"; + /** + * places of version infos in each deployment phase + * @var type + */ private $_aPlaces=array( "onhold"=>"Queue", "ready4deployment"=>"Repo", @@ -46,9 +68,7 @@ class project { */ private function _readConfig() { require($this->_sCfgfile); - $this->_sWorkDir = $aConfig['workDir']; - $this->_sPackageDir = $this->_sWorkDir.'/packages'; - $this->_aPhases=$aConfig["phases"]; + $this->_aConfig = $aConfig; return true; } @@ -57,18 +77,30 @@ class project { * @return boolean */ private function _verifyConfig() { - if (!count($this->_aConfig)) - die("ERROR::CONFIG: no config was found."); - if (!$this->_sPackageDir) + if (!count($this->_aPrjConfig)) + die("ERROR::CONFIG: no config was for found the project. check $aProjects in config file."); + + if (!array_key_exists("packageDir", $this->_aConfig)) + die("ERROR::CONFIG: packagedir is not defined."); + + if (!$this->_aConfig["packageDir"]) die("ERROR::CONFIG: packagedir is not set."); - if (!file_exists($this->_sPackageDir)) - die("ERROR::CONFIG: packagedir does not exist: "" . $this->_sPackageDir . ""."); - if (!array_key_exists("phases", $this->_aConfig)) - die("ERROR::CONFIG: key "phases" was not found in config.<br><pre>" . print_r($this->_aConfig, true) . "</pre>"); + + if (!file_exists($this->_aConfig["packageDir"])) + die("ERROR::CONFIG: packagedir does not exist: "" . $this->_aConfig['packageDir'] . ""."); + + if (!array_key_exists("phases", $this->_aPrjConfig)) + die("ERROR::CONFIG: key "phases" was not found in config.<br><pre>" . print_r($this->_aPrjConfig, true) . "</pre>"); + // TODO: verify ausbauen return true; } + /** + * execute a commandline; returns a string of output of timestamp, command, output and returncode + * @param string $sCommand + * @return string + */ private function _execAndSend($sCommand){ $sReturn=''; $bUseHtml=$_SERVER?true:false; @@ -82,19 +114,34 @@ class project { flush(); $process = proc_open($sCommand, $descriptorspec, $pipes, realpath('./'), array()); - $sReturn.="[".date("H:i:s d.m.Y")."] $sCommand"; - $sReturn.=$bUseHtml?"<br><pre>":"\n"; + $sReturn.="[".date("H:i:s d.m.Y")."] "; + $sReturn.=$bUseHtml?"<strong>$sCommand</strong>":"$sCommand"; + $sReturn.=$bUseHtml?"<br>":"\n"; + $sErrors=false; if (is_resource($process)) { - $oStatus = proc_get_status($process); while ($s = fgets($pipes[1])) { $sReturn.=$s; flush(); } + while ($s = fgets($pipes[2])) { + $sErrors.=$s; + flush(); + } + } + if ($sErrors)$sReturn.="STDERR:\n".$sErrors; + $oStatus = proc_get_status($process); + $iRc=$oStatus['exitcode']; + $sReturn.="[".date("H:i:s d.m.Y")."] exitcode ".$iRc; + if ($bUseHtml){ + if ($iRc==0) { + $sReturn="<pre>".$sReturn; + } else { + $sReturn='<pre class="error">'.$sReturn; + } + $sReturn.='</pre>'; } - $sReturn.=$bUseHtml?"</pre>":"\n"; - $sReturn.="[".date("H:i:s d.m.Y")."] finished; rc=".$oStatus['exitcode']; - $sReturn.=$bUseHtml?"<hr>":"\n---------\n"; + flush(); return $sReturn; } @@ -102,10 +149,14 @@ class project { // GETTER // ---------------------------------------------------------------------- + /** + * get a temp directory + * @return string + */ private function _getTempDir(){ - $s=$this->_sWorkDir."/build/".$this->_aConfig["fileprefix"]."_".date("Ymd-His"); + $s=$this->_aConfig['workDir']."/build/".$this->_aPrjConfig["fileprefix"]."_".date("Ymd-His"); // TODO: auskommentieren - $s=$this->_sWorkDir."/build/".$this->_aConfig["fileprefix"]."_temp"; + $s=$this->_aConfig['workDir']."/build/".$this->_aPrjConfig["fileprefix"]."_temp"; return $s; } /** @@ -115,7 +166,7 @@ class project { * @return string */ private function _getFileBase($sPhase, $sPlace){ - if (!array_key_exists($sPhase, $this->_aPhases)){ + if (!array_key_exists($sPhase, $this->_aConfig["phases"])){ die("ERROR: _getFileBase - this phase does not exist: $sPhase."); } if (!array_key_exists($sPlace, $this->_aPlaces)){ @@ -124,14 +175,14 @@ class project { // local file for onhold|ready4deployment - $sBase=$this->_sPackageDir."/".$sPhase."/".$this->_aConfig["fileprefix"]; + $sBase=$this->_aConfig['packageDir']."/".$sPhase."/".$this->_aPrjConfig["fileprefix"]; if ($sPlace=="onhold") $sBase.="_onhold"; // url for deployed if ($sPlace=="deployed"){ - if ($this->isActivePhase($sPhase) && array_key_exists("url", $this->_aConfig["phases"][$sPhase])){ - $sBase=$this->_aConfig["phases"][$sPhase]["url"].$this->_aConfig["fileprefix"]; + if ($this->isActivePhase($sPhase) && array_key_exists("url", $this->_aPrjConfig["phases"][$sPhase])){ + $sBase=$this->_aPrjConfig["phases"][$sPhase]["url"].$this->_aPrjConfig["fileprefix"]; } else { $sBase=''; } @@ -167,7 +218,7 @@ class project { * @return array */ public function getConfig() { - return $this->_aConfig; + return $this->_aPrjConfig; } /** @@ -175,7 +226,7 @@ class project { * @return string */ public function getLabel() { - return $this->_aConfig["label"]; + return $this->_aPrjConfig["label"]; } /** @@ -183,7 +234,7 @@ class project { * @return string */ public function getDescription() { - return $this->_aConfig["description"]; + return $this->_aPrjConfig["description"]; } /** @@ -193,7 +244,7 @@ class project { public function getAllPhaseInfos(){ if (!array_key_exists("phases", $this->_aData)) $this->_aData["phases"]=array(); - foreach(array_keys($this->_aPhases) as $sPhase){ + foreach(array_keys($this->_aConfig["phases"]) as $sPhase){ if (!array_key_exists($sPhase, $this->_aData["phases"])){ $this->getPhaseInfos($sPhase); } @@ -260,7 +311,7 @@ class project { $sJsonfile=$this->_getInfofile($sPhase, $sKey); $aTmp[$sKey]=array(); if ($this->isActivePhase($sPhase)){ - $sJsonUrl=$this->_aConfig["phases"][$sPhase]["url"].$this->_aConfig["fileprefix"].".json"; + $sJsonUrl=$this->_aPrjConfig["phases"][$sPhase]["url"].$this->_aPrjConfig["fileprefix"].".json"; $sJsonData=@file_get_contents($sJsonUrl); if ($sJsonData){ $aJson=json_decode($sJsonData, true); @@ -291,9 +342,9 @@ class project { */ public function isActivePhase($sPhase){ return ( - array_key_exists($sPhase, $this->_aConfig["phases"]) - && array_key_exists("url", $this->_aConfig["phases"][$sPhase]) - && $this->_aConfig["phases"][$sPhase]["url"] + array_key_exists($sPhase, $this->_aPrjConfig["phases"]) + && array_key_exists("url", $this->_aPrjConfig["phases"][$sPhase]) + && $this->_aPrjConfig["phases"][$sPhase]["url"] ); } @@ -303,14 +354,14 @@ class project { */ public function getNextPhase($sPhase=false){ if ($sPhase){ - if (!array_key_exists($sPhase, $this->_aPhases)){ + if (!array_key_exists($sPhase, $this->_aConfig["phases"])){ die("ERROR: this phase does not exist: $sPhase."); } } $sNextPhase=false; $bUseNextPhase=$sPhase?false:true; - foreach(array_keys($this->_aPhases) as $s){ + foreach(array_keys($this->_aConfig["phases"]) as $s){ if ($bUseNextPhase){ if ($this->isActivePhase($s)){ $sNextPhase=$s; @@ -338,7 +389,7 @@ class project { } - if (!array_key_exists($sPhase, $this->_aPhases)){ + if (!array_key_exists($sPhase, $this->_aConfig["phases"])){ die("ERROR: in canDeploy this phase does not exist: $sPhase."); } if (!$this->isActivePhase($sPhase)){ @@ -387,12 +438,12 @@ class project { * @return boolean */ public function setProjectById($sId) { - $this->_aConfig = array(); + $this->_aPrjConfig = array(); require($this->_sCfgfile); if (!array_key_exists("$sId", $aProjects)){ die("ERROR: a project with ID $sId does not exist."); } - $this->_aConfig=$aProjects[$sId]; + $this->_aPrjConfig=$aProjects[$sId]; $_aConfig["id"]=$sId; $this->_verifyConfig(); return true; @@ -404,20 +455,55 @@ class project { public function build(){ $sReturn=false; - switch ($this->_aConfig["build"]["type"]) { + switch ($this->_aPrjConfig["build"]["type"]) { case "git": $sTempDir=$this->_getTempDir(); $sFirstLevel=$this->getNextPhase(); - // $this->_execAndSend($sCommand); - $sReturn.="TODO:<br>"; - @mkdir($sTempDir); + // --- checkout + $sReturn.="<h3>Checkout</h3>"; + if (!file_exists($sTempDir)) { + $sReturn.="* create ".$sTempDir."<br>"; + mkdir($sTempDir); + } + if (!file_exists($sTempDir)) { + die("ERROR: build - $sTempDir was not created."); + } + + // $sReturn.=$this->_execAndSend("find " . $this->_aConfig["workDir"]); + $sReturn.=$this->_execAndSend("cd $sTempDir && git init"); + + $sKeyfile=dirname(dirname(__file__))."/".$this->_aPrjConfig["build"]["keyfile"]; + $sWrapper=dirname(dirname(dirname(dirname(__file__))))."/shellscripts/gitsshwrapper.sh"; + $sReturn.=$this->_execAndSend("ls -l ".$sWrapper); + // $sReturn.=$this->_execAndSend("ls -l ".$sKeyfile); + $sReturn.=$this->_execAndSend("cd $sTempDir && export GIT_SSH=$sWrapper ; export PKEY=$sKeyfile; git pull ".$this->_aPrjConfig["build"]["ssh"]); + + $sVersion.=$this->_execAndSend("cd $sTempDir && export GIT_SSH=$sWrapper ; export PKEY=$sKeyfile; git pull ".$this->_aPrjConfig["build"]["ssh"]); + + $sReturn.=$this->_execAndSend("ls -lisa $sTempDir"); + $sVersioninfo=shell_exec("cd $sTempDir && git log -1"); + + $sReturn.=$sVersioninfo; + + // --- execute hook + $sHookfile=$this->_aConfig['hooks']['build-aftercheckout']; + $sReturn.='<h3>Execute Hook '.$sHookfile.'</h3>'; + if (file_exists($sTempDir.'/'.$sHookfile)){ + $sReturn.=$this->_execAndSend('cd '.$sTempDir.' && bash "'.$sHookfile .'"'); + } else { + $sReturn.='SKIP. Hook was not found.<br>'; + } + + // --- create package + $sReturn.='<h3>Create package</h3>'; + if (!file_exists($sTempDir.'/public_html')){ + $sReturn.='ERROR: a subdir public_html does not exist.'; + return $sReturn; + } - $this->_execAndSend(""); - $sReturn.="* GIT PULL ".$this->_aConfig["build"]["url"]."<br>"; - $sReturn.="* wenn Hook-Skript im Projekt, dann ausfuehren<br>"; $sReturn.="* Check: gibt es ein public_html - wenn nein: abbrechen<br>"; $sReturn.="* <br>"; $sReturn.="* Info-JSON erstellen und in public_html ablegen<br>"; @@ -432,7 +518,7 @@ class project { break; default: - die("Build Type not supported: " . $this->_aConfig["build"]["type"]); + die("Build Type not supported: " . $this->_aPrjConfig["build"]["type"]); break; } return $sReturn; diff --git a/public_html/deployment/config/inc_projects_config.php b/public_html/deployment/config/inc_projects_config.php index e8211095..ad59d1fd 100644 --- a/public_html/deployment/config/inc_projects_config.php +++ b/public_html/deployment/config/inc_projects_config.php @@ -8,7 +8,10 @@ $aConfig=array( // Basispfad: - 'workDir'=>"/var/imldeployment", + 'workDir'=>'/var/imldeployment', + 'hooks'=>array( + 'build-aftercheckout'=>'hooks/build.sh', + ), 'phases'=>array( @@ -36,7 +39,10 @@ $aProjects=array( "contact" => 'axel.hahn@iml.unibe.ch', "build"=>array( "type"=>"git", // one of git, svn, ... - "url"=>"gitlab.iml.unibe.ch:admins/imldeployment.git", + "ssh"=>"git@gitlab.iml.unibe.ch:admins/imldeployment.git", + + // der public Key muss beim Git-Repo hinterlegt sein + "keyfile"=>"config/sshkeys/git@gitlab.iml.unibe.ch", ), "phases"=>array( @@ -58,7 +64,10 @@ $aProjects=array( "contact" => 'Entwickler, Verantwortliche etc.', "build"=>array( "type"=>"git", // one of git, svn, ... - "url"=>"ssh gituser@gitserver:/path/to/project", + // for github: + // generate ssh keypair + // https://help.github.com/articles/generating-ssh-keys + "ssh"=>"ssh gituser@gitserver:/path/to/project", ), "phases"=>array( @@ -127,8 +136,7 @@ switch ($_SERVER["SERVER_NAME"]) { break; } + $aConfig=array_merge($aConfig, array( - 'builtDir'=>$aConfig['workDir'].'/built', 'packageDir'=>$aConfig['workDir'].'/packages', )); - diff --git a/public_html/deployment/config/sshkeys/git@gitlab.iml.unibe.ch b/public_html/deployment/config/sshkeys/git@gitlab.iml.unibe.ch new file mode 100644 index 00000000..ffe9dd74 --- /dev/null +++ b/public_html/deployment/config/sshkeys/git@gitlab.iml.unibe.ch @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAz36Hcm+QX0lI5sm9BLy9I1HkWXtHgHDAsDYdPGkkzp5DjxHF +QsroQqhKObl17NCIJm4B6i5ORB2mvfVXk9R/3hP24NRvfI0TSS2rU0HbHY37zKPF +TQ4gQaDcEnafDOmy6j9PXoGgQ8PyA+LvDWmKLJZDQbHIis2aWzlb7/KUne1VHqQU +rUKagMz0aFvvAeC25IwBmH5Lwimb6vYwbxSBqoAT7KXmruwu8LFhBDjQqaiq5c7z +q7FkSQovJtss1mVc5/mW0SYkS8ekxjOmIY6pPswVroYEefA5b2vw2MrC5cSU0pQ5 +TdHgxmkNmy+QAWTKs7pTR/7nDGNU9y8Sc04WUQIDAQABAoIBAQCKjAIE91l/Rn/X +Gn2L3Dquis/er+JecOs4velnnQ1mqWaS8Vq17qaHW7e0M5H6PoOqpWnB5Il+Eg50 +aI3Bt/JpZwtBtJd8ovZttoDfZunYIiYvzmq/uN7w82f/LBWnmaRNpVhp0kQg+4Vt +8umMGxyYCP1/sCYoCIE4yGQLI/74M3z88ldTC9un5xbx5hVHucOIlx24AwSWaNAS +IFJGOYtIyWD/3ZkI/JH1irnX71lGE0G64VLujzVZC9SpqYETKmr5xHJapYEdvltx +w6vwjGCZV9jpsyXtHPeyYSaSmqQaK0+PL0ZpkEnZei8ulduXgcjl21Wh+bUBJhlS +Eoqe60DBAoGBAOqRstkffnrB/1itdjtvgWT7G3WEgU/pHUUp4TzNZshBrZP65w8F +yiy7hNxbiz+JWy1gGSJSwP4YBQPEAeY+dGiPw3wjye3gn4zIwoGrgbEShBNiOK7z +M+L13fFyJnkFz7YS2PWv488j8NpXspY9+0KrfDw5S2jtzfNE9PpG0HbTAoGBAOJz +lIrNfXZl9ZU4D0/mJrgEbZvO5/F/HMZbVbK6OgYmJpcaeGbtDgHqH/qsviCV4u0b +LIRoXutugmvwYoa64YVnAPYVlhVDwOQiU3v0LUFV+mZxTDaK7kr3Na3aI4wd1J1C +l9mbvOh8iY84+a/VZijLeG4fXbZ/ZWV8bif74I/LAoGBAOIwtOGh+Piu8We1fPk7 +QO77JTNhHsDL7amwBL3440/f5V146C4YSyhvemJy9AfEj+Nlc1chrXBYAR3seFhp +iR764mpmqGV14OSFAuq/U0RIsotuf3JUmogUxnv4sxiofe74pbXkcixgX/Rr9I3k +HtHfQuFf7lO0XJBkwkZE2uh5AoGBALMFMG8y2HabUDRxJxnBFubvCT/dqFuwY60k +U3GB65Ek4+kc0gZ8bVByKGnh2kSkect8agsa/78blBuE5D8iylrN/WKN2iJhd8Ji +qKEbfhNixxvpgZi06IF3QYZ5JxUEGCtik+1CQ2t/2LfTEQFCsQqbIE/emBVITX6X +ifYuF29VAoGAEfxoPdtEjzsd7jxw3vnAGVAHNR2g9sklpcJnMcrkokuZjti+iE3g +xOqkzRzfJyYSRz46VzzgDJUJWluxudDaaSXvGmVOgeFPlF2jHdsS0XfiE8NrfBD3 +36GY7UZ+grbNktguaKtCkPXuKIxtM30+1c7kZVoTQ+dnTKErCyjuU0Y= +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/public_html/deployment/config/sshkeys/git@gitlab.iml.unibe.ch.pub b/public_html/deployment/config/sshkeys/git@gitlab.iml.unibe.ch.pub new file mode 100644 index 00000000..2ddfb0dc --- /dev/null +++ b/public_html/deployment/config/sshkeys/git@gitlab.iml.unibe.ch.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDPfodyb5BfSUjmyb0EvL0jUeRZe0eAcMCwNh08aSTOnkOPEcVCyuhCqEo5uXXs0IgmbgHqLk5EHaa99VeT1H/eE/bg1G98jRNJLatTQdsdjfvMo8VNDiBBoNwSdp8M6bLqP09egaBDw/ID4u8NaYoslkNBsciKzZpbOVvv8pSd7VUepBStQpqAzPRoW+8B4LbkjAGYfkvCKZvq9jBvFIGqgBPspeau7C7wsWEEONCpqKrlzvOrsWRJCi8m2yzWZVzn+ZbRJiRLx6TGM6Yhjqk+zBWuhgR58Dlva/DYysLlxJTSlDlN0eDGaQ2bL5ABZMqzulNH/ucMY1T3LxJzThZR imldeploy \ No newline at end of file diff --git a/shellscripts/gitsshwrapper.sh b/shellscripts/gitsshwrapper.sh new file mode 100644 index 00000000..201c2c9f --- /dev/null +++ b/shellscripts/gitsshwrapper.sh @@ -0,0 +1,14 @@ +#!/bin/bash +# wrapper to make git remote command with ssh private key file +# http://alvinabad.wordpress.com/2013/03/23/how-to-specify-an-ssh-key-file-with-the-git-command/ +# +# SYNTAX: +# gitwrapperssh.sh [keyfile] [command] +# + +if [ -z "$PKEY" ]; then + # if PKEY is not specified, run ssh using default keyfile + ssh "$@" +else + ssh -i "$PKEY" "$@" +fi \ No newline at end of file -- GitLab