Skip to content

Commit 3a5642e

Browse files
dhasani23David Hasani
andauthored
refactor(amazonq): move utils functions to dedicated file (#6165)
## Problem Lots of file utils functions in `startTransformByQ.ts` should be in `transformFileHandler.ts` ## Solution Move them. --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). License: I confirm that my contribution is made under the terms of the Apache 2.0 license. --------- Co-authored-by: David Hasani <davhasan@amazon.com>
1 parent 11b5100 commit 3a5642e

File tree

6 files changed

+121
-119
lines changed

6 files changed

+121
-119
lines changed

packages/amazonq/test/e2e/amazonq/transformByQ.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { qTestingFramework } from './framework/framework'
88
import sinon from 'sinon'
99
import { Messenger } from './framework/messenger'
1010
import { JDKVersion, TransformationType, transformByQState } from 'aws-core-vscode/codewhisperer'
11-
import { GumbyController, startTransformByQ, TabsStorage } from 'aws-core-vscode/amazonqGumby'
11+
import { GumbyController, setMaven, startTransformByQ, TabsStorage } from 'aws-core-vscode/amazonqGumby'
1212
import { using, registerAuthHook, TestFolder } from 'aws-core-vscode/test'
1313
import { loginToIdC } from './utils/setup'
1414
import { fs } from 'aws-core-vscode/shared'
@@ -338,7 +338,7 @@ describe('Amazon Q Code Transformation', function () {
338338

339339
it('WHEN transforming a Java 8 project E2E THEN job is successful', async function () {
340340
transformByQState.setTransformationType(TransformationType.LANGUAGE_UPGRADE)
341-
await startTransformByQ.setMaven()
341+
await setMaven()
342342
await startTransformByQ.processLanguageUpgradeTransformFormInput(tempDir, JDKVersion.JDK8, JDKVersion.JDK17)
343343
await startTransformByQ.startTransformByQ()
344344
assert.strictEqual(transformByQState.getPolledJobStatus(), 'COMPLETED')

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,14 @@ 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,
30+
openHilPomFile,
3531
} from '../../../codewhisperer/commands/startTransformByQ'
3632
import { JDKVersion, TransformationCandidateProject, transformByQState } from '../../../codewhisperer/models/model'
3733
import {
@@ -61,6 +57,12 @@ import { getStringHash } from '../../../shared/utilities/textUtilities'
6157
import { getVersionData } from '../../../codewhisperer/service/transformByQ/transformMavenHandler'
6258
import AdmZip from 'adm-zip'
6359
import { AuthError } from '../../../auth/sso/server'
60+
import {
61+
setMaven,
62+
openBuildLogFile,
63+
parseBuildFile,
64+
validateSQLMetadataFile,
65+
} from '../../../codewhisperer/service/transformByQ/transformFileHandler'
6466
import { getAuthType } from '../../../auth/utils'
6567

6668
// These events can be interactions within the chat,

packages/core/src/amazonqGumby/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ export { default as MessengerUtils } from './chat/controller/messenger/messenger
99
export { GumbyController } from './chat/controller/controller'
1010
export { TabsStorage } from '../amazonq/webview/ui/storages/tabsStorage'
1111
export * as startTransformByQ from '../../src/codewhisperer/commands/startTransformByQ'
12+
export { setMaven } from '../../src/codewhisperer/service/transformByQ/transformFileHandler'
1213
export * from './errors'

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

Lines changed: 1 addition & 103 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,
@@ -71,6 +67,7 @@ import {
7167
getJsonValuesFromManifestFile,
7268
highlightPomIssueInProject,
7369
parseVersionsListFromPomFile,
70+
setMaven,
7471
writeLogs,
7572
} from '../service/transformByQ/transformFileHandler'
7673
import { sleep } from '../../shared/utilities/timeoutUtils'
@@ -81,7 +78,6 @@ import { setContext } from '../../shared/vscode/setContext'
8178
import { makeTemporaryToolkitFolder } from '../../shared'
8279
import globals from '../../shared/extensionGlobals'
8380
import { convertDateToTimestamp } from '../../shared/datetime'
84-
import { isWin } from '../../shared/vscode/env'
8581
import { findStringInDirectory } from '../../shared/utilities/workspaceUtils'
8682

8783
function getFeedbackCommentData() {
@@ -111,63 +107,6 @@ export async function processSQLConversionTransformFormInput(pathToProject: stri
111107
// targetJDKVersion defaults to JDK17, the only supported version, which is fine
112108
}
113109

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-
171110
async function validateJavaHome(): Promise<boolean> {
172111
const versionData = await getVersionData()
173112
let javaVersionUsedByMaven = versionData[1]
@@ -290,41 +229,6 @@ export async function finalizeTransformByQ(status: string) {
290229
}
291230
}
292231

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-
328232
export async function preTransformationUploadCode() {
329233
await vscode.commands.executeCommand('aws.amazonq.transformationHub.focus')
330234

@@ -499,12 +403,6 @@ export async function openHilPomFile() {
499403
)
500404
}
501405

502-
export async function openBuildLogFile() {
503-
const logFilePath = transformByQState.getPreBuildLogFilePath()
504-
const doc = await vscode.workspace.openTextDocument(logFilePath)
505-
await vscode.window.showTextDocument(doc)
506-
}
507-
508406
export async function terminateHILEarly(jobID: string) {
509407
// Call resume with "REJECTED" state which will put our service
510408
// back into the normal flow and will not trigger HIL again for this step

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

Lines changed: 104 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,15 @@ 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'
1620

1721
export function getDependenciesFolderInfo(): FolderInfo {
1822
const dependencyFolderName = `${CodeWhispererConstants.dependencyFolderName}${globals.clock.Date.now()}`
@@ -37,6 +41,104 @@ export async function checkBuildSystem(projectPath: string) {
3741
return BuildSystem.Unknown
3842
}
3943

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

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

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,7 @@ import assert, { fail } from 'assert'
77
import * as vscode from 'vscode'
88
import * as sinon from 'sinon'
99
import { DB, transformByQState, TransformByQStoppedError } from '../../../codewhisperer/models/model'
10-
import {
11-
finalizeTransformationJob,
12-
parseBuildFile,
13-
setMaven,
14-
stopTransformByQ,
15-
validateSQLMetadataFile,
16-
} from '../../../codewhisperer/commands/startTransformByQ'
10+
import { stopTransformByQ, finalizeTransformationJob } from '../../../codewhisperer/commands/startTransformByQ'
1711
import { HttpResponse } from 'aws-sdk'
1812
import * as codeWhisperer from '../../../codewhisperer/client/codewhisperer'
1913
import * as CodeWhispererConstants from '../../../codewhisperer/models/constants'
@@ -43,6 +37,11 @@ import { TransformationCandidateProject, ZipManifest } from '../../../codewhispe
4337
import globals from '../../../shared/extensionGlobals'
4438
import { env, fs } from '../../../shared'
4539
import { convertDateToTimestamp, convertToTimeString } from '../../../shared/datetime'
40+
import {
41+
setMaven,
42+
parseBuildFile,
43+
validateSQLMetadataFile,
44+
} from '../../../codewhisperer/service/transformByQ/transformFileHandler'
4645

4746
describe('transformByQ', function () {
4847
let tempDir: string

0 commit comments

Comments
 (0)