← back to Rebel Walls Push

scripts/rollback-TK11248.js

58 lines

'use strict';
/* Rollback for the TK-11248 batch. Reverses whichever step was applied.
 *   --step=11238  restores Aries title from TK-11238-restore.json
 *   --step=10405  recreates the 12 deleted Default-Title variants from TK-10405-restore-map.json
 *                 (Shopify assigns NEW variant ids; SKU/price/options restored)
 * DRY-RUN by default; --apply to fire. Rollback is the undo of a recorded write,
 * so it only needs --apply (no sentinel) — but it prints exactly what it will do first.
 *
 * Usage:
 *   node rollback-TK11248.js --step=11238            # dry-run
 *   node rollback-TK11248.js --step=11238 --apply    # restore title
 *   node rollback-TK11248.js --step=10405 --apply    # recreate 12 variants
 */
const fs = require('fs');
const path = require('path');
const { gqlRetry, sleep } = require('./_shop');
const DATA = path.join(__dirname, '..', 'data');
const argv = process.argv.slice(2);
const APPLY = argv.includes('--apply');
const STEP = (argv.find(x => x.startsWith('--step=')) || '').split('=')[1];

const PRODUCT_UPDATE = `mutation($input: ProductInput!){ productUpdate(input:$input){ product{ id title } userErrors{ field message } } }`;
const VARIANTS_CREATE = `mutation($productId: ID!, $variants:[ProductVariantsBulkInput!]!){
  productVariantsBulkCreate(productId:$productId, variants:$variants){
    productVariants{ id title sku price } userErrors{ field message } } }`;

async function rb11238() {
  const r = JSON.parse(fs.readFileSync(path.join(DATA, 'TK-11238-restore.json'), 'utf8'));
  console.log(`ROLLBACK TK-11238: product ${r.product_id} title -> "${r.restore_title}"`);
  if (!APPLY) { console.log('[dry-run]'); return; }
  const w = await gqlRetry(PRODUCT_UPDATE, { input: { id: r.product_gid, title: r.restore_title } }, 'rb-title');
  const ue = w.json.data.productUpdate.userErrors;
  console.log(ue && ue.length ? `userErrors ${JSON.stringify(ue)}` : `restored: "${w.json.data.productUpdate.product.title}"`);
}
async function rb10405() {
  const m = JSON.parse(fs.readFileSync(path.join(DATA, 'TK-10405-restore-map.json'), 'utf8'));
  console.log(`ROLLBACK TK-10405: recreate ${m.variants.length} Default-Title variants`);
  for (const v of m.variants) {
    // optionValues must map to the product's option; Default Title = single default option value.
    const optionValues = (v.options && v.options.length)
      ? v.options.map(o => ({ optionName: o.name, name: o.value })) : [{ optionName: 'Title', name: 'Default Title' }];
    console.log(`  ${v.pid} recreate ${v.sku}@$${v.price}`);
    if (!APPLY) { console.log('   [dry-run]'); continue; }
    const w = await gqlRetry(VARIANTS_CREATE, { productId: v.product_gid,
      variants: [{ price: v.price, inventoryItem: { sku: v.sku }, optionValues }] }, `rb-create:${v.pid}`);
    const ue = w.json.data.productVariantsBulkCreate.userErrors;
    console.log(ue && ue.length ? `   userErrors ${JSON.stringify(ue)}` : `   recreated ${w.json.data.productVariantsBulkCreate.productVariants.map(x=>x.id).join(',')}`);
    await sleep(400);
  }
}
(async () => {
  console.log(`### rollback-TK11248 STEP=${STEP} APPLY=${APPLY}`);
  if (STEP === '11238') await rb11238();
  else if (STEP === '10405') await rb10405();
  else { console.error('specify --step=11238 or --step=10405'); process.exit(1); }
  console.log(APPLY ? 'rollback complete.' : 'dry-run complete, no writes.');
})().catch(e => { console.error('FATAL', e); process.exit(2); });