Skip to content
Draft
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 @@ -1155,14 +1155,12 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
this._onChange.fire(undefined);
}
if (e.affectsConfiguration(AutoCheckUpdatesConfigurationKey)) {
if (this.isAutoCheckUpdatesEnabled()) {
this.checkForUpdates(`Enabled auto check updates`);
}
void this.checkForUpdatesAutomatically(`Enabled auto check updates`);
}
}));
this._register(this.extensionEnablementService.onEnablementChanged(platformExtensions => {
if (this.isAutoCheckUpdatesEnabled() && this.getAutoUpdateValue() === 'on' && platformExtensions.some(e => this.extensionEnablementService.isEnabled(e))) {
this.checkForUpdates('Extension enablement changed');
if (this.getAutoUpdateValue() === 'on' && platformExtensions.some(e => this.extensionEnablementService.isEnabled(e))) {
void this.checkForUpdatesAutomatically('Extension enablement changed');
}
}));
this._register(Event.debounce(this.onChange, () => undefined, 100)(() => this.hasOutdatedExtensionsContextKey.set(this.outdated.length > 0)));
Expand All @@ -1172,22 +1170,16 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
owner: 'sandy081';
comment: 'Report when update check is triggered on product update';
}>('extensions:updatecheckonproductupdate');
if (this.isAutoCheckUpdatesEnabled()) {
this.checkForUpdates('Product update');
}
void this.checkForUpdatesAutomatically('Product update');
}
}));

this._register(this.allowedExtensionsService.onDidChangeAllowedExtensionsConfigValue(() => {
if (this.isAutoCheckUpdatesEnabled()) {
this.checkForUpdates('Allowed extensions changed');
}
void this.checkForUpdatesAutomatically('Allowed extensions changed');
}));

