forked from BasedHardware/omi
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdesktop-release-lifecycle.ts
More file actions
88 lines (80 loc) · 2.78 KB
/
Copy pathdesktop-release-lifecycle.ts
File metadata and controls
88 lines (80 loc) · 2.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
export type DesktopReleaseChannel = "candidate" | "beta" | "stable" | null;
export type DesktopReleaseLifecycle =
| "build_candidate"
| "beta_live"
| "stable_candidate"
| "stable";
export interface DesktopStableCandidate {
complete: boolean;
nominatedAt: string | null;
nominatedBy: string | null;
}
const LIFECYCLE_LABELS: Record<DesktopReleaseLifecycle, string> = {
build_candidate: "Build candidate",
beta_live: "Beta",
stable_candidate: "Stable candidate",
stable: "Stable",
};
export function desktopReleaseLifecycleLabel(
lifecycle: DesktopReleaseLifecycle,
): string {
return LIFECYCLE_LABELS[lifecycle];
}
function isTrueMetadata(value: string | undefined): boolean {
const normalized = value?.trim().toLowerCase();
return normalized === "true" || normalized === "1" || normalized === "yes";
}
export function desktopStableCandidateFromMetadata(
metadata: Record<string, string>,
expected: { releaseTag: string },
): DesktopStableCandidate {
const required = [
metadata.stableCandidateTag,
metadata.stableCandidateSha,
metadata.stableCandidateAt,
metadata.stableCandidateBy,
metadata.stableCandidateRationale,
metadata.stableCandidateSoakReview,
metadata.stableCandidateTelemetryReview,
metadata.stableCandidateReleaseNotesReview,
];
const referencesCurrentRelease =
metadata.stableCandidateTag?.trim() === expected.releaseTag;
return {
complete:
isTrueMetadata(metadata.stableCandidate) &&
required.every((value) => Boolean(value?.trim())) &&
referencesCurrentRelease,
nominatedAt: metadata.stableCandidateAt?.trim() || null,
nominatedBy: metadata.stableCandidateBy?.trim() || null,
};
}
export function desktopReleaseLifecycle(
channel: DesktopReleaseChannel,
betaLive: boolean,
stableCandidate: DesktopStableCandidate,
): DesktopReleaseLifecycle {
if (channel === "stable") return "stable";
if (betaLive && stableCandidate.complete) return "stable_candidate";
if (betaLive) return "beta_live";
return "build_candidate";
}
export function tagBuildNumber(tag: string): number | null {
const match = tag.match(/\+(\d+)-macos$/);
if (!match) return null;
return Number.parseInt(match[1], 10);
}
export function newestSparkleVersion(appcast: string): number | null {
const versions: number[] = [];
// `exec` loops rather than `for...of matchAll()`: this package targets es5,
// where iterating an IterableIterator is a compile error (TS2802).
const patterns = [/<sparkle:version>(\d+)<\/sparkle:version>/g, /sparkle:version="(\d+)"/g];
for (const pattern of patterns) {
let match = pattern.exec(appcast);
while (match !== null) {
versions.push(Number.parseInt(match[1], 10));
match = pattern.exec(appcast);
}
}
return versions.length ? Math.max(...versions) : null;
}