diff --git a/.github/workflows/r2-pages.yml b/.github/workflows/r2-pages.yml index b437e18ca..ca4a7c953 100644 --- a/.github/workflows/r2-pages.yml +++ b/.github/workflows/r2-pages.yml @@ -13,6 +13,12 @@ on: - "README.md" - "CLOUDFLARE.md" workflow_dispatch: + inputs: + force_upload: + description: "Upload every manifest object instead of only changed objects." + required: false + type: boolean + default: false permissions: contents: read @@ -96,4 +102,5 @@ jobs: OPENCLAW_R2_ACCESS_KEY_ID: ${{ secrets.OPENCLAW_R2_ACCESS_KEY_ID }} OPENCLAW_R2_SECRET_ACCESS_KEY: ${{ secrets.OPENCLAW_R2_SECRET_ACCESS_KEY }} R2_UPLOAD_CONCURRENCY: 64 + R2_UPLOAD_FORCE: ${{ github.event_name == 'workflow_dispatch' && inputs.force_upload == true && '1' || '0' }} run: npm run docs:r2:upload diff --git a/scripts/docs-site/r2-upload.mjs b/scripts/docs-site/r2-upload.mjs index 7d05af300..bc457698a 100644 --- a/scripts/docs-site/r2-upload.mjs +++ b/scripts/docs-site/r2-upload.mjs @@ -16,6 +16,7 @@ const region = process.env.OPENCLAW_R2_REGION || "auto"; const service = "s3"; const retryAttempts = Number.parseInt(process.env.R2_UPLOAD_RETRIES || "5", 10); const deleteOrphans = process.env.R2_DELETE_ORPHANS !== "0"; +const forceUpload = process.env.R2_UPLOAD_FORCE === "1"; if (!Number.isFinite(concurrency) || concurrency < 1) throw new Error("R2_UPLOAD_CONCURRENCY must be a positive integer"); if (!fs.existsSync(manifestPath)) throw new Error("dist/docs-r2-manifest.json does not exist; run docs:build:r2 first"); @@ -28,19 +29,21 @@ const remoteManifest = await getRemoteManifest(); const remoteEntries = new Map((remoteManifest?.entries || []).map((entry) => [entry.key, entry])); const localKeys = new Set(manifest.entries.map((entry) => entry.key)); localKeys.add(remoteManifestKey); -const changed = manifest.entries.filter((entry) => { - const remote = remoteEntries.get(entry.key); - return !remote - || remote.sha256 !== entry.sha256 - || remote.contentType !== entry.contentType - || remote.cacheControl !== entry.cacheControl; -}); +const changed = forceUpload + ? manifest.entries + : manifest.entries.filter((entry) => { + const remote = remoteEntries.get(entry.key); + return !remote + || remote.sha256 !== entry.sha256 + || remote.contentType !== entry.contentType + || remote.cacheControl !== entry.cacheControl; + }); const manifestDeletedKeys = Array.from(remoteEntries.keys()).filter((key) => !localKeys.has(key)); const orphanedKeys = deleteOrphans ? (await listBucketKeys()).filter((key) => !localKeys.has(key)) : []; const deleted = Array.from(new Set([...manifestDeletedKeys, ...orphanedKeys])).sort().map((key) => ({ key })); console.log( - `r2 upload plan: ${changed.length}/${manifest.entries.length} changed objects, ${deleted.length} deleted objects (${manifestDeletedKeys.length} from manifest, ${orphanedKeys.length} orphaned) for ${bucket}`, + `r2 upload plan: ${changed.length}/${manifest.entries.length} changed objects, ${deleted.length} deleted objects (${manifestDeletedKeys.length} from manifest, ${orphanedKeys.length} orphaned, force=${forceUpload}) for ${bucket}`, ); await uploadEntries(changed); await deleteEntries(deleted);