Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/fingerprint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,13 @@ export class Fingerprint {
// because we can't know if there was an undeclared input that this script
// depends on.
allDependenciesAreFullyTracked &&
// A no-op script. Can't produce output, so always trackable.
// A no-command script. Doesn't ever do anything itsef, so always fully
// tracked.
(script.command === undefined ||
// A one-shot script. Trackable if we know both its inputs and outputs.
// A service. Fully tracked if we know its inputs. Can't produce output.
(script.service && script.files !== undefined) ||
// A standard script. Fully tracked if we know both its inputs and
// outputs.
(script.files !== undefined && script.output !== undefined));

const fingerprint = new Fingerprint();
Expand Down
75 changes: 75 additions & 0 deletions src/test/service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -734,4 +734,79 @@ test(
})
);

test(
'service fingerprint is trackable despite never having outputs',
timeout(async ({rig}) => {
// consumer
// |
// v
// service

const consumer = await rig.newCommand();
const service = await rig.newCommand();
await rig.writeAtomic({
'package.json': {
scripts: {
consumer: 'wireit',
service: 'wireit',
},
wireit: {
consumer: {
command: consumer.command,
dependencies: ['service'],
files: [],
output: [],
},
service: {
command: service.command,
service: true,
files: ['input'],
},
},
},
});

// Run 1. Nothing cached yet.
{
await rig.write('input', '0');
const wireit = rig.exec('npm run consumer');
const serviceInv = await service.nextInvocation();
const consumerInv = await consumer.nextInvocation();
consumerInv.exit(0);
await serviceInv.closed;
await consumerInv.closed;
const {code} = await wireit.exit;
assert.equal(code, 0);
assert.equal(consumer.numInvocations, 1);
assert.equal(service.numInvocations, 1);
}

// Run 2. No input change. Consumer output is cached, service never needs to
// start.
{
const wireit = rig.exec('npm run consumer');
const {code} = await wireit.exit;
assert.equal(code, 0);
assert.equal(consumer.numInvocations, 1);
assert.equal(service.numInvocations, 1);
}

// Run 3. Service input changed. That affects the service fingerprint and
// transitively affects the consumer fingerprint, so both need to run.
{
await rig.write('input', '1');
const wireit = rig.exec('npm run consumer');
const serviceInv = await service.nextInvocation();
const consumerInv = await consumer.nextInvocation();
consumerInv.exit(0);
await serviceInv.closed;
await consumerInv.closed;
const {code} = await wireit.exit;
assert.equal(code, 0);
assert.equal(consumer.numInvocations, 2);
assert.equal(service.numInvocations, 2);
}
})
);

test.run();