@jsenv/monorepo 0.4.11 → 0.4.13
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.4.
|
|
3
|
+
"version": "0.4.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Helpers to manage packages in a monorepo",
|
|
6
6
|
"repository": {
|
|
@@ -23,10 +23,10 @@
|
|
|
23
23
|
"/src/"
|
|
24
24
|
],
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@jsenv/filesystem": "4.15.
|
|
27
|
-
"@jsenv/humanize": "1.8.
|
|
28
|
-
"@jsenv/package-publish": "1.11.
|
|
29
|
-
"@jsenv/urls": "2.9.
|
|
26
|
+
"@jsenv/filesystem": "4.15.28",
|
|
27
|
+
"@jsenv/humanize": "1.8.6",
|
|
28
|
+
"@jsenv/package-publish": "1.11.59",
|
|
29
|
+
"@jsenv/urls": "2.9.17",
|
|
30
30
|
"semver": "7.8.5"
|
|
31
31
|
},
|
|
32
32
|
"publishConfig": {
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { createTaskLog } from "@jsenv/humanize";
|
|
2
|
+
import {
|
|
3
|
+
checkVersionStatusInRegistry,
|
|
4
|
+
VERSION_STATUS,
|
|
5
|
+
} from "@jsenv/package-publish/src/internal/staged_version.js";
|
|
6
|
+
import {
|
|
7
|
+
compareTwoPackageVersions,
|
|
8
|
+
VERSION_COMPARE_RESULTS,
|
|
9
|
+
} from "./compare_two_package_versions.js";
|
|
10
|
+
|
|
11
|
+
/*
|
|
12
|
+
* The workspace packages whose version is not published on the registry, each
|
|
13
|
+
* with its status there: absent, or staged (the registry has it but does not
|
|
14
|
+
* expose it yet)
|
|
15
|
+
*/
|
|
16
|
+
export const collectUnpublishedPackages = async ({
|
|
17
|
+
workspacePackages,
|
|
18
|
+
registryLatestVersions,
|
|
19
|
+
registryUrl,
|
|
20
|
+
token,
|
|
21
|
+
}) => {
|
|
22
|
+
const aheadPackageNames = Object.keys(workspacePackages).filter(
|
|
23
|
+
(packageName) => {
|
|
24
|
+
const workspacePackage = workspacePackages[packageName];
|
|
25
|
+
const registryLatestVersion = registryLatestVersions[packageName];
|
|
26
|
+
if (registryLatestVersion === null) {
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
const result = compareTwoPackageVersions(
|
|
30
|
+
workspacePackage.packageObject.version,
|
|
31
|
+
registryLatestVersion,
|
|
32
|
+
);
|
|
33
|
+
return (
|
|
34
|
+
result === VERSION_COMPARE_RESULTS.GREATER ||
|
|
35
|
+
result === VERSION_COMPARE_RESULTS.DIFF_TAG
|
|
36
|
+
);
|
|
37
|
+
},
|
|
38
|
+
);
|
|
39
|
+
if (aheadPackageNames.length === 0) {
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const statusTask = createTaskLog(`check versions on registry`);
|
|
44
|
+
let packageInfos;
|
|
45
|
+
try {
|
|
46
|
+
packageInfos = await Promise.all(
|
|
47
|
+
aheadPackageNames.map(async (packageName) => {
|
|
48
|
+
const workspacePackage = workspacePackages[packageName];
|
|
49
|
+
const packageVersion = workspacePackage.packageObject.version;
|
|
50
|
+
const versionStatus = await checkVersionStatusInRegistry({
|
|
51
|
+
registryUrl,
|
|
52
|
+
packageName,
|
|
53
|
+
packageVersion,
|
|
54
|
+
token,
|
|
55
|
+
});
|
|
56
|
+
return {
|
|
57
|
+
packageName,
|
|
58
|
+
packageVersion,
|
|
59
|
+
packageSlug: `${packageName}@${packageVersion}`,
|
|
60
|
+
rootDirectoryUrl: new URL("./", workspacePackage.packageUrl),
|
|
61
|
+
versionStatus,
|
|
62
|
+
};
|
|
63
|
+
}),
|
|
64
|
+
);
|
|
65
|
+
statusTask.done();
|
|
66
|
+
} catch (e) {
|
|
67
|
+
statusTask.fail();
|
|
68
|
+
throw e;
|
|
69
|
+
}
|
|
70
|
+
return packageInfos.filter(
|
|
71
|
+
({ versionStatus }) => versionStatus !== VERSION_STATUS.PUBLISHED,
|
|
72
|
+
);
|
|
73
|
+
};
|
package/src/main.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { publishPackages } from "./publish_packages.js";
|
|
2
2
|
export { syncPackagesVersions } from "./sync_packages_versions.js";
|
|
3
3
|
export { upgradeExternalVersions } from "./upgrade_external_versions.js";
|
|
4
|
+
export { waitForPackagesPublication } from "./wait_for_packages_publication.js";
|
package/src/publish_packages.js
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
import { createLogger,
|
|
1
|
+
import { createLogger, UNICODE } from "@jsenv/humanize";
|
|
2
2
|
import { publish } from "@jsenv/package-publish/src/internal/publish.js";
|
|
3
3
|
import {
|
|
4
|
-
checkVersionStatusInRegistry,
|
|
5
4
|
VERSION_STATUS,
|
|
6
5
|
waitForStagedVersionToLand,
|
|
7
6
|
} from "@jsenv/package-publish/src/internal/staged_version.js";
|
|
8
|
-
import {
|
|
9
|
-
compareTwoPackageVersions,
|
|
10
|
-
VERSION_COMPARE_RESULTS,
|
|
11
|
-
} from "./internal/compare_two_package_versions.js";
|
|
7
|
+
import { collectUnpublishedPackages } from "./internal/collect_unpublished_packages.js";
|
|
12
8
|
import { syncPackagesVersions } from "./sync_packages_versions.js";
|
|
13
9
|
|
|
14
10
|
const REGISTRY_URL = "https://registry.npmjs.org";
|
|
@@ -16,71 +12,24 @@ const REGISTRY_URL = "https://registry.npmjs.org";
|
|
|
16
12
|
export const publishPackages = async ({ directoryUrl, packagesRelations }) => {
|
|
17
13
|
// the sync check already read the package.json files and the registry;
|
|
18
14
|
// it hands both back so that publishing does not do it a second time
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
const { workspacePackages, registryLatestVersions } = syncResult;
|
|
27
|
-
const toPublishPackageNames = Object.keys(workspacePackages).filter(
|
|
28
|
-
(packageName) => {
|
|
29
|
-
const workspacePackage = workspacePackages[packageName];
|
|
30
|
-
const registryLatestVersion = registryLatestVersions[packageName];
|
|
31
|
-
if (registryLatestVersion === null) {
|
|
32
|
-
return true;
|
|
33
|
-
}
|
|
34
|
-
const result = compareTwoPackageVersions(
|
|
35
|
-
workspacePackage.packageObject.version,
|
|
36
|
-
registryLatestVersion,
|
|
37
|
-
);
|
|
38
|
-
return (
|
|
39
|
-
result === VERSION_COMPARE_RESULTS.GREATER ||
|
|
40
|
-
result === VERSION_COMPARE_RESULTS.DIFF_TAG
|
|
41
|
-
);
|
|
42
|
-
},
|
|
43
|
-
);
|
|
44
|
-
if (toPublishPackageNames.length === 0) {
|
|
45
|
-
console.log(`${UNICODE.OK} packages are published on registry`);
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
|
|
15
|
+
const { workspacePackages, registryLatestVersions } =
|
|
16
|
+
await ensureVersionsAreInSync({
|
|
17
|
+
directoryUrl,
|
|
18
|
+
packagesRelations,
|
|
19
|
+
});
|
|
49
20
|
const token = process.env.NPM_TOKEN;
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const versionStatus = await checkVersionStatusInRegistry({
|
|
58
|
-
registryUrl: REGISTRY_URL,
|
|
59
|
-
packageName,
|
|
60
|
-
packageVersion,
|
|
61
|
-
token,
|
|
62
|
-
});
|
|
63
|
-
return {
|
|
64
|
-
packageName,
|
|
65
|
-
packageVersion,
|
|
66
|
-
packageSlug: `${packageName}@${packageVersion}`,
|
|
67
|
-
rootDirectoryUrl: new URL("./", workspacePackage.packageUrl),
|
|
68
|
-
versionStatus,
|
|
69
|
-
};
|
|
70
|
-
}),
|
|
71
|
-
);
|
|
72
|
-
statusTask.done();
|
|
73
|
-
} catch (e) {
|
|
74
|
-
statusTask.fail();
|
|
75
|
-
throw e;
|
|
76
|
-
}
|
|
77
|
-
const packagesToPublish = packageInfos.filter(
|
|
21
|
+
const unpublishedPackages = await collectUnpublishedPackages({
|
|
22
|
+
workspacePackages,
|
|
23
|
+
registryLatestVersions,
|
|
24
|
+
registryUrl: REGISTRY_URL,
|
|
25
|
+
token,
|
|
26
|
+
});
|
|
27
|
+
const packagesToPublish = unpublishedPackages.filter(
|
|
78
28
|
({ versionStatus }) => versionStatus === VERSION_STATUS.ABSENT,
|
|
79
29
|
);
|
|
80
|
-
const stagedPackages =
|
|
30
|
+
const stagedPackages = unpublishedPackages.filter(
|
|
81
31
|
({ versionStatus }) => versionStatus === VERSION_STATUS.STAGED,
|
|
82
32
|
);
|
|
83
|
-
|
|
84
33
|
if (packagesToPublish.length === 0 && stagedPackages.length === 0) {
|
|
85
34
|
console.log(`${UNICODE.OK} packages are published on registry`);
|
|
86
35
|
return;
|
|
@@ -107,20 +56,24 @@ export const publishPackages = async ({ directoryUrl, packagesRelations }) => {
|
|
|
107
56
|
});
|
|
108
57
|
}
|
|
109
58
|
for (const { packageSlug, rootDirectoryUrl } of packagesToPublish) {
|
|
110
|
-
await publish({
|
|
59
|
+
const { success } = await publish({
|
|
111
60
|
logger: createLogger({ logLevel: "info" }),
|
|
112
61
|
packageSlug,
|
|
113
62
|
rootDirectoryUrl,
|
|
114
63
|
registryUrl: REGISTRY_URL,
|
|
115
64
|
token,
|
|
116
65
|
});
|
|
66
|
+
if (!success) {
|
|
67
|
+
throw new Error(`failed to publish ${packageSlug}`);
|
|
68
|
+
}
|
|
117
69
|
}
|
|
118
70
|
};
|
|
119
71
|
|
|
120
72
|
/*
|
|
121
73
|
* Publishing while package.json files are not in sync would put on the registry
|
|
122
74
|
* packages depending on versions that do not exist (or are outdated).
|
|
123
|
-
*
|
|
75
|
+
* Syncing modifies package.json files, a change to review and commit, so it is
|
|
76
|
+
* never done here: the publish fails instead.
|
|
124
77
|
*/
|
|
125
78
|
const ensureVersionsAreInSync = async ({ directoryUrl, packagesRelations }) => {
|
|
126
79
|
const {
|
|
@@ -136,19 +89,16 @@ const ensureVersionsAreInSync = async ({ directoryUrl, packagesRelations }) => {
|
|
|
136
89
|
packagesRelations,
|
|
137
90
|
});
|
|
138
91
|
if (outdatedPackageNames.length) {
|
|
139
|
-
|
|
140
|
-
`${
|
|
92
|
+
throw new Error(
|
|
93
|
+
`${outdatedPackageNames.length} packages have a version older than the one published on registry
|
|
141
94
|
- ${outdatedPackageNames.join(`
|
|
142
95
|
- `)}
|
|
143
96
|
Run "npm run monorepo:sync_versions" and review the changes before publishing`,
|
|
144
97
|
);
|
|
145
|
-
return null;
|
|
146
98
|
}
|
|
147
99
|
const outOfSyncCount = versionUpdates.length + dependencyUpdates.length;
|
|
148
|
-
if (outOfSyncCount
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
console.warn(`${UNICODE.WARNING} versions are not in sync, ${outOfSyncCount} things must be updated in package.json files
|
|
100
|
+
if (outOfSyncCount) {
|
|
101
|
+
throw new Error(`versions are not in sync, ${outOfSyncCount} things must be updated in package.json files
|
|
152
102
|
- ${[
|
|
153
103
|
...versionUpdates.map(
|
|
154
104
|
({ packageName, from, to }) => `${packageName}: ${from} -> ${to}`,
|
|
@@ -158,42 +108,8 @@ Run "npm run monorepo:sync_versions" and review the changes before publishing`,
|
|
|
158
108
|
`${packageName} -> ${dependencyName}: ${from} -> ${to}`,
|
|
159
109
|
),
|
|
160
110
|
].join(`
|
|
161
|
-
- `)}
|
|
162
|
-
|
|
163
|
-
if (!confirmed) {
|
|
164
|
-
console.log(`${UNICODE.INFO} publish aborted, versions are not in sync`);
|
|
165
|
-
return null;
|
|
166
|
-
}
|
|
167
|
-
// the dry run has mutated its own copy of the package objects; sync again on
|
|
168
|
-
// freshly read files (but with what the registry already told us) so that the
|
|
169
|
-
// updates are actually written and the package objects match the files
|
|
170
|
-
const syncResult = await syncPackagesVersions({
|
|
171
|
-
directoryUrl,
|
|
172
|
-
packagesRelations,
|
|
173
|
-
registryLatestVersions,
|
|
174
|
-
});
|
|
175
|
-
return {
|
|
176
|
-
workspacePackages: syncResult.workspacePackages,
|
|
177
|
-
registryLatestVersions,
|
|
178
|
-
};
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
const confirm = async (question) => {
|
|
182
|
-
if (!process.stdin.isTTY) {
|
|
183
|
-
console.warn(
|
|
184
|
-
`${UNICODE.FAILURE} cannot ask confirmation (stdin is not a TTY)`,
|
|
185
|
-
);
|
|
186
|
-
return false;
|
|
187
|
-
}
|
|
188
|
-
const { createInterface } = await import("node:readline/promises");
|
|
189
|
-
const readlineInterface = createInterface({
|
|
190
|
-
input: process.stdin,
|
|
191
|
-
output: process.stdout,
|
|
192
|
-
});
|
|
193
|
-
try {
|
|
194
|
-
const answer = await readlineInterface.question(`${question} (y/N) `);
|
|
195
|
-
return answer.trim().toLowerCase() === "y";
|
|
196
|
-
} finally {
|
|
197
|
-
readlineInterface.close();
|
|
111
|
+
- `)}
|
|
112
|
+
Run "npm run monorepo:sync_versions" and review the changes before publishing`);
|
|
198
113
|
}
|
|
114
|
+
return { workspacePackages, registryLatestVersions };
|
|
199
115
|
};
|
|
@@ -74,6 +74,7 @@ Use a tool like "git diff" to see the new versions and ensure this is what you w
|
|
|
74
74
|
workspacePackages,
|
|
75
75
|
registryLatestVersions,
|
|
76
76
|
outdatedPackageNames,
|
|
77
|
+
toPublishPackageNames,
|
|
77
78
|
versionUpdates,
|
|
78
79
|
dependencyUpdates,
|
|
79
80
|
};
|
|
@@ -248,6 +249,7 @@ Use a tool like "git diff" to see the new versions and ensure this is what you w
|
|
|
248
249
|
workspacePackages,
|
|
249
250
|
registryLatestVersions,
|
|
250
251
|
outdatedPackageNames,
|
|
252
|
+
toPublishPackageNames,
|
|
251
253
|
versionUpdates,
|
|
252
254
|
dependencyUpdates,
|
|
253
255
|
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Waits until every workspace package version is published on the registry.
|
|
3
|
+
* Meant for when publishing happens elsewhere (a CI workflow for instance):
|
|
4
|
+
* it tells when the versions found in package.json files can be installed.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { humanizeDuration, UNICODE } from "@jsenv/humanize";
|
|
8
|
+
import { waitForVersionInRegistry } from "@jsenv/package-publish/src/internal/staged_version.js";
|
|
9
|
+
import { collectUnpublishedPackages } from "./internal/collect_unpublished_packages.js";
|
|
10
|
+
import { collectWorkspacePackages } from "./internal/collect_workspace_packages.js";
|
|
11
|
+
import { fetchWorkspaceLatests } from "./internal/fetch_workspace_latests.js";
|
|
12
|
+
|
|
13
|
+
const REGISTRY_URL = "https://registry.npmjs.org";
|
|
14
|
+
|
|
15
|
+
export const waitForPackagesPublication = async ({
|
|
16
|
+
directoryUrl,
|
|
17
|
+
timeout = 15 * 60_000,
|
|
18
|
+
}) => {
|
|
19
|
+
const workspacePackages = await collectWorkspacePackages({ directoryUrl });
|
|
20
|
+
const registryLatestVersions = await fetchWorkspaceLatests(workspacePackages);
|
|
21
|
+
const unpublishedPackages = await collectUnpublishedPackages({
|
|
22
|
+
workspacePackages,
|
|
23
|
+
registryLatestVersions,
|
|
24
|
+
registryUrl: REGISTRY_URL,
|
|
25
|
+
});
|
|
26
|
+
if (unpublishedPackages.length === 0) {
|
|
27
|
+
console.log(`${UNICODE.OK} packages are published on registry`);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
console.log(`${UNICODE.INFO} ${unpublishedPackages.length} packages not published on registry yet
|
|
31
|
+
- ${unpublishedPackages.map(({ packageSlug }) => packageSlug).join(`
|
|
32
|
+
- `)}`);
|
|
33
|
+
for (const { packageName, packageVersion } of unpublishedPackages) {
|
|
34
|
+
await waitForVersionInRegistry({
|
|
35
|
+
registryUrl: REGISTRY_URL,
|
|
36
|
+
packageName,
|
|
37
|
+
packageVersion,
|
|
38
|
+
timeout,
|
|
39
|
+
timeoutErrorMessage: `${packageName}@${packageVersion} is still not published on ${REGISTRY_URL} after ${humanizeDuration(timeout)}. Check whatever publishes it.`,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
console.log(`${UNICODE.OK} packages are published on registry`);
|
|
43
|
+
};
|