docs-v2/.github/scripts/cache-manager.cjs

177 lines
4.8 KiB
JavaScript

#!/usr/bin/env node
/**
* Simple Cache Manager for Link Validation Results
* Uses GitHub Actions cache API or local file storage
*/
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const process = require('process');
const CACHE_VERSION = 'v1';
const CACHE_KEY_PREFIX = 'link-validation';
const LOCAL_CACHE_DIR = path.join(process.cwd(), '.cache', 'link-validation');
/**
* Simple cache interface
*/
class CacheManager {
constructor(options = {}) {
this.useGitHubCache =
options.useGitHubCache !== false && process.env.GITHUB_ACTIONS;
this.localCacheDir = options.localCacheDir || LOCAL_CACHE_DIR;
// Configurable cache TTL - default 30 days, support environment variable
this.cacheTTLDays =
options.cacheTTLDays || parseInt(process.env.LINK_CACHE_TTL_DAYS) || 30;
this.maxAge = this.cacheTTLDays * 24 * 60 * 60 * 1000;
if (!this.useGitHubCache) {
this.ensureLocalCacheDir();
}
}
ensureLocalCacheDir() {
if (!fs.existsSync(this.localCacheDir)) {
fs.mkdirSync(this.localCacheDir, { recursive: true });
}
}
generateCacheKey(filePath, fileHash) {
const pathHash = crypto
.createHash('sha256')
.update(filePath)
.digest('hex')
.substring(0, 8);
return `${CACHE_KEY_PREFIX}-${CACHE_VERSION}-${pathHash}-${fileHash}`;
}
async get(filePath, fileHash) {
if (this.useGitHubCache) {
return await this.getFromGitHubCache(filePath, fileHash);
} else {
return await this.getFromLocalCache(filePath, fileHash);
}
}
async set(filePath, fileHash, results) {
if (this.useGitHubCache) {
return await this.setToGitHubCache(filePath, fileHash, results);
} else {
return await this.setToLocalCache(filePath, fileHash, results);
}
}
async getFromGitHubCache(filePath, fileHash) {
// TODO: This method is a placeholder for GitHub Actions cache integration
// GitHub Actions cache is handled directly in the workflow via actions/cache
// This method should either be implemented or removed in future versions
console.warn(
'[PLACEHOLDER] getFromGitHubCache: Using placeholder implementation - always returns null'
);
return null;
}
async setToGitHubCache(filePath, fileHash, results) {
// TODO: This method is a placeholder for GitHub Actions cache integration
// GitHub Actions cache is handled directly in the workflow via actions/cache
// This method should either be implemented or removed in future versions
console.warn(
'[PLACEHOLDER] setToGitHubCache: Using placeholder implementation - always returns true'
);
return true;
}
async getFromLocalCache(filePath, fileHash) {
const cacheKey = this.generateCacheKey(filePath, fileHash);
const cacheFile = path.join(this.localCacheDir, `${cacheKey}.json`);
if (!fs.existsSync(cacheFile)) {
return null;
}
try {
const content = fs.readFileSync(cacheFile, 'utf8');
const cached = JSON.parse(content);
// TTL check using configured cache duration
const age = Date.now() - new Date(cached.cachedAt).getTime();
if (age > this.maxAge) {
fs.unlinkSync(cacheFile);
return null;
}
return cached.results;
} catch (error) {
// Clean up corrupted cache
try {
fs.unlinkSync(cacheFile);
} catch {
// Ignore cleanup errors
}
return null;
}
}
async setToLocalCache(filePath, fileHash, results) {
const cacheKey = this.generateCacheKey(filePath, fileHash);
const cacheFile = path.join(this.localCacheDir, `${cacheKey}.json`);
const cacheData = {
filePath,
fileHash,
results,
cachedAt: new Date().toISOString(),
};
try {
fs.writeFileSync(cacheFile, JSON.stringify(cacheData, null, 2));
return true;
} catch (error) {
console.warn(`Cache save failed: ${error.message}`);
return false;
}
}
async cleanup() {
if (this.useGitHubCache) {
return { removed: 0, note: 'GitHub Actions cache auto-managed' };
}
let removed = 0;
if (!fs.existsSync(this.localCacheDir)) {
return { removed };
}
const files = fs.readdirSync(this.localCacheDir);
for (const file of files) {
if (!file.endsWith('.json')) continue;
const filePath = path.join(this.localCacheDir, file);
try {
const stat = fs.statSync(filePath);
if (Date.now() - stat.mtime.getTime() > this.maxAge) {
fs.unlinkSync(filePath);
removed++;
}
} catch {
// Remove corrupted files
try {
fs.unlinkSync(filePath);
removed++;
} catch {
// Ignore errors
}
}
}
return { removed };
}
}
module.exports = CacheManager;
module.exports.CacheManager = CacheManager;