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