Skip to content

Commit cc6da58

Browse files
authored
fix(build): fix package release ordering (#7829)
1 parent db78633 commit cc6da58

3 files changed

Lines changed: 141 additions & 1 deletion

File tree

scripts/update-versions/getChangedPackages.mjs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import { dirname, join, relative } from "node:path";
1414
import { fileURLToPath } from "node:url";
1515

16+
import { Graph } from "./lib/Graph.mjs";
1617
import {
1718
getLernaList,
1819
getLocalChangedPackagesManifest,
@@ -37,7 +38,8 @@ const relativeLocation = (pkg) => {
3738
location: relative(root, pkg.location),
3839
};
3940
};
40-
const list = [...linked, ...unlinked].map(relativeLocation);
41+
42+
const list = Graph.toposort([...unlinked, ...linked].map(relativeLocation));
4143

4244
/*
4345
[

scripts/update-versions/lib/Graph.mjs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
import fs from "node:fs";
2+
import path from "node:path";
3+
4+
import { graphTest } from "./Graph.test.mjs";
5+
import { root } from "./release.mjs";
16
/**
27
* Dependency graph used to increment package versions.
38
*/
@@ -8,6 +13,47 @@ export class Graph {
813
this.down = {};
914
}
1015

16+
/**
17+
* @param _list - of items having package name and location relative to the root.
18+
* @returns sorted list.
19+
*/
20+
static toposort(_list) {
21+
const list = [..._list].sort((a, b) => {
22+
return a.name < b.name;
23+
});
24+
25+
const graph = new Graph();
26+
for (const { location } of list) {
27+
const pkgJson = JSON.parse(fs.readFileSync(path.join(root, location, "package.json"), "utf-8"));
28+
graph.register(pkgJson);
29+
}
30+
31+
const byName = Object.fromEntries(list.map((item) => [item.name, item]));
32+
33+
const visited = new Set();
34+
const sorted = [];
35+
36+
const visit = (name) => {
37+
if (visited.has(name)) {
38+
return;
39+
}
40+
visited.add(name);
41+
42+
for (const dep of graph.up[name] ?? []) {
43+
if (dep in byName) {
44+
visit(dep);
45+
}
46+
}
47+
sorted.push(byName[name]);
48+
};
49+
50+
for (const { name } of list) {
51+
visit(name);
52+
}
53+
54+
return sorted;
55+
}
56+
1157
/**
1258
* @param {string} name - of dependency to register.
1359
* @param {Record<string, string>} dependencies - its dependencies.
@@ -50,3 +96,5 @@ export class Graph {
5096
return out;
5197
}
5298
}
99+
100+
graphTest();
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import assert from "node:assert";
2+
3+
import { Graph } from "./Graph.mjs";
4+
5+
export function graphTest() {
6+
const list = [
7+
{ name: "@aws-sdk/client-s3", location: "clients/client-s3" },
8+
{ name: "@aws-sdk/core", location: "packages-internal/core" },
9+
{ name: "@aws-sdk/crc64-nvme", location: "packages-internal/crc64-nvme" },
10+
{ name: "@aws-sdk/credential-provider-env", location: "packages-internal/credential-provider-env" },
11+
{ name: "@aws-sdk/credential-provider-http", location: "packages-internal/credential-provider-http" },
12+
{ name: "@aws-sdk/credential-provider-ini", location: "packages-internal/credential-provider-ini" },
13+
{ name: "@aws-sdk/credential-provider-login", location: "packages-internal/credential-provider-login" },
14+
{ name: "@aws-sdk/credential-provider-node", location: "packages-internal/credential-provider-node" },
15+
{ name: "@aws-sdk/credential-provider-process", location: "packages-internal/credential-provider-process" },
16+
{ name: "@aws-sdk/credential-provider-sso", location: "packages-internal/credential-provider-sso" },
17+
{
18+
name: "@aws-sdk/credential-provider-web-identity",
19+
location: "packages-internal/credential-provider-web-identity",
20+
},
21+
{ name: "@aws-sdk/middleware-bucket-endpoint", location: "packages-internal/middleware-bucket-endpoint" },
22+
{ name: "@aws-sdk/middleware-expect-continue", location: "packages-internal/middleware-expect-continue" },
23+
{ name: "@aws-sdk/middleware-flexible-checksums", location: "packages-internal/middleware-flexible-checksums" },
24+
{ name: "@aws-sdk/middleware-host-header", location: "packages-internal/middleware-host-header" },
25+
{ name: "@aws-sdk/middleware-location-constraint", location: "packages-internal/middleware-location-constraint" },
26+
{ name: "@aws-sdk/middleware-logger", location: "packages-internal/middleware-logger" },
27+
{ name: "@aws-sdk/middleware-recursion-detection", location: "packages-internal/middleware-recursion-detection" },
28+
{ name: "@aws-sdk/middleware-sdk-s3", location: "packages-internal/middleware-sdk-s3" },
29+
{ name: "@aws-sdk/middleware-ssec", location: "packages-internal/middleware-ssec" },
30+
{ name: "@aws-sdk/middleware-user-agent", location: "packages-internal/middleware-user-agent" },
31+
{ name: "@aws-sdk/nested-clients", location: "packages-internal/nested-clients" },
32+
{ name: "@aws-sdk/region-config-resolver", location: "packages-internal/region-config-resolver" },
33+
{ name: "@aws-sdk/signature-v4-multi-region", location: "packages-internal/signature-v4-multi-region" },
34+
{ name: "@aws-sdk/token-providers", location: "packages/token-providers" },
35+
{ name: "@aws-sdk/types", location: "packages-internal/types" },
36+
{ name: "@aws-sdk/util-arn-parser", location: "packages-internal/util-arn-parser" },
37+
{ name: "@aws-sdk/util-endpoints", location: "packages-internal/util-endpoints" },
38+
{ name: "@aws-sdk/util-user-agent-browser", location: "packages-internal/util-user-agent-browser" },
39+
{ name: "@aws-sdk/util-user-agent-node", location: "packages-internal/util-user-agent-node" },
40+
{ name: "@aws-sdk/xml-builder", location: "packages-internal/xml-builder" },
41+
];
42+
43+
function shuffle(list) {
44+
const a = [...list];
45+
for (let i = a.length - 1; i > 0; --i) {
46+
const j = Math.floor(Math.random() * (i + 1));
47+
[a[i], a[j]] = [a[j], a[i]];
48+
}
49+
return a;
50+
}
51+
52+
function ordered(list, a, b) {
53+
const nameList = list.map((i) => i.name);
54+
assert(nameList.indexOf(a) !== -1, `${a} did not appear in list.`);
55+
assert(nameList.indexOf(b) !== -1, `${b} did not appear in list.`);
56+
assert(nameList.indexOf(a) <= nameList.indexOf(b), `${a} did not appear before ${b}`);
57+
}
58+
59+
for (const _list of [list, shuffle(list), shuffle(list), shuffle(list)]) {
60+
const sorted = Graph.toposort(_list);
61+
const check = ordered.bind(null, sorted);
62+
63+
check("@aws-sdk/types", "@aws-sdk/core");
64+
check("@aws-sdk/xml-builder", "@aws-sdk/core");
65+
check("@aws-sdk/core", "@aws-sdk/credential-provider-env");
66+
check("@aws-sdk/core", "@aws-sdk/credential-provider-http");
67+
check("@aws-sdk/core", "@aws-sdk/credential-provider-ini");
68+
check("@aws-sdk/core", "@aws-sdk/credential-provider-login");
69+
check("@aws-sdk/core", "@aws-sdk/credential-provider-process");
70+
check("@aws-sdk/core", "@aws-sdk/credential-provider-sso");
71+
check("@aws-sdk/core", "@aws-sdk/credential-provider-web-identity");
72+
check("@aws-sdk/core", "@aws-sdk/middleware-flexible-checksums");
73+
check("@aws-sdk/core", "@aws-sdk/middleware-sdk-s3");
74+
check("@aws-sdk/core", "@aws-sdk/middleware-user-agent");
75+
check("@aws-sdk/core", "@aws-sdk/nested-clients");
76+
77+
check("@aws-sdk/credential-provider-env", "@aws-sdk/credential-provider-ini");
78+
check("@aws-sdk/credential-provider-http", "@aws-sdk/credential-provider-ini");
79+
check("@aws-sdk/credential-provider-login", "@aws-sdk/credential-provider-ini");
80+
check("@aws-sdk/credential-provider-process", "@aws-sdk/credential-provider-ini");
81+
check("@aws-sdk/credential-provider-sso", "@aws-sdk/credential-provider-ini");
82+
check("@aws-sdk/credential-provider-web-identity", "@aws-sdk/credential-provider-ini");
83+
84+
check("@aws-sdk/token-providers", "@aws-sdk/credential-provider-sso");
85+
86+
for (const name of _list.map((i) => i.name)) {
87+
check(name, "@aws-sdk/client-s3");
88+
}
89+
}
90+
}

0 commit comments

Comments
 (0)