Skip to content

Commit 50ac3c5

Browse files
author
Sam Thorogood
authored
flip Chrome release data to being built externally (GoogleChrome#1562)
* flip Chrome data to being built * convert back to Date
1 parent ec5cea8 commit 50ac3c5

File tree

5 files changed

+176
-195
lines changed

5 files changed

+176
-195
lines changed

external/build/chrome-release.js

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/**
2+
* @fileoverview Fetches Chrome release data and writes to storage.
3+
*/
4+
5+
const buildVersionInformation = require('./lib/chrome-release.js');
6+
const fs = require('fs');
7+
const path = require('path');
8+
9+
async function run() {
10+
const versionInformation = await buildVersionInformation();
11+
12+
const targetFile = path.join(__dirname, '../data/chrome-release.json');
13+
fs.writeFileSync(targetFile, JSON.stringify(versionInformation));
14+
}
15+
16+
run();

external/build/lib/chrome-release.js

+145
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/*
2+
* Copyright 2020 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
const OMAHA_PROXY_JSON = 'https://omahaproxy.appspot.com/all.json';
18+
const SCHEDULE_JSON =
19+
'https://chromiumdash.appspot.com/fetch_milestone_schedule';
20+
21+
// these OS' have weird releases, don't include
22+
const SKIP_OS = ['webview', 'ios'];
23+
24+
const fetch = require('node-fetch');
25+
26+
/**
27+
* Finds the major Chrome release version from the passed string that looks like "84.0.1231.11".
28+
*
29+
* @param {string} raw
30+
* @return {number}
31+
*/
32+
function extractMajorVersion(raw) {
33+
// this is [major, minor, branch, patch]
34+
const [major] = raw.split('.').map(x => parseInt(x) || 0);
35+
return major;
36+
}
37+
38+
/**
39+
* Fetches Chrome release data for a major version from the Chromium Dashboard. Can return null
40+
* if the version or data returned is invalid.
41+
*
42+
* @param {string} channel
43+
* @param {number} version
44+
* @return {Promise<ChromeReleaseData?>}
45+
*/
46+
async function dataForVersion(channel, version) {
47+
const url = `${SCHEDULE_JSON}?mstone=${version}`;
48+
const json = await fetch(url).then(r => r.json());
49+
50+
// We expect this to be shaped like {mstones: [{...}]}, with just a single item returned.
51+
52+
if (!('mstones' in json) || !json['mstones'][0]) {
53+
return null;
54+
}
55+
const data = json['mstones'][0];
56+
if (!('stable_date' in data) || data['mstone'] !== version) {
57+
return null;
58+
}
59+
60+
// The underlying data contains useful keys "stable_date", "earliest_beta" and "final_beta",
61+
// among others, most of which are currently ignored.
62+
63+
return {
64+
mstone: version,
65+
key: channel,
66+
stableDate: new Date(data['stable_date']),
67+
};
68+
}
69+
70+
/**
71+
* Generates Chrome version information.
72+
*
73+
* While there are many channels, we just care about 'stable' and 'beta'. This method returns a
74+
* value for both.
75+
*
76+
* Beta is not always stable+1 in the underlying data, it can either be stable+0 or stable+2
77+
* depending on the point in the release cycle.
78+
*
79+
* @return {Promise<{channels: Object<string, !Object>}>}
80+
*/
81+
module.exports = async function buildVersionInformation() {
82+
const json = await fetch(OMAHA_PROXY_JSON).then(r => r.json());
83+
84+
/** @type {{[channel: string]: number}} */
85+
const raw = {};
86+
87+
// Find the current version for every channel. The published data returns the versions for each
88+
// operating system. We take the highest major version found across each OS and use that.
89+
for (const {os, versions} of json) {
90+
if (SKIP_OS.includes(os)) {
91+
continue;
92+
}
93+
94+
for (const {channel, version} of versions) {
95+
if (!['stable', 'beta'].includes(channel)) {
96+
continue;
97+
}
98+
const majorVersion = extractMajorVersion(version);
99+
if (majorVersion === 0) {
100+
continue;
101+
}
102+
raw[channel] = Math.max(raw[channel] ?? 0, majorVersion);
103+
}
104+
}
105+
106+
// Sanity-check that we have 'stable', and if we have 'beta', that it's one or two higher.
107+
// Create the virtual 'pending' if it's two higher.
108+
if (!('stable' in raw) || raw['beta'] < raw['stable']) {
109+
console.warn(raw);
110+
throw new Error('bad Chrome release data, no stable or beta < stable');
111+
}
112+
if (!('beta' in raw) || raw['beta'] === raw['stable']) {
113+
// pretend beta is stable+1 if it's not here or beta===stable
114+
raw['beta'] = raw['stable'] + 1;
115+
}
116+
const {beta, stable} = raw;
117+
if (beta === stable + 1) {
118+
// great
119+
} else if (beta === stable + 2) {
120+
// This can occur if Chrome does something weird with releases, basically the previous beta
121+
// is about to be released but it's not done yet.
122+
raw['pending'] = stable + 1;
123+
} else {
124+
console.warn(raw);
125+
throw new Error('bad Chrome release data, beta is >+2 from stable');
126+
}
127+
128+
// Now that we have all major versions, look up and/or cache the schedule for each version. This
129+
// might be the same version for multiple channels, but Eleventy is caching the result for us.
130+
131+
/** @type {(arg: [string, number]) => Promise<[string, ChromeReleaseData]>} */
132+
const fetchChannelData = async ([channel, mstone]) => {
133+
const data = await dataForVersion(channel, mstone);
134+
if (!data) {
135+
throw new Error(`couldn't fetch data for Chrome ${mstone}`);
136+
}
137+
return [channel, data];
138+
};
139+
140+
const channels = Object.fromEntries(
141+
await Promise.all(Object.entries(raw).map(fetchChannelData))
142+
);
143+
144+
return {channels};
145+
};

external/testdata/chrome-release.json

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"channels":{"beta":{"mstone":95,"key":"beta","stableDate":"2021-10-18T13:00:00.000Z"},"stable":{"mstone":94,"key":"stable","stableDate":"2021-09-20T14:00:00.000Z"}}}

