Google Sheets script for Trello V2 8

Since I have posted the Google Sheets script for Trello I made some updates to include members assigned to card and customfields value (power-up), so I thought I’d share the code.

/**
 * Loads the details from a Trello board using the Trello API v1, into a google sheet.
 *
 * Each time it is run the sheet gets cleared and the following data are downloaded from the Trello board 
 *"Date", "Task", "Desc", "Who", "List", "Link", "Labels","Label Colors","Checklists", "Due Date", "Due Complete","Task (Link)", "Members", "Comments"
 *
 * NOTE: Additional columns are created for custom fields if any
 *
 * Additionally the sheet for checklist gets cleared and the following data are downloaded from the Trello board 
 *"Card","Checklist", "Check Name", "State","Task","Who","Link","Labels","Due Date","Due Complete","List","Members"
 * 
 * Additionally the sheet for comments gets cleared and the following data are downloaded from the Trello board 
 *"Card","Date", "Who Commented", "Comment","Task","Who","Link","Labels","Due Date","Due Complete","List","Members"
 *
 * @param {string} api_key The Trello API Key (Get it from https://trello.com/app-key)
 * @param {string} api_token The Trello API token (Get it from https://trello.com/app-key)
 * @param {string} board_id The Trello Board ID who's cards will be downloaded (Get it from adding ".json" at the end of the board url)
 * @param {string} sheetName The name of the sheet in the active spreadsheet to update it's rows
 * @param {string} checklistSheetName The name of the sheet in the active spreadsheet to update it's rows for checklists
 * @param {string} commentsSheetName The name of the sheet in the active spreadsheet to update it's rows for comments
 * @param {boolean} enableStackdriverLogging True to enable Stackdriver Logging. Default is false
 * @param {string} logingName logging name to be appended in the message. Default is ""
 * @return {void} Not applicable. 
 */ 
