2023-07-12 16:18:05 +02:00
|
|
|
import { fileExtension } from '@joplin/lib/path-utils';
|
|
|
|
|
|
|
|
export interface CheckForUpdateOptions {
|
|
|
|
includePreReleases?: boolean;
|
|
|
|
}
|
|
|
|
|
2024-08-27 19:04:18 +02:00
|
|
|
export interface GitHubReleaseAsset {
|
2023-08-06 13:57:26 +02:00
|
|
|
name: string;
|
|
|
|
browser_download_url: string;
|
2024-09-14 23:16:42 +02:00
|
|
|
url?: string;
|
2023-08-06 13:57:26 +02:00
|
|
|
}
|
|
|
|
|
2023-07-12 16:18:05 +02:00
|
|
|
export interface GitHubRelease {
|
2024-09-14 23:16:42 +02:00
|
|
|
id?: string;
|
2023-07-12 16:18:05 +02:00
|
|
|
tag_name: string;
|
|
|
|
prerelease: boolean;
|
|
|
|
body: string;
|
2023-08-06 13:57:26 +02:00
|
|
|
assets: GitHubReleaseAsset[];
|
2023-07-12 16:18:05 +02:00
|
|
|
html_url: string;
|
|
|
|
}
|
|
|
|
|
2023-08-06 13:57:26 +02:00
|
|
|
export interface Release {
|
2023-07-12 16:18:05 +02:00
|
|
|
version: string;
|
|
|
|
prerelease: boolean;
|
|
|
|
downloadUrl: string;
|
|
|
|
notes: string;
|
|
|
|
pageUrl: string;
|
|
|
|
}
|
|
|
|
|
2023-08-06 13:57:26 +02:00
|
|
|
export type Platform = typeof process.platform;
|
|
|
|
|
|
|
|
export type Architecture = typeof process.arch;
|
|
|
|
|
2023-07-12 16:18:05 +02:00
|
|
|
function getMajorMinorTagName(tagName: string) {
|
|
|
|
const s = tagName.split('.');
|
|
|
|
s.pop();
|
|
|
|
return s.join('.');
|
|
|
|
}
|
|
|
|
|
2023-08-06 13:57:26 +02:00
|
|
|
export const extractVersionInfo = (releases: GitHubRelease[], platform: Platform, arch: Architecture, portable: boolean, options: CheckForUpdateOptions) => {
|
2023-07-12 16:18:05 +02:00
|
|
|
options = { includePreReleases: false, ...options };
|
|
|
|
|
|
|
|
if (!releases.length) throw new Error('Cannot get latest release info (JSON)');
|
|
|
|
|
|
|
|
let release = null;
|
|
|
|
|
|
|
|
if (options.includePreReleases) {
|
|
|
|
release = releases[0];
|
|
|
|
} else {
|
|
|
|
for (const r of releases) {
|
|
|
|
if (!r.prerelease) {
|
|
|
|
release = r;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!release) throw new Error('Could not get tag name');
|
|
|
|
|
|
|
|
const version = release.tag_name.substr(1);
|
|
|
|
|
|
|
|
// We concatenate all the release notes of the major/minor versions
|
|
|
|
// corresponding to the latest version. For example, if the latest version
|
|
|
|
// is 1.8.3, we concatenate all the 1.8.x versions. This is so that no
|
|
|
|
// matter from which version you upgrade, you always see the full changes,
|
|
|
|
// with the latest changes being on top.
|
|
|
|
|
|
|
|
const fullReleaseNotes = [];
|
|
|
|
const majorMinorTagName = getMajorMinorTagName(release.tag_name);
|
|
|
|
|
|
|
|
for (const release of releases) {
|
|
|
|
if (getMajorMinorTagName(release.tag_name) === majorMinorTagName) {
|
|
|
|
fullReleaseNotes.push(release.body.trim());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-06 13:57:26 +02:00
|
|
|
let foundAsset: GitHubReleaseAsset = null;
|
2023-07-12 16:18:05 +02:00
|
|
|
|
2023-08-06 13:57:26 +02:00
|
|
|
if (platform === 'win32' && portable) {
|
|
|
|
foundAsset = release.assets.find(asset => {
|
|
|
|
return asset.name === 'JoplinPortable.exe';
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!foundAsset && platform === 'win32') {
|
|
|
|
foundAsset = release.assets.find(asset => {
|
|
|
|
return !!asset.name.match(/^Joplin-Setup-[\d.]+\.exe$/);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-08-25 10:21:34 +02:00
|
|
|
const arm64DMGPattern = /arm64\.(dmg|DMG)$/;
|
2023-08-06 13:57:26 +02:00
|
|
|
if (platform === 'darwin' && arch === 'arm64') {
|
|
|
|
foundAsset = release.assets.find(asset => {
|
2023-08-25 10:21:34 +02:00
|
|
|
return asset.name.match(arm64DMGPattern);
|
2023-08-06 13:57:26 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!foundAsset && platform === 'darwin') {
|
|
|
|
foundAsset = release.assets.find(asset => {
|
2023-08-25 10:21:34 +02:00
|
|
|
return fileExtension(asset.name) === 'dmg' && !asset.name.match(arm64DMGPattern);
|
2023-08-06 13:57:26 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
if (platform === 'linux') {
|
|
|
|
foundAsset = release.assets.find(asset => {
|
|
|
|
return fileExtension(asset.name) === 'AppImage';
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
let downloadUrl: string = null;
|
|
|
|
|
|
|
|
if (foundAsset) {
|
|
|
|
downloadUrl = foundAsset.browser_download_url.replace('github.com/laurent22/joplin/releases/download', 'objects.joplinusercontent.com');
|
|
|
|
downloadUrl.concat('?source=DesktopApp&type=Update');
|
2023-07-12 16:18:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function cleanUpReleaseNotes(releaseNotes: string[]) {
|
|
|
|
const lines = releaseNotes.join('\n\n* * *\n\n').split('\n');
|
|
|
|
const output = [];
|
|
|
|
for (const line of lines) {
|
|
|
|
const r = line
|
|
|
|
.replace(/\(#.* by .*\)/g, '') // Removes issue numbers and names - (#3157 by [@user](https://github.com/user))
|
|
|
|
.replace(/\([0-9a-z]{7}\)/g, '') // Removes commits - "sync state or data (a6caa35)"
|
|
|
|
.replace(/\(#[0-9]+\)/g, '') // Removes issue numbers - "(#4727)"
|
|
|
|
.replace(/ {2}/g, ' ')
|
|
|
|
.trim();
|
|
|
|
|
|
|
|
output.push(r);
|
|
|
|
}
|
|
|
|
return output.join('\n');
|
|
|
|
}
|
|
|
|
|
|
|
|
const output: Release = {
|
|
|
|
version: version,
|
|
|
|
downloadUrl: downloadUrl,
|
|
|
|
notes: cleanUpReleaseNotes(fullReleaseNotes),
|
|
|
|
pageUrl: release.html_url,
|
|
|
|
prerelease: release.prerelease,
|
|
|
|
};
|
|
|
|
|
|
|
|
return output;
|
|
|
|
};
|