mirror of
https://github.com/microsoft/vscode.git
synced 2026-07-08 15:55:15 +01:00
da03e4ef04
* extensions: add delayed auto-update mode to extensions.autoUpdate
Folds a 6-hour delayed auto-update mode into the existing
`extensions.autoUpdate` setting, which is now a string enum
('on' | 'delayed' | 'off') and policy-controllable via the
ExtensionsAutoUpdate policy.
When set to 'delayed', an extension whose newer version was published
less than 6 hours ago is treated as outdated-but-delayed: it is excluded
from auto-update and the activity badge, and surfaces an info status
explaining when it will be auto updated. Manual updates still work.
Includes startup migration from legacy values (true/'all'/
'onlyEnabledExtensions' -> 'on'; false/'none'/'onlySelectedExtensions'
-> 'off') plus defensive read-time normalization, and unit tests for the
new logic.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* update policy file
* extensions: address code review feedback for delayed auto-update
- Type IExtensionsConfiguration.autoUpdate as AutoUpdateConfigurationValue
- Keep ExtensionStatusAction.update() returning void; add recomputeStatus()
for callers that need to await the computed status
- Preserve the higher-priority warning CSS class when the delayed info status
is also applied to an outdated extension
- Hover awaits recomputeStatus() instead of update()
- Update pluginAutoUpdate doc comment to the on/delayed/off enum values
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* update policies data
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
81 lines
3.5 KiB
TypeScript
81 lines
3.5 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
|
|
import { CancellationToken } from '../../../../base/common/cancellation.js';
|
|
import { Disposable } from '../../../../base/common/lifecycle.js';
|
|
import { autorun } from '../../../../base/common/observable.js';
|
|
import { ILogService } from '../../../../platform/log/common/log.js';
|
|
import { IWorkbenchContribution } from '../../../common/contributions.js';
|
|
import { IExtensionsWorkbenchService } from '../../extensions/common/extensions.js';
|
|
import { IPluginInstallService } from '../common/plugins/pluginInstallService.js';
|
|
import { IPluginMarketplaceService } from '../common/plugins/pluginMarketplaceService.js';
|
|
|
|
/**
|
|
* Bridges the periodic plugin update *check* performed by
|
|
* {@link IPluginMarketplaceService} with the plugin update *action* exposed
|
|
* by {@link IPluginInstallService}.
|
|
*
|
|
* The marketplace service flips `hasUpdatesAvailable` to `true` roughly once
|
|
* a day when at least one cloned plugin repository has upstream changes.
|
|
* Without this contribution, that signal was never consumed and plugins
|
|
* were never auto-updated (see microsoft/vscode#308563).
|
|
*
|
|
* When the signal becomes `true` and `extensions.autoUpdate` is set to update
|
|
* extensions (`'on'` or `'delayed'`), we silently update all installed plugins.
|
|
* The `'off'` mode gates updates on a per-extension opt-in that has no plugin
|
|
* equivalent, so it is treated the same as disabled for plugins.
|
|
*
|
|
* The flag is cleared after every attempt — including failures — so the
|
|
* next periodic check's `false → true` transition can always re-trigger the
|
|
* autorun. `updateAllPlugins` already clears it on success; clearing again
|
|
* in `finally` is a no-op on the success path and handles the partial-
|
|
* failure path where the install service leaves the flag at `true`.
|
|
*/
|
|
export class PluginAutoUpdate extends Disposable implements IWorkbenchContribution {
|
|
static readonly ID = 'workbench.contrib.pluginAutoUpdate';
|
|
|
|
private _updateInFlight = false;
|
|
|
|
constructor(
|
|
@IPluginMarketplaceService private readonly _pluginMarketplaceService: IPluginMarketplaceService,
|
|
@IPluginInstallService private readonly _pluginInstallService: IPluginInstallService,
|
|
@IExtensionsWorkbenchService private readonly _extensionsWorkbenchService: IExtensionsWorkbenchService,
|
|
@ILogService private readonly _logService: ILogService,
|
|
) {
|
|
super();
|
|
|
|
this._register(autorun(reader => {
|
|
if (!this._pluginMarketplaceService.hasUpdatesAvailable.read(reader)) {
|
|
return;
|
|
}
|
|
void this._triggerAutoUpdate();
|
|
}));
|
|
}
|
|
|
|
private async _triggerAutoUpdate(): Promise<void> {
|
|
if (this._updateInFlight) {
|
|
return;
|
|
}
|
|
|
|
const autoUpdate = this._extensionsWorkbenchService.getAutoUpdateValue();
|
|
if (autoUpdate === 'off') {
|
|
return;
|
|
}
|
|
|
|
this._updateInFlight = true;
|
|
try {
|
|
await this._pluginInstallService.updateAllPlugins({ silent: true }, CancellationToken.None);
|
|
} catch (err) {
|
|
this._logService.error('[PluginAutoUpdate] Failed to auto-update plugins:', err);
|
|
} finally {
|
|
this._updateInFlight = false;
|
|
// Ensure the flag is cleared even on partial failure so the next
|
|
// periodic check can re-arm the autorun via a `false → true`
|
|
// transition.
|
|
this._pluginMarketplaceService.clearUpdatesAvailable();
|
|
}
|
|
}
|
|
}
|