2024-04-14 15:10:34 +02:00
|
|
|
/*
|
|
|
|
|
* Copyright (C) Contributors to the Suwayomi project
|
|
|
|
|
*
|
|
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
|
|
|
*/
|
|
|
|
|
|
2026-03-11 00:11:29 +01:00
|
|
|
import type { ExecSyncOptions } from 'node:child_process';
|
|
|
|
|
import { execSync } from 'node:child_process';
|
2024-04-14 15:10:34 +02:00
|
|
|
import { writeFileSync } from 'node:fs';
|
|
|
|
|
import packageJson from '../../package.json';
|
|
|
|
|
|
|
|
|
|
type TPackageJson = typeof packageJson;
|
2026-05-15 16:30:57 +02:00
|
|
|
type DependencyType = keyof Pick<TPackageJson, 'dependencies' | 'devDependencies'>;
|
|
|
|
|
|
|
|
|
|
type OutdatedPayload = {
|
|
|
|
|
current: string;
|
|
|
|
|
latest: string;
|
|
|
|
|
wanted: string;
|
|
|
|
|
isDeprecated: boolean;
|
|
|
|
|
dependencyType: DependencyType;
|
|
|
|
|
};
|
2024-04-14 15:10:34 +02:00
|
|
|
|
2026-05-15 16:30:57 +02:00
|
|
|
type OutdatedDependency = OutdatedPayload & {
|
2024-04-14 15:10:34 +02:00
|
|
|
name: string;
|
|
|
|
|
isMajorUpdate: boolean;
|
|
|
|
|
};
|
|
|
|
|
|
2026-05-15 16:30:57 +02:00
|
|
|
const PACKAGE_TYPES: DependencyType[] = ['dependencies', 'devDependencies'];
|
2026-03-08 23:25:02 +01:00
|
|
|
|
2026-05-15 16:30:57 +02:00
|
|
|
const updateVersionInPackageJson = <TDependencyType extends DependencyType>(
|
|
|
|
|
type: TDependencyType,
|
|
|
|
|
dependency: keyof TPackageJson[TDependencyType],
|
|
|
|
|
version: string,
|
2024-04-14 15:10:34 +02:00
|
|
|
) => {
|
2026-05-15 16:30:57 +02:00
|
|
|
// @ts-ignore - TS2322: Type string is not assignable to type (packageJson[type][dependency])
|
|
|
|
|
packageJson[type][dependency] = version;
|
2024-04-14 15:10:34 +02:00
|
|
|
};
|
|
|
|
|
|
2026-05-15 16:30:57 +02:00
|
|
|
const updateVersionsInPackageJson = (dependencies: OutdatedDependency[]) => {
|
|
|
|
|
dependencies.forEach(({ name, dependencyType, latest }) =>
|
|
|
|
|
updateVersionInPackageJson(dependencyType, name as keyof TPackageJson[typeof dependencyType], latest),
|
2024-04-14 15:10:34 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
writeFileSync('package.json', `${JSON.stringify(packageJson, null, 2)}\n`);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param asJson
|
|
|
|
|
* @param stdio - only considered in case asJson is falsy
|
|
|
|
|
*/
|
2026-05-15 16:30:57 +02:00
|
|
|
const execOutdatedCmd = ({ asJson = false, stdio }: { asJson?: boolean; stdio?: ExecSyncOptions['stdio'] } = {}):
|
2024-04-14 15:10:34 +02:00
|
|
|
| string
|
|
|
|
|
| null => {
|
|
|
|
|
try {
|
2026-05-15 16:30:57 +02:00
|
|
|
execSync(`pnpm outdated ${asJson ? '--json' : ''}`, { stdio: !asJson ? stdio : undefined })?.toString();
|
2024-04-14 15:10:34 +02:00
|
|
|
return null;
|
|
|
|
|
} catch (e: any) {
|
|
|
|
|
if (e?.stdout === null) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!Buffer.isBuffer(e.stdout)) {
|
|
|
|
|
throw e;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return e.stdout.toString();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const getOutdatedDependencies = (): OutdatedDependency[] => {
|
2026-05-15 16:30:57 +02:00
|
|
|
const output = execOutdatedCmd({ asJson: true });
|
2024-04-14 15:10:34 +02:00
|
|
|
|
|
|
|
|
if (output === null) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-15 16:30:57 +02:00
|
|
|
const outdatedPayload = JSON.parse(output) as Record<string, OutdatedPayload>;
|
|
|
|
|
|
|
|
|
|
const outdatedPackages = Object.entries(outdatedPayload).map(([name, info]) => ({
|
|
|
|
|
name,
|
|
|
|
|
...info,
|
|
|
|
|
}));
|
2024-04-14 15:10:34 +02:00
|
|
|
|
|
|
|
|
return outdatedPackages
|
2026-05-15 16:30:57 +02:00
|
|
|
.map((dependency) => ({
|
|
|
|
|
...dependency,
|
|
|
|
|
isMajorUpdate: dependency.current.split('.')[0] !== dependency.latest.split('.')[0],
|
2024-04-14 15:10:34 +02:00
|
|
|
}))
|
2026-05-15 16:30:57 +02:00
|
|
|
.filter(({ dependencyType }) => PACKAGE_TYPES.includes(dependencyType))
|
|
|
|
|
.toSorted((a, b) => a.dependencyType.localeCompare(b.dependencyType));
|
2024-04-14 15:10:34 +02:00
|
|
|
};
|
|
|
|
|
|
2026-03-11 00:11:29 +01:00
|
|
|
const log = (...args: Parameters<typeof console.log>) => console.log('updateDependencies:', ...args);
|
2024-04-14 15:10:34 +02:00
|
|
|
|
2026-03-11 00:11:29 +01:00
|
|
|
const updateDependencies = () => {
|
2024-04-14 15:10:34 +02:00
|
|
|
log('checking for outdated dependencies...');
|
|
|
|
|
|
|
|
|
|
const outdatedDependencies = getOutdatedDependencies();
|
|
|
|
|
const autoUpdatableDependencies = outdatedDependencies.filter(({ isMajorUpdate }) => !isMajorUpdate);
|
|
|
|
|
|
|
|
|
|
if (!outdatedDependencies.length) {
|
|
|
|
|
log('all dependencies are up-to-date');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-15 16:30:57 +02:00
|
|
|
execOutdatedCmd({ stdio: 'inherit' });
|
2024-04-14 15:10:34 +02:00
|
|
|
|
|
|
|
|
if (!autoUpdatableDependencies.length) {
|
|
|
|
|
log('no automatically updatable dependencies found');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log('updating dependencies with non breaking changes...');
|
|
|
|
|
|
2026-05-15 16:30:57 +02:00
|
|
|
updateVersionsInPackageJson(autoUpdatableDependencies);
|
2024-04-14 15:10:34 +02:00
|
|
|
|
2026-05-15 16:30:57 +02:00
|
|
|
execSync('pnpm i', { stdio: 'inherit' });
|
2024-04-14 15:10:34 +02:00
|
|
|
|
|
|
|
|
log('commiting changes...');
|
|
|
|
|
|
2026-05-15 16:30:57 +02:00
|
|
|
execSync('git add package.json pnpm-lock.yaml && git commit -m "Update dependencies"', { stdio: 'inherit' });
|
2024-04-14 15:10:34 +02:00
|
|
|
|
|
|
|
|
log('updated dependencies with non breaking changes. Check dependencies with breaking changes listed below:');
|
|
|
|
|
|
2026-05-15 16:30:57 +02:00
|
|
|
execOutdatedCmd({ stdio: 'inherit' });
|
2024-04-14 15:10:34 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
updateDependencies();
|