Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/extension/chatSessions/copilotcli/vscode-node/test/copilotCLISDKUpgrade.spec.ts
13406 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { promises as fs } from 'fs';
7
import { isBinaryFile } from 'isbinaryfile';
8
import * as path from 'path';
9
import { beforeAll, describe, it } from 'vitest';
10
import { TestLogService } from '../../../../../platform/testing/common/testLogService';
11
import { copyRipgrepShim } from '../../../copilotcli/node/ripgrepShim';
12
13
describe('CopilotCLI SDK Upgrade', function () {
14
const extensionPath = path.join(__dirname, '..', '..', '..', '..', '..', '..');
15
const copilotSDKPath = path.join(extensionPath, 'node_modules', '@github', 'copilot');
16
beforeAll(async function () {
17
await copyBinaries(extensionPath);
18
});
19
it('should be able to load the SDK without errors', async function () {
20
await import('@github/copilot/sdk');
21
});
22
23
it('should not contain new native binaries nor removed native binaries', async function () {
24
// This is a very basic check to ensure that when the Copilot CLI SDK is upgraded,
25
// we are aware of any changes to the native binaries it contains.
26
// Such changes may require us to update our extension packaging or other handling.
27
const existingBinaries = new Set(await findAllBinaries(copilotSDKPath));
28
const knownBinaries = new Set([
29
// node-pty related files (already accounted for in SDK, using VS Code node-pty).
30
path.join('prebuilds', 'darwin-arm64', 'pty.node'),
31
path.join('prebuilds', 'darwin-x64', 'pty.node'),
32
path.join('prebuilds', 'linux-arm64', 'pty.node'),
33
path.join('prebuilds', 'linux-x64', 'pty.node'),
34
path.join('prebuilds', 'win32-arm64', 'conpty', 'OpenConsole.exe'),
35
path.join('prebuilds', 'win32-arm64', 'conpty', 'conpty.dll'),
36
path.join('prebuilds', 'win32-arm64', 'conpty.node'),
37
path.join('prebuilds', 'win32-arm64', 'conpty.pdb'),
38
path.join('prebuilds', 'win32-arm64', 'conpty_console_list.node'),
39
path.join('prebuilds', 'win32-arm64', 'conpty_console_list.pdb'),
40
path.join('prebuilds', 'win32-x64', 'conpty', 'OpenConsole.exe'),
41
path.join('prebuilds', 'win32-x64', 'conpty', 'conpty.dll'),
42
path.join('prebuilds', 'win32-x64', 'conpty.node'),
43
path.join('prebuilds', 'win32-x64', 'conpty.pdb'),
44
path.join('prebuilds', 'win32-x64', 'conpty_console_list.node'),
45
path.join('prebuilds', 'win32-x64', 'conpty_console_list.pdb'),
46
// ripgrep
47
path.join('ripgrep', 'bin', 'win32-arm64', 'rg.exe'),
48
path.join('ripgrep', 'bin', 'win32-x64', 'rg.exe'),
49
path.join('prebuilds', 'darwin-arm64', 'spawn-helper'),
50
path.join('prebuilds', 'darwin-x64', 'spawn-helper'),
51
// computer use
52
path.join('prebuilds', 'darwin-arm64', 'computer.node'),
53
path.join('prebuilds', 'darwin-x64', 'computer.node'),
54
path.join('prebuilds', 'linux-arm64', 'computer.node'),
55
path.join('prebuilds', 'linux-x64', 'computer.node'),
56
path.join('prebuilds', 'win32-arm64', 'computer.node'),
57
path.join('prebuilds', 'win32-x64', 'computer.node'),
58
// win32 native module (formerly win_error_mode)
59
path.join('prebuilds', 'win32-arm64', 'win32.node'),
60
path.join('prebuilds', 'win32-x64', 'win32.node'),
61
// Second copy of computer.node / win32.node re-shipped by the @github/copilot/sdk subpackage
62
// (previously hidden by a broad sdk/prebuilds/** exclusion that masked the node-pty files we used to shim in at test setup).
63
path.join('sdk', 'prebuilds', 'darwin-arm64', 'computer.node'),
64
path.join('sdk', 'prebuilds', 'darwin-x64', 'computer.node'),
65
path.join('sdk', 'prebuilds', 'linux-arm64', 'computer.node'),
66
path.join('sdk', 'prebuilds', 'linux-x64', 'computer.node'),
67
path.join('sdk', 'prebuilds', 'win32-arm64', 'computer.node'),
68
path.join('sdk', 'prebuilds', 'win32-x64', 'computer.node'),
69
path.join('sdk', 'prebuilds', 'win32-arm64', 'win32.node'),
70
path.join('sdk', 'prebuilds', 'win32-x64', 'win32.node'),
71
path.join('ripgrep', 'bin', 'darwin-arm64', 'rg'),
72
path.join('ripgrep', 'bin', 'darwin-x64', 'rg'),
73
path.join('ripgrep', 'bin', 'linux-x64', 'rg'),
74
path.join('ripgrep', 'bin', 'linux-arm64', 'rg'),
75
// sharp related files
76
path.join('sharp', 'node_modules', '@img', 'sharp-wasm32', 'lib', 'sharp-wasm32.node.wasm'),
77
// sharp related files, files copied by us.
78
path.join('sdk', 'sharp', 'node_modules', '@img', 'sharp-wasm32', 'lib', 'sharp-wasm32.node.wasm'),
79
// parsing commands for shell.
80
'tree-sitter-bash.wasm',
81
'tree-sitter-powershell.wasm',
82
'tree-sitter.wasm',
83
'tree-sitter-c_sharp.wasm',
84
'tree-sitter-c.wasm',
85
'tree-sitter-cpp.wasm',
86
'tree-sitter-css.wasm',
87
'tree-sitter-html.wasm',
88
'tree-sitter-java.wasm',
89
'tree-sitter-php.wasm',
90
'tree-sitter-go.wasm',
91
'tree-sitter-json.wasm',
92
'tree-sitter-javascript.wasm',
93
'tree-sitter-python.wasm',
94
'tree-sitter-ruby.wasm',
95
'tree-sitter-tsx.wasm',
96
'tree-sitter-rust.wasm',
97
'tree-sitter-typescript.wasm',
98
'tree-sitter-scala.wasm',
99
].map(p => path.join(copilotSDKPath, p)));
100
101
// Exclude ripgrep files that we copy over in src/extension/chatSessions/copilotcli/node/ripgrepShim.ts (until we get better API/solution from SDK)
102
const ripgrepFilesWeCopy = path.join(copilotSDKPath, 'sdk', 'ripgrep', 'bin');
103
104
const errors: string[] = [];
105
// Look for new binaries
106
for (const binary of existingBinaries) {
107
if (binary.startsWith(ripgrepFilesWeCopy)) {
108
continue;
109
}
110
const binaryName = path.basename(binary);
111
if (binaryName.startsWith('keytar') || binaryName.startsWith('clipboard')) {
112
continue;
113
}
114
if (!knownBinaries.has(binary)) {
115
errors.push(`Unexpected native binary found in Copilot CLI SDK: ${path.relative(copilotSDKPath, binary)}`);
116
}
117
}
118
// Look for removed binaries.
119
for (const binary of knownBinaries) {
120
if (binary.startsWith(ripgrepFilesWeCopy)) {
121
continue;
122
}
123
if (!existingBinaries.has(binary)) {
124
errors.push(`Expected native binary missing from Copilot CLI SDK: ${path.relative(copilotSDKPath, binary)}`);
125
}
126
}
127
128
if (errors.length > 0) {
129
throw new Error(errors.join('\n'));
130
}
131
});
132
133
it('should be able to load the @github/copilot module without errors', async function () {
134
await import('@github/copilot/sdk');
135
});
136
});
137
138
async function copyBinaries(extensionPath: string) {
139
const copilotSDKPath = path.join(extensionPath, 'node_modules', '@github', 'copilot');
140
const vscodeRipgrepPath = path.join(copilotSDKPath, 'ripgrep', 'bin', process.platform + '-' + process.arch);
141
await copyRipgrepShim(extensionPath, vscodeRipgrepPath, new TestLogService());
142
}
143
async function findAllBinaries(dir: string): Promise<string[]> {
144
const binaryFiles: string[] = [];
145
const filesToIgnore = ['.DS_Store'];
146
async function findFilesRecursively(dir: string): Promise<void> {
147
try {
148
await fs.access(dir);
149
} catch {
150
return;
151
}
152
153
const entries = await fs.readdir(dir, { withFileTypes: true });
154
await Promise.all(entries.map(async (entry) => {
155
const fullPath = path.join(dir, entry.name);
156
if (filesToIgnore.includes(entry.name)) {
157
return;
158
}
159
if (entry.isDirectory()) {
160
await findFilesRecursively(fullPath);
161
} else if (entry.isFile()) {
162
const isBinary = await isBinaryFile(fullPath);
163
if (isBinary) {
164
binaryFiles.push(fullPath);
165
}
166
}
167
}));
168
}
169
170
await findFilesRecursively(dir);
171
return binaryFiles;
172
}
173
174