mirror of
https://github.com/actualbudget/actual.git
synced 2026-04-30 10:14:53 -05:00
Migrate get-next-package-version.js to TypeScript (#7227)
* Migrate `get-next-package-version.js` to TypeScript * Add release notes * Stronger type check * Fix step ordering * Fix typo * Fix missed ordering
This commit is contained in:
committed by
GitHub
parent
4f7c3c51a5
commit
e1606b31ab
6
.github/workflows/electron-pr.yml
vendored
6
.github/workflows/electron-pr.yml
vendored
@@ -42,6 +42,8 @@ jobs:
|
|||||||
python3 -m venv .venv
|
python3 -m venv .venv
|
||||||
source .venv/bin/activate
|
source .venv/bin/activate
|
||||||
python3 -m pip install setuptools
|
python3 -m pip install setuptools
|
||||||
|
- name: Set up environment
|
||||||
|
uses: ./.github/actions/setup
|
||||||
- if: ${{ startsWith(matrix.os, 'ubuntu') }}
|
- if: ${{ startsWith(matrix.os, 'ubuntu') }}
|
||||||
name: Setup Flatpak dependencies
|
name: Setup Flatpak dependencies
|
||||||
run: |
|
run: |
|
||||||
@@ -56,11 +58,9 @@ jobs:
|
|||||||
|
|
||||||
METAINFO_FILE="packages/desktop-electron/extra-resources/linux/com.actualbudget.actual.metainfo.xml"
|
METAINFO_FILE="packages/desktop-electron/extra-resources/linux/com.actualbudget.actual.metainfo.xml"
|
||||||
TODAY=$(date +%Y-%m-%d)
|
TODAY=$(date +%Y-%m-%d)
|
||||||
VERSION=$(node ./packages/ci-actions/bin/get-next-package-version.js --package-json ./packages/desktop-electron/package.json --type nightly)
|
VERSION=$(yarn workspace @actual-app/ci-actions tsx bin/get-next-package-version.ts --package-json ./packages/desktop-electron/package.json --type nightly)
|
||||||
sed -i "s/%RELEASE_VERSION%/$VERSION/g; s/%RELEASE_DATE%/$TODAY/g" "$METAINFO_FILE"
|
sed -i "s/%RELEASE_VERSION%/$VERSION/g; s/%RELEASE_DATE%/$TODAY/g" "$METAINFO_FILE"
|
||||||
flatpak run --command=flatpak-builder-lint org.flatpak.Builder appstream "$METAINFO_FILE"
|
flatpak run --command=flatpak-builder-lint org.flatpak.Builder appstream "$METAINFO_FILE"
|
||||||
- name: Set up environment
|
|
||||||
uses: ./.github/actions/setup
|
|
||||||
- name: Build Electron
|
- name: Build Electron
|
||||||
run: ./bin/package-electron
|
run: ./bin/package-electron
|
||||||
|
|
||||||
|
|||||||
8
.github/workflows/generate-release-pr.yml
vendored
8
.github/workflows/generate-release-pr.yml
vendored
@@ -20,6 +20,10 @@ jobs:
|
|||||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.event.inputs.ref }}
|
ref: ${{ github.event.inputs.ref }}
|
||||||
|
- name: Set up environment
|
||||||
|
uses: ./.github/actions/setup
|
||||||
|
with:
|
||||||
|
download-translations: 'false'
|
||||||
- name: Bump package versions
|
- name: Bump package versions
|
||||||
id: bump_package_versions
|
id: bump_package_versions
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -35,12 +39,12 @@ jobs:
|
|||||||
pkg="${packages[$key]}"
|
pkg="${packages[$key]}"
|
||||||
|
|
||||||
if [[ -n "${{ github.event.inputs.version }}" ]]; then
|
if [[ -n "${{ github.event.inputs.version }}" ]]; then
|
||||||
version=$(node ./packages/ci-actions/bin/get-next-package-version.js \
|
version=$(yarn workspace @actual-app/ci-actions tsx bin/get-next-package-version.ts \
|
||||||
--package-json "./packages/$pkg/package.json" \
|
--package-json "./packages/$pkg/package.json" \
|
||||||
--version "${{ github.event.inputs.version }}" \
|
--version "${{ github.event.inputs.version }}" \
|
||||||
--update)
|
--update)
|
||||||
else
|
else
|
||||||
version=$(node ./packages/ci-actions/bin/get-next-package-version.js \
|
version=$(yarn workspace @actual-app/ci-actions tsx bin/get-next-package-version.ts \
|
||||||
--package-json "./packages/$pkg/package.json" \
|
--package-json "./packages/$pkg/package.json" \
|
||||||
--type auto \
|
--type auto \
|
||||||
--update)
|
--update)
|
||||||
|
|||||||
@@ -39,6 +39,9 @@ jobs:
|
|||||||
source .venv/bin/activate
|
source .venv/bin/activate
|
||||||
python3 -m pip install setuptools
|
python3 -m pip install setuptools
|
||||||
|
|
||||||
|
- name: Set up environment
|
||||||
|
uses: ./.github/actions/setup
|
||||||
|
|
||||||
- if: ${{ startsWith(matrix.os, 'ubuntu') }}
|
- if: ${{ startsWith(matrix.os, 'ubuntu') }}
|
||||||
name: Setup Flatpak dependencies
|
name: Setup Flatpak dependencies
|
||||||
run: |
|
run: |
|
||||||
@@ -53,16 +56,14 @@ jobs:
|
|||||||
|
|
||||||
METAINFO_FILE="packages/desktop-electron/extra-resources/linux/com.actualbudget.actual.metainfo.xml"
|
METAINFO_FILE="packages/desktop-electron/extra-resources/linux/com.actualbudget.actual.metainfo.xml"
|
||||||
TODAY=$(date +%Y-%m-%d)
|
TODAY=$(date +%Y-%m-%d)
|
||||||
VERSION=$(node ./packages/ci-actions/bin/get-next-package-version.js --package-json ./packages/desktop-electron/package.json --type nightly)
|
VERSION=$(yarn workspace @actual-app/ci-actions tsx bin/get-next-package-version.ts --package-json ./packages/desktop-electron/package.json --type nightly)
|
||||||
sed -i "s/%RELEASE_VERSION%/$VERSION/g; s/%RELEASE_DATE%/$TODAY/g" "$METAINFO_FILE"
|
sed -i "s/%RELEASE_VERSION%/$VERSION/g; s/%RELEASE_DATE%/$TODAY/g" "$METAINFO_FILE"
|
||||||
flatpak run --command=flatpak-builder-lint org.flatpak.Builder appstream "$METAINFO_FILE"
|
flatpak run --command=flatpak-builder-lint org.flatpak.Builder appstream "$METAINFO_FILE"
|
||||||
- name: Set up environment
|
|
||||||
uses: ./.github/actions/setup
|
|
||||||
|
|
||||||
- name: Update package versions
|
- name: Update package versions
|
||||||
run: |
|
run: |
|
||||||
# Get new nightly version
|
# Get new nightly version
|
||||||
NEW_DESKTOP_APP_VERSION=$(node ./packages/ci-actions/bin/get-next-package-version.js --package-json ./packages/desktop-electron/package.json --type nightly)
|
NEW_DESKTOP_APP_VERSION=$(yarn workspace @actual-app/ci-actions tsx bin/get-next-package-version.ts --package-json ./packages/desktop-electron/package.json --type nightly)
|
||||||
|
|
||||||
# Set package version
|
# Set package version
|
||||||
npm version $NEW_DESKTOP_APP_VERSION --no-git-tag-version --workspace=desktop-electron --no-workspaces-update
|
npm version $NEW_DESKTOP_APP_VERSION --no-git-tag-version --workspace=desktop-electron --no-workspaces-update
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ jobs:
|
|||||||
- name: Update package versions
|
- name: Update package versions
|
||||||
run: |
|
run: |
|
||||||
# Get new nightly versions
|
# Get new nightly versions
|
||||||
NEW_CORE_VERSION=$(node ./packages/ci-actions/bin/get-next-package-version.js --package-json ./packages/loot-core/package.json --type nightly)
|
NEW_CORE_VERSION=$(yarn workspace @actual-app/ci-actions tsx bin/get-next-package-version.ts --package-json ./packages/loot-core/package.json --type nightly)
|
||||||
NEW_WEB_VERSION=$(node ./packages/ci-actions/bin/get-next-package-version.js --package-json ./packages/desktop-client/package.json --type nightly)
|
NEW_WEB_VERSION=$(yarn workspace @actual-app/ci-actions tsx bin/get-next-package-version.ts --package-json ./packages/desktop-client/package.json --type nightly)
|
||||||
NEW_SYNC_VERSION=$(node ./packages/ci-actions/bin/get-next-package-version.js --package-json ./packages/sync-server/package.json --type nightly)
|
NEW_SYNC_VERSION=$(yarn workspace @actual-app/ci-actions tsx bin/get-next-package-version.ts --package-json ./packages/sync-server/package.json --type nightly)
|
||||||
NEW_API_VERSION=$(node ./packages/ci-actions/bin/get-next-package-version.js --package-json ./packages/api/package.json --type nightly)
|
NEW_API_VERSION=$(yarn workspace @actual-app/ci-actions tsx bin/get-next-package-version.ts --package-json ./packages/api/package.json --type nightly)
|
||||||
|
|
||||||
# Set package versions
|
# Set package versions
|
||||||
npm version $NEW_CORE_VERSION --no-git-tag-version --workspace=@actual-app/core --no-workspaces-update
|
npm version $NEW_CORE_VERSION --no-git-tag-version --workspace=@actual-app/core --no-workspaces-update
|
||||||
|
|||||||
44
packages/ci-actions/bin/get-next-package-version.js → packages/ci-actions/bin/get-next-package-version.ts
Executable file → Normal file
44
packages/ci-actions/bin/get-next-package-version.js → packages/ci-actions/bin/get-next-package-version.ts
Executable file → Normal file
@@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
// This script is used in GitHub Actions to get the next version based on the current package.json version.
|
// This script is used in GitHub Actions to get the next version based on the current package.json version.
|
||||||
// It supports three types of versioning: nightly, hotfix, and monthly.
|
// It supports three types of versioning: nightly, hotfix, and monthly.
|
||||||
|
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import { parseArgs } from 'node:util';
|
import { parseArgs } from 'node:util';
|
||||||
|
|
||||||
import { getNextVersion } from '../src/versions/get-next-package-version.js';
|
import {
|
||||||
|
getNextVersion,
|
||||||
const args = process.argv;
|
isValidVersionType,
|
||||||
|
} from '../src/versions/get-next-package-version';
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
'package-json': {
|
'package-json': {
|
||||||
@@ -28,40 +28,53 @@ const options = {
|
|||||||
short: 'u',
|
short: 'u',
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
};
|
} as const;
|
||||||
|
|
||||||
|
function fail(message: string): never {
|
||||||
|
console.error(message);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
const { values } = parseArgs({
|
const { values } = parseArgs({
|
||||||
args,
|
|
||||||
options,
|
options,
|
||||||
allowPositionals: true,
|
allowPositionals: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!values['package-json']) {
|
const packageJsonPath = values['package-json'];
|
||||||
console.error(
|
if (!packageJsonPath) {
|
||||||
|
fail(
|
||||||
'Please specify the path to package.json using --package-json or -p option.',
|
'Please specify the path to package.json using --package-json or -p option.',
|
||||||
);
|
);
|
||||||
process.exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const packageJsonPath = values['package-json'];
|
|
||||||
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
||||||
|
|
||||||
|
if (!('version' in packageJson) || typeof packageJson.version !== 'string') {
|
||||||
|
fail('The specified package.json does not contain a valid version field.');
|
||||||
|
}
|
||||||
|
|
||||||
const currentVersion = packageJson.version;
|
const currentVersion = packageJson.version;
|
||||||
|
|
||||||
const explicitVersion = values.version;
|
const explicitVersion = values.version;
|
||||||
let newVersion;
|
let newVersion;
|
||||||
|
|
||||||
if (explicitVersion) {
|
if (explicitVersion) {
|
||||||
newVersion = explicitVersion;
|
newVersion = explicitVersion;
|
||||||
} else {
|
} else {
|
||||||
|
const type = values.type;
|
||||||
|
if (!type || !isValidVersionType(type)) {
|
||||||
|
fail('Please specify the release type using --type or -t.');
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
newVersion = getNextVersion({
|
newVersion = getNextVersion({
|
||||||
currentVersion,
|
currentVersion,
|
||||||
type: values.type,
|
type,
|
||||||
currentDate: new Date(),
|
currentDate: new Date(),
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (error) {
|
||||||
console.error(e.message);
|
fail(error instanceof Error ? error.message : String(error));
|
||||||
process.exit(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,6 +89,5 @@ try {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error:', error.message);
|
fail(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
||||||
process.exit(1);
|
|
||||||
}
|
}
|
||||||
8
packages/ci-actions/bin/tsx
Executable file
8
packages/ci-actions/bin/tsx
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
cd ../../
|
||||||
|
|
||||||
|
script="$1"
|
||||||
|
shift
|
||||||
|
exec node --import=extensionless/register --experimental-strip-types packages/ci-actions/"$script" "$@"
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"tsx": "node --import=extensionless/register --experimental-strip-types",
|
"tsx": "bin/tsx",
|
||||||
"test": "vitest --run",
|
"test": "vitest --run",
|
||||||
"typecheck": "tsgo -b"
|
"typecheck": "tsgo -b"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ describe('getNextVersion (lib)', () => {
|
|||||||
expect(() =>
|
expect(() =>
|
||||||
getNextVersion({
|
getNextVersion({
|
||||||
currentVersion: '25.8.4',
|
currentVersion: '25.8.4',
|
||||||
type: 'unknown',
|
type: 'unknown' as never,
|
||||||
currentDate: new Date('2025-08-10'),
|
currentDate: new Date('2025-08-10'),
|
||||||
}),
|
}),
|
||||||
).toThrow(/Invalid type/);
|
).toThrow(/Invalid type/);
|
||||||
@@ -1,35 +1,69 @@
|
|||||||
function parseVersion(version) {
|
export const versionTypeArray = [
|
||||||
|
'auto',
|
||||||
|
'hotfix',
|
||||||
|
'monthly',
|
||||||
|
'nightly',
|
||||||
|
] as const;
|
||||||
|
export type VersionType = (typeof versionTypeArray)[number];
|
||||||
|
|
||||||
|
type ParsedVersion = {
|
||||||
|
versionYear: number;
|
||||||
|
versionMonth: number;
|
||||||
|
versionHotfix: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
type GetNextVersionOptions = {
|
||||||
|
currentVersion: string;
|
||||||
|
type: VersionType;
|
||||||
|
currentDate?: Date;
|
||||||
|
};
|
||||||
|
|
||||||
|
function parseVersion(version: string): ParsedVersion {
|
||||||
const [y, m, p] = version.split('.');
|
const [y, m, p] = version.split('.');
|
||||||
return {
|
return {
|
||||||
versionYear: parseInt(y, 10),
|
versionYear: Number.parseInt(y, 10),
|
||||||
versionMonth: parseInt(m, 10),
|
versionMonth: Number.parseInt(m, 10),
|
||||||
versionHotfix: parseInt(p, 10),
|
versionHotfix: Number.parseInt(p, 10),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function computeNextMonth(versionYear, versionMonth) {
|
function computeNextMonth(versionYear: number, versionMonth: number) {
|
||||||
// Create date and add 1 month
|
const versionDate = new Date(2000 + versionYear, versionMonth - 1, 1);
|
||||||
const versionDate = new Date(2000 + versionYear, versionMonth - 1, 1); // month is 0-indexed
|
|
||||||
const nextVersionMonthDate = new Date(
|
const nextVersionMonthDate = new Date(
|
||||||
versionDate.getFullYear(),
|
versionDate.getFullYear(),
|
||||||
versionDate.getMonth() + 1,
|
versionDate.getMonth() + 1,
|
||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Format back to YY.M format
|
|
||||||
const fullYear = nextVersionMonthDate.getFullYear();
|
const fullYear = nextVersionMonthDate.getFullYear();
|
||||||
const nextVersionYear = fullYear.toString().slice(fullYear < 2100 ? -2 : -3);
|
const nextVersionYear = fullYear.toString().slice(fullYear < 2100 ? -2 : -3);
|
||||||
const nextVersionMonth = nextVersionMonthDate.getMonth() + 1; // Convert back to 1-indexed
|
const nextVersionMonth = nextVersionMonthDate.getMonth() + 1;
|
||||||
|
|
||||||
return { nextVersionYear, nextVersionMonth };
|
return { nextVersionYear, nextVersionMonth };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine logical type from 'auto' based on the current date and version
|
export function isValidVersionType(value: string): value is VersionType {
|
||||||
function resolveType(type, currentDate, versionYear, versionMonth) {
|
return versionTypeArray.includes(value as VersionType);
|
||||||
if (type !== 'auto') return type;
|
}
|
||||||
|
|
||||||
|
function resolveType(
|
||||||
|
type: VersionType,
|
||||||
|
currentDate: Date,
|
||||||
|
versionYear: number,
|
||||||
|
versionMonth: number,
|
||||||
|
) {
|
||||||
|
if (type !== 'auto') {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
const inPatchMonth =
|
const inPatchMonth =
|
||||||
currentDate.getFullYear() === 2000 + versionYear &&
|
currentDate.getFullYear() === 2000 + versionYear &&
|
||||||
currentDate.getMonth() + 1 === versionMonth;
|
currentDate.getMonth() + 1 === versionMonth;
|
||||||
if (inPatchMonth && currentDate.getDate() <= 25) return 'hotfix';
|
|
||||||
|
if (inPatchMonth && currentDate.getDate() <= 25) {
|
||||||
|
return 'hotfix';
|
||||||
|
}
|
||||||
|
|
||||||
return 'monthly';
|
return 'monthly';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,7 +71,7 @@ export function getNextVersion({
|
|||||||
currentVersion,
|
currentVersion,
|
||||||
type,
|
type,
|
||||||
currentDate = new Date(),
|
currentDate = new Date(),
|
||||||
}) {
|
}: GetNextVersionOptions) {
|
||||||
const { versionYear, versionMonth, versionHotfix } =
|
const { versionYear, versionMonth, versionHotfix } =
|
||||||
parseVersion(currentVersion);
|
parseVersion(currentVersion);
|
||||||
const { nextVersionYear, nextVersionMonth } = computeNextMonth(
|
const { nextVersionYear, nextVersionMonth } = computeNextMonth(
|
||||||
@@ -51,11 +85,10 @@ export function getNextVersion({
|
|||||||
versionMonth,
|
versionMonth,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Format date stamp once for nightly
|
|
||||||
const currentDateString = currentDate
|
const currentDateString = currentDate
|
||||||
.toISOString()
|
.toISOString()
|
||||||
.split('T')[0]
|
.split('T')[0]
|
||||||
.replaceAll('-', '');
|
.replace(/-/g, '');
|
||||||
|
|
||||||
switch (resolvedType) {
|
switch (resolvedType) {
|
||||||
case 'nightly':
|
case 'nightly':
|
||||||
@@ -66,7 +99,7 @@ export function getNextVersion({
|
|||||||
return `${nextVersionYear}.${nextVersionMonth}.0`;
|
return `${nextVersionYear}.${nextVersionMonth}.0`;
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Invalid type specified. Use "auto", "nightly", "hotfix", or "monthly".',
|
`Invalid type ${String(resolvedType satisfies never)} specified. Use "auto", "nightly", "hotfix", or "monthly".`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,8 +2,8 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ES2022",
|
"target": "ES2022",
|
||||||
"lib": [],
|
"lib": [],
|
||||||
"module": "nodenext",
|
"module": "es2022",
|
||||||
"moduleResolution": "nodenext",
|
"moduleResolution": "bundler",
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"types": ["node"],
|
"types": ["node"],
|
||||||
|
|||||||
6
upcoming-release-notes/7227.md
Normal file
6
upcoming-release-notes/7227.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
category: Maintenance
|
||||||
|
authors: [jfdoming]
|
||||||
|
---
|
||||||
|
|
||||||
|
Migrate `get-next-package-version.js` to TypeScript
|
||||||
Reference in New Issue
Block a user