Compare commits
15 Commits
renovate/c
...
refactor-i
Author | SHA1 | Date | |
---|---|---|---|
f9d8f8601b
|
|||
6ccf7f08f9
|
|||
8c12ed263f
|
|||
63d91e18f8
|
|||
7c788de362
|
|||
adedc4e7a0
|
|||
616584e43a
|
|||
ffa09c46c0
|
|||
91fdb76f0f
|
|||
751fd07d45
|
|||
d6c9360dcf
|
|||
bb83d5493a
|
|||
b421097f6b
|
|||
d9bd7f6a85
|
|||
705d67adec
|
57
.gitea/workflows/maintenance.yaml
Normal file
57
.gitea/workflows/maintenance.yaml
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
name: Auto Maintenance Cycle
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- .gitea/workflows/maintenance.yaml
|
||||||
|
schedule:
|
||||||
|
- cron: 0 3 2 * *
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
auto-update:
|
||||||
|
name: pre-commit Autoupdate
|
||||||
|
runs-on: pi64
|
||||||
|
env:
|
||||||
|
SPECIFIC_BRANCH: chore/update-pre-commit
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: main
|
||||||
|
token: ${{ secrets.REPO_TOKEN }}
|
||||||
|
- name: Attempt to checkout specific branch
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: ${{ env.SPECIFIC_BRANCH }}
|
||||||
|
token: ${{ secrets.REPO_TOKEN }}
|
||||||
|
continue-on-error: true
|
||||||
|
- uses: actions/setup-python@v4
|
||||||
|
- run: pip install pre-commit
|
||||||
|
shell: bash
|
||||||
|
- run: pre-commit autoupdate
|
||||||
|
shell: bash
|
||||||
|
- name: Test pre-commit
|
||||||
|
run: SKIP=no-commit-to-branch pre-commit run -a
|
||||||
|
- name: Commit
|
||||||
|
id: auto-commit-action
|
||||||
|
uses: stefanzweifel/git-auto-commit-action@v5
|
||||||
|
with:
|
||||||
|
commit_message: 'chore: update pre-commit hooks'
|
||||||
|
branch: ${{ env.SPECIFIC_BRANCH }}
|
||||||
|
create_branch: true
|
||||||
|
commit_user_name: runner
|
||||||
|
commit_user_email: git@horstenkamp.eu
|
||||||
|
commit_author: runner <git@horstenkamp.eu>
|
||||||
|
- name: Generate Date
|
||||||
|
run: echo "CURRENT_DATE=$(date +'%Y-%m-%d')" >> $GITHUB_ENV
|
||||||
|
- name: Create an PR action
|
||||||
|
if: steps.auto-commit-action.outputs.changes_detected == 'true'
|
||||||
|
uses: https://git.horstenkamp.eu/Philipp/gitea-act-create-pr@main
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.REPO_TOKEN }}
|
||||||
|
branch: ${{ env.SPECIFIC_BRANCH }}
|
||||||
|
title: Updates to the pre-commit action created at ${{ env.CURRENT_DATE }}
|
||||||
|
body: Update to the pre-commit action.
|
||||||
|
base_branch: ${{gitea.ref_name}}
|
||||||
|
assignees: ${{ vars.ASSIGNEES }}
|
||||||
|
reviewers: ${{ vars.REVIEWERS }}
|
268
index.js
268
index.js
@ -5,104 +5,112 @@ const { glob } = require("glob");
|
|||||||
const path = require("path");
|
const path = require("path");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replaces specific placeholder strings within the provided content with corresponding dynamic values.
|
* Replaces placeholder strings in content with dynamic values.
|
||||||
*
|
*
|
||||||
* This function specifically targets three placeholders:
|
* @param {string} content
|
||||||
* - {{gitHash}} is replaced with the current Git commit hash, obtained from the GITHUB_SHA environment variable.
|
* @param {string} hostname
|
||||||
* - {{gitRef}} is replaced with the Git reference (branch or tag) that triggered the workflow, obtained from the GITHUB_REF environment variable.
|
* @returns {string}
|
||||||
* - {{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) {
|
function replacePlaceholders(content, hostname) {
|
||||||
const deployTime = new Date().toISOString();
|
const deployTime = new Date().toISOString();
|
||||||
|
const gitHash = process.env.GITHUB_SHA;
|
||||||
|
const gitRef = process.env.GITHUB_REF;
|
||||||
|
|
||||||
|
core.info("Replacing placeholders:");
|
||||||
|
core.info(` GITHUB_SHA: ${gitHash}`);
|
||||||
|
core.info(` GITHUB_REF: ${gitRef}`);
|
||||||
|
core.info(` deployTime: ${deployTime}`);
|
||||||
|
core.info(` hostname: ${hostname}`);
|
||||||
|
|
||||||
return content
|
return content
|
||||||
.replace(/{{gitHash}}/g, process.env.GITHUB_SHA)
|
.replace(/{{gitHash}}/g, gitHash)
|
||||||
.replace(/{{gitRef}}/g, process.env.GITHUB_REF)
|
.replace(/{{gitRef}}/g, gitRef)
|
||||||
.replace(/{{deployTime}}/g, deployTime)
|
.replace(/{{deployTime}}/g, deployTime)
|
||||||
.replace(/{{hostname}}/g, 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.
|
* Replaces placeholders in files matched by glob.
|
||||||
*
|
*
|
||||||
* This function searches for files in the filesystem using the provided glob pattern, optionally prefixed. It reads each file,
|
* @param {string} pattern
|
||||||
* uses the `replacePlaceholders` function to replace specific placeholders in the file's content, and then writes the modified content
|
* @param {string} [prefix]
|
||||||
* 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} hostname
|
||||||
*
|
* @returns {Promise<string[]>}
|
||||||
* @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.
|
|
||||||
*/
|
*/
|
||||||
async function readReplaceAndWriteFiles(pattern, prefix, hostname) {
|
function readReplaceAndWriteFiles(pattern, prefix, hostname) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const globPattern = prefix ? path.join(prefix, pattern) : pattern;
|
const globPattern = prefix ? path.join(prefix, pattern) : pattern;
|
||||||
|
|
||||||
glob(globPattern, async (err, files) => {
|
glob(globPattern, (err, files) => {
|
||||||
if (err) {
|
if (err) return reject(err);
|
||||||
return reject(err);
|
|
||||||
}
|
|
||||||
let processPromises = [];
|
|
||||||
|
|
||||||
files.forEach((file) => {
|
if (!files.length) {
|
||||||
let processPromise = fs.promises
|
core.warning(
|
||||||
|
`No files matched for placeholder replacement: ${globPattern}`,
|
||||||
|
);
|
||||||
|
return resolve([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
core.info(`📝 Matched files for replacement:`);
|
||||||
|
files.forEach((file) => core.info(` - ${file}`));
|
||||||
|
|
||||||
|
const promises = files.map((file) =>
|
||||||
|
fs.promises
|
||||||
.readFile(file, "utf8")
|
.readFile(file, "utf8")
|
||||||
.then((content) => {
|
.then((content) => {
|
||||||
content = replacePlaceholders(content, hostname);
|
content = replacePlaceholders(content, hostname);
|
||||||
return fs.promises.writeFile(file, content);
|
return fs.promises.writeFile(file, content);
|
||||||
});
|
})
|
||||||
|
.then(() => {
|
||||||
|
core.info(`Replaced placeholders in file: ${file}`);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
processPromises.push(processPromise);
|
Promise.all(promises)
|
||||||
});
|
.then(() => {
|
||||||
|
core.info(
|
||||||
try {
|
`Successfully replaced placeholders in ${files.length} file(s).`,
|
||||||
await Promise.all(processPromises);
|
);
|
||||||
resolve(files);
|
resolve(files);
|
||||||
} catch (processError) {
|
})
|
||||||
reject(processError);
|
.catch(reject);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads files matching a glob pattern into a dictionary.
|
* Reads files into a dictionary of key → content.
|
||||||
* @param {string} pattern - Glob pattern to match files.
|
*
|
||||||
* @param {string} prefix - Directory prefix for file paths.
|
* @param {string} pattern
|
||||||
* @returns {Promise<Object>} - Promise resolving to a dictionary of file contents keyed by filenames.
|
* @param {string} prefix
|
||||||
|
* @returns {Promise<Object>}
|
||||||
*/
|
*/
|
||||||
function readFilesIntoDict(pattern, prefix) {
|
function readFilesIntoDict(pattern, prefix) {
|
||||||
// Prepend the prefix to the glob pattern
|
|
||||||
const globPattern = prefix ? path.join(prefix, pattern) : pattern;
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
const globPattern = prefix ? path.join(prefix, pattern) : pattern;
|
||||||
|
|
||||||
glob(globPattern, (err, files) => {
|
glob(globPattern, (err, files) => {
|
||||||
if (err) {
|
if (err) return reject(err);
|
||||||
return reject(err);
|
|
||||||
|
if (!files.length) {
|
||||||
|
core.warning(`No files matched for upload: ${globPattern}`);
|
||||||
|
} else {
|
||||||
|
core.info(`📁 Matched files for upload:`);
|
||||||
|
files.forEach((file) => core.info(` - ${file}`));
|
||||||
}
|
}
|
||||||
|
|
||||||
let fileDict = {};
|
const fileDict = {};
|
||||||
let readPromises = [];
|
const readPromises = files.map((file) =>
|
||||||
|
fs.promises.readFile(file, "utf8").then((content) => {
|
||||||
files.forEach((file) => {
|
|
||||||
let readPromise = fs.promises.readFile(file, "utf8").then((content) => {
|
|
||||||
// Remove the prefix from the filename and drop the file suffix
|
|
||||||
let key = file;
|
let key = file;
|
||||||
if (prefix && file.startsWith(prefix)) {
|
if (prefix && file.startsWith(prefix)) {
|
||||||
key = key.slice(prefix.length);
|
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;
|
fileDict[key] = content;
|
||||||
});
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
readPromises.push(readPromise);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Use Promise.all to ensure all files are read before resolving
|
|
||||||
Promise.all(readPromises)
|
Promise.all(readPromises)
|
||||||
.then(() => resolve(fileDict))
|
.then(() => resolve(fileDict))
|
||||||
.catch(reject);
|
.catch(reject);
|
||||||
@ -111,96 +119,106 @@ function readFilesIntoDict(pattern, prefix) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates the provided authentication credentials.
|
* Validates provided credentials.
|
||||||
* @param {string} token - The authentication token.
|
*
|
||||||
* @param {string} username - The username.
|
* @param {string} token
|
||||||
* @param {string} password - The password.
|
* @param {string} username
|
||||||
* @returns {string|null} - Returns an error message if validation fails, otherwise null.
|
* @param {string} password
|
||||||
|
* @returns {string|null}
|
||||||
*/
|
*/
|
||||||
function validateAuthentication(token, username, password) {
|
function validateAuthentication(token, username, password) {
|
||||||
if (token) {
|
if (token && (username || password)) {
|
||||||
if (username || password) {
|
return "Token is defined along with username and/or 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
|
if (!token && (!username || !password)) {
|
||||||
|
return "Username and password must both be defined if token is not used.";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Posts code to Screeps server.
|
* Main logic for uploading code to Screeps.
|
||||||
*/
|
*/
|
||||||
async function postCode() {
|
function postCode() {
|
||||||
|
core.info("🟢 Starting Screeps upload action...");
|
||||||
|
|
||||||
const protocol = core.getInput("protocol") || "https";
|
const protocol = core.getInput("protocol") || "https";
|
||||||
const hostname = core.getInput("hostname") || "screeps.com";
|
const hostname = core.getInput("hostname") || "screeps.com";
|
||||||
const port = core.getInput("port") || "443";
|
const port = core.getInput("port") || "443";
|
||||||
const path = core.getInput("path") || "/";
|
const path = core.getInput("path") || "/";
|
||||||
|
|
||||||
const token = core.getInput("token") || undefined;
|
const token = core.getInput("token") || undefined;
|
||||||
const username = core.getInput("username") || undefined;
|
const username = core.getInput("username") || undefined;
|
||||||
const password = core.getInput("password") || undefined;
|
const password = core.getInput("password") || undefined;
|
||||||
const prefix = core.getInput("source-prefix");
|
const prefix = core.getInput("source-prefix");
|
||||||
const pattern = core.getInput("pattern") || "*.js";
|
const pattern = core.getInput("pattern") || "*.js";
|
||||||
const branch = core.getInput("branch") || "default";
|
const branch = core.getInput("branch") || "default";
|
||||||
|
|
||||||
const gitReplace = core.getInput("git-replace") || null;
|
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 = {
|
const login_arguments = {
|
||||||
token: token,
|
token,
|
||||||
username: username,
|
username,
|
||||||
password: password,
|
password,
|
||||||
protocol: protocol,
|
protocol,
|
||||||
hostname: hostname,
|
hostname,
|
||||||
port: port,
|
port,
|
||||||
path: path,
|
path,
|
||||||
};
|
};
|
||||||
|
|
||||||
core.info("login_arguments:");
|
core.info("🔧 Inputs:");
|
||||||
core.info(JSON.stringify(login_arguments, null, 2));
|
core.info(` prefix: ${prefix}`);
|
||||||
|
core.info(` pattern: ${pattern}`);
|
||||||
|
core.info(` branch: ${branch}`);
|
||||||
|
core.info(` gitReplace: ${gitReplace}`);
|
||||||
|
|
||||||
const errorMessage = validateAuthentication(token, username, password);
|
const errorMessage = validateAuthentication(token, username, password);
|
||||||
if (errorMessage) {
|
if (errorMessage) {
|
||||||
core.error(errorMessage);
|
core.setFailed(errorMessage);
|
||||||
return;
|
return Promise.reject(new Error(errorMessage));
|
||||||
}
|
}
|
||||||
let api = new ScreepsAPI(login_arguments);
|
|
||||||
if (token) {
|
const replacePromise = gitReplace
|
||||||
const response = await api.code.set(branch, files_to_push);
|
? readReplaceAndWriteFiles(gitReplace, prefix, hostname)
|
||||||
core.info(JSON.stringify(response, null, 2));
|
: Promise.resolve();
|
||||||
console.log(`Code set successfully to ${branch}`);
|
|
||||||
} else {
|
return replacePromise
|
||||||
core.info(`Logging in as user ${username}`);
|
.then(() => readFilesIntoDict(pattern, prefix))
|
||||||
await Promise.resolve()
|
.then((files_to_push) => {
|
||||||
.then(() => api.auth(username, password, login_arguments))
|
const fileCount = Object.keys(files_to_push).length;
|
||||||
.then(() => {
|
core.info(`📦 Files prepared for upload: ${fileCount}`);
|
||||||
api.code.set(branch, files_to_push);
|
|
||||||
})
|
if (fileCount === 0) {
|
||||||
.then(() => {
|
core.warning("No files were found to upload. Exiting.");
|
||||||
console.log(`Code set successfully to ${branch}`);
|
return;
|
||||||
})
|
}
|
||||||
.catch((err) => {
|
|
||||||
console.error("Error:", err);
|
core.info(`⬆️ Uploading to branch '${branch}':`);
|
||||||
|
Object.keys(files_to_push).forEach((key) => {
|
||||||
|
core.info(` - ${key}`);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
const api = new ScreepsAPI(login_arguments);
|
||||||
|
|
||||||
|
if (token) {
|
||||||
|
return api.code.set(branch, files_to_push).then((response) => {
|
||||||
|
core.info(JSON.stringify(response, null, 2));
|
||||||
|
core.info(`✅ Code uploaded to branch '${branch}' using token.`);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
core.info(`🔐 Logging in as user '${username}'...`);
|
||||||
|
return api
|
||||||
|
.auth(username, password, login_arguments)
|
||||||
|
.then(() => api.code.set(branch, files_to_push))
|
||||||
|
.then(() => {
|
||||||
|
core.info(`✅ Code uploaded to branch '${branch}' via basic auth.`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
postCode();
|
|
||||||
|
// Kick off the process and ensure failures are surfaced
|
||||||
|
postCode().catch((err) => {
|
||||||
|
core.setFailed(err.message || err);
|
||||||
|
});
|
||||||
|
|
||||||
|
core.info(`✅ Final Code uploaded to branch via basic auth.`);
|
||||||
|
core.debug(`✅ DEBUG Final Code uploaded to branch via basic auth. DEBUG`);
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
|
|
||||||
}
|
|
Reference in New Issue
Block a user