【问题标题】:Update (Overwrite) one Apps Script file with another Apps Script file using Apps Script Code使用 Apps 脚本代码用另一个 Apps 脚本文件更新(覆盖)一个 Apps 脚本文件
【发布时间】:2016-04-01 04:29:55
【问题描述】:

覆盖文件。覆盖 Apps 脚本文件。

不是创建新的 Apps 脚本文件的问题。那对我没有帮助。我需要更新现有的 Apps 脚本文件。这个问题类似于创建一个新文件,但它不是同一个问题。更新的语法和更新的要求可能与创建新文件有很大不同,我无法从有关创建新文件的答案中获得解决方案。我查看了创建新文件的答案,但没有回答我的问题。

我已尝试使用 Advanced Drive Service 将现有的 Apps 脚本文件更新为另一个 Apps 脚本文件。

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。我通过将“目标”应用程序脚本文件下载到 JSON,然后打开 JSON 文件并复制文件 ID 来获得这些 ID。所以,我知道这些是正确的。我想要一种使用代码从项目中检索这些单个文件 ID 的方法。关于创建 new 应用程序脚本文件的帖子没有说明如何从项目文件中获取“子”ID。项目文件 ID 与项目内部的每个文件 ID 不同。 nametype 属性很明显。从示例中,只有两种类型的文件具有server_js 和“html”类型。看起来 Apps Script 项目文件的内部文件的 source 可以是字符串文字。因此,您可以输入任何您想要的替换内容。

target ID 是不言自明的。

如果有办法通过高级驱动器服务或UrlFetchApp.fetch() 来回答我的问题。我只想使用 Apps 脚本。所以,我不是在寻找用其他语言编写的解决方案,也不是在 Apps 脚本之外运行的解决方案。

使用上面的代码,我从倒数第二行得到一个错误:

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

错误是:

该应用没有更新 Apps 脚本所需的范围。

因此,很明显,它正在寻找在某处指示的范围设置。我猜它会进入选项的第四个参数。

【问题讨论】:

  • Henrique 在 this post 的 cmets 中指出,通过 Drive.Files.Update() 路由无法设置所需的 drive.scripts 范围,因此多步骤 UrlFetchApp() 过程是唯一的方法如此处的答案中提供的那样

标签: google-apps-script


【解决方案1】:

新的 Apps 脚本 API 现在允许更新 Apps 脚本项目。更新的项目可以绑定到文档。 (Sheet、Form、Doc)此代码使用 REST API,并使用 UrlFetchApp.fetch(url,options) 从 Apps 脚本代码发出 PUT 请求此代码正在从 Apps 脚本文件运行以更新另一个 Apps 脚本文件。

必须为运行代码的 Apps 脚本文件启用 Apps 脚本 API。 Apps Script API 在 Google 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) 很重要的原因。

【讨论】:

  • 是否可以只加载一个脚本文件而不破坏其余文件?
  • 是的,但是你需要从目标文件中获取所有原始文件,更新你想要更改的一个文件,然后将所有文件写回目标。没有内置选项可以仅更新项目文件中的一个内部文件。因此,需要了解 Apps 脚本文件的 JSON 结构,并更新 JSON 对象。
  • 我发现复制源和目标 jsons、解析它们、附加所需文件然后将其写回目标项目非常容易。
  • 文件也可以被删除,例如,如果您将文件从开发文件复制到生产文件,并且您的开发文件中有一些文件在生产项目中不需要。
【解决方案2】:

我创建了一个项目的 GitHub 存储库,该存储库将从源 Apps 脚本文件更新一个 Apps 脚本文件(目标)。完全免费复制和使用。

GitHub Repository - apps-script-update

有关说明,请参阅 GitHub 存储库中的自述文件

GitHub 上的代码使用较新的 Apps Script API,这与原始答案不同。

【讨论】:

  • drive 范围应涵盖drive.readonly,因此在您的列表中没有必要。
  • 检索文件 id 仍然只能通过手动下载 json 文件(如问题中所述)而不是从 fetch 响应中获得,对吧?
  • gitHub 代码是一个带有文件选择器的 Web 应用程序。该应用程序唯一需要手动完成的事情是在目标项目中创建具有相同名称的文件,就像在源项目中一样(Apps 脚本文件)。
【解决方案3】:

您需要请求特殊的 Drive-AppsScript scope:

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

由于您不能告诉 Apps 脚本为您询问此范围(它通过分析您的代码自动确定自己的范围)。您需要自己进行 oAuth 舞蹈(例如使用 Eric's lib)。但是,由于您也无法设置您自己检索的此令牌以供脚本在其内置或高级服务调用中使用(无论如何我都不知道),您也必须手动进行 UrlFetch 调用,并传递您的标头中的“自定义”标记(如“create new script”问题中所示。

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 脚本文件并插入新文件?例如。您将一个新的 HTML 文件添加到源中。
  • 不,我从来没有从应用程序脚本本身做到这一点。在 node-js 中,我总是替换所有文件。
  • 这可以简化为应用脚本现在支持编辑范围developers.google.com/apps-script/concepts/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-12
  • 1970-01-01
相关资源
最近更新 更多