Skip to content

Commit 09872d3

Browse files
author
David Hasani
committed
refactor(amazonq): move utils functions to dedicated file
1 parent 3a39b10 commit 09872d3

File tree

4 files changed

+127
-125
lines changed

4 files changed

+127
-125
lines changed

packages/core/src/amazonqGumby/chat/controller/controller.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,13 @@ import {
2020
compileProject,
2121
finishHumanInTheLoop,
2222
getValidLanguageUpgradeCandidateProjects,
23-
openBuildLogFile,
24-
openHilPomFile,
25-
parseBuildFile,
2623
postTransformationJob,
2724
processLanguageUpgradeTransformFormInput,
2825
processSQLConversionTransformFormInput,
2926
startTransformByQ,
3027
stopTransformByQ,
3128
validateCanCompileProject,
32-
setMaven,
3329
getValidSQLConversionCandidateProjects,
34-
validateSQLMetadataFile,
3530
} from '../../../codewhisperer/commands/startTransformByQ'
3631
import { JDKVersion, TransformationCandidateProject, transformByQState } from '../../../codewhisperer/models/model'
3732
import {
@@ -62,6 +57,13 @@ import { getStringHash } from '../../../shared/utilities/textUtilities'
6257
import { getVersionData } from '../../../codewhisperer/service/transformByQ/transformMavenHandler'
6358
import AdmZip from 'adm-zip'
6459
import { AuthError } from '../../../auth/sso/server'
60+
import {
61+
setMaven,
62+
openHilPomFile,
63+
openBuildLogFile,
64+
parseBuildFile,
65+
validateSQLMetadataFile,
66+
} from '../../../codewhisperer/service/transformByQ/transformFileHandler'
6567

6668
// These events can be interactions within the chat,
6769
// or elsewhere in the IDE

packages/core/src/codewhisperer/commands/startTransformByQ.ts

Lines changed: 1 addition & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55

66
import * as vscode from 'vscode'
77
import * as fs from 'fs' // eslint-disable-line no-restricted-imports
8-
import * as os from 'os'
9-
import * as xml2js from 'xml2js'
108
import path from 'path'
119
import { getLogger } from '../../shared/logger'
1210
import * as CodeWhispererConstants from '../models/constants'
@@ -18,7 +16,6 @@ import {
1816
FolderInfo,
1917
ZipManifest,
2018
TransformByQStatus,
21-
DB,
2219
TransformationType,
2320
TransformationCandidateProject,
2421
} from '../models/model'
@@ -56,7 +53,6 @@ import { MetadataResult } from '../../shared/telemetry/telemetryClient'
5653
import { submitFeedback } from '../../feedback/vue/submitFeedback'
5754
import { placeholder } from '../../shared/vscode/commands2'
5855
import {
59-
AbsolutePathDetectedError,
6056
AlternateDependencyVersionsNotFoundError,
6157
JavaHomeNotSetError,
6258
JobStartError,
@@ -69,8 +65,8 @@ import {
6965
getCodeIssueSnippetFromPom,
7066
getDependenciesFolderInfo,
7167
getJsonValuesFromManifestFile,
72-
highlightPomIssueInProject,
7368
parseVersionsListFromPomFile,
69+
setMaven,
7470
writeLogs,
7571
} from '../service/transformByQ/transformFileHandler'
7672
import { sleep } from '../../shared/utilities/timeoutUtils'
@@ -81,7 +77,6 @@ import { setContext } from '../../shared/vscode/setContext'
8177
import { makeTemporaryToolkitFolder } from '../../shared'
8278
import globals from '../../shared/extensionGlobals'
8379
import { convertDateToTimestamp } from '../../shared/datetime'
84-
import { isWin } from '../../shared/vscode/env'
8580
import { findStringInDirectory } from '../../shared/utilities/workspaceUtils'
8681

8782
function getFeedbackCommentData() {
@@ -111,63 +106,6 @@ export async function processSQLConversionTransformFormInput(pathToProject: stri
111106
// targetJDKVersion defaults to JDK17, the only supported version, which is fine
112107
}
113108

114-
export async function validateSQLMetadataFile(fileContents: string, message: any) {
115-
try {
116-
const sctData = await xml2js.parseStringPromise(fileContents)
117-
const dbEntities = sctData['tree']['instances'][0]['ProjectModel'][0]['entities'][0]
118-
const sourceDB = dbEntities['sources'][0]['DbServer'][0]['$']['vendor'].trim().toUpperCase()
119-
const targetDB = dbEntities['targets'][0]['DbServer'][0]['$']['vendor'].trim().toUpperCase()
120-
const sourceServerName = dbEntities['sources'][0]['DbServer'][0]['$']['name'].trim()
121-
transformByQState.setSourceServerName(sourceServerName)
122-
if (sourceDB !== DB.ORACLE) {
123-
transformByQState.getChatMessenger()?.sendUnrecoverableErrorResponse('unsupported-source-db', message.tabID)
124-
return false
125-
} else if (targetDB !== DB.AURORA_POSTGRESQL && targetDB !== DB.RDS_POSTGRESQL) {
126-
transformByQState.getChatMessenger()?.sendUnrecoverableErrorResponse('unsupported-target-db', message.tabID)
127-
return false
128-
}
129-
transformByQState.setSourceDB(sourceDB)
130-
transformByQState.setTargetDB(targetDB)
131-
132-
const serverNodeLocations =
133-
sctData['tree']['instances'][0]['ProjectModel'][0]['relations'][0]['server-node-location']
134-
const schemaNames = new Set<string>()
135-
serverNodeLocations.forEach((serverNodeLocation: any) => {
136-
const schemaNodes = serverNodeLocation['FullNameNodeInfoList'][0]['nameParts'][0][
137-
'FullNameNodeInfo'
138-
].filter((node: any) => node['$']['typeNode'].toLowerCase() === 'schema')
139-
schemaNodes.forEach((node: any) => {
140-
schemaNames.add(node['$']['nameNode'].toUpperCase())
141-
})
142-
})
143-
transformByQState.setSchemaOptions(schemaNames) // user will choose one of these
144-
getLogger().info(
145-
`CodeTransformation: Parsed .sct file with source DB: ${sourceDB}, target DB: ${targetDB}, source host name: ${sourceServerName}, and schema names: ${Array.from(schemaNames)}`
146-
)
147-
} catch (err: any) {
148-
getLogger().error('CodeTransformation: Error parsing .sct file. %O', err)
149-
transformByQState.getChatMessenger()?.sendUnrecoverableErrorResponse('error-parsing-sct-file', message.tabID)
150-
return false
151-
}
152-
return true
153-
}
154-
155-
export async function setMaven() {
156-
let mavenWrapperExecutableName = isWin() ? 'mvnw.cmd' : 'mvnw'
157-
const mavenWrapperExecutablePath = path.join(transformByQState.getProjectPath(), mavenWrapperExecutableName)
158-
if (fs.existsSync(mavenWrapperExecutablePath)) {
159-
if (mavenWrapperExecutableName === 'mvnw') {
160-
mavenWrapperExecutableName = './mvnw' // add the './' for non-Windows
161-
} else if (mavenWrapperExecutableName === 'mvnw.cmd') {
162-
mavenWrapperExecutableName = '.\\mvnw.cmd' // add the '.\' for Windows
163-
}
164-
transformByQState.setMavenName(mavenWrapperExecutableName)
165-
} else {
166-
transformByQState.setMavenName('mvn')
167-
}
168-
getLogger().info(`CodeTransformation: using Maven ${transformByQState.getMavenName()}`)
169-
}
170-
171109
async function validateJavaHome(): Promise<boolean> {
172110
const versionData = await getVersionData()
173111
let javaVersionUsedByMaven = versionData[1]
@@ -290,41 +228,6 @@ export async function finalizeTransformByQ(status: string) {
290228
}
291229
}
292230

293-
export async function parseBuildFile() {
294-
try {
295-
const absolutePaths = ['users/', 'system/', 'volumes/', 'c:\\', 'd:\\']
296-
const alias = path.basename(os.homedir())
297-
absolutePaths.push(alias)
298-
const buildFilePath = path.join(transformByQState.getProjectPath(), 'pom.xml')
299-
if (fs.existsSync(buildFilePath)) {
300-
const buildFileContents = fs.readFileSync(buildFilePath).toString().toLowerCase()
301-
const detectedPaths = []
302-
for (const absolutePath of absolutePaths) {
303-
if (buildFileContents.includes(absolutePath)) {
304-
detectedPaths.push(absolutePath)
305-
}
306-
}
307-
if (detectedPaths.length > 0) {
308-
const warningMessage = CodeWhispererConstants.absolutePathDetectedMessage(
309-
detectedPaths.length,
310-
path.basename(buildFilePath),
311-
detectedPaths.join(', ')
312-
)
313-
transformByQState.getChatControllers()?.errorThrown.fire({
314-
error: new AbsolutePathDetectedError(warningMessage),
315-
tabID: ChatSessionManager.Instance.getSession().tabID,
316-
})
317-
getLogger().info('CodeTransformation: absolute path potentially in build file')
318-
return warningMessage
319-
}
320-
}
321-
} catch (err: any) {
322-
// swallow error
323-
getLogger().error(`CodeTransformation: error scanning for absolute paths, tranformation continuing: ${err}`)
324-
}
325-
return undefined
326-
}
327-
328231
export async function preTransformationUploadCode() {
329232
await vscode.commands.executeCommand('aws.amazonq.transformationHub.focus')
330233

@@ -488,21 +391,6 @@ export async function initiateHumanInTheLoopPrompt(jobId: string) {
488391
return false
489392
}
490393

491-
export async function openHilPomFile() {
492-
const humanInTheLoopManager = HumanInTheLoopManager.instance
493-
await highlightPomIssueInProject(
494-
humanInTheLoopManager.getNewPomFileVirtualFileReference(),
495-
HumanInTheLoopManager.instance.diagnosticCollection,
496-
humanInTheLoopManager.getManifestFileValues().sourcePomVersion
497-
)
498-
}
499-
500-
export async function openBuildLogFile() {
501-
const logFilePath = transformByQState.getPreBuildLogFilePath()
502-
const doc = await vscode.workspace.openTextDocument(logFilePath)
503-
await vscode.window.showTextDocument(doc)
504-
}
505-
506394
export async function terminateHILEarly(jobID: string) {
507395
// Call resume with "REJECTED" state which will put our service
508396
// back into the normal flow and will not trigger HIL again for this step

packages/core/src/codewhisperer/service/transformByQ/transformFileHandler.ts

Lines changed: 114 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,16 @@ import * as path from 'path'
88
import * as os from 'os'
99
import xml2js = require('xml2js')
1010
import * as CodeWhispererConstants from '../../models/constants'
11-
import { existsSync, writeFileSync } from 'fs' // eslint-disable-line no-restricted-imports
12-
import { BuildSystem, FolderInfo, transformByQState } from '../../models/model'
11+
import { existsSync, readFileSync, writeFileSync } from 'fs' // eslint-disable-line no-restricted-imports
12+
import { BuildSystem, DB, FolderInfo, transformByQState } from '../../models/model'
1313
import { IManifestFile } from '../../../amazonqFeatureDev/models'
1414
import fs from '../../../shared/fs/fs'
1515
import globals from '../../../shared/extensionGlobals'
16+
import { ChatSessionManager } from '../../../amazonqGumby/chat/storages/chatSession'
17+
import { AbsolutePathDetectedError } from '../../../amazonqGumby/errors'
18+
import { getLogger } from '../../../shared/logger'
19+
import { isWin } from '../../../shared/vscode/env'
20+
import { HumanInTheLoopManager } from './humanInTheLoopManager'
1621

1722
export function getDependenciesFolderInfo(): FolderInfo {
1823
const dependencyFolderName = `${CodeWhispererConstants.dependencyFolderName}${globals.clock.Date.now()}`
@@ -37,6 +42,113 @@ export async function checkBuildSystem(projectPath: string) {
3742
return BuildSystem.Unknown
3843
}
3944

45+
export async function parseBuildFile() {
46+
try {
47+
const absolutePaths = ['users/', 'system/', 'volumes/', 'c:\\', 'd:\\']
48+
const alias = path.basename(os.homedir())
49+
absolutePaths.push(alias)
50+
const buildFilePath = path.join(transformByQState.getProjectPath(), 'pom.xml')
51+
if (existsSync(buildFilePath)) {
52+
const buildFileContents = readFileSync(buildFilePath).toString().toLowerCase()
53+
const detectedPaths = []
54+
for (const absolutePath of absolutePaths) {
55+
if (buildFileContents.includes(absolutePath)) {
56+
detectedPaths.push(absolutePath)
57+
}
58+
}
59+
if (detectedPaths.length > 0) {
60+
const warningMessage = CodeWhispererConstants.absolutePathDetectedMessage(
61+
detectedPaths.length,
62+
path.basename(buildFilePath),
63+
detectedPaths.join(', ')
64+
)
65+
transformByQState.getChatControllers()?.errorThrown.fire({
66+
error: new AbsolutePathDetectedError(warningMessage),
67+
tabID: ChatSessionManager.Instance.getSession().tabID,
68+
})
69+
getLogger().info('CodeTransformation: absolute path potentially in build file')
70+
return warningMessage
71+
}
72+
}
73+
} catch (err: any) {
74+
// swallow error
75+
getLogger().error(`CodeTransformation: error scanning for absolute paths, tranformation continuing: ${err}`)
76+
}
77+
return undefined
78+
}
79+
80+
export async function validateSQLMetadataFile(fileContents: string, message: any) {
81+
try {
82+
const sctData = await xml2js.parseStringPromise(fileContents)
83+
const dbEntities = sctData['tree']['instances'][0]['ProjectModel'][0]['entities'][0]
84+
const sourceDB = dbEntities['sources'][0]['DbServer'][0]['$']['vendor'].trim().toUpperCase()
85+
const targetDB = dbEntities['targets'][0]['DbServer'][0]['$']['vendor'].trim().toUpperCase()
86+
const sourceServerName = dbEntities['sources'][0]['DbServer'][0]['$']['name'].trim()
87+
transformByQState.setSourceServerName(sourceServerName)
88+
if (sourceDB !== DB.ORACLE) {
89+
transformByQState.getChatMessenger()?.sendUnrecoverableErrorResponse('unsupported-source-db', message.tabID)
90+
return false
91+
} else if (targetDB !== DB.AURORA_POSTGRESQL && targetDB !== DB.RDS_POSTGRESQL) {
92+
transformByQState.getChatMessenger()?.sendUnrecoverableErrorResponse('unsupported-target-db', message.tabID)
93+
return false
94+
}
95+
transformByQState.setSourceDB(sourceDB)
96+
transformByQState.setTargetDB(targetDB)
97+
98+
const serverNodeLocations =
99+
sctData['tree']['instances'][0]['ProjectModel'][0]['relations'][0]['server-node-location']
100+
const schemaNames = new Set<string>()
101+
serverNodeLocations.forEach((serverNodeLocation: any) => {
102+
const schemaNodes = serverNodeLocation['FullNameNodeInfoList'][0]['nameParts'][0][
103+
'FullNameNodeInfo'
104+
].filter((node: any) => node['$']['typeNode'].toLowerCase() === 'schema')
105+
schemaNodes.forEach((node: any) => {
106+
schemaNames.add(node['$']['nameNode'].toUpperCase())
107+
})
108+
})
109+
transformByQState.setSchemaOptions(schemaNames) // user will choose one of these
110+
getLogger().info(
111+
`CodeTransformation: Parsed .sct file with source DB: ${sourceDB}, target DB: ${targetDB}, source host name: ${sourceServerName}, and schema names: ${Array.from(schemaNames)}`
112+
)
113+
} catch (err: any) {
114+
getLogger().error('CodeTransformation: Error parsing .sct file. %O', err)
115+
transformByQState.getChatMessenger()?.sendUnrecoverableErrorResponse('error-parsing-sct-file', message.tabID)
116+
return false
117+
}
118+
return true
119+
}
120+
121+
export async function setMaven() {
122+
let mavenWrapperExecutableName = isWin() ? 'mvnw.cmd' : 'mvnw'
123+
const mavenWrapperExecutablePath = path.join(transformByQState.getProjectPath(), mavenWrapperExecutableName)
124+
if (existsSync(mavenWrapperExecutablePath)) {
125+
if (mavenWrapperExecutableName === 'mvnw') {
126+
mavenWrapperExecutableName = './mvnw' // add the './' for non-Windows
127+
} else if (mavenWrapperExecutableName === 'mvnw.cmd') {
128+
mavenWrapperExecutableName = '.\\mvnw.cmd' // add the '.\' for Windows
129+
}
130+
transformByQState.setMavenName(mavenWrapperExecutableName)
131+
} else {
132+
transformByQState.setMavenName('mvn')
133+
}
134+
getLogger().info(`CodeTransformation: using Maven ${transformByQState.getMavenName()}`)
135+
}
136+
137+
export async function openHilPomFile() {
138+
const humanInTheLoopManager = HumanInTheLoopManager.instance
139+
await highlightPomIssueInProject(
140+
humanInTheLoopManager.getNewPomFileVirtualFileReference(),
141+
HumanInTheLoopManager.instance.diagnosticCollection,
142+
humanInTheLoopManager.getManifestFileValues().sourcePomVersion
143+
)
144+
}
145+
146+
export async function openBuildLogFile() {
147+
const logFilePath = transformByQState.getPreBuildLogFilePath()
148+
const doc = await vscode.workspace.openTextDocument(logFilePath)
149+
await vscode.window.showTextDocument(doc)
150+
}
151+
40152
export async function createPomCopy(
41153
dirname: string,
42154
pomFileVirtualFileReference: vscode.Uri,

packages/core/src/test/codewhisperer/commands/transformByQ.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,7 @@ import * as vscode from 'vscode'
88
import * as sinon from 'sinon'
99
import { makeTemporaryToolkitFolder } from '../../../shared/filesystemUtilities'
1010
import { DB, transformByQState, TransformByQStoppedError } from '../../../codewhisperer/models/model'
11-
import {
12-
parseBuildFile,
13-
stopTransformByQ,
14-
validateSQLMetadataFile,
15-
} from '../../../codewhisperer/commands/startTransformByQ'
11+
import { stopTransformByQ } from '../../../codewhisperer/commands/startTransformByQ'
1612
import { HttpResponse } from 'aws-sdk'
1713
import * as codeWhisperer from '../../../codewhisperer/client/codewhisperer'
1814
import * as CodeWhispererConstants from '../../../codewhisperer/models/constants'
@@ -42,6 +38,10 @@ import { TransformationCandidateProject, ZipManifest } from '../../../codewhispe
4238
import globals from '../../../shared/extensionGlobals'
4339
import { fs } from '../../../shared'
4440
import { convertDateToTimestamp, convertToTimeString } from '../../../shared/datetime'
41+
import {
42+
parseBuildFile,
43+
validateSQLMetadataFile,
44+
} from '../../../codewhisperer/service/transformByQ/transformFileHandler'
4545

4646
describe('transformByQ', function () {
4747
let tempDir: string

0 commit comments

Comments
 (0)