dashboard/shell/utils/dynamic-content/new-release.ts

127 lines
5.0 KiB
TypeScript

/**
*
* The code in this file is responsible for adding New Release notifications driven off of the dynamic content metadata
*
* We handle two cases:
*
* 1. There is a new patch release available for the current Rancher version (e.g. user is in 2.12.0 and we release 2.12.1)
* 2. There is a new patch release available for the current Rancher version AND there is a newer version for a high minor releases
* > this often occurs because we release monthly releases in parallel with the new minor releases
*
* We show slightly different messages in these 2 cases.
*
*/
import semver from 'semver';
import { NotificationLevel } from '@shell/types/notifications';
import { READ_NEW_RELEASE } from '@shell/store/prefs';
import { Context, ReleaseInfo, VersionInfo } from './types';
import { removeMatchingNotifications } from './util';
export async function processReleaseVersion(context: Context, releaseInfo: ReleaseInfo[] | undefined, versionInfo: VersionInfo) {
if (!releaseInfo || !versionInfo?.version || !Array.isArray(releaseInfo)) {
return;
}
const { version } = versionInfo;
const versions = releaseInfo.map((v: any) => semver.coerce(v.name));
// Sort the versions, so that the newest is first in the list
versions.sort((a: any, b: any) => semver.gt(b, a) ? 1 : -1);
// Find first newer version
const newer = versions.find((v: any) => semver.gt(v, version));
// Find newest patch version for the current version (if available)
const newerPatch = versions.find((v: any) => {
const newVersion = semver.coerce(v);
return newVersion && newVersion.major === version.major && newVersion.minor === version.minor && semver.gt(v, version);
});
if (newer) {
context.logger.info(`Found a newer release: ${ newer.version }`);
if (newerPatch && newer !== newerPatch) {
context.logger.info(`Also found a newer patch release: ${ newerPatch.version }`);
// There is a new patch release and a newer release
await addNewMultipleReleasesNotification(context, newerPatch.version, newer.version);
} else {
// There is a new release (but no newer patch release)
await addNewReleaseNotification(context, newer.version);
}
}
}
async function addNewReleaseNotification(context: Context, version: string) {
const prefix = 'new-release-';
const releaseNotesUrl = context.settings.releaseNotesUrl.replace('$version', version);
const { dispatch, getters, logger } = context;
// TODO: Get the preference
const lastReadVersion = getters['prefs/get'](READ_NEW_RELEASE) || '';
const t = getters['i18n/t'];
// Delete notification(s) for old release notes
// This shouldn't happen normally, as we release less often than notifications should expire
if (!await removeMatchingNotifications(context, prefix, version) && lastReadVersion !== version) {
logger.debug(`Adding new release notification for ${ version } because one did not exist`);
const notification = {
id: `${ prefix }${ version }`,
level: NotificationLevel.Announcement,
title: t('dynamicContent.newRelease.title', { version }),
message: t('dynamicContent.newRelease.message', { version }),
preference: {
key: READ_NEW_RELEASE,
value: version
},
primaryAction: {
label: t('dynamicContent.newRelease.moreInfo'),
target: releaseNotesUrl
}
};
await dispatch('notifications/add', notification);
}
}
async function addNewMultipleReleasesNotification(context: Context, version1: string, version2: string) {
const prefix = 'new-release-';
const key = `${ version1 }-${ version2 }`;
const releaseNotesUrl1 = context.settings.releaseNotesUrl.replace('$version', version1);
const releaseNotesUrl2 = context.settings.releaseNotesUrl.replace('$version', version2);
const { dispatch, getters, logger } = context;
// TODO: Get the preference
const lastReadVersion = getters['prefs/get'](READ_NEW_RELEASE) || '';
const t = getters['i18n/t'];
// Delete notification(s) for old release notes
// This shouldn't happen normally, as we release less often than notifications should expire
if (!await removeMatchingNotifications(context, prefix, key) && lastReadVersion !== key) {
logger.info(`Adding new multiple release notification for ${ version1 } and ${ version2 }`);
const notification = {
id: `${ prefix }${ key }`,
level: NotificationLevel.Announcement,
title: t('dynamicContent.multipleNewReleases.title'),
message: t('dynamicContent.multipleNewReleases.message', { version1, version2 }),
preference: {
key: READ_NEW_RELEASE,
value: key
},
primaryAction: {
label: t('dynamicContent.multipleNewReleases.moreInfo', { version: version1 }),
target: releaseNotesUrl1
},
secondaryAction: {
label: t('dynamicContent.multipleNewReleases.moreInfo', { version: version2 }),
target: releaseNotesUrl2
}
};
await dispatch('notifications/add', notification);
}
}