Skip to content

Commit 8d57d66

Browse files
committed
Move skipBadPublishes() -> calculate-versions
1 parent 36941b5 commit 8d57d66

File tree

7 files changed

+64
-79
lines changed

7 files changed

+64
-79
lines changed

packages/publisher/src/calculate-versions.ts

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ import {
1111
UncachedNpmInfoClient,
1212
withNpmCache,
1313
CachedNpmInfoClient,
14+
max,
1415
} from "@definitelytyped/utils";
1516
import { fetchTypesPackageVersionInfo } from "@definitelytyped/retag";
17+
import * as semver from "semver";
1618
import { cacheDirPath } from "./lib/settings";
1719

1820
if (!module.parent) {
@@ -49,7 +51,7 @@ async function computeAndSaveChangedPackages(
4951
changedTypings: cp.changedTypings.map(
5052
({ pkg: { id }, version, latestVersion }): ChangedTypingJson => ({ id, version, latestVersion })
5153
),
52-
changedNotNeededPackages: cp.changedNotNeededPackages.map((p) => p.name),
54+
changedNotNeededPackages: cp.changedNotNeededPackages.map(({ pkg: { name }, version }) => ({ name, version })),
5355
};
5456
await writeDataFile(versionsFilename, json);
5557
return cp;
@@ -80,32 +82,54 @@ async function computeChangedPackages(
8082
});
8183
log.info("# Computing deprecated packages...");
8284
const changedNotNeededPackages = await mapDefinedAsync(allPackages.allNotNeeded(), async (pkg) => {
83-
if (!(await isAlreadyDeprecated(pkg, client, log))) {
85+
const version = await fetchIncipientStubVersion(pkg, client, log);
86+
if (version) {
8487
assertDefined(
8588
await client.fetchAndCacheNpmInfo(pkg.libraryName),
8689
`To deprecate '@types/${pkg.name}', '${pkg.libraryName}' must exist on npm.`
8790
);
8891
log.info(`To be deprecated: ${pkg.name}`);
89-
return pkg;
92+
return { pkg, version };
9093
}
9194
return undefined;
9295
});
9396
return { changedTypings, changedNotNeededPackages };
9497
}
9598

