Skip to content

Commit 2c84261

Browse files
committed
fix(ci): remove orphaned production asset metadata from dev and pass --non-interactive to blueprints deploy
1 parent 5964e5e commit 2c84261

2 files changed

Lines changed: 62 additions & 18 deletions

File tree

‎.github/workflows/deploy.yml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ jobs:
7373
echo "Resolved Organization ID: $ORG_ID"
7474
mkdir -p .sanity
7575
echo "{\"organizationId\":\"$ORG_ID\"}" > .sanity/blueprint.config.json
76-
pnpm exec sanity blueprints deploy --organization-id "$ORG_ID" --stack ${{ vars.SANITY_STUDIO_DATASET }}
76+
pnpm exec sanity blueprints deploy --organization-id "$ORG_ID" --stack ${{ vars.SANITY_STUDIO_DATASET }} --non-interactive
7777
env:
7878
SANITY_AUTH_TOKEN: ${{ secrets.SANITY_AUTH_TOKEN }}
7979
SANITY_API_WRITE_TOKEN: ${{ secrets.SANITY_API_WRITE_TOKEN }}
@@ -147,7 +147,7 @@ jobs:
147147
echo "Resolved Organization ID: $ORG_ID"
148148
mkdir -p .sanity
149149
echo "{\"organizationId\":\"$ORG_ID\"}" > .sanity/blueprint.config.json
150-
pnpm exec sanity blueprints deploy --organization-id "$ORG_ID" --stack ${{ vars.SANITY_STUDIO_DATASET }}
150+
pnpm exec sanity blueprints deploy --organization-id "$ORG_ID" --stack ${{ vars.SANITY_STUDIO_DATASET }} --non-interactive
151151
env:
152152
SANITY_AUTH_TOKEN: ${{ secrets.SANITY_AUTH_TOKEN }}
153153
SANITY_API_WRITE_TOKEN: ${{ secrets.SANITY_API_WRITE_TOKEN }}

‎.github/workflows/nightly-dataset-sync.yml‎

