Skip to content

Commit

Permalink
filesystem test
Browse files Browse the repository at this point in the history
  • Loading branch information
nahuelhds committed Jan 13, 2024
1 parent 80fdf30 commit 121ca29
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 61 deletions.
89 changes: 30 additions & 59 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,87 +1,58 @@
import { setFailed } from "@actions/core";
import fs from "fs";
import { CustomError } from "ts-custom-error";

import { extractArticle } from "./extractors/extractArticle";
import { extractFeed } from "./extractors/extractFeed";
import { FeedEntry } from "./extractors/types/feed-extractor";
import { logger } from "./logger";
import { UnknownError } from "./utils/errors";
import { buildFilename, getInputFeedUrls, getOutputDir } from "./utils/utils";
import { storeFile } from "./utils/fs";
import { buildFilename, getInputFeedUrls, getOutputDir } from "./utils/io";

export async function fetchEntries() {
try {
const outputDir = getOutputDir();
const feedUrls = getInputFeedUrls();

feedUrls.map(async (feedUrl: URL) => {
try {
const feedData = await extractFeed(feedUrl);
if (!feedData) {
logger.warn(
`Feed %s does not contain any entry. Cannot continue.`,
feedUrl,
);
return;
}

// Check if directory exists; if not, create it
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}

void Promise.all(
feedData.entries.map(async (feedEntry) => {
try {
const article = await extractArticle(feedEntry);

if (!article) {
logger.warn(
`Article "%s" is not valid or does not contain a defined url. Cannot store it.`,
feedEntry.link,
);
return;
}

const filename = buildFilename(article.url);
const destinationFile = `${outputDir}/${filename}.json`;
if (fs.existsSync(destinationFile)) {
logger.debug(
`Article "%s" already exists on path "%s"`,
article.url,
destinationFile,
);
return;
}

const fileContent = JSON.stringify(article, null, 2);
fs.writeFileSync(destinationFile, fileContent, {
encoding: "utf8",
});
logger.info(
`New article stored: "%s". Path: "%s"`,
article.url,
destinationFile,
);
} catch (err) {
if (err instanceof CustomError) {
logger.warn(err.message);
return;
}
setFailed(new UnknownError(err).message);
return;
}
}),
);
void Promise.all(feedData.entries.map(processEntry));
} catch (err) {
if (err instanceof CustomError) {
logger.warn(err.message);
return;
}

setFailed(new UnknownError(err).message);
return;
}
});
} catch (error) {
setFailed(new UnknownError(error).message);
return;
}
}

async function processEntry(feedEntry: FeedEntry) {
const outputDir = getOutputDir();
try {
const article = await extractArticle(feedEntry);
const filename = buildFilename(article.url);
const destinationFile = `${outputDir}/${filename}.json`;
const fileContents = JSON.stringify(article, null, 2);
storeFile(destinationFile, fileContents);
logger.info(
`New article stored: "%s". Path: "%s"`,
article.url,
destinationFile,
);
} catch (err) {
if (err instanceof CustomError) {
logger.warn(err.message);
return;
}

setFailed(new UnknownError(err).message);
return;
}
}
65 changes: 65 additions & 0 deletions src/utils/fs.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import fs from "fs";

import { FileExistsError, storeFile } from "./fs";

jest.mock("fs");

describe("fs", () => {
describe("storeFile", () => {
it("throws FileExistsError if file already exists", () => {
fs.existsSync = jest.fn().mockReturnValue(true);
expect(() => storeFile("some-file.json", "fileContents")).toThrow(
FileExistsError,
);
});

it("creates the file", () => {
const expectedPath = `dir/file.json`;
const expectedContent = "fileContents";
fs.existsSync = jest.fn();
fs.mkdirSync = jest.fn();
fs.writeFileSync = jest.fn();

storeFile(expectedPath, expectedContent);
expect(fs.writeFileSync).toHaveBeenCalledWith(
expectedPath,
expectedContent,
{ encoding: "utf8" },
);
});

it("creates the dir if it does not exists", () => {
const expectedDir = "dir";
const path = `${expectedDir}/file.json`;
fs.existsSync = jest
.fn()
// File exists
.mockReturnValueOnce(false)
// Dir exists
.mockReturnValueOnce(false);

fs.mkdirSync = jest.fn();

storeFile(path, "fileContents");
expect(fs.mkdirSync).toHaveBeenCalledWith(expectedDir, {
recursive: true,
});
});

it("does not created the dir if it exists already", () => {
const expectedDir = "dir";
const path = `${expectedDir}/file.json`;
fs.existsSync = jest
.fn()
// File exists
.mockReturnValueOnce(false)
// Dir exists
.mockReturnValueOnce(true);

fs.mkdirSync = jest.fn();

storeFile(path, "fileContents");
expect(fs.mkdirSync).not.toHaveBeenCalled();
});
});
});
26 changes: 26 additions & 0 deletions src/utils/fs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import fs from "fs";
import path from "path";
import { CustomError } from "ts-custom-error";

export function storeFile(destinationPath: string, fileContents: string) {
if (fs.existsSync(destinationPath)) {
throw new FileExistsError(destinationPath);
}

const dir = path.dirname(destinationPath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}

fs.writeFileSync(destinationPath, fileContents, {
encoding: "utf8",
});
}

export class FileExistsError extends CustomError {
public constructor(path: string) {
super(`The file "${path}" already exists`);
// Set name explicitly as minification can mangle class names
Object.defineProperty(this, "name", { value: "FileExistsError" });
}
}
4 changes: 2 additions & 2 deletions src/utils/utils.test.ts → src/utils/io.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { InvalidUrlError, NoUrlsGivenError, ParseUrlsError } from "./errors";
import { buildFilename, getInputFeedUrls, getOutputDir } from "./utils";
import { buildFilename, getInputFeedUrls, getOutputDir } from "./io";

const originalEnv = process.env;

describe("utils", () => {
describe("io", () => {
beforeEach(() => {
process.env = { ...originalEnv };
});
Expand Down
File renamed without changes.

0 comments on commit 121ca29

Please sign in to comment.