diff --git a/CHANGELOG.md b/CHANGELOG.md index c3e06e5c8..a3dac7258 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ Note: Can be used with `sfdx plugins:install sfdx-hardis@beta` and docker image `hardisgroupcom/sfdx-hardis@beta` +## [5.0.6] 2024-09-25 + +- Allow to purge flows & flow interviews using `--no-prompt` option +- Fix duplicate `-f` short option by replacing `delete-flow-interviews` short by `-w` + ## [5.0.5] 2024-09-24 - When git add / stash failure, display a message explaining to run `git config --system core.longpaths true` to solve the issue. @@ -93,7 +98,7 @@ We made many tests but risk zero do not exist, so if you see any bug, please rep - Rename command **hardis:project:deploy:source:dx** into **hardis:project:deploy:smart** (previous command alias remains, no need to update your pipelines !) - **commandsPreDeploy** and **commandsPostDeploy** - New option **context** for a command, defining when it is run and when it is not: **all** (default), **check-deployment-only** or **process-deployment-only** - - New option **runOnlyOnceByOrg**: If set to `true`, the command will be run only one time per org. A record of SfdxHardisTrace__c is stored to make that possible (it needs to be existing in target org) + - New option **runOnlyOnceByOrg**: If set to `true`, the command will be run only one time per org. A record of SfdxHardisTrace\_\_c is stored to make that possible (it needs to be existing in target org) - New commands - **hardis:project:deploy:simulate** to validate the deployment of a single metadata (used by VsCode extension) - **hardis:org:diagnose:releaseupdates** to check for org Release Updates from Monitoring or locally diff --git a/src/commands/hardis/org/purge/flow.ts b/src/commands/hardis/org/purge/flow.ts index 0255770dc..31dde7992 100644 --- a/src/commands/hardis/org/purge/flow.ts +++ b/src/commands/hardis/org/purge/flow.ts @@ -17,27 +17,9 @@ export default class OrgPurgeFlow extends SfCommand { public static description = messages.getMessage('orgPurgeFlow'); public static examples = [ - `$ sf hardis:org:purge:flow --no-prompt`, - `$ sf hardis:org:purge:flow --target-org nicolas.vuillamy@gmail.com - Found 1 records: - ID MASTERLABEL VERSIONNUMBER DESCRIPTION STATUS - 30109000000kX7uAAE TestFlow 2 test flowwww Obsolete - Are you sure you want to delete this list of records (y/n)?: y - Successfully deleted record: 30109000000kX7uAAE. - Deleted the following list of records: - ID MASTERLABEL VERSIONNUMBER DESCRIPTION STATUS - 30109000000kX7uAAE TestFlow 2 test flowwww Obsolete - `, - `$ sf hardis:org:purge:flow --target-org nicolas.vuillamy@gmail.com --status "Obsolete,Draft,InvalidDraft --name TestFlow" - Found 4 records: - ID MASTERLABEL VERSIONNUMBER DESCRIPTION STATUS - 30109000000kX7uAAE TestFlow 2 test flowwww Obsolete - 30109000000kX8EAAU TestFlow 6 test flowwww InvalidDraft - 30109000000kX8AAAU TestFlow 5 test flowwww InvalidDraft - 30109000000kX89AAE TestFlow 4 test flowwww Draft - Are you sure you want to delete this list of records (y/n)?: n - No record deleted - `, + `$ sf hardis:org:purge:flow`, + `$ sf hardis:org:purge:flow --target-org nicolas.vuillamy@gmail.com --no-prompt --delete-flow-interviews`, + `$ sf hardis:org:purge:flow --target-org nicolas.vuillamy@gmail.com --status "Obsolete,Draft,InvalidDraft" --name TestFlow`, ]; // public static args = [{name: 'file'}]; @@ -58,8 +40,8 @@ export default class OrgPurgeFlow extends SfCommand { char: 's', description: messages.getMessage('statusFilter'), }), - "delete-flow-interviews": Flags.boolean({ - char: 'f', + 'delete-flow-interviews': Flags.boolean({ + char: 'w', default: false, description: `If the presence of Flow interviews prevent to delete flows versions, delete them before retrying to delete flow versions`, }), @@ -95,6 +77,7 @@ export default class OrgPurgeFlow extends SfCommand { protected statusFilter: string[] = []; protected nameFilter: string | null = null; protected username: string; + protected promptUser = true; protected deleteFlowInterviews: boolean; protected allowPurgeFailure: boolean; protected flowRecordsRaw: any[]; @@ -105,10 +88,10 @@ export default class OrgPurgeFlow extends SfCommand { public async run(): Promise { const { flags } = await this.parse(OrgPurgeFlow); - const prompt = flags.prompt === false ? false : true; + this.promptUser = flags.prompt === false ? false : true; this.nameFilter = flags.name || null; this.allowPurgeFailure = flags.allowpurgefailure === false ? false : true; - this.deleteFlowInterviews = flags["delete-flow-interviews"] || false; + this.deleteFlowInterviews = flags['delete-flow-interviews'] || false; this.debugMode = flags.debug || false; this.username = flags['target-org'].getUsername(); @@ -134,7 +117,7 @@ export default class OrgPurgeFlow extends SfCommand { this.formatFlowRecords(); // Confirm deletion - if (prompt) { + if (this.promptUser) { const confirmDelete = await prompts({ type: 'confirm', name: 'value', @@ -171,18 +154,26 @@ export default class OrgPurgeFlow extends SfCommand { this.deletedErrors.push(deleteRes); } } - if (this.deletedErrors.length > 0 && (this.deleteFlowInterviews === true || !isCI) && tryDeleteInterviews === true) { + if ( + this.deletedErrors.length > 0 && + (this.deleteFlowInterviews === true || !isCI) && + tryDeleteInterviews === true + ) { await this.manageDeleteFlowInterviews(conn); } if (this.deletedErrors.length > 0) { - const errMsg = `[sfdx-hardis] There have been errors while deleting ${this.deletedErrors.length} record(s): \n${JSON.stringify(this.deletedErrors)}`; + const errMsg = `[sfdx-hardis] There have been errors while deleting ${ + this.deletedErrors.length + } record(s): \n${JSON.stringify(this.deletedErrors)}`; if (this.allowPurgeFailure) { uxLog(this, c.yellow(errMsg)); } else { throw new SfError( c.yellow( - `There have been errors while deleting ${this.deletedErrors.length} record(s): \n${JSON.stringify(this.deletedErrors)}` + `There have been errors while deleting ${this.deletedErrors.length} record(s): \n${JSON.stringify( + this.deletedErrors + )}` ) ); } @@ -204,7 +195,7 @@ export default class OrgPurgeFlow extends SfCommand { } // Display flows & Prompt user if not in CI await this.displayFlowInterviewToDelete(flowInterviewsIds, conn); - if (!isCI) { + if (!isCI && this.promptUser === true) { const confirmDelete = await prompts({ type: 'confirm', name: 'value', @@ -217,7 +208,7 @@ export default class OrgPurgeFlow extends SfCommand { } // Delete flow interviews const deleteInterviewResults = await bulkDelete('FlowInterview', flowInterviewsIds, conn); - this.deletedRecords.push(deleteInterviewResults?.successfulResults || []) + this.deletedRecords.push(deleteInterviewResults?.successfulResults || []); this.deletedErrors = deleteInterviewResults?.failedResults || []; // Try to delete flow versions again uxLog(this, c.cyan(`Trying again to delete flow versions after deleting flow interviews...`)); @@ -236,7 +227,10 @@ export default class OrgPurgeFlow extends SfCommand { Description: record.Description, }; }); - uxLog(this, `[sfdx-hardis] Found ${c.bold(this.flowRecords.length)} records:\n${c.yellow(columnify(this.flowRecords))}`); + uxLog( + this, + `[sfdx-hardis] Found ${c.bold(this.flowRecords.length)} records:\n${c.yellow(columnify(this.flowRecords))}` + ); } private async listFlowVersionsToDelete(manageableConstraint: string) { @@ -248,7 +242,8 @@ export default class OrgPurgeFlow extends SfCommand { } query += ' ORDER BY Definition.DeveloperName,VersionNumber'; - const flowQueryCommand = 'sf data query ' + ` --query "${query}"` + ` --target-org ${this.username}` + ' --use-tooling-api'; + const flowQueryCommand = + 'sf data query ' + ` --query "${query}"` + ` --target-org ${this.username}` + ' --use-tooling-api'; const flowQueryRes = await execSfdxJson(flowQueryCommand, this, { output: false, debug: this.debugMode, @@ -262,12 +257,13 @@ export default class OrgPurgeFlow extends SfCommand { if (flags.status) { // Input parameter used this.statusFilter = flags.status.split(','); - } else if (isCI) { + } else if (isCI || this.promptUser === false) { // Obsolete by default for CI this.statusFilter = ['Obsolete']; } else { // Query all flows definitions - const allFlowQueryCommand = 'sf data query ' + + const allFlowQueryCommand = + 'sf data query ' + ` --query "SELECT Id,DeveloperName,MasterLabel,ManageableState FROM FlowDefinition WHERE ${manageableConstraint} ORDER BY DeveloperName"` + ` --target-org ${this.username}` + ' --use-tooling-api'; @@ -309,10 +305,14 @@ export default class OrgPurgeFlow extends SfCommand { } private async displayFlowInterviewToDelete(flowVInterviewIds: string[], conn: any) { - const query = "SELECT Name,InterviewLabel,InterviewStatus,CreatedBy.Username,CreatedDate,LastModifiedDate " + + const query = + 'SELECT Name,InterviewLabel,InterviewStatus,CreatedBy.Username,CreatedDate,LastModifiedDate ' + `FROM FlowInterview WHERE Id IN ('${flowVInterviewIds.join("','")}')` + - " ORDER BY Name"; + ' ORDER BY Name'; const flowsInterviewsToDelete = (await bulkQuery(query, conn)).records; - uxLog(this, c.yellow(`Flow interviews to be deleted would be the following:\n${columnify(flowsInterviewsToDelete)}`)); + uxLog( + this, + c.yellow(`Flow interviews to be deleted would be the following:\n${columnify(flowsInterviewsToDelete)}`) + ); } }