Skip to content

Commit

Permalink
refactor: optimize the example
Browse files Browse the repository at this point in the history
  • Loading branch information
pplmx committed Aug 29, 2024
1 parent 70d7e8d commit 6c0e80c
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 64 deletions.
38 changes: 18 additions & 20 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,57 +38,55 @@ const fs = __importStar(__nccwpck_require__(3977));
const core = __importStar(__nccwpck_require__(2186));
const axios_1 = __importDefault(__nccwpck_require__(8757));
const toml = __importStar(__nccwpck_require__(4920));
// Function to check API reachability
async function checkAPIReachability(apiUrl) {
try {
const response = await axios_1.default.get(apiUrl, { timeout: 10000 });
if (response.status < 200 || response.status >= 300) {
core.warning(`API is not reachable, status code: ${response.status}`);
}
else {
core.info(`API ${apiUrl} is reachable.`);
}
}
catch (error) {
core.warning(`Failed to make API request: ${error instanceof Error ? error.message : String(error)}`);
}
}
// Function to read and append text to a file
async function readAndAppendToFile(inputFile, outputFile, appendText) {
try {
const content = await fs.readFile(inputFile, "utf-8");
const modifiedContent = `${content}\n${appendText}`;
await fs.writeFile(outputFile, modifiedContent, { encoding: "utf-8" });
core.info(`Appended text to file: ${outputFile}`);
}
catch (error) {
throw new Error(`File operation failed: ${error instanceof Error ? error.message : String(error)}`);
}
}
function processText(text, findWord, replaceWord) {
const processedText = text.replace(new RegExp(findWord, "g"), replaceWord);
const wordCount = processedText.trim() === "" ? 0 : processedText.trim().split(/\s+/).length;
return { processedText, wordCount };
}
function calculateNumberStats(numbers) {
const sum = numbers.reduce((acc, num) => acc + num, 0);
const average = numbers.length > 0 ? sum / numbers.length : 0;
return { sum, average };
}
async function run() {
try {
const configPath = core.getInput("config_path") || ".github/configs/setup-custom-action-by-ts.toml";
const configContent = await fs.readFile(configPath, "utf-8");
const config = toml.parse(configContent);
const { input_text = "", find_word = "", replace_word = "", number_list = [], input_file = "", output_file = "", append_text = "", api_url = "", } = config;
if (api_url) {
try {
await checkAPIReachability(api_url);
core.info(`API ${api_url} is reachable.`);
}
catch (error) {
core.warning(error instanceof Error ? error.message : String(error));
}
await checkAPIReachability(api_url);
}
if (input_file && output_file && append_text) {
try {
await readAndAppendToFile(input_file, output_file, append_text);
core.info(`Appended text to file: ${output_file}`);
}
catch (error) {
core.warning(error instanceof Error ? error.message : String(error));
}
await readAndAppendToFile(input_file, output_file, append_text);
}
const processedText = input_text.replace(new RegExp(find_word, "g"), replace_word);
const wordCount = processedText.trim() === "" ? 0 : processedText.trim().split(/\s+/).length;
const sum = number_list.reduce((acc, num) => acc + num, 0);
const average = number_list.length > 0 ? sum / number_list.length : 0;
const { processedText, wordCount } = processText(input_text, find_word, replace_word);
const { sum, average } = calculateNumberStats(number_list);
core.setOutput("processed_text", processedText);
core.setOutput("word_count", wordCount);
core.setOutput("sum", sum);
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "setup-custom-action-by-ts",
"version": "0.1.1",
"version": "0.2.1",
"description": "A custom GitHub Action using typescript",
"author": "Mystic",
"repository": {
Expand Down
46 changes: 26 additions & 20 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,52 @@ interface Config {
api_url?: string;
}

// Function to check API reachability
async function checkAPIReachability(apiUrl: string): Promise<void> {
try {
const response = await axios.get(apiUrl, { timeout: 10000 });
if (response.status < 200 || response.status >= 300) {
core.warning(`API is not reachable, status code: ${response.status}`);
} else {
core.info(`API ${apiUrl} is reachable.`);
}
} catch (error) {
core.warning(`Failed to make API request: ${error instanceof Error ? error.message : String(error)}`);
}
}

// Function to read and append text to a file
async function readAndAppendToFile(inputFile: string, outputFile: string, appendText: string): Promise<void> {
try {
const content = await fs.readFile(inputFile, "utf-8");
const modifiedContent = `${content}\n${appendText}`;
await fs.writeFile(outputFile, modifiedContent, { encoding: "utf-8" });
core.info(`Appended text to file: ${outputFile}`);
} catch (error) {
throw new Error(`File operation failed: ${error instanceof Error ? error.message : String(error)}`);
}
}

function processText(
text: string,
findWord: string,
replaceWord: string,
): {
processedText: string;
wordCount: number;
} {
const processedText = text.replace(new RegExp(findWord, "g"), replaceWord);
const wordCount = processedText.trim() === "" ? 0 : processedText.trim().split(/\s+/).length;
return { processedText, wordCount };
}

function calculateNumberStats(numbers: number[]): { sum: number; average: number } {
const sum = numbers.reduce((acc, num) => acc + num, 0);
const average = numbers.length > 0 ? sum / numbers.length : 0;
return { sum, average };
}

export async function run(): Promise<void> {
try {
const configPath = core.getInput("config_path") || ".github/configs/setup-custom-action-by-ts.toml";

const configContent = await fs.readFile(configPath, "utf-8");
const config: Config = toml.parse(configContent);

Expand All @@ -56,28 +75,15 @@ export async function run(): Promise<void> {
} = config;

if (api_url) {
try {
await checkAPIReachability(api_url);
core.info(`API ${api_url} is reachable.`);
} catch (error) {
core.warning(error instanceof Error ? error.message : String(error));
}
await checkAPIReachability(api_url);
}

if (input_file && output_file && append_text) {
try {
await readAndAppendToFile(input_file, output_file, append_text);
core.info(`Appended text to file: ${output_file}`);
} catch (error) {
core.warning(error instanceof Error ? error.message : String(error));
}
await readAndAppendToFile(input_file, output_file, append_text);
}

const processedText = input_text.replace(new RegExp(find_word, "g"), replace_word);
const wordCount = processedText.trim() === "" ? 0 : processedText.trim().split(/\s+/).length;

const sum = number_list.reduce((acc: number, num: number) => acc + num, 0);
const average = number_list.length > 0 ? sum / number_list.length : 0;
const { processedText, wordCount } = processText(input_text, find_word, replace_word);
const { sum, average } = calculateNumberStats(number_list);

core.setOutput("processed_text", processedText);
core.setOutput("word_count", wordCount);
Expand Down
58 changes: 37 additions & 21 deletions tests/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ describe("GitHub Action", () => {
const mockSetOutput = jest.spyOn(core, "setOutput");
const mockSetFailed = jest.spyOn(core, "setFailed");
const mockWarning = jest.spyOn(core, "warning");
const mockInfo = jest.spyOn(core, "info");
const mockReadFile = fs.readFile as jest.MockedFunction<typeof fs.readFile>;
const mockWriteFile = fs.writeFile as jest.MockedFunction<typeof fs.writeFile>;
const mockAxiosGet = axios.get as jest.MockedFunction<typeof axios.get>;
Expand Down Expand Up @@ -63,6 +64,7 @@ describe("GitHub Action", () => {
await run();

expect(mockAxiosGet).toHaveBeenCalledWith("https://api.example.com/data", { timeout: 10000 });
expect(mockInfo).toHaveBeenCalledWith("API https://api.example.com/data is reachable.");
});

it("should check API reachability correctly and warn on bad status", async () => {
Expand All @@ -74,47 +76,61 @@ describe("GitHub Action", () => {
});

it("should read from the input file and append text to the output file correctly", async () => {
// Mock for the first call (config file)
mockReadFile.mockImplementationOnce(() => Promise.resolve(mockConfig));

// Mock for the second call (input file)
mockReadFile.mockImplementationOnce(() => Promise.resolve("Original file content."));
mockReadFile.mockImplementation((path) => {
if (path === ".github/configs/setup-custom-action-by-ts.toml") {
return Promise.resolve(mockConfig);
}
if (path === "input.txt") {
return Promise.resolve("Original file content.");
}
return Promise.reject(new Error("Unexpected file read"));
});

const mockAppendText = "Goodbye!";
await run();

expect(mockReadFile).toHaveBeenCalledWith(".github/configs/setup-custom-action-by-ts.toml", "utf-8");
expect(mockReadFile).toHaveBeenCalledWith("input.txt", "utf-8");
expect(mockWriteFile).toHaveBeenCalledWith("output.txt", "Original file content.\nGoodbye!", {
encoding: "utf-8",
});
expect(mockInfo).toHaveBeenCalledWith("Appended text to file: output.txt");
});

it("should handle file read errors gracefully", async () => {
// First call to mock the config file
mockReadFile.mockImplementationOnce(() => Promise.resolve(mockConfig));

// Second call to mock the input file read error
mockReadFile.mockImplementationOnce(() => Promise.reject(new Error("Failed to read input file")));
mockReadFile.mockImplementation((path) => {
if (path === ".github/configs/setup-custom-action-by-ts.toml") {
return Promise.resolve(mockConfig);
}
if (path === "input.txt") {
return Promise.reject(new Error("Failed to read input file"));
}
return Promise.reject(new Error("Unexpected file read"));
});

await run();

expect(mockWarning).toHaveBeenCalledWith("File operation failed: Failed to read input file");
expect(mockSetFailed).toHaveBeenCalledWith(
"Action failed with error: File operation failed: Failed to read input file",
);
});

it("should handle file write errors gracefully", async () => {
// First call to mock the config file
mockReadFile.mockImplementationOnce(() => Promise.resolve(mockConfig));

// Second call to mock the input file read
mockReadFile.mockImplementationOnce(() => Promise.resolve("Original file content."));

// Mock write file to throw an error
mockWriteFile.mockImplementationOnce(() => Promise.reject(new Error("Failed to write to output file")));
mockReadFile.mockImplementation((path) => {
if (path === ".github/configs/setup-custom-action-by-ts.toml") {
return Promise.resolve(mockConfig);
}
if (path === "input.txt") {
return Promise.resolve("Original file content.");
}
return Promise.reject(new Error("Unexpected file read"));
});
mockWriteFile.mockRejectedValue(new Error("Failed to write to output file"));

await run();

expect(mockWarning).toHaveBeenCalledWith("File operation failed: Failed to write to output file");
expect(mockSetFailed).toHaveBeenCalledWith(
"Action failed with error: File operation failed: Failed to write to output file",
);
});

it("should use default values when config is empty", async () => {
Expand Down

0 comments on commit 6c0e80c

Please sign in to comment.