Select Git revision
check_couchdb
-
Hahn Axel (hahn) authoredHahn Axel (hahn) authored
project_gui.class.php 78.71 KiB
<?php
require_once 'project.class.php';
require_once 'htmlguielements.class.php';
/* ######################################################################
IML DEPLOYMENT
class project for all actions for single project
Rendering of web ui
---------------------------------------------------------------------
2013-11-08 Axel <axel.hahn@iml.unibe.ch>
###################################################################### */
/**
* class for single project
*/
// class project {
class projectgui extends project {
/**
* constructor
* @param string $sId id of the project
public function __construct($sId = false) {
parent::__construct($sId);
$this->_oHtml = new htmlguielements();
}
*/
// ----------------------------------------------------------------------
// private functions
// ----------------------------------------------------------------------
/**
* return html code for a div with background color based on a checksum of the given text
* @param string $sText text that is used for checksum; if false ist returns a gray
* @param string $sContent optional: text to show
* @return string
*/
private function _getChecksumDiv($sText, $sContent='', $sBarHeight='3px') {
if ($sText){
// color ranges in decimal values for RGB from ... to
$iFgStart=60; $iFgEnd=160;
$iBgStart=200; $iBgEnd=250;
$iFgStart=60; $iFgEnd=160;
$iBgStart=190; $iBgEnd=250;
// deivider: 3 digits of md5 will be extracted
$iFgDivider=16*16*16/($iFgEnd-$iFgStart);
$iBgDivider=16*16*16/($iBgEnd-$iBgStart);
$sHash=md5($sText);
$sColor=''
. 'color: rgba('
. ($iFgStart + round(hexdec(substr($sHash,0,3))/$iFgDivider)) . ','
. ($iFgStart + round(hexdec(substr($sHash,3,3))/$iFgDivider)) . ','
. ($iFgStart + round(hexdec(substr($sHash,6,3))/$iFgDivider)) . ','
. '1'
. ');'
. 'background: rgba('
. ($iBgStart + round(hexdec(substr($sHash,0,3))/$iBgDivider)) . ','
. ($iBgStart + round(hexdec(substr($sHash,3,3))/$iBgDivider)) . ','
. ($iBgStart + round(hexdec(substr($sHash,6,3))/$iBgDivider)) . ','
. '1'
. ');'
;
} else {
$sColor = "color: #888; background: #ccc;";
}
return '<div style="' . $sColor . ' border-top: '.$sBarHeight.' solid;">'.($sContent ? $sContent : ' ').'</div>';
}
/**
* get html code for the colored bar on top of each phase detail items
* @param string $sPhase phase of a project
* @param string $sPlace place in the given phase
* @return string
*/
private function _renderBar($sPhase, $sPlace, $sBarHeight='3px') {
$aDataPhase = $this->getPhaseInfos($sPhase);
$aData = $aDataPhase[$sPlace];
if (!array_key_exists("revision", $aData)) {
return false;
}
return $this->_getChecksumDiv($aData["revision"], '', $sBarHeight);
}
private function _renderHostsData($aData) {
$sReturn = '';
if (array_key_exists('_hosts', $aData)) {
// $sReturn.= print_r($aData['_hosts'], 1);
$sReturn.= '<div class="hosts">'
. '<br><strong>' . t('hosts') . ':</strong><br>'
;
foreach ($aData['_hosts'] as $sHostname => $aHostinfos) {
$oUpdateDate = date("U", strtotime($aHostinfos['time']));
$iAgeUpdate = round((date("U") - $oUpdateDate) / 60);
$sAge = $iAgeUpdate < 60 * 60 * 13 ? $iAgeUpdate . " min" : "??";
$sReturn.= '<div class="host">'
. $this->_getChecksumDiv(
$aHostinfos['_data']['revision'],
$this->_oHtml->getIcon('host').'<br>' . $sHostname
)
. "($sAge)"
. '</div>'
;
}
$sReturn.= '</div><div style="clear: both;"></div>';
}
return $sReturn;
}
/**
* get html code for list of hosts in a phase
* @param string $sPhase phase of a project
* @return string
*/
private function _renderHosts($sPhase) {
$aDataPhase = $this->getPhaseInfos($sPhase);
if (is_array($aDataPhase) && array_key_exists('deployed', $aDataPhase)) {
return $this->_renderHostsData($aDataPhase['deployed']);
}
return '';
}
/**
* get html code for list of files in a phase
* @param string $sPhase phase of a project
* @return string
*/
private function _renderFiles($sPhase) {
$sReturn = '';
$aFiles = $this->getBuildfilesByPlace($sPhase, 'ready2install');
if (!$aFiles || !$aFiles['filecount']) {
return '';
}
$sReturn.='<strong>' . t("filelist") . '</strong> (' . $aFiles['filecount'] . '):<br>';
foreach ($aFiles['files'] as $sFilename => $aData) {
$sReturn.='<div class="file file-' . $aData['type'] . ' fileext-' . $aData['extension'] . '" title="' . $sFilename . ' (' . $aData['type'] . ')">'
. $aData['icon'] . $sFilename
// . ' ('.$aData['type'].')'
. '</div>'
;
}
$sReturn.='(' . $aFiles['totalsize-hr'] . ')';
return $sReturn;
}
// ----------------------------------------------------------------------
// RENDERING
// ----------------------------------------------------------------------
/**
* render html for a row with td for all places of a phase
* @param string $sPhase phase
* @param bool $bActions draw action links (deploy, accept) on/ off
* @param bool $bLong use long variant to display infos?
* @return string|boolean
*/
public function renderAllPhaseDetails($sPhase, $bActions = true, $bLong = true) {
if (!$sPhase) {
return false;
}
if (!$this->isActivePhase($sPhase)) {
return '
<td class="td-phase-' . $sPhase . ' td-phase-inactive ' . $this->_aConfig["id"] . '" colspan="' . count($this->_aPlaces) . '">
<div class="versioninfo center inactive">' . $this->_oHtml->getIcon('sign-info').t('inactive') . '</div>
</td>';
}
$sRow2 = false;
$aRows = array();
$sLastPlace = '';
foreach (array_keys($this->_aPlaces) as $sPlace) {
$aRows[$sPlace] = $this->renderPhaseDetail($sPhase, $sPlace, $bActions, $bLong);
// generate ">>" sign for lastly generated td
if ($sLastPlace && array_key_exists("version", $this->_aData["phases"][$sPhase][$sLastPlace])
&& array_key_exists("version", $this->_aData["phases"][$sPhase][$sPlace])
&& $this->_aData["phases"][$sPhase][$sLastPlace]["version"] == $this->_aData["phases"][$sPhase][$sPlace]["version"]
&& !$bLong
) {
$aRows[$sLastPlace] = $this->_renderBar($sPhase, $sPlace) . "»";
}
$sLastPlace = $sPlace;
}
foreach (array_keys($this->_aPlaces) as $sPlace) {
$sRow2.='<td class=" td-phase-'.$sPhase.' td-place-'.$sPlace.' td' . $this->_aConfig["id"] . '">' . $aRows[$sPlace] . '</td>';
}
return $sRow2;
}
/**
* return html code for current project errors by rendering a box per error in $this->_errors
* @return string
*/
public function renderErrorBoxes(){
$sReturn='';
if(count($this->_errors)){
foreach($this->_errors as $sError){
$sReturn.=$this->_oHtml->getBox("error", $sError);
}
}
return $sReturn;
}
/**
* fix output of commit message as html
* This is a compatibility function for older builds
*
* @param string $sMessage git commit message
* @return string
*/
public function transformCommitMessage($sMessage){
if(strstr($sMessage, '<br>Date:')){
$_aReplace=[
'<br>Author:' => "\nAuthor:",
'<br>Date:' => "\nDate:",
'<br><br>' => "\n\n",
];
$sMessage=str_replace(array_keys($_aReplace), array_values($_aReplace), $sMessage)." *";
}
return htmlentities($sMessage);
}
/**
* render html code for info link that shows popup with metadata on mouseover
* @param array $aInfos metainfos of the package (from json file)
* one of ok=1|error=message - status key
* date - timestamp of build
* revision - revision
* branch - branch
* message - commit message
* @param array $aOptions options
* title - tile in popover; default: empty
* label - link label; default: empty (results in Infos|ERROR)
* more - additional infos in popover; default: empty
* hpos - horizontal position; one of left|right; default: right
* @return string
*/
public function renderInfoLink($aInfos, $aOptions = array()) {
$sReturn = '';
$bIsError = false;
$this->_oHtml = new htmlguielements();
$sInfos='';
$sTitle='';
if (array_key_exists("title", $aOptions) && $aOptions["title"]) {
$sTitle.=$aOptions["title"];
}
if (array_key_exists("ok", $aInfos)) {
$sLinktitle = t('infos');
if (array_key_exists("message", $aInfos)) {
$sInfos.=$this->_getChecksumDiv($aInfos["revision"],
$this->_oHtml->getIconByType('calendar') . t('build-from') . ' ' . date("d.m.Y H:i:s", strtotime($aInfos["date"])) . '<br>'
. $this->_oHtml->getIconByType('branch') . t('branch') . ': ' . $aInfos["branch"] . '<br>'
. $this->_oHtml->getIconByType('revision') . t('revision') . ': ' . $this->_renderRevision($aInfos["revision"]) . '<br>'
. $this->_oHtml->getIconByType('comment') . t('commitmessage') . ': '
)
. '<pre>' . $this->transformCommitMessage($aInfos["message"]) . '</pre>';
if (array_key_exists("more", $aOptions)) {
$sInfos.=$aOptions["more"];
}
}
} else {
$bIsError = true;
if (!$sTitle) {
$sTitle.=' ' . t('error');
}
$sLinktitle = t('error');
$sInfos = $this->_oHtml->getBox('error', '') . '<p>'.$aInfos["error"].'</p>';
}
$sInfos.=$this->_renderHostsData($aInfos, '');
if (array_key_exists("label", $aOptions) && $aOptions["label"]) {
$sLinktitle.=$aOptions["label"];
}
// render html
$sId = 'info' . md5($sInfos);
$sReturn = '<a href="#" class="btn ' . ($bIsError ? 'btn-danger' : 'btn-default') . '" title=""
onclick="showIdAsModalMessage(\'' . $sId . '\', \''.$sTitle.'\'); return false;"
>'
. $this->_oHtml->getIcon($bIsError ? 'sign-error' : 'sign-info') // ... '<i class="fa fa-info"></i> '
. $sLinktitle
. '</a><div id="' . $sId . '" style="display: none;" '
;
if (array_key_exists("hpos", $aOptions)) {
$sReturn.=' class="' . $aOptions["hpos"] . '"';
}
$sReturn.='>';
if ($sTitle) {
// $sReturn.='<span class="title">' . $sTitle . '</span><br><br>';
}
$sReturn.=$sInfos . '</div>';
if ($bIsError) {
// $sReturn = '<div class="error">' . $sReturn . '</div>';
}
return $sReturn;
}
/**
* render html for a colored link to any project action
* @param string $sFunction name of the action; one of accept|build|cleanup|deploy|new|overview|phase|rollback|setup
* @param string $sPhase current phase where to place the link
* @return string
*/
public function renderLink($sFunction, $sPhase = false, $sVersion = false) {
$sFirst = $this->getNextPhase();
$sNext = $this->getNextPhase($sPhase);
$aLinkdata = array(
'default' => array('class' => ''),
'accept' => array('class' => $sNext,
'hint' => sprintf(t("accept-hint"), $sPhase, $sNext),
'label' => t('accept'),
),
'build' => array('class' => $sFirst,
'hint' => sprintf(t("build-hint"), $sFirst),
'label' => t('build'),
'role' => 'buildProject'
),
'cleanup' => array('class' => ''),
'deploy' => array('class' => $sPhase,
'hint' => sprintf(t("deploy-hint"), $sPhase),
'label' => t('deploy'),
),
'new' => array(
'hint' => t("new-project-hint"),
'label' => t('new-project'),
),
'overview' => array('class' => '',
'hint' => t('menu-project-home') . ' [' . $this->getLabel() . ']',
'label' => $this->getLabel()
),
'phase' => array('icon' => $this->_oHtml->getIcon('phase'), 'class' => $sPhase,
'hint' => sprintf(t('phase-details-hint'), $sPhase),
'label' => sprintf(t('phase-details'), $sPhase),
),
'rollback' => array('class' => $sPhase,
'hint' => sprintf(t('rollback-hint'), $sPhase, $sVersion),
'label' => t('rollback')
),
'setup' => array('class' => $sPhase,
'hint' => sprintf(t('setup-hint'), $sPhase, $sVersion),
'label' => t('setup'),
'class' => 'btn'
),
);
/*
if (!$this->oUser->hasRole("project-action-$sFunction")){
// $sClass .= ' disabled';
// return '<span title="no permission [project-action-'.$sFunction.']">[ ]</span>';
}
*
*/
// fuer wen ist der Link
$sRole = '';
$sOnMouseover = '';
$sOnMouseout = '';
switch($sFunction){
case 'accept';
$sRole = 'developer';
if ($sNext == "live") {
$sRole = 'pl';
// $aLinkdata[$sFunction]['icon']='glyphicon glyphicon-star';
}
$sOnMouseover = '$(\'.td-phase-' . $sNext . '.td' . $this->_aConfig["id"] . '\').addClass(\'highlight\');';
$sOnMouseout = '$(\'.td-phase-' . $sNext . '.td' . $this->_aConfig["id"] . '\').removeClass(\'highlight\');';
break;
case 'build';
$sRole = 'developer';
$sOnMouseover = '$(\'.td-phase-' . $sNext . '.td' . $this->_aConfig["id"] . '\').addClass(\'highlight\');';
$sOnMouseout = '$(\'.td-phase-' . $sNext . '.td' . $this->_aConfig["id"] . '\').removeClass(\'highlight\');';
break;
case 'deploy';
$sRole = 'developer';
$sOnMouseover = '$(\'.td-phase-' . $sPhase . '.td-place-ready2install.td' . $this->_aConfig["id"] . '\').addClass(\'highlight\');'
.'$(\'.td-phase-' . $sPhase . '.td-place-deployed.td' . $this->_aConfig["id"] . '\').addClass(\'highlight\');'
;
$sOnMouseout = '$(\'.td-phase-' . $sPhase . '.td-place-ready2install.td' . $this->_aConfig["id"] . '\').removeClass(\'highlight\');'
.'$(\'.td-phase-' . $sPhase . '.td-place-deployed.td' . $this->_aConfig["id"] . '\').removeClass(\'highlight\');'
;
break;
}
// $sClass = $sPhase;
$sIconClass = (array_key_exists($sFunction, $aLinkdata)) ? $aLinkdata[$sFunction]['icon'] : $aLinkdata['default']['icon'];
$sHint = isset($aLinkdata[$sFunction]['hint']) ? $aLinkdata[$sFunction]['hint'] : "";
$sLabel = isset($aLinkdata[$sFunction]['label']) ? $aLinkdata[$sFunction]['label'] : $sFunction;
$sClass = isset($aLinkdata[$sFunction]['class']) ? $aLinkdata[$sFunction]['class'] : '';
if ($sRole) {
$sClass .= " role role" . $sRole;
}
$sLink = "/deployment/" . ($this->_aConfig["id"] ? $this->_aConfig["id"] : 'all/setup') . "/";
if ($sFunction != "overview") {
$sLink.="$sFunction/";
}
if ($sPhase) {
$sLink.="$sPhase/";
}
if ($sVersion) {
$sLink.="$sVersion/";
}
if (!$this->oUser->hasPermission("project-action-$sFunction")) {
// $sClass .= ' disabled';
return '<span class="btn disabled btn-default" title="no permission [project-action-' . $sFunction . '] for user [' . $this->oUser->getUsername() . ']"><i class="' . $sIconClass . '"></i> ' . $sLabel . '</span>';
}
// $sClass='btn ' . (strstr('btn-', $sClass) ? '': 'btn-default ') .$sClass;
return $this->_oHtml->getLinkButton(array(
'href' => $sLink,
'title' => $sHint,
'class' => $sClass,
'type' => $sFunction,
'onmouseover' => $sOnMouseover,
'onmouseout' => $sOnMouseout,
'label' => $sLabel,
));
// return '<a href="' . $sLink . '" ' . $sOnMouseover . ' title="' . $sHint . '" class="btn btn-default ' . $sClass . '"><i class="' . $sIconClass . '"></i> ' . $sLabel . '</a>';
}
/**
* return html code for the setup form for a new project
* @return string
*/
public function renderNewProject() {
global $aParams;
if (!$this->oUser->hasPermission("project-action-create")) {
return $this->oUser->showDenied();
}
require_once ("formgen.class.php");
$i = 0;
$sID = array_key_exists("id", $aParams) ? $aParams["id"] : "";
$aForms = array(
'setup' => array(
'meta' => array(
'method' => 'POST',
'action' => '?',
),
'validate' => array(),
'form' => array(
'input' . $i++ => array(
'type' => 'hidden',
'name' => 'setupaction',
'value' => 'create',
),
'input' . $i++ => array(
'type' => 'text',
'name' => 'id',
'label' => t("class-project-info-setup-projectId"),
'value' => $sID,
'required' => 'required',
'validate' => 'isastring',
'size' => 100,
'pattern' => '[a-z0-9\-_]*',
'placeholder' => t("class-project-info-setup-projectId-placeholder"),
),
),
),
);
$aForms["setup"]["form"]['input' . $i++] = array(
'type' => 'submit',
'name' => 'btnsave',
'label' => t("save"),
'value' => $this->_oHtml->getIcon('sign-ok') . t("save"),
);
$oForm = new formgen($aForms);
return $oForm->renderHtml("setup");
}
/**
* render html for a place of a phase
* @param string $sPhase phase
* @param string $sPlace name of the place; one of onhold|ready2install|deployed
* @param bool $bActions draw action links (deploy, accept) on/ off
* @param bool $bLong use long variant to display infos?
* @return string|boolean
*/
public function renderPhaseDetail($sPhase, $sPlace, $bActions = true, $bLong = true) {
if (!$sPhase) {
return false;
}
if (!$sPlace) {
return false;
}
if (!$this->isActivePhase($sPhase)) {
return false;
}
if (!array_key_exists($sPlace, $this->_aPlaces)) {
return false;
}
$sReturn = '';
$aDataPhase = $this->getPhaseInfos($sPhase);
$aData = $aDataPhase[$sPlace];
// foreach($aDataPhase[$sPlace] as $aData) {
if (array_key_exists("ok", $aData) && array_key_exists("version", $aData)) {
// TODO: getChecksumDiv anhand der Repo-Versionsnummer - dann kann man beim build auch die Farbe mit dem Repo HEAD vergleichen
// time
$sDateFormat = "d.m.Y H:i";
$oPkgDate = date("U", strtotime($aData["date"]));
/*
$iAge=date("U")-$oPkgDate;
$sAgeClass="";
if ($iAge< 60*60*24*3){
$sAgeClass="last1d";
}
if ($iAge< 60*60){
$sAgeClass="last1h";
}
*/
if ($bLong) {
// long display of the revision
// $sJsonUrl = $this->_getInfofile($sPhase, $sPlace);
$sReturn .=$this->_getChecksumDiv(
$aData["revision"],
$this->_oHtml->getIconByType('calendar') .' ' . date($sDateFormat, $oPkgDate) . '<br>'
. $this->_oHtml->getIconByType('branch') . t('branch') . ': ' . $aData["branch"] . '<br>'
. $this->_oHtml->getIconByType('revision') . t('revision') . ': ' . $this->_renderRevision($aData["revision"]) . '<br>'
. $this->_oHtml->getIconByType('comment') . t('commitmessage') . ':<br>'
)
. '<pre>' . $this->transformCommitMessage($aData["message"]) . '</pre>'
// . '<i class="glyphicon glyphicon-globe"></i> ' . t('url') . ': <a href="' . $sJsonUrl . '">' . $sJsonUrl . '</a><br>'
;
if ($sPlace == "deployed" && array_key_exists("url", $this->_aPrjConfig["phases"][$sPhase])) {
$sUrl = $this->_aPrjConfig["phases"][$sPhase]["url"];
$sReturn.=$this->_oHtml->getIconByType('link-extern') . ' '. t('url') . ': <a href="' . $sUrl . '">' . $sUrl . '</a><br>';
}
} else {
$sReturn .= $this->_getChecksumDiv(
$aData["revision"],
$this->_oHtml->getIconByType('calendar') .' ' . date($sDateFormat, $oPkgDate)
);
if ($sPlace == "deployed" && array_key_exists("url", $this->_aPrjConfig["phases"][$sPhase])) {
$sMore = $this->_oHtml->getIconByType('link-extern').' '
. t('url')
. ': <a href="' . $this->_aPrjConfig["phases"][$sPhase]["url"] . '">' . $this->_aPrjConfig["phases"][$sPhase]["url"] . '</a><br>';
}
$sReturn.=' ' . $this->renderInfoLink(
$aData,
[
'title' => $this->getLabel() . " :: $sPhase :: $sPlace",
'more' => $sMore,
]
);
}
switch ($sPlace) {
case "onhold":
if (array_key_exists("phases", $this->_aConfig) && array_key_exists($sPhase, $this->_aConfig["phases"])) {
// $sReturn .= print_r($this->_aConfig["phases"][$sPhase], true);
if (count($this->_getDeploytimes($sPhase))) {
$sReturn .= '<br>'.$this->_oHtml->getIcon('time').t('deploytimes') . ':<br>'
. implode("<br>", array_values($this->_getDeploytimes($sPhase)))
. '<br>';
}
if ($bActions) {
$sReturn .= ' ' . $this->renderLink("deploy", $sPhase);
}
}
break;
case "ready2install":
/*
// IDEA: try to install the same phase again. Needs update of method project->deploy()
if ($bActions) {
$sReturn .= ' ' . $this->renderLink("deploy", $sPhase);
}
*/
break;
case "deployed":
if ($bActions && $this->canAcceptPhase($sPhase)) {
$sReturn .= ' ' . $this->renderLink("accept", $sPhase);
}
break;
default:
break;
}
// $this->_getChecksumDiv($aData["revision"])
} else {
if (array_key_exists("error", $aData)) {
$sReturn.=''
. $this->renderInfoLink(array('error' => $aData["error"]), array())
;
} else if (array_key_exists("warning", $aData)) {
$sReturn.= '<div class="warning">'.$this->_oHtml->getIcon('sign-info'). t('warning') . ':<br>' . $aData["warning"] . '</div>';
} else {
// OK = 1 ... for the queue we show no hint
return '';
/*
return $sPlace=='onhold'
? t('class-project-queue-empty')
: ''
;
*/
}
} // if
// } // for
return $sReturn;
}
/**
* render html for the project overview; it shows the defined phases for
* the project as a table
* @return type
*/
public function renderPhaseInfo() {
$sRow1 = false;
$sRow2 = false;
$renderAdminLTE=new renderadminlte();
$iWidth=min(12 / count($this->getActivePhases()), 4);
foreach ($this->getActivePhases() as $sPhase) {
$sRow1.=$renderAdminLTE->addCol(
'<table class="nomargin"><tr><th class="' . $sPhase . ' tdphase">' . $sPhase . '</th></tr></table>'
,
$iWidth);
$sDetails=t('url') . ': <a href="' . $this->_aPrjConfig["phases"][$sPhase]["url"] . '">' . $this->_aPrjConfig["phases"][$sPhase]["url"] . '</a><br>'
. '<br>' . t('deploytimes') . ':<br>';
if (count($this->_getDeploytimes($sPhase))) {
$sDetails.=implode("<br>", $this->_getDeploytimes($sPhase));
} else {
$sDetails.=t('deploytimes-immediately');
}
$sDetails.='<br>' . $this->renderLink("phase", $sPhase)
. $this->_renderHosts($sPhase)
. '<br>'
. $this->_renderFiles($sPhase)
;
$sRow2.=$renderAdminLTE->addCol(
$renderAdminLTE->getCard(array (
'class' => $sPhase,
'variant' => '',
'tb-remove' => 1,
'tb-collapse' => 1,
'title' => '',
'tools' => '',
'text' => $sDetails,
'footer' => '',
)),
$iWidth
);
}
return ''
.$renderAdminLTE->addRow($sRow1)
.$renderAdminLTE->addRow($sRow2)
;
}
/**
* render html for a row with td for all places (first row)
* @param string $sPhase phase (just needed for coloring)
* @return string
*/
public function renderPlacesAsTd($sPhase) {
$sRow1 = '';
foreach (array_keys($this->_aPlaces) as $sPlace) {
$sRow1.='<td class="' . $sPhase . ' ' . $this->_aConfig["id"] . ' tdphase">' . t($sPlace) . '</td>';
}
return $sRow1;
}
/**
* return html code for the setup form of an exsiting project
* @return string
*/
public function renderProjectSetup() {
if (!$this->oUser->hasPermission("project-action-setup")) {
return $this->oUser->showDenied();
}
$sMessages = '';
require_once ("formgen.class.php");
$aSelectProjectGroup = array(
'type' => 'select',
'name' => 'projectgroup',
'label' => t("projectgroup"),
'options' => array(
OPTION_NONE => array(
'label' => t('none'),
),
'' => array(
'label' => '- - - - - - - - - - - - - - - - - - - - ',
),
),
);
foreach($this->_aConfig['projectgroups'] as $sGroupid=>$sGroupLabel){
$bActive=$this->getProjectGroup() === $sGroupid;
$aSelectProjectGroup['options'][$sGroupid] = array(
'label' => $sGroupLabel,
'selected' => $bActive ? 'selected' : false,
);
}
$aSelectSlack = array(
'type' => 'hidden',
'name' => 'messenger[slack]',
'value' => false,
);
if (
isset($this->_aConfig['messenger']['slack']['presets'])
&& count($this->_aConfig['messenger']['slack']['presets'])
) {
$aSelectSlack = array(
'type' => 'select',
'name' => 'messenger[slack]',
'label' => t("messenger-slack"),
'options' => array(
OPTION_NONE => array(
'label' => t('none'),
),
'' => array(
'label' => '- - - - - - - - - - - - - - - - - - - - ',
),
),
);
foreach($this->_aConfig['messenger']['slack']['presets'] as $sSlackUrl=>$aSlackCfg){
$bActive=$this->_aPrjConfig['messenger']['slack'] === $sSlackUrl;
$aSelectSlack['options'][$sSlackUrl] = array(
'label' => array_key_exists('label', $aSlackCfg) ? $aSlackCfg['label'] : $sSlackUrl,
'selected' => $bActive ? 'selected' : false,
);
}
}
// ---------- Build plugins
/*
$aPluginsBuild = array(
'select' => array(
'type' => 'checkbox',
'name' => 'build[enabled_build_plugins]',
'label' => t("build-plugins"),
'options' => [],
),
// 'project-config' => '',
);
foreach (array_keys($this->getConfiguredPlugins('build')) as $sPluginName){
$sPluginFile=$this->_getPluginFilename('build', $sPluginName);
$TmpRolloutPlugin = false;
$sMyClassname='build_'. $sPluginName;
if(file_exists($sPluginFile)){
try{
include_once $this->_getPluginFilename('build', $sPluginName);
$TmpRolloutPlugin = new $sMyClassname([]);
echo "FOUND $sMyClassname<br>";
$aPluginsBuild['select']['options'][$sPluginName]=array(
'label' => $TmpRolloutPlugin->getName(),
'checked' => $bActive,
// 'onclick' => '$(\'.'.$sMyDivClass.'\').hide(); $(\'.' . $sMyDivClassActive . '\').show();',
);
} catch (Exception $ex) {
}
} else {
$aRollout['project-select']['options'][$sPluginName]=array(
'label' => 'not found: <span class="error">' . $sMyClassname . '</span>',
'checked' => false,
'disabled' => "disabled",
);
}
}
echo '<pre>'; print_r($aPluginsBuild); die(__METHOD__);
*/
// ---------- /Build plugins
// ---------- Rollout plugins
$aRollout = array(
'project-select' => array(
'type' => 'radio',
'name' => 'deploy[enabled_rollout_plugin]',
'label' => t("deploy-rollout-plugin"),
),
'project-config' => '',
);
foreach (array_keys($this->getConfiguredPlugins('rollout')) as $sPluginName){
$sPluginFile=$this->_getPluginFilename('rollout', $sPluginName);
$TmpRolloutPlugin = false;
$sMyClassname='rollout_'. $sPluginName;
$sMyDivId='rollout-'. $sPluginName.'-config';
$sMyDivClass='rolloutconfigdiv';
$sMyDivClassActive='rolloutconfigdiv-'. $sPluginName;
$bActive=$sPluginName === $this->oRolloutPlugin->getId();
if(file_exists($sPluginFile)){
try{
include_once $this->_getPluginFilename('rollout', $sPluginName);
$TmpRolloutPlugin = new $sMyClassname(array(
'lang'=>$this->_aConfig['lang'],
'phase'=>false,
'globalcfg'=>$this->_aConfig['plugins']['rollout'][$sPluginName],
'projectcfg'=>$this->_aPrjConfig,
));
$aRollout['project-select']['options'][$sPluginName]=array(
'label' => $TmpRolloutPlugin->getName(),
'checked' => $bActive,
'onclick' => '$(\'.'.$sMyDivClass.'\').hide(); $(\'.' . $sMyDivClassActive . '\').show();',
);
$aRollout['project-config'].=''
. '<div id="'.$sMyDivId.'" class="'.$sMyDivClass.' '.$sMyDivClassActive.'"'
. ($bActive ? '' : ' style="display: none;"' )
. '>'
. $TmpRolloutPlugin->renderFormdata4Project()
. '</div>'
;
// generate form firlds for each phase
foreach(array_keys($this->getPhases()) as $sMyPhase){
$aRollout[$sMyPhase].=''
. '<div id="'.$sMyDivId.'-'.$sMyPhase.'" class="'.$sMyDivClass.' '.$sMyDivClassActive.'"'
. ($bActive ? '' : ' style="display: none;"' )
. '>'
. $TmpRolloutPlugin->renderFormdata4Phase($sMyPhase)
. '</div>'
;
}
} catch (Exception $ex) {
}
} else {
$aRollout['project-select']['options'][$sPluginName]=array(
'label' => 'not found: <span class="error">' . $sMyClassname . '</span>',
'checked' => false,
'disabled' => "disabled",
);
}
}
// ---------- /Rollout plugins
$aForemanHostgroups = false;
$iForemanHostgroupDefault = false;
$sForemanHostgroupDefault = false;
if (array_key_exists('foreman', $this->_aConfig)) {
// echo '<pre>' . print_r($this->_aPrjConfig, 1) . '</pre>';
$iForemanHostgroupDefault = (int) $this->_aPrjConfig['deploy']['foreman']['hostgroup'];
require_once('foremanapi.class.php');
$oForeman = new ForemanApi($this->_aConfig['foreman']);
// $oForeman->setDebug(1);
// $oForeman->selfcheck(); die(__FUNCTION__);
$aForemanHostgroups = $oForeman->read(array(
'request' => array(
array('hostgroups'),
// array('operatingsystems',4),
),
'response' => array(
'id', 'title'
),
));
$aSelectForemanGroups = array(
'type' => 'select',
'name' => 'deploy[foreman][hostgroup]',
'label' => $this->_oHtml->getIcon('foreman') . t("foreman-hostgroup"),
'options' => array(
OPTION_NONE => array(
'label' => t('none'),
),
'' => array(
'label' => '- - - - - - - - - - - - - - - - - - - - ',
),
),
);
if ($aForemanHostgroups && count($aForemanHostgroups)) {
foreach ($aForemanHostgroups as $aItem) {
$bActive=$iForemanHostgroupDefault === (int) $aItem['id'];
$aSelectForemanGroups['options'][$aItem['id']] = array(
'label' => $aItem['title'],
'selected' => $bActive ? 'selected' : false,
);
$sForemanHostgroupDefault = $bActive ? $aItem['title'] : $sForemanHostgroupDefault;
}
}
}
$i = 0;
$aPrefixItem = count($this->getVersions()) ?
array(
'type' => 'markup',
'value' => '<div class="form-group">
<label class="col-sm-2">' . t('fileprefix') . '</label>
<div class="col-sm-10">
<input id="inputprefix" type="hidden" name="fileprefix" value="' . $this->_aPrjConfig["fileprefix"] . '">
' . $this->_aPrjConfig["fileprefix"] . '
</div></div>
',
) : array(
'type' => 'text',
'name' => 'fileprefix',
// 'disabled' => 'disabled',
'label' => t('fileprefix-label'),
'value' => $this->_aPrjConfig["fileprefix"],
'required' => 'required',
'validate' => 'isastring',
'pattern' => '[a-z0-9\-_]*',
'size' => 100,
'placeholder' => '',
);
// detect access to repo url
$aBranches=$this->getRemoteBranches(true);
// $aRepodata = $this->getRepoRevision();
// if (is_array($aRepodata) && array_key_exists("message", $aRepodata)) {
if (is_array($aBranches) && count($aBranches)) {
$sRepoCheck = '<span class="ok">' . sprintf(t('class-project-info-repoaccess'), count($aBranches)) . '</span>';
} else {
$sRepoError=sprintf(t('class-project-error-no-repoaccess'), $aRepodata["error"]);
$sRepoCheck = '<span class="error">' . $sRepoError . '</span>';
$sMessages.=$this->_oHtml->getBox("error", $sRepoError);
}
// generate datalist with exisating ssh keys for auth field
$sAuthListitems = '';
foreach ($this->_getSshKeys() as $sKey) {
$sAuthListitems.='<option value="' . $sKey . '">';
}
$aForms = array(
'setup' => array(
'meta' => array(
'method' => 'POST',
'action' => '?',
),
'validate' => array(),
'form' => array(
'input' . $i++ => array(
'type' => 'hidden',
'name' => 'setupaction',
'value' => 'save',
),
'input' . $i++ => array(
'type' => 'hidden',
'name' => 'id',
'value' => $this->_aConfig["id"],
),
'input' . $i++ => array(
'type' => 'markup',
'value' => '<div class="tabbable">
<ul class="nav nav-tabs">
<li class="active"><a href="#tab1" class="nav-link active" data-toggle="tab" aria-selected="1">' . $this->_oHtml->getIcon('list').t('setup-metadata') . '</a></li>
<li><a href="#tab2" class="nav-link" data-toggle="tab">' . $this->_oHtml->getIcon('repository').t('repositoryinfos') . '</a></li>
<li><a href="#tab3" class="nav-link" data-toggle="tab">' . $this->_oHtml->getIcon('deploy-configfile').t('deploy-configfile') . '</a></li>
<li><a href="#tab4" class="nav-link" data-toggle="tab">' . $this->_oHtml->getIcon('deploy-rollout-plugin').t('deploy-rollout-plugin') . '</a></li>
<li><a href="#tab5" class="nav-link" data-toggle="tab">' . $this->_oHtml->getIcon('phase').t('phases') . '</a></li>
<li><a href="#tab6" class="nav-link" data-toggle="tab">' . $this->_oHtml->getIcon('raw-data').t('raw-data') . '</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane fade active show" id="tab1">
<br>
',
),
// --------------------------------------------------
// Tab for metadata
// -------------------------------------------------
'input' . $i++ => array(
'type' => 'text',
'name' => 'label',
'label' => t('projectname'),
'value' => $this->_aPrjConfig["label"],
'required' => 'required',
'validate' => 'isastring',
'size' => 100,
'placeholder' => 'Projekt',
),
'input' . $i++ => array(
'type' => 'text',
'name' => 'description',
'label' => t('projectdescription'),
'value' => $this->_aPrjConfig["description"],
'required' => 'required',
'validate' => 'isastring',
'size' => 100,
'placeholder' => '',
),
'input' . $i++ => array(
'type' => 'text',
'name' => 'contact',
'label' => t('contact'),
'value' => $this->_aPrjConfig["contact"],
'required' => 'required',
'validate' => 'isastring',
'size' => 100,
'placeholder' => '',
),
'input' . $i++ => $aSelectProjectGroup,
'input' . $i++ => array(
'type' => 'markup',
'value' => '<p>' . t('messenger') . '</p>',
),
'input' . $i++ => array(
'type' => 'text',
'name' => 'messenger[email]',
'label' => t("messenger-email"),
'value' => $this->_aPrjConfig["messenger"]["email"],
'validate' => 'isastring',
'size' => 100,
'placeholder' => '',
'autocomplete' => 'off',
),
'input' . $i++ => $aSelectSlack,
// --------------------------------------------------
// Tab soources repository & build
// --------------------------------------------------
'input' . $i++ => array(
'type' => 'markup',
'value' => ' </div><div class="tab-pane fade" id="tab2">
<p>' . t('setup-hint-build') . '</p>',
),
'input' . $i++ => array(
'type' => 'text',
'name' => 'build[type]',
'label' => t("build-type"),
'value' => $this->_aPrjConfig["build"]["type"],
'required' => 'required',
'validate' => 'isastring',
'size' => 100,
'placeholder' => '',
),
'input' . $i++ => array(
'type' => 'text',
'name' => 'build[url]',
'label' => t("repository-url"),
'value' => $this->_aPrjConfig["build"]["url"],
// 'required' => 'required',
'validate' => 'isastring',
'size' => 100,
'placeholder' => '',
),
'input' . $i++ => array(
'type' => 'text',
'name' => 'build[auth]',
'label' => t("repository-auth"),
'value' => $this->_aPrjConfig["build"]["auth"],
// 'required' => 'required',
'list' => 'listauth', // listauth is the next form id below
'validate' => 'isastring',
'size' => 100,
'placeholder' => '',
),
'input' . $i++ => array(
'type' => 'markup',
'value' => '<datalist id="listauth">' . $sAuthListitems . '</datalist>',
),
'input' . $i++ => array(
'type' => 'markup',
'value' => '<div class="form-group">'
. '<label class="col-sm-2"> </label><div class="col-sm-10">'
. $sRepoCheck
. '</div></div>',
),
'input' . $i++ => array(
'type' => 'text',
'name' => 'build[webaccess]',
'label' => t("repository-urlwebgui"),
'value' => $this->_aPrjConfig["build"]["webaccess"],
'validate' => 'isastring',
'size' => 100,
'placeholder' => '',
),
'input' . $i++ => $aPrefixItem,
'input' . $i++ => array(
'type' => 'markup',
'value' => '<div style="clear: both"></div>',
),
// task#1498 - handle project without "public" directory
'input' . $i++ => array(
'type' => 'checkbox',
'name' => 'build[haspublic]',
'label' => t("repository-has-public-dir"),
'required' => false,
'validate' => 'isastring',
'options' => array(
'1' => array(
'label' => t("yes"),
'checked' => (array_key_exists('haspublic', $this->_aPrjConfig["build"]) ? $this->_aPrjConfig["build"]["haspublic"] : 0),
),
),
),
// --------------------------------------------------
// Tab for config and API key
// --------------------------------------------------
'input' . $i++ => array(
'type' => 'markup',
'value' => ' </div><div class="tab-pane fade" id="tab3">
<p>' . t('deploy-configfile-hint') . '</p>',
),
'textarea' . $i++ => array(
'type' => 'textarea',
'name' => 'deploy[configfile]',
'label' => t("deploy-configfile"),
'value' => $this->_aPrjConfig['deploy']["configfile"],
// 'required' => 'required',
'validate' => 'isastring',
'cols' => 100,
'rows' => 10,
'placeholder' => 'export myvariable="hello world"',
),
'input' . $i++ => array(
'type' => 'text',
'name' => 'api[secret]',
'label' => t("api-secret"),
'value' => $this->_aPrjConfig["api"]["secret"],
'validate' => 'isastring',
'size' => 100,
'placeholder' => '',
),
'input' . $i++ => array(
'type' => 'markup',
'value' => '<div class="col-sm-12">'
. '<p>' . t('api-secret-hint') . '<br>'
. '<a href="#" class="btn btn-default" onclick="$(\'#input'.($i-2).'\').val(generateSecret(64)); return false">'.t("api-secret-generate").'</a>'
. '</p></div>',
),
// --------------------------------------------------
// Tab rollout plugin
// --------------------------------------------------
'input' . $i++ => array(
'type' => 'markup',
'value' => ' </div><div class="tab-pane fade" id="tab4">
<p>' . t('deploy-rollout-plugin-hint') . '</p>',
),
// select box for active rollout plugin
$aRollout['project-select'],
// project based config
'input' . $i++ => array(
'type' => 'markup',
'value' => ''
. '<hr>'
.'<label class="col-sm-2">'.t('deploy-rollout-plugin-config') .'</label>'
.'<div class="col-sm-10">'. $aRollout['project-config'].'</div>'
),
// --------------------------------------------------
'input' . $i++ => array(
'type' => 'markup',
'value' => ' </div><div class="tab-pane fade" id="tab5">
<p>' . sprintf(t("class-project-info-setup-phaseinfos"), $this->getNextPhase()) . '</p>',
),
),
),
);
// --------------------------------------------------
// Tab for phases
// --------------------------------------------------
if ($aSelectForemanGroups) {
$aForms["setup"]["form"]['input' . $i++] = array(
'type' => 'markup',
'value' => '<strong>'.t("defaults-all-phases").'</strong><br><br>',
);
$aForms["setup"]["form"]['input' . $i++] = $aSelectForemanGroups;
$aForms["setup"]["form"]['input' . $i++] = array(
'type' => 'markup',
'value' => '<br><br>',
);
}
foreach (array_keys($this->getPhases()) as $sPhase) {
$bActivePhase = $this->isActivePhase($sPhase);
$sUrl = array_key_exists("url", $this->_aPrjConfig["phases"][$sPhase]) ? $this->_aPrjConfig["phases"][$sPhase]["url"] : "";
$sDeploymethod = array_key_exists("deploymethod", $this->_aPrjConfig["phases"][$sPhase]) ? $this->_aPrjConfig["phases"][$sPhase]["deploymethod"] : "";
$sDeployhosts = array_key_exists("hosts", $this->_aPrjConfig["phases"][$sPhase]) ? $this->_aPrjConfig["phases"][$sPhase]["hosts"] : "";
/*
* task-1847 - reove adding ssh key
if($sDeployhosts){
echo "$sDeployhosts<br>";
if(!strpos($sDeployhosts, ",")){
$sCmd=sprintf($this->_aConfig["installPackages"]["addkeycommand"], $sDeployhosts, $sDeployhosts);
exec($sCmd . " 2>&1", $aOut);
echo "<pre>\$ $sCmd<br>"
. implode('<br>', $aOut)
."</pre>"
;
}
}
*/
$sDeploytimes = array_key_exists("deploytimes", $this->_aPrjConfig["phases"][$sPhase]) ? $this->_aPrjConfig["phases"][$sPhase]["deploytimes"] : "";
$sDivId4PhaseSettings = 'divSettings' . $sPhase;
$sDivId4TargetHosts = 'divSettings' . $sPhase . 'hosts';
if ($aSelectForemanGroups) {
$iForemanHostgroup = (int) $this->_aPrjConfig['phases'][$sPhase]['foreman-hostgroup'];
$aSelectForemanHostGroup = array(
'type' => 'select',
'name' => 'phases[' . $sPhase . '][foreman-hostgroup]',
'label' => $this->_oHtml->getIcon('foreman') . t("foreman-hostgroup"),
'options' => array(
OPTION_DEFAULT => array(
'label' => t('default') . ' (' . $sForemanHostgroupDefault . ')',
'selected' => $iForemanHostgroup === OPTION_DEFAULT ? 'selected' : false,
),
OPTION_NONE => array(
'label' => t('none'),
'selected' => $iForemanHostgroup === OPTION_NONE ? 'selected' : false,
),
'' => array(
'label' => '- - - - - - - - - - - - - - - - - - - - ',
),
),
);
if (is_array($aForemanHostgroups) && count($aForemanHostgroups)) {
foreach ($aForemanHostgroups as $aItem) {
$aSelectForemanHostGroup['options'][$aItem['id']] = array(
'label' => $aItem['title'],
'selected' => ($iForemanHostgroup === $aItem['id']) ? 'selected' : false,
);
}
}
}
$aForms["setup"]["form"]['input' . $i++] = array(
'type' => 'markup',
'value' => ''
// .'<pre>'.print_r($this->_aPrjConfig["phases"][$sPhase], 1).'</pre>'
/*
. '<a class="'.$sPhase.'">'
. t("phase") . ' ' . $sPhase
. '</a>'
*/
. '<table class="table">'
. '<tbody>'
. '<tr><th class="' . $sPhase . '">' . $this->_oHtml->getIcon('phase') . t("phase") . ' ' . $sPhase . '</th></tr>'
. '<tr><td class="' . ($bActivePhase ? $sPhase : '') . '">'
. ''
);
$aForms["setup"]["form"]['input' . $i++] = array(
'type' => 'checkbox',
'name' => 'phases[' . $sPhase . '][active]',
'label' => t("phase-is-active"),
// 'value' => $bUsePuppet,
'required' => false,
'validate' => 'isastring',
// 'size' => 100,
// 'placeholder' => '...',
'options' => array(
'1' => array(
'label' => t("yes"),
'checked' => $bActivePhase,
'onclick' => '$(\'#' . $sDivId4PhaseSettings . '\').css(\'display\', (this.checked ? \'block\' : \'none\') )',
),
),
);
$aForms["setup"]["form"]['input' . $i++] = array(
'type' => 'markup',
'value' => ''
. '<div id="' . $sDivId4PhaseSettings . '" ' . ($bActivePhase ? '' : ' style="display: none;"') . '>'
);
$aForms["setup"]["form"]['input' . $i++] = array(
'type' => 'text',
'name' => 'phases[' . $sPhase . '][url]',
'label' => $this->_oHtml->getIcon('url') . t("url-project-website"),
'value' => $sUrl,
// 'required' => 'required',
'validate' => 'isastring',
'size' => 100,
'placeholder' => 'https://' . $sPhase . '.[' . t("project") . '].[...]/',
);
$aForms["setup"]["form"]['input' . $i++] = array(
'type' => 'radio',
'name' => 'phases[' . $sPhase . '][deploymethod]',
'label' => $this->_oHtml->getIcon('method') . t("deploymethod"),
// 'value' => $bUsePuppet,
// 'required' => 'required',
'validate' => 'isastring',
// 'size' => 100,
// 'placeholder' => '...',
'options' => array(
'none' => array(
'label' => t("deploymethod-none"),
'checked' => $sDeploymethod === "none",
'onclick' => '$(\'#' . $sDivId4TargetHosts . '\').css(\'display\', (this.checked ? \'none\' : \'block\') )',
),
'rolloutplugin' => array(
// 'label' => t("deploymethod-puppet").' - '. $this->oRolloutPlugin->getName(),
'label' => t("deploymethod-rolloutplugin"),
'checked' => $sDeploymethod === "rolloutplugin",
'onclick' => '$(\'#' . $sDivId4TargetHosts . '\').css(\'display\', (this.checked ? \'block\' : \'none\') )',
),
/*
* see deploy method to handle an action
'sshproxy' => array(
'label' => t("deploymethod-sshproxy"),
'checked' => $sDeploymethod==="sshproxy",
'onclick' => '$(\'#'.$sDivId4TargetHosts.'\').css(\'display\', (this.checked ? \'block\' : \'none\') )',
),
*/
),
);
$aForms["setup"]["form"]['input' . $i++] = array(
'type' => 'markup',
'value' => ''
. '<div id="' . $sDivId4TargetHosts . '" ' . ($sDeploymethod !== "none" ? '' : ' style="display: none;"') . '>'
);
// rollout plugin: phase specific overrides
$aForms["setup"]["form"]['input' . $i++] = array(
'type' => 'markup',
'value' => ''
// . '<hr>'
.'<label class="col-sm-2">'.t('deploy-rollout-plugin-config') .'</label>'
.'<div class="col-sm-10">'.$aRollout[$sPhase].'</div>'
);
$aForms["setup"]["form"]['input' . $i++] = array(
'type' => 'text',
'name' => 'phases[' . $sPhase . '][hosts]',
'label' => $this->_oHtml->getIcon('host') . t("phase-targethosts"),
'value' => $sDeployhosts,
// 'required' => 'required',
'validate' => 'isastring',
'size' => 100,
'placeholder' => 'FQDN1,FQDN2',
);
/*
if ($sPuppethost) {
// add ssh host key
$sOut0 = shell_exec(sprintf($this->_aConfig["installPackages"]["addkeycommand"], $sPuppethost, $sPuppethost));
$sCmd2 = 'ssh ' . $this->_aConfig["installPackages"]["user"]
. '@' . $sPuppethost
. ' ' . $this->_aConfig["installPackages"]["testcommand"];
$sOut = 'skip';
// $sOut = shell_exec($sCmd2);
// Check auf Versionsnummer - mehr als n Zeichen ist mutmasslich eine Fehlermeldung
if (strlen($sOut) > 7) {
$sMessages.=$this->getBox("error", sprintf(t("class-project-error-setup-sudo-pupet-agent-failed"), $sPhase, $sCmd, $sOut));
$sOut = '<span class="error" title="' . $sCmd . '">' . $sOut . '</span>';
} else {
$sOut = '<span class="ok">' . sprintf(t("class-project-info-setup-ssh-and-puppet-ok"), $sPuppethost) . '</span>';
}
$aForms["setup"]["form"]['input' . $i++] = array(
'type' => 'markup',
'value' => '<div class="form-group">'
. '<label class="col-sm-2"> </label><div class="col-sm-10">'
. $sOut
. '</div></div>',
);
}
*/
// when to deploy
$aForms["setup"]["form"]['input' . $i++] = array(
'type' => 'text',
'name' => 'phases[' . $sPhase . '][deploytimes]',
'label' => $this->_oHtml->getIcon('time') . t("deploytimes"),
'value' => $sDeploytimes,
// 'required' => 'required',
'validate' => 'isastring',
'size' => 100,
'placeholder' => isset($this->_aConfig["phases"][$sPhase]["deploytimes"]) ? implode(", ", $this->_aConfig["phases"][$sPhase]["deploytimes"]) : '',
);
$aForms["setup"]["form"]['input' . $i++] = array(
'type' => 'markup',
'value' => ''
. '</div>'
);
if ($aSelectForemanGroups) {
$aForms["setup"]["form"]['input' . $i++] = $aSelectForemanHostGroup;
}
$aForms["setup"]["form"]['input' . $i++] = array(
'type' => 'markup',
'value' => ''
. '</div>'
); // close div for active phase
$aForms["setup"]["form"]['input' . $i++] = array(
'type' => 'markup',
'value' => '</td></tr></tbody></table>',
);
} // END: loop over phases
// --------------------------------------------------
// Tab for raw data
// --------------------------------------------------
$sRolloutDebug='<hr>DEBUG:<br>';
foreach (array_keys($this->getPhases()) as $sPhase) {
if ($this->isActivePhase($sPhase)){
$sRolloutDebug.='<strong>'.$sPhase.'</strong>'
. '<pre>Config = '.print_r($this->oRolloutPlugin->getConfig($sPhase, 1), 1).'</pre>'
. '<pre>Commands = '.print_r($this->oRolloutPlugin->getDeployCommands($sPhase, 1), 1).'</pre>'
;
}
}
$aForms["setup"]["form"]['input' . $i++] = array(
'type' => 'markup',
'value' => '</div>'
. '<div class="tab-pane fade" id="tab6">'
. '<br><pre>'.print_r($this->_aPrjConfig, 1).'</pre>'
. $sRolloutDebug
. '</div>'
. '</div>'
. '</div>'
. '<div style="clear: both; margin-bottom: 1em;"></div>'
. '<hr>',
);
$aForms["setup"]["form"]['input' . $i++] = array(
'type' => 'submit',
'name' => 'btnsave',
'label' => t("save"),
'value' => $this->_oHtml->getIcon('sign-ok').t("save"),
);
$oForm = new formgen($aForms);
return $sMessages . $oForm->renderHtml("setup");
}
/**
* return html code for the installed version in the repository
* @param boolean $bRefresh optional: refresh flag; default: use cached information
* @return string
*/
public function renderRepoInfo($bRefresh=false) {
$sReturn = "";
switch ($this->_aPrjConfig["build"]["type"]) {
case "git":
$aRepodata = $this->getRepoRevision($bRefresh);
if (array_key_exists("revision", $aRepodata)) {
$sReturn.=$this->_getChecksumDiv($aRepodata["revision"],
$this->_oHtml->getIconByType('branch') . t('branch') . ': ' . (array_key_exists("branch", $aRepodata) ? $aRepodata["branch"] : '-') . '<br>'
. $this->_oHtml->getIconByType('revision') . t('revision') . ': ' . $this->_renderRevision($aRepodata["revision"]) . '<br>'
. $this->_oHtml->getIconByType('comment') . t('commitmessage') . ':<br>'
)
."<pre>" . htmlentities($aRepodata["message"]). "</pre>";
} else {
$sReturn .= $this->_oHtml->getBox("error", sprintf(t('class-project-error-no-repoinfo'), $aRepodata["error"]))
. $this->renderLink("setup") . '<br>';
}
break;
default:
$sReturn .= $this->_oHtml->getBox("error", sprintf(t('class-project-error-wrong-buildtype'), $this->_aPrjConfig["build"]["type"]));
}
if (array_key_exists("url", $this->_aPrjConfig["build"])) {
$sReturn.=t('repository-url') . ': ' . $this->_aPrjConfig["build"]["url"] . '<br>';
}
if (array_key_exists("webaccess", $this->_aPrjConfig["build"])) {
$sReturn.=t('repository-access-browser') . ':<br><a href="' . $this->_aPrjConfig["build"]["webaccess"] . '">' . $this->_aPrjConfig["build"]["webaccess"] . '</a><br>';
}
return $sReturn;
}
/**
* get html code for a link to the commit
* (works for guithub and gitlab instances)
*
* @param string $sRevision
* @return string
*/
public function _renderRevision($sRevision) {
$sUrl = str_replace('/tree/master', '', $this->_aPrjConfig["build"]["webaccess"]) . '/commit/' . $sRevision;
return '<a href="' . $sUrl . '">' . $sRevision . '</a>';
return $sUrl;
}
/**
* get html form with selectr for remote branches
* @param string $sActiveBranchname force active branch name
* @param bool $bIgnoreCache flag to ignore exiting cached data
* @return string
*/
public function renderSelectRemoteBranches($sActiveBranchname = false, $bIgnoreCache=false) {
$this->log(__FUNCTION__."(sActiveBranchname = $sActiveBranchname, bIgnoreCache = ".($bIgnoreCache ? 'true' : 'false').") start");
$aReturn = array();
$aRadios = array();
$bFoundActive = false;
$i = 0;
if (!$this->_oVcs) {
$this->_initVcs();
}
require_once("formgen.class.php");
if (!$sActiveBranchname) {
$sActiveBranchname = $this->_sBranchname;
}
if ($this->_oVcs) {
if (!method_exists($this->_oVcs, "getRemoteBranches")) {
// the version control class does not have this method
return '';
}
foreach ($this->_oVcs->getRemoteBranches($bIgnoreCache) as $aBranch) {
$sBranch = $aBranch['name'];
$aRadios[$sBranch] = array(
'value' => $sBranch,
'label' => $aBranch['label'],
);
// if no param was given the first branch will be marked
if (!$sActiveBranchname) {
$sActiveBranchname = $sBranch;
}
if ($sBranch == $sActiveBranchname) {
$bFoundActive = true;
// $aRadios[$sBranch]['checked'] = 'checked';
$aRadios[$sBranch]['selected'] = 'selected';
} else {
// for SELECT we need the onclick even on select element
// not on the option (Chrome)
// $aRadios[$sBranch]['onclick'] = 'document.getElementById(\'submitBranch\').click()';
}
};
}
// no branches were found
if (count($aRadios) == 0) {
return '';
}
$aForms = array(
'frmSelectBranch' => array(
'meta' => array(
'method' => 'POST',
'action' => '?',
'id' => 'frmSelectBranch',
),
'validate' => array(),
'form' => array(
'branchname' => array(
'inline' => true,
'type' => 'select',
'onchange' => 'document.getElementById(\'submitBranch\').click()',
'name' => 'branchname',
'label' => '<strong>' . t('branch-select') . '</strong>',
'validate' => 'isastring',
'options' => $aRadios,
),
),
),
);
// submit to switch branches - only if a selection is available
if (count($aRadios) > 1 || !$bFoundActive) {
$aForms['frmSelectBranch']['form']['submitBranch'] = array(
'type' => 'submit',
'name' => 'btnsave',
'onclick' => 'showModalMessage(\'' . t('branch-switch') . '\'); ',
'label' => t("change"),
'value' => $this->_oHtml->getIcon('sign-ok').t("change"),
);
}
$oFrm = new formgen($aForms);
return $oFrm->renderHtml('frmSelectBranch')
. '<script>$("#submitBranch").hide();</script>';
// return $oFrm->renderHtmlElement('dummy',$aFormData);
}
/**
* return html code for a list of all built packages and their usage
* @return string
*/
public function renderVersionUsage() {
$sReturn = false;
$sRowHead1 = false;
$sRowHead2 = '<td></td>';
$aAllVersions = $this->_getVersionUsage();
if (!count($aAllVersions)) {
return $this->_oHtml->getBox("info", t('class-project-info-no-package'));
}
foreach ($this->getActivePhases() as $sPhase) {
$sRowHead1.='<th class="' . $sPhase . ' tdphase" colspan="' . (count($this->_aPlaces) + 1) . '">' . $sPhase . '</th>';
$sRowHead2.='<td></td>' . $this->renderPlacesAsTd($sPhase);
}
krsort($aAllVersions);
foreach ($aAllVersions as $sVersion => $aData) {
$sReturn.='<tr>';
$sInfos = $this->renderInfoLink($aData["info"], array('hpos' => 'left'));
$sReturn.='<td>'
. $this->_getChecksumDiv(
$aData['info']['revision'],
$this->_oHtml->getIconByType('calendar') . t('build-from') . ': ' . $sVersion .'<br>'
. $this->_oHtml->getIconByType('branch') . t('branch') . ': ' . $aData['info']["branch"] . '<br>'
. $this->_oHtml->getIconByType('revision') . t('revision') . ': ' . $this->_renderRevision($aData['info']["revision"]) . '<br>'
)
. '</td><td>'
. ' ' . $sInfos . ' '
. '</td>'
;
foreach ($this->getActivePhases() as $sPhase) {
$sTLine = '';
$bCanRollback = $aData["rollback"][$sPhase];
// $sReturn.=$aData["rollback"][$sPhase] ? '<td>'.$this->renderLink("rollback", $sPhase, $sVersion).'</td>' : '<td>Rollback NOT possible</td>';
// $sReturn.=$aData["rollback"][$sPhase] ? '<td> Y </td>' : '<td> N </td>';
$sReturn.='<td> </td>';
foreach (array_keys($this->_aPlaces) as $sPlace) {
$bFound = false;
$sReturn.=$aData["usage"][$sPhase][$sPlace]
? '<td class="' . $sPhase . '" style="text-align: center;">'
. $this->_getChecksumDiv($aData['info']['revision'], 'X')
. '</td>'
: '<td> </td>'
;
}
}
$sReturn.='</tr>';
}
$sReturn = t('class-project-info-table-packages') . '<br><br>'
. '<table>'
. '<thead><tr><td>Version</td><td></td>'
. $sRowHead1
. '</tr><tr><td>'
. $sRowHead2
. '</tr></thead>'
. '<tbody>'
. $sReturn
. '</tbody>'
. '</table>';
return $sReturn;
}
/**
* render graphical overview of process (in project overview)
* @return string
*/
public function renderVisual() {
$sReturn = '';
$renderAdminLTE=new renderadminlte();
$sBarHeightBg = '1.0em';
$sBarHeight = '0.8em';
$sContinue = '<span style="font-size: 300%; color:#ace;">»»</span><br>';
$aBranches=$this->getRemoteBranches();
if(!is_array($aBranches)){
return '<br>'.$this->_oHtml->getBox("error", t("project-setup-incomplete"));
}
$sRepoBar = '';
/*
Speedup:
$aRepodata = $this->getRepoRevision();
if (array_key_exists("revision", $aRepodata)) {
$sRepoBar = $this->_getChecksumDiv($aRepodata["revision"]);
} else {
$sRepoBar = '<span class="error">' . t("error") . '</span>';
}
*/
$sPackagebar = '';
$aVersions = $this->_getVersionUsage();
foreach ($aVersions as $sVersion => $aData) {
$sBar = $aData["info"]["revision"] ? $this->_getChecksumDiv($aData["info"]["revision"], '' , $sBarHeight) : '';
$sPackagebar.='<span title="' . $sVersion . '" style="float: left; background:#eee; height: '.$sBarHeightBg.'; width:' . (100 / count($aVersions)) . '%">' . $sBar . ' </span>';
}
$sPhaseImg = '';
$sLastPhase = '';
foreach ($this->getActivePhases() as $sPhase) {
if ($sPhaseImg) {
$sAction = $sContinue;
if ($this->canAcceptPhase($sLastPhase)) {
$sAction .= $this->renderLink("accept", $sLastPhase);
}
$sPhaseImg.='<div class="action">' . $sAction . '</div>';
}
$sLastPhase = $sPhase;
$sFullbar = '';
foreach (array_keys($this->_aPlaces) as $sPlace) {
$sFullbar.='<span title="' . $this->_aPlaces[$sPlace] . '" style="float: left; background:#eee; height: '.$sBarHeightBg.'; width:' . (100 / count($this->_aPlaces)) . '%">' . $this->_renderBar($sPhase, $sPlace, $sBarHeight) . ' </span>';
}
// $sDetail = $sFullbar . '<br><a href="#h3phases" class="scroll-link">' . $sPhase . '</a>';
$sDetail = $sFullbar . '<br>' . $sPhase;
$sPhaseImg.='
<div class="process">
<div class="details">' . $sDetail . ' </div>
</div>';
}
$sReturn .= ''
. '<div class="visualprocess">'
. $renderAdminLTE->addRow(
''
. $renderAdminLTE->addCol(
$renderAdminLTE->getCard([
'type'=>'',
'variant'=>'outline',
'title'=>'',
'text'=> '<h3>'.t("versioncontrol"). '</h3>' . $sRepoBar . '<br>
' . t("repositoryinfos") . '<br>
' // . $this->_aPrjConfig["build"]["type"]
. preg_replace('/.*\@(.*):.*/', '$1', $this->_aPrjConfig["build"]["url"])
. '<br>(<strong title="' . t('branch-select') . '">' . count($aBranches) . '</strong>)',
]
), 2
)
. $renderAdminLTE->addCol(
'<div class="action">' . $sContinue . t("build-hint-overview") . '<br><br>' . ($this->canAcceptPhase() ? $this->renderLink("build") : '') . '</div>',
1
)
. $renderAdminLTE->addCol(
$renderAdminLTE->getCard([
'type'=>'',
'variant'=>'outline',
'title'=>'',
'text'=> '<h3>'.$this->_oHtml->getIcon('package') . t("archive"). '</h3>'
. '<div class="archive">'
. '<div class="details">'
. $sPackagebar . '<br>'
. '</div>'
. t("packages") . '<br>'
.'(<strong>' . count($this->_getVersionUsage()) . '</strong>)'
. '</div>'
]
), 2
)
. $renderAdminLTE->addCol(
'<div class="action">'.$sContinue . sprintf(t("queue-hint-overview"), $this->getNextPhase()).'</div>',
1
)
. $renderAdminLTE->addCol(
$renderAdminLTE->getCard([
'type'=>'',
'variant'=>'outline',
'title'=>'',
'text'=> '<h3>'.$this->_oHtml->getIcon('phase') . t("phases"). '</h3>'
. ($sPhaseImg ? $sPhaseImg : '<div class="process">' . t("none") . '</div>')
]
), 6
)
)
.'</div>'
;
return $sReturn;
}
}