this._register(this.meteredConnectionService.onDidChangeIsConnectionMetered(() => {
if (this.isAutoCheckUpdatesEnabled()) {
this.checkForUpdates('Connection is no longer metered');
}
void this.checkForUpdatesAutomatically('Connection is no longer metered');
if (isWeb && !this.isAutoUpdateEnabled()) {
this.autoUpdateBuiltinExtensions();
}
Expand Down Expand Up @@ -2225,13 +2217,26 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
return this.configurationService.getValue(AutoCheckUpdatesConfigurationKey);
}

private async checkForUpdatesAutomatically(reason?: string): Promise<void> {
await this.meteredConnectionService.whenInitialized;
if (!this._store.isDisposed && this.isAutoCheckUpdatesEnabled()) {
await this.checkForUpdates(reason);
}
}

private eventuallyCheckForUpdates(immediate = false): void {
this.updatesCheckDelayer.cancel();
this.updatesCheckDelayer.trigger(async () => {
await this.meteredConnectionService.whenInitialized;
if (this._store.isDisposed) {
return;
}
if (this.isAutoCheckUpdatesEnabled()) {
await this.checkForUpdates();
}
this.eventuallyCheckForUpdates();
if (!this._store.isDisposed) {
this.eventuallyCheckForUpdates();
}
}, immediate ? 0 : this.getUpdatesCheckInterval()).then(undefined, err => null);
}

Expand All @@ -2248,7 +2253,8 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
}

private async autoUpdateBuiltinExtensions(): Promise<void> {
if (this.meteredConnectionService.isConnectionMetered) {
await this.meteredConnectionService.whenInitialized;
if (this._store.isDisposed || this.meteredConnectionService.isConnectionMetered) {
return;
}
await this.checkForUpdates(undefined, true);
Expand All @@ -2272,6 +2278,10 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
}

private async autoUpdateExtensions(): Promise<void> {
await this.meteredConnectionService.whenInitialized;
if (this._store.isDisposed) {
return;
}
if (this.meteredConnectionService.isConnectionMetered) {
this.logService.trace('[Extensions]: Skipping auto-update because connection is metered');
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ suite('ExtensionRecommendationsService Test', () => {
});

instantiationService.stub(IUpdateService, { onStateChange: Event.None, state: State.Uninitialized });
instantiationService.stub(IMeteredConnectionService, { isConnectionMetered: false, onDidChangeIsConnectionMetered: Event.None });
instantiationService.stub(IMeteredConnectionService, { isConnectionMetered: false, whenInitialized: Promise.resolve(), onDidChangeIsConnectionMetered: Event.None });
instantiationService.set(IExtensionsWorkbenchService, disposableStore.add(instantiationService.createInstance(ExtensionsWorkbenchService)));
instantiationService.stub(IExtensionTipsService, disposableStore.add(instantiationService.createInstance(TestExtensionTipsService)));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ function setupTest(disposables: Pick<DisposableStore, 'add'>) {
instantiationService.stub(IUserDataSyncEnablementService, disposables.add(instantiationService.createInstance(UserDataSyncEnablementService)));

instantiationService.stub(IUpdateService, { onStateChange: Event.None, state: State.Uninitialized });
instantiationService.stub(IMeteredConnectionService, { isConnectionMetered: false, onDidChangeIsConnectionMetered: Event.None });
instantiationService.stub(IMeteredConnectionService, { isConnectionMetered: false, whenInitialized: Promise.resolve(), onDidChangeIsConnectionMetered: Event.None });
instantiationService.set(IExtensionsWorkbenchService, disposables.add(instantiationService.createInstance(ExtensionsWorkbenchService)));
instantiationService.stub(IWorkspaceTrustManagementService, disposables.add(new TestWorkspaceTrustManagementService()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ suite('ExtensionsViews Tests', () => {
await (<TestExtensionEnablementService>instantiationService.get(IWorkbenchExtensionEnablementService)).setEnablement([localDisabledLanguage], EnablementState.DisabledGlobally);

instantiationService.stub(IUpdateService, { onStateChange: Event.None, state: State.Uninitialized });
instantiationService.stub(IMeteredConnectionService, { isConnectionMetered: false, onDidChangeIsConnectionMetered: Event.None });
instantiationService.stub(IMeteredConnectionService, { isConnectionMetered: false, whenInitialized: Promise.resolve(), onDidChangeIsConnectionMetered: Event.None });
instantiationService.set(IExtensionsWorkbenchService, disposableStore.add(instantiationService.createInstance(ExtensionsWorkbenchService)));
testableView = disposableStore.add(instantiationService.createInstance(ExtensionsListView, {}, { id: '', title: '' }));
queryPage = aPage([]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import * as sinon from 'sinon';
import assert from 'assert';
import { DeferredPromise, timeout } from '../../../../../base/common/async.js';
import { generateUuid } from '../../../../../base/common/uuid.js';
import { ExtensionState, AutoCheckUpdatesConfigurationKey, AutoUpdateConfigurationKey, AutoUpdateDelayConfigurationKey, ExtensionRuntimeActionType, AutoUpdateConfigurationValue } from '../../common/extensions.js';
import { ExtensionsWorkbenchService } from '../../browser/extensionsWorkbenchService.js';
Expand Down Expand Up @@ -157,7 +158,7 @@ suite('ExtensionsWorkbenchServiceTest', () => {
instantiationService.stubPromise(INotificationService, 'prompt', 0);
(<TestExtensionEnablementService>instantiationService.get(IWorkbenchExtensionEnablementService)).reset();
instantiationService.stub(IUpdateService, { onStateChange: Event.None, state: State.Uninitialized });
instantiationService.stub(IMeteredConnectionService, { isConnectionMetered: false, onDidChangeIsConnectionMetered: Event.None });
instantiationService.stub(IMeteredConnectionService, { isConnectionMetered: false, whenInitialized: Promise.resolve(), onDidChangeIsConnectionMetered: Event.None });
});

test('test gallery extension', async () => {
Expand Down Expand Up @@ -1778,6 +1779,31 @@ suite('ExtensionsWorkbenchServiceTest', () => {
assert.deepStrictEqual(testObject.getDisabledAutoUpdateExtensions(), []);
});

test('waits for metered connection initialization before checking for updates automatically', async () => {
const initialized = new DeferredPromise<void>();
instantiationService.stub(IMeteredConnectionService, {
isConnectionMetered: false,
whenInitialized: initialized.p,
onDidChangeIsConnectionMetered: Event.None,
});
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]);
let getExtensionsCount = 0;
instantiationService.stub(IExtensionGalleryService, 'getExtensions', async () => {
getExtensionsCount++;
return [];
});

testObject = await aWorkbenchService();
await timeout(0);
assert.strictEqual(getExtensionsCount, 0);

initialized.complete();
await timeout(0);
await timeout(0);

assert.strictEqual(getExtensionsCount, 1);
});

async function aWorkbenchService(): Promise<ExtensionsWorkbenchService> {
const workbenchService: ExtensionsWorkbenchService = disposableStore.add(instantiationService.createInstance(ExtensionsWorkbenchService));
await workbenchService.queryLocal();
Expand Down