2

I'm trying to list all my google script files using the Google Drive File API as documented here. However I always get back an empty [] list. I think my token and my scopes are fine as I'm getting back this from Google OAuth2:

{ "access_token": "xxxxx", "expires_in": 3600, "refresh_token": "yyyyy",
"scope": "https://www.googleapis.com/auth/drive.scripts https://www.googleapis.com/auth/drive.appdata https://www.googleapis.com/auth/drive",
"token_type": "Bearer"
}

But then when I issue the query using mimeType filtering (I just want to get google app scripts list):

mimeType = 'application/vnd.google-apps.script'

I'm only getting back an empty items list ([]), even if I've just created a google script inside a Google Sheet:

{ "kind": "drive#fileList", "etag": "....", "selfLink": "https://www.googleapis.com/drive/v2/files?q=mimeType+%3D+'application/vnd.google-apps.script'", "incompleteSearch": false, "items": []}

I'm guessing that app-script means something else than google script code which is part of a Google Sheet... Any help appreciated :)

A. Masson
  • 2,287
  • 3
  • 30
  • 36
  • 2
    You want to retrieve the list of scripts of the container-bound project type. If my understanding is correct, unfortunately, this cannot be done yet. https://issuetracker.google.com/issues/111149037 When you want to retrieve the list of scripts of the standalone projects, you can do it using drive.files.list. If you try to retrieve the list of standalone projects, when the issue which returns "empty [] list" occurs, can you provide your latest script? – Tanaike Aug 30 '18 at 02:12
  • Your understanding is correct I'm talking about Container-bound Scripts (as opposed to standalone scripts) so I should have specifiy that. So your answer is correct (you can upgrade it as an answer and I'll approve it). You helped me then to find out this https://stackoverflow.com/questions/32714503/is-there-a-way-to-import-export-container-bound-scripts so at least It should be possible to 'export' the code... I'm gona try. – A. Masson Aug 30 '18 at 10:51
  • I'm also gona try this https://github.com/google/clasp since it's talking about "The Drive ID of a parent file that the created script project is bound to"... which is exactly the problem you mentioned. If it works I'll update this thread soon :) – A. Masson Aug 30 '18 at 11:06
  • Thank you for replying. Yes. I think that if the parent ID (Google Docs ID) can be retrieved from the project ID, the project ID should be able to be retrieved from Google Docs ID. So I reported as the future request. And also I posted an answer including the method exporting each script from the project using GAS. Could you please confirm it? – Tanaike Aug 31 '18 at 03:14

2 Answers2

3

About retrieving the file list of projects of the container-bound script type and exporting each script from the project, please check the following answer.

Retrieve file list of projects of container-bound script type

  • Unfortunately, the file list of projects of the container-bound script type cannot be retrieved yet, while the file list of projects of the standalone type can be retrieved using drive.files.list of Drive API.

Export scripts in a project

  • When you want to export each script from a project of the containter-bound script type and the standalone type, you can do it using Google Apps Script API.
    • This might become a GAS sample script for your situation. here.
    • Also you can do it using a GAS library like this.
Tanaike
  • 181,128
  • 11
  • 97
  • 165
  • I finally decided to go with https://developers.google.com/apps-script/guides/clasp as a very good alternative for my needs. I tested it and looks this tools has a lot of features for managing google scripts. For the problem of listing container bound scripts I decided to use their scriptId so I can manage them with clasp... – A. Masson Aug 31 '18 at 12:32
  • @A. Masson Thank you for your additional information. I'm glad your issue was solved. – Tanaike Aug 31 '18 at 23:17
3

A Patchwork Quilt of a Work Around to get a list of Standalone and Bound Project Ids

I posted this here because I ran across this page several times during the last couple of days and in case there is someone else who would really like to get a complete list of their projects and doesn't mind having to jump through a few hoops to get it then this might be useful to them.

I found a way to get all of the my Apps Script Project File Ids. It's not pretty but but I got all 1393 of them bound and standalone. I went into Google Developer Hub and noticed that my project id's could be found in an attribute name data-script-id="project id" and by continuing to page down to the bottom of the list I was able to get the page to keep seeking more pages until there were none left. Then I went into Chrome developers tools and I found the div that contained all the divs with the above attribute and for me this one was named <div class="uBvHbd" and I copied the entire div and tried pasting it into an ascii file on my Google Account but I found that to be a problem so I opened up my copy of UltraEdit and pasted it in there. I played around with the regex for a while and spent the day retraining myself on the UltraEdit Document Model and their version of the Javascript Engine and developed the following routines which allowed me to build a complete list of projectids.

UltraEdits Scripting Language:

