Files
AutoJs6/.utils/scrape-and-inject-latest-gradle-wrapper.mjs

193 lines
6.9 KiB
JavaScript

// scrape-and-inject-latest-gradle-wrapper.mjs
import * as fs from 'node:fs';
import * as path from 'node:path';
import { compareVersionStrings } from './utils/versioning.mjs';
import { fetchGradleReleases } from './fetch-and-parse-gradle-releases.mjs';
import { readPropertiesSync, writePropertiesSyncWithMap } from './utils/properties.mjs';
const KEY = 'distributionUrl';
const URL_PREFIX = 'https://services.gradle.org/distributions';
/** @type {GradleReleaseConfig} */
const config = {
// @Hint by SuperMonster003 on Sep 10, 2025.
// ! Limit major version to 8.Y.Z, to:
// ! - Legacy IDE/tooling compatibility
// ! - JDK 17 constraint; Gradle 9+ requires JDK 21
// ! - Align with AGP/KGP/plugins matrix
// ! - Mitigate deprecation removals
// ! Set to null/remove to track latest major.
// ! zh-CN:
// ! 将主版本限制在 8.Y.Z, 以便:
// ! - 兼容旧版 IDE/Tooling API
// ! - 满足 JDK 17 运行时约束, 避免 Gradle 9+ 需 JDK 21
// ! - 与 AGP/KGP/第三方插件版本矩阵匹配
// ! - 降低弃用 API 移除导致的构建中断风险
// ! 如需跟随最新主版本, 将 majorVersionLimit 设为 null 或移除此项.
// # majorVersionLimit: '8.Y.Z',
majorVersionLimit: null,
format: 'bin',
};
/**
* @param {GradleRelease[]} releases
* @param {string} majorVersionLimit
* @returns {GradleRelease}
*/
function getLatestRelease(releases, majorVersionLimit) {
const limitedRelease = releases
.sort((a, b) => compareVersionStrings(b.versionName, a.versionName))
.find((release) => compareVersionStrings(release.versionName, majorVersionLimit) <= 0);
if (!limitedRelease) {
throw new Error(`No release found for major version limit: "${majorVersionLimit}"`);
}
return limitedRelease;
}
/**
* @param {string} latestGradleVersion
* @returns {string}
*/
function getLatestGradleUrl(latestGradleVersion) {
const format = config.format ?? 'bin';
return `${URL_PREFIX}/gradle-${latestGradleVersion}-${format}.zip`;
}
/**
* @param {Object} data
* @param {string} [data.fileName='gradle-wrapper.properties']
* @param {string} [data.dirName='../gradle/wrapper']
* @param {string} data.latestGradleVersion
* @param {string} data.latestGradleUrl
* @param {string|number} data.rawMajorVersionLimit
* @returns {Promise<void>}
*/
async function updateGradleWrapperFileContent(
{
fileName = 'gradle-wrapper.properties',
dirName = '../gradle/wrapper',
latestGradleVersion,
latestGradleUrl,
rawMajorVersionLimit,
},
) {
const path = `${dirName.replace(/\/?$/, '/')}${fileName}`;
const majorVersionLimit = parseMajorVersionLimit(rawMajorVersionLimit);
const messages = [];
const props = readPropertiesSync(path);
let propUrl = props.get(KEY);
if (!propUrl) {
propUrl = latestGradleUrl;
messages.push(`Append: ${KEY}=${propUrl}`);
}
const re = /(gradle-)(.+)(-(?:bin|all)\.zip)/;
let propVersion = propUrl.match(re)?.[2];
if (!propVersion) {
messages.push(`-- ${propUrl}\n-> ${latestGradleUrl}`);
propUrl = latestGradleUrl;
propVersion = latestGradleVersion;
}
if (compareVersionStrings(propVersion, majorVersionLimit) > 0) {
const suffix = ` (downgrade, limited by "${rawMajorVersionLimit}")`;
messages.push(`-- ${propUrl}\n-> ${latestGradleUrl}${suffix}`);
props.set(KEY, propUrl.replace(re, `$1${latestGradleVersion}$3`));
} else if (compareVersionStrings(propVersion, latestGradleVersion) < 0) {
const suffix = ` (upgrade)`;
messages.push(`-- ${propUrl}\n-> ${latestGradleUrl}${suffix}`);
props.set(KEY, propUrl.replace(re, `$1${latestGradleVersion}$3`));
}
if (messages.length > 0) {
writePropertiesSyncWithMap(path, props);
const maxLength = Math.max(...messages.join('\n').split('\n').map(s => s.length));
const SEP_EQ = '='.repeat(maxLength);
const SEP_DASH = '-'.repeat(maxLength);
console.log(`[${fileName}] Updated (Gradle version)`);
console.log(SEP_EQ);
messages.forEach((msg, idx) => {
console.log(msg);
if (idx !== messages.length - 1) {
console.log(SEP_DASH);
}
});
console.log(SEP_EQ);
} else {
// console.log(`[${fileName}] No update needed (Gradle version)`);
}
}
/**
* @param {string|number} rawMajorVersionLimit
* @returns {string}
*/
function parseMajorVersionLimit(rawMajorVersionLimit) {
const majorVersionLimit = rawMajorVersionLimit ?? 'x.y.z';
const limits = String(majorVersionLimit).split('.');
for (let i = 0; i < limits.length; i++) {
let limit = limits[i];
if (limit.match(/([xyz*?])(\.\1)*/i)) {
limits[i] = limit = '9'.repeat(9);
}
if (isNaN(parseInt(limit))) {
throw new Error(`Invalid major version limit: ${majorVersionLimit}`);
}
}
return limits.join('.');
}
/**
* @param {string} wrappersPath
* @returns {Array<{dirName: string, rawMajorVersionLimit: string}>}
*/
function listMatchingSubdirectories(wrappersPath) {
const pattern = /^g(\d+)$/;
const fullWrappersPath = path.resolve(wrappersPath);
if (!fs.existsSync(fullWrappersPath)) {
console.warn(`Wrappers directory not found: ${fullWrappersPath}`);
return [];
}
const results = [];
const entries = fs.readdirSync(fullWrappersPath, { withFileTypes: true });
entries.forEach(entry => {
if (!entry.isDirectory()) return;
const matched = pattern.exec(entry.name);
const version = matched?.[1] ?? null;
if (version === null) return;
results.push({
dirName: `${wrappersPath.replace(/\/?$/, '/')}${entry.name}/gradle/wrapper`,
rawMajorVersionLimit: `${version}.y.z`,
});
});
return results;
}
(async function main() {
const releases = await fetchGradleReleases();
if (!releases || releases.length === 0) {
throw new Error('No Gradle releases found');
}
const wrapperDir = '../gradle/wrapper';
const modernWrappersDir = '../gradle/wrappers';
const candidates = [ {
dirName: wrapperDir,
rawMajorVersionLimit: config.majorVersionLimit,
} ].concat(listMatchingSubdirectories(modernWrappersDir));
for (const { dirName, rawMajorVersionLimit } of candidates) {
const latestRelease = getLatestRelease(releases, parseMajorVersionLimit(rawMajorVersionLimit));
const latestGradleVersion = latestRelease.versionName;
const latestGradleUrl = getLatestGradleUrl(latestGradleVersion);
await updateGradleWrapperFileContent({
dirName, latestGradleVersion, latestGradleUrl, rawMajorVersionLimit,
});
}
})().catch(err => {
console.error('Failed to scrape or inject latest Gradle wrapper:', err);
process.exit(1);
});