使用Apps Script代码将一个Apps Script文件更新(覆盖)为另一个Apps Script文件

4

覆盖文件。覆盖Apps Script文件。

这不是一个创建新的Apps Script文件的问题。那样对我没有帮助。我需要更新现有的Apps Script文件。这个问题类似于创建一个新文件,但并不是完全相同的问题。更新的语法和要求可能与创建新文件的不同之处足以使我无法从有关创建新文件的答案中得到解决方案。我已经查看了有关创建新文件的答案,但那并没有回答我的问题。

我尝试使用高级驱动服务(Advanced Drive Service)来将另一个Apps Script文件更新到现有的Apps Script文件中。

function updateMyScript() {
  var targetFileID = 'File ID';

  var dataSource = {
    "files": [
      {
        "id":"739a57da-f77c-4e1a-96df-7d86ef227d62",
        "name":"Code",
        "type":"server_js",
        "source":"function doGet() {\n  return HtmlService.createHtmlOutputFromFile(\u0027index\u0027);\n}\n"
      },
      {
        "id":"2c7e8b5a-dbc5-4cd2-80e9-77b6291b3167",
        "name":"index",
        "type":"html",
        "source":"\u003chtml\u003e\n  \u003cbody\u003e\n    New message!!\n  \u003c/body\u003e\n\u003c/html\u003e"
      }
    ]
  };

  var filesResource = Drive.Files.get(targetFileID);
  var blob = Utilities.newBlob(JSON.stringify(dataSource), "application/vnd.google-apps.script+json");
  var whatRezult = Drive.Files.update(filesResource, targetFileID, blob, {"convert":"true"});

  Logger.log('whatRezult: ' + whatRezult);
};
dataSource对象中的id属性是项目内每个特定的.gshtml文件的ID。我通过将“target”Apps Script文件下载为JSON,然后打开JSON文件并复制文件ID来获得这些ID。因此,我知道这些是正确的。我想要一种从代码中检索这些单独文件ID的方法。关于创建一个新的apps script文件的帖子,没有解释如何从项目文件获取“子”ID。项目文件ID与项目内每个文件的ID不同。 nametype属性很明显。而且,从示例中可以看出,只有两种类型的文件,类型分别为server_js和“html”。对于Apps Script项目文件中的内部文件,它们的source可以是字符串文字。因此,您可以键入您想要替换内容。

target ID很容易理解。

如果可以使用高级驱动程序服务或UrlFetchApp.fetch()完成此操作,那么这将回答我的问题。我只想使用Apps Script。因此,我不需要用其他语言编写的解决方案,也不需要在Apps Script之外运行的解决方案。

使用上述代码,我从倒数第二行收到错误消息:

Drive.Files.update(filesResource, targetFileID, blob, {"convert":"true"});

错误信息如下:

应用程序没有更新Apps Scripts所需的范围。

显然,它正在寻找某个地方指示范围设置。 我猜它会放在选项的第四个参数中。

Henrique在此帖子的评论中指出,通过Drive.Files.Update()路线设置所需的drive.scripts范围是不可能的,因此多步骤的UrlFetchApp()过程是提供的答案中唯一的方法。 - Bryan P
3个回答

4

您需要请求特殊的Drive-AppsScript 范围

https://www.googleapis.com/auth/drive.scripts

由于您不能告诉Apps Script为您请求此范围(它通过分析您的代码自动确定其自己的范围)。 您需要自己进行oAuth认证(例如使用Eric的库)。 但是,因为您也不能为脚本设置自己检索到的令牌以在其内置或高级服务调用中使用(我不知道有没有这样的方法),所以您还需要手动进行UrlFetch调用,并在标题中传递您的“自定义”令牌(如“创建新脚本”问题中所示)。

对于update的UrlFetch调用与insert非常相似。 只需将方法更改为PUT并在路径中添加应用程序脚本项目ID即可。

var url = "https://www.googleapis.com/upload/drive/v2/files/" + scriptID;
var requestBody = ...; //the same
var options = {
  "headers": {
     'Authorization': 'Bearer ' +  yourManuallyFetchedToken,
   }, 
  "contentType": "application/vnd.google-apps.script+json",
  "method" : "PUT", //changed here from POST to PUT
  "payload": JSON.stringify(requestBody)
}

