Update Code to 1.141.0 (#8040)

* Update Code to 1.141.0
* Allow pull_request_target
* Add e2e tests for remote storage
* Fix Typescript extension not loading
* Remove unused imports
This commit is contained in:
cdrci
2026-10-07 22:54:47 -08:00
committed by GitHub
parent 6d7b6f8a17
commit 8b41915d25
17 changed files with 338 additions and 58 deletions
+9
View File
@@ -79,6 +79,9 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
with:
submodules: true
# When an update/ branch is merged, a release is automatically created
# which requires secrets.
allow-unsafe-pr-checkout: true
- run: quilt push -a
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
with:
@@ -173,6 +176,9 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
with:
submodules: true
# When an update/ branch is merged, a release is automatically created
# which requires secrets.
allow-unsafe-pr-checkout: true
- run: quilt push -a
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
with:
@@ -233,6 +239,9 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
with:
submodules: true
# When an update/ branch is merged, a release is automatically created
# which requires secrets.
allow-unsafe-pr-checkout: true
# quilt has no windows build. The patches are ordinary -p1 diffs
# against the repository root, so git applies them in series order.
+17
View File
@@ -22,6 +22,23 @@ Code v99.99.999
## Unreleased
Code v1.141.0
### Added
- A new `--enable-remote-storage` flag can be used to make code-server persist
workbench storage on the remote server instead of browser storage. Use this if
you want to share storage between multiple devices.
### Fixed
- The Typescript extension was trying to load as a browser extension even though
we build the remote server version, causing it to fail to activate.
### Changed
- Update to Code 1.141.0
## [4.140.0](https://github.com/coder/code-server/releases/tag/v4.140.0) - 2026-10-02
Code v1.140.0
+14 -4
View File
@@ -58,10 +58,17 @@ main() {
exit 1
fi
# Add the date, our name, links, enable telemetry (this just makes telemetry
# available; telemetry can still be disabled by flag or setting), and
# configure trusted extensions (since some, like github.copilot-chat, never
# ask to be trusted and this is the only way to get auth working).
# Modify the product.json:
# - Add the date
# - Set the code-server name.
# - Add our links
# - Enable telemetry (this just makes telemetry available; telemetry can still
# be disabled by flag or setting)
# - Configure trusted extensions (since some, like github.copilot-chat, never
# ask to be trusted and this is the only way to get auth working).
# - Make Typescript server plugins run in the workspace. We build the remote
# server version, so there is no browser distribution, and this key is not
# added automatically.
#
# This needs to be done before building as Code will read this file and embed
# it into the client-side code.
@@ -103,6 +110,9 @@ main() {
],
"aiConfig": {
"ariaKey": "code-server"
},
"extensionPointExtensionKind": {
"typescriptServerPlugins": ["workspace"]
}
}
EOF
+6 -6
View File
@@ -48,8 +48,8 @@ Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench-dev.html
+ <link rel="manifest" href="{{VS_BASE}}/manifest.json" crossorigin="use-credentials" />
<style id="vscode-css-modules" type="text/css" media="screen"></style>
</head>
@@ -41,7 +41,7 @@
<!-- Startup fallback: shown only if the scripts below never run, e.g. because a proxy,
@@ -92,7 +92,7 @@
<!-- Startup (do not modify order of script tags!) -->
<script nonce="{{WORKBENCH_SCRIPT_NONCE}}">
@@ -85,8 +85,8 @@ Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.html
+ <link rel="manifest" href="{{VS_BASE}}/manifest.json" crossorigin="use-credentials" />
<link rel="stylesheet" href="{{WORKBENCH_WEB_BASE_URL}}/out/vs/code/browser/workbench/workbench.css">
</head>
@@ -37,7 +37,7 @@
<!-- Startup fallback: shown only if the scripts below never run, e.g. because a proxy,
@@ -88,7 +88,7 @@
<!-- Startup (do not modify order of script tags!) -->
<script nonce="{{WORKBENCH_SCRIPT_NONCE}}">
@@ -281,8 +281,8 @@ Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.ts
-
(function () {
// Find config by checking for DOM
@@ -610,8 +600,8 @@ function readCookie(name: string): strin
// This script running at all means the page scripts were not blocked or rewritten.
@@ -614,8 +604,8 @@ function readCookie(name: string): strin
if (!configElement || !configElementAttribute) {
throw new Error('Missing web configuration element');
}
+5 -5
View File
@@ -272,7 +272,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/extensions/browser/extens
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts
+++ code-server/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts
@@ -475,9 +475,6 @@ export class InstallAction extends Exten
@@ -479,9 +479,6 @@ export class InstallAction extends Exten
if (this.extension.isBuiltin) {
return;
}
@@ -282,7 +282,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/extensions/browser/extens
if (this.extension.state !== ExtensionState.Uninstalled) {
return;
}
@@ -782,7 +779,7 @@ export abstract class InstallInOtherServ
@@ -786,7 +783,7 @@ export abstract class InstallInOtherServ
}
if (isLanguagePackExtension(this.extension.local.manifest)) {
@@ -291,7 +291,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/extensions/browser/extens
}
// Prefers to run on UI
@@ -2281,17 +2278,6 @@ export class SetLanguageAction extends E
@@ -2285,17 +2282,6 @@ export class SetLanguageAction extends E
update(): void {
this.enabled = false;
this.class = SetLanguageAction.DisabledClass;
@@ -309,7 +309,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/extensions/browser/extens
}
override async run(): Promise<any> {
@@ -2308,7 +2294,6 @@ export class ClearLanguageAction extends
@@ -2312,7 +2298,6 @@ export class ClearLanguageAction extends
private static readonly DisabledClass = `${this.EnabledClass} disabled`;
constructor(
@@ -317,7 +317,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/extensions/browser/extens
@ILocaleService private readonly localeService: ILocaleService,
) {
super(ClearLanguageAction.ID, ClearLanguageAction.TITLE.value, ClearLanguageAction.DisabledClass, false);
@@ -2318,17 +2303,6 @@ export class ClearLanguageAction extends
@@ -2322,17 +2307,6 @@ export class ClearLanguageAction extends
update(): void {
this.enabled = false;
this.class = ClearLanguageAction.DisabledClass;
+2 -2
View File
@@ -225,7 +225,7 @@ Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench-dev.html
+ <link rel="manifest" href="/manifest.json" crossorigin="use-credentials" />
<style id="vscode-css-modules" type="text/css" media="screen"></style>
</head>
<!-- Startup fallback: shown only if the scripts below never run, e.g. because a proxy,
Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.html
===================================================================
--- code-server.orig/lib/vscode/src/vs/code/browser/workbench/workbench.html
@@ -251,7 +251,7 @@ Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.html
+ <link rel="manifest" href="/manifest.json" crossorigin="use-credentials" />
<link rel="stylesheet" href="{{WORKBENCH_WEB_BASE_URL}}/out/vs/code/browser/workbench/workbench.css">
</head>
<!-- Startup fallback: shown only if the scripts below never run, e.g. because a proxy,
Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts
+2 -2
View File
@@ -110,7 +110,7 @@ Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.ts
import type { IURLCallbackProvider } from '../../../workbench/services/url/browser/urlService.js';
import { create } from '../../../workbench/workbench.web.main.internal.js';
@@ -612,6 +613,44 @@ class WorkspaceProvider implements IWork
@@ -616,6 +617,44 @@ class WorkspaceProvider implements IWork
settingsSyncOptions: config.settingsSyncOptions ? { enabled: config.settingsSyncOptions.enabled, } : undefined,
workspaceProvider: WorkspaceProvider.create(config),
urlCallbackProvider: new LocalStorageURLCallbackProvider(config.callbackRoute),
@@ -159,7 +159,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/remote/browser/remoteExpl
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts
+++ code-server/lib/vscode/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts
@@ -99,8 +99,8 @@ export class ForwardedPortsView extends
@@ -100,8 +100,8 @@ export class ForwardedPortsView extends
private async enableForwardedPortsFeatures() {
this.contextKeyListener.clear();
+11 -7
View File
@@ -3,10 +3,10 @@ Index: code-server/lib/vscode/src/vs/platform/secrets/common/secrets.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/platform/secrets/common/secrets.ts
+++ code-server/lib/vscode/src/vs/platform/secrets/common/secrets.ts
@@ -139,8 +139,13 @@ export class BaseSecretStorageService ex
@@ -144,8 +144,13 @@ export class BaseSecretStorageService ex
return await readEncryptedSecret(
key,
(fullKey) => this.getValueFromStorage(key, fullKey, storageService),
(fullKey) => this.getValueFromStorage(key, fullKey, storageService),
- // If the storage service is in-memory, we don't need to decrypt
- this._type === 'in-memory' ? (v) => Promise.resolve(v) : (v) => this._encryptionService.decrypt(v),
+ // Don't decrypt if storage is in-memory or if encryption service is not available
@@ -19,10 +19,10 @@ Index: code-server/lib/vscode/src/vs/platform/secrets/common/secrets.ts
this._logService,
);
} catch (e) {
@@ -160,8 +165,13 @@ export class BaseSecretStorageService ex
@@ -168,8 +173,13 @@ export class BaseSecretStorageService ex
key,
value,
(fullKey, encrypted) => this.setValueInStorage(key, fullKey, encrypted, storageService),
(fullKey, encrypted) => this.setValueInStorage(key, fullKey, encrypted, storageService),
- // If the storage service is in-memory, we don't need to encrypt
- this._type === 'in-memory' ? (v) => Promise.resolve(v) : (v) => this._encryptionService.encrypt(v),
+ // Don't encrypt if storage is in-memory or if encryption service is not available
@@ -35,7 +35,7 @@ Index: code-server/lib/vscode/src/vs/platform/secrets/common/secrets.ts
this._logService,
);
} catch (e) {
@@ -194,8 +204,9 @@ export class BaseSecretStorageService ex
@@ -224,8 +234,9 @@ export class BaseSecretStorageService ex
private async initialize(): Promise<IStorageService> {
let storageService;
@@ -47,7 +47,7 @@ Index: code-server/lib/vscode/src/vs/platform/secrets/common/secrets.ts
this._type = 'persisted';
storageService = this._storageService;
} else {
@@ -203,7 +214,7 @@ export class BaseSecretStorageService ex
@@ -233,7 +244,7 @@ export class BaseSecretStorageService ex
if (this._type === 'in-memory') {
return this._storageService;
}
@@ -77,10 +77,14 @@ Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/code/browser/workbench/workbench.ts
+++ code-server/lib/vscode/src/vs/code/browser/workbench/workbench.ts
@@ -625,2 +625,2 @@
@@ -655,8 +655,8 @@ class WorkspaceProvider implements IWork
})
}
},
- secretStorageProvider: config.remoteAuthority && !secretStorageKeyPath
- ? undefined /* with a remote without embedder-preferred storage, store on the remote */
+ secretStorageProvider: config.remoteStorageEnabled || (config.remoteAuthority && !secretStorageKeyPath)
+ ? undefined /* with remote storage enabled, or without embedder-prefered storage, store on the remote */
: new LocalStorageSecretStorageProvider(secretStorageCrypto),
});
})();
+146 -22
View File
@@ -1,8 +1,13 @@
Reuse VS Code's Electron storage service for remote persistence
Index: code-server/lib/vscode/src/vs/platform/storage/electron-main/storageMainService.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/platform/storage/electron-main/storageMainService.ts
+++ code-server/lib/vscode/src/vs/platform/storage/electron-main/storageMainService.ts
@@ -14 +14,6 @@
@@ -11,7 +11,12 @@ import { IStorage } from '../../../base/
import { INativeEnvironmentService } from '../../environment/common/environment.js';
import { IFileService } from '../../files/common/files.js';
import { createDecorator } from '../../instantiation/common/instantiation.js';
-import { ILifecycleMainService, LifecycleMainPhase, ShutdownReason } from '../../lifecycle/electron-main/lifecycleMainService.js';
+import type { ILifecycleMainService, ShutdownReason } from '../../lifecycle/electron-main/lifecycleMainService.js';
+
@@ -10,44 +15,110 @@ Reuse VS Code's Electron storage service for remote persistence
+// that module imports Electron, which is not present in the code-server server image.
+const LIFECYCLE_MAIN_PHASE_AFTER_WINDOW_OPEN = 3;
+const SHUTDOWN_REASON_KILL = 2;
@@ -101 +101 @@
import { ILogService } from '../../log/common/log.js';
import { AbstractStorageService, isProfileUsingDefaultStorage, IStorageService, StorageScope, StorageTarget } from '../common/storage.js';
import { ApplicationStorageMain, ApplicationSharedStorageMain, ProfileStorageMain, InMemoryStorageMain, IStorageMain, IStorageMainOptions, WorkspaceStorageMain, IStorageChangeEvent } from './storageMain.js';
@@ -92,7 +97,7 @@ export class StorageMainService extends
@ILogService private readonly logService: ILogService,
@INativeEnvironmentService private readonly environmentService: INativeEnvironmentService,
@IUserDataProfilesMainService private readonly userDataProfilesService: IUserDataProfilesMainService,
- @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService,
+ private readonly lifecycleMainService: ILifecycleMainService,
@@ -117 +117 @@
@IFileService private readonly fileService: IFileService,
@IUriIdentityService private readonly uriIdentityService: IUriIdentityService,
) {
@@ -114,7 +119,7 @@ export class StorageMainService extends
// Application Storage: Warmup when any window opens
(async () => {
- await this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen);
+ await this.lifecycleMainService.when(LIFECYCLE_MAIN_PHASE_AFTER_WINDOW_OPEN);
@@ -256 +256 @@
this.applicationStorage.init();
this.applicationSharedStorage.init();
@@ -253,7 +258,7 @@ export class StorageMainService extends
}
private createProfileStorage(profile: IUserDataProfile): IStorageMain {
- if (this.shutdownReason === ShutdownReason.KILL) {
+ if (this.shutdownReason === SHUTDOWN_REASON_KILL) {
@@ -295 +295 @@
// Workaround for native crashes that we see when
// SQLite DBs are being created even after shutdown
@@ -292,7 +297,7 @@ export class StorageMainService extends
}
private createWorkspaceStorage(workspace: IAnyWorkspaceIdentifier): IStorageMain {
- if (this.shutdownReason === ShutdownReason.KILL) {
+ if (this.shutdownReason === SHUTDOWN_REASON_KILL) {
// Workaround for native crashes that we see when
// SQLite DBs are being created even after shutdown
Index: code-server/lib/vscode/src/vs/workbench/services/storage/electron-browser/storageService.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/services/storage/electron-browser/storageService.ts
+++ code-server/lib/vscode/src/vs/workbench/services/storage/electron-browser/storageService.ts
@@ -6 +6 @@
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-import { IMainProcessService } from '../../../../platform/ipc/common/mainProcessService.js';
+import { IRemoteService } from '../../../../platform/ipc/common/services.js';
@@ -22 +22 @@
import { IStorage, Storage, MigratingStorage } from '../../../../base/parts/storage/common/storage.js';
import { RemoteStorageService } from '../../../../platform/storage/common/storageService.js';
import { FallbackApplicationStorageDatabaseClient, ApplicationSharedStorageDatabaseClient } from '../../../../platform/storage/common/storageIpc.js';
@@ -19,10 +19,10 @@ export class NativeWorkbenchStorageServi
workspace: IAnyWorkspaceIdentifier | undefined,
private readonly userDataProfileService: IUserDataProfileService,
userDataProfilesService: IUserDataProfilesService,
- mainProcessService: IMainProcessService,
+ remoteService: Pick<IRemoteService, 'getChannel'>,
@@ -25 +25 @@
private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService,
) {
- super(workspace, { currentProfile: userDataProfileService.currentProfile, defaultProfile: userDataProfilesService.defaultProfile }, mainProcessService, workbenchEnvironmentService);
+ super(workspace, { currentProfile: userDataProfileService.currentProfile, defaultProfile: userDataProfilesService.defaultProfile }, remoteService as IRemoteService, workbenchEnvironmentService);
this.registerListeners();
}
Index: code-server/lib/vscode/src/vs/server/node/serverEnvironmentService.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/serverEnvironmentService.ts
+++ code-server/lib/vscode/src/vs/server/node/serverEnvironmentService.ts
@@ -68,0 +69 @@
@@ -66,6 +66,7 @@ export const serverOptions: OptionDescri
'disable-experiments': OPTIONS['disable-experiments'],
'disable-workspace-trust': OPTIONS['disable-workspace-trust'],
'file-watcher-polling': { type: 'string', deprecates: ['fileWatcherPolling'] },
+ 'enable-remote-storage': { type: 'boolean', cat: 'o', description: nls.localize('enable-remote-storage', 'Persist browser storage (settings, state, etc.) on the server instead of browser IndexedDB. Enables state portability across browsers/devices.') },
@@ -214,0 +216 @@
'log': OPTIONS['log'],
'logsPath': OPTIONS['logsPath'],
'force-disable-user-env': OPTIONS['force-disable-user-env'],
@@ -212,6 +213,7 @@ export interface ServerParsedArgs {
'logsPath'?: string;
'force-disable-user-env'?: boolean;
+ 'enable-remote-storage'?: boolean;
'enable-proposed-api'?: string[];
/* ----- vs code web options ----- */
Index: code-server/lib/vscode/src/vs/server/node/serverServices.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/serverServices.ts
+++ code-server/lib/vscode/src/vs/server/node/serverServices.ts
@@ -107,0 +108,4 @@
@@ -105,6 +105,10 @@ import { McpManagementChannel } from '..
import { AllowedMcpServersService } from '../../platform/mcp/common/allowedMcpServersService.js';
import { IMcpGalleryManifestService } from '../../platform/mcp/common/mcpGalleryManifest.js';
import { McpGalleryManifestIPCService } from '../../platform/mcp/common/mcpGalleryManifestServiceIpc.js';
+import { StorageDatabaseChannel } from '../../platform/storage/electron-main/storageIpc.js';
+import { StorageMainService } from '../../platform/storage/electron-main/storageMainService.js';
+import type { ILifecycleMainService } from '../../platform/lifecycle/electron-main/lifecycleMainService.js';
+import type { IUserDataProfilesMainService } from '../../platform/userDataProfile/electron-main/userDataProfile.js';
@@ -240,0 +245,15 @@
import { SANDBOX_HELPER_CHANNEL_NAME, SandboxHelperChannel } from '../../platform/sandbox/common/sandboxHelperIpc.js';
import { SandboxHelperService } from '../../platform/sandbox/node/sandboxHelper.js';
@@ -238,6 +242,21 @@ export async function setupServerService
services.set(IMcpGatewayService, new SyncDescriptor(McpGatewayService));
const instantiationService: IInstantiationService = new InstantiationService(services);
+ // Reuse the Electron storage service on the remote. The server has no
+ // windows, so its lifecycle is always ready and never loads a window.
+ const storageMainService = disposables.add(new StorageMainService(
@@ -63,7 +134,10 @@ Reuse VS Code's Electron storage service for remote persistence
+ uriIdentityService,
+ ));
+
@@ -419,6 +439,7 @@ export async function setupServerServices(connectionToken: ServerConnectionToken
services.set(ILanguagePackService, instantiationService.createInstance(NativeLanguagePackService));
const ptyHostStarter = instantiationService.createInstance(
@@ -420,6 +439,7 @@ export async function setupServerService
const languagePackChannel = ProxyChannel.fromService<RemoteAgentConnectionContext>(accessor.get(ILanguagePackService), disposables);
socketServer.registerChannel('languagePacks', languagePackChannel);
@@ -71,28 +145,61 @@ Reuse VS Code's Electron storage service for remote persistence
// clean up extensions folder
remoteExtensionsScanner.whenExtensionsReady().then(() => extensionManagementService.cleanUp());
Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts
+++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts
@@ -411 +411,2 @@
@@ -451,7 +451,8 @@ export class WebClientServer {
folderUri: resolveWorkspaceURI(this._environmentService.args['default-folder']),
workspaceUri: resolveWorkspaceURI(this._environmentService.args['default-workspace']),
productConfiguration,
- callbackRoute: callbackRoute
+ callbackRoute: callbackRoute,
+ remoteStorageEnabled: this._environmentService.args['enable-remote-storage'] ? true : undefined
};
const cookies = cookie.parse(req.headers.cookie || '');
Index: code-server/lib/vscode/src/vs/workbench/browser/web.api.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/browser/web.api.ts
+++ code-server/lib/vscode/src/vs/workbench/browser/web.api.ts
@@ -413,0 +414,5 @@
@@ -411,6 +411,11 @@ export interface IWorkbenchConstructionO
readonly authenticationProviders?: readonly IAuthenticationProvider[];
//#endregion
+ /**
+ * Persist workbench storage on the remote server instead of browser IndexedDB.
+ */
+ readonly remoteStorageEnabled?: boolean;
+
//#region Development options
Index: code-server/lib/vscode/src/vs/workbench/browser/web.main.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/workbench/browser/web.main.ts
+++ code-server/lib/vscode/src/vs/workbench/browser/web.main.ts
@@ -35,0 +36 @@
@@ -33,6 +33,7 @@ import { ISignService } from '../../plat
import { SignService } from '../../platform/sign/browser/signService.js';
import { IWorkbenchConstructionOptions, IWorkbench, IWorkspace, ITunnel } from './web.api.js';
import { BrowserStorageService } from '../services/storage/browser/storageService.js';
+import { NativeWorkbenchStorageService } from '../services/storage/electron-browser/storageService.js';
@@ -479 +480 @@
import { IStorageService } from '../../platform/storage/common/storage.js';
import { toLocalISOString } from '../../base/common/date.js';
import { isWorkspaceToOpen, isFolderToOpen } from '../../platform/window/common/window.js';
@@ -482,7 +483,7 @@ export class BrowserMain extends Disposa
serviceCollection.set(IWorkbenchConfigurationService, service);
return service;
}),
- this.createStorageService(workspace, logService, userDataProfileService).then(service => {
+ this.createStorageService(workspace, environmentService, logService, userDataProfileService, userDataProfilesService, remoteAgentService).then(service => {
@@ -601 +602,15 @@
serviceCollection.set(IStorageService, service);
return service;
})
@@ -604,7 +605,21 @@ export class BrowserMain extends Disposa
}));
}
- protected async createStorageService(workspace: IAnyWorkspaceIdentifier, logService: ILogService, userDataProfileService: IUserDataProfileService): Promise<IStorageService> {
+ protected async createStorageService(workspace: IAnyWorkspaceIdentifier, environmentService: IBrowserWorkbenchEnvironmentService, logService: ILogService, userDataProfileService: IUserDataProfileService, userDataProfilesService: IUserDataProfilesService, remoteAgentService: IRemoteAgentService): Promise<IStorageService> {
+ const connection = remoteAgentService.getConnection();
@@ -109,14 +216,31 @@ Reuse VS Code's Electron storage service for remote persistence
+ }
+ }
+
const storageService = new BrowserStorageService(workspace, userDataProfileService, logService);
try {
Index: code-server/lib/vscode/src/vs/sessions/browser/web.main.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/sessions/browser/web.main.ts
+++ code-server/lib/vscode/src/vs/sessions/browser/web.main.ts
@@ -42 +42 @@
@@ -39,9 +39,9 @@ export class SessionsBrowserMain extends
_workspace: IAnyWorkspaceIdentifier,
environmentService: IBrowserWorkbenchEnvironmentService,
userDataProfileService: IUserDataProfileService,
- _userDataProfilesService: BrowserUserDataProfilesService,
+ userDataProfilesService: BrowserUserDataProfilesService,
@@ -44 +44 @@
fileService: FileService,
- _remoteAgentService: IRemoteAgentService,
+ remoteAgentService: IRemoteAgentService,
@@ -85 +85 @@
uriIdentityService: IUriIdentityService,
policyService: IPolicyService,
logService: ILogService,
@@ -82,7 +82,7 @@ export class SessionsBrowserMain extends
serviceCollection.set(IWorkbenchConfigurationService, configurationService);
// Storage
- const storageService = await this.createStorageService(workspaceIdentifier, logService, userDataProfileService);
+ const storageService = await this.createStorageService(workspaceIdentifier, environmentService, logService, userDataProfileService, userDataProfilesService, remoteAgentService);
serviceCollection.set(IStorageService, storageService);
// Workspace Trust Service
+1 -1
View File
@@ -24,6 +24,6 @@ trusted-domains.diff
signature-verification.diff
copilot.diff
app-name.diff
csp-hashes.diff
remote-storage.diff
remote-secret-storage.diff
csp-hashes.diff
@@ -2,7 +2,8 @@ import * as vscode from "vscode"
export function activate(context: vscode.ExtensionContext) {
vscode.window.showInformationMessage("test extension loaded")
// Test extension
// Prints the current proxy URI into a notification.
context.subscriptions.push(
vscode.commands.registerCommand("codeServerTest.proxyUri", () => {
if (process.env.VSCODE_PROXY_URI) {
@@ -13,7 +14,8 @@ export function activate(context: vscode.ExtensionContext) {
}),
)
// asExternalUri extension
// Asks for a URI, then runs it through asExternalUri and prints the result
// into a notification.
context.subscriptions.push(
vscode.commands.registerCommand("codeServerTest.asExternalUri", async () => {
const input = await vscode.window.showInputBox({
@@ -28,4 +30,29 @@ export function activate(context: vscode.ExtensionContext) {
}
}),
)
const secretKey = "code-server-test-secret"
// Asks for a string, then stores it as a secret.
context.subscriptions.push(
vscode.commands.registerCommand("codeServerTest.setSecret", async () => {
const input = await vscode.window.showInputBox({
prompt: "Secret to store",
})
if (input) {
await context.secrets.store(secretKey, input)
vscode.window.showInformationMessage(`set secret: ${input}`)
} else {
vscode.window.showErrorMessage(`Failed to run test case. No input provided.`)
}
}),
)
// Prints the current secret, if any.
context.subscriptions.push(
vscode.commands.registerCommand("codeServerTest.getSecret", async () => {
vscode.window.showInformationMessage(`get secret: ${await context.secrets.get(secretKey)}`)
}),
)
}
@@ -22,6 +22,16 @@
"command": "codeServerTest.asExternalUri",
"title": "asExternalUri test",
"category": "code-server"
},
{
"command": "codeServerTest.setSecret",
"title": "Set test secret",
"category": "code-server"
},
{
"command": "codeServerTest.getSecret",
"title": "Get test secret",
"category": "code-server"
}
]
},
+5 -4
View File
@@ -363,13 +363,14 @@ export class CodeServerPage {
}
/**
* Checks if the test extension loaded
* Checks if the test extension loaded by waiting for its notification. Once
* it appears, dismiss the notification.
*/
async waitForTestExtensionLoaded(): Promise<void> {
const selector = "text=test extension loaded"
this.codeServer.logger.debug("Waiting for test extension to load...")
await this.page.waitForSelector(selector)
const locator = this.page.getByRole("dialog", { name: "Info: test extension loaded" })
await locator.hover()
await locator.getByLabel("Clear Notification (Del)").click()
}
/**
-2
View File
@@ -1,5 +1,3 @@
import { promises as fs } from "fs"
import * as path from "path"
import { clean } from "../utils/helpers"
import { describe, test, expect } from "./baseFixture"
+61
View File
@@ -0,0 +1,61 @@
import { promises as fs } from "fs"
import * as path from "path"
import { describe, test, expect } from "./baseFixture"
const tests = [
{
name: "browser storage",
args: [],
},
{
name: "remote storage",
args: ["--enable-remote-storage"],
},
]
for (const tc of tests) {
const args = ["--disable-workspace-trust", "--extensions-dir", path.join(__dirname, "./extensions"), ...tc.args]
describe(tc.name, args, {}, () => {
test("should store workbench state and secrets", async ({ codeServerPage }) => {
// Create and open a file.
const dir = await codeServerPage.workspaceDir
const file = path.join(dir, "foo")
await fs.writeFile(file, "bar")
await codeServerPage.openFile(file)
// Store a secret.
const secret = "foo-bar-baz"
await codeServerPage.waitForTestExtensionLoaded()
await codeServerPage.executeCommandViaMenus("code-server: Set test secret")
await codeServerPage.page.waitForSelector(".quick-input-widget:focus-within")
await codeServerPage.page.keyboard.type(secret)
await codeServerPage.page.keyboard.press("Enter")
await expect(codeServerPage.page.getByText(`Info: set secret: ${secret}`)).toBeVisible()
// There should be a workspace storage directory.
const userDir = path.join(dir, "User/workspaceStorage")
const dirs = await fs.readdir(userDir)
expect(dirs.length).toBe(1)
const storageFile = path.join(userDir, dirs[0], "state.vscdb")
if (tc.args.includes("--enable-remote-storage")) {
// The sqlite database should exist.
fs.stat(storageFile)
} else {
// But no sqlite database.
expect(() => fs.stat(storageFile)).rejects.toThrow("ENOENT")
}
// Reload using a command so it has a chance to flush storage.
await codeServerPage.executeCommandViaMenus("Developer: Reload Window")
await codeServerPage.waitForTestExtensionLoaded()
// Should see the same file.
await codeServerPage.waitForTab(file)
// Should be able to retrieve the secret.
await codeServerPage.executeCommandViaMenus("code-server: Get test secret")
await expect(codeServerPage.page.getByText(`Info: get secret: ${secret}`)).toBeVisible()
})
})
}
+19
View File
@@ -0,0 +1,19 @@
import { promises as fs } from "fs"
import * as path from "path"
import { describe, test, expect } from "./baseFixture"
const args = ["--disable-workspace-trust"]
describe("typescript extension", args, {}, () => {
test("should load as a workspace extension", async ({ codeServerPage }) => {
const dir = await codeServerPage.workspaceDir
const file = path.join(dir, "foo.ts")
await fs.writeFile(file, 'const n: number = "x"')
await codeServerPage.openFile(file)
await codeServerPage.executeCommandViaMenus("Developer: Show Running Extensions")
await expect(
codeServerPage.page.getByLabel("typescript-language-features").getByText(/localhost:\d+/),
).toBeVisible()
})
})