Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2861,7 +2861,7 @@ export class ExtensionStatusAction extends ExtensionAction {
const delay = fromNow(Date.now() - this.extensionsWorkbenchService.getAutoUpdateDelay(), false, true);
const updateAt = fromNow(Date.now() + this.extensionsWorkbenchService.getAutoUpdateDelayRemaining(this.extension), false, true);
// Do not override the higher-priority warning class with the info class.
this.updateStatus({ icon: infoIcon, message: new MarkdownString(localize('autoUpdateDelayed', "This extension is not updated yet because new versions are auto updated {0} after they are published. It will be auto updated {1}.", delay, updateAt)) }, !hasConsentWarning);
this.updateStatus({ icon: infoIcon, message: new MarkdownString(localize('autoUpdateDelayed', "This extension is not updated yet because new versions become eligible for automatic update {0} after they are published. It will become eligible {1}.", delay, updateAt)) }, !hasConsentWarning);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import * as nls from '../../../../nls.js';
import * as semver from '../../../../base/common/semver/semver.js';
import { Event, Emitter } from '../../../../base/common/event.js';
import { index } from '../../../../base/common/arrays.js';
import { CancelablePromise, Promises, ThrottledDelayer, createCancelablePromise, disposableTimeout } from '../../../../base/common/async.js';
import { CancelablePromise, Promises, ThrottledDelayer, createCancelablePromise } from '../../../../base/common/async.js';
import { CancellationError, getErrorMessage, isCancellationError } from '../../../../base/common/errors.js';
import { Disposable, MutableDisposable, toDisposable } from '../../../../base/common/lifecycle.js';
import { IPager, singlePagePager } from '../../../../base/common/paging.js';
Expand Down Expand Up @@ -999,7 +999,6 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension

private installing: IExtension[] = [];
private tasksInProgress: CancelablePromise<any>[] = [];
private readonly delayedAutoUpdateCheckTimer = this._register(new MutableDisposable());

readonly whenInitialized: Promise<void>;

Expand Down Expand Up @@ -1135,19 +1134,13 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
// Register listeners for auto updates
this._register(this.configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration(AutoUpdateConfigurationKey)) {
if (!this.isAutoUpdateEnabled()) {
// Auto update disabled — cancel any pending delayed re-check
this.delayedAutoUpdateCheckTimer.value = undefined;
} else {
if (this.isAutoUpdateEnabled()) {
this.eventuallyAutoUpdateExtensions();
}
// The auto update value affects whether an extension is shown as delayed
this._onChange.fire(undefined);
}
if (e.affectsConfiguration(AutoUpdateDelayConfigurationKey)) {
// The delay affects when delayed updates are applied — cancel any pending
// delayed re-check and re-run the scheduling path with the new delay.
this.delayedAutoUpdateCheckTimer.value = undefined;
if (this.isAutoUpdateEnabled()) {
this.eventuallyAutoUpdateExtensions();
}
Expand Down Expand Up @@ -2280,7 +2273,6 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
const toUpdate: IExtension[] = [];
const disabledAutoUpdate = [];
const consentRequired = [];
let soonestDelayRemaining = Number.MAX_SAFE_INTEGER;
for (const extension of this.outdated) {
if (!this.shouldAutoUpdateExtension(extension)) {
disabledAutoUpdate.push(extension.identifier.id);
Expand All @@ -2291,7 +2283,6 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
const delayRemaining = this.getAutoUpdateDelayRemaining(extension);
if (delayRemaining > 0) {
this.logService.trace('Auto update delayed for extension', extension.identifier.id);
soonestDelayRemaining = Math.min(soonestDelayRemaining, delayRemaining);
continue;
}
}
Expand All @@ -2302,12 +2293,6 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
toUpdate.push(extension);
}

if (soonestDelayRemaining < Number.MAX_SAFE_INTEGER) {
this.delayedAutoUpdateCheckTimer.value = disposableTimeout(() => this.eventuallyCheckForUpdates(true), soonestDelayRemaining);
} else {
this.delayedAutoUpdateCheckTimer.value = undefined;
}

if (disabledAutoUpdate.length) {
this.logService.trace('Auto update disabled for extensions', disabledAutoUpdate.join(', '));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@

import * as sinon from 'sinon';
import assert from 'assert';
import { timeout } from '../../../../../base/common/async.js';
import { generateUuid } from '../../../../../base/common/uuid.js';
import { runWithFakedTimers } from '../../../../../base/test/common/virtualScheduling/index.js';
import { ExtensionState, AutoCheckUpdatesConfigurationKey, AutoUpdateConfigurationKey, AutoUpdateDelayConfigurationKey, ExtensionRuntimeActionType, AutoUpdateConfigurationValue } from '../../common/extensions.js';
import { ExtensionsWorkbenchService } from '../../browser/extensionsWorkbenchService.js';
import {
Expand Down Expand Up @@ -496,6 +498,31 @@ suite('ExtensionsWorkbenchServiceTest', () => {
assert.strictEqual(testObject.isAutoUpdateDelayed(testObject.local[0]), false);
});

test('test delayed auto update does not reschedule the marketplace update check', () => runWithFakedTimers({ useFakeTimers: true, startTime: 1000 * 60 * 60 * 3 }, async () => {
const local = aLocalExtension('a', { version: '1.0.1' });
const gallery = aGalleryExtension(local.manifest.name, {
identifier: local.identifier,
version: '1.0.2',
lastUpdated: Date.now() - (1000 * 60 * 60)
});
let updateCheckCount = 0;
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
instantiationService.stub(IExtensionGalleryService, 'getExtensions', async () => {
updateCheckCount++;
return [gallery];
});

testObject = await aWorkbenchService();
await testObject.checkForUpdates();
await timeout(1001);
const updateCheckCountBeforeQuarantineExpires = updateCheckCount;

await timeout(1000 * 60 * 60);

assert.strictEqual(updateCheckCount, updateCheckCountBeforeQuarantineExpires);
testObject.dispose();
}));

test('test getAutoUpdateValue normalizes legacy and migrated values', async () => {
const expected = new Map<unknown, AutoUpdateConfigurationValue>([
['on', 'on'],
Expand Down
Loading