Lines changed: 60 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,37 @@ jobs:
5959
const lines = fs.readFileSync("/tmp/production.ndjson", "utf8").trim().split("\n").filter(Boolean);
6060
const allDocs = lines.map((l) => JSON.parse(l));
6161
62+
const activeTypes = new Set([
63+
"post",
64+
"podcast",
65+
"guest",
66+
"author",
67+
"sponsor",
68+
"page",
69+
"settings",
70+
"podcastType",
71+
"syndication",
72+
"transcript",
73+
]);
6274
const assetDocs = allDocs.filter((d) => d._type === "sanity.imageAsset" || d._type === "sanity.fileAsset");
6375
const imageAssetMap = new Map(
6476
allDocs.filter((d) => d._type === "sanity.imageAsset").map((d) => [d._id, d])
6577
);
66-
const contentDocs = allDocs.filter((d) => d._type !== "sanity.imageAsset" && d._type !== "sanity.fileAsset");
78+
const rawContentDocs = allDocs.filter((d) => activeTypes.has(d._type));
79+
const activeDocIds = new Set(rawContentDocs.filter((d) => d._type !== "transcript").map((d) => d._id));
80+
const contentDocs = rawContentDocs.filter((d) => {
81+
if (d._type !== "transcript") return true;
82+
// Exclude transcripts that only reference legacy/deleted document types (lesson/short)
83+
for (const v of Object.values(d)) {
84+
if (v && typeof v === "object" && typeof v._ref === "string" && !activeDocIds.has(v._ref)) {
85+
return false;
86+
}
87+
}
88+
return true;
89+
});
6790
6891
// Collect all known IDs (including assets and syndication.* targets) so valid strong references are never weakened
69-
const allTargetIds = new Set(allDocs.map((d) => d._id));
92+
const allTargetIds = new Set(contentDocs.map((d) => d._id));
7093
const syndicationStubs = new Map();
7194
7295
for (const doc of contentDocs) {
@@ -260,7 +283,6 @@ jobs:
260283
}
261284
console.log(`Found ${devUploadedIds.size} image binaries in 'dev' CDN bucket (${prodToDevAssetMap.size} mapped IDs).`);
262285
263-
const activeTypes = new Set(["post", "podcast", "guest", "author", "sponsor", "page", "settings", "podcastType"]);
264286
const priorityRefs = new Set();
265287
const inlineRefs = new Set();
266288
@@ -274,7 +296,6 @@ jobs:
274296
}
275297
276298
for (const doc of contentDocs) {
277-
if (!activeTypes.has(doc._type)) continue;
278299
if (doc.coverImage?.asset?._ref) priorityRefs.add(doc.coverImage.asset._ref);
279300
if (doc.photo?.asset?._ref) priorityRefs.add(doc.photo.asset._ref);
280301
if (doc.ogImage?.asset?._ref) priorityRefs.add(doc.ogImage.asset._ref);
@@ -363,6 +384,34 @@ jobs:
363384
return devUploadedIds;
364385
}
365386
387+
async function cleanupOrphanedDevDocs() {
388+
const expRes = await fetch(`https://${projectId}.api.sanity.io/v2021-06-07/data/export/dev`, {
389+
headers: { Authorization: `Bearer ${activeToken || tokens[0]}` },
390+
});
391+
if (!expRes.ok) return;
392+
const text = await expRes.text();
393+
const devDocs = text.trim().split("\n").filter(Boolean).map((l) => JSON.parse(l));
394+
const deleteMutations = [];
395+
396+
for (const d of devDocs) {
397+
if (d._type.startsWith("system.")) continue;
398+
if (d._type === "sanity.imageAsset" || d._type === "sanity.fileAsset") {
399+
if (typeof d.path === "string" && d.path.includes("/production/")) {
400+
deleteMutations.push({ delete: { id: d._id } });
401+
}
402+
continue;
403+
}
404+
if (!activeTypes.has(d._type) || (d._type === "transcript" && !allTargetIds.has(d._id))) {
405+
deleteMutations.push({ delete: { id: d._id } });
406+
}
407+
}
408+
409+
if (deleteMutations.length > 0) {
410+
console.log(`Cleaning up ${deleteMutations.length} legacy/orphaned documents in 'dev'...`);
411+
await sendChunked(deleteMutations, "Cleanup Legacy & Orphaned Docs", "raw");
412+
}
413+
}
414+
366415
(async () => {
367416
if (prodDeduplicateMutations.length > 0) {
368417
console.log(`Cleaning up ${prodDeduplicateMutations.length} duplicate syndications arrays in production...`);
@@ -375,30 +424,25 @@ jobs:
375424
}
376425
377426
// 1. Upload/map missing active image binaries to dev (populates prodToDevAssetMap & allTargetIds)
378-
const devUploadedIds = await uploadMissingDevImages();
427+
await uploadMissingDevImages();
379428
380429
// 2. Now sanitize content documents so all active image _refs are rewritten to their real dev binary asset IDs
381430
const sanitized = contentDocs.map(sanitizeDoc);
382431
console.log(`Prepared ${sanitized.length} content documents and ${syndicationStubs.size} syndication stubs for dataset "dev"...`);
383432
384-
// 3. Import remaining asset metadata docs (for unreferenced/legacy assets) so all asset refs resolve
385-
const remainingAssetDocs = assetDocs
386-
.filter((d) => !devUploadedIds.has(d._id))
387-
.map(({ _rev, ...rest }) => rest);
388-
if (remainingAssetDocs.length > 0) {
389-
await sendChunked(remainingAssetDocs, "Pass 1a: Remaining Asset Metadata", "createIfNotExists");
390-
}
391-
392-
// 4. Create content + syndication stubs so all internal document references resolve as strong references
433+
// 3. Create content + syndication stubs so all internal document references resolve as strong references
393434
const stubs = [
394435
...sanitized.map((d) => ({ _id: d._id, _type: d._type })),
395436
...Array.from(syndicationStubs.values()),
396437
];
397-
await sendChunked(stubs, "Pass 1b: Document & Syndication Stubs", "createIfNotExists");
438+
await sendChunked(stubs, "Pass 1: Document & Syndication Stubs", "createIfNotExists");
398439
399-
// 5. Populate full content documents (with strong coverImage.asset & syndications references and unique _keys)
440+
// 4. Populate full content documents (with strong coverImage.asset & syndications references and unique _keys)
400441
await sendChunked(sanitized, "Pass 2: Content Docs", "createOrReplace");
401442
443+
// 5. Remove any legacy document types and orphaned production-path asset metadata from dev
444+
await cleanupOrphanedDevDocs();
445+
402446
console.log("Dataset sync completed successfully!");
403447
})().catch((err) => {
404448
console.error(err);

0 commit comments

Comments
 (0)