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
1 change: 1 addition & 0 deletions docs/angular/guides/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,7 @@ Tasks runners can accept different options. The following are the options suppor
- `cacheDirectory` defines where the local cache is stored, which is `node_modules/.cache/nx` by default.
- `encryptionKey` (when using `"@nrwl/nx-cloud"` only) defines an encryption key to support end-to-end encryption of your cloud cache. You may also provide an environment variable with the key `NX_CLOUD_ENCRYPTION_KEY` that contains an encryption key as its value. The Nx Cloud task runner normalizes the key length, so any length of key is acceptable.
- `runtimeCacheInputs` defines the list of commands that are run by the runner to include into the computation hash value.
- `selectivelyHashTsConfig` only hash the path mapping of the active project in the `tsconfig.base.json` (e.g., adding/removing projects doesn't affect the hash of existing projects). Defaults to `false`

`runtimeCacheInputs` are set as follows:

Expand Down
1 change: 1 addition & 0 deletions docs/node/guides/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,7 @@ Tasks runners can accept different options. The following are the options suppor
- `cacheDirectory` defines where the local cache is stored, which is `node_modules/.cache/nx` by default.
- `encryptionKey` (when using `"@nrwl/nx-cloud"` only) defines an encryption key to support end-to-end encryption of your cloud cache. You may also provide an environment variable with the key `NX_CLOUD_ENCRYPTION_KEY` that contains an encryption key as its value. The Nx Cloud task runner normalizes the key length, so any length of key is acceptable.
- `runtimeCacheInputs` defines the list of commands that are run by the runner to include into the computation hash value.
- `selectivelyHashTsConfig` only hash the path mapping of the active project in the `tsconfig.base.json` (e.g., adding/removing projects doesn't affect the hash of existing projects). Defaults to `false`

`runtimeCacheInputs` are set as follows:

Expand Down
1 change: 1 addition & 0 deletions docs/react/guides/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@ Tasks runners can accept different options. The following are the options suppor
- `cacheDirectory` defines where the local cache is stored, which is `node_modules/.cache/nx` by default.
- `encryptionKey` (when using `"@nrwl/nx-cloud"` only) defines an encryption key to support end-to-end encryption of your cloud cache. You may also provide an environment variable with the key `NX_CLOUD_ENCRYPTION_KEY` that contains an encryption key as its value. The Nx Cloud task runner normalizes the key length, so any length of key is acceptable.
- `runtimeCacheInputs` defines the list of commands that are run by the runner to include into the computation hash value.
- `selectivelyHashTsConfig` only hash the path mapping of the active project in the `tsconfig.base.json` (e.g., adding/removing projects doesn't affect the hash of existing projects). Defaults to `false`

`runtimeCacheInputs` are set as follows:

Expand Down
176 changes: 133 additions & 43 deletions packages/workspace/src/core/hasher/hasher.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,36 @@ import fs = require('fs');
jest.mock('fs');

describe('Hasher', () => {
const nxJson = {
npmScope: 'nrwl',
projects: {
parent: { implicitDependencies: [], tags: [] },
child: { implicitDependencies: [], tags: [] },
},
};

const workSpaceJson = {
projects: {
parent: { root: 'libs/parent' },
child: { root: 'libs/child' },
},
};

const tsConfigBaseJsonHash = JSON.stringify({
compilerOptions: {
paths: {
'@nrwl/parent': ['libs/parent/src/index.ts'],
'@nrwl/child': ['libs/child/src/index.ts'],
},
},
});
let hashes = {
'yarn.lock': 'yarn.lock.hash',
'nx.json': 'nx.json.hash',
'package-lock.json': 'package-lock.json.hash',
'package.json': 'package.json.hash',
'pnpm-lock.yaml': 'pnpm-lock.yaml.hash',
'tsconfig.base.json': 'tsconfig.base.json.hash',
'tsconfig.base.json': tsConfigBaseJsonHash,
'workspace.json': 'workspace.json.hash',
global1: 'global1.hash',
global2: 'global2.hash',
Expand All @@ -23,24 +46,84 @@ describe('Hasher', () => {
};
}

it('should create project hash', async () => {
beforeAll(() => {
fs.readFileSync = (file) => {
if (file === 'workspace.json') {
return JSON.stringify({
projects: { proj: { root: 'proj-from-workspace.json' } },
});
return JSON.stringify(workSpaceJson);
}
if (file === 'nx.json') {
return JSON.stringify({ projects: { proj: 'proj-from-nx.json' } });
return JSON.stringify(nxJson);
}
if (file === 'tsconfig.base.json') {
return tsConfigBaseJsonHash;
}
return file;
};
});

it('should create project hash', async () => {
hashes['/file'] = 'file.hash';
const hasher = new Hasher(
{
nodes: {
parent: {
name: 'parent',
type: 'lib',
data: {
root: '',
files: [{ file: '/file', ext: '.ts', hash: 'file.hash' }],
},
},
},
dependencies: {
parent: [],
},
},
{} as any,
{
runtimeCacheInputs: ['echo runtime123', 'echo runtime456'],
},
createHashing()
);

const hash = await hasher.hashTaskWithDepsAndContext({
target: { project: 'parent', target: 'build' },
id: 'parent-build',
overrides: { prop: 'prop-value' },
});

expect(hash.value).toContain('yarn.lock.hash'); //implicits
expect(hash.value).toContain('file.hash'); //project files
expect(hash.value).toContain('prop-value'); //overrides
expect(hash.value).toContain('parent'); //project
expect(hash.value).toContain('build'); //target
expect(hash.value).toContain('runtime123'); //target
expect(hash.value).toContain('runtime456'); //target

expect(hash.details.command).toEqual('parent|build||{"prop":"prop-value"}');
expect(hash.details.nodes).toEqual({
parent:
'/file|file.hash|{"root":"libs/parent"}|{"implicitDependencies":[],"tags":[]}|{"compilerOptions":{"paths":{"@nrwl/parent":["libs/parent/src/index.ts"],"@nrwl/child":["libs/child/src/index.ts"]}}}',
});
expect(hash.details.implicitDeps).toEqual({
'nx.json': '{"npmScope":"nrwl"}',
'yarn.lock': 'yarn.lock.hash',
'package-lock.json': 'package-lock.json.hash',
'pnpm-lock.yaml': 'pnpm-lock.yaml.hash',
});
expect(hash.details.runtime).toEqual({
'echo runtime123': 'runtime123',
'echo runtime456': 'runtime456',
});
});

it('should create project hash with tsconfig.base.json cache', async () => {
hashes['/file'] = 'file.hash';
const hasher = new Hasher(
{
nodes: {
proj: {
name: 'proj',
parent: {
name: 'parent',
type: 'lib',
data: {
root: '',
Expand All @@ -49,40 +132,41 @@ describe('Hasher', () => {
},
},
dependencies: {
proj: [],
parent: [],
},
},
{} as any,
{
runtimeCacheInputs: ['echo runtime123', 'echo runtime456'],
selectivelyHashTsConfig: true,
},
createHashing()
);

const hash = await hasher.hashTaskWithDepsAndContext({
target: { project: 'proj', target: 'build' },
id: 'proj-build',
target: { project: 'parent', target: 'build' },
id: 'parent-build',
overrides: { prop: 'prop-value' },
});

expect(hash.value).toContain('yarn.lock.hash'); //implicits
expect(hash.value).toContain('file.hash'); //project files
expect(hash.value).toContain('prop-value'); //overrides
expect(hash.value).toContain('proj'); //project
expect(hash.value).toContain('parent'); //project
expect(hash.value).toContain('build'); //target
expect(hash.value).toContain('runtime123'); //target
expect(hash.value).toContain('runtime456'); //target

expect(hash.details.command).toEqual('proj|build||{"prop":"prop-value"}');
expect(hash.details.command).toEqual('parent|build||{"prop":"prop-value"}');
expect(hash.details.nodes).toEqual({
proj: '/file.ts|file.hash|{"root":"proj-from-workspace.json"}|"proj-from-nx.json"',
parent:
'/file.ts|file.hash|{"root":"libs/parent"}|{"implicitDependencies":[],"tags":[]}|{"compilerOptions":{"paths":{"@nrwl/parent":["libs/parent/src/index.ts"]}}}',
});
expect(hash.details.implicitDeps).toEqual({
'nx.json': '{"npmScope":"nrwl"}',
'yarn.lock': 'yarn.lock.hash',
'nx.json': '{}',
'package-lock.json': 'package-lock.json.hash',
'pnpm-lock.yaml': 'pnpm-lock.yaml.hash',
'tsconfig.base.json': 'tsconfig.base.json.hash',
});
expect(hash.details.runtime).toEqual({
'echo runtime123': 'runtime123',
Expand All @@ -94,8 +178,8 @@ describe('Hasher', () => {
const hasher = new Hasher(
{
nodes: {
proj: {
name: 'proj',
parent: {
name: 'parent',
type: 'lib',
data: {
root: '',
Expand All @@ -104,7 +188,7 @@ describe('Hasher', () => {
},
},
dependencies: {
proj: [],
parent: [],
},
},
{} as any,
Expand All @@ -116,8 +200,8 @@ describe('Hasher', () => {

try {
await hasher.hashTaskWithDepsAndContext({
target: { project: 'proj', target: 'build' },
id: 'proj-build',
target: { project: 'parent', target: 'build' },
id: 'parent-build',
overrides: {},
});
fail('Should not be here');
Expand Down Expand Up @@ -172,8 +256,10 @@ describe('Hasher', () => {

// note that the parent hash is based on parent source files only!
expect(hash.details.nodes).toEqual({
parent: '/filea.ts|a.hash|""|""',
child: '/fileb.ts|b.hash|""|""',
child:
'/fileb.ts|b.hash|{"root":"libs/child"}|{"implicitDependencies":[],"tags":[]}|{"compilerOptions":{"paths":{"@nrwl/parent":["libs/parent/src/index.ts"],"@nrwl/child":["libs/child/src/index.ts"]}}}',
parent:
'/filea.ts|a.hash|{"root":"libs/parent"}|{"implicitDependencies":[],"tags":[]}|{"compilerOptions":{"paths":{"@nrwl/parent":["libs/parent/src/index.ts"],"@nrwl/child":["libs/child/src/index.ts"]}}}',
});
});

Expand All @@ -183,16 +269,16 @@ describe('Hasher', () => {
const hasher = new Hasher(
{
nodes: {
proja: {
name: 'proja',
parent: {
name: 'parent',
type: 'lib',
data: {
root: '',
files: [{ file: '/filea.ts', hash: 'a.hash' }],
},
},
projb: {
name: 'projb',
child: {
name: 'child',
type: 'lib',
data: {
root: '',
Expand All @@ -201,8 +287,8 @@ describe('Hasher', () => {
},
},
dependencies: {
proja: [{ source: 'proja', target: 'projb', type: 'static' }],
projb: [{ source: 'projb', target: 'proja', type: 'static' }],
parent: [{ source: 'parent', target: 'child', type: 'static' }],
child: [{ source: 'child', target: 'parent', type: 'static' }],
},
},
{} as any,
Expand All @@ -211,37 +297,41 @@ describe('Hasher', () => {
);

const tasksHash = await hasher.hashTaskWithDepsAndContext({
target: { project: 'proja', target: 'build' },
id: 'proja-build',
target: { project: 'parent', target: 'build' },
id: 'parent-build',
overrides: { prop: 'prop-value' },
});

expect(tasksHash.value).toContain('yarn.lock.hash'); //implicits
expect(tasksHash.value).toContain('a.hash'); //project files
expect(tasksHash.value).toContain('b.hash'); //project files
expect(tasksHash.value).toContain('prop-value'); //overrides
expect(tasksHash.value).toContain('proj'); //project
expect(tasksHash.value).toContain('parent|build'); //project and target
expect(tasksHash.value).toContain('build'); //target
expect(tasksHash.details.nodes).toEqual({
proja: '/filea.ts|a.hash|""|""',
projb: '/fileb.ts|b.hash|""|""',
child:
'/fileb.ts|b.hash|{"root":"libs/child"}|{"implicitDependencies":[],"tags":[]}|{"compilerOptions":{"paths":{"@nrwl/parent":["libs/parent/src/index.ts"],"@nrwl/child":["libs/child/src/index.ts"]}}}',
parent:
'/filea.ts|a.hash|{"root":"libs/parent"}|{"implicitDependencies":[],"tags":[]}|{"compilerOptions":{"paths":{"@nrwl/parent":["libs/parent/src/index.ts"],"@nrwl/child":["libs/child/src/index.ts"]}}}',
});

const hashb = await hasher.hashTaskWithDepsAndContext({
target: { project: 'projb', target: 'build' },
id: 'projb-build',
target: { project: 'child', target: 'build' },
id: 'child-build',
overrides: { prop: 'prop-value' },
});

expect(hashb.value).toContain('yarn.lock.hash'); //implicits
expect(hashb.value).toContain('a.hash'); //project files
expect(hashb.value).toContain('b.hash'); //project files
expect(hashb.value).toContain('prop-value'); //overrides
expect(hashb.value).toContain('proj'); //project
expect(hashb.value).toContain('child|build'); //project and target
expect(hashb.value).toContain('build'); //target
expect(hashb.details.nodes).toEqual({
proja: '/filea.ts|a.hash|""|""',
projb: '/fileb.ts|b.hash|""|""',
child:
'/fileb.ts|b.hash|{"root":"libs/child"}|{"implicitDependencies":[],"tags":[]}|{"compilerOptions":{"paths":{"@nrwl/parent":["libs/parent/src/index.ts"],"@nrwl/child":["libs/child/src/index.ts"]}}}',
parent:
'/filea.ts|a.hash|{"root":"libs/parent"}|{"implicitDependencies":[],"tags":[]}|{"compilerOptions":{"paths":{"@nrwl/parent":["libs/parent/src/index.ts"],"@nrwl/child":["libs/child/src/index.ts"]}}}',
});
});

Expand All @@ -251,8 +341,8 @@ describe('Hasher', () => {
const hasher = new Hasher(
{
nodes: {
proja: {
name: 'proja',
parent: {
name: 'parent',
type: 'lib',
data: {
root: '',
Expand Down Expand Up @@ -282,8 +372,8 @@ describe('Hasher', () => {
);

const tasksHash = await hasher.hashTaskWithDepsAndContext({
target: { project: 'proja', target: 'build' },
id: 'proja-build',
target: { project: 'parent', target: 'build' },
id: 'parent-build',
overrides: { prop: 'prop-value' },
});

Expand Down
Loading