LCOV - code coverage report
Current view: top level - src - release_html.c (source / functions) Hit Total Coverage
Test: deployctl-0.3.15.2.96a2d Code Coverage Lines: 410 435 94.3 %
Date: 2018-06-22 Functions: 15 16 93.8 %
Legend: Lines: hit not hit

          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(&regex, 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(&regex);
     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(&regex, 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, &regex,(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(&regex);
     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             : }

Generated by: LCOV version 1.10