2026-06-04 15:16:53 -04:00
const fs = require ( "fs" );
const path = require ( "path" );
2026-10-10 14:58:27 -05:00
const { changelogSection } = require ( "./lib/changelog-section.cjs" );
2026-06-04 15:16:53 -04:00
function parseArgs ( argv ) {
const args = {};
for ( let i = 0 ; i < argv . length ; i ++ ) {
const arg = argv [ i ];
if ( arg . startsWith ( "--" )) {
const key = arg . slice ( 2 );
const next = argv [ i + 1 ];
if ( next === undefined || next . startsWith ( "--" )) {
args [ key ] = true ;
} else {
args [ key ] = next ;
i ++ ;
}
}
}
return args ;
}
function fail ( message ) {
console . error ( `generate-release-body: ${ message } ` );
process . exit ( 1 );
}
2026-10-10 14:58:27 -05:00
function buildTable ( version , mobileVersion , mobileTag ) {
const tag = `v ${ version } ` ;
2026-06-04 15:16:53 -04:00
const base = `https://github.com/Termix-SSH/Termix/releases/download/ ${ tag } ` ;
2026-10-10 14:58:27 -05:00
const mobileBase = `https://github.com/Termix-SSH/Mobile/releases/download/ ${ mobileTag || `v ${ mobileVersion } ` } ` ;
2026-06-04 15:16:53 -04:00
const win = ( file ) => ` ${ base } / ${ file } ` ;
const linux = ( file ) => ` ${ base } / ${ file } ` ;
const mac = ( file ) => ` ${ base } / ${ file } ` ;
return [
`| Architecture | Windows | Linux | Mac | Android | iOS |` ,
`|------------------|------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------|---------------------------------------------|-----------------------------------|` ,
2026-10-10 14:58:27 -05:00
`| **x86-64 (64-bit)** | [EXE]( ${ win ( "termix_windows_x64_nsis.exe" ) } ) · [MSI]( ${ win ( "termix_windows_x64_msi.msi" ) } ) · [Portable]( ${ win ( "termix_windows_x64_portable.zip" ) } ) | [AppImage]( ${ linux ( "termix_linux_x64_appimage.AppImage" ) } ) · [DEB]( ${ linux ( "termix_linux_x64_deb.deb" ) } ) · [Portable]( ${ linux ( "termix_linux_x64_portable.tar.gz" ) } ) | [DMG]( ${ mac ( "termix_macos_x64_dmg.dmg" ) } ) | - | - |` ,
2026-10-18 00:34:50 -05:00
`| **AArch64 (ARM64)** | [EXE]( ${ win ( "termix_windows_arm64_nsis.exe" ) } ) · [MSI]( ${ win ( "termix_windows_arm64_msi.msi" ) } ) · [Portable]( ${ win ( "termix_windows_arm64_portable.zip" ) } ) | [AppImage]( ${ linux ( "termix_linux_arm64_appimage.AppImage" ) } ) · [DEB]( ${ linux ( "termix_linux_arm64_deb.deb" ) } ) · [Portable]( ${ linux ( "termix_linux_arm64_portable.tar.gz" ) } ) | [DMG]( ${ mac ( "termix_macos_arm64_dmg.dmg" ) } ) | [APK ( ${ mobileVersion } )]( ${ mobileBase } /termix_android.apk) | [IPA ( ${ mobileVersion } )]( ${ mobileBase } /termix_ios.ipa) |` ,
2026-10-10 14:58:27 -05:00
`| **ARMv7 (32-bit)** | - | [AppImage]( ${ linux ( "termix_linux_armv7l_appimage.AppImage" ) } ) · [DEB]( ${ linux ( "termix_linux_armv7l_deb.deb" ) } ) · [Portable]( ${ linux ( "termix_linux_armv7l_portable.tar.gz" ) } ) | - | - | - |` ,
`| **x86-32 (32-bit)** | [EXE]( ${ win ( "termix_windows_ia32_nsis.exe" ) } ) · [MSI]( ${ win ( "termix_windows_ia32_msi.msi" ) } ) · [Portable]( ${ win ( "termix_windows_ia32_portable.zip" ) } ) | - | - | - | - |` ,
`| **Universal** | [Chocolatey](https://docs.termix.site/install/apps/windows) | [Flatpak](https://docs.termix.site/install/apps/linux) | [DMG]( ${ mac ( "termix_macos_universal_dmg.dmg" ) } ) · [App Store](https://apps.apple.com/us/app/termix-ssh-companion/id6752672071) · [Homebrew](https://docs.termix.site/install/apps/macos) | - | - |` ,
]. join ( "\n" );
}
2026-10-29 18:31:59 -05:00
function buildFullBuilds ( version ) {
const base = `https://github.com/Termix-SSH/Termix/releases/download/v ${ version } ` ;
const link = ( label , file ) => `[ ${ label } ]( ${ base } / ${ file } )` ;
return [
"The builds above include the standard plugins. The full builds include every official plugin, which helps on a network with no internet. You can still turn plugins on or off in the Plugins tab. Full builds are x64 only (universal on Mac):" ,
"" ,
`- Windows: ${ link ( "EXE" , "termix_windows_x64_full_nsis.exe" ) } ` ,
`- Linux: ${ link ( "AppImage" , "termix_linux_x64_full_appimage.AppImage" ) } · ${ link ( "DEB" , "termix_linux_x64_full_deb.deb" ) } ` ,
`- Mac: ${ link ( "DMG" , "termix_macos_universal_full_dmg.dmg" ) } ` ,
]. join ( "\n" );
}
2026-10-10 14:58:27 -05:00
function buildBody ({ version , mobileVersion , mobileTag , changelog }) {
const notes = changelogSection ( changelog , version );
if ( ! notes ) fail ( `CHANGELOG.md has no notes for ${ version } ` );
const donateAlert = [
"> [!TIP]" ,
"> Termix is free and always will be. If it's useful to you, consider [donating](https://donate.termix.site/donate/) to support development." ,
]. join ( "\n" );
return [
donateAlert ,
"" ,
notes ,
"" ,
"### Downloads" ,
"" ,
buildTable ( version , mobileVersion , mobileTag ),
2026-10-29 18:31:59 -05:00
"" ,
buildFullBuilds ( version ),
2026-06-04 15:16:53 -04:00
]. join ( "\n" );
}
function main () {
const args = parseArgs ( process . argv . slice ( 2 ));
const version = args . version ;
const mobileVersion = args [ "mobile-version" ];
2026-10-10 14:58:27 -05:00
const mobileTag =
typeof args [ "mobile-tag" ] === "string" ? args [ "mobile-tag" ] : undefined ;
const changelogPath = path . resolve ( args . changelog || "CHANGELOG.md" );
2026-06-04 15:16:53 -04:00
if ( ! version || version === true ) fail ( "--version is required" );
if ( ! mobileVersion || mobileVersion === true )
fail ( "--mobile-version is required" );
2026-10-10 14:58:27 -05:00
if ( ! fs . existsSync ( changelogPath )) {
fail ( `changelog not found: ${ changelogPath } ` );
2026-06-04 15:16:53 -04:00
}
2026-10-10 14:58:27 -05:00
const changelog = fs . readFileSync ( changelogPath , "utf8" );
process . stdout . write (
buildBody ({ version , mobileVersion , mobileTag , changelog }) + "\n" ,
);
2026-06-04 15:16:53 -04:00
}
2026-10-10 14:58:27 -05:00
if ( require . main === module ) {
main ();
}
module . exports = { buildBody };