function loadTrello(api_key,api_token,board_id,sheetName,checklistSheetName, commentsSheetName, enableStackdriverLogging, logingName) {
  try {
    if (enableStackdriverLogging) console.time(logingName + " - loadTrello");
    if (enableStackdriverLogging) console.log(logingName + " - Loading from Trello STARTED");
    
    var url = "https://api.trello.com/1/";
    var key_and_token = "key="+api_key+"&token="+api_token;    
    var cr = 2;
    
    // get sheet with name Trello, clear all contents, add titles
    var ss = SpreadsheetApp.getActive().getSheetByName(sheetName).clear();
    var trelloFiledHeaders = ["Date", "Task", "Desc", "Who", "List", "Link", "Labels","Label Colors","Checklists", "Due Date", "Due Complete", "Task (Link1)", "Members", "Comments"];
    // headers without custom fields
    var originalTrelloFiledHeadersCount = 14;
    // headers with custom fields
    var trelloFiledHeadersCount = originalTrelloFiledHeadersCount;
    //Get all custom fields from Trello API
    var response = UrlFetchApp.fetch(url + "boards/" + board_id + "/customFields?" + key_and_token);
    var boardCustomFields = JSON.parse((response.getContentText()));
    // for all custom fields
    for (var i=0; i < boardCustomFields.length; i++) {
      trelloFiledHeaders.push(boardCustomFields[i].name);
      //position in append array of custom fields
      boardCustomFields[i].pos=trelloFiledHeadersCount;
      trelloFiledHeadersCount++;
    }
    ss.appendRow(trelloFiledHeaders);
    ss.getRange(1,1,1,trelloFiledHeadersCount).setFontWeight("Bold");
    
    // get sheet for checklists, clear all contents, add titles
    var ssChecklist = SpreadsheetApp.getActive().getSheetByName(checklistSheetName).clear();
    ssChecklist.appendRow(["Card","Checklist", "Check Name", "State","Task","Who","Link","Labels","Due Date","Due Complete","List","Members"]);
    ssChecklist.getRange(1,1,1,12).setFontWeight("Bold");
    
    // get sheet for comments, clear all contents, add titles
    var ssComments = SpreadsheetApp.getActive().getSheetByName(commentsSheetName).clear();
    ssComments.appendRow(["Card","Date", "Who Commented", "Comment","Task","Who","Link","Labels","Due Date","Due Complete","List","Members"]);
    ssComments.getRange(1,1,1,12).setFontWeight("Bold");
    
    //Get all lists from Trello API
    var response = UrlFetchApp.fetch(url + "boards/" + board_id + "/lists?cards=all&" + key_and_token);
    var lists = JSON.parse((response.getContentText()));
    
    // for all lists 
    for (var i=0; i < lists.length; i++) {
      var list = lists[i];
      // Get all cards from Trello API
      // /?filter=all if we want archived as well (archived have closed:true)
      var response = UrlFetchApp.fetch(url + "list/" + list.id + "/cards/?actions=all&customFieldItems=true&" + key_and_token); 
      var cards = JSON.parse(response.getContentText());
      if(!cards) continue;
      
      // for all cards
      for (var j=0; j < cards.length; j++) {
        var appentArray = new Array(trelloFiledHeadersCount);
        //initialize custom fields values
        for (var jk=originalTrelloFiledHeadersCount; jk < trelloFiledHeadersCount; jk++) {
          appentArray[jk] = "";
        }
        var card = cards[j];
        
        var name = card.name;
        var link = card.shortUrl;
        var listname = list.name;
        var desc = card.desc;
        var duedate = card.due;
        var duecomplete = (card.dueComplete == true ? 'YES' : 'NO');
        var labels = "";
        var labelsColors = "";
        for (var l=0; l < card.labels.length; l++) {
          labels = labels + (labels == "" ? "" : ", ")  + card.labels[l].name;
          labelsColors = labelsColors + (labelsColors == "" ? "" : "\n")  + card.labels[l].color;
        }
        var namelink = '=HYPERLINK("' + link +'", "' + name + '")';
        for (var k=0; k < card.actions.length; k++) {
          // Get the rest of the card data
          var dato = card.actions[k].date;
          var fullname = card.actions[k].memberCreator.fullName;
        }
        
        // ------- Custom Fields  --------------------
        var customFieldItems = card.customFieldItems;
        for (var ck=0; ck < customFieldItems.length; ck++) {
          // get board custom field from id
          var boardCustomField = searchArray(customFieldItems[ck].idCustomField, boardCustomFields);
          
          var customFieldValueText = "";
          if (boardCustomField.type=="text") {
            customFieldValueText = customFieldItems[ck].value.text;
          } else if (boardCustomField.type=="checkbox") {
            customFieldValueText = customFieldItems[ck].value.checked; 
          }else if (boardCustomField.type=="date") {
            customFieldValueText = customFieldItems[ck].value.date; 
          }else if (boardCustomField.type=="number") {
            customFieldValueText = customFieldItems[ck].value.number; 
          }else if (boardCustomField.type=="list") {
            customFieldValueText = searchArray(customFieldItems[ck].idValue, boardCustomField.options).value.text; 
          }
            appentArray[boardCustomField.pos] = customFieldValueText;
        }
        // Get custom field items END -----
               
        //-------- Members  ----------------------
        //Get all Members frin API
        var response = UrlFetchApp.fetch(url + "cards/" + card.id + "/members/?" + key_and_token);
        var membersdetails = JSON.parse(response.getContentText());
                
        var membersstr = "";
        
        // For all checklists get Name
        for (var o=0; o < membersdetails.length; o++) {
          membersstr = membersstr + (membersstr == "" ? "" : ", \n") + membersdetails[o].fullName;
        }
        
        //-------- Checklists ----------------------
        //Get all checklists of card from Trello API
        var response = UrlFetchApp.fetch(url + "cards/" + card.id + "/checklists?action=all&" + key_and_token);
        var cardchecklists = JSON.parse(response.getContentText());
        
        var checkliststr = "";
        // For all checklists get Name
        for (var m=0; m < cardchecklists.length; m++) {
          checkliststr = checkliststr + (checkliststr == "" ? "" : "\n\n") + cardchecklists[m].name + "\n --------- \n";
          // For all checklists get Items
          for (var n=0; n < cardchecklists[m].checkItems.length; n++) {
            checkliststr = checkliststr + (checkliststr == "" ? "" : "\n") + (cardchecklists[m].checkItems[n].state == 'complete' ? "[x] ":"[ ] " ) + cardchecklists[m].checkItems[n].name;
            //append row in checklist sheet            
            ssChecklist.appendRow([card.name,cardchecklists[m].name, cardchecklists[m].checkItems[n].name, cardchecklists[m].checkItems[n].state
              ,name + " - " +cardchecklists[m].checkItems[n].name,fullname,link,labels,duedate,duecomplete,listname,membersstr]);
          }
        }
        
        //-------- Comments ----------------------
        //Get all comments of card from Trello API
        var response = UrlFetchApp.fetch(url + "cards/" + card.id + "/?actions=commentCard&" + key_and_token);
        var cardcomments = JSON.parse(response.getContentText()).actions;
        
        var cardcommentsstr = "";
        // For all comments get Name
        for (var p=0; p < cardcomments.length; p++) {
          cardcommentsstr = cardcommentsstr + (cardcommentsstr == "" ? "" : "\n\n") + cardcomments[p].date + " --" + cardcomments[p].memberCreator.fullName + "\n --------- \n" + cardcomments[p].data.text;
          //append row in checklist sheet            
            ssComments.appendRow([card.name,cardcomments[p].date, cardcomments[p].memberCreator.fullName, cardcomments[p].data.text
              ,name,fullname,link,labels,duedate,duecomplete,listname,membersstr]);          
        }
              
      //Append row with data
      appentArray[0] = dato;
      appentArray[1] =  name;
      appentArray[2] =  desc;
      appentArray[3] =  fullname;
      appentArray[4] =  listname;
      appentArray[5] =  link;
      appentArray[6] =  labels;
      appentArray[7] =  labelsColors;
      appentArray[8] =  checkliststr;
      appentArray[9] =  duedate;
      appentArray[10] =  duecomplete;
      appentArray[11] =  namelink;
      appentArray[12] =  membersstr;
      appentArray[13] =  cardcommentsstr;
      ss.appendRow(appentArray);
      
      //change labels color ---
      var labelsColor = labelsColors.split('\n');
      if (labelsColor[0] == "sky") {
        ss.getRange(cr, 8).setBackground("#87CEFA");
      } else {
        ss.getRange(cr, 8).setBackground(labelsColor[0]);
        if ((labelsColor[0] == "red") || (labelsColor[0] == "black") || (labelsColor[0] == "purple") || (labelsColor[0] == "green") || (labelsColor[0] == "blue")) {
          ss.getRange(cr, 8).setFontColor("white");
        }
      }
      //change labels color END ---
      
      cr++;
     }                                      
    }
  } catch (e) {
    if (enableStackdriverLogging) console.error(logingName + " ERROR: " + e);    
  } finally {
    if (enableStackdriverLogging) console.log(logingName + " - Loading from Trello ENDED");
    if (enableStackdriverLogging) console.timeEnd(logingName + " - loadTrello");
  }
}

