This commit updates the @actions/core dependency from v2 to v3. The primary change in @actions/core v3 is that it is now an ESM-only package. To maintain compatibility, the following changes were made: - Added "type": "module" to package.json to switch the project to ESM. - Converted index.js from CommonJS to ESM, replacing require with import/export. - Converted __tests__/index.test.js to ESM to support testing the updated index.js. - Re-built the production bundle in dist/ using ncc to reflect the changes. - Updated the main entry point check in index.js to use import.meta.url for ESM compatibility. This ensures the action continues to function correctly with the latest GitHub Actions toolkit library.
183 lines
6.6 KiB
JavaScript
183 lines
6.6 KiB
JavaScript
import { ScreepsAPI } from "screeps-api";
|
|
import * as core from "@actions/core";
|
|
import fs from "fs";
|
|
import { glob } from "glob";
|
|
import path from "path";
|
|
import { fileURLToPath } from "url";
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
export function replacePlaceholders(content, hostname) {
|
|
const deployTime = new Date().toISOString();
|
|
return content
|
|
.replace(/{{gitHash}}/g, process.env.GITHUB_SHA)
|
|
.replace(/{{gitRef}}/g, process.env.GITHUB_REF)
|
|
.replace(/{{deployTime}}/g, deployTime)
|
|
.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<string[]>} A promise that resolves with an array of file paths that were processed, or rejects with an error if the process fails.
|
|
*/
|
|
export async function readReplaceAndWriteFiles(pattern, prefix, hostname) {
|
|
const globPattern = prefix ? path.join(prefix, pattern) : pattern;
|
|
const files = await glob(globPattern);
|
|
|
|
let processPromises = files.map((file) => {
|
|
return fs.promises.readFile(file, "utf8").then((content) => {
|
|
content = replacePlaceholders(content, hostname);
|
|
return fs.promises.writeFile(file, content);
|
|
});
|
|
});
|
|
|
|
await Promise.all(processPromises);
|
|
return files;
|
|
}
|
|
|
|
/**
|
|
* 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<Object>} - Promise resolving to a dictionary of file contents keyed by filenames.
|
|
*/
|
|
export async function readFilesIntoDict(pattern, prefix) {
|
|
// Prepend the prefix to the glob pattern
|
|
const globPattern = prefix ? path.join(prefix, pattern) : pattern;
|
|
const files = await glob(globPattern);
|
|
|
|
let fileDict = {};
|
|
let readPromises = files.map((file) => {
|
|
return 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
|
|
|
|
fileDict[key] = content;
|
|
});
|
|
});
|
|
|
|
await Promise.all(readPromises);
|
|
return fileDict;
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
export 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.";
|
|
}
|
|
}
|
|
return null; // No errors found
|
|
}
|
|
|
|
/**
|
|
* Posts code to Screeps server.
|
|
*/
|
|
export 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;
|
|
|
|
if (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}`);
|
|
});
|
|
|
|
const login_arguments = {
|
|
token: token,
|
|
username: username,
|
|
password: password,
|
|
protocol: protocol,
|
|
hostname: hostname,
|
|
port: port,
|
|
path: path,
|
|
};
|
|
|
|
core.info("login_arguments:");
|
|
core.info(JSON.stringify(login_arguments, null, 2));
|
|
|
|
const errorMessage = validateAuthentication(token, username, password);
|
|
if (errorMessage) {
|
|
core.error(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);
|
|
});
|
|
}
|
|
}
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
if (process.argv[1] === __filename) {
|
|
postCode();
|
|
}
|