Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shorten log lines when there is a too big JSON, by removing info not relevant for display, like unchanged files or test classes results #977

Merged
merged 1 commit into from
Jan 7, 2025
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@

Note: Can be used with `sfdx plugins:install sfdx-hardis@beta` and docker image `hardisgroupcom/sfdx-hardis@beta`

## [5.13.1] 2025-01-07

- [hardis:doc:project2markdown](https://sfdx-hardis.cloudity.com/hardis/doc/project2markdown/) Display a screen emoji in documentation flows table when they are not tied to an Object
- [hardis:project:deploy:smart](https://sfdx-hardis.cloudity.com/hardis/doc/project/deploy/smart/): Shorten log lines when there is a too big JSON, by removing info not relevant for display, like unchanged files or test classes results.

## [5.13.0] 2025-01-05

Expand Down
3 changes: 2 additions & 1 deletion src/common/utils/deployTipJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { getAllTips } from "./deployTipsList.js";
import { stripAnsi, uxLog } from "./index.js";
import { AiProvider, AiResponse } from "../aiProvider/index.js";
import { updatePullRequestResult } from "./deployTips.js";
import { shortenLogLines } from "./deployUtils.js";


export async function analyzeDeployErrorLogsJson(resultJson: any, log: string, includeInLog = true, options: any): Promise<any> {
Expand Down Expand Up @@ -116,7 +117,7 @@ export async function analyzeDeployErrorLogsJson(resultJson: any, log: string, i
// Update data that will be used for Pull Request comment
await updatePullRequestResult(errorsAndTips, failedTests, options);
// Return results
const newLog = includeInLog ? log + "\n\n" + detailedErrorLines.join("\n") : log;
const newLog = includeInLog ? shortenLogLines(log) + "\n\n" + detailedErrorLines.join("\n") : shortenLogLines(log);
return { tips, errorsAndTips, failedTests, errLog: newLog };
}

Expand Down
25 changes: 23 additions & 2 deletions src/common/utils/deployUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
gitHasLocalUpdates,
isCI,
killBoringExitHandlers,
replaceJsonInString,
uxLog,
} from './index.js';
import { CONSTANTS, getConfig, setConfig } from '../../config/index.js';
Expand Down Expand Up @@ -423,12 +424,32 @@ async function handleDeployError(
throw new SfError('Deployment failure. Check messages above');
}

export function truncateProgressLogLines(rawLog: string) {
const rawLogCleaned = rawLog
export function shortenLogLines(rawLog: string) {
let rawLogCleaned = rawLog
.replace(/(SOURCE PROGRESS \|.*\n)/gm, '')
.replace(/(MDAPI PROGRESS \|.*\n)/gm, '')
.replace(/(DEPLOY PROGRESS \|.*\n)/gm, '')
.replace(/(Status: In Progress \|.*\n)/gm, '');
// Truncate JSON if huge log
if (rawLogCleaned.split("\n").length > 1000 && !(process.env?.NO_TRUNCATE_LOGS === "true")) {
const msg = "Result truncated by sfdx-hardis. Define NO_TRUNCATE_LOGS=true tu have full JSON logs";
const jsonLog = findJsonInString(rawLogCleaned);
if (jsonLog) {
if (jsonLog?.result?.details?.componentSuccesses) {
jsonLog.result.details.componentSuccesses = jsonLog.result.details.componentSuccesses.filter(item => item.changed === true);
jsonLog.truncatedBySfdxHardis = msg;
}
if (jsonLog?.result?.details?.runTestResult) {
delete jsonLog.result.details.runTestResult;
jsonLog.truncatedBySfdxHardis = msg;
}
if (jsonLog?.result?.files) {
jsonLog.result.files = jsonLog.result.files.filter(item => item.state === 'Changed');
jsonLog.truncatedBySfdxHardis = msg;
}
rawLogCleaned = replaceJsonInString(rawLogCleaned, jsonLog);
}
}
return rawLogCleaned;
}

Expand Down
24 changes: 20 additions & 4 deletions src/common/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { simpleGit, FileStatusResult, SimpleGit } from 'simple-git';
import { CONSTANTS, getConfig, getReportDirectory, setConfig } from '../../config/index.js';
import { prompts } from './prompts.js';
import { encryptFile } from '../cryptoUtils.js';
import { deployMetadatas, truncateProgressLogLines } from './deployUtils.js';
import { deployMetadatas, shortenLogLines } from './deployUtils.js';
import { isProductionOrg, promptProfiles, promptUserEmail } from './orgUtils.js';
import { WebSocketClient } from '../websocketClient.js';
import moment from 'moment';
Expand Down Expand Up @@ -647,7 +647,7 @@ export async function execCommand(
}
// Display error in red if not json
if (!command.includes('--json') || options.fail) {
const strErr = truncateProgressLogLines(`${(e as any).stdout}\n${(e as any).stderr}`);
const strErr = shortenLogLines(`${(e as any).stdout}\n${(e as any).stderr}`);
console.error(c.red(strErr));
(e as Error).message = (e as Error).message += '\n' + strErr;
// Manage retry if requested
Expand Down Expand Up @@ -678,9 +678,9 @@ export async function execCommand(
error: e,
};
}
// Display output if requested, for better user unrstanding of the logs
// Display output if requested, for better user understanding of the logs
if (options.output || options.debug) {
uxLog(commandThis, c.italic(c.grey(truncateProgressLogLines(commandResult.stdout))));
uxLog(commandThis, c.italic(c.grey(shortenLogLines(commandResult.stdout))));
}
// Return status 0 if not --json
if (!command.includes('--json')) {
Expand Down Expand Up @@ -1353,6 +1353,22 @@ export function findJsonInString(inputString: string) {
return null;
}

export function replaceJsonInString(inputString: string, jsonObject: any): string {
// Regular expression to match a JSON object
const jsonMatch = stripAnsi(inputString).match(/\{[\s\S]*\}|\[[\s\S]*\]/);
if (jsonMatch) {
try {
const jsonString = JSON.stringify(jsonObject, null, 2);
return stripAnsi(inputString).replace(jsonMatch[0], jsonString);
} catch (err: any) {
uxLog(this, c.yellow('Warning: unable to replace JSON in string:' + err.message));
return inputString;
}
}
uxLog(this, c.yellow('Warning: unable to find json to replace in string'));
return inputString;
}

// Ugly hack but no choice
// It happens that in case of huge logs, process.exit triggers a blocking error.
// Remove them, as anyway we want to stop the process.
Expand Down
Loading