Line data Source code
1 : /*
2 : release_html.c
3 : Created by Danny Goossen, Gioxa Ltd on 3/3/17.
4 :
5 : MIT License
6 :
7 : Copyright (c) 2017 deployctl, Gioxa Ltd.
8 :
9 : Permission is hereby granted, free of charge, to any person obtaining a copy
10 : of this software and associated documentation files (the "Software"), to deal
11 : in the Software without restriction, including without limitation the rights
12 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 : copies of the Software, and to permit persons to whom the Software is
14 : furnished to do so, subject to the following conditions:
15 :
16 : The above copyright notice and this permission notice shall be included in all
17 : copies or substantial portions of the Software.
18 :
19 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 : SOFTWARE.
26 :
27 : */
28 :
29 :
30 :
31 : #include "deployd.h"
32 :
33 : /*------------------------------------------------------------------------
34 : * check if substring of list in tag,
35 : * return 1 on no match, indicating a clean tag ( not beta or test ...)
36 : *------------------------------------------------------------------------*/
37 8 : int is_clean_tag(void * opaque,const char * tag, const char ** list)
38 : {
39 8 : if (!tag && list) return 0;
40 7 : if (!list || !*list ) return 1;
41 5 : char * work_tag=strdup(tag);
42 5 : upper_string(work_tag);
43 5 : debug("is clean tag: %s, upp: %s \n",tag, work_tag);
44 :
45 : const char** item;
46 5 : int result=1;
47 9 : for (item = list; *item != NULL; item++)
48 : {
49 8 : if (strstr(work_tag,*item)!=NULL)
50 : {
51 4 : debug ("Not a clean tag\n");
52 4 : result=0;;
53 4 : break;
54 : }
55 :
56 : }
57 5 : if (work_tag) free(work_tag);
58 5 : if (result) debug("Result is clean\n");
59 5 : return result;
60 : }
61 :
62 : /*------------------------------------------------------------------------
63 : * slug a null or non Null terminated string:
64 : * replace all non (a-zA-Z0-9) with -
65 : * no - at beginning or end, no subsequent dashes
66 : *
67 : * return a null terminated string, caller is responsible for freeing it!
68 : *------------------------------------------------------------------------*/
69 10 : char * slug_it(const char * input_str, size_t len)
70 : {
71 : regex_t regex;
72 : int reti;
73 10 : size_t prev_end=0;
74 10 : char * output=NULL;
75 10 : char * instr=NULL;
76 10 : char regex_str[]= "[^a-zA-Z0-9]";
77 10 : int regex_match_cnt=1+1;
78 :
79 : regmatch_t ovector[2];
80 : //regmatch_t * ovector= calloc(sizeof(regmatch_t),regex_match_cnt);
81 10 : if (!input_str) return NULL;
82 :
83 :
84 : // prepare input and output buffer
85 8 : if (len)
86 : {
87 1 : output=calloc(1, len+1);
88 1 : instr=calloc(1, len+1);
89 1 : memcpy(instr, input_str, len);
90 : }
91 : else
92 : {
93 7 : len=strlen(input_str);
94 7 : output=calloc(1, strlen(input_str)+1);
95 7 : instr=strdup(input_str);
96 : }
97 8 : if (!output || !instr){
98 0 : if (output) free(output);
99 0 : if (instr) free(instr);
100 : return NULL;
101 : }
102 : /* Compile regular expression */
103 :
104 8 : reti = regcomp(®ex, regex_str, REG_EXTENDED);
105 8 : if (reti) { // should not happen, regex is fixed, not variable
106 0 : error("Could not compile regex\n");
107 0 : regfree(®ex);
108 0 : if (instr) free(instr);
109 0 : if (output) free(output);
110 : return NULL;
111 : }
112 :
113 : /* Execute regular expression in loop */
114 :
115 : for (;;)
116 : {
117 : size_t len_subject;
118 44 : reti = regexec(®ex, instr+prev_end, regex_match_cnt, ovector, 0);
119 44 : if (!reti)
120 : {
121 36 : if (ovector[0].rm_so !=-1 && (ovector[0].rm_eo-ovector[0].rm_so) == 1)
122 : {
123 36 : if (!prev_end )
124 7 : memcpy(output,instr,ovector[0].rm_so);
125 : else
126 29 : memcpy(output+strlen(output),instr+prev_end,ovector[0].rm_so);
127 :
128 36 : len_subject=strlen(output);
129 36 : if ( len_subject>0 && output[len_subject-1]!='-' ) output[len_subject]='-';
130 36 : prev_end=prev_end+ovector[0].rm_eo;
131 : }
132 : else break;
133 : }
134 8 : else if (reti == REG_NOMATCH)
135 : {
136 : // copy rest from lastmatch end to end of subject
137 8 : memcpy(output+strlen(output),(instr+ prev_end), len-prev_end);
138 8 : break;
139 : }
140 : else
141 0 : { char errmsg[1024];regerror(reti, ®ex,(char *) errmsg, 1024);error( "Regex match failed: %s\n", errmsg);break;}
142 36 : }
143 :
144 : //remove trailing -
145 1 : while(strlen(output) && output[strlen(output)-1]=='-') output[strlen(output)-1]='\0';
146 :
147 8 : regfree(®ex);
148 8 : if (strlen(output)==0)
149 : {
150 2 : if (output) free(output);
151 2 : if (instr) free(instr);
152 : return NULL;
153 : }
154 6 : if (instr) free(instr);
155 : // we only want lowercase
156 6 : lower_string(output);
157 : // chop anything longer then 63
158 6 : if (strlen(output)>63) output[63]=0;
159 : // we cant end with -
160 6 : if (len>61 && output[62]=='-') output[62]=0;
161 6 : return output;
162 : }
163 :
164 : /*------------------------------------------------------------------------
165 : * returns the html body or a markdown string w cmark, markdown processor
166 : * return a null terminated string, caller is responsible for freeing it!
167 : *------------------------------------------------------------------------*/
168 3 : char * html_body_release(char * buf_in)
169 : {
170 : //debug("cmark version: %d\n",cmark_version());
171 : cmark_parser *parser;
172 3 : int options = CMARK_OPT_DEFAULT;
173 : cmark_node *document;
174 3 : parser = cmark_parser_new(options);
175 3 : cmark_parser_feed(parser, buf_in, strlen(buf_in));
176 :
177 3 : document = cmark_parser_finish(parser);
178 :
179 3 : cmark_parser_free(parser);
180 :
181 3 : char * body = cmark_render_html(document, options);
182 : //debug("html_body=>>>\n%s\n<<<=\n",body);
183 3 : cmark_node_free(document);
184 3 : return body;
185 : }
186 :
187 :
188 : /*------------------------------------------------------------------------
189 : * Read a file with dirpath/filename
190 : * returns NULL on errors
191 : * return a null terminated string, caller is responsible for freeing it!
192 : *------------------------------------------------------------------------*/
193 4 : char* read_file( const char * dirpath, const char * filename)
194 : {
195 :
196 4 : if (!dirpath || !filename) return NULL;
197 : //printf("%s/%s\n",dirpath,filename);
198 : char filepath[1024];
199 4 : sprintf(filepath, "%s/%s",dirpath,filename);
200 4 : FILE *f = fopen(filepath, "r");
201 4 : if (f == NULL)
202 : {
203 0 : debug("process_link_file: %s\n",strerror(errno));
204 0 : return NULL;
205 : }
206 : struct MemoryStruct mem;
207 4 : init_dynamicbuf(&mem);
208 : char buf[1024];
209 4 : bzero(buf, 1024);
210 12 : while( fgets( buf, 1024, f ) != NULL )
211 : {
212 4 : Writedynamicbuf(buf, &mem );
213 4 : bzero(buf, 1024);
214 : }
215 4 : fclose(f);
216 : //fprintf(stderr,"readfile: >\n%s\n",mem.memory);
217 4 : return mem.memory;
218 : }
219 : /*------------------------------------------------------------------------
220 : * Read a JSON file with dirpath/filename
221 : * returns NULL on errors
222 : * returns a cJSON object, caller is responsible for freeing it!
223 : *------------------------------------------------------------------------*/
224 3 : cJSON * read_release_json(void * opaque, const char * dirpath)
225 : {
226 : // debug
227 : //printf("%s\n",dirpath);
228 3 : if (!dirpath) return NULL;
229 3 : FILE *f = fopen(dirpath, "r");
230 3 : if (f == NULL)
231 : {
232 1 : debug("read_previous release.json: %s\n",strerror(errno));
233 1 : return NULL;
234 : }
235 : struct MemoryStruct mem;
236 2 : init_dynamicbuf(&mem);
237 : char buf[1024];
238 2 : bzero(buf, 1024);
239 8 : while( fgets( buf, 1024, f ) != NULL )
240 : {
241 4 : Writedynamicbuf(buf, &mem );
242 4 : bzero(buf, 1024);
243 : }
244 2 : fclose(f);
245 2 : cJSON * result=cJSON_Parse(mem.memory);
246 2 : free(mem.memory);
247 2 : return result;
248 : }
249 :
250 :
251 : /*------------------------------------------------------------------------
252 : * get filesize of filename, returns -1 on error
253 : *------------------------------------------------------------------------*/
254 0 : off_t fsize(const char *filename) {
255 : struct stat st;
256 :
257 1 : if (stat(filename, &st) == 0)
258 : {
259 : //debug("file size stat: %d\n",st.st_size);
260 1 : return st.st_size;
261 : }
262 : return -1;
263 : }
264 :
265 :
266 : /*------------------------------------------------------------------------
267 : * cJSON * JSON_dir_list=> creates a dir list cJSON object
268 : *
269 : * creates cJSON array of href links list, with filename and filesize
270 : * excludes directories
271 : * excludes files starting with "."
272 : * excludes files with extension ".url", as these are links
273 : * links prefixed with sub_path
274 : * from directory basepath/public/sub_path
275 : *------------------------------------------------------------------------*/
276 : /* e.g.:
277 : "files": [
278 : {
279 : "name": "file2.sh",
280 : "link": "0-1-5/files/file2.sh",
281 : "size": 54321
282 : },
283 : {
284 : "name": "my_file1.txt",
285 : "link": "0-1-5/files/my_file1.txt",
286 : "size": 12345
287 : }
288 : ]
289 : */
290 16 : cJSON * JSON_dir_list( const char *basepath, const char *sub_path)
291 : {
292 16 : debug("getting directory listing: %s/public%s\n",basepath, sub_path);
293 : DIR *dp;
294 : struct dirent *ep;
295 : char dirpath[1024];
296 16 : sprintf(dirpath, "%s/public%s",basepath,sub_path);
297 :
298 16 : dp = opendir (dirpath);
299 16 : cJSON * filearray=NULL;;
300 16 : cJSON * tmp=NULL;
301 : char link[1024];
302 16 : if (dp != NULL)
303 : {
304 1 : debug("dir open\n");
305 6 : while ((ep = readdir (dp)))
306 : {
307 4 : if (ep->d_name[0]!='.' && ep->d_type!=DT_DIR && !(strstr(ep->d_name, ".url\0")))
308 : {
309 1 : tmp= cJSON_CreateObject();
310 1 : cJSON_AddItemToObject(tmp, "name", cJSON_CreateString(ep->d_name));
311 1 : sprintf(link, "%s/%s",sub_path,ep->d_name);
312 1 : cJSON_AddItemToObject(tmp, "link", cJSON_CreateString(link));
313 :
314 : char filename[1024];
315 1 : sprintf(filename, "%s/%s",dirpath,ep->d_name);
316 1 : off_t filesize=fsize(filename);
317 1 : cJSON_AddItemToObject(tmp, "size", cJSON_CreateNumber(filesize));
318 :
319 1 : if (!filearray) filearray=cJSON_CreateArray();
320 1 : cJSON_AddItemToArray(filearray, tmp);
321 : }
322 : }
323 1 : (void) closedir (dp);
324 1 : debug("directory closed\n");
325 1 : debug("is cJSON_IsArray=%d\n",cJSON_IsArray(filearray));
326 : }
327 : else
328 : {
329 15 : sock_error("Directory JSON parser");
330 15 : return NULL;
331 : }
332 1 : debug("DONE directory listing: %s\n",dirpath);
333 1 : return filearray;
334 : }
335 :
336 :
337 :
338 :
339 :
340 : /*------------------------------------------------------------------------
341 : * cJSON * JJSON_link_list=> creates a links list cJSON object
342 : *
343 : * creates the links structure of the release from *.url
344 : * with "name" : filename without ".url"
345 : * with "link" : subpath/<content before ,>
346 : * if a ',' present, a "metric" : <content after metric>
347 : * links prefixed with sub_path
348 : * from directory basepath/public/sub_path
349 : *------------------------------------------------------------------------*/
350 : /*
351 : "links":
352 : [
353 : {
354 : "name": "coverage",
355 : "link": "0-1-5/coveragexxx"
356 : "metric": "99.1%"
357 : } , {.....}
358 : ]
359 : */
360 12 : cJSON * JSON_link_list( const char *basepath, const char *sub_path)
361 : {
362 12 : debug("getting directory link listing: %s/public%s\n",basepath, sub_path);
363 : DIR *dp;
364 : struct dirent *ep;
365 : char dirpath[1024];
366 12 : sprintf(dirpath, "%s/public%s",basepath,sub_path);
367 :
368 12 : dp = opendir (dirpath);
369 12 : cJSON * linkarray=NULL;;
370 12 : cJSON * tmp=NULL;
371 : char link[1024];
372 12 : if (dp != NULL)
373 : {
374 8 : while ((ep = readdir (dp)))
375 : {
376 : //(strstr(ep->d_name, ".url\0")
377 7 : char * url_ext=strstr(ep->d_name, ".url\0");
378 7 : if (url_ext)
379 : {
380 4 : tmp= cJSON_CreateObject();
381 : // use part of .url file, without the url as name
382 :
383 : // read the file, and parse into link and metric
384 4 : char * url_content=read_file(dirpath, ep->d_name);
385 4 : if (url_content && strlen(url_content)>1)
386 : {
387 4 : if (url_content[strlen(url_content)-1]=='\n') url_content[strlen(url_content)-1]=0;
388 4 : cJSON_AddItemToObject(tmp, "name", cJSON_CreateString_n(ep->d_name,(int)(url_ext-ep->d_name)));
389 4 : char * tab_pos=strchr(url_content, (int)',');
390 4 : if (tab_pos) tab_pos[0]=0; // this cuts the url_content string to the link
391 : //fprintf(stderr,"url_content=>%s<\n",url_content);
392 4 : if (strncmp(url_content, "http://", 7)==0)
393 1 : sprintf(link,"%s",url_content);
394 3 : else if (strncmp(url_content, "https://", 8)==0)
395 1 : sprintf(link,"%s",url_content);
396 2 : else if (url_content[0]=='/')
397 1 : sprintf(link, "%s%s",sub_path,url_content);
398 : else
399 1 : sprintf(link, "%s/%s",sub_path,url_content);
400 4 : cJSON_AddItemToObject(tmp, "link", cJSON_CreateString(link));
401 4 : if (tab_pos)
402 : {
403 1 : cJSON_AddItemToObject(tmp, "metric", cJSON_CreateString(tab_pos+1));
404 : }
405 4 : free(url_content);
406 4 : if (!linkarray) linkarray=cJSON_CreateArray();
407 4 : cJSON_AddItemToArray(linkarray, tmp);
408 : }
409 : }
410 : }
411 1 : (void) closedir (dp);
412 : }
413 : else
414 : {
415 11 : sock_error("Directory JSON parser");
416 11 : return NULL;
417 : }
418 1 : debug("DONE directory link listing: %s\n",dirpath);
419 1 : return linkarray;
420 : }
421 :
422 : /*------------------------------------------------------------------------
423 : * converts a release(s).json obj to a javascript var with project info
424 : * returns NULL on errors
425 : * return a null terminated string, caller is responsible for freeing it!
426 : *------------------------------------------------------------------------*/
427 6 : char * create_release_json_js (void * opaque, char * download_url, char * releases_json, int tag, char * last_tag)
428 : {
429 6 : debug("start create_release_json_js\n");
430 6 : cJSON * env_cjson=((data_exchange_t *)opaque)->env_json;
431 :
432 : struct MemoryStruct js_out;
433 6 : init_dynamicbuf(&js_out);
434 :
435 : /*
436 : var target = "Releases"
437 : var download_url= "https://downloads.deployctl.com";
438 : var deployctl_version="0.0.20";
439 : var project_info={
440 : "name": "deployctl",
441 : "link": "https://gitlab.gioxa.com/deployctl/deployctl",
442 : "path": "/deployctl/deployctl"
443 : };
444 : */
445 :
446 6 : Writedynamicbuf("var target = \"", &js_out);
447 6 : if (strcmp(cJSON_get_key(env_cjson, "CI_ENVIRONMENT_NAME"),"production")==0)
448 : {
449 5 : if (tag)
450 2 : Writedynamicbuf( "Release", &js_out);
451 : else
452 3 : Writedynamicbuf( "Releases", &js_out);
453 : }
454 : else
455 1 : Writedynamicbuf(cJSON_get_key(env_cjson, "CI_ENVIRONMENT_NAME"), &js_out);
456 :
457 6 : Writedynamicbuf("\";\n", &js_out);
458 :
459 :
460 6 : if (download_url)
461 : {
462 1 : Writedynamicbuf("var download_url = \"", &js_out);
463 1 : Writedynamicbuf( download_url, &js_out);
464 1 : Writedynamicbuf("\";\n", &js_out);
465 : }
466 6 : if (last_tag && !tag) // can only write last_tag when releases
467 : {
468 1 : Writedynamicbuf("var last_tag = \"", &js_out);
469 1 : Writedynamicbuf( last_tag, &js_out);
470 1 : Writedynamicbuf("\";\n", &js_out);
471 : }
472 6 : Writedynamicbuf("var deployctl_version = \"", &js_out);
473 6 : Writedynamicbuf( PACKAGE_VERSION, &js_out);
474 6 : Writedynamicbuf("\";\n", &js_out);
475 : // project_info
476 6 : Writedynamicbuf("var project_info = {", &js_out);
477 : // project name
478 6 : Writedynamicbuf( "\"name\" : \"", &js_out);
479 6 : Writedynamicbuf( cJSON_get_key(env_cjson, "CI_PROJECT_NAME"), &js_out);
480 6 : Writedynamicbuf("\",\n", &js_out);
481 : // project path
482 6 : Writedynamicbuf( "\"path\" : \"", &js_out);
483 6 : Writedynamicbuf( cJSON_get_key(env_cjson, "CI_PROJECT_PATH"), &js_out);
484 6 : Writedynamicbuf("\",\n", &js_out);
485 : // project path
486 6 : Writedynamicbuf( "\"link\" : \"", &js_out);
487 6 : Writedynamicbuf( cJSON_get_key(env_cjson, "CI_PROJECT_URL"), &js_out);
488 6 : Writedynamicbuf("\"", &js_out);
489 : // close
490 6 : Writedynamicbuf("};\n", &js_out);
491 6 : if (releases_json)
492 : {
493 2 : Writedynamicbuf("var ReleaseData = ", &js_out);
494 2 : Writedynamicbuf(releases_json, &js_out);
495 2 : Writedynamicbuf(";\n", &js_out);
496 : }
497 6 : return (js_out.memory);
498 :
499 : }
500 :
501 : /*------------------------------------------------------------------------
502 : * get's the git-release from .GIT_VERSION in project_path, if present
503 : * returns NULL on errors or not present
504 : * return a null terminated string, caller is responsible for freeing it!
505 : *------------------------------------------------------------------------*/
506 10 : char * check_if_git_version_file(const char * project_path)
507 : {
508 :
509 10 : if (!project_path ) return NULL;
510 : char filepath[1024];
511 :
512 9 : sprintf(filepath, "%s/.GIT_VERSION",project_path);
513 :
514 9 : FILE *f = fopen(filepath, "r");
515 9 : if (f == NULL)
516 : {
517 2 : debug("read gitversion : %s\n",strerror(errno));
518 2 : return NULL;
519 : }
520 : struct MemoryStruct mem;
521 7 : init_dynamicbuf(&mem);
522 7 : debug("Reading: %s\n",filepath);
523 : char buf[1024];
524 7 : bzero(buf, 1024);
525 21 : while( fgets( buf, 1024, f ) != NULL )
526 : {
527 7 : Writedynamicbuf(buf, &mem );
528 7 : bzero(buf, 1024);
529 : }
530 7 : fclose(f);
531 7 : int i=0;
532 157 : while (mem.memory[i]!=0 )
533 : {
534 143 : if(mem.memory[i] ==13 || mem.memory[i] ==10) mem.memory[i]=0;
535 143 : i++;
536 : }
537 7 : if (strlen(mem.memory)>2 && strlen(mem.memory)<30)
538 : {
539 5 : debug("Read: %s\n",mem.memory);
540 5 : return mem.memory;
541 : }
542 : else
543 : {
544 2 : debug("Read bad : %s\n",mem.memory);
545 2 : free(mem.memory);
546 2 : return NULL;
547 : }
548 : }
549 :
550 : /*------------------------------------------------------------------------
551 : * get's the last tag from latest.tag from basePATH/public if present
552 : * returns NULL on errors or not present
553 : * return a null terminated string, caller is responsible for freeing it!
554 : *------------------------------------------------------------------------*/
555 7 : char * check_last_tag(void * opaque,const char * basePATH)
556 : {
557 :
558 7 : if (!basePATH ) return NULL;
559 : char filepath[1024];
560 7 : sprintf(filepath, "%s/public/latest.tag",basePATH);
561 7 : debug ("try to find last tag in %s\n",filepath);
562 7 : FILE *f = fopen(filepath, "r");
563 7 : if (f == NULL)
564 : {
565 2 : debug("read last_tag : %s\n",strerror(errno));
566 2 : return NULL;
567 : }
568 : struct MemoryStruct mem;
569 5 : init_dynamicbuf(&mem);
570 : char buf[1024];
571 5 : bzero(buf, 1024);
572 15 : while( fgets( buf, 1024, f ) != NULL )
573 : {
574 5 : Writedynamicbuf(buf, &mem );
575 5 : bzero(buf, 1024);
576 : }
577 5 : fclose(f);
578 5 : debug("Found tag: >%s<\n",mem.memory);
579 5 : int i=0;
580 137 : while (mem.memory[i]!=0 )
581 : {
582 127 : if(mem.memory[i] ==13 || mem.memory[i] ==10) mem.memory[i]=0;
583 127 : i++;
584 : }
585 5 : if (strlen(mem.memory)>2 && strlen(mem.memory)<30)
586 : {
587 : return mem.memory;
588 : }
589 : else
590 : {
591 2 : free(mem.memory);
592 2 : return NULL;
593 : }
594 : }
595 :
596 :
597 :
598 11 : int add_deploy_info_json(void * opaque,cJSON * project_json)
599 : {
600 11 : cJSON * env=((data_exchange_t *)opaque)->env_json;
601 11 : char* ci_project_url=cJSON_get_key(env, "CI_PROJECT_URL");
602 :
603 : char link[1024];
604 11 : debug("inside add deploy info\n");
605 : // "project": {"name": "test_deploy_release","link": "https://gitlab.gioxa.com/deployctl/test_deploy_release"},
606 11 : cJSON * tmp=cJSON_CreateObject();
607 11 : cJSON_AddItemToObject(tmp, "name", cJSON_CreateString(cJSON_get_key(env, "CI_PROJECT_NAME")));
608 11 : cJSON_AddItemToObject(tmp, "path", cJSON_CreateString(cJSON_get_key(env, "CI_PROJECT_PATH")));
609 11 : sprintf(link, "%s",ci_project_url);
610 11 : cJSON_AddItemToObject(tmp, "link", cJSON_CreateString(link));
611 11 : cJSON_AddItemToObject(project_json, "project", tmp);
612 11 : debug("project name\n");
613 : // "commit": {"name": "d89a8974","link": https://gitlab.gioxa.com/deployctl/test_deploy_release/commit/d89a8974b4363b3f65256330ccdd6dec6614df4e},
614 11 : tmp=cJSON_CreateObject();
615 11 : char * CI_COMMIT_SHA=cJSON_GetObjectItem(env, "CI_COMMIT_SHA")->valuestring;
616 : char commit_name[9];
617 11 : sprintf(commit_name, "%.*s",8,CI_COMMIT_SHA);
618 11 : cJSON_AddItemToObject(tmp, "name",cJSON_CreateString(commit_name) );
619 11 : sprintf(link, "%s/commit/%s",ci_project_url,CI_COMMIT_SHA);
620 11 : cJSON_AddItemToObject(tmp, "link", cJSON_CreateString(link));
621 11 : cJSON_AddItemToObject(project_json, "commit", tmp);
622 11 : debug("commit\n");
623 : //"deployed": {"name": "danny.goossen@gioxa.com" }, // no link yet, no info yet, "link": "https://gitlab.gioxa.com/dgoo2308"},
624 :
625 11 : tmp=cJSON_CreateObject();
626 11 : if (cJSON_GetObjectItem(env, "GITLAB_USER_NAME"))
627 : {
628 0 : cJSON_AddItemToObject(tmp, "name", cJSON_CreateString(cJSON_GetObjectItem(env, "GITLAB_USER_NAME")->valuestring));
629 0 : cJSON_AddItemToObject(tmp, "login", cJSON_CreateString(cJSON_GetObjectItem(env, "GITLAB_USER_LOGIN")->valuestring));
630 : }
631 : else
632 11 : cJSON_AddItemToObject(tmp, "name", cJSON_CreateString(cJSON_GetObjectItem(env, "GITLAB_USER_EMAIL")->valuestring));
633 :
634 11 : cJSON_AddItemToObject(tmp, "user_id", cJSON_CreateString(cJSON_GetObjectItem(env, "GITLAB_USER_ID")->valuestring));
635 :
636 : time_t timer;
637 : char date_buffer[26];
638 : struct tm* tm_info;
639 :
640 11 : time(&timer);
641 11 : tm_info = localtime(&timer);
642 11 : strftime(date_buffer, 26, "%Y-%m-%dT%H:%M:%S%z", tm_info);
643 11 : cJSON_AddItemToObject(tmp, "date", cJSON_CreateString(date_buffer));
644 :
645 11 : cJSON_AddItemToObject(tmp, "pipeline_id", cJSON_CreateString(cJSON_GetObjectItem(env, "CI_PIPELINE_ID")->valuestring));
646 11 : cJSON_AddItemToObject(tmp, "job_id", cJSON_CreateString(cJSON_GetObjectItem(env, "CI_JOB_ID")->valuestring));
647 :
648 11 : cJSON_AddItemToObject(project_json, "deployed", tmp);
649 11 : debug("LEAVING add deploy info\n");
650 11 : return 0;
651 : ///
652 : }
653 :
654 :
655 : /*------------------------------------------------------------------------
656 : * create_thisrelease_json:
657 : * creates a cJSON object of this release
658 : * from release_info (gitlab api) and CI-variables with base_path and sub_path
659 : *------------------------------------------------------------------------*/
660 11 : cJSON * create_thisrelease_json( void * opaque , cJSON * release_info, int production, const char * base_path,const char * sub_path)
661 : {
662 11 : cJSON * env=((data_exchange_t *)opaque)->env_json;
663 :
664 11 : cJSON * this_release=NULL;
665 11 : this_release=cJSON_CreateObject();
666 : // start the release info.
667 11 : debug("start making this release JSON\n");
668 : char link[1024];
669 11 : char* ci_build_tag=NULL;
670 : cJSON * tmp;
671 11 : char* ci_project_url=cJSON_get_key(env, "CI_PROJECT_URL");
672 11 : if (cJSON_GetObjectItem(env, "CI_COMMIT_TAG"))
673 : {
674 6 : ci_build_tag=cJSON_get_key(env, "CI_COMMIT_REF_NAME");
675 :
676 : // "tag": { "name": "{CI_COMMIT_SHA}","link": "https://gitlab.gioxa.com/deployctl/test_deploy_release/tags/{CI_COMMIT_SHA}" ==> only when CI_COMMIT_SHA},
677 6 : tmp=cJSON_CreateObject();
678 6 : cJSON_AddItemToObject(tmp, "name", cJSON_CreateString(ci_build_tag));
679 6 : sprintf(link, "%s/tags/%s",ci_project_url,ci_build_tag);
680 6 : cJSON_AddItemToObject(tmp, "link", cJSON_CreateString(link));
681 6 : cJSON_AddItemToObject(this_release, "tag", tmp);
682 6 : tmp=cJSON_CreateObject();
683 6 : if ( cJSON_GetObjectItem(release_info,"message" ))
684 : {
685 : // "tag_info": { "message": "test site and api","notes_html": "<p>test site and api ... etc</p>"},
686 1 : cJSON_AddItemToObject(tmp, "message", cJSON_CreateString(cJSON_get_key(release_info,"message" )));
687 : }
688 : else
689 : {
690 5 : cJSON_AddItemToObject(tmp, "message", cJSON_CreateString("---"));
691 : }
692 6 : cJSON * tmp_json=cJSON_GetObjectItem(release_info, "release");
693 6 : if (tmp_json)
694 : {
695 3 : if (cJSON_GetObjectItem(tmp_json, "description"))
696 : {
697 : //debug("parsing release->description==>\n%s\n<==\n",cJSON_GetObjectItem(tmp_json, "description")->valuestring);
698 2 : char * tmp_str= html_body_release(cJSON_GetObjectItem(tmp_json, "description")->valuestring);
699 2 : if (tmp_str)
700 : {
701 2 : cJSON_AddItemToObject(tmp, "notes_html", cJSON_CreateString(tmp_str));
702 2 : free(tmp_str);
703 : }
704 0 : else cJSON_AddItemToObject(tmp, "notes_html", cJSON_CreateString("<p>could not Parse Release</p>"));
705 1 : } else debug("could not find description in release_info\n");
706 3 : }else debug("could not find release in release_info\n");
707 6 : cJSON_AddItemToObject(this_release, "tag_info", tmp);
708 6 : debug("end tag check\n");
709 : }
710 : else
711 : {
712 5 : tmp=cJSON_CreateObject();
713 5 : char * project_path=cJSON_get_key(env, "CI_PROJECT_DIR");
714 : char * git_version;
715 : // "environment": { "name": "{CI_ENVIRONMENT_NAME}",
716 : // so
717 : // priority 1 : CI_GIT_VERSION
718 : // priority 2 : file .GIT_VERSION
719 : // if none above CI_COMMIT_TAG
720 : // link always to /tree/$CI_COMMIT_REF_NAME
721 : // if
722 :
723 :
724 : char commit_sha[10];
725 5 : sprintf(commit_sha,"%.*s",8,cJSON_get_key (env, "CI_COMMIT_SHA"));
726 5 : debug("start tag name: with commit sha >%s<\n",commit_sha );
727 5 : if (cJSON_GetObjectItem(env, "CI_GIT_VERSION"))
728 : {
729 2 : if (strcmp(commit_sha, cJSON_get_key (env, "CI_GIT_VERSION"))==0)
730 : {
731 : // in case we had no tag commit's yet, we get hash, so add the # in front
732 : char commit_sha_hash[10];
733 1 : sprintf(commit_sha_hash,"#%s",commit_sha);
734 1 : cJSON_AddItemToObject(tmp, "name", cJSON_CreateString(commit_sha_hash));
735 : }
736 : else
737 1 : cJSON_AddItemToObject(tmp, "name", cJSON_CreateString(cJSON_get_key (env, "CI_GIT_VERSION")));
738 : }
739 3 : else if ((git_version=check_if_git_version_file(project_path)))
740 : {
741 2 : debug("Got file_git_version >%s<\n",git_version);
742 2 : if (strcmp(commit_sha, git_version)==0)
743 : { // in case we had no tag commit's yet, we get hash, so add the # in front
744 1 : debug("Same as commit, add # in front \n");
745 : char commit_sha_hash[10];
746 1 : sprintf(commit_sha_hash,"#%s",commit_sha);
747 1 : cJSON_AddItemToObject(tmp, "name", cJSON_CreateString(commit_sha_hash));
748 : }
749 : else
750 : {
751 1 : debug(" not same so write git_version from file\n");
752 1 : cJSON_AddItemToObject(tmp, "name", cJSON_CreateString(git_version));
753 :
754 : }
755 2 : if (git_version) free(git_version);
756 : }
757 : else
758 : {
759 : char commit_sha_hash[10];
760 1 : sprintf(commit_sha_hash,"#%s",commit_sha);
761 1 : cJSON_AddItemToObject(tmp, "name", cJSON_CreateString(commit_sha_hash));
762 : }
763 5 : sprintf(link, "%s/tree/%s",ci_project_url,cJSON_get_key (env, "CI_COMMIT_REF_NAME"));
764 5 : cJSON_AddItemToObject(tmp, "link", cJSON_CreateString(link));
765 5 : cJSON_AddItemToObject(this_release, "tag", tmp);
766 : }
767 :
768 11 : add_deploy_info_json(opaque,this_release);
769 :
770 : // get htref dirlist
771 11 : cJSON * tmp_links =JSON_link_list( base_path ,sub_path);
772 :
773 11 : cJSON * env_hrefs=cJSON_GetObjectItem(env,"DEPLOY_hrefs");
774 : cJSON * hr_item;
775 11 : cJSON * tmp_link=NULL;
776 : // get links for gitlab-ci.yml
777 11 : if (env_hrefs)
778 0 : cJSON_ArrayForEach(hr_item,env_hrefs)
779 : {
780 : // links need to have content.
781 0 : if (strlen(hr_item->child->string)!=0 && strlen(hr_item->child->valuestring)!=0)
782 : {
783 0 : tmp_link=cJSON_CreateObject();
784 0 : debug("adding yaml link: %s,%s\n",hr_item->child->string,hr_item->child->valuestring);
785 0 : cJSON_AddItemToObject(tmp_link,"name",cJSON_CreateString(hr_item->child->string));
786 0 : cJSON_AddItemToObject(tmp_link,"link",cJSON_CreateString(hr_item->child->valuestring));
787 0 : if (!tmp_links) tmp_links=cJSON_CreateArray();
788 0 : cJSON_AddItemToArray(tmp_links, tmp_link);
789 : }
790 : }
791 :
792 11 : if (tmp_links ) cJSON_AddItemToObject(this_release, "links", tmp_links);
793 :
794 11 : cJSON * tmp_files =JSON_dir_list( base_path ,sub_path);
795 11 : if (tmp_files) cJSON_AddItemToObject(this_release, "files", tmp_files);
796 11 : debug("Done building this_release\n");
797 11 : return this_release;
798 : }
799 :
800 : /*------------------------------------------------------------------------
801 : * create_releases_json:
802 : * Merges previous cJSON ** releases with cJSON * this_release
803 : * if release-tag already present, it's replaced by this_release
804 : *
805 : * returns in **releases the cJSON releases, or NULL
806 : * returns NULL on errors or not present
807 : * return a null terminated string, caller is responsible for freeing it!
808 : *------------------------------------------------------------------------*/
809 3 : char * create_releases_json( void * opaque , const cJSON * this_release, cJSON ** releases, int production)
810 : {
811 3 : debug("Start create_releases_json\n");
812 3 : cJSON * env=((data_exchange_t *)opaque)->env_json;
813 3 : char* ci_build_tag=cJSON_get_key(env, "CI_COMMIT_REF_NAME");
814 :
815 3 : if (!ci_build_tag && *releases) // what is this?
816 : {
817 1 : debug("delete releases\n");
818 1 : cJSON_Delete(*releases);
819 1 : *releases=NULL;
820 : }
821 :
822 : // finish it
823 3 : cJSON * releases_array=NULL;
824 3 : if (!*releases)
825 : {
826 2 : *releases= cJSON_CreateObject();
827 : }
828 3 : releases_array=cJSON_GetObjectItem(*releases, "releases");
829 3 : if (!releases_array)
830 : {
831 2 : debug("no releases\n");
832 2 : releases_array=cJSON_CreateArray();
833 2 : cJSON_AddItemToObject(*releases, "releases",releases_array );
834 : }
835 3 : if (*releases)
836 : {
837 3 : debug("checking if this release was already deployd?\n");
838 3 : cJSON * pos=NULL;
839 3 : int item=0;
840 3 : int exists=0;
841 3 : int found_dup=-1;
842 4 : cJSON_ArrayForEach(pos, releases_array)
843 : {
844 1 : cJSON * tag=NULL;
845 1 : tag=cJSON_GetObjectItem(pos, "tag");
846 1 : if (tag) exists=(validate_key(tag, "name", ci_build_tag)==0);
847 1 : if (exists) found_dup=item;
848 1 : exists=0;
849 1 : item ++;
850 : }
851 3 : if (found_dup>-1)
852 : {
853 1 : debug("found_dup release tag, deleting: %d\n",found_dup);
854 1 : cJSON_DeleteItemFromArray(releases_array, found_dup);
855 : }
856 : }
857 3 : debug("Inserting this release in the releases array\n");
858 3 : cJSON_AddItemToBeginArray(releases_array, cJSON_Duplicate(this_release,1));
859 3 : char * result=cJSON_PrintBuffered(*releases, 1, 1);
860 3 : return result;
861 : }
862 :
863 : /*------------------------------------------------------------------------
864 : * validate_project_path_slug(void * opaque, char * output_buf)
865 : * compaires the CI-environment with CI_PROJECT_PATH_SLUG
866 : * returns 0 on valid
867 : *------------------------------------------------------------------------*/
868 5 : int validate_project_path_slug(cJSON * env_json, struct trace_Struct *trace, int suggest)
869 : {
870 5 : int result=0;
871 5 : char * project_path_slug=NULL;
872 :
873 5 : project_path_slug=slug_it(cJSON_get_key(env_json, "CI_PROJECT_PATH"), 0);
874 :
875 5 : result=validate_key(env_json, "CI_PROJECT_PATH_SLUG", project_path_slug);
876 5 : if (result!=0)
877 : { // recommend to set PROJECT_PATH_SLUG
878 4 : if (project_path_slug)
879 : {
880 2 : if (suggest) Write_dyn_trace(trace, red,"\nERROR: set \"CI_PROJECT_PATH_SLUG\" to \"%s\"\n",project_path_slug);
881 2 : debug("ERROR: set \"CI_PROJECT_PATH_SLUG\" to \"%s\"\n",project_path_slug);
882 : }
883 : else
884 : {
885 2 : Write_dyn_trace(trace, red,"\nERROR: \"CI_PROJECT_PATH\" invalid or missing \" %s \n", cJSON_get_key(env_json, "CI_PROJECT_PATH"));
886 2 : debug("ERROR: \"CI_PROJECT_PATH\" invalid or missing \" %s \n", cJSON_get_key(env_json, "CI_PROJECT_PATH"));
887 : }
888 : }
889 : else
890 1 : debug("OK: \"CI_PROJECT_PATH_SLUG\" == \"%s\"\n",project_path_slug);
891 :
892 5 : if (project_path_slug) free(project_path_slug);
893 5 : return result;
894 : }
895 :
896 : // TODO move to utils.c
897 :
898 : /*------------------------------------------------------------------------
899 : * extract the version Number
900 : *
901 : * returns 0 on valid
902 : *------------------------------------------------------------------------*/
903 1 : int ci_extract_server_version(const char* CI_SERVER_VERSION,int *major_v,int*minor_v,int *revision_v)
904 : {
905 : //setdebug();
906 1 : const char s[2] = ".";
907 : char *token;
908 1 : int count=0;
909 1 : char * str=strdup(CI_SERVER_VERSION);
910 1 : char * org_str_save=str; //save original str for free
911 1 : debug( "\nversion str %s\n", str );
912 1 : char * saveptr=NULL;
913 :
914 : /* get the first token */
915 1 : token = strtok_r(str, s,&saveptr);
916 :
917 : /* walk through other tokens */
918 5 : while( token != NULL && count<3 )
919 : {
920 :
921 3 : debug( "version token %d: %s\n",count ,token );
922 3 : char * errCheck=NULL;
923 3 : int i = (int)strtol(token, &errCheck,(10));
924 :
925 3 : if(errCheck != token)
926 3 : debug( "value round %d: %d\n",count,i);
927 : else
928 0 : debug("value round %d: --\n",count);
929 :
930 3 : if (count==0 && major_v)
931 : {
932 1 : if(errCheck != token)
933 1 : *major_v=i;
934 : else
935 0 : *major_v=-1;
936 : }
937 2 : else if (count==1&& minor_v)
938 : {
939 1 : if(errCheck != token)
940 1 : *minor_v=i;
941 : else
942 0 : *minor_v=-1;
943 : }
944 1 : else if (count==2&& revision_v)
945 : {
946 1 : if(errCheck != token)
947 1 : *revision_v=i;
948 : else
949 0 : *revision_v=-1;
950 : }
951 3 : count++;
952 3 : token = strtok_r(NULL, s,&saveptr);
953 : }
954 1 : if (org_str_save)free(org_str_save);
955 1 : debug("finish get version\n");
956 1 : return 0;
957 : }
|