Skip to content
Draft
Show file tree
Hide file tree
Changes from 5 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 @@ -17,6 +17,8 @@ import {
vscodeCommand,
vscodeFolderName,
workflowFileName,
CodefulSdk,
CodefulSdkVersion,
Comment thread
Copilot marked this conversation as resolved.
Outdated
} from '../../../../constants';
import { localize } from '../../../../localize';
import { ext } from '../../../../extensionVariables';
Expand Down Expand Up @@ -149,7 +151,8 @@ export const createCodefulWorkflowFile = async (

// Create the .csproj file (only for first workflow)
const templateProjPath = path.join(__dirname, assetsFolderName, 'CodefulProjectTemplate', 'CodefulProj');
const templateProjContent = await fse.readFile(templateProjPath, 'utf-8');
const templateProjContent = (await fse.readFile(templateProjPath, 'utf-8'))
.replace(/<%= codefulSdkPackageVersion %>/g, CodefulSdkVersion.WorkflowsSDK);
Comment on lines +153 to +154
const csprojFilePath = path.join(logicAppFolderPath, `${logicAppName}.csproj`);
await fse.writeFile(csprojFilePath, templateProjContent);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ vi.mock('../../../../constants', () => ({
hostFileName: 'host.json',
localSettingsFileName: 'local.settings.json',
workflowFileName: 'workflow.json',
CodefulSDKs: { DurableTask: 'DurableTask', WorkflowsWebJobs: 'WorkflowsWebJobs', WorkflowsSDK: 'WorkflowsSDK' },
CodefulSdkVersions: { DurableTask: '1.0.0', WorkflowsWebJobs: '1.0.0', WorkflowsSDK: '1.0.0' },
CodefulSdk: { DurableTask: 'DurableTask', WorkflowsWebJobs: 'WorkflowsWebJobs', WorkflowsSDK: 'WorkflowsSDK' },
CodefulSdkVersion: { DurableTask: '1.0.0', WorkflowsWebJobs: '1.0.0', WorkflowsSDK: '1.0.0' },
artifactsDirectory: 'Artifacts',
libDirectory: 'lib',
}));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import {
hostFileName,
localSettingsFileName,
workflowFileName,
CodefulSDKs,
CodefulSdkVersions,
CodefulSdk,
CodefulSdkVersion,
artifactsDirectory,
libDirectory,
} from '../../../constants';
Expand Down Expand Up @@ -208,13 +208,13 @@ async function updateBuildFile(context: IActionContext, target: vscode.Uri, dotn
let xmlBuildFile: any = await getDotnetBuildFile(context, target.fsPath);
xmlBuildFile = JSON.parse(xmlBuildFile);
if (isCodeful) {
xmlBuildFile = addNugetPackagesToBuildFileByName(xmlBuildFile, CodefulSDKs.DurableTask, CodefulSdkVersions[CodefulSDKs.DurableTask]);
xmlBuildFile = addNugetPackagesToBuildFileByName(xmlBuildFile, CodefulSdk.DurableTask, CodefulSdkVersion.DurableTask);
xmlBuildFile = addNugetPackagesToBuildFileByName(
xmlBuildFile,
CodefulSDKs.WorkflowsWebJobs,
CodefulSdkVersions[CodefulSDKs.WorkflowsWebJobs]
CodefulSdk.WorkflowsWebJobs,
CodefulSdkVersion.WorkflowsWebJobs
);
xmlBuildFile = addNugetPackagesToBuildFileByName(xmlBuildFile, CodefulSDKs.WorkflowsSDK, CodefulSdkVersions[CodefulSDKs.WorkflowsSDK]);
xmlBuildFile = addNugetPackagesToBuildFileByName(xmlBuildFile, CodefulSdk.WorkflowsSDK, CodefulSdkVersion.WorkflowsSDK);
xmlBuildFile['Project']['PropertyGroup']['TargetFramework'] = dotnetVersion;
} else {
xmlBuildFile = addNugetPackagesToBuildFile(xmlBuildFile); // adds Microsoft.Azure.Workflows.WebJobs.Extension
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import AdmZip from 'adm-zip';
import type { ChildProcessWithoutNullStreams } from 'child_process';
import { mkdtemp, rm } from 'fs/promises';
import { tmpdir } from 'os';
import path from 'path';
import { pathToFileURL } from 'url';
import { fileURLToPath, pathToFileURL } from 'url';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { codefulSdkPackageFileName } from '../../../constants';

const lspServerAssetsDirectory = fileURLToPath(new URL('../../../assets/LSPServer/', import.meta.url));
const processShutdownTimeoutMs = 5_000;

interface JsonRpcMessage {
id?: number | string;
Expand Down Expand Up @@ -33,9 +38,11 @@ class LspProcess {
}
>();
private readonly stderrChunks: string[] = [];
private readonly closePromise: Promise<void>;
private disposed = false;

public constructor(private readonly child: ChildProcessWithoutNullStreams) {
this.closePromise = new Promise((resolve) => child.once('close', () => resolve()));
child.stdout.on('data', (chunk: Buffer) => this.handleStdout(chunk));
child.stderr.on('data', (chunk: Buffer) => this.stderrChunks.push(chunk.toString('utf8')));
child.on('exit', (code, signal) => {
Expand Down Expand Up @@ -90,9 +97,33 @@ class LspProcess {
// The process is being torn down; a failed shutdown request should not hide the test assertion.
}

if (!this.child.killed) {
if (await this.waitForClose(processShutdownTimeoutMs)) {
return;
}

if (this.child.exitCode === null && this.child.signalCode === null) {
this.child.kill();
}

if (!(await this.waitForClose(processShutdownTimeoutMs))) {
throw new Error(`Timed out waiting for the LSP server process to exit.\n${this.stderr}`);
}
}

private async waitForClose(timeoutMs: number): Promise<boolean> {
let timeout: NodeJS.Timeout | undefined;
try {
return await Promise.race([
this.closePromise.then(() => true),
new Promise<boolean>((resolve) => {
timeout = setTimeout(() => resolve(false), timeoutMs);
}),
]);
} finally {
if (timeout) {
clearTimeout(timeout);
}
}
}

private write(message: JsonRpcMessage & { jsonrpc: '2.0' }): void {
Expand Down Expand Up @@ -204,11 +235,11 @@ describe('bundled LSP server CodeLens', () => {

async function startBundledLspServer(initializationOptions?: Record<string, unknown>): Promise<LspProcess> {
const extractDirectory = await createTempDirectory();
const zipPath = path.join(process.cwd(), 'src', 'assets', 'LSPServer', 'LSPServer.zip');
const zipPath = path.join(lspServerAssetsDirectory, 'LSPServer.zip');
new AdmZip(zipPath).extractAllTo(extractDirectory, true, true);

const serverDllPath = path.join(extractDirectory, 'LSPServer', 'SdkLspServer.dll');
const sdkPackagePath = path.join(process.cwd(), 'src', 'assets', 'LSPServer', 'Microsoft.Azure.Workflows.Sdk.1.0.0-preview.1.nupkg');
const sdkPackagePath = path.join(lspServerAssetsDirectory, codefulSdkPackageFileName);
const { spawn: realSpawn } = await vi.importActual<typeof import('child_process')>('child_process');
const child = realSpawn('dotnet', [serverDllPath, '--sdk', sdkPackagePath], {
stdio: ['pipe', 'pipe', 'pipe'],
Expand All @@ -234,7 +265,7 @@ describe('bundled LSP server CodeLens', () => {
}

async function createTempDirectory(): Promise<string> {
const directory = await mkdtemp(path.join(process.cwd(), 'logicapps-lsp-codelens-'));
const directory = await mkdtemp(path.join(tmpdir(), 'logicapps-lsp-codelens-'));
tempDirectories.push(directory);
return directory;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
import LogicAppsLanguageServer from '../languageServer';
import path from 'path';
import { codefulSdkPackageFileName } from '../../../constants';

const mocks = vi.hoisted(() => ({
createFileSystemWatcher: vi.fn(),
Expand Down Expand Up @@ -148,7 +149,7 @@ describe('LogicAppsLanguageServer', () => {
const languageClient = { start: vi.fn().mockResolvedValue(undefined) };
mocks.languageClient.mockReturnValue(languageClient);
mocks.pathExists.mockImplementation(async (filePath: string) => filePath === lspServerPath || filePath === sdkFolderPath);
mocks.readdir.mockResolvedValue(['Microsoft.Azure.Workflows.Sdk.1.0.0-preview.1.nupkg']);
mocks.readdir.mockResolvedValue([codefulSdkPackageFileName]);

await new LogicAppsLanguageServer({} as any).start();

Expand All @@ -159,11 +160,11 @@ describe('LogicAppsLanguageServer', () => {
{
run: {
command: 'D:\\dependencies\\DotNetSDK\\dotnet.exe',
args: [lspServerPath, '--sdk', path.join(sdkFolderPath, 'Microsoft.Azure.Workflows.Sdk.1.0.0-preview.1.nupkg')],
args: [lspServerPath, '--sdk', path.join(sdkFolderPath, codefulSdkPackageFileName)],
},
debug: {
command: 'D:\\dependencies\\DotNetSDK\\dotnet.exe',
args: [lspServerPath, '--sdk', path.join(sdkFolderPath, 'Microsoft.Azure.Workflows.Sdk.1.0.0-preview.1.nupkg')],
args: [lspServerPath, '--sdk', path.join(sdkFolderPath, codefulSdkPackageFileName)],
},
},
expect.objectContaining({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { IActionContext } from '@microsoft/vscode-azext-utils';
import { callWithTelemetryAndErrorHandling } from '@microsoft/vscode-azext-utils';
import {
autoRuntimeDependenciesPathSettingKey,
CodefulSdk,
connectionsFileName,
lspDirectory,
onStartLanguageServer,
Expand Down Expand Up @@ -201,7 +202,7 @@ export default class LogicAppsLanguageServer {

const files = await fse.readdir(sdkFolderPath);
const sdkNupkgFile = files.find((file) => {
return file.startsWith('Microsoft.Azure.Workflows.Sdk.') && file.endsWith('.nupkg');
return file.startsWith(`${CodefulSdk.WorkflowsSDK}.`) && file.endsWith('.nupkg');
});
if (!sdkNupkgFile) {
return { lspServerPath, sdkNupkgPath: undefined };
Expand Down
14 changes: 10 additions & 4 deletions apps/vs-code-designer/src/app/utils/__test__/codeful.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import path from 'path';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { lspDirectory } from '../../../constants';
import { codefulSdkProjectHashMarkerName, CodefulSdk, CodefulSdkVersion, lspDirectory, lspSdkHashMarkerName } from '../../../constants';
import {
codefulProjectsExist,
detectAgentCodefulWorkflow,
Expand Down Expand Up @@ -56,9 +56,15 @@ describe('invalidateCodefulSdkCacheIfNeeded', () => {
const runtimeDependenciesPath = 'D:\\runtime-dependencies';
const lspDirectoryPath = path.join(runtimeDependenciesPath, lspDirectory);
const nugetConfigPath = path.join(projectPath, 'nuget.config');
const installedSdkHashMarkerPath = path.join(runtimeDependenciesPath, '.lspsdk-hash');
const projectSdkHashMarkerPath = path.join(projectPath, '.nuget', '.logicapps-lspsdk-hash');
const projectSdkPackagePath = path.join(projectPath, '.nuget', 'packages', 'microsoft.azure.workflows.sdk', '1.0.0-preview.1');
const installedSdkHashMarkerPath = path.join(runtimeDependenciesPath, lspSdkHashMarkerName);
const projectSdkHashMarkerPath = path.join(projectPath, '.nuget', codefulSdkProjectHashMarkerName);
const projectSdkPackagePath = path.join(
projectPath,
'.nuget',
'packages',
CodefulSdk.WorkflowsSDK.toLowerCase(),
CodefulSdkVersion.WorkflowsSDK
);
const projectAssetsPath = path.join(projectPath, 'obj', 'project.assets.json');
const projectNugetCachePath = path.join(projectPath, 'obj', 'project.nuget.cache');
const localSettingsPath = path.join(projectPath, 'local.settings.json');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { defaultDependencyPathValue, lspDirectory } from '../../../constants';
import { codefulSdkPackageFileName, defaultDependencyPathValue, lspDirectory } from '../../../constants';
import { ext } from '../../../extensionVariables';
import { ensureRuntimeDependenciesDir } from '../binaries';
import { formatLockedFileError, installLSPSDK } from '../languageServerProtocol';
Expand Down Expand Up @@ -62,7 +62,7 @@ describe('installLSPSDK', () => {
const lspHashMarker = path.join(targetDirectory, '.lspserver-hash');
const sdkDirectoryPath = path.join(targetDirectory, lspDirectory);
const sdkHashMarker = path.join(targetDirectory, '.lspsdk-hash');
const sdkPackageName = 'Microsoft.Azure.Workflows.Sdk.1.0.0-preview.1.nupkg';
const sdkPackageName = codefulSdkPackageFileName;
const sdkDestinationFile = path.join(sdkDirectoryPath, sdkPackageName);
const legacyLspVersionMarker = path.join(targetDirectory, '.lspserver-version');
const legacyLspPathMarker = path.join(targetDirectory, '.lspserver-path');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { describe, it, expect, vi, afterEach } from 'vitest';
import * as fse from 'fs-extra';
import * as path from 'path';
import * as verifyIsProject from '../verifyIsProject';
import { hostFileName, localSettingsFileName, workflowFileName } from '../../../constants';
import { CodefulSdk, CodefulSdkVersion, hostFileName, localSettingsFileName, workflowFileName } from '../../../constants';

vi.mock('../../utils/vsCodeConfig/settings', () => ({
getWorkspaceSetting: vi.fn(),
Expand Down Expand Up @@ -84,7 +84,7 @@ describe('isLogicAppProject', () => {
return [
'<Project Sdk="Microsoft.NET.Sdk">',
' <PropertyGroup><TargetFramework>net8</TargetFramework></PropertyGroup>',
' <ItemGroup><PackageReference Include="Microsoft.Azure.Workflows.Sdk" Version="1.0.0-preview.1" /></ItemGroup>',
` <ItemGroup><PackageReference Include="${CodefulSdk.WorkflowsSDK}" Version="${CodefulSdkVersion.WorkflowsSDK}" /></ItemGroup>`,
'</Project>',
].join('\n');
}
Expand Down
23 changes: 14 additions & 9 deletions apps/vs-code-designer/src/app/utils/codeful.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import path from 'path';
import * as fse from 'fs-extra';
import * as vscode from 'vscode';
import { autoRuntimeDependenciesPathSettingKey, defaultDependencyPathValue, localSettingsFileName, lspDirectory, workflowCodefulEnabledKey } from '../../constants';
import {
autoRuntimeDependenciesPathSettingKey,
CodefulSdk,
CodefulSdkVersion,
defaultDependencyPathValue,
localSettingsFileName,
lspDirectory,
workflowCodefulEnabledKey,
lspSdkHashMarkerName,
codefulSdkProjectHashMarkerName,
} from '../../constants';
import { ext } from '../../extensionVariables';
import { getGlobalSetting } from './vsCodeConfig/settings';

const codefulSdkPackageId = 'Microsoft.Azure.Workflows.Sdk';
const codefulSdkPackageVersion = '1.0.0-preview.1';
const lspSdkHashMarkerName = '.lspsdk-hash';
const codefulSdkProjectHashMarkerName = '.logicapps-lspsdk-hash';

/**
* Checks whether any workspace folder contains a codeful Logic Apps project.
*/
Expand Down Expand Up @@ -99,7 +104,7 @@ export const invalidateCodefulSdkCacheIfNeeded = async (projectPath: string): Pr

const projectNugetFolder = path.join(projectPath, '.nuget');
const projectSdkHashMarkerPath = path.join(projectNugetFolder, codefulSdkProjectHashMarkerName);
const projectSdkPackagePath = path.join(projectNugetFolder, 'packages', codefulSdkPackageId.toLowerCase(), codefulSdkPackageVersion);
const projectSdkPackagePath = path.join(projectNugetFolder, 'packages', CodefulSdk.WorkflowsSDK.toLowerCase(), CodefulSdkVersion.WorkflowsSDK);
const restoreNoOpCachePaths = [
path.join(projectPath, 'obj', 'project.assets.json'),
path.join(projectPath, 'obj', 'project.nuget.cache'),
Expand All @@ -112,7 +117,7 @@ export const invalidateCodefulSdkCacheIfNeeded = async (projectPath: string): Pr
if (await fse.pathExists(projectSdkPackagePath)) {
await fse.remove(projectSdkPackagePath);
ext.outputChannel.appendLog(
`Removed stale ${codefulSdkPackageId} ${codefulSdkPackageVersion} from project-local NuGet cache at ${projectSdkPackagePath}.`
`Removed stale ${CodefulSdk.WorkflowsSDK} ${CodefulSdkVersion.WorkflowsSDK} from project-local NuGet cache at ${projectSdkPackagePath}.`
);
}

Expand Down Expand Up @@ -203,7 +208,7 @@ function escapeRegExp(value: string): string {
* @returns `true` if the project targets .NET 8 and includes the Microsoft.Azure.Workflows.Sdk package, `false` otherwise
*/
const isCodefulNet8Csproj = (csprojContent: string): boolean => {
return csprojContent.includes('<TargetFramework>net8</TargetFramework>') && csprojContent.includes('Microsoft.Azure.Workflows.Sdk');
return csprojContent.includes('<TargetFramework>net8</TargetFramework>') && csprojContent.includes(CodefulSdk.WorkflowsSDK);
};

/**
Expand Down
13 changes: 9 additions & 4 deletions apps/vs-code-designer/src/app/utils/languageServerProtocol.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import path from 'path';
import * as fse from 'fs-extra';
import { assetsFolderName, lspDirectory } from '../../constants';
import {
assetsFolderName,
codefulSdkPackageFileName,
lspDirectory,
lspSdkHashMarkerName,
lspServerDirectoryName,
lspServerHashMarkerName,
} from '../../constants';
import { ext } from '../../extensionVariables';
import { lspSdkHashMarkerName, lspServerDirectoryName, lspServerHashMarkerName } from './languageServerProtocolConstants';
import AdmZip from 'adm-zip';
import { createHash } from 'crypto';
import { ensureRuntimeDependenciesDir } from './binaries';

export { lspSdkHashMarkerName, lspServerDirectoryName, lspServerHashMarkerName };
const lockedFileErrorCodes = new Set(['EBUSY', 'EPERM']);
const lockedFileRetryDelayMs = 2000;
const lockedFileRetryAttempts = 3;
Expand All @@ -25,7 +30,7 @@ export async function installLSPSDK(): Promise<void> {

// Check if SDK needs to be copied or updated
const lspDirectoryPath = path.join(targetDirectory, lspDirectory);
const sdkNupkgFile = path.join(__dirname, assetsFolderName, 'LSPServer', 'Microsoft.Azure.Workflows.Sdk.1.0.0-preview.1.nupkg');
const sdkNupkgFile = path.join(__dirname, assetsFolderName, 'LSPServer', codefulSdkPackageFileName);
const sdkHashMarkerFile = path.join(targetDirectory, lspSdkHashMarkerName);
const destinationFile = path.join(lspDirectoryPath, path.basename(sdkNupkgFile));
const sdkHash = await getFileHash(sdkNupkgFile);
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.21.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.17.1" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Core" Version="1.19.0" />
<PackageReference Include="Microsoft.Azure.Workflows.Sdk" Version="1.0.0-preview.1"/>
<PackageReference Include="Microsoft.Azure.Workflows.Sdk" Version="<%= codefulSdkPackageVersion %>"/>
</ItemGroup>
<ItemGroup>
</ItemGroup>
Expand Down
Binary file not shown.
Binary file not shown.
24 changes: 13 additions & 11 deletions apps/vs-code-designer/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -484,20 +484,22 @@ export const connectedEnvironmentNameValidation = /^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0
export const resourceGroupNameValidation = /^[-\w._()]{1,90}$/;
export const namespaceValidation = /^([A-Za-z_][A-Za-z0-9_]*)(\.[A-Za-z_][A-Za-z0-9_]*)*$/;

// Codeful SDK versions
export const CodefulSDKs = {
export const CodefulSdk = {
DurableTask: 'Microsoft.Azure.WebJobs.Extensions.DurableTask',
WorkflowsWebJobs: 'Microsoft.Azure.Workflows.WebJobs.Extension',
WorkflowsSDK: 'Microsoft.Azure.Workflows.Sdk',
};
export type CodefulSDKs = (typeof CodefulSDKs)[keyof typeof CodefulSDKs];
export type CodefulSdk = (typeof CodefulSdk)[keyof typeof CodefulSdk];

const codefulSdkVersion = '1.127.21.3-preview';
const workflowsWebJobsVersion = '1.127.21.3-preview';
const durableTaskVersion = '2.9.0';

export const CodefulSdkVersions = {
[CodefulSDKs.DurableTask]: durableTaskVersion,
[CodefulSDKs.WorkflowsWebJobs]: workflowsWebJobsVersion,
[CodefulSDKs.WorkflowsSDK]: codefulSdkVersion,
export const CodefulSdkVersion = {
DurableTask: '2.9.0',
WorkflowsWebJobs: '1.127.21.3-preview',
WorkflowsSDK: '1.0.0-preview.2',
};
export type CodefulSdkVersion = (typeof CodefulSdkVersion)[keyof typeof CodefulSdkVersion];

export const codefulSdkPackageFileName = `${CodefulSdk.WorkflowsSDK}.${CodefulSdkVersion.WorkflowsSDK}.nupkg`;
export const lspServerDirectoryName = 'LSPServer';
export const lspServerHashMarkerName = '.lspserver-hash';
export const lspSdkHashMarkerName = '.lspsdk-hash';
export const codefulSdkProjectHashMarkerName = '.logicapps-lspsdk-hash';
Loading
Loading