fix: persist OG image cache outside act runner workspace
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m51s
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m51s
The cache was written to .cache/og/ relative to the workspace, which is under /usr/local/git/.cache/act/<unique-hash>/hostexecutor/ — a new path per run, so every build regenerated all images from scratch. OG_CACHE_DIR env var now controls the cache path (resolved to an absolute path). CI sets it to /usr/local/git/.cache/og, which survives between runs. Locally it still defaults to .cache/og inside the project dir. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1
.github/workflows/deploy.yml
vendored
1
.github/workflows/deploy.yml
vendored
@@ -125,6 +125,7 @@ jobs:
|
||||
GITEA_URL: https://gitea.giersig.eu
|
||||
GITEA_INTERNAL_URL: http://127.0.0.1:3000
|
||||
GITEA_ORG: giersig.eu
|
||||
OG_CACHE_DIR: /usr/local/git/.cache/og
|
||||
|
||||
- name: Deploy via rsync
|
||||
run: |
|
||||
|
||||
@@ -26,6 +26,12 @@ const postGraph = esmRequire("@rknightuk/eleventy-plugin-post-graph");
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const siteUrl = process.env.SITE_URL || "https://example.com";
|
||||
|
||||
// OG image cache — persistent across CI runs when OG_CACHE_DIR env var is set.
|
||||
// In CI, point this outside the act runner workspace (e.g. /usr/local/git/.cache/og).
|
||||
const OG_CACHE_DIR = process.env.OG_CACHE_DIR
|
||||
? resolve(process.env.OG_CACHE_DIR)
|
||||
: resolve(__dirname, ".cache", "og");
|
||||
|
||||
// Slugify each path segment, preserving "/" separators for nested tags (e.g. "tech/programming")
|
||||
const nestedSlugify = (str) => {
|
||||
if (!str) return "";
|
||||
@@ -49,7 +55,7 @@ export default function (eleventyConfig) {
|
||||
eleventyConfig.setUseGitIgnore(false);
|
||||
|
||||
// Passthrough copy for OG images
|
||||
eleventyConfig.addPassthroughCopy({ ".cache/og": "images/og" });
|
||||
eleventyConfig.addPassthroughCopy({ [OG_CACHE_DIR]: "images/og" });
|
||||
|
||||
// Ignore output directory (prevents re-processing generated files via symlink)
|
||||
eleventyConfig.ignores.add("_site");
|
||||
@@ -78,8 +84,8 @@ export default function (eleventyConfig) {
|
||||
eleventyConfig.watchIgnores.add("/app/data/site/**");
|
||||
eleventyConfig.watchIgnores.add("pagefind");
|
||||
eleventyConfig.watchIgnores.add("pagefind/**");
|
||||
eleventyConfig.watchIgnores.add(".cache/og");
|
||||
eleventyConfig.watchIgnores.add(".cache/og/**");
|
||||
eleventyConfig.watchIgnores.add(OG_CACHE_DIR);
|
||||
eleventyConfig.watchIgnores.add(OG_CACHE_DIR + "/**");
|
||||
eleventyConfig.watchIgnores.add(".cache/unfurl");
|
||||
eleventyConfig.watchIgnores.add(".cache/unfurl/**");
|
||||
|
||||
@@ -388,9 +394,8 @@ export default function (eleventyConfig) {
|
||||
eleventyConfig.on("eleventy.before", () => { _ogFileSet = null; });
|
||||
function hasOgImage(ogSlug) {
|
||||
if (!_ogFileSet) {
|
||||
const ogDir = resolve(__dirname, ".cache", "og");
|
||||
try {
|
||||
_ogFileSet = new Set(readdirSync(ogDir));
|
||||
_ogFileSet = new Set(readdirSync(OG_CACHE_DIR));
|
||||
} catch {
|
||||
_ogFileSet = new Set();
|
||||
}
|
||||
@@ -658,7 +663,7 @@ export default function (eleventyConfig) {
|
||||
eleventyConfig.addPassthroughCopy("favicon.ico");
|
||||
eleventyConfig.addPassthroughCopy("robots.txt");
|
||||
eleventyConfig.addPassthroughCopy("interactive");
|
||||
eleventyConfig.addPassthroughCopy({ ".cache/og": "og" });
|
||||
eleventyConfig.addPassthroughCopy({ [OG_CACHE_DIR]: "og" });
|
||||
// Funkwhale images are copied in eleventy.after (after data files download them)
|
||||
|
||||
// Copy vendor web components from node_modules
|
||||
@@ -929,8 +934,7 @@ export default function (eleventyConfig) {
|
||||
// Check if a generated OG image exists for this slug
|
||||
eleventyConfig.addFilter("hasOgImage", (slug) => {
|
||||
if (!slug) return false;
|
||||
const ogPath = resolve(__dirname, ".cache", "og", `${slug}.png`);
|
||||
return existsSync(ogPath);
|
||||
return existsSync(resolve(OG_CACHE_DIR, `${slug}.png`));
|
||||
});
|
||||
|
||||
// Inline file contents (for critical CSS inlining)
|
||||
@@ -1589,7 +1593,6 @@ export default function (eleventyConfig) {
|
||||
eleventyConfig.on("eleventy.before", () => {
|
||||
console.time("[og] image generation");
|
||||
const contentDir = resolve(__dirname, "content");
|
||||
const cacheDir = resolve(__dirname, ".cache");
|
||||
const siteName = process.env.SITE_NAME || "My IndieWeb Blog";
|
||||
const BATCH_SIZE = 100;
|
||||
try {
|
||||
@@ -1601,7 +1604,7 @@ export default function (eleventyConfig) {
|
||||
"--expose-gc",
|
||||
resolve(__dirname, "lib", "og-cli.js"),
|
||||
contentDir,
|
||||
cacheDir,
|
||||
OG_CACHE_DIR,
|
||||
siteName,
|
||||
String(BATCH_SIZE),
|
||||
], {
|
||||
@@ -1620,16 +1623,15 @@ export default function (eleventyConfig) {
|
||||
}
|
||||
|
||||
// Sync new OG images to output directory.
|
||||
// During incremental builds, .cache/og is in watchIgnores so Eleventy's
|
||||
// During incremental builds, OG_CACHE_DIR is in watchIgnores so Eleventy's
|
||||
// passthrough copy won't pick up newly generated images. Copy them manually.
|
||||
const ogCacheDir = resolve(cacheDir, "og");
|
||||
const ogOutputDir = resolve(__dirname, "_site", "og");
|
||||
if (existsSync(ogCacheDir) && existsSync(resolve(__dirname, "_site"))) {
|
||||
if (existsSync(OG_CACHE_DIR) && existsSync(resolve(__dirname, "_site"))) {
|
||||
mkdirSync(ogOutputDir, { recursive: true });
|
||||
let synced = 0;
|
||||
for (const file of readdirSync(ogCacheDir)) {
|
||||
for (const file of readdirSync(OG_CACHE_DIR)) {
|
||||
if (file.endsWith(".png") && !existsSync(resolve(ogOutputDir, file))) {
|
||||
copyFileSync(resolve(ogCacheDir, file), resolve(ogOutputDir, file));
|
||||
copyFileSync(resolve(OG_CACHE_DIR, file), resolve(ogOutputDir, file));
|
||||
synced++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* CLI entry point for OG image generation.
|
||||
* Runs as a separate process to isolate memory from Eleventy.
|
||||
*
|
||||
* Usage: node lib/og-cli.js <contentDir> <cacheDir> <siteName> [batchSize]
|
||||
* Usage: node lib/og-cli.js <contentDir> <ogDir> <siteName> [batchSize]
|
||||
*
|
||||
* batchSize: Max images to generate per invocation (0 = unlimited).
|
||||
* When set, exits after generating that many images so the caller
|
||||
@@ -14,15 +14,15 @@
|
||||
|
||||
import { generateOgImages } from "./og.js";
|
||||
|
||||
const [contentDir, cacheDir, siteName, batchSizeStr] = process.argv.slice(2);
|
||||
const [contentDir, ogDir, siteName, batchSizeStr] = process.argv.slice(2);
|
||||
|
||||
if (!contentDir || !cacheDir || !siteName) {
|
||||
console.error("[og] Usage: node og-cli.js <contentDir> <cacheDir> <siteName> [batchSize]");
|
||||
if (!contentDir || !ogDir || !siteName) {
|
||||
console.error("[og] Usage: node og-cli.js <contentDir> <ogDir> <siteName> [batchSize]");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const batchSize = parseInt(batchSizeStr, 10) || 0;
|
||||
const result = await generateOgImages(contentDir, cacheDir, siteName, batchSize);
|
||||
const result = await generateOgImages(contentDir, ogDir, siteName, batchSize);
|
||||
|
||||
// Exit code 2 signals "batch complete, more images remain"
|
||||
if (result?.hasMore) {
|
||||
|
||||
@@ -426,8 +426,7 @@ function scanContentFiles(contentDir) {
|
||||
* @param {number} batchSize - Max images to generate (0 = unlimited)
|
||||
* @returns {{ hasMore: boolean }} Whether more images need generation
|
||||
*/
|
||||
export async function generateOgImages(contentDir, cacheDir, siteName, batchSize = 0) {
|
||||
const ogDir = join(cacheDir, "og");
|
||||
export async function generateOgImages(contentDir, ogDir, siteName, batchSize = 0) {
|
||||
mkdirSync(ogDir, { recursive: true });
|
||||
|
||||
const manifestPath = join(ogDir, "manifest.json");
|
||||
|
||||
Reference in New Issue
Block a user