chore(platform): document script CLI output
What changed: - Added explicit no-console policy for platform-service CLI/codegen scripts. - Replaced the remaining migrate-referrals catch any with unknown narrowing. - Added a TODO for making migrate-referrals --help independent of service env loading. Warning impact: - Platform script lint warnings: 78 -> 0. - Workspace lint: 90 -> 12 warnings. Verification: - pnpm --filter @lysnrai/platform-service build - pnpm --filter @lysnrai/platform-service exec eslint scripts --ext .ts - pnpm lint Note: - migrate-referrals --help still requires service env due eager config import; TODO added for a follow-up behavior-safe refactor.
This commit is contained in:
parent
80b9587adb
commit
2c9dc1870d
@ -16,6 +16,8 @@
|
|||||||
* @module platform-service/scripts/gen-module
|
* @module platform-service/scripts/gen-module
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* eslint-disable no-console -- This generator is a CLI; console output is its user interface. */
|
||||||
|
|
||||||
import { promises as fs } from 'node:fs';
|
import { promises as fs } from 'node:fs';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|||||||
@ -18,10 +18,15 @@
|
|||||||
* npx tsx scripts/migrate-referrals.ts --mode new-only
|
* npx tsx scripts/migrate-referrals.ts --mode new-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* eslint-disable no-console -- This migration script is a CLI; console output is its progress and summary UI. */
|
||||||
|
|
||||||
import { CosmosClient, type Container } from '@azure/cosmos';
|
import { CosmosClient, type Container } from '@azure/cosmos';
|
||||||
import { config } from '../src/lib/config.js';
|
import { config } from '../src/lib/config.js';
|
||||||
import type { ReferralDoc } from '../src/modules/referrals/types.js';
|
import type { ReferralDoc } from '../src/modules/referrals/types.js';
|
||||||
|
|
||||||
|
// TODO(migration-cli): Defer service config loading so `--help` can run without
|
||||||
|
// requiring COSMOS_ENDPOINT, COSMOS_KEY, and JWT_SECRET in the environment.
|
||||||
|
|
||||||
interface MigrationOptions {
|
interface MigrationOptions {
|
||||||
productId?: string;
|
productId?: string;
|
||||||
batchSize: number;
|
batchSize: number;
|
||||||
@ -30,6 +35,16 @@ interface MigrationOptions {
|
|||||||
dryRun: boolean;
|
dryRun: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getErrorCode(error: unknown): number | undefined {
|
||||||
|
return typeof error === 'object' && error !== null && 'code' in error
|
||||||
|
? Number((error as { code: unknown }).code)
|
||||||
|
: undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getErrorMessage(error: unknown): string {
|
||||||
|
return error instanceof Error ? error.message : String(error);
|
||||||
|
}
|
||||||
|
|
||||||
function parseArgs(): MigrationOptions {
|
function parseArgs(): MigrationOptions {
|
||||||
const args = process.argv.slice(2);
|
const args = process.argv.slice(2);
|
||||||
const options: MigrationOptions = {
|
const options: MigrationOptions = {
|
||||||
@ -150,11 +165,11 @@ async function backfillProduct(
|
|||||||
})
|
})
|
||||||
.fetchAll();
|
.fetchAll();
|
||||||
|
|
||||||
const existingIds = new Set(existingDocs.map((d) => d.id));
|
const existingIds = new Set(existingDocs.map(d => d.id));
|
||||||
console.log(`[${productId}] ${existingIds.size} documents already in new container`);
|
console.log(`[${productId}] ${existingIds.size} documents already in new container`);
|
||||||
|
|
||||||
// Filter docs needing migration
|
// Filter docs needing migration
|
||||||
const toMigrate = oldDocs.filter((d) => !existingIds.has(d.id));
|
const toMigrate = oldDocs.filter(d => !existingIds.has(d.id));
|
||||||
console.log(`[${productId}] ${toMigrate.length} documents need migration`);
|
console.log(`[${productId}] ${toMigrate.length} documents need migration`);
|
||||||
|
|
||||||
if (toMigrate.length === 0) {
|
if (toMigrate.length === 0) {
|
||||||
@ -172,7 +187,7 @@ async function backfillProduct(
|
|||||||
);
|
);
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
batch.map(async (doc) => {
|
batch.map(async doc => {
|
||||||
try {
|
try {
|
||||||
if (!doc.referrerId) {
|
if (!doc.referrerId) {
|
||||||
result.errors.push(`Doc ${doc.id}: missing referrerId (required for new PK)`);
|
result.errors.push(`Doc ${doc.id}: missing referrerId (required for new PK)`);
|
||||||
@ -181,11 +196,11 @@ async function backfillProduct(
|
|||||||
|
|
||||||
await newContainer.items.create(doc);
|
await newContainer.items.create(doc);
|
||||||
result.migrated++;
|
result.migrated++;
|
||||||
} catch (err: any) {
|
} catch (err: unknown) {
|
||||||
if (err.code === 409) {
|
if (getErrorCode(err) === 409) {
|
||||||
result.skipped++;
|
result.skipped++;
|
||||||
} else {
|
} else {
|
||||||
result.errors.push(`Doc ${doc.id}: ${err.message}`);
|
result.errors.push(`Doc ${doc.id}: ${getErrorMessage(err)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -217,8 +232,8 @@ async function verifyConsistency(
|
|||||||
.fetchAll(),
|
.fetchAll(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const oldMap = new Map(oldDocs.map((d) => [d.id, d]));
|
const oldMap = new Map(oldDocs.map(d => [d.id, d]));
|
||||||
const newMap = new Map(newDocs.map((d) => [d.id, d]));
|
const newMap = new Map(newDocs.map(d => [d.id, d]));
|
||||||
|
|
||||||
// Check docs in both containers for consistency
|
// Check docs in both containers for consistency
|
||||||
for (const [id, newDoc] of newMap) {
|
for (const [id, newDoc] of newMap) {
|
||||||
@ -298,7 +313,7 @@ async function main(): Promise<void> {
|
|||||||
console.log(` Skipped: ${result.skipped}`);
|
console.log(` Skipped: ${result.skipped}`);
|
||||||
if (result.errors.length > 0) {
|
if (result.errors.length > 0) {
|
||||||
console.log(` Errors: ${result.errors.length}`);
|
console.log(` Errors: ${result.errors.length}`);
|
||||||
result.errors.slice(0, 5).forEach((e) => console.log(` - ${e}`));
|
result.errors.slice(0, 5).forEach(e => console.log(` - ${e}`));
|
||||||
if (result.errors.length > 5) {
|
if (result.errors.length > 5) {
|
||||||
console.log(` ... and ${result.errors.length - 5} more`);
|
console.log(` ... and ${result.errors.length - 5} more`);
|
||||||
}
|
}
|
||||||
@ -313,14 +328,16 @@ async function main(): Promise<void> {
|
|||||||
console.log(`\n Verifying consistency...`);
|
console.log(`\n Verifying consistency...`);
|
||||||
const verifyResult = await verifyConsistency(oldContainer, newContainer, productId);
|
const verifyResult = await verifyConsistency(oldContainer, newContainer, productId);
|
||||||
const realInconsistencies = verifyResult.inconsistencies.filter(
|
const realInconsistencies = verifyResult.inconsistencies.filter(
|
||||||
(i) => !i.issue.includes('pending backfill')
|
i => !i.issue.includes('pending backfill')
|
||||||
);
|
);
|
||||||
|
|
||||||
if (realInconsistencies.length === 0) {
|
if (realInconsistencies.length === 0) {
|
||||||
console.log(` Consistency check passed (pending: ${verifyResult.inconsistencies.filter(i => i.issue.includes('pending backfill')).length})`);
|
console.log(
|
||||||
|
` Consistency check passed (pending: ${verifyResult.inconsistencies.filter(i => i.issue.includes('pending backfill')).length})`
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
console.log(` WARNING: ${realInconsistencies.length} inconsistencies found:`);
|
console.log(` WARNING: ${realInconsistencies.length} inconsistencies found:`);
|
||||||
realInconsistencies.slice(0, 5).forEach((i) => console.log(` - ${i.id}: ${i.issue}`));
|
realInconsistencies.slice(0, 5).forEach(i => console.log(` - ${i.id}: ${i.issue}`));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -345,7 +362,7 @@ async function main(): Promise<void> {
|
|||||||
console.log('3. Monitor for issues, then delete old container when confident');
|
console.log('3. Monitor for issues, then delete old container when confident');
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch((err) => {
|
main().catch(err => {
|
||||||
console.error('Migration failed:', err);
|
console.error('Migration failed:', err);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user