setup-sdl: Use 'streams' to download sources from GitHub

From 41f924902ec57d2aff71889bc2856a361b6abdef Mon Sep 17 00:00:00 2001
From: Anonymous Maarten <[EMAIL REDACTED]>
Date: Fri, 16 Aug 2024 20:22:22 +0200
Subject: [PATCH] Use 'streams' to download sources from GitHub

---
 packed/index.js | 31 ++++++++++++++++++++++++++++---
 src/main.ts     | 17 ++++++++++++++---
 2 files changed, 42 insertions(+), 6 deletions(-)

diff --git a/packed/index.js b/packed/index.js
index 189b033..e6385ac 100644
--- a/packed/index.js
+++ b/packed/index.js
@@ -81,6 +81,8 @@ var crypto = __importStar(__nccwpck_require__(6113));
 var fs = __importStar(__nccwpck_require__(7147));
 var os = __importStar(__nccwpck_require__(2037));
 var path = __importStar(__nccwpck_require__(1017));
+var node_fs_1 = __nccwpck_require__(7561);
+var promises_1 = __nccwpck_require__(6402);
 var cache = __importStar(__nccwpck_require__(7799));
 var core = __importStar(__nccwpck_require__(2186));
 var rest_1 = __nccwpck_require__(1273);
@@ -128,7 +130,7 @@ function download_git_repo(args) {
                 case 0:
                     fs.mkdirSync(args.directory, { recursive: true });
                     return [4 /*yield*/, core.group("Downloading and extracting ".concat(args.repo_owner, "/").concat(args.repo_name, " (").concat(args.git_hash, ") into ").concat(args.directory), function () { return __awaiter(_this, void 0, void 0, function () {
-                            var response, ARCHIVE_PATH, admzip;
+                            var response, assetStream, ARCHIVE_PATH, outputFile, admzip;
                             return __generator(this, function (_a) {
                                 switch (_a.label) {
                                     case 0:
@@ -137,12 +139,19 @@ function download_git_repo(args) {
                                                 owner: args.repo_owner,
                                                 repo: args.repo_name,
                                                 ref: args.git_hash,
+                                                request: {
+                                                    parseSuccessResponseBody: false, // required to access response as stream
+                                                },
                                             })];
                                     case 1:
                                         response = _a.sent();
-                                        core.info("Writing zip archive to disk...");
+                                        assetStream = response.data;
                                         ARCHIVE_PATH = path.join(args.directory, "archive.zip");
-                                        fs.writeFileSync(ARCHIVE_PATH, Buffer.from(response.data));
+                                        outputFile = (0, node_fs_1.createWriteStream)(ARCHIVE_PATH);
+                                        core.info("Writing zip archive to disk...");
+                                        return [4 /*yield*/, (0, promises_1.pipeline)(assetStream, outputFile)];
+                                    case 2:
+                                        _a.sent();
                                         core.info("Extracting zip archive...");
                                         admzip = new AdmZip(ARCHIVE_PATH);
                                         admzip.getEntries().forEach(function (entry) {
@@ -67087,6 +67096,14 @@ module.exports = require("node:events");
 
 /***/ }),
 
+/***/ 7561:
+/***/ ((module) => {
+
+"use strict";
+module.exports = require("node:fs");
+
+/***/ }),
+
 /***/ 8849:
 /***/ ((module) => {
 
@@ -67127,6 +67144,14 @@ module.exports = require("node:stream");
 
 /***/ }),
 
+/***/ 6402:
+/***/ ((module) => {
+
+"use strict";
+module.exports = require("node:stream/promises");
+
+/***/ }),
+
 /***/ 7261:
 /***/ ((module) => {
 
diff --git a/src/main.ts b/src/main.ts
index 2d88c10..83b3a47 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -3,6 +3,8 @@ import * as crypto from "crypto";
 import * as fs from "fs";
 import * as os from "os";
 import * as path from "path";
+import { createWriteStream } from "node:fs";
+import { pipeline } from "node:stream/promises";
 
 import * as cache from "@actions/cache";
 import * as core from "@actions/core";
@@ -73,16 +75,25 @@ async function download_git_repo(args: {
     `Downloading and extracting ${args.repo_owner}/${args.repo_name} (${args.git_hash}) into ${args.directory}`,
     async () => {
       core.info("Downloading git zip archive...");
+      /* Use streams to avoid HTTP 500 HttpError/RequestError: other side closed
+       * https://github.com/octokit/rest.js/issues/12#issuecomment-1916023479
+       * https://github.com/octokit/rest.js/issues/461#issuecomment-2293930969
+       */
       const response = await args.octokit.rest.repos.downloadZipballArchive({
         owner: args.repo_owner,
         repo: args.repo_name,
         ref: args.git_hash,
+        request: {
+          parseSuccessResponseBody: false, // required to access response as stream
+        },
       });
-      core.info("Writing zip archive to disk...");
+      const assetStream = response.data as unknown as NodeJS.ReadableStream;
       const ARCHIVE_PATH = path.join(args.directory, "archive.zip");
-      fs.writeFileSync(ARCHIVE_PATH, Buffer.from(response.data as ArrayBuffer));
-      core.info("Extracting zip archive...");
+      const outputFile = createWriteStream(ARCHIVE_PATH);
+      core.info("Writing zip archive to disk...");
+      await pipeline(assetStream, outputFile);
 
+      core.info("Extracting zip archive...");
       const admzip = new AdmZip(ARCHIVE_PATH);
       admzip.getEntries().forEach((entry) => {
         if (entry.isDirectory) {