96-
async function isAlreadyDeprecated(
99+
/**
100+
* Return the version of the stub @types/package we are about to publish
101+
* and deprecate, if that @typees/package is not already deprecated.
102+
*/
103+
async function fetchIncipientStubVersion(
97104
pkg: NotNeededPackage,
98105
client: CachedNpmInfoClient,
99106
log: LoggerWithErrors
100-
): Promise<boolean> {
101-
const cachedInfo = client.getNpmInfoFromCache(pkg.fullEscapedNpmName);
102-
let latestVersion = cachedInfo && assertDefined(cachedInfo.distTags.get("latest"));
103-
let latestVersionInfo = cachedInfo && latestVersion && assertDefined(cachedInfo.versions.get(latestVersion));
107+
): Promise<string | false> {
108+
let info = client.getNpmInfoFromCache(pkg.fullEscapedNpmName);
109+
let latestVersion = info && assertDefined(info.distTags.get("latest"));
110+
let latestVersionInfo = latestVersion && assertDefined(info!.versions.get(latestVersion));
104111
if (!latestVersionInfo || !latestVersionInfo.deprecated) {
105112
log.info(`Version info not cached for deprecated package ${pkg.desc}`);
106-
const info = assertDefined(await client.fetchAndCacheNpmInfo(pkg.fullEscapedNpmName));
113+
info = assertDefined(await client.fetchAndCacheNpmInfo(pkg.fullEscapedNpmName));
107114
latestVersion = assertDefined(info.distTags.get("latest"));
108115
latestVersionInfo = assertDefined(info.versions.get(latestVersion));
109116
}
110-
return !!latestVersionInfo.deprecated;
117+
// When we fail to publish a deprecated package, it leaves behind an entry in the time property.
118+
// So the keys of 'time' give the actual 'latest'.
119+
// If that's not equal to the expected latest, try again by bumping the patch version of the last attempt by 1.
120+
return (
121+
!latestVersionInfo.deprecated &&
122+
String(max([pkg.version, semver.inc(findActualLatest(info!.time), "patch")!], semver.compare))
123+
);
124+
}
125+
126+
function findActualLatest(times: Map<string, string>) {
127+
const actual = max(
128+
[...times].filter(([version]) => version !== "modified" && version !== "created"),
129+
([, a], [, b]) => (new Date(a) as never) - (new Date(b) as never)
130+
);
131+
if (!actual) {
132+
throw new Error("failed to find actual latest");
133+
}
134+
return actual[0];
111135
}

packages/publisher/src/generate-packages.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import {
1616
logger,
1717
writeLog,
1818
writeFile,
19-
Logger,
2019
writeTgz,
2120
withNpmCache,
2221
UncachedNpmInfoClient,
@@ -36,7 +35,6 @@ import {
3635
} from "@definitelytyped/definitions-parser";
3736
import { readChangedPackages, ChangedPackages } from "./lib/versions";
3837
import { outputDirectory } from "./util/util";
39-
import { skipBadPublishes } from "./lib/npm";
4038

4139
const mitLicense = readFileSync(joinPaths(__dirname, "..", "LICENSE"), "utf-8");
4240

@@ -73,9 +71,9 @@ export default async function generatePackages(
7371
await withNpmCache(
7472
new UncachedNpmInfoClient(),
7573
async (client) => {
76-
for (const pkg of changedPackages.changedNotNeededPackages) {
74+
for (const { pkg, version } of changedPackages.changedNotNeededPackages) {
7775
log(` * ${pkg.libraryName}`);
78-
await generateNotNeededPackage(pkg, client, log);
76+
await generateNotNeededPackage(pkg, version, client);
7977
}
8078
},
8179
cacheDirPath
@@ -102,15 +100,14 @@ async function generateTypingPackage(
102100

103101
async function generateNotNeededPackage(
104102
pkg: NotNeededPackage,
105-
client: CachedNpmInfoClient,
106-
log: Logger
103+
version: string,
104+
client: CachedNpmInfoClient
107105
): Promise<void> {
108-
pkg = skipBadPublishes(pkg, client, log);
109106
const info = await client.fetchAndCacheNpmInfo(pkg.libraryName);
110107
assert(info);
111108
const readme = `This is a stub types definition for ${getFullNpmName(pkg.name)} (${info.homepage}).\n
112109
${pkg.libraryName} provides its own type definitions, so you don't need ${getFullNpmName(pkg.name)} installed!`;
113-
await writeCommonOutputs(pkg, createNotNeededPackageJSON(pkg), readme);
110+
await writeCommonOutputs(pkg, createNotNeededPackageJSON(pkg, version), readme);
114111
}
115112

116113
async function writeCommonOutputs(pkg: AnyPackage, packageJson: string, readme: string): Promise<void> {
@@ -210,10 +207,13 @@ function dependencySemver(dependency: DependencyVersion): string {
210207
return dependency === "*" ? dependency : "^" + formatTypingVersion(dependency);
211208
}
212209

213-
export function createNotNeededPackageJSON({ libraryName, license, fullNpmName, version }: NotNeededPackage): string {
210+
export function createNotNeededPackageJSON(
211+
{ libraryName, license, fullNpmName }: NotNeededPackage,
212+
version: string
213+
): string {
214214
const out = {
215215
name: fullNpmName,
216-
version: String(version),
216+
version,
217217
typings: null, // tslint:disable-line no-null-keyword
218218
description: `Stub TypeScript definitions entry for ${libraryName}, which provides its own types definitions`,
219219
main: "",

packages/publisher/src/lib/npm.ts

Lines changed: 0 additions & 32 deletions
This file was deleted.

packages/publisher/src/lib/package-publisher.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,14 @@ export async function publishTypingsPackage(
2828
export async function publishNotNeededPackage(
2929
client: NpmPublishClient,
3030
pkg: NotNeededPackage,
31+
version: string,
3132
dry: boolean,
3233
log: Logger
3334
): Promise<void> {
3435
log(`Deprecating ${pkg.name}`);
3536
await common(client, pkg, log, dry);
3637
// Don't use a newline in the deprecation message because it will be displayed as "\n" and not as a newline.
37-
await deprecateNotNeededPackage(client, pkg, dry, log);
38+
await deprecateNotNeededPackage(client, pkg, version, dry, log);
3839
}
3940

4041
async function common(client: NpmPublishClient, pkg: AnyPackage, log: Logger, dry: boolean): Promise<void> {
@@ -46,14 +47,15 @@ async function common(client: NpmPublishClient, pkg: AnyPackage, log: Logger, dr
4647
export async function deprecateNotNeededPackage(
4748
client: NpmPublishClient,
4849
pkg: NotNeededPackage,
50+
version: string,
4951
dry = false,
5052
log: Logger
5153
): Promise<void> {
5254
const name = pkg.fullNpmName;
5355
if (dry) {
54-
log("(dry) Skip deprecate not needed package " + name + " at " + pkg.version);
56+
log("(dry) Skip deprecate not needed package " + name + " at " + version);
5557
} else {
56-
log(`Deprecating ${name} at ${pkg.version} with message: ${pkg.deprecatedMessage()}.`);
57-
await client.deprecate(name, String(pkg.version), pkg.deprecatedMessage());
58+
log(`Deprecating ${name} at ${version} with message: ${pkg.deprecatedMessage()}.`);
59+
await client.deprecate(name, version, pkg.deprecatedMessage());
5860
}
5961
}

packages/publisher/src/lib/versions.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export interface ChangedTyping {
1919

2020
export interface ChangedPackagesJson {
2121
readonly changedTypings: readonly ChangedTypingJson[];
22-
readonly changedNotNeededPackages: readonly string[];
22+
readonly changedNotNeededPackages: readonly { readonly name: string; readonly version: string }[];
2323
}
2424

2525
export interface ChangedTypingJson {
@@ -30,7 +30,7 @@ export interface ChangedTypingJson {
3030

3131
export interface ChangedPackages {
3232
readonly changedTypings: readonly ChangedTyping[];
33-
readonly changedNotNeededPackages: readonly NotNeededPackage[];
33+
readonly changedNotNeededPackages: readonly { readonly pkg: NotNeededPackage; readonly version: string }[];
3434
}
3535

3636
export async function readChangedPackages(allPackages: AllPackages): Promise<ChangedPackages> {
@@ -43,8 +43,9 @@ export async function readChangedPackages(allPackages: AllPackages): Promise<Cha
4343
latestVersion,
4444
})
4545
),
46-
changedNotNeededPackages: json.changedNotNeededPackages.map((id) =>
47-
assertDefined(allPackages.getNotNeededPackage(id))
48-
),
46+
changedNotNeededPackages: json.changedNotNeededPackages.map(({ name, version }) => ({
47+
pkg: assertDefined(allPackages.getNotNeededPackage(name)),
48+
version,
49+
})),
4950
};
5051
}

packages/publisher/src/publish-packages.ts

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,9 @@ import {
1111
Fetcher,
1212
writeLog,
1313
NpmPublishClient,
14-
withNpmCache,
15-
UncachedNpmInfoClient,
1614
} from "@definitelytyped/utils";
1715
import { readChangedPackages, ChangedPackages } from "./lib/versions";
18-
import { skipBadPublishes } from "./lib/npm";
1916
import { getSecret, Secret } from "./lib/secrets";
20-
import { cacheDirPath } from "./lib/settings";
2117

2218
if (!module.parent) {
2319
const dry = !!yargs.argv.dry;
@@ -27,11 +23,12 @@ if (!module.parent) {
2723
if (deprecateName !== undefined) {
2824
// A '--deprecate' command is available in case types-publisher got stuck *while* trying to deprecate a package.
2925
// Normally this should not be needed.
30-
26+
const pkg = AllPackages.readSingleNotNeeded(deprecateName, dt);
3127
const log = logger()[0];
3228
await deprecateNotNeededPackage(
3329
await NpmPublishClient.create(await getSecret(Secret.NPM_TOKEN), undefined),
34-
AllPackages.readSingleNotNeeded(deprecateName, dt),
30+
pkg,
31+
String(pkg.version),
3532
/*dry*/ false,
3633
log
3734
);
@@ -143,16 +140,9 @@ export default async function publishPackages(
143140
}
144141
}
145142

146-
await withNpmCache(
147-
new UncachedNpmInfoClient(),
148-
async (infoClient) => {
149-
for (const n of changedPackages.changedNotNeededPackages) {
150-
const target = skipBadPublishes(n, infoClient, log);
151-
await publishNotNeededPackage(client, target, dry, log);
152-
}
153-
},
154-
cacheDirPath
155-
);
143+
for (const { pkg, version } of changedPackages.changedNotNeededPackages) {
144+
await publishNotNeededPackage(client, pkg, version, dry, log);
145+
}
156146

157147
await writeLog("publishing.md", logResult());
158148
console.log("Done!");

packages/publisher/test/generate-packages.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ testo({
137137
}`);
138138
},
139139
basicNotNeededPackageJson() {
140-
const s = createNotNeededPackageJSON(createUnneededPackage());
140+
const s = createNotNeededPackageJSON(createUnneededPackage(), "1.1.1");
141141
expect(s).toEqual(`{
142142
"name": "@types/absalom",
143143
"version": "1.1.1",
@@ -154,7 +154,7 @@ testo({
154154
},
155155
scopedNotNeededPackageJson() {
156156
const scopedUnneeded = new NotNeededPackage("google-cloud__pubsub", "@google-cloud/chubdub", "0.26.0");
157-
const s = createNotNeededPackageJSON(scopedUnneeded);
157+
const s = createNotNeededPackageJSON(scopedUnneeded, "0.26.0");
158158
expect(s).toEqual(`{
159159
"name": "@types/google-cloud__pubsub",
160160
"version": "0.26.0",

0 commit comments

Comments
 (0)