From 705d67adecfce5850ff412377619f87f49b69688 Mon Sep 17 00:00:00 2001 From: Philipp Horstenkamp Date: Mon, 21 Apr 2025 22:54:49 +0200 Subject: [PATCH] Refactor the index.js --- index.js | 169 ++++++++++++++++++++++++------------------------------- 1 file changed, 72 insertions(+), 97 deletions(-) diff --git a/index.js b/index.js index eba2489..1dc62d7 100644 --- a/index.js +++ b/index.js @@ -4,21 +4,11 @@ const fs = require("fs"); const { glob } = require("glob"); const path = require("path"); -/** - * Replaces specific placeholder strings within the provided content with corresponding dynamic values. - * - * This function specifically targets three placeholders: - * - {{gitHash}} is replaced with the current Git commit hash, obtained from the GITHUB_SHA environment variable. - * - {{gitRef}} is replaced with the Git reference (branch or tag) that triggered the workflow, obtained from the GITHUB_REF environment variable. - * - {{deployTime}} is replaced with the current ISO timestamp. - * - * Note: This function is designed for use within a GitHub Actions workflow where GITHUB_SHA and GITHUB_REF environment variables are automatically set. - * - * @param {string} content - The string content in which placeholders are to be replaced. - * @returns {string} The content with placeholders replaced by their respective dynamic values. - */ function replacePlaceholders(content, hostname) { const deployTime = new Date().toISOString(); + core.debug( + `Replacing placeholders with: GITHUB_SHA=${process.env.GITHUB_SHA}, GITHUB_REF=${process.env.GITHUB_REF}, deployTime=${deployTime}, hostname=${hostname}`, + ); return content .replace(/{{gitHash}}/g, process.env.GITHUB_SHA) .replace(/{{gitRef}}/g, process.env.GITHUB_REF) @@ -26,33 +16,33 @@ function replacePlaceholders(content, hostname) { .replace(/{{hostname}}/g, hostname); } -/** - * Reads all files matching a specified pattern, replaces certain placeholders in their content, and writes the updated content back to the files. - * - * This function searches for files in the filesystem using the provided glob pattern, optionally prefixed. It reads each file, - * uses the `replacePlaceholders` function to replace specific placeholders in the file's content, and then writes the modified content - * back to the original file. This is useful for dynamically updating file contents in a batch process, such as during a build or deployment. - * - * @param {string} pattern - The glob pattern used to find files. Example: '*.js' for all JavaScript files. - * @param {string} [prefix] - An optional directory prefix to prepend to the glob pattern. This allows searching within a specific directory. - * @returns {Promise} A promise that resolves with an array of file paths that were processed, or rejects with an error if the process fails. - */ async function readReplaceAndWriteFiles(pattern, prefix, hostname) { return new Promise((resolve, reject) => { const globPattern = prefix ? path.join(prefix, pattern) : pattern; + core.info(`Searching files with glob pattern: ${globPattern}`); glob(globPattern, async (err, files) => { if (err) { + core.error(`Glob error: ${err}`); return reject(err); } + + if (files.length === 0) { + core.warning("No files matched the glob pattern."); + } + let processPromises = []; files.forEach((file) => { + core.debug(`Processing file: ${file}`); let processPromise = fs.promises .readFile(file, "utf8") .then((content) => { content = replacePlaceholders(content, hostname); return fs.promises.writeFile(file, content); + }) + .then(() => { + core.info(`Replaced and wrote file: ${file}`); }); processPromises.push(processPromise); @@ -60,27 +50,24 @@ async function readReplaceAndWriteFiles(pattern, prefix, hostname) { try { await Promise.all(processPromises); + core.info(`Successfully processed ${files.length} files.`); resolve(files); } catch (processError) { + core.error(`Error during file processing: ${processError}`); reject(processError); } }); }); } -/** - * Reads files matching a glob pattern into a dictionary. - * @param {string} pattern - Glob pattern to match files. - * @param {string} prefix - Directory prefix for file paths. - * @returns {Promise} - Promise resolving to a dictionary of file contents keyed by filenames. - */ function readFilesIntoDict(pattern, prefix) { - // Prepend the prefix to the glob pattern const globPattern = prefix ? path.join(prefix, pattern) : pattern; + core.info(`Reading files into dict with glob: ${globPattern}`); return new Promise((resolve, reject) => { glob(globPattern, (err, files) => { if (err) { + core.error(`Glob error: ${err}`); return reject(err); } @@ -88,119 +75,107 @@ function readFilesIntoDict(pattern, prefix) { let readPromises = []; files.forEach((file) => { + core.debug(`Reading file: ${file}`); let readPromise = fs.promises.readFile(file, "utf8").then((content) => { - // Remove the prefix from the filename and drop the file suffix let key = file; if (prefix && file.startsWith(prefix)) { key = key.slice(prefix.length); } - key = path.basename(key, path.extname(key)); // Drop the file suffix - + key = path.basename(key, path.extname(key)); fileDict[key] = content; }); readPromises.push(readPromise); }); - // Use Promise.all to ensure all files are read before resolving Promise.all(readPromises) - .then(() => resolve(fileDict)) - .catch(reject); + .then(() => { + core.debug(`Read ${files.length} files into dictionary.`); + resolve(fileDict); + }) + .catch((readErr) => { + core.error(`Error reading files: ${readErr}`); + reject(readErr); + }); }); }); } -/** - * Validates the provided authentication credentials. - * @param {string} token - The authentication token. - * @param {string} username - The username. - * @param {string} password - The password. - * @returns {string|null} - Returns an error message if validation fails, otherwise null. - */ function validateAuthentication(token, username, password) { - if (token) { - if (username || password) { - return "Token is defined along with username and/or password."; - } - } else { - if (!username && !password) { - return "Neither token nor password and username are defined."; - } - if (username && !password) { - return "Username is defined but no password is provided."; - } - if (!username && password) { - return "Password is defined but no username is provided."; - } + if (token && (username || password)) { + return "Token is defined along with username and/or password."; } - return null; // No errors found + if (!token && (!username || !password)) { + return "Username and password must both be defined if token is not used."; + } + return null; } -/** - * Posts code to Screeps server. - */ async function postCode() { const protocol = core.getInput("protocol") || "https"; const hostname = core.getInput("hostname") || "screeps.com"; const port = core.getInput("port") || "443"; const path = core.getInput("path") || "/"; - const token = core.getInput("token") || undefined; const username = core.getInput("username") || undefined; const password = core.getInput("password") || undefined; const prefix = core.getInput("source-prefix"); const pattern = core.getInput("pattern") || "*.js"; const branch = core.getInput("branch") || "default"; - const gitReplace = core.getInput("git-replace") || null; + core.info("Starting Screeps code upload action..."); + if (gitReplace) { + core.info(`Replacing placeholders in files matching: ${gitReplace}`); await readReplaceAndWriteFiles(gitReplace, prefix, hostname); } const files_to_push = await readFilesIntoDict(pattern, prefix); - - core.info(`Trying to upload the following files to ${branch}:`); - Object.keys(files_to_push).forEach((key) => { - core.info(`Key: ${key}`); - }); + core.info( + `Preparing to upload ${ + Object.keys(files_to_push).length + } files to branch: ${branch}`, + ); const login_arguments = { - token: token, - username: username, - password: password, - protocol: protocol, - hostname: hostname, - port: port, - path: path, + token, + username, + password, + protocol, + hostname, + port, + path, }; - - core.info("login_arguments:"); - core.info(JSON.stringify(login_arguments, null, 2)); + core.debug(`Login arguments: ${JSON.stringify(login_arguments, null, 2)}`); const errorMessage = validateAuthentication(token, username, password); if (errorMessage) { - core.error(errorMessage); + core.setFailed(errorMessage); return; } + let api = new ScreepsAPI(login_arguments); - if (token) { - const response = await api.code.set(branch, files_to_push); - core.info(JSON.stringify(response, null, 2)); - console.log(`Code set successfully to ${branch}`); - } else { - core.info(`Logging in as user ${username}`); - await Promise.resolve() - .then(() => api.auth(username, password, login_arguments)) - .then(() => { - api.code.set(branch, files_to_push); - }) - .then(() => { - console.log(`Code set successfully to ${branch}`); - }) - .catch((err) => { - console.error("Error:", err); - }); + + try { + if (token) { + const response = await api.code.set(branch, files_to_push); + core.info( + `Code uploaded via token. Response: ${JSON.stringify( + response, + null, + 2, + )}`, + ); + } else { + core.info(`Logging in with username/password for user ${username}`); + await api.auth(username, password, login_arguments); + await api.code.set(branch, files_to_push); + core.info("Code uploaded via basic auth."); + } + } catch (err) { + core.setFailed(`Upload failed: ${err.message || err}`); } } + postCode();