site/_data/chrome.js

+14-120
Original file line numberDiff line numberDiff line change
@@ -14,132 +14,26 @@
1414
* limitations under the License.
1515
*/
1616

17-
const {fetchFromCache} = require('./lib/cache');
18-
19-
const OMAHA_PROXY_JSON = 'https://omahaproxy.appspot.com/all.json';
20-
const SCHEDULE_JSON =
21-
'https://chromiumdash.appspot.com/fetch_milestone_schedule';
22-
23-
// these OS' have weird releases, don't include
24-
const SKIP_OS = ['webview', 'ios'];
25-
26-
/**
27-
* Finds the major Chrome release version from the passed string that looks like "84.0.1231.11".
28-
*
29-
* @param {string} raw
30-
* @return {number}
31-
*/
32-
function extractMajorVersion(raw) {
33-
// this is [major, minor, branch, patch]
34-
const [major] = raw.split('.').map(x => parseInt(x) || 0);
35-
return major;
36-
}
37-
38-
/**
39-
* Fetches Chrome release data for a major version from the Chromium Dashboard. Can return null
40-
* if the version or data returned is invalid.
41-
*
42-
* @param {string} channel
43-
* @param {number} version
44-
* @return {Promise<ChromeReleaseData?>}
45-
*/
46-
async function dataForVersion(channel, version) {
47-
const url = `${SCHEDULE_JSON}?mstone=${version}`;
48-
const json = await fetchFromCache(url);
49-
50-
// We expect this to be shaped like {mstones: [{...}]}, with just a single item returned.
51-
52-
if (!('mstones' in json) || !json['mstones'][0]) {
53-
return null;
54-
}
55-
const data = json['mstones'][0];
56-
if (!('stable_date' in data) || data['mstone'] !== version) {
57-
return null;
58-
}
59-
60-
// The underlying data contains useful keys "stable_date", "earliest_beta" and "final_beta",
61-
// among others, most of which are currently ignored.
62-
63-
return {
64-
mstone: version,
65-
key: channel,
66-
stableDate: new Date(data['stable_date']),
67-
};
68-
}
17+
const fs = require('fs');
18+
const path = require('path');
6919