我将把这个答案标记为正确,并授予您额外的积分。我已经让某些东西起作用,并确定requestBody需要在其中包含文件id。我提供了一个包括其他信息的答案。您提供的关于范围、URL和方法的信息对其成功至关重要。所以,这很有帮助。要使其实际工作还有很多要做,但是提供所有这些信息对于一个问题来说“太广泛”了。您是否曾成功更新现有的Apps Script文件并插入新文件?例如,您向源代码中添加了一个新的HTML文件。 - Alan Wells
不,我从未在应用脚本中完成过这个。在Node.js中,我总是替换所有文件。 - Henrique G. Abreu
1
这可以简化为应用脚本现在支持编辑范围。https://developers.google.com/apps-script/concepts/scopes#setting_explicit_scopes - Kos

3
我已经创建了一个GitHub仓库,该项目将从源Apps Script文件更新一个Apps Script文件(目标)。这个项目完全可以免费复制和使用。 GitHub 代码库-apps-script-update 请查看GitHub存储库中的自述文件以获取说明。
GitHub上的代码正在使用较新的Apps Script API,与原始答案不同。

1
drive 范围应该包括 drive.readonly,因此在您的列表中不需要它。 - Henrique G. Abreu
获取文件ID仍然只能通过手动下载JSON文件来获得,就像问题中提到的那样,而不是从fetch响应中获取,对吗? - Bryan P
GitHub代码是一个带有文件选择器的Web应用程序。该应用程序唯一需要手动完成的事情是,在目标项目中创建与源项目(Apps Script文件)中相同名称的文件。 - Alan Wells

2
新的Apps Script API现在允许更新一个Apps Script项目。被更新的项目可以与文档绑定(工作表、表格、文档)。这段代码使用了REST API,通过Apps Script代码中的UrlFetchApp.fetch(url,options)发送PUT请求。此代码从一个Apps Script文件中运行以更新另一个Apps Script文件。
必须启用Apps Script API才能运行代码的Apps Script文件。在Google Cloud控制台中启用Apps Script API。从代码编辑器中,选择“资源”和“Cloud平台项目”,搜索Apps Script API并启用它。
function updateContent(scriptId,content,theAccessTkn) {
//try{
  var options,payload,response,url;

  if (!content) {
    //Error handling function
    return;
  }

  if (!theAccessTkn) {
    theAccessTkn = ScriptApp.getOAuthToken();
  }

  //https://developers.google.com/apps-script/api/reference/rest/v1/projects/updateContent
  url = "https://script.googleapis.com/v1/projects/" + scriptId + "/content";

  options = {
    "method" : "PUT",
    "muteHttpExceptions": true,
    "headers": {
      'Authorization': 'Bearer ' +  theAccessTkn
     },
    "contentType": "application/json",//If the content type is set then you can stringify the payload
    "payload": JSON.stringify(content)
  };

  response = UrlFetchApp.fetch(url,options);
  response = JSON.parse(response);//Must be parsed even though it shows as coming back as an object

  //Logger.log('typeof response: ' + typeof response)

  //Logger.log('response 29 in file GS_Update: ' + JSON.stringify(response).slice(0,45))

  return response;
//} catch(e) {
  //Logger.log(response)
//}
};

为了避免授权错误,您必须使用正确的范围。

这些范围可以在appsscript.json文件中设置。要查看appsscript.json文件,您必须先单击“视图”菜单,然后选择“显示清单”菜单项。

{
  "timeZone": "America/New_York",
  "oauthScopes": [
    "https://www.googleapis.com/auth/script.projects",
    "https://www.googleapis.com/auth/script.external_request"
  ],
  "dependencies": {
  },
  "exceptionLogging": "STACKDRIVER"
}

第一次使用Apps Script API时,PUT请求可能无法正常工作,并会返回一个带有指向Google Cloud控制台的链接的错误信息。因此,查看从response = UrlFetchApp.fetch(url,options);语句获取的返回响应Logger.log('typeof response: ' + typeof response)非常重要。


是否可能在不破坏其余文件的情况下仅加载一个脚本文件? - Cooper
1
是的,但您需要从目标文件中获取所有原始文件,更新要更改的一个文件,然后将所有文件写回目标。项目文件中没有内置选项仅更新一个内部文件。因此,关键是了解应用脚本文件的JSON结构,并更新JSON对象。 - Alan Wells
我觉得很容易,只需要复制源JSON和目标JSON,解析它们,添加所需的文件,然后将其写回到目标项目中。 - Cooper
文件也可以被删除,例如如果你正在从开发文件复制文件到生产文件,并且在你的开发文件中有一些在生产项目中不需要的文件。 - Alan Wells

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接