@jsenv/monorepo 0.3.19 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/monorepo",
3
- "version": "0.3.19",
3
+ "version": "0.4.1",
4
4
  "type": "module",
5
5
  "description": "Helpers to manage packages in a monorepo",
6
6
  "repository": {
@@ -23,9 +23,9 @@
23
23
  "/src/"
24
24
  ],
25
25
  "dependencies": {
26
- "@jsenv/filesystem": "4.15.17",
26
+ "@jsenv/filesystem": "4.15.18",
27
27
  "@jsenv/humanize": "1.7.8",
28
- "@jsenv/package-publish": "1.11.47",
28
+ "@jsenv/package-publish": "1.11.48",
29
29
  "@jsenv/urls": "2.9.10",
30
30
  "semver": "7.8.5"
31
31
  },
@@ -6,8 +6,17 @@ import {
6
6
  VERSION_COMPARE_RESULTS,
7
7
  } from "./internal/compare_two_package_versions.js";
8
8
  import { fetchWorkspaceLatests } from "./internal/fetch_workspace_latests.js";
9
+ import { syncPackagesVersions } from "./sync_packages_versions.js";
10
+
11
+ export const publishPackages = async ({ directoryUrl, packagesRelations }) => {
12
+ const versionsInSync = await ensureVersionsAreInSync({
13
+ directoryUrl,
14
+ packagesRelations,
15
+ });
16
+ if (!versionsInSync) {
17
+ return;
18
+ }
9
19
 
10
- export const publishPackages = async ({ directoryUrl }) => {
11
20
  const workspacePackages = await collectWorkspacePackages({ directoryUrl });
12
21
  const registryLatestVersions = await fetchWorkspaceLatests(workspacePackages);
13
22
  const toPublishPackageNames = Object.keys(workspacePackages).filter(
@@ -58,3 +67,69 @@ export const publishPackages = async ({ directoryUrl }) => {
58
67
  Promise.resolve(),
59
68
  );
60
69
  };
70
+
71
+ /*
72
+ * Publishing while package.json files are not in sync would put on the registry
73
+ * packages depending on versions that do not exist (or are outdated).
74
+ * When versions are not in sync we ask permission to sync them before publishing.
75
+ */
76
+ const ensureVersionsAreInSync = async ({ directoryUrl, packagesRelations }) => {
77
+ const { outdatedPackageNames, versionUpdates, dependencyUpdates } =
78
+ await syncPackagesVersions({
79
+ logs: false,
80
+ dryRun: true,
81
+ directoryUrl,
82
+ packagesRelations,
83
+ });
84
+ if (outdatedPackageNames.length) {
85
+ console.warn(
86
+ `${UNICODE.FAILURE} ${outdatedPackageNames.length} packages have a version older than the one published on registry
87
+ - ${outdatedPackageNames.join(`
88
+ - `)}
89
+ Run "npm run monorepo:sync_versions" and review the changes before publishing`,
90
+ );
91
+ return false;
92
+ }
93
+ const outOfSyncCount = versionUpdates.length + dependencyUpdates.length;
94
+ if (outOfSyncCount === 0) {
95
+ return true;
96
+ }
97
+ console.warn(`${UNICODE.WARNING} versions are not in sync, ${outOfSyncCount} things must be updated in package.json files
98
+ - ${[
99
+ ...versionUpdates.map(
100
+ ({ packageName, from, to }) => `${packageName}: ${from} -> ${to}`,
101
+ ),
102
+ ...dependencyUpdates.map(
103
+ ({ packageName, dependencyName, from, to }) =>
104
+ `${packageName} -> ${dependencyName}: ${from} -> ${to}`,
105
+ ),
106
+ ].join(`
107
+ - `)}`);
108
+ const confirmed = await confirm(`Sync versions and publish?`);
109
+ if (!confirmed) {
110
+ console.log(`${UNICODE.INFO} publish aborted, versions are not in sync`);
111
+ return false;
112
+ }
113
+ await syncPackagesVersions({ directoryUrl, packagesRelations });
114
+ return true;
115
+ };
116
+
117
+ const confirm = async (question) => {
118
+ if (!process.stdin.isTTY) {
119
+ console.warn(
120
+ `${UNICODE.FAILURE} cannot ask confirmation (stdin is not a TTY)`,
121
+ );
122
+ return false;
123
+ }
124
+ const { createInterface } = await import("node:readline/promises");
125
+ const readlineInterface = createInterface({
126
+ input: process.stdin,
127
+ output: process.stdout,
128
+ });
129
+ try {
130
+ const answer = await readlineInterface.question(`${question} (y/N) `);
131
+ return answer.trim().toLowerCase() === "y";
132
+ } finally {
133
+ readlineInterface.close();
134
+ }
135
+ };
@@ -14,6 +14,7 @@ import { shouldUpdateVersion } from "./internal/should_update_version.js";
14
14
 
15
15
  export const syncPackagesVersions = async ({
16
16
  logs = true,
17
+ dryRun = false,
17
18
  directoryUrl,
18
19
  packagesRelations = {},
19
20
  }) => {
@@ -50,17 +51,24 @@ export const syncPackagesVersions = async ({
50
51
  const versionUpdates = [];
51
52
  const dependencyUpdates = [];
52
53
  if (outdatedPackageNames.length) {
53
- outdatedPackageNames.forEach((outdatedPackageName) => {
54
- const workspacePackage = workspacePackages[outdatedPackageName];
55
- workspacePackage.packageObject.version =
56
- registryLatestVersions[outdatedPackageName];
57
- workspacePackage.updateFile(workspacePackage.packageObject);
58
- });
59
- console.warn(
60
- `${UNICODE.WARNING} ${outdatedPackageNames.length} packages modified because they where outdated.
54
+ if (!dryRun) {
55
+ outdatedPackageNames.forEach((outdatedPackageName) => {
56
+ const workspacePackage = workspacePackages[outdatedPackageName];
57
+ workspacePackage.packageObject.version =
58
+ registryLatestVersions[outdatedPackageName];
59
+ workspacePackage.updateFile(workspacePackage.packageObject);
60
+ });
61
+ }
62
+ if (logs) {
63
+ console.warn(
64
+ `${UNICODE.WARNING} ${outdatedPackageNames.length} packages ${
65
+ dryRun ? "are outdated" : "modified because they where outdated"
66
+ }.
61
67
  Use a tool like "git diff" to see the new versions and ensure this is what you want`,
62
- );
68
+ );
69
+ }
63
70
  return {
71
+ outdatedPackageNames,
64
72
  versionUpdates,
65
73
  dependencyUpdates,
66
74
  };
@@ -196,23 +204,27 @@ Use a tool like "git diff" to see the new versions and ensure this is what you w
196
204
  }
197
205
  });
198
206
  }
199
- if (toPublishPackageNames.length === 0) {
200
- console.log(`${UNICODE.OK} packages are published on registry`);
201
- } else {
202
- console.log(
203
- `${UNICODE.INFO} ${
204
- toPublishPackageNames.length
205
- } packages could be published
207
+ if (logs) {
208
+ if (toPublishPackageNames.length === 0) {
209
+ console.log(`${UNICODE.OK} packages are published on registry`);
210
+ } else {
211
+ console.log(
212
+ `${UNICODE.INFO} ${
213
+ toPublishPackageNames.length
214
+ } packages could be published
206
215
  - ${toPublishPackageNames.map(
207
216
  (name) => `${name}@${workspacePackages[name].packageObject.version}`,
208
217
  ).join(`
209
218
  - `)}`,
210
- );
219
+ );
220
+ }
221
+ }
222
+ if (!dryRun) {
223
+ Object.keys(packageFilesToUpdate).forEach((packageName) => {
224
+ const workspacePackage = workspacePackages[packageName];
225
+ workspacePackage.updateFile(workspacePackage.packageObject);
226
+ });
211
227
  }
212
- Object.keys(packageFilesToUpdate).forEach((packageName) => {
213
- const workspacePackage = workspacePackages[packageName];
214
- workspacePackage.updateFile(workspacePackage.packageObject);
215
- });
216
228
  const updateCount = versionUpdates.length + dependencyUpdates.length;
217
229
  if (logs) {
218
230
  if (updateCount === 0) {
@@ -228,6 +240,7 @@ Use a tool like "git diff" to see the new versions and ensure this is what you w
228
240
  }
229
241
 
230
242
  return {
243
+ outdatedPackageNames,
231
244
  versionUpdates,
232
245
  dependencyUpdates,
233
246
  };