Skip to content

Commit db449ee

Browse files
committed
fix(node): honor describe labels and stale bundles
1 parent e0bcac6 commit db449ee

4 files changed

Lines changed: 81 additions & 5 deletions

File tree

packages/node/src/cli/commands/assemblies.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -671,12 +671,14 @@ async function shouldSkipStaleOutput({
671671
outputPlanMtime,
672672
outputRootIsDirectory,
673673
reprocessStale,
674+
singleInputReference = 'output-plan',
674675
}: {
675676
inputPaths: string[]
676677
outputPath: string | null
677678
outputPlanMtime: Date
678679
outputRootIsDirectory: boolean
679680
reprocessStale?: boolean
681+
singleInputReference?: 'input' | 'output-plan'
680682
}): Promise<boolean> {
681683
if (reprocessStale || outputPath == null || outputRootIsDirectory) {
682684
return false
@@ -692,7 +694,16 @@ async function shouldSkipStaleOutput({
692694
}
693695

694696
if (inputPaths.length === 1) {
695-
return isMeaningfullyNewer(outputStat.mtime, outputPlanMtime)
697+
if (singleInputReference === 'output-plan') {
698+
return isMeaningfullyNewer(outputStat.mtime, outputPlanMtime)
699+
}
700+
701+
const [inputErr, inputStat] = await tryCatch(fsp.stat(inputPaths[0]))
702+
if (inputErr != null || inputStat == null) {
703+
return false
704+
}
705+
706+
return isMeaningfullyNewer(outputStat.mtime, inputStat.mtime)
696707
}
697708

698709
const inputStats = await Promise.all(
@@ -1442,6 +1453,7 @@ export async function create(
14421453
outputPlanMtime: new Date(0),
14431454
outputRootIsDirectory,
14441455
reprocessStale,
1456+
singleInputReference: 'input',
14451457
})
14461458
) {
14471459
outputctl.debug(`SKIPPED STALE SINGLE ASSEMBLY ${resolvedOutput ?? 'null'}`)

packages/node/src/cli/semanticIntents/imageDescribe.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,7 @@ function resolveRequestedDescribeFields({
118118
explicitFields: ImageDescribeField[]
119119
profile: 'wordpress' | null
120120
}): ImageDescribeField[] {
121-
if (
122-
explicitFields.length > 0 &&
123-
!(explicitFields.length === 1 && explicitFields[0] === 'labels')
124-
) {
121+
if (explicitFields.length > 0) {
125122
return explicitFields
126123
}
127124

packages/node/test/unit/cli/assemblies-create.test.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,55 @@ describe('assemblies create', () => {
456456
expect(await readFile(outputPath, 'utf8')).toBe('existing-bundle')
457457
})
458458

459+
it('reruns single-input bundled assemblies when the input is newer than the output', async () => {
460+
vi.spyOn(console, 'error').mockImplementation(() => {})
461+
462+
const tempDir = await createTempDir('transloadit-bundle-single-input-stale-')
463+
const inputPath = path.join(tempDir, 'a.txt')
464+
const outputPath = path.join(tempDir, 'bundle.zip')
465+
466+
await writeFile(inputPath, 'a')
467+
await writeFile(outputPath, 'existing-bundle')
468+
469+
const outputTime = new Date('2026-01-01T00:00:10.000Z')
470+
const inputTime = new Date('2026-01-01T00:00:20.000Z')
471+
472+
await utimes(inputPath, inputTime, inputTime)
473+
await utimes(outputPath, outputTime, outputTime)
474+
475+
const output = new OutputCtl()
476+
const client = {
477+
createAssembly: vi.fn().mockResolvedValue({ assembly_id: 'assembly-single-input-stale' }),
478+
awaitAssemblyCompletion: vi.fn().mockResolvedValue({
479+
ok: 'ASSEMBLY_COMPLETED',
480+
results: {
481+
compressed: [{ url: 'http://downloads.test/bundle-single.zip', name: 'bundle.zip' }],
482+
},
483+
}),
484+
}
485+
486+
nock('http://downloads.test').get('/bundle-single.zip').reply(200, 'fresh-bundle')
487+
488+
await create(output, client as never, {
489+
inputs: [inputPath],
490+
output: outputPath,
491+
singleAssembly: true,
492+
stepsData: {
493+
compressed: {
494+
robot: '/file/compress',
495+
result: true,
496+
use: {
497+
steps: [':original'],
498+
bundle_steps: true,
499+
},
500+
},
501+
},
502+
})
503+
504+
expect(client.createAssembly).toHaveBeenCalledTimes(1)
505+
expect(await readFile(outputPath, 'utf8')).toBe('fresh-bundle')
506+
})
507+
459508
it('rewrites existing bundled outputs on single-assembly reruns', async () => {
460509
vi.spyOn(console, 'error').mockImplementation(() => {})
461510

packages/node/test/unit/cli/intents.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,24 @@ describe('intent commands', () => {
273273
expect(createSpy).not.toHaveBeenCalled()
274274
})
275275

276+
it('rejects combining --fields labels with --for wordpress', async () => {
277+
const { createSpy } = await runIntentCommand([
278+
'image',
279+
'describe',
280+
'--input',
281+
'hero.jpg',
282+
'--fields',
283+
'labels',
284+
'--for',
285+
'wordpress',
286+
'--out',
287+
'fields.json',
288+
])
289+
290+
expect(process.exitCode).toBe(1)
291+
expect(createSpy).not.toHaveBeenCalled()
292+
})
293+
276294
it('maps image generate flags to /image/generate step parameters', async () => {
277295
const { createSpy } = await runIntentCommand([
278296
'image',

0 commit comments

Comments
 (0)