diff --git a/packages/workspace/src/core/hasher/hasher.spec.ts b/packages/workspace/src/core/hasher/hasher.spec.ts index fbe616b802fbd..d9ac60a05dc93 100644 --- a/packages/workspace/src/core/hasher/hasher.spec.ts +++ b/packages/workspace/src/core/hasher/hasher.spec.ts @@ -6,6 +6,7 @@ jest.doMock('../../utils/app-root', () => { }); import fs = require('fs'); +import { DependencyType } from '@nrwl/devkit'; import { Hasher } from './hasher'; jest.mock('fs'); @@ -272,6 +273,53 @@ describe('Hasher', () => { }); }); + it('should hash dependent npm project versions', async () => { + hashes['/filea'] = 'a.hash'; + hashes['/fileb'] = 'b.hash'; + const hasher = new Hasher( + { + nodes: { + 'npm:react': { + name: 'parent', + type: 'npm', + data: { + version: '17.0.0', + }, + }, + app: { + name: 'app', + type: 'app', + data: { + root: '', + files: [{ file: '/filea.ts', hash: 'a.hash' }], + }, + }, + }, + dependencies: { + 'npm:react': [], + app: [ + { source: 'app', target: 'npm:react', type: DependencyType.static }, + ], + }, + }, + {} as any, + {}, + createHashing() + ); + + const hash = await hasher.hashTaskWithDepsAndContext({ + target: { project: 'app', target: 'build' }, + id: 'app-build', + overrides: { prop: 'prop-value' }, + }); + + // note that the parent hash is based on parent source files only! + expect(hash.details.nodes).toEqual({ + app: '/filea.ts|a.hash|""|""|{"compilerOptions":{"paths":{"@nrwl/parent":["libs/parent/src/index.ts"],"@nrwl/child":["libs/child/src/index.ts"]}}}', + 'npm:react': '17.0.0', + }); + }); + it('should hash when circular dependencies', async () => { hashes['/filea'] = 'a.hash'; hashes['/fileb'] = 'b.hash'; diff --git a/packages/workspace/src/core/hasher/hasher.ts b/packages/workspace/src/core/hasher/hasher.ts index 81c6032a0aadd..36b3900a5ffdc 100644 --- a/packages/workspace/src/core/hasher/hasher.ts +++ b/packages/workspace/src/core/hasher/hasher.ts @@ -15,6 +15,7 @@ import { performance } from 'perf_hooks'; import { appRootPath } from '../../utils/app-root'; import { workspaceFileName } from '../file-utils'; import { defaultHashing, HashingImpl } from './hashing-impl'; +import { isNpmProject } from '../project-graph'; export interface Hash { value: string; @@ -341,6 +342,12 @@ class ProjectHasher { if (!this.sourceHashes[projectName]) { this.sourceHashes[projectName] = new Promise(async (res) => { const p = this.projectGraph.nodes[projectName]; + + if (isNpmProject(p)) { + res(this.hashing.hashArray([p.data.version])); + return; + } + const fileNames = p.data.files.map((f) => f.file); const values = p.data.files.map((f) => f.hash);