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
31 changes: 26 additions & 5 deletions src/solutions/solution-problems.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ describe('SolutionProblems', () => {
logMessages: {
success: true,
errors: [],
warnings: ["mylayer.clayer.yml - file '/packs/Component/config.c' update required from component 'Arm::Device@2.3.4'"],
warnings: ["mylayer.clayer.yml - update required for file '/packs/Component/config.c' from component 'Arm::Device@2.3.4'"],
info: [],
},
});
Expand All @@ -272,7 +272,7 @@ describe('SolutionProblems', () => {

it('creates merge diagnostic action for merge messages with component context', () => {
const result = solutionProblems['createMergeDiagnosticAction'](
"file '/packs/Component/config.c' update required from component 'Arm::Device@2.3.4'",
"update required for file '/packs/Component/config.c' from component 'Arm::Device@2.3.4'",
layerPath,
);

Expand All @@ -285,6 +285,27 @@ describe('SolutionProblems', () => {
});
});

it('creates merge diagnostic action for current toolbox message wording', () => {
const configPath = 'C:/CubeMX/CubeMX/RTE/CMSIS/RTX_Config.c';
const result = solutionProblems['createMergeDiagnosticAction'](
`update recommended for file '${configPath}' from component 'CMSIS:RTOS2:Keil RTX5&Source'.\nMerge content from update file, rename update file to base file and remove previous base file`,
layerPath,
);

expect(result).toEqual({
message: "update recommended for config file 'RTX_Config.c' from component 'CMSIS:RTOS2:Keil RTX5&Source'.",
code: {
value: 'Open in Merge View',
target: vscode.Uri.parse(`command:${MERGE_FILE_COMMAND_ID}?${encodeURIComponent(JSON.stringify([configPath]))}`),
},
});
});

it('treats Windows-style merge paths as absolute', () => {
expect(solutionProblems['isAbsoluteFilePath']('C:/CubeMX/CubeMX/RTE/CMSIS/RTX_Config.c')).toBe(true);
expect(solutionProblems['isAbsoluteFilePath']('relative-config.c')).toBe(false);
});

it('returns undefined merge diagnostic action for non-merge messages', () => {
const result = solutionProblems['createMergeDiagnosticAction'](
"component 'Arm::Device@2.3.4' is missing",
Expand All @@ -304,7 +325,7 @@ describe('SolutionProblems', () => {
logMessages: {
success: true,
errors: [],
warnings: ["mylayer.clayer.yml - file 'relative-config.c' update recommended"],
warnings: ["mylayer.clayer.yml - update recommended for file 'relative-config.c'"],
info: [],
},
});
Expand All @@ -323,7 +344,7 @@ describe('SolutionProblems', () => {
});

it.each(['required', 'recommended', 'suggested', 'mandatory'] as const)(
'renders merge diagnostics for %s update levels',
'renders merge diagnostics for current toolbox wording with %s update levels',
async updateLevel => {
await solutionProblems.activate({ subscriptions: [] } as unknown as ExtensionContext);
const setSpy = jest.spyOn(vscode.languages.createDiagnosticCollection(), 'set');
Expand All @@ -334,7 +355,7 @@ describe('SolutionProblems', () => {
logMessages: {
success: true,
errors: [],
warnings: [`mylayer.clayer.yml - file '/packs/Component/${updateLevel}.c' update ${updateLevel}`],
warnings: [`mylayer.clayer.yml - update ${updateLevel} for file '/packs/Component/${updateLevel}.c'; merge content from update file, rename update file to base file and remove previous base file`],
info: [],
},
});
Expand Down
36 changes: 25 additions & 11 deletions src/solutions/solution-problems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,13 @@ export const enrichLogMessagesFromToolOutput = async (logMessages: LogMessages,

export const MERGE_VIEW_LINK_LABEL = 'Open in Merge View';
export type MergeUpdateLevel = 'required' | 'recommended' | 'suggested' | 'mandatory';
const mergeMessageRegex = /file\s+'([^']+)'\s+update\s+(required|recommended|suggested|mandatory)/i;
const mergeMessagePatterns = [
{
pattern: /update\s+(required|recommended|suggested|mandatory)\s+for\s+file\s+'([^']+)'/i,
getLocalPath: (match: RegExpExecArray) => match[2],
getUpdateLevel: (match: RegExpExecArray) => match[1],
},
] as const;
const mergeComponentRegex = /(?:for|from)\s+component\s+'([^']+)'/i;
export interface MergeMessageMatch {
localPath: string;
Expand Down Expand Up @@ -311,17 +317,21 @@ export class SolutionProblemsImpl implements SolutionProblems {
}

private parseMergeMessage(line: string): MergeMessageMatch | undefined {
const match = mergeMessageRegex.exec(line);
if (!match || match.index === undefined) {
return undefined;
for (const item of mergeMessagePatterns) {
const match = item.pattern.exec(line);
if (!match || match.index === undefined) {
continue;
}

return {
localPath: item.getLocalPath(match),
updateLevel: item.getUpdateLevel(match).toLowerCase() as MergeUpdateLevel,
matchStart: match.index,
matchLength: match[0].length,
};
Comment thread
mguzmanm marked this conversation as resolved.
}

return {
localPath: match[1],
updateLevel: match[2].toLowerCase() as MergeUpdateLevel,
matchStart: match.index,
matchLength: match[0].length,
};
return undefined;
}

private createMergeDiagnosticMessage(localPath: string, updateLevel: MergeUpdateLevel, componentId: string | undefined): string {
Expand All @@ -340,14 +350,18 @@ export class SolutionProblemsImpl implements SolutionProblems {
return vscode.Uri.parse(`command:${MERGE_FILE_COMMAND_ID}?${args}`);
}

private isAbsoluteFilePath(filePath: string): boolean {
return path.isAbsolute(filePath) || path.win32.isAbsolute(filePath);
}

private createMergeDiagnosticAction(message: string, diagnosticFilePath: string): { message: string; code: NonNullable<vscode.Diagnostic['code']> } | undefined {
const merge = this.parseMergeMessage(message);
if (!merge) {
return undefined;
}

const componentId = mergeComponentRegex.exec(message)?.[1];
const localPath = path.isAbsolute(merge.localPath) ? merge.localPath : diagnosticFilePath;
const localPath = this.isAbsoluteFilePath(merge.localPath) ? merge.localPath : diagnosticFilePath;
const formattedMessage = this.createMergeDiagnosticMessage(localPath, merge.updateLevel, componentId);

return {
Expand Down
Loading