function getDocumentPaths() {
  UltraEdit.outputWindow.write('File Paths:');
  for(var i=0;i<UltraEdit.document.length;i++) {
    UltraEdit.outputWindow.write('[' + i + ']: ' + UltraEdit.document[i].path);
  }
}

function getFileNames() {
  var nA=[];
  var fnToIdx={fnA:[]};
  for(var i=0;i<UltraEdit.document.length;i++) {
    var p=UltraEdit.document[i].path;
    var pA=p.split(/\\/);
    var fn=pA[pA.length-1].split('.')[0];
     fnToIdx.fnA.push(fn);
     fnToIdx[fn]=i;
  }
   UltraEdit.outputWindow.write('FileNames: \r\n' + fnToIdx.fnA.join('\r\n'));
   return fnToIdx;
}

function getScriptIdsIndex() {
  for(var i=0;i<UltraEdit.document.length;i++) {
    if(UltraEdit.document[i].isName('ScriptIds')) {
      return i;
    }
  }
}

function getFileIndexByName(name) {
  var name=name||'ScriptIds';
  if(name) {
    for(var i=0;i<UltraEdit.document.length;i++) {
      if(UltraEdit.document[i].isName(name)) {
        return i;
      }
    }
  }else{
    UltraEdit.messageBox("Invalid or Missing Inputs at getFileIndexByName().","Alert")
  }
}

function getAllFileIndices(obj) {
  UltraEdit.outputWindow.write('File Indices:');
  var fnIndicesA=[]
  for(var j=0;j<obj.fnA.length;j++) {
    fnIndicesA.push({name:obj.fnA[j] , index:obj[obj.fnA[j]]})
  }
  var_dump(fnIndicesA);
}

function updateWorkingTabs(index) {
  UltraEdit.outputWindow.write('Index: ' + index);
  UltraEdit.document[index].selectAll();
  UltraEdit.document[index].copy();
  var workingTabsA=[];
  for(var i=0;i<UltraEdit.document.length;i++) {
    if(UltraEdit.document[i].path.slice(0,-1)=='Edit') {
      UltraEdit.document[i].paste();
      workingTabsA.push(i);
    }
  }
  return workingTabsA;
}

function findAllIds() {
  var fnToIndex=getFileNames();
  UltraEdit.document[fnToIndex['ScriptIds']].selectAll();
  UltraEdit.document[fnToIndex['ScriptIds']].copy();
  var s=UltraEdit.clipboardContent;
  var re=/data-script-id="[^"]+"/g;
  var matchA=s.match(re);
  UltraEdit.document[fnToIndex['FileIds']].selectAll();
  UltraEdit.document[fnToIndex['FileIds']].cut();
  for(var i=0;i<matchA.length;i++) {
    UltraEdit.document[fnToIndex['FileIds']].write(matchA[i].slice(16,-1)  + '\r\n');
  }
}

function removeDuplicates() {
  var fnToIndex=getFileNames();
  UltraEdit.document[fnToIndex['FileIds']].selectAll();
  UltraEdit.document[fnToIndex['FileIds']].copy();
  var fnA=UltraEdit.clipboardContent.split('\r\n');
  if(!fnA[fnA.length-1]) {
    fnA.pop();
  }
  var uA=[];
  for(var i=0;i<fnA.length;i++) {
    if(uA.indexOf(fnA[i])==-1) {
      uA.push(fnA[i]);
    }
  }
  var s='';  
  for(var i=0;i<uA.length;i++) {
    if(i>0){
      s+='\r\n';
    }
    s+=uA[i];
  }
  UltraEdit.document[fnToIndex['FileIds']].selectAll();
  UltraEdit.document[fnToIndex['FileIds']].cut();
  UltraEdit.document[fnToIndex['FileIds']].write(s);
 }

UltraEdit.outputWindow.clear();
//UltraEdit.open('E:\\Projects\\ScriptIds\\ScriptIds.txt');
//var ScriptIds_idx=getScriptIdsIndex();
//var wtA=updateWorkingTabs(ScriptIds_idx);

//findAllIds()

removeDuplicates();

The input file was 24 MB and the output list was 81KB and it took the script running on my laptop less then 5 seconds to strip out the id's and remove duplicates (didn't find any either).

I ran these two routines in Google Apps Script to get script info from Google Apps Script API so that I could figure out which were Standalone and which were container bound. And for the container bound I was able to get the Container Filename and id.

