|
1 | 1 | #!/usr/bin/env node |
2 | | -import * as fs from 'fs'; |
3 | | -import * as path from 'path'; |
| 2 | +import { workspaces } from '@angular-devkit/core'; |
| 3 | +import { NodeJsSyncHost } from '@angular-devkit/core/node'; |
| 4 | +import { |
| 5 | + Argument, |
| 6 | + Command, |
| 7 | + Option, |
| 8 | +} from 'commander'; |
| 9 | +import { |
| 10 | + readFile, |
| 11 | + stat, |
| 12 | + writeFile, |
| 13 | +} from 'fs/promises'; |
| 14 | +import { join } from 'path'; |
4 | 15 |
|
5 | | -export interface DaffJson { |
6 | | - projects?: Record<string, { drivers?: { magento?: string } }>; |
| 16 | +import { DaffJson } from '../versioning/daff-json.type'; |
| 17 | +import { magentoFindSupportedVersion } from '../versioning/magento/find-supported'; |
| 18 | +import { MagentoVersionString } from '../versioning/magento/type'; |
| 19 | +import packagesJson from '../versioning/packages.json'; |
| 20 | +import { DaffPackagePlatformVersions } from '../versioning/packages.type'; |
| 21 | +import { DAFF_VERSIONING_PLATFORMS } from '../versioning/platforms.const'; |
| 22 | +import { DaffVersioningPlatforms } from '../versioning/platforms.type'; |
| 23 | + |
| 24 | +const DAFF_JSON_SCAFFOLD: DaffJson = { |
| 25 | + $schema: '@daffodil/commerce/daff.schema.json', |
| 26 | + projects: {}, |
| 27 | +}; |
| 28 | + |
| 29 | +interface Options { |
| 30 | + daff: string; |
| 31 | + ng: string; |
7 | 32 | } |
8 | 33 |
|
9 | | -export const syncProjects = (daff: DaffJson, angular: any): any => { |
| 34 | +export const syncProjects = (daff: DaffJson, angular: workspaces.WorkspaceDefinition, packages: DaffPackagePlatformVersions) => { |
10 | 35 | for (const [projectName, cfg] of Object.entries(daff.projects ?? {})) { |
11 | | - const version = cfg.drivers?.magento; |
12 | | - if (!version) { |
13 | | - throw new Error( |
14 | | - `Project '${projectName}' in daff.json is missing a driver version; cannot sync.`, |
15 | | - ); |
16 | | - } |
| 36 | + if (cfg.drivers) { |
| 37 | + for (const [platform, version] of Object.entries(cfg.drivers)) { |
| 38 | + if (!version) { |
| 39 | + throw new Error( |
| 40 | + `Project '${projectName}', platform ${platform} in daff.json is missing a driver version; cannot sync.`, |
| 41 | + ); |
| 42 | + } |
17 | 43 |
|
18 | | - const project = angular.projects?.[projectName]; |
19 | | - if (!project) { |
20 | | - throw new Error(`Project '${projectName}' not found in angular.json.`); |
| 44 | + const project = angular.projects.get(projectName); |
| 45 | + if (!project) { |
| 46 | + throw new Error(`Project '${projectName}' not found in angular.json.`); |
| 47 | + } |
| 48 | + const target = project.targets.get('build'); |
| 49 | + if (!target) { |
| 50 | + throw new Error(`Build configuration not found in '${projectName}'`); |
| 51 | + } |
| 52 | + const conditions = Object.entries(packages[platform]).reduce((acc, [packageName, versions]) => { |
| 53 | + if (platform === 'magento') { |
| 54 | + const supportedVersion = magentoFindSupportedVersion(versions, version); |
| 55 | + if (supportedVersion) { |
| 56 | + acc.push(`${packageName}-${platform}-${supportedVersion}`); |
| 57 | + } else { |
| 58 | + console.warn(`No supported ${platform} version found for @daffodil/${packageName}. Supported versions are ${versions}`); |
| 59 | + } |
| 60 | + } |
| 61 | + return acc; |
| 62 | + }, <Array<string>>[]); |
| 63 | + target.options ??= {}; |
| 64 | + target.options.conditions = conditions; |
| 65 | + } |
21 | 66 | } |
22 | | - |
23 | | - project.architect ??= {}; |
24 | | - project.architect.build ??= {}; |
25 | | - project.architect.build.configurations ??= {}; |
26 | | - project.architect.build.configurations.production ??= {}; |
27 | | - project.architect.build.configurations.production.conditions = [`magento-${version}`]; |
28 | 67 | } |
29 | 68 |
|
30 | 69 | return angular; |
31 | 70 | }; |
32 | 71 |
|
33 | | -const main = (): void => { |
34 | | - const [, , cmd] = process.argv; |
35 | | - if (cmd !== 'sync') { |
36 | | - console.error('Usage: daff sync'); |
37 | | - process.exit(1); |
38 | | - } |
| 72 | +const daffJson = (path: string) => ({ |
| 73 | + read: async () => { |
| 74 | + try { |
| 75 | + return <DaffJson>JSON.parse(await readFile(path, 'utf-8')); |
| 76 | + } catch (error: any) { |
| 77 | + throw new Error(`Failed to parse daff.json: ${error.message}`); |
| 78 | + } |
| 79 | + }, |
| 80 | + write: (daff: DaffJson) => { |
| 81 | + try { |
| 82 | + return writeFile(path, JSON.stringify(daff, null, 2), 'utf-8'); |
| 83 | + } catch (error: any) { |
| 84 | + throw new Error(`Failed to save daff.json: ${error.message}`); |
| 85 | + } |
| 86 | + }, |
| 87 | +}); |
39 | 88 |
|
40 | | - const cwd = process.cwd(); |
41 | | - const daffPath = path.join(cwd, 'daff.json'); |
42 | | - const ngPath = path.join(cwd, 'angular.json'); |
| 89 | +const ngJson = (path: string) => { |
| 90 | + const host = workspaces.createWorkspaceHost(new NodeJsSyncHost()); |
| 91 | + return { |
| 92 | + read: async () => { |
| 93 | + try { |
| 94 | + return (await workspaces.readWorkspace(path, host)).workspace; |
| 95 | + } catch (error: any) { |
| 96 | + throw new Error(`Failed to parse angular.json: ${error.message}`); |
| 97 | + } |
| 98 | + }, |
| 99 | + write: (wksp: workspaces.WorkspaceDefinition) => workspaces.writeWorkspace(wksp, host, path), |
| 100 | + }; |
| 101 | +}; |
43 | 102 |
|
44 | | - if (!fs.existsSync(daffPath)) { |
45 | | - console.error(`daff.json not found at ${daffPath}`); |
46 | | - process.exit(1); |
47 | | - } |
48 | | - if (!fs.existsSync(ngPath)) { |
49 | | - console.error(`angular.json not found at ${ngPath}`); |
50 | | - process.exit(1); |
51 | | - } |
| 103 | +const main = () => { |
| 104 | + const program = new Command('daff'); |
52 | 105 |
|
53 | | - const daff = <DaffJson>JSON.parse(fs.readFileSync(daffPath, 'utf-8')); |
54 | | - const angular = JSON.parse(fs.readFileSync(ngPath, 'utf-8')); |
| 106 | + const sync = async () => { |
| 107 | + const opts = program.opts<Options>(); |
| 108 | + const { read, write } = await ngJson(opts.ng); |
| 109 | + const ng = syncProjects(await daffJson(opts.daff).read(), await read(), <any>packagesJson); |
| 110 | + await write(ng); |
| 111 | + }; |
| 112 | + const version = async (project: string, platform: DaffVersioningPlatforms, v: MagentoVersionString) => { |
| 113 | + const opts = program.opts<Options>(); |
| 114 | + const { |
| 115 | + read, |
| 116 | + write, |
| 117 | + } = daffJson(opts.daff); |
| 118 | + const daff = await stat(opts.daff) |
| 119 | + ? await read() |
| 120 | + : { ...DAFF_JSON_SCAFFOLD }; |
| 121 | + daff.projects ??= {}; |
| 122 | + daff.projects[project] ??= {}; |
| 123 | + daff.projects[project].drivers ??= {}; |
| 124 | + daff.projects[project].drivers[platform] = v; |
| 125 | + await write(daff); |
| 126 | + await sync(); |
| 127 | + }; |
55 | 128 |
|
56 | | - try { |
57 | | - syncProjects(daff, angular); |
58 | | - } catch (e) { |
59 | | - console.error((<Error>e).message); |
60 | | - process.exit(1); |
61 | | - } |
| 129 | + const cwd = process.cwd(); |
| 130 | + |
| 131 | + program.addOption(new Option('-d, --daff <path>', 'Path to daff.json').default(join(cwd, 'daff.json'))); |
| 132 | + program.addOption(new Option('-a, --ng <path>', 'Path to angular.json').default(join(cwd, 'angular.json'))); |
| 133 | + |
| 134 | + program.addCommand(new Command('sync').action(sync)); |
| 135 | + program.addCommand(new Command('version') |
| 136 | + .addArgument(new Argument('project', 'The project for which to set a platform version')) |
| 137 | + .addArgument(new Argument('platform', 'The platform for which to set a version').choices(DAFF_VERSIONING_PLATFORMS)) |
| 138 | + .addArgument(new Argument('version', 'The version to set for the specified project and platform')) |
| 139 | + .action(version), |
| 140 | + ); |
62 | 141 |
|
63 | | - fs.writeFileSync(ngPath, JSON.stringify(angular, null, 2) + '\n'); |
64 | | - console.warn('angular.json updated.'); |
| 142 | + program.parse(); |
65 | 143 | }; |
66 | 144 |
|
67 | 145 | if (require.main === module) { |
|
0 commit comments