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
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"type": "git",
"url": "https://github.com/wurstscript/wurst4vscode.git"
},
"version": "0.12.18",
"version": "0.12.19",
"publisher": "peterzeller",
"engines": {
"vscode": "^1.109.0"
Expand Down
69 changes: 68 additions & 1 deletion scripts/test-webview.js
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,72 @@ function testInstallerVersionShaParsing() {
assert.equal(mod.displayGitSha('73DFD74A6'), '73dfd74', 'prompt display must always use 7 lowercase characters');
}

async function testInstalledVersionDetection() {
let invocation;
const diagnostics = [];
const commonMocks = {
vscode: {
workspace: { getConfiguration: () => ({ get: () => '' }) },
window: {},
ProgressLocation: {},
},
fs: {
existsSync: () => true,
statSync: () => ({ size: 123, mtimeMs: 456 }),
},
'../paths': {
WURST_HOME: 'wurst-home', RUNTIME_DIR: 'runtime', COMPILER_DIR: 'compiler',
COMPILER_JAR: 'wurstscript.jar', GRILL_HOME_DIR: 'grill', UPDATE_SNOOZE_FILE: 'snooze.json',
},
'./fsUtils': {},
'./pathManager': {},
'../languageServer': {},
'../features/diagnostics': {
appendDiagnostic: (_source, message) => diagnostics.push(message),
},
};
const mod = loadTsModuleWithMocks('src/install/installer.ts', {
...commonMocks,
child_process: {
spawnSync: () => ({ status: 0 }),
execFile: (command, args, _options, callback) => {
invocation = { command, args };
callback(null, '1.9.0.0-v0.0.0-6-b36c3461-61-gba83111da\n', '');
},
},
'./downloader': {},
});

assert.equal(await mod.getInstalledVersionString(), '1.9.0.0-v0.0.0-6-b36c3461-61-gba83111da');
assert.deepEqual(invocation, {
command: require('path').join('runtime', 'bin', process.platform === 'win32' ? 'java.exe' : 'java'),
args: ['-jar', 'wurstscript.jar', '-version'],
}, 'version detection must use the compiler-supported -version flag');
assert.deepEqual(diagnostics, []);

let fetchedLatest = false;
let prompted = false;
const failureMod = loadTsModuleWithMocks('src/install/installer.ts', {
...commonMocks,
vscode: {
...commonMocks.vscode,
window: { showInformationMessage: () => { prompted = true; } },
},
child_process: {
spawnSync: () => ({ status: 0 }),
execFile: (_command, _args, _options, callback) => callback(new Error('version failed'), '', ''),
},
'./downloader': {
fetchNightlyCommitSha: async () => { fetchedLatest = true; return 'a'.repeat(40); },
},
});

await failureMod.maybeOfferUpdate();
assert.equal(fetchedLatest, false, 'a failed installed-version check must not be treated as an available update');
assert.equal(prompted, false, 'a failed installed-version check must not show a misleading update prompt');
assert.ok(diagnostics.some((message) => message.includes('version detection failed')));
}

function testNonBlockingStartupAndForcedReinstallWiring() {
const extension = fs.readFileSync(path.join(root, 'src/extension.ts'), 'utf8');
const languageServer = fs.readFileSync(path.join(root, 'src/languageServer.ts'), 'utf8');
Expand All @@ -594,7 +660,7 @@ function testNonBlockingStartupAndForcedReinstallWiring() {
assert.ok(languageServer.includes("'$(circle-filled) WurstScript Update'"), 'the status item must indicate when an update is available');
assert.ok(!installer.includes("{ modal: true, detail }, 'Update', 'Later'"), 'the automatic update notification must not be modal');
assert.ok(installer.includes("'Update', 'Later'"), 'the non-modal update notification must retain its actions');
assert.ok(installer.includes("execFile(java, ['-jar', COMPILER_JAR, '--version']"), 'version detection must use an asynchronous child process');
assert.ok(installer.includes("execFile(java, ['-jar', COMPILER_JAR, '-version']"), 'version detection must use an asynchronous child process');
assert.ok(!manifest.activationEvents.includes('workspaceContains:**/*.wurst'), 'activation must not recursively scan for loose Wurst files');
assert.ok(manifest.activationEvents.includes('onLanguage:wurst'), 'opening a Wurst document must activate the extension');
assert.ok(installer.includes('withWurstInstallLock('), 'install replacement must be serialized across VS Code windows');
Expand Down Expand Up @@ -1127,6 +1193,7 @@ async function main() {
await testFolderModeMapAssetResolution();
testBc5DdsDecode();
testInstallerVersionShaParsing();
await testInstalledVersionDetection();
testObjModEditorTypeAndRecoveryGuards();
testWpmEditorInlineScriptAndRecoveryGuards();
testNonBlockingStartupAndForcedReinstallWiring();
Expand Down
23 changes: 19 additions & 4 deletions src/install/installer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ type PreparedNightlyInstall = {
};

export type UpdateAvailable = {
installedSha: string | null;
installedSha: string;
latestSha: string;
};

Expand Down Expand Up @@ -143,8 +143,14 @@ export function getInstalledVersionString(): Promise<string | null> {

installedVersionCacheKey = cacheKey;
installedVersionPromise = new Promise((resolve) => {
execFile(java, ['-jar', COMPILER_JAR, '--version'], { encoding: 'utf8', windowsHide: true }, (error, stdout, stderr) => {
execFile(java, ['-jar', COMPILER_JAR, '-version'], { encoding: 'utf8', windowsHide: true }, (error, stdout, stderr) => {
if (error) {
const output = `${stdout || ''}\n${stderr || ''}`.trim();
const outputDetail = output ? `\n${output}` : '';
appendDiagnostic(
'VS Code extension',
`WurstScript version detection failed: ${error.message}${outputDetail}`
);
resolve(null);
return;
}
Expand Down Expand Up @@ -429,14 +435,23 @@ export async function maybeOfferUpdate(onUpdateAvailable?: (update: UpdateAvaila

const installed = await getInstalledVersionString();
const installedSha = installed ? extractGitSha(installed) : null;
if (!installedSha) {
appendDiagnostic(
'VS Code extension',
installed
? `Update check skipped: installed version did not contain a Git revision: ${installed}`
: 'Update check skipped: installed WurstScript version could not be determined.'
);
return;
}
const latestSha = await fetchNightlyCommitSha();
if (installedSha && gitShasMatch(installedSha, latestSha)) return;
if (gitShasMatch(installedSha, latestSha)) return;

onUpdateAvailable?.({ installedSha, latestSha });
if (readUpdateSnoozedUntil() > Date.now()) return;

const versions = [
installedSha ? `Installed: ${displayGitSha(installedSha)}` : 'Installed: unknown',
`Installed: ${displayGitSha(installedSha)}`,
`Latest: ${displayGitSha(latestSha)}`,
].join(' · ');

Expand Down
Loading