Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 235e6e4

Browse files
committedMar 10, 2020
feat(core): add runtimeCacheInputs to capture node version, os in the cache key
1 parent 9e64253 commit 235e6e4

File tree

4 files changed

+88
-20
lines changed

4 files changed

+88
-20
lines changed
 

‎packages/workspace/src/tasks-runner/hasher.spec.ts

+38-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Hasher } from './hasher';
2+
23
const hasha = require('hasha');
34
const fs = require('fs');
45
jest.mock('hasha');
@@ -30,7 +31,10 @@ describe('Hasher', () => {
3031
proj: []
3132
}
3233
},
33-
{} as any
34+
{} as any,
35+
{
36+
runtimeCacheInputs: ['echo runtime123', 'echo runtime456']
37+
}
3438
);
3539

3640
const hash = await hasher.hash({
@@ -44,10 +48,39 @@ describe('Hasher', () => {
4448
expect(hash).toContain('prop-value'); //overrides
4549
expect(hash).toContain('proj'); //project
4650
expect(hash).toContain('build'); //target
51+
expect(hash).toContain('runtime123'); //target
52+
expect(hash).toContain('runtime456'); //target
4753

4854
done();
4955
});
5056

57+
it('should throw an error when failed to execute runtimeCacheInputs', async () => {
58+
const hasher = new Hasher(
59+
{
60+
nodes: {},
61+
dependencies: {}
62+
},
63+
{} as any,
64+
{
65+
runtimeCacheInputs: ['boom']
66+
}
67+
);
68+
69+
try {
70+
await hasher.hash({
71+
target: { project: 'proj', target: 'build' },
72+
id: 'proj-build',
73+
overrides: {}
74+
});
75+
fail('Should not be here');
76+
} catch (e) {
77+
expect(e.message).toContain(
78+
'Nx failed to execute runtimeCacheInputs defined in nx.json failed:'
79+
);
80+
expect(e.message).toContain('boom: not found');
81+
}
82+
});
83+
5184
it('should hash when circular dependencies', async done => {
5285
hashes['/filea'] = 'a.hash';
5386
hashes['/fileb'] = 'b.hash';
@@ -70,7 +103,8 @@ describe('Hasher', () => {
70103
projb: [{ source: 'projb', target: 'proja', type: 'static' }]
71104
}
72105
},
73-
{} as any
106+
{} as any,
107+
{}
74108
);
75109

76110
const hasha = await hasher.hash({
@@ -119,7 +153,8 @@ describe('Hasher', () => {
119153
},
120154
dependencies: {}
121155
},
122-
{} as any
156+
{} as any,
157+
{}
123158
);
124159

125160
const hash = await hasher.hash({

‎packages/workspace/src/tasks-runner/hasher.ts

+48-16
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,69 @@ import { NxJson } from '../core/shared-interfaces';
33
import { Task } from './tasks-runner';
44
import { statSync } from 'fs';
55
import { rootWorkspaceFileNames } from '../core/file-utils';
6+
import { execSync } from 'child_process';
67

78
const hasha = require('hasha');
89

910
export class Hasher {
1011
static version = '1.0';
1112
implicitDependencies: Promise<string>;
13+
runtimeInputs: Promise<string>;
1214
fileHashes = new FileHashes();
1315
projectHashes = new ProjectHashes(this.projectGraph, this.fileHashes);
1416

1517
constructor(
1618
private readonly projectGraph: ProjectGraph,
17-
private readonly nxJson: NxJson
19+
private readonly nxJson: NxJson,
20+
private readonly options: any
1821
) {}
1922

2023
async hash(task: Task): Promise<string> {
21-
const hash = await this.projectHashes.hashProject(task.target.project, [
22-
task.target.project
24+
const args = [
25+
task.target.project || '',
26+
task.target.target || '',
27+
task.target.configuration || '',
28+
JSON.stringify(task.overrides)
29+
];
30+
31+
const values = await Promise.all([
32+
this.projectHashes.hashProject(task.target.project, [
33+
task.target.project
34+
]),
35+
this.implicitDepsHash(),
36+
this.runtimeInputsHash()
2337
]);
24-
const implicits = await this.implicitDepsHash();
25-
return hasha(
26-
[
27-
Hasher.version,
28-
task.target.project || '',
29-
task.target.target || '',
30-
task.target.configuration || '',
31-
JSON.stringify(task.overrides),
32-
implicits,
33-
hash
34-
],
35-
{ algorithm: 'sha256' }
36-
);
38+
39+
return hasha([Hasher.version, ...args, ...values], { algorithm: 'sha256' });
40+
}
41+
42+
private async runtimeInputsHash() {
43+
if (this.runtimeInputs) return this.runtimeInputs;
44+
45+
const inputs =
46+
this.options && this.options.runtimeCacheInputs
47+
? this.options.runtimeCacheInputs
48+
: [];
49+
if (inputs.length > 0) {
50+
try {
51+
const values = await Promise.all(
52+
inputs.map(async i =>
53+
execSync(i)
54+
.toString()
55+
.trim()
56+
)
57+
);
58+
this.runtimeInputs = hasha(values, { algorithm: 'sha256' });
59+
} catch (e) {
60+
throw new Error(
61+
`Nx failed to execute runtimeCacheInputs defined in nx.json failed:\n${e.message}`
62+
);
63+
}
64+
} else {
65+
this.runtimeInputs = Promise.resolve('');
66+
}
67+
68+
return this.runtimeInputs;
3769
}
3870

3971
private async implicitDepsHash() {

‎packages/workspace/src/tasks-runner/run-command.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export async function runCommand<T extends RunArgs>(
3636
);
3737

3838
if (tasksRunner !== require('./default-tasks-runner').defaultTasksRunner) {
39-
const hasher = new Hasher(projectGraph, nxJson);
39+
const hasher = new Hasher(projectGraph, nxJson, tasksOptions);
4040
await Promise.all(
4141
tasks.map(async t => {
4242
t.hash = await hasher.hash(t);

‎packages/workspace/src/tasks-runner/tasks-runner-v2.ts

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export interface DefaultTasksRunnerOptions {
2929
parallel?: boolean;
3030
maxParallel?: number;
3131
cacheableOperations?: string[];
32+
runtimeCacheInputs?: string[];
3233
cacheDirectory?: string;
3334
remoteCache?: RemoteCache;
3435
lifeCycle?: LifeCycle;

0 commit comments

Comments
 (0)
Please sign in to comment.