/**
* Finds objects in an array of objects by obj.id 
*
* @param {string} idKey The id sting to find
* @param {Array} myArray The array that contains the objects
* @return {object} The object that is found. 
*/ 
function searchArray(idKey, myArray){
    for (var i=0; i < myArray.length; i++) {
        if (myArray[i].id === idKey) {
            return myArray[i];
        }
    }
}

8 thoughts on “Google Sheets script for Trello V2

  1. Reply lehcuom Jul 17,2019 5:00 pm

    Cool ! I’ll try to run it !
    It seems a bit more complicated than the V1 ^^

    It won’t run for now because of this part in each “for” loop : &amp;lt
    It says I miss a “)” but I don’t find why.

    Can I use the loop with “for (var i=0; i<lists.length; i++)" instead ?

    (Sorry for my english and my programing skills )

  2. Reply lehcuom Jul 18,2019 5:12 pm

    It works since I deleted “&amp,amp,amp” and the variables in the function LoadTrello()
    I replaced “&amp;lt;” by “<" in the loop too

    Pour les français, il faut remplacer "HYPERLINK" par "LIEN_HYPERTEXTE" pour le lien vers la tâche.

    • Reply Constantinos Jul 22,2019 10:06 pm

      Hello,

      Thank you for your comment, am sorry for the “&amp,amp,amp” in my code. My editor was escaping the characters. I have updated the code.

      • Reply lehcuom Jul 30,2019 6:12 pm

        No worries, you helped me way more than I did ^^

        Do you have an idea to change the date format ?

        it comes like “2019-03-19T16:28:20.445Z” but Gsheet don’t understand it.
        It would understand “2019-03-19 16:28:20”

  3. Reply Alexandre Aug 7,2019 12:01 pm

    Hello Thanks a lot for this script ?. I’ve got a problem with my DONE list. It counts 16 cards vs 75 in my list on trello.
    I’dont know why. ?
    Is that a Trello API limitation ?

    Alexandre

    • Reply Constantinos Aug 7,2019 3:40 pm

      Hello. Glad you liked the script. Trello API does have limitations but I have never reached them my self (check out https://developers.trello.com/docs/limits and https://developers.trello.com/docs/rate-limits). I suspect though that something might be breaking the script (probably my fault 🙂 ). the fact that the script breaks at the same place each time, indicates that something in your data might be producing an error.

      If you used my function, set the enableStackdriverLogging to True and use the google’s Stackdriver Log Viewer to check for any errors. If you find any errors let me know, its probably something I missed while writing the script.

Leave a Reply

  

  

  

This site uses Akismet to reduce spam. Learn how your comment data is processed.