diff --git a/src/commander/uploadPdf.ts b/src/commander/uploadPdf.ts index ec56a92..1ec464f 100644 --- a/src/commander/uploadPdf.ts +++ b/src/commander/uploadPdf.ts @@ -14,13 +14,10 @@ command .name('upload-pdf') .description('Upload PDFs for visual comparison') .argument('', 'Path of the directory containing PDFs') - .option('-c --config ', 'Config file path; the same file used by exec, thresholds read from the top level or a pdf block') .option('--fetch-results [filename]', 'Fetch results and optionally specify an output file, e.g., .json') .option('--buildName ', 'Specify the build name') .option('--markBaseline', 'Mark this build baseline') .option('--pdfNames ', 'Specify PDF names for the upload') - .option('--approvalThreshold ', 'Mismatch % at or below which every PDF in this upload is auto-approved (0-100); per-PDF overrides go in the config file under pdf.thresholds') - .option('--rejectionThreshold ', 'Mismatch % at or above which every PDF in this upload is auto-rejected (0-100); per-PDF overrides go in the config file under pdf.thresholds') .option('--sync', 'Wait for the uploaded PDFs to be compared and return the results') .action(async function(directory, _, command) { const options = command.optsWithGlobals(); diff --git a/src/lib/ctx.ts b/src/lib/ctx.ts index 9e7aa5e..1b176e6 100644 --- a/src/lib/ctx.ts +++ b/src/lib/ctx.ts @@ -34,11 +34,6 @@ export default (options: Record): Context => { try { if (options.config) { config = JSON.parse(fs.readFileSync(options.config, 'utf-8')); - // the schema now also accepts a pdf-only file, so keep every other command on the rule - // it had before: no web or mobile block means nothing to run - if (options.commandType !== constants.COMMAND_TYPE_UPLOAD_PDF && !config.web && !config.mobile) { - throw new Error('Invalid config; must have either web or mobile config'); - } // TODO: Mask sensitive data of config file // logger.debug(`Config file ${options.config} loaded: ${JSON.stringify(config, null, 2)}`); @@ -293,13 +288,6 @@ export default (options: Record): Context => { userName: options.userName || '', accessKey: options.accessKey || '', pdfNames: options.pdfNames || '', - // flag > pdf block > project. The top-level approvalThreshold/rejectionThreshold are the - // web values and are never read for pdf. Kept as strings so an explicit 0 is sent rather - // than dropped; the backend does the range/band validation - approvalThreshold: firstThreshold(options.approvalThreshold, (config as any).pdf?.approvalThreshold), - rejectionThreshold: firstThreshold(options.rejectionThreshold, (config as any).pdf?.rejectionThreshold), - // per-pdf overrides come only from the config file; there is no flag for them - pdfThresholds: (config as any).pdf?.thresholds ?? {}, sync: options.sync ? true : false }, cliVersion: version, @@ -325,11 +313,4 @@ export default (options: Record): Context => { logFileUUID: logFileUUID, logFilePath: logFilePath } -} -// first source that actually set a value; a numeric 0 from config is a value, an empty flag is not -function firstThreshold(...sources: any[]): string { - for (const s of sources) { - if (s !== undefined && s !== null && s !== '') return String(s); - } - return ''; -} +} \ No newline at end of file diff --git a/src/lib/httpClient.ts b/src/lib/httpClient.ts index 5c68996..bd740dd 100644 --- a/src/lib/httpClient.ts +++ b/src/lib/httpClient.ts @@ -813,7 +813,7 @@ export default class httpClient { } } - async uploadPdf(ctx: Context, form: FormData, buildName?: string, pdfNames?: string, snapshotUuids?: string, thresholds?: Record): Promise { + async uploadPdf(ctx: Context, form: FormData, buildName?: string, pdfNames?: string, snapshotUuids?: string): Promise { form.append('projectToken', this.projectToken); if (ctx.build.name !== undefined && ctx.build.name !== '') { form.append('buildName', buildName); @@ -831,10 +831,6 @@ export default class httpClient { if (snapshotUuids && snapshotUuids !== '') { form.append('snapshotUuids', snapshotUuids); } - // already resolved per pdf by the task; only the final map goes over, never the raw flags - if (thresholds && Object.keys(thresholds).length > 0) { - form.append('thresholds', JSON.stringify(thresholds)); - } if (ctx.git?.branch) form.append('branch', ctx.git.branch); if (ctx.git?.commitId) form.append('commitId', ctx.git.commitId); diff --git a/src/lib/pdfThresholds.ts b/src/lib/pdfThresholds.ts deleted file mode 100644 index 84e6f69..0000000 --- a/src/lib/pdfThresholds.ts +++ /dev/null @@ -1,36 +0,0 @@ -export type PdfThreshold = { approval?: number; rejection?: number }; -export type PdfThresholdMap = Record; - -// mirrors the web path: the CLI resolves per item and the backend receives one final value each -export function resolvePdfThresholds( - documentNames: string[], - perFile: PdfThresholdMap, - buildApproval: string, - buildRejection: string -): PdfThresholdMap { - const unknown = Object.keys(perFile).filter(name => !documentNames.includes(name)); - if (unknown.length) { - throw new Error(`pdf.thresholds in the config file names PDFs that are not in this upload: ${unknown.sort().join(', ')}. Keys must match the uploaded file names (or --pdfNames) exactly.`); - } - const buildA = toNumber(buildApproval, 'approvalThreshold'); - const buildR = toNumber(buildRejection, 'rejectionThreshold'); - const resolved: PdfThresholdMap = {}; - for (const name of documentNames) { - const approval = perFile[name]?.approval ?? buildA; - const rejection = perFile[name]?.rejection ?? buildR; - if (approval === undefined && rejection === undefined) continue; - resolved[name] = {}; - if (approval !== undefined) resolved[name].approval = approval; - if (rejection !== undefined) resolved[name].rejection = rejection; - } - return resolved; -} - -function toNumber(s: string, field: string): number | undefined { - if (s === undefined || s === null || s === '') return undefined; - const n = Number(s); - if (!Number.isFinite(n)) { - throw new Error(`${field} must be a number between 0 and 100, got "${s}"`); - } - return n; -} diff --git a/src/lib/schemaValidation.ts b/src/lib/schemaValidation.ts index ed76a97..76951d6 100644 --- a/src/lib/schemaValidation.ts +++ b/src/lib/schemaValidation.ts @@ -389,54 +389,11 @@ const ConfigSchema = { showRenderErrors: { type: "boolean", errorMessage: "Invalid config; showRenderErrors must be true/false" - }, - pdf: { - type: "object", - properties: { - approvalThreshold: { - type: "number", - minimum: 0, - maximum: 100, - errorMessage: "Invalid config; pdf.approvalThreshold must be a number between 0 and 100" - }, - rejectionThreshold: { - type: "number", - minimum: 0, - maximum: 100, - errorMessage: "Invalid config; pdf.rejectionThreshold must be a number between 0 and 100" - }, - thresholds: { - type: "object", - additionalProperties: { - type: "object", - properties: { - approval: { - type: "number", - minimum: 0, - maximum: 100, - errorMessage: "Invalid config; pdf.thresholds..approval must be a number between 0 and 100" - }, - rejection: { - type: "number", - minimum: 0, - maximum: 100, - errorMessage: "Invalid config; pdf.thresholds..rejection must be a number between 0 and 100" - } - }, - additionalProperties: false, - errorMessage: "Invalid config; each pdf.thresholds entry may only have approval and rejection" - }, - errorMessage: "Invalid config; pdf.thresholds must be an object keyed by PDF name" - } - }, - additionalProperties: false, - errorMessage: "Invalid config; pdf may only contain approvalThreshold, rejectionThreshold and thresholds" } }, anyOf: [ { required: ["web"] }, - { required: ["mobile"] }, - { required: ["pdf"] } + { required: ["mobile"] } ], additionalProperties: false } diff --git a/src/tasks/uploadPdfs.ts b/src/tasks/uploadPdfs.ts index 60ab01a..072c6ed 100644 --- a/src/tasks/uploadPdfs.ts +++ b/src/tasks/uploadPdfs.ts @@ -6,7 +6,6 @@ import path from 'path'; import fs from 'fs'; import FormData from 'form-data'; import { randomUUID } from 'node:crypto'; -import { resolvePdfThresholds } from '../lib/pdfThresholds.js'; export default (ctx: Context): ListrTask => { return { @@ -56,15 +55,6 @@ async function uploadPdfs(ctx: Context, pdfPath: string): Promise { const providedNames = pdfNames ? pdfNames.split(',').map(name => name.trim()) : []; const documentNames = uploadedFileNames.map((fileName, index) => providedNames[index] ?? fileName); - // resolved per pdf here, as the web path does per snapshot, so the backend gets one final - // value per file: config pdf.thresholds entry, else the build-level value (flag > pdf block > top-level) - const thresholds = resolvePdfThresholds( - documentNames, - ctx.options.pdfThresholds ?? {}, - ctx.options.approvalThreshold, - ctx.options.rejectionThreshold - ); - let snapshotUuids = ''; if (ctx.options.sync) { const syncTargets = documentNames.map(name => ({ name, uuid: randomUUID() as string })); @@ -77,7 +67,7 @@ async function uploadPdfs(ctx: Context, pdfPath: string): Promise { } try { - const response = await ctx.client.uploadPdf(ctx, formData, buildName, pdfNames, snapshotUuids, thresholds); + const response = await ctx.client.uploadPdf(ctx, formData, buildName, pdfNames, snapshotUuids); if (response && response.buildId) { ctx.build.id = response.buildId; ctx.log.debug(`PDF upload successful. Build ID: ${ctx.build.id}`); diff --git a/src/types.ts b/src/types.ts index 6171436..364f07f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -88,9 +88,6 @@ export interface Context { gitURL?: string, showRenderErrors?: boolean, pdfNames?: string, - approvalThreshold?: string, - rejectionThreshold?: string, - pdfThresholds?: Record, sync?: boolean, userName?: string, accessKey?: string