@azure-utils/storybooks
Version:
Utils to upload and manage Storybooks via Azure Functions and storage.
93 lines (82 loc) • 2.67 kB
text/typescript
import fs from "node:fs";
import path from "node:path";
import os from "node:os";
import type { HttpResponseInit } from "@azure/functions";
import { responseError } from "./response-utils";
import {
generateAzureStorageContainerName,
uploadDirToAzureBlobStorage,
} from "./azure-storage-blob";
import decompress from "decompress";
import { Readable } from "node:stream";
import { once } from "node:events";
import { BlobServiceClient } from "@azure/storage-blob";
import { getStore } from "./store";
import type { ReadableStream } from "node:stream/web";
export async function uploadZipWithDecompressed(
projectId: string,
buildSHA: string,
zipFile?: File
): Promise<HttpResponseInit | undefined> {
const { context, connectionString, request } = getStore();
const tmpDir = os.tmpdir();
const dirpath = fs.mkdtempSync(path.join(tmpDir, "storybook-"));
const zipFilePath = path.join(
dirpath,
`${projectId}-${buildSHA}-storybook.zip`
);
try {
if (zipFile) {
await writeStreamToFile(
Readable.fromWeb(zipFile.stream() as unknown as ReadableStream<any>),
zipFilePath
);
} else {
await writeStreamToFile(Readable.fromWeb(request.body!), zipFilePath);
}
await decompress(zipFilePath, dirpath);
const containerClient = BlobServiceClient.fromConnectionString(
connectionString
).getContainerClient(generateAzureStorageContainerName(projectId));
const blobName = `${buildSHA}/storybook.zip`;
context.debug(
`Uploading stream to blob: ${blobName} (container: ${containerClient.containerName})`
);
const uploadResponse = await containerClient
.getBlockBlobClient(blobName)
.uploadFile(zipFilePath, {
blobHTTPHeaders: {
blobContentType: "application/zip",
blobContentEncoding: "utf8",
blobCacheControl: "public, max-age=31536000",
},
});
if (uploadResponse.errorCode) {
return responseError(
"Failed to upload Storybook.",
context,
uploadResponse._response.status
);
}
await uploadDirToAzureBlobStorage(
context,
containerClient,
dirpath,
(blobName) => path.join(buildSHA, blobName)
);
return;
} finally {
fs.rmSync(dirpath, { recursive: true, force: true });
}
}
async function writeStreamToFile(readable: Readable, filePath: string) {
const writable = fs.createWriteStream(filePath);
for await (const chunk of readable) {
if (!writable.write(chunk)) {
// Wait if backpressure is applied
await once(writable, "drain");
}
}
writable.end();
await once(writable, "finish");
}