function getInfo(projectId) {
  var projectId=projectId||pid;
  var rObj={'ProjectId':projectId};
  var params = {muteHttpExceptions:true,headers: {"Authorization": "Bearer " + ScriptApp.getOAuthToken()}};
  try {
    var url=Utilities.formatString('https://script.googleapis.com/v1/projects/%s',projectId);
  }
  catch(e) {
    return rObj['Error']=e;
  }
  var resp=UrlFetchApp.fetch(url,params);
  var data=JSON.parse(resp.getContentText());
  if(data.hasOwnProperty('parentId')) {
    var pFile=DriveApp.getFileById(data.parentId)
    var parentName=pFile.getName();
    var pfldrA=[];
    var pFolders=pFile.getParents();
    while(pFolders.hasNext()) {
      var folder=pFolders.next();
      pfldrA.push({id:folder.getId(),name:folder.getName()});
    }
    rObj['ProjectName']=data.title;
    rObj['ParentName']=parentName;
    rObj['ParentId']=data.parentId;
    rObj['ParentFolders']='';
    rObj['ParentFolderIds']='';
  //var html=Utilities.formatString('<br /><b>Project Name:</b>%s<br /><b>ParentName:</b> %s<br /><b>ParentId:</b> %s',data.title,parentName,data.parentId);
  //html+=Utilities.formatString('<br /><b>Parent Folders:</b>');
    for(var i=0;i<pfldrA.length;i++) {
      if(i>0) {
        rObj.ParentFolders+=', ';
        rObj.ParentFolderIds+=', ';
      }
      //html+=Utilities.formatString('<br /><b>Name:</b> %s <b>Id:</b> %s',pfldrA[i].name,pfldrA[i].id);
      rObj.ParentFolders+=pfldrA[i].name;
      rObj.ParentFolderIds+=pfldrA[i].id;
    }
  }else{
    rObj['ProjectName']=data.title;
    //var html=Utilities.formatString('<br /><b>StandAlone Project</b><br /><b>Project Name:</b>%s<br /><b>ProjectId:</b>%s',data.title,projectId);
  }
  //Logger.log(data);
  //var userInterface=HtmlService.createHtmlOutput(html);
  //SpreadsheetApp.getUi().showModelessDialog(userInterface, "Project Info");
  return rObj;
}

function updateProjects() {
  var ss=SpreadsheetApp.getActive();
  var sh=ss.getSheetByName('Projects');
  var idx={hA:[],hr:1}
  idx.hA=sh.getRange(1,1,1,sh.getLastColumn()).getValues()[0];
  idx.hA.forEach(function(e,i){idx[e]=i;});
  var lr=sh.getLastRow();
  var sr=getColumnHeight(1,sh,ss) + 1;
  var cnt=25;
  setGlobal('count',cnt);
  if(lr-sr+1<cnt) {
    cnt=lr-sr+1;
  }
  if(sr>=lr) {
    setGlobal('count',0);
    return;
  }
  //Item    ProjectId   ProjectName ParentId    ParentName  ParentFolders   ParentFolderIds
  var rg=sh.getRange(sr,1,cnt,sh.getLastColumn());
  var vA=rg.getValues();
  for(var i=0;i<vA.length;i++) {
    if(!vA[i][idx.Item] && vA[i][idx.ProjectId]) {
      var pObj=getInfo(vA[i][idx.ProjectId]);
      if(!pObj.hasOwnProperty('Error') && pObj.hasOwnProperty('ParentId')) {
        vA[i][idx.Item]=i+sr;
        vA[i][idx.ProjectName]=pObj.ProjectName;
        vA[i][idx.ParentId]=pObj.ParentId;
        vA[i][idx.ParentName]=pObj.ParentName;
        vA[i][idx.ParentFolders]=pObj.ParentFolders;
        vA[i][idx.ParentFolderIds]=pObj.ParentFolderIds;
      }else if(!pObj.hasOwnProperty('Error') && !pObj.hasOwnProperty('ParentId')){
        vA[i][idx.Item]=i+sr;
        vA[i][idx.ProjectName]=pObj.ProjectName;
        vA[i][idx.ParentName]='Standalone Project';
      }else{
        vA[i][idxItem]=i+sr;
        vA[i][idx.ProjectName]=(pObj.hasOwnProperty('Error'))?pObj.Error:"Unknown Problem";
      }
      Utilities.sleep(1000);
    }
  }
  rg.setValues(vA);
}

I'll come back later and put some comments in the code. It's not pretty but I now have a list of all my projects and where to find them and the names of their containers if they have one. I have to thank @Tanaike for the Apps Script library. It really helped me to figure out how access the Apps Script API which turned out to be a lot less difficult than I thought it would be.

A Glimpse at a portion of the final list:

enter image description here

Cooper
  • 59,616
  • 6
  • 23
  • 54