7020
/**
7121
* Generates Chrome version information.
72-
*
73-
* While there are many channels, we just care about 'stable' and 'beta'. This method returns a
74-
* value for both.
75-
*
76-
* Beta is not always stable+1 in the underlying data, it can either be stable+0 or stable+2
77-
* depending on the point in the release cycle.
78-
*
79-
* @return {!Promise<{channels: !Object<string, !Object>}>}
8022
*/
8123
module.exports = async function buildVersionInformation() {
82-
const json = await fetchFromCache(OMAHA_PROXY_JSON);
83-
84-
/** @type {{[channel: string]: number}} */
85-
const raw = {};
86-
87-
// Find the current version for every channel. The published data returns the versions for each
88-
// operating system. We take the highest major version found across each OS and use that.
89-
for (const {os, versions} of json) {
90-
if (SKIP_OS.includes(os)) {
91-
continue;
92-
}
93-
94-
for (const {channel, version} of versions) {
95-
if (!['stable', 'beta'].includes(channel)) {
96-
continue;
97-
}
98-
const majorVersion = extractMajorVersion(version);
99-
if (majorVersion === 0) {
100-
continue;
101-
}
102-
raw[channel] = Math.max(raw[channel] ?? 0, majorVersion);
103-
}
104-
}
24+
const chromeReleaseDataFile = path.join(
25+
__dirname,
26+
'../../external/data/chrome-release.json'
27+
);
28+
const data = /** @type {{channels: Object<string, ChromeReleaseData>}} */ (
29+
JSON.parse(fs.readFileSync(chromeReleaseDataFile, 'utf-8'))
30+
);
10531

106-
// Sanity-check that we have 'stable', and if we have 'beta', that it's one or two higher.
107-
// Create the virtual 'pending' if it's two higher.
108-
if (!('stable' in raw) || raw['beta'] < raw['stable']) {
109-
console.warn(raw);
110-
throw new Error('bad Chrome release data, no stable or beta < stable');
111-
}
112-
if (!('beta' in raw) || raw['beta'] === raw['stable']) {
113-
// pretend beta is stable+1 if it's not here or beta===stable
114-
raw['beta'] = raw['stable'] + 1;
32+
for (const channel in data.channels) {
33+
const o = data.channels[channel];
34+
// JSON-encoding flattens this to a string, so reconstruct the Date.
35+
o.stableDate = new Date(o.stableDate);
11536
}
116-
const {beta, stable} = raw;
117-
if (beta === stable + 1) {
118-
// great
119-
} else if (beta === stable + 2) {
120-
// This can occur if Chrome does something weird with releases, basically the previous beta
121-
// is about to be released but it's not done yet.
122-
raw['pending'] = stable + 1;
123-
} else {
124-
console.warn(raw);
125-
throw new Error('bad Chrome release data, beta is >+2 from stable');
126-
}
127-
128-
// Now that we have all major versions, look up and/or cache the schedule for each version. This
129-
// might be the same version for multiple channels, but Eleventy is caching the result for us.
130-
131-
/** @type {(arg: [string, number]) => Promise<[string, ChromeReleaseData]>} */
132-
const fetchChannelData = async ([channel, mstone]) => {
133-
const data = await dataForVersion(channel, mstone);
134-
if (!data) {
135-
throw new Error(`couldn't fetch data for Chrome ${mstone}`);
136-
}
137-
return [channel, data];
138-
};
139-
140-
const channels = Object.fromEntries(
141-
await Promise.all(Object.entries(raw).map(fetchChannelData))
142-
);
14337

144-
return {channels};
38+
return data;
14539
};

tests/site/_data/chrome.js

-75
This file was deleted.

0 commit comments

Comments
 (0)