1/**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * @format
8 */
9
10const {spawnSync} = require('child_process');
11const {writeFileSync, readFileSync} = require('fs');
12const path = require('path');
13
14const checkForGitChanges = require('./check-for-git-changes');
15const forEachPackage = require('./for-each-package');
16
17const ROOT_LOCATION = path.join(__dirname, '..', '..');
18const TEMPLATE_LOCATION = path.join(ROOT_LOCATION, 'template');
19const REPO_CONFIG_LOCATION = path.join(ROOT_LOCATION, 'repo-config');
20
21const readJSONFile = pathToFile => JSON.parse(readFileSync(pathToFile));
22
23const checkIfShouldUpdateDependencyPackageVersion = (
24  consumerPackageAbsolutePath,
25  updatedPackageName,
26  updatedPackageVersion,
27) => {
28  const consumerPackageManifestPath = path.join(
29    consumerPackageAbsolutePath,
30    'package.json',
31  );
32  const consumerPackageManifest = readJSONFile(consumerPackageManifestPath);
33
34  const dependencyVersion =
35    consumerPackageManifest.dependencies?.[updatedPackageName];
36
37  if (dependencyVersion && dependencyVersion !== '*') {
38    const updatedDependencyVersion = dependencyVersion.startsWith('^')
39      ? `^${updatedPackageVersion}`
40      : updatedPackageVersion;
41
42    if (updatedDependencyVersion !== dependencyVersion) {
43      console.log(
44        `\uD83D\uDCA1 ${consumerPackageManifest.name} was updated: now using version ${updatedPackageVersion} of ${updatedPackageName}`,
45      );
46
47      const updatedPackageManifest = {
48        ...consumerPackageManifest,
49        dependencies: {
50          ...consumerPackageManifest.dependencies,
51          [updatedPackageName]: updatedDependencyVersion,
52        },
53      };
54
55      writeFileSync(
56        consumerPackageManifestPath,
57        JSON.stringify(updatedPackageManifest, null, 2) + '\n',
58        'utf-8',
59      );
60    }
61  }
62
63  const devDependencyVersion =
64    consumerPackageManifest.devDependencies?.[updatedPackageName];
65
66  if (devDependencyVersion && devDependencyVersion !== '*') {
67    const updatedDependencyVersion = devDependencyVersion.startsWith('^')
68      ? `^${updatedPackageVersion}`
69      : updatedPackageVersion;
70
71    if (updatedDependencyVersion !== devDependencyVersion) {
72      console.log(
73        `\uD83D\uDCA1 ${consumerPackageManifest.name} was updated: now using version ${updatedPackageVersion} of ${updatedPackageName}`,
74      );
75
76      const updatedPackageManifest = {
77        ...consumerPackageManifest,
78        devDependencies: {
79          ...consumerPackageManifest.devDependencies,
80          [updatedPackageName]: updatedDependencyVersion,
81        },
82      };
83
84      writeFileSync(
85        consumerPackageManifestPath,
86        JSON.stringify(updatedPackageManifest, null, 2) + '\n',
87        'utf-8',
88      );
89    }
90  }
91};
92
93const alignPackageVersions = () => {
94  if (checkForGitChanges()) {
95    console.log(
96      '\u274c Found uncommitted changes. Please commit or stash them before running this script',
97    );
98
99    process.exit(1);
100  }
101
102  forEachPackage((packageAbsolutePath, _, packageManifest) => {
103    checkIfShouldUpdateDependencyPackageVersion(
104      ROOT_LOCATION,
105      packageManifest.name,
106      packageManifest.version,
107    );
108
109    checkIfShouldUpdateDependencyPackageVersion(
110      TEMPLATE_LOCATION,
111      packageManifest.name,
112      packageManifest.version,
113    );
114
115    checkIfShouldUpdateDependencyPackageVersion(
116      REPO_CONFIG_LOCATION,
117      packageManifest.name,
118      packageManifest.version,
119    );
120
121    forEachPackage(pathToPackage =>
122      checkIfShouldUpdateDependencyPackageVersion(
123        pathToPackage,
124        packageManifest.name,
125        packageManifest.version,
126      ),
127    );
128  });
129
130  if (!checkForGitChanges()) {
131    console.log(
132      '\u2705 There were no changes. Every consumer package uses the actual version of dependency package.',
133    );
134    return;
135  }
136
137  console.log('Running yarn to update lock file...');
138  spawnSync('yarn', ['install'], {
139    cwd: ROOT_LOCATION,
140    shell: true,
141    stdio: 'inherit',
142    encoding: 'utf-8',
143  });
144};
145
146alignPackageVersions();
147