From a6168fe474fd9d8a3cf12247d497e69457a283bd Mon Sep 17 00:00:00 2001 From: Craigory Coppola Date: Sat, 1 May 2021 17:41:28 -0500 Subject: [PATCH] feat(core): #6 schematic to sync nuget packages across workspace --- .github/ISSUE_TEMPLATE/bug_report.md | 11 +-- .github/ISSUE_TEMPLATE/feature_request.md | 3 +- .github/workflows/main.yml | 1 - CHANGELOG.md | 6 +- e2e/core-e2e/tests/nx-dotnet.spec.ts | 14 +-- e2e/utils/index.ts | 28 +++--- packages/core/package.json | 2 +- .../core/src/executors/build/executor.spec.ts | 6 +- packages/core/src/executors/build/executor.ts | 6 +- packages/core/src/executors/serve/executor.ts | 6 +- packages/core/src/executors/test/executor.ts | 6 +- .../core/src/generators/app/generator.spec.ts | 2 +- packages/core/src/generators/app/generator.ts | 2 +- .../src/generators/init/generator.spec.ts | 1 + .../core/src/generators/init/generator.ts | 1 + .../core/src/generators/lib/generator.spec.ts | 2 +- packages/core/src/generators/lib/generator.ts | 2 +- .../nuget-reference/generator.spec.ts | 3 +- .../generators/nuget-reference/generator.ts | 7 +- .../generators/project-reference/generator.ts | 2 +- .../src/generators/sync/generator.spec.ts | 27 +++++- .../core/src/generators/sync/generator.ts | 54 +++++++++++- packages/core/src/generators/sync/schema.json | 23 +---- .../utils/resolve-version-mismatch.ts | 9 +- .../utils/update-dependency-version.ts | 85 +++++++------------ .../core/src/graph/process-project-graph.ts | 8 +- .../models/build-executor-configuration.ts | 2 +- .../src/models/test-executor-configuration.ts | 2 +- packages/dotnet/package.json | 2 +- .../dotnet/src/lib/core/dotnet.factory.ts | 2 +- packages/typescript/package.json | 2 +- .../src/generators/typescript/generator.ts | 4 +- packages/utils/package.json | 2 +- .../utils/src/lib/utility-functions/args.ts | 6 +- .../utils/src/lib/utility-functions/config.ts | 1 + .../utils/src/lib/utility-functions/glob.ts | 14 +-- .../utils/src/lib/utility-functions/index.ts | 1 + .../utils/src/lib/utility-functions/rimraf.ts | 2 +- .../src/lib/utility-functions/workspace.ts | 54 ++++++++++-- .../utils/src/lib/utility-functions/xml.ts | 30 +++++++ tools/scripts/build.ts | 6 +- tools/scripts/e2e.ts | 12 +-- tools/scripts/patch-package-versions/index.ts | 2 +- tools/utils/get-affected.ts | 2 +- 44 files changed, 279 insertions(+), 184 deletions(-) create mode 100644 packages/utils/src/lib/utility-functions/xml.ts diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 84fe7e35..1248c8a3 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,10 +1,9 @@ --- name: Bug report about: Create a report to help us improve -title: "[BUG] " +title: '[BUG] ' labels: bug, needs-triage assignees: '' - --- **Describe the bug** @@ -12,6 +11,7 @@ A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: + 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' @@ -24,9 +24,10 @@ A clear and concise description of what you expected to happen. If applicable, add screenshots to help explain your problem. **Environment:** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] + +- OS: [e.g. iOS] +- Browser [e.g. chrome, safari] +- Version [e.g. 22] - Affected Packages **Additional context** diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 2b183f55..8452a833 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,10 +1,9 @@ --- name: Feature request about: Suggest an idea for this project -title: "[Feature]" +title: '[Feature]' labels: enhancement, needs-triage assignees: '' - --- **Is your feature request related to a problem? Please describe.** diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 80d88cfb..5e38bbf3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,7 +10,6 @@ env: NX_RUN_GROUP: ${{ github.run_id }} jobs: - build: runs-on: ubuntu-latest name: Building affected apps diff --git a/CHANGELOG.md b/CHANGELOG.md index f27825f6..a7cae6cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,12 @@ # [0.3.0-dev.4](https://github.com/nx-dotnet/nx-dotnet/compare/v0.3.0-dev.3...v0.3.0-dev.4) (2021-04-29) - ### Bug Fixes -* **repo:** update .releaserc to commit package.json version back ([dea86e3](https://github.com/nx-dotnet/nx-dotnet/commit/dea86e3c2015ede2c10c508f8c79f2877ed9ee4d)) - +- **repo:** update .releaserc to commit package.json version back ([dea86e3](https://github.com/nx-dotnet/nx-dotnet/commit/dea86e3c2015ede2c10c508f8c79f2877ed9ee4d)) ### Features -* **core:** schematic for adding npm package [#5](https://github.com/nx-dotnet/nx-dotnet/issues/5) ([b97c097](https://github.com/nx-dotnet/nx-dotnet/commit/b97c0972f1cbc87045e9047bf0222e90d3940cfe)), closes [#6](https://github.com/nx-dotnet/nx-dotnet/issues/6) +- **core:** schematic for adding npm package [#5](https://github.com/nx-dotnet/nx-dotnet/issues/5) ([b97c097](https://github.com/nx-dotnet/nx-dotnet/commit/b97c0972f1cbc87045e9047bf0222e90d3940cfe)), closes [#6](https://github.com/nx-dotnet/nx-dotnet/issues/6) ## [0.2.1](https://github.com/nx-dotnet/nx-dotnet/compare/v0.2.0...v0.2.1) (2021-04-27) diff --git a/e2e/core-e2e/tests/nx-dotnet.spec.ts b/e2e/core-e2e/tests/nx-dotnet.spec.ts index bb5ee9e5..437bd3eb 100644 --- a/e2e/core-e2e/tests/nx-dotnet.spec.ts +++ b/e2e/core-e2e/tests/nx-dotnet.spec.ts @@ -12,15 +12,15 @@ describe('nx-dotnet e2e', () => { ensureNxProject('@nx-dotnet/core', 'dist/packages/core'); await runNxCommandAsync( - `generate @nx-dotnet/core:app ${testApp} --language="C#" --template="webapi"` + `generate @nx-dotnet/core:app ${testApp} --language="C#" --template="webapi"`, ); await runNxCommandAsync( - `generate @nx-dotnet/core:lib ${testLib} --language="C#" --template="classlib"` + `generate @nx-dotnet/core:lib ${testLib} --language="C#" --template="classlib"`, ); const output = await runNxCommandAsync( - `generate @nx-dotnet/core:project-reference ${testApp} ${testLib}` + `generate @nx-dotnet/core:project-reference ${testApp} ${testLib}`, ); expect(output.stdout).toMatch(/Reference .* added to the project/); @@ -32,7 +32,7 @@ describe('nx-dotnet e2e', () => { it('should obey dry-run', async () => { const app = uniq('app'); await runNxCommandAsync( - `generate @nx-dotnet/core:app ${app} --language="C#" --template="webapi" --dry-run` + `generate @nx-dotnet/core:app ${app} --language="C#" --template="webapi" --dry-run`, ); let exists = true; @@ -48,7 +48,7 @@ describe('nx-dotnet e2e', () => { it('should generate an app', async () => { const app = uniq('app'); await runNxCommandAsync( - `generate @nx-dotnet/core:app ${app} --language="C#" --template="webapi"` + `generate @nx-dotnet/core:app ${app} --language="C#" --template="webapi"`, ); let exists = true; @@ -66,7 +66,7 @@ describe('nx-dotnet e2e', () => { it('should obey dry-run', async () => { const lib = uniq('lib'); await runNxCommandAsync( - `generate @nx-dotnet/core:lib ${lib} --language="C#" --template="webapi" --dry-run` + `generate @nx-dotnet/core:lib ${lib} --language="C#" --template="webapi" --dry-run`, ); let exists = true; @@ -82,7 +82,7 @@ describe('nx-dotnet e2e', () => { it('should generate an lib', async () => { const lib = uniq('lib'); await runNxCommandAsync( - `generate @nx-dotnet/core:lib ${lib} --language="C#" --template="webapi"` + `generate @nx-dotnet/core:lib ${lib} --language="C#" --template="webapi"`, ); let exists = true; diff --git a/e2e/utils/index.ts b/e2e/utils/index.ts index e6ec8620..ed698caf 100644 --- a/e2e/utils/index.ts +++ b/e2e/utils/index.ts @@ -42,7 +42,7 @@ export function workspaceConfigName() { } export function updateWorkspaceConfig( - callback: (json: { [key: string]: any }) => Object + callback: (json: { [key: string]: any }) => Object, ) { const file = workspaceConfigName(); updateFile(file, JSON.stringify(callback(readJson(file)), null, 2)); @@ -66,7 +66,7 @@ export function runCreateWorkspace( packageManager?: 'npm' | 'yarn' | 'pnpm'; cli?: string; extraArgs?: string; - } + }, ) { projName = name; @@ -197,7 +197,7 @@ export function runCommandAsync( opts: RunCmdOpts = { silenceError: false, env: process.env, - } + }, ): Promise<{ stdout: string; stderr: string; combinedOutput: string }> { return new Promise((resolve, reject) => { exec( @@ -211,7 +211,7 @@ export function runCommandAsync( reject(err); } resolve({ stdout, stderr, combinedOutput: `${stdout}${stderr}` }); - } + }, ); }); } @@ -219,7 +219,7 @@ export function runCommandAsync( export function runCommandUntil( command: string, criteria: (output: string) => boolean, - { kill = true } = {} + { kill = true } = {}, ): Promise<{ process: ChildProcess }> { const pm = getPackageManagerCommand(); const p = exec(`${pm.runNx} ${command}`, { @@ -259,12 +259,12 @@ export function runCLIAsync( silenceError: false, env: process.env, silent: false, - } + }, ): Promise<{ stdout: string; stderr: string; combinedOutput: string }> { const pm = getPackageManagerCommand(); return runCommandAsync( `${opts.silent ? pm.runNxSilent : pm.runNx} ${command}`, - opts + opts, ); } @@ -274,7 +274,7 @@ export function runNgAdd( silenceError: false, env: process.env, cwd: tmpProjPath(), - } + }, ): string { try { packageInstall('@nrwl/workspace'); @@ -283,12 +283,12 @@ export function runNgAdd( { cwd: tmpProjPath(), env: opts.env as any, - } + }, ) .toString() .replace( /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, - '' + '', ); } catch (e) { if (opts.silenceError) { @@ -305,7 +305,7 @@ export function runCLI( opts: RunCmdOpts = { silenceError: false, env: process.env, - } + }, ): string { try { const pm = getPackageManagerCommand(); @@ -315,7 +315,7 @@ export function runCLI( }).toString(); r = r.replace( /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, - '' + '', ); if (process.env.VERBOSE_OUTPUT) { console.log(r); @@ -402,7 +402,7 @@ export function createFile(f: string, content: string = ''): void { export function updateFile( f: string, - content: string | ((content: string) => string) + content: string | ((content: string) => string), ): void { ensureDirSync(path.dirname(tmpProjPath(f))); if (typeof content === 'string') { @@ -410,7 +410,7 @@ export function updateFile( } else { writeFileSync( tmpProjPath(f), - content(readFileSync(tmpProjPath(f)).toString()) + content(readFileSync(tmpProjPath(f)).toString()), ); } } diff --git a/packages/core/package.json b/packages/core/package.json index e235ffa7..d06c3d0a 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -21,4 +21,4 @@ "bugs": { "url": "https://github.com/nx-dotnet/nx-dotnet/issues/new?assignees=&labels=bug%2C+needs-triage&template=bug_report.md&title=%5BBUG%5D+" } -} \ No newline at end of file +} diff --git a/packages/core/src/executors/build/executor.spec.ts b/packages/core/src/executors/build/executor.spec.ts index 5451c4cf..1d8838ae 100644 --- a/packages/core/src/executors/build/executor.spec.ts +++ b/packages/core/src/executors/build/executor.spec.ts @@ -56,7 +56,7 @@ describe('Build Executor', () => { } catch (e) { console.log(e.message); expect(e.message).toMatch( - "Unable to find a build-able project within project's source directory!" + "Unable to find a build-able project within project's source directory!", ); } }); @@ -80,7 +80,7 @@ describe('Build Executor', () => { } catch (e) { console.log(e.message); expect(e.message).toMatch( - "More than one build-able projects are contained within the project's source directory!" + "More than one build-able projects are contained within the project's source directory!", ); } }); @@ -96,7 +96,7 @@ describe('Build Executor', () => { const res = await executor(options, context, dotnetClient); expect( - (dotnetClient as jest.Mocked).build + (dotnetClient as jest.Mocked).build, ).toHaveBeenCalled(); expect(res.success).toBeTruthy(); }); diff --git a/packages/core/src/executors/build/executor.ts b/packages/core/src/executors/build/executor.ts index eb58ed40..eadc7554 100644 --- a/packages/core/src/executors/build/executor.ts +++ b/packages/core/src/executors/build/executor.ts @@ -15,11 +15,11 @@ import { BuildExecutorSchema } from './schema'; export default async function runExecutor( options: BuildExecutorSchema, context: ExecutorContext, - dotnetClient: DotNetClient = new DotNetClient(dotnetFactory()) + dotnetClient: DotNetClient = new DotNetClient(dotnetFactory()), ) { const nxProjectConfiguration = getExecutedProjectConfiguration(context); const projectFilePath = await getProjectFileForNxProject( - nxProjectConfiguration + nxProjectConfiguration, ); dotnetClient.build( @@ -27,7 +27,7 @@ export default async function runExecutor( Object.keys(options).map((x) => ({ flag: x as dotnetBuildFlags, value: (options as Record)[x], - })) + })), ); return { diff --git a/packages/core/src/executors/serve/executor.ts b/packages/core/src/executors/serve/executor.ts index 4a4483ae..13e0f4a3 100644 --- a/packages/core/src/executors/serve/executor.ts +++ b/packages/core/src/executors/serve/executor.ts @@ -26,7 +26,7 @@ let projectDirectory: string; export default function dotnetRunExecutor( options: ServeExecutorSchema, context: ExecutorContext, - dotnetClient: DotNetClient = new DotNetClient(dotnetFactory()) + dotnetClient: DotNetClient = new DotNetClient(dotnetFactory()), ): Promise<{ success: boolean }> { const nxProjectConfiguration = getExecutedProjectConfiguration(context); @@ -43,7 +43,7 @@ export default function dotnetRunExecutor( context.workspace, (dependency) => { watcher.add(dependency.root); - } + }, ); watcher.on('all', (event, path) => { @@ -68,7 +68,7 @@ export default function dotnetRunExecutor( const setupDotnetRun = ( dotnetClient: DotNetClient, project: string, - options: ServeExecutorSchema + options: ServeExecutorSchema, ) => { if (childProcess) { childProcess.kill('SIGTERM'); diff --git a/packages/core/src/executors/test/executor.ts b/packages/core/src/executors/test/executor.ts index 17376312..19cad089 100644 --- a/packages/core/src/executors/test/executor.ts +++ b/packages/core/src/executors/test/executor.ts @@ -15,11 +15,11 @@ import { TestExecutorSchema } from './schema'; export default async function runExecutor( options: TestExecutorSchema, context: ExecutorContext, - dotnetClient: DotNetClient = new DotNetClient(dotnetFactory()) + dotnetClient: DotNetClient = new DotNetClient(dotnetFactory()), ) { const nxProjectConfiguration = getExecutedProjectConfiguration(context); const projectFilePath = await getProjectFileForNxProject( - nxProjectConfiguration + nxProjectConfiguration, ); dotnetClient.test( @@ -27,7 +27,7 @@ export default async function runExecutor( Object.keys(options).map((x) => ({ flag: x as dotnetTestFlags, value: (options as Record)[x], - })) + })), ); return { diff --git a/packages/core/src/generators/app/generator.spec.ts b/packages/core/src/generators/app/generator.spec.ts index b5211671..33a83b66 100644 --- a/packages/core/src/generators/app/generator.spec.ts +++ b/packages/core/src/generators/app/generator.spec.ts @@ -40,7 +40,7 @@ describe('nx-dotnet library generator', () => { appTree, options, dotnetClient, - 'application' + 'application', ); }); }); diff --git a/packages/core/src/generators/app/generator.ts b/packages/core/src/generators/app/generator.ts index 89767c82..f31d9190 100644 --- a/packages/core/src/generators/app/generator.ts +++ b/packages/core/src/generators/app/generator.ts @@ -8,7 +8,7 @@ import { NxDotnetGeneratorSchema } from './schema'; export default function ( host: Tree, options: NxDotnetGeneratorSchema, - dotnetClient = new DotNetClient(dotnetFactory()) + dotnetClient = new DotNetClient(dotnetFactory()), ) { return GenerateProject(host, options, dotnetClient, 'application'); } diff --git a/packages/core/src/generators/init/generator.spec.ts b/packages/core/src/generators/init/generator.spec.ts index 688acac1..b31d9991 100644 --- a/packages/core/src/generators/init/generator.spec.ts +++ b/packages/core/src/generators/init/generator.spec.ts @@ -1,5 +1,6 @@ import { readJson, Tree } from '@nrwl/devkit'; import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; + import { CONFIG_FILE_PATH, NxDotnetConfig } from '@nx-dotnet/utils'; import generator from './generator'; diff --git a/packages/core/src/generators/init/generator.ts b/packages/core/src/generators/init/generator.ts index de53e838..50ef31a7 100644 --- a/packages/core/src/generators/init/generator.ts +++ b/packages/core/src/generators/init/generator.ts @@ -5,6 +5,7 @@ import { Tree, writeJson, } from '@nrwl/devkit'; + import { CONFIG_FILE_PATH, NxDotnetConfig } from '@nx-dotnet/utils'; export default async function (host: Tree) { diff --git a/packages/core/src/generators/lib/generator.spec.ts b/packages/core/src/generators/lib/generator.spec.ts index d16fc23f..3e798b33 100644 --- a/packages/core/src/generators/lib/generator.spec.ts +++ b/packages/core/src/generators/lib/generator.spec.ts @@ -40,7 +40,7 @@ describe('nx-dotnet library generator', () => { appTree, options, dotnetClient, - 'library' + 'library', ); }); }); diff --git a/packages/core/src/generators/lib/generator.ts b/packages/core/src/generators/lib/generator.ts index 40f22677..89e5495b 100644 --- a/packages/core/src/generators/lib/generator.ts +++ b/packages/core/src/generators/lib/generator.ts @@ -8,7 +8,7 @@ import { NxDotnetGeneratorSchema } from './schema'; export default function ( host: Tree, options: NxDotnetGeneratorSchema, - dotnetClient = new DotNetClient(dotnetFactory()) + dotnetClient = new DotNetClient(dotnetFactory()), ) { return GenerateProject(host, options, dotnetClient, 'library'); } diff --git a/packages/core/src/generators/nuget-reference/generator.spec.ts b/packages/core/src/generators/nuget-reference/generator.spec.ts index a6821a13..617ba338 100644 --- a/packages/core/src/generators/nuget-reference/generator.spec.ts +++ b/packages/core/src/generators/nuget-reference/generator.spec.ts @@ -1,13 +1,14 @@ import { Tree } from '@nrwl/devkit'; import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; +import { prompt } from 'inquirer'; + import { DotNetClient, mockDotnetFactory } from '@nx-dotnet/dotnet'; import { updateConfig } from '@nx-dotnet/utils'; import generator from './generator'; import { NugetReferenceGeneratorSchema } from './schema'; -import { prompt } from 'inquirer'; import PromptUI = require('inquirer/lib/ui/prompt'); jest.mock('../../../../dotnet/src/lib/core/dotnet.client'); diff --git a/packages/core/src/generators/nuget-reference/generator.ts b/packages/core/src/generators/nuget-reference/generator.ts index f3b5aad0..3e0bdd2d 100644 --- a/packages/core/src/generators/nuget-reference/generator.ts +++ b/packages/core/src/generators/nuget-reference/generator.ts @@ -5,7 +5,6 @@ import { DotNetClient, dotnetFactory, } from '@nx-dotnet/dotnet'; - import { ALLOW_MISMATCH, getProjectFileForNxProject, @@ -13,9 +12,9 @@ import { updateConfig, } from '@nx-dotnet/utils'; -import { NugetReferenceGeneratorSchema } from './schema'; -import { UpdateDependencyVersions } from '../utils/update-dependency-version'; import { resolveVersionMismatch } from '../utils/resolve-version-mismatch'; +import { updateDependencyVersions } from '../utils/update-dependency-version'; +import { NugetReferenceGeneratorSchema } from './schema'; export default async function ( host: Tree, @@ -59,7 +58,7 @@ export default async function ( resolvedVersion !== configuredPkgVersion && resolvedVersion ) { - UpdateDependencyVersions(host, options.packageName, resolvedVersion); + updateDependencyVersions(host, options.packageName, resolvedVersion); } } catch (e: unknown) { console.warn('Config not updated since dotnet failed to add dependency!'); diff --git a/packages/core/src/generators/project-reference/generator.ts b/packages/core/src/generators/project-reference/generator.ts index 4c8548e0..3af5cd43 100644 --- a/packages/core/src/generators/project-reference/generator.ts +++ b/packages/core/src/generators/project-reference/generator.ts @@ -8,7 +8,7 @@ import { NxDotnetGeneratorSchema } from './schema'; export default async function ( host: Tree, options: NxDotnetGeneratorSchema, - client = new DotNetClient(dotnetFactory()) + client = new DotNetClient(dotnetFactory()), ) { const hostProject = readProjectConfiguration(host, options.project); const sourceProject = readProjectConfiguration(host, options.reference); diff --git a/packages/core/src/generators/sync/generator.spec.ts b/packages/core/src/generators/sync/generator.spec.ts index d195dfaa..5a2da487 100644 --- a/packages/core/src/generators/sync/generator.spec.ts +++ b/packages/core/src/generators/sync/generator.spec.ts @@ -1,19 +1,38 @@ -import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; import { Tree } from '@nrwl/devkit'; +import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; + +import { prompt } from 'inquirer'; + +import { updateConfig, getNxDotnetProjects } from '@nx-dotnet/utils'; import generator from './generator'; -import { SyncGeneratorSchema } from './schema'; + +import PromptUI = require('inquirer/lib/ui/prompt'); + +jest.mock('../../../../dotnet/src/lib/core/dotnet.client'); +jest.mock('../../../../utils/src/lib/utility-functions/workspace'); +jest.mock('inquirer'); describe('sync generator', () => { let appTree: Tree; - const options: SyncGeneratorSchema = { name: 'test' }; beforeEach(() => { appTree = createTreeWithEmptyWorkspace(); + updateConfig(appTree, { nugetPackages: {} }); + + (prompt as jest.MockedFunction) + .mockReset() + .mockImplementation((async () => { + return {}; + }) as () => Promise & { ui: PromptUI }); + + (getNxDotnetProjects as jest.MockedFunction) + .mockReset() + .mockImplementation(() => new Map()); }); it('should run successfully', async () => { - await generator(appTree, options); + await generator(appTree); expect(true).toBeTruthy(); }); }); diff --git a/packages/core/src/generators/sync/generator.ts b/packages/core/src/generators/sync/generator.ts index e419e032..95997f2a 100644 --- a/packages/core/src/generators/sync/generator.ts +++ b/packages/core/src/generators/sync/generator.ts @@ -1,8 +1,54 @@ import { Tree } from '@nrwl/devkit'; -import { SyncGeneratorSchema } from './schema'; +import { + ALLOW_MISMATCH, + getNxDotnetProjects, + getProjectFilesForProject, + iterateChildrenByPath, + readConfig, + readXml, + updateConfig, +} from '@nx-dotnet/utils'; -// eslint-disable-next-line @typescript-eslint/no-unused-vars -export default async function (host: Tree, options: SyncGeneratorSchema) { - console.log('Syncing dependencies between project files and config...'); +import { resolveVersionMismatch } from '../utils/resolve-version-mismatch'; +import { updateDependencyVersions } from '../utils/update-dependency-version'; + +export default async function (host: Tree) { + const config = readConfig(host); + const projects = getNxDotnetProjects(host); + + for (const [projectName, configuration] of projects.entries()) { + const projectFiles = getProjectFilesForProject(host, configuration); + for (const f of projectFiles) { + const xmldoc = readXml(host, f); + console.log(`Scanning packages for ${projectName} (${f})`); + await iterateChildrenByPath( + xmldoc, + 'ItemGroup.PackageReference', + async (reference) => { + const pkg = reference.attr['Include']; + const version = reference.attr['Version']; + const configuredVersion = config.nugetPackages[pkg]; + + if ( + version && + version !== configuredVersion && + configuredVersion !== ALLOW_MISMATCH + ) { + const resolved = await resolveVersionMismatch( + version, + configuredVersion, + false, + ); + // console.log('Resolved:', resolved) + config.nugetPackages[pkg] = resolved; + if (resolved !== ALLOW_MISMATCH) { + updateDependencyVersions(host, pkg, resolved); + } + } + }, + ); + } + } + updateConfig(host, config); } diff --git a/packages/core/src/generators/sync/schema.json b/packages/core/src/generators/sync/schema.json index fd7cd479..58f7f3ae 100644 --- a/packages/core/src/generators/sync/schema.json +++ b/packages/core/src/generators/sync/schema.json @@ -4,26 +4,5 @@ "id": "Sync", "title": "", "type": "object", - "properties": { - "name": { - "type": "string", - "description": "", - "$default": { - "$source": "argv", - "index": 0 - }, - "x-prompt": "What name would you like to use?" - }, - "tags": { - "type": "string", - "description": "Add tags to the project (used for linting)", - "alias": "t" - }, - "directory": { - "type": "string", - "description": "A directory where the project is placed", - "alias": "d" - } - }, - "required": ["name"] + "properties": {} } diff --git a/packages/core/src/generators/utils/resolve-version-mismatch.ts b/packages/core/src/generators/utils/resolve-version-mismatch.ts index 29f6e93c..29359816 100644 --- a/packages/core/src/generators/utils/resolve-version-mismatch.ts +++ b/packages/core/src/generators/utils/resolve-version-mismatch.ts @@ -1,19 +1,20 @@ -import { ALLOW_MISMATCH } from '@nx-dotnet/utils'; import { prompt } from 'inquirer'; +import { ALLOW_MISMATCH } from '@nx-dotnet/utils'; + export async function resolveVersionMismatch( desired: string | undefined, configured: string | undefined, allowVersionMismatch: boolean, -): Promise { +): Promise { if (configured) { if (configured !== desired) { if (allowVersionMismatch || configured === ALLOW_MISMATCH) { return ALLOW_MISMATCH; - } else if (!desired && configured !== ALLOW_MISMATCH) { + } else if (!desired) { console.log(`Installing with pre-configured version ${configured}`); return configured; - } else if (desired) { + } else { const { resolution } = await prompt([ { type: 'list', diff --git a/packages/core/src/generators/utils/update-dependency-version.ts b/packages/core/src/generators/utils/update-dependency-version.ts index 1346353f..869e7274 100644 --- a/packages/core/src/generators/utils/update-dependency-version.ts +++ b/packages/core/src/generators/utils/update-dependency-version.ts @@ -1,61 +1,42 @@ +import { Tree } from '@nrwl/devkit'; + import { - getProjects, - readProjectConfiguration, - Tree, - WorkspaceConfiguration, - WorkspaceJsonConfiguration, -} from '@nrwl/devkit'; -import { NXDOTNET_TAG } from '@nx-dotnet/utils'; -import { XmlDocument } from 'xmldoc'; + getNxDotnetProjects, + getProjectFilesForProject, + iterateChildrenByPath, + readXml, +} from '@nx-dotnet/utils'; -export function UpdateDependencyVersions( +export async function updateDependencyVersions( host: Tree, packageName: string, version: string, ) { - const projects = getProjects(host); - projects.forEach((configuration, projectName) => { - if ( - configuration.tags?.includes(NXDOTNET_TAG) && - configuration.sourceRoot - ) { - const projectFiles = host - .children(configuration.sourceRoot) - .filter((x) => x.endsWith('proj')) - .map((x) => `${configuration.sourceRoot}/${x}`); - console.log(projectName, projectFiles); - - projectFiles.forEach((f) => { - let fileText = host.read(f)?.toString(); - if (fileText) { - let updateFile = false; - const xmldoc = new XmlDocument(fileText); - xmldoc.childrenNamed('ItemGroup').forEach((itemGroup) => { - itemGroup.childrenNamed('PackageReference').forEach((reference) => { - console.log( - reference.attr['Include'], - reference.attr['Version'], - ':', - packageName, - version, - ); - if ( - reference.attr['Include'] === packageName && - reference.attr['Version'] !== version - ) { - console.warn( - `Updating ${projectName} to use ${packageName} v${version}`, - ); - reference.attr['Version'] = version; - updateFile = true; - } - }); - }); - if (updateFile) { - host.write(f, xmldoc.toString()); + const projects = getNxDotnetProjects(host); + for (const [projectName, configuration] of projects.entries()) { + const projectFiles = getProjectFilesForProject(host, configuration); + for (const f of projectFiles) { + const xmldoc = readXml(host, f); + let updateFile = false; + await iterateChildrenByPath( + xmldoc, + 'ItemGroup.PackageReference', + (reference) => { + if ( + reference.attr['Include'] === packageName && + reference.attr['Version'] !== version + ) { + console.warn( + `Updating ${projectName} to use ${packageName} v${version}`, + ); + reference.attr['Version'] = version; + updateFile = true; } - } - }); + }, + ); + if (updateFile) { + host.write(f, xmldoc.toString()); + } } - }); + } } diff --git a/packages/core/src/graph/process-project-graph.ts b/packages/core/src/graph/process-project-graph.ts index 223ca5e3..d1ae351b 100644 --- a/packages/core/src/graph/process-project-graph.ts +++ b/packages/core/src/graph/process-project-graph.ts @@ -10,7 +10,7 @@ import { getDependantProjectsForNxProject } from '@nx-dotnet/utils'; export function processProjectGraph( graph: ProjectGraph, - context: ProjectGraphProcessorContext + context: ProjectGraphProcessorContext, ) { const builder = new ProjectGraphBuilder(graph); @@ -21,7 +21,7 @@ export function processProjectGraph( } } catch { console.warn( - `nx-dotnet encountered an error parsing dependencies for ${name}` + `nx-dotnet encountered an error parsing dependencies for ${name}`, ); } }); @@ -33,13 +33,13 @@ function visitProject( builder: ProjectGraphBuilder, context: ProjectGraphProcessorContext, project: ProjectConfiguration, - projectName: string + projectName: string, ) { getDependantProjectsForNxProject( projectName, context.workspace, (projectConfig, dependencyName) => { builder.addDependency(DependencyType.static, projectName, dependencyName); - } + }, ); } diff --git a/packages/core/src/models/build-executor-configuration.ts b/packages/core/src/models/build-executor-configuration.ts index aaa2d0c0..8c5737aa 100644 --- a/packages/core/src/models/build-executor-configuration.ts +++ b/packages/core/src/models/build-executor-configuration.ts @@ -4,7 +4,7 @@ import { TargetConfiguration } from '@nrwl/devkit'; * Returns a TargetConfiguration for the nx-dotnet/core:build executor */ export function GetBuildExecutorConfiguration( - projectRoot: string + projectRoot: string, ): BuildExecutorConfiguration { const outputDirectory = `dist/${projectRoot}`; diff --git a/packages/core/src/models/test-executor-configuration.ts b/packages/core/src/models/test-executor-configuration.ts index 5d9ed2e2..515d75d8 100644 --- a/packages/core/src/models/test-executor-configuration.ts +++ b/packages/core/src/models/test-executor-configuration.ts @@ -1,7 +1,7 @@ import { TargetConfiguration } from '@nrwl/devkit'; export function GetTestExecutorConfig( - projectName?: string + projectName?: string, ): TestTargetConfiguration { return { executor: '@nx-dotnet/core:test', diff --git a/packages/dotnet/package.json b/packages/dotnet/package.json index 855d8b39..4012619b 100644 --- a/packages/dotnet/package.json +++ b/packages/dotnet/package.json @@ -16,4 +16,4 @@ "bugs": { "url": "https://github.com/nx-dotnet/nx-dotnet/issues/new?assignees=&labels=bug%2C+needs-triage&template=bug_report.md&title=%5BBUG%5D+" } -} \ No newline at end of file +} diff --git a/packages/dotnet/src/lib/core/dotnet.factory.ts b/packages/dotnet/src/lib/core/dotnet.factory.ts index 2be2b28f..f6bdc5ba 100644 --- a/packages/dotnet/src/lib/core/dotnet.factory.ts +++ b/packages/dotnet/src/lib/core/dotnet.factory.ts @@ -26,7 +26,7 @@ export function dotnetFactory(): LoadedCLI { }; } catch (e) { throw new Error( - 'dotnet not installed. Local support not yet added https://github.com/AgentEnder/nx-dotnet/issues/3' + 'dotnet not installed. Local support not yet added https://github.com/AgentEnder/nx-dotnet/issues/3', ); } } diff --git a/packages/typescript/package.json b/packages/typescript/package.json index 40f7ba18..5479d491 100644 --- a/packages/typescript/package.json +++ b/packages/typescript/package.json @@ -20,4 +20,4 @@ "bugs": { "url": "https://github.com/nx-dotnet/nx-dotnet/issues/new?assignees=&labels=bug%2C+needs-triage&template=bug_report.md&title=%5BBUG%5D+" } -} \ No newline at end of file +} diff --git a/packages/typescript/src/generators/typescript/generator.ts b/packages/typescript/src/generators/typescript/generator.ts index 28816fd3..aa3cb572 100644 --- a/packages/typescript/src/generators/typescript/generator.ts +++ b/packages/typescript/src/generators/typescript/generator.ts @@ -21,7 +21,7 @@ interface NormalizedSchema extends TypescriptGeneratorSchema { function normalizeOptions( host: Tree, - options: TypescriptGeneratorSchema + options: TypescriptGeneratorSchema, ): NormalizedSchema { const name = names(options.name).fileName; const projectDirectory = options.directory @@ -53,7 +53,7 @@ function addFiles(host: Tree, options: NormalizedSchema) { host, path.join(__dirname, 'files'), options.projectRoot, - templateOptions + templateOptions, ); } diff --git a/packages/utils/package.json b/packages/utils/package.json index 1416cd2a..a2cb01b6 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -5,4 +5,4 @@ "dependencies": {}, "license": "MIT", "version": "0.3.0-dev.4" -} \ No newline at end of file +} diff --git a/packages/utils/src/lib/utility-functions/args.ts b/packages/utils/src/lib/utility-functions/args.ts index 780325c8..096c1899 100644 --- a/packages/utils/src/lib/utility-functions/args.ts +++ b/packages/utils/src/lib/utility-functions/args.ts @@ -4,13 +4,13 @@ export function isDryRun(): boolean { export function swapKeysUsingMap( object: Record, - map: Record + map: Record, ): Record { return Object.fromEntries( Object.entries(object).map(([key, value]) => [ key in map ? map[key] : key, value, - ]) + ]), ); } @@ -18,7 +18,7 @@ export function swapArrayFieldValueUsingMap( array: T[], field: keyof T, // eslint-disable-next-line @typescript-eslint/no-explicit-any - map: any + map: any, ) { return array.map((x) => ({ ...x, diff --git a/packages/utils/src/lib/utility-functions/config.ts b/packages/utils/src/lib/utility-functions/config.ts index 29ef2a86..99aba37f 100644 --- a/packages/utils/src/lib/utility-functions/config.ts +++ b/packages/utils/src/lib/utility-functions/config.ts @@ -1,4 +1,5 @@ import { readJson, Tree, writeJson } from '@nrwl/devkit'; + import { CONFIG_FILE_PATH } from '../constants'; import { NxDotnetConfig } from '../models'; diff --git a/packages/utils/src/lib/utility-functions/glob.ts b/packages/utils/src/lib/utility-functions/glob.ts index 4aab876c..a4a7e459 100644 --- a/packages/utils/src/lib/utility-functions/glob.ts +++ b/packages/utils/src/lib/utility-functions/glob.ts @@ -6,7 +6,7 @@ import * as _glob from 'glob'; */ export function glob(path: string): Promise { return new Promise((resolve, reject) => - _glob(path, (err, matches) => (err ? reject() : resolve(matches))) + _glob(path, (err, matches) => (err ? reject() : resolve(matches))), ); } @@ -16,15 +16,15 @@ export function findProjectFileInPath(path: string): Promise { return glob(`${path}/**/*.*proj`).then((results) => { if (!results || results.length === 0) { throw new Error( - "Unable to find a build-able project within project's source directory!" + "Unable to find a build-able project within project's source directory!", ); } if (results.length > 1) { throw new Error( `More than one build-able projects are contained within the project's source directory! \r\n ${results.join( - ', \r\n' - )}` + ', \r\n', + )}`, ); } return results[0]; @@ -37,15 +37,15 @@ export function findProjectFileInPathSync(path: string): string { const results = _glob.sync(`${path}/**/*.*proj`); if (!results || results.length === 0) { throw new Error( - "Unable to find a build-able project within project's source directory!" + "Unable to find a build-able project within project's source directory!", ); } if (results.length > 1) { throw new Error( `More than one build-able projects are contained within the project's source directory! \r\n ${results.join( - ', \r\n' - )}` + ', \r\n', + )}`, ); } return results[0]; diff --git a/packages/utils/src/lib/utility-functions/index.ts b/packages/utils/src/lib/utility-functions/index.ts index 5a569c9c..0cd5fb02 100644 --- a/packages/utils/src/lib/utility-functions/index.ts +++ b/packages/utils/src/lib/utility-functions/index.ts @@ -5,3 +5,4 @@ export * from './parameters'; export * from './rimraf'; export * from './workspace'; export * from './config'; +export * from './xml'; diff --git a/packages/utils/src/lib/utility-functions/rimraf.ts b/packages/utils/src/lib/utility-functions/rimraf.ts index 8a58194c..a7c25479 100644 --- a/packages/utils/src/lib/utility-functions/rimraf.ts +++ b/packages/utils/src/lib/utility-functions/rimraf.ts @@ -4,6 +4,6 @@ export async function rimraf(path: string) { return new Promise((resolve) => rimrafExternal(path, () => { resolve(); - }) + }), ); } diff --git a/packages/utils/src/lib/utility-functions/workspace.ts b/packages/utils/src/lib/utility-functions/workspace.ts index 8ddc66eb..faa1bb07 100644 --- a/packages/utils/src/lib/utility-functions/workspace.ts +++ b/packages/utils/src/lib/utility-functions/workspace.ts @@ -1,13 +1,20 @@ -import { ProjectConfiguration, WorkspaceJsonConfiguration } from '@nrwl/devkit'; +import { + getProjects, + NxJsonProjectConfiguration, + ProjectConfiguration, + Tree, + WorkspaceJsonConfiguration, +} from '@nrwl/devkit'; import { readFileSync } from 'fs'; import { isAbsolute, resolve } from 'path'; import { XmlDocument, XmlElement } from 'xmldoc'; +import { NXDOTNET_TAG } from '../constants'; import { findProjectFileInPath, findProjectFileInPathSync } from './glob'; export async function getProjectFileForNxProject( - project: ProjectConfiguration + project: ProjectConfiguration, ) { const srcDirectory = project.root; return findProjectFileInPath(srcDirectory); @@ -21,7 +28,10 @@ export function getProjectFileForNxProjectSync(project: ProjectConfiguration) { export function getDependantProjectsForNxProject( targetProject: string, workspaceConfiguration: WorkspaceJsonConfiguration, - forEachCallback?: (project: ProjectConfiguration, projectName: string) => void + forEachCallback?: ( + project: ProjectConfiguration, + projectName: string, + ) => void, ): { [projectName: string]: ProjectConfiguration; } { @@ -33,11 +43,11 @@ export function getDependantProjectsForNxProject( }); const netProjectFilePath = getProjectFileForNxProjectSync( - workspaceConfiguration.projects[targetProject] + workspaceConfiguration.projects[targetProject], ); const xml: XmlDocument = new XmlDocument( - readFileSync(netProjectFilePath).toString() + readFileSync(netProjectFilePath).toString(), ); xml.childrenNamed('ItemGroup').forEach((itemGroup) => @@ -49,7 +59,7 @@ export function getDependantProjectsForNxProject( } else { absoluteFilePath = resolve( netProjectFilePath.split('/').slice(0, -1).join('/'), - includeFilePath + includeFilePath, ); } @@ -58,15 +68,43 @@ export function getDependantProjectsForNxProject( if (forEachCallback) { forEachCallback( workspaceConfiguration.projects[dependency], - dependency + dependency, ); } dependantProjects[dependency] = workspaceConfiguration.projects[dependency]; } }); - }) + }), ); return dependantProjects; } + +export function getNxDotnetProjects( + host: Tree, +): Map { + const allProjects = getProjects(host); + + for (const key in allProjects) { + const p = allProjects.get(key); + if (!p?.tags?.includes(NXDOTNET_TAG)) { + allProjects.delete(key); + } + } + + return allProjects; +} + +export function getProjectFilesForProject( + host: Tree, + project: ProjectConfiguration | undefined, +) { + if (!project?.sourceRoot) { + throw new Error('Unable to read source root for project!'); + } + return host + .children(project.sourceRoot) + .filter((x) => x.endsWith('proj')) + .map((x) => `${project.sourceRoot}/${x}`); +} diff --git a/packages/utils/src/lib/utility-functions/xml.ts b/packages/utils/src/lib/utility-functions/xml.ts new file mode 100644 index 00000000..32786f40 --- /dev/null +++ b/packages/utils/src/lib/utility-functions/xml.ts @@ -0,0 +1,30 @@ +import { Tree } from '@nrwl/devkit'; + +import { XmlDocument, XmlElement } from 'xmldoc'; + +export function readXml(host: Tree, path: string): XmlDocument { + const fileText = host.read(path)?.toString(); + if (!fileText) { + throw new Error(`Unable to read ${path}`); + } + return new XmlDocument(fileText); +} + +export async function iterateChildrenByPath( + root: XmlElement, + path: string, + callback: + | ((element: XmlElement) => Promise) + | ((element: XmlElement) => void), +) { + const parts = path.split('.'); + const children = root.childrenNamed(parts[0]); + for (const childNode of children) { + if (parts.length > 1) { + const nextPath = parts.slice(1, parts.length).join('.'); + await iterateChildrenByPath(childNode, nextPath, callback); + } else { + await callback(childNode); + } + } +} diff --git a/tools/scripts/build.ts b/tools/scripts/build.ts index 6af578c7..121876bb 100644 --- a/tools/scripts/build.ts +++ b/tools/scripts/build.ts @@ -5,7 +5,7 @@ export function build( nxVersion, ngCliVersion, typescriptVersion, - prettierVersion + prettierVersion, ) { try { execSync('npx nx run-many --target=build --all', { @@ -20,7 +20,7 @@ export function build( const files = [ ...['core', 'dotnet', 'typescript', 'utils'].map( - (f) => `${f}/package.json` + (f) => `${f}/package.json`, ), ].map((f) => `${BUILD_DIR}/${f}`); @@ -29,7 +29,7 @@ export function build( content = content .replace( /exports.nxVersion = '\*'/g, - `exports.nxVersion = '${nxVersion}'` + `exports.nxVersion = '${nxVersion}'`, ) .replace(/NX_VERSION/g, nxVersion) .replace(/TYPESCRIPT_VERSION/g, typescriptVersion) diff --git a/tools/scripts/e2e.ts b/tools/scripts/e2e.ts index 7419d7bb..6dc13f53 100644 --- a/tools/scripts/e2e.ts +++ b/tools/scripts/e2e.ts @@ -17,7 +17,7 @@ export const getDirectories = (source) => function updateVersion(packagePath) { const content = JSON.parse( - readFileSync(packagePath + '/package.json').toString() + readFileSync(packagePath + '/package.json').toString(), ); content.version = process.env.PUBLISHED_VERSION; Object.entries(content.dependencies || {}).forEach(([key, value]) => { @@ -27,7 +27,7 @@ function updateVersion(packagePath) { }); writeFileSync( packagePath + '/package.json', - JSON.stringify(content, null, 2) + JSON.stringify(content, null, 2), ); } @@ -51,8 +51,8 @@ function publishPackage(packagePath, npmMajorVersion: number) { process.env.npm_config_registry }\n${process.env.npm_config_registry.replace( 'http:', - '' - )}/:_authToken=fake` + '', + )}/:_authToken=fake`, ); } @@ -92,7 +92,7 @@ async function runTest() { if (process.argv[3] === 'affected') { const affected = execSync( - `npx nx print-affected --base=origin/master --select=projects` + `npx nx print-affected --base=origin/master --select=projects`, ) .toString() .split(',') @@ -129,7 +129,7 @@ async function runTest() { NPM_CONFIG_REGISTRY: 'http://localhost:4872', YARN_REGISTRY: 'http://localhost:4872', }, - } + }, ); } else { execSync(`yarn nx run-many --target=e2e --all`, { diff --git a/tools/scripts/patch-package-versions/index.ts b/tools/scripts/patch-package-versions/index.ts index 2f7f32f9..63b85b26 100644 --- a/tools/scripts/patch-package-versions/index.ts +++ b/tools/scripts/patch-package-versions/index.ts @@ -36,7 +36,7 @@ export function PatchPackageVersions(newVersion: string, updateGit = true) { `git commit ${ idx > 0 ? '--amend --no-edit' : '-m "chore(release): bump version"' }`, - { stdio: ['ignore', 'inherit', 'inherit'] } + { stdio: ['ignore', 'inherit', 'inherit'] }, ); } }); diff --git a/tools/utils/get-affected.ts b/tools/utils/get-affected.ts index 9556a449..0f737e06 100644 --- a/tools/utils/get-affected.ts +++ b/tools/utils/get-affected.ts @@ -2,7 +2,7 @@ import { execSync } from 'child_process'; export function getAffectedProjects( all = process.env.ALL === 'true', - specific = process.env.SPECIFIC_PROJECT + specific = process.env.SPECIFIC_PROJECT, ) { let projects = []; if (specific && specific !== 'null') {