6.7.0 - Alpha21 - Fine tuning

This commit is contained in:
SuperMonster003
2026-02-24 21:00:46 +08:00
parent 427c671f1c
commit e5c4e9ac8c
11 changed files with 126 additions and 42 deletions

View File

@@ -1,26 +1,101 @@
// scrape-and-inject-agp-releases-list.mjs
import * as cheerio from 'cheerio';
import { compareVersionStrings } from './utils/versioning.mjs';
import { compareVersionStrings, compareVersionStringsDescending } from './utils/versioning.mjs';
import { getMinSupportedAgpVersion } from './utils/properties.mjs';
import { sleep } from './utils/async.mjs';
import { updateGradleListData } from './utils/update-helper.mjs';
const URL = 'https://developer.android.com/reference/tools/gradle-api';
// @Hint by JetBrains AI Assistant (GPT-5.2) on Feb 23, 2026.
// ! Use Google Maven metadata instead of scraping developer.android.com to avoid frequent network timeouts.
// ! zh-CN: 使用 Google Maven 元数据替代抓取 developer.android.com, 以避免频繁的网络超时.
// # const URL = 'https://developer.android.com/reference/tools/gradle-api';
const MAVEN_METADATA_URL = 'https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle/maven-metadata.xml';
/**
* Fetch text with retry/backoff.
* zh-CN: 带重试/退避的文本拉取.
*
* @param {string | URL | Request} url
* @param attempts
* @param timeoutMs
*/
async function fetchTextWithRetry(url, { attempts = 5, timeoutMs = 60000 } = {}) {
let lastErr;
for (let i = 0; i < attempts; i++) {
const controller = new AbortController();
const t = setTimeout(() => controller.abort(new Error(`Request timed out after ${timeoutMs}ms`)), timeoutMs);
try {
const res = await fetch(url, {
signal: controller.signal,
headers: {
// Some CDNs behave better with a UA.
// zh-CN: 某些 CDN 在带 UA 的情况下表现更稳定.
'User-Agent': 'agp-releases-list-updater/1.0 (+nodejs)',
'Accept': 'application/xml,text/xml,text/plain,*/*',
},
});
if (!res.ok) {
// noinspection ExceptionCaughtLocallyJS
throw new Error(`HTTP ${res.status} ${res.statusText}`);
}
return await res.text();
} catch (e) {
lastErr = e;
// Exponential backoff with jitter.
// zh-CN: 带抖动的指数退避.
const backoff = Math.min(2000 * (2 ** i), 15000) + Math.floor(Math.random() * 250);
await sleep(backoff);
} finally {
clearTimeout(t);
}
}
throw lastErr;
}
/**
* Minimal parser: extract <version>...</version>.
* zh-CN: 最小解析器: 提取 <version>...</version>.
*
* @param {string} xml
*/
function extractVersionsFromMavenMetadataXml(xml) {
const versions = [];
const re = /<version>\s*([^<\s]+)\s*<\/version>/g;
let m;
while ((m = re.exec(xml)) !== null) {
versions.push(m[1]);
}
return versions;
}
(async function main() {
const res = await fetch(URL);
const $ = cheerio.load(await res.text());
const results = new Set();
$('table').find('a').each((_, el) => {
const a = $(el);
const href = a.attr('href');
if (href.includes('reference/tools/gradle-api')) {
results.add(a.text());
}
});
const xml = await fetchTextWithRetry(MAVEN_METADATA_URL);
const versions = extractVersionsFromMavenMetadataXml(xml);
const minSupportedVersion = getMinSupportedAgpVersion();
const agpList = new Set(Array.from(results).filter(v => compareVersionStrings(v, minSupportedVersion) >= 0));
await updateGradleListData('agp-releases', agpList, {
const agpListAll = new Set(versions.filter(v => compareVersionStrings(v, minSupportedVersion) >= 0));
const agpListMajor = new Map();
const rex = /^(\d+\.\d+)\.(\d+.*)$/
for (let v of agpListAll) {
const matched = rex.exec(v);
if (!matched) {
continue;
}
const major = matched[1];
if (!agpListMajor.has(major)) {
agpListMajor.set(major, v);
} else {
if (compareVersionStrings(v, agpListMajor.get(major)) > 0) {
agpListMajor.set(major, v);
}
}
}
const agpListFinal = new Set([...agpListMajor.values()].sort(compareVersionStringsDescending));
await updateGradleListData('agp-releases', agpListFinal, {
label: 'AGP releases list',
sort: 'descending.as.version',
});