diff --git a/src/updatechecker.js b/src/updatechecker.js index 5741d0678..cc8fa06c3 100644 --- a/src/updatechecker.js +++ b/src/updatechecker.js @@ -12,11 +12,12 @@ exports = module.exports = { const apps = require('./apps.js'), appstore = require('./appstore.js'), assert = require('assert'), + constants = require('./constants.js'), debug = require('debug')('box:updatechecker'), notifications = require('./notifications.js'), paths = require('./paths.js'), safe = require('safetydance'), - util = require('util'); + updater = require('./updater.js'); function setUpdateInfo(state) { // appid -> update info { creationDate, manifest } @@ -83,22 +84,38 @@ async function checkBoxUpdates(options) { return; } - if (util.isDeepStrictEqual(state.box, updateInfo)) { - debug(`checkBoxUpdates: Skipping notification of box update ${updateInfo.version} as user was already notified`); - return; - } - - debug(`checkBoxUpdates: ${updateInfo.version} is available. renotification: ${!!state.box}`); - - const changelog = updateInfo.changelog.map((m) => `* ${m}\n`).join(''); - const message = `Changelog:\n${changelog}\n\nGo to the Settings view to update.\n\n`; - - await notifications.pin(notifications.TYPE_BOX_UPDATE, `Cloudron v${updateInfo.version} is available`, message, { context: updateInfo.version }); + debug(`checkBoxUpdates: ${updateInfo.version} is available`); state.box = updateInfo; setUpdateInfo(state); } +async function raiseNotifications() { + const state = getUpdateInfo(); + + const pattern = await updater.getAutoupdatePattern(); + + if (pattern === constants.AUTOUPDATE_PATTERN_NEVER && state.box) { + const updateInfo = state.box; + const changelog = updateInfo.changelog.map((m) => `* ${m}\n`).join(''); + const message = `Changelog:\n${changelog}\n\nGo to the Settings view to update.\n\n`; + + await notifications.pin(notifications.TYPE_BOX_UPDATE, `Cloudron v${updateInfo.version} is available`, message, { context: updateInfo.version }); + } + + const result = await apps.list(); + for (const app of result) { + // currently, we do not raise notifications when auto-update is disabled. separate notifications appears spammy when having many apps + // in the future, we can maybe aggregate? + if (app.updateInfo && !app.updateInfo.isAutoUpdatable) { + debug(`autoUpdate: ${app.fqdn} cannot be autoupdated. skipping`); + await notifications.pin(notifications.TYPE_MANUAL_APP_UPDATE_NEEDED, `${app.manifest.title} at ${app.fqdn} requires manual update to version ${app.updateInfo.manifest.version}`, + `Changelog:\n${app.updateInfo.manifest.changelog}\n`, { context: app.id }); + continue; + } + } +} + async function checkForUpdates(options) { assert.strictEqual(typeof options, 'object'); @@ -107,4 +124,7 @@ async function checkForUpdates(options) { const [appError] = await safe(checkAppUpdates(options)); if (appError) debug('checkForUpdates: error checking for app updates: %o', appError); + + // raise notifications here because the updatechecker runs regardless of auto-updater cron job + await raiseNotifications(); } diff --git a/src/updater.js b/src/updater.js index 2310bccef..8e008740a 100644 --- a/src/updater.js +++ b/src/updater.js @@ -274,10 +274,10 @@ async function autoUpdate(auditSource) { continue; } + if (!app.updateInfo) continue; // possible, if an update check happenned in parallel + if (!app.updateInfo?.isAutoUpdatable) { - debug(`autoUpdate: ${app.fqdn} cannot be autoupdated. skipping`); - await notifications.pin(notifications.TYPE_MANUAL_APP_UPDATE_NEEDED, `${app.manifest.title} at ${app.fqdn} requires manual update to version ${appUpdateInfo.manifest.version}`, - `Changelog:\n${appUpdateInfo.manifest.changelog}\n`, { context: app.id }); + debug(`autoUpdate: ${app.fqdn} requires manual update. skipping`); continue; }