1<?php 2/** 3 * Jenkins Syntax Plugin: display and trigger Jenkins job inside Dokuwiki 4 * 5 * @author Algorys 6 */ 7 8if (!defined('DOKU_INC')) die(); 9require 'jenkinsapi/jenkins.php'; 10 11class syntax_plugin_jenkins extends DokuWiki_Syntax_Plugin { 12 13 public function getType() { 14 return 'substition'; 15 } 16 17 public function getPType() { 18 return 'normal'; 19 } 20 // Keep syntax inside plugin 21 function getAllowedTypes() { 22 return array('container', 'baseonly', 'substition','protected','disabled','formatting','paragraphs'); 23 } 24 25 public function getSort() { 26 return 199; 27 } 28 29 function connectTo($mode) { 30 $this->Lexer->addSpecialPattern('<jenkins[^>]*/>', $mode, 'plugin_jenkins'); 31 } 32 33 function getURLProtocol($url) { 34 if (strpos($url, 'https') !== false) { 35 $url_protocol = array( 36 'protocol' => 'https', 37 'url' => str_replace('https://', '', $url) 38 ); 39 return $url_protocol; 40 } elseif (strpos($url, 'http') !== false) { 41 $url_protocol = array( 42 'protocol' => 'http', 43 'url' => str_replace('http://', '', $url) 44 ); 45 return $url_protocol; 46 } else { 47 return array('state'=>$state, 'bytepos_end' => $pos + strlen($match)); 48 } 49 } 50 51 // Dokuwiki Handler 52 function handle($match, $state, $pos, Doku_Handler $handler) { 53 switch($state){ 54 case DOKU_LEXER_SPECIAL : 55 $data = array( 56 'state'=>$state, 57 'build'=>false, 58 ); 59 60 // Jenkins Configuration 61 $jenkins_data = $this->getURLProtocol($this->getConf('jenkins.url')); 62 $data['url'] = $jenkins_data['url']; 63 $data['protocol'] = $jenkins_data['protocol']; 64 $data['user'] = $this->getConf('jenkins.user'); 65 $data['token'] = $this->getConf('jenkins.token'); 66 67 // Jenkins Job 68 preg_match("/job *= *(['\"])(.*?)\\1/", $match, $job); 69 if (count($job) != 0) { 70 $data['job'] = $job[2]; 71 } 72 // Jenkins Build 73 preg_match("/build *= *(['\"])(\\d+)\\1/", $match, $build_nb); 74 if ((count($build_nb) != 0) && ($build_nb[2] != 0)) { 75 $data['build_nb'] = $build_nb[2]; 76 $data['build'] = true; 77 } 78 79 return $data; 80 case DOKU_LEXER_UNMATCHED : 81 return array('state'=>$state, 'text'=>$match); 82 default: 83 return array('state'=>$state, 'bytepos_end' => $pos + strlen($match)); 84 } 85 } 86 87 // Dokuwiki Renderer 88 function render($mode, Doku_Renderer $renderer, $data) { 89 if($mode != 'xhtml') return false; 90 91 $renderer->info['cache'] = false; 92 switch($data['state']) { 93 case DOKU_LEXER_SPECIAL: 94 $this->rendererJenkins($renderer, $data); 95 case DOKU_LEXER_EXIT: 96 case DOKU_LEXER_ENTER: 97 case DOKU_LEXER_UNMATCHED: 98 $renderer->doc .= $renderer->_xmlEntities($data['text']); 99 break; 100 } 101 return true; 102 } 103 104 function rendererJenkins($renderer, $data) { 105 // Get Jenkins data 106 $jenkins = new DokuwikiJenkins($data); 107 $url = $jenkins->getJobURLRequest($data['job']); 108 if (isset($data['build_nb'])) { 109 $url = $url . '/' . $data['build_nb']; 110 } 111 $build = $data['build']; 112 $request = $jenkins->request($url, $build); 113 $weather_icon = $jenkins->getWeatherImg($jenkins->getJobURLRequest($data['job'])); 114 115 if ($request == '') { 116 $this->renderErrorRequest($renderer, $data); 117 } else { 118 // Manage data 119 $img = $this->getBuildIcon($request['result']); 120 $duration = $this->getDurationFromMilliseconds($request['duration']); 121 $short_desc = $request['actions'][0]['causes'][0]['shortDescription']; 122 123 // RENDERER 124 $renderer->doc .= '<div>'; 125 // Jenkins logo 126 $renderer->doc .= '<span><img src="lib/plugins/jenkins/images/jenkins.png" class="jenkinslogo"></span> '; 127 // Build span 128 $renderer->doc .= '<span class="jenkins">'; 129 // Weather 130 $renderer->doc .= '<img src="lib/plugins/jenkins/images/'.$weather_icon.'" class="jenkins">'; 131 // Url and Job name 132 $renderer->doc .= '<a href="'.$request['url'].'" class="jenkins" target="_blank"> '.$request['fullDisplayName'].'</a> '; 133 $renderer->doc .= '<img src="lib/plugins/jenkins/images/'.$img.'" class="jenkins" title="'.$request['result'].'">'; 134 $renderer->doc .= '</span>'; 135 // Job Details 136 $renderer->doc .= '<p>'; 137 $renderer->doc .= '<span> <b>'.$this->getLang('jenkins.duration').':</b> '.$duration.'</span>'; 138 $renderer->doc .= '<span> <b>'.$this->getLang('jenkins.msg').'</b> '; 139 if ($short_desc != '') 140 $renderer->doc .= $short_desc.'</span>'; 141 else 142 $renderer->doc .= $this->getLang('jenkins.nodesc').'</span>'; 143 $renderer->doc .= '</p></div>'; 144 } 145 } 146 147 function renderErrorRequest($renderer, $data) { 148 $renderer->doc .= '<div><p>'; 149 $renderer->doc .= '<span><img src="lib/plugins/jenkins/images/jenkins.png" class="jenkinslogo"></span> '; 150 $renderer->doc .= '<span class="jenkinsfailed">'; 151 $renderer->doc .= sprintf($this->getLang('jenkins.error'), $data['job']); 152 $renderer->doc .= '</span></p>'; 153 $renderer->doc .= '</div>'; 154 } 155 156 function getBuildIcon($result) { 157 $icons = Array( 158 'SUCCESS' => 'success.svg', 159 'ABORTED' => 'aborted.svg', 160 'FAILURE' => 'failed.svg' 161 ); 162 163 return $icons[$result]; 164 } 165 166 function getDurationFromMilliseconds($ms) { 167 $x = $ms / 1000; 168 $seconds = $x % 60; 169 $x /= 60; 170 $minutes = $x % 60; 171 $x /= 60; 172 $hours = $x % 24; 173 $x /= 24; 174 $days = $x; 175 176 $duration = ''; 177 if ($days >= 1) { 178 $duration .= $days.'d '; 179 } 180 if ($hours >= 1) { 181 $duration .= $hours.'h '; 182 } 183 if ($minutes >= 1) { 184 $duration .= $minutes.'m '; 185 } 186 if ($seconds >= 1) { 187 $duration .= $seconds.'s '; 188 } 189 190 return $duration; 191 } 192 193} 194