Skip to content

Commit 74832fb

Browse files
author
David Hasani
committed
add permissions prompt
1 parent 14b4358 commit 74832fb

File tree

8 files changed

+99
-5
lines changed

8 files changed

+99
-5
lines changed

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

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,10 @@ import {
5757
openBuildLogFile,
5858
parseBuildFile,
5959
validateSQLMetadataFile,
60+
validateYamlFile,
6061
} from '../../../codewhisperer/service/transformByQ/transformFileHandler'
6162
import { getAuthType } from '../../../auth/utils'
63+
import fs from '../../../shared/fs/fs'
6264

6365
// These events can be interactions within the chat,
6466
// or elsewhere in the IDE
@@ -385,6 +387,9 @@ export class GumbyController {
385387
transformByQState.setCustomDependencyVersionFilePath('')
386388
this.promptJavaHome('source', message.tabID)
387389
break
390+
case ButtonActions.AGREE_TO_LOCAL_BUILD:
391+
await this.prepareLanguageUpgradeProject(message) // build project locally right after user agrees to do so
392+
break
388393
case ButtonActions.VIEW_TRANSFORMATION_HUB:
389394
await vscode.commands.executeCommand(GumbyCommands.FOCUS_TRANSFORMATION_HUB, CancelActionPositions.Chat)
390395
break
@@ -585,8 +590,12 @@ export class GumbyController {
585590
if (!fileUri || fileUri.length === 0) {
586591
return
587592
}
588-
// TO-DO: validate the YAML file?
589-
this.messenger.sendMessage('Received custom dependency version YAML file!', message.tabID, 'ai-prompt')
593+
const fileContents = await fs.readFileText(fileUri[0].fsPath)
594+
const isValidYaml = await validateYamlFile(fileContents, message)
595+
if (!isValidYaml) {
596+
return
597+
}
598+
this.messenger.sendMessage('Received custom dependency version YAML file.', message.tabID, 'ai-prompt')
590599
transformByQState.setCustomDependencyVersionFilePath(fileUri[0].fsPath)
591600
this.promptJavaHome('source', message.tabID)
592601
}
@@ -686,7 +695,7 @@ export class GumbyController {
686695
const pathToJavaHome = extractPath(data.message)
687696
if (pathToJavaHome) {
688697
transformByQState.setTargetJavaHome(pathToJavaHome)
689-
await this.prepareLanguageUpgradeProject(data) // build project locally right after saving target JDK path
698+
this.messenger.sendPermissionToBuildMessage(data.tabID)
690699
} else {
691700
this.messenger.sendUnrecoverableErrorResponse('invalid-java-home', data.tabID)
692701
}

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

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ export type UnrecoverableErrorType =
5050
| 'job-start-failed'
5151
| 'unsupported-source-db'
5252
| 'unsupported-target-db'
53+
| 'missing-yaml-key'
5354
| 'error-parsing-sct-file'
5455
| 'invalid-zip-no-sct-file'
5556
| 'invalid-from-to-jdk'
@@ -345,6 +346,35 @@ export class Messenger {
345346
)
346347
}
347348

349+
public sendPermissionToBuildMessage(tabID: string) {
350+
const message = CodeWhispererConstants.buildLocallyChatMessage
351+
352+
const buttons: ChatItemButton[] = []
353+
buttons.push({
354+
keepCardAfterClick: false,
355+
text: 'Agree',
356+
id: ButtonActions.AGREE_TO_LOCAL_BUILD,
357+
position: 'outside',
358+
})
359+
buttons.push({
360+
keepCardAfterClick: false,
361+
text: 'No, stop the transformation',
362+
id: ButtonActions.CANCEL_TRANSFORMATION_FORM,
363+
position: 'outside',
364+
})
365+
366+
this.dispatcher.sendChatMessage(
367+
new ChatMessage(
368+
{
369+
message,
370+
messageType: 'ai-prompt',
371+
buttons,
372+
},
373+
tabID
374+
)
375+
)
376+
}
377+
348378
public sendAsyncEventProgress(
349379
tabID: string,
350380
inProgress: boolean,
@@ -461,6 +491,9 @@ export class Messenger {
461491
case 'unsupported-target-db':
462492
message = CodeWhispererConstants.invalidMetadataFileUnsupportedTargetDB
463493
break
494+
case 'missing-yaml-key':
495+
message = CodeWhispererConstants.invalidYamlFileMissingKey
496+
break
464497
case 'error-parsing-sct-file':
465498
message = CodeWhispererConstants.invalidMetadataFileErrorParsing
466499
break
@@ -786,7 +819,7 @@ dependencyManagement:
786819
originType: "FIRST_PARTY" # or "THIRD_PARTY" # Optional
787820
- identifier: "com.example:library2"
788821
targetVersion: "3.0.0"
789-
origin: "THIRD_PARTY"
822+
originType: "THIRD_PARTY"
790823
plugins:
791824
- identifier: "com.example.plugin"
792825
targetVersion: "1.2.0"

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export enum ButtonActions {
2222
SELECT_SQL_CONVERSION_METADATA_FILE = 'gumbySQLConversionMetadataTransformFormConfirm',
2323
SELECT_CUSTOM_DEPENDENCY_VERSION_FILE = 'gumbyCustomDependencyVersionTransformFormConfirm',
2424
CONTINUE_TRANSFORMATION_FORM = 'gumbyTransformFormContinue',
25+
AGREE_TO_LOCAL_BUILD = 'gumbyAgreeToLocalBuild',
2526
CONFIRM_DEPENDENCY_FORM = 'gumbyTransformDependencyFormConfirm',
2627
CANCEL_DEPENDENCY_FORM = 'gumbyTransformDependencyFormCancel',
2728
CONFIRM_JAVA_HOME_FORM = 'gumbyJavaHomeFormConfirm',

packages/core/src/codewhisperer/models/constants.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,9 @@ export const buildSucceededChatMessage = 'I was able to build your project and w
587587
export const buildSucceededNotification =
588588
'Amazon Q was able to build your project and will start transforming your code soon.'
589589

590+
export const buildLocallyChatMessage =
591+
'I will build your project on this machine throughout the transformation process.'
592+
590593
export const absolutePathDetectedMessage = (numPaths: number, buildFile: string, listOfPaths: string) =>
591594
`I detected ${numPaths} potential absolute file path(s) in your ${buildFile} file: **${listOfPaths}**. Absolute file paths might cause issues when I build your code. Any errors will show up in the build log.`
592595

@@ -599,6 +602,9 @@ export const invalidMetadataFileUnsupportedSourceDB =
599602
export const invalidMetadataFileUnsupportedTargetDB =
600603
'I can only convert SQL for migrations to Aurora PostgreSQL or Amazon RDS for PostgreSQL target databases. The provided .sct file indicates another target database for this migration.'
601604

605+
export const invalidYamlFileMissingKey =
606+
'Your YAML file is not formatted correctly. Make sure that the .yaml file you upload follows the format of the sample file provided.'
607+
602608
export const invalidMetadataFileErrorParsing =
603609
"It looks like the .sct file you provided isn't valid. Make sure that you've uploaded the .zip file you retrieved from your schema conversion in AWS DMS."
604610

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -783,7 +783,12 @@ async function processClientInstructions(jobId: string, clientInstructionsPath:
783783
export async function runClientSideBuild(projectPath: string, clientInstructionArtifactId: string) {
784784
// baseCommand will be one of: '.\mvnw.cmd', './mvnw', 'mvn'
785785
const baseCommand = transformByQState.getMavenName()
786-
const args = ['test']
786+
const args = ['clean']
787+
if (transformByQState.getCustomBuildCommand() === CodeWhispererConstants.skipUnitTestsBuildCommand) {
788+
args.push('test-compile')
789+
} else {
790+
args.push('test')
791+
}
787792
// TO-DO / QUESTION: why not use the build command from the downloaded manifest?
788793
transformByQState.appendToBuildLog(`Running ${baseCommand} ${args}`)
789794
const environment = { ...process.env, JAVA_HOME: transformByQState.getTargetJavaHome() }

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export function getDependenciesFolderInfo(): FolderInfo {
2828
}
2929
}
3030

31+
// TO-DO: what happens when intermediate build logs are massive from downloading dependencies? exlude those lines?
3132
export async function writeAndShowBuildLogs() {
3233
const logFilePath = path.join(os.tmpdir(), 'build-logs.txt')
3334
writeFileSync(logFilePath, transformByQState.getBuildLog())
@@ -137,6 +138,18 @@ export async function parseBuildFile() {
137138
return undefined
138139
}
139140

141+
export async function validateYamlFile(fileContents: string, message: any) {
142+
const requiredKeys = ['dependencyManagement:', 'identifier:', 'targetVersion:']
143+
for (const key of requiredKeys) {
144+
if (!fileContents.includes(key)) {
145+
getLogger().info(`CodeTransformation: missing yaml key: ${key}`)
146+
transformByQState.getChatMessenger()?.sendUnrecoverableErrorResponse('missing-yaml-key', message.tabID)
147+
return false
148+
}
149+
}
150+
return true
151+
}
152+
140153
export async function validateSQLMetadataFile(fileContents: string, message: any) {
141154
try {
142155
const sctData = await xml2js.parseStringPromise(fileContents)

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,8 @@ export class TransformationHubViewProvider implements vscode.WebviewViewProvider
349349
CodeWhispererConstants.uploadingCodeStepMessage,
350350
activeStepId === 0
351351
)
352+
// TO-DO: remove this step entirely since we do entirely client-side builds
353+
// TO-DO: do we still show the "Building in Java 17/21 environment" progress update?
352354
const buildMarkup =
353355
activeStepId >= 1 && transformByQState.getTransformationType() !== TransformationType.SQL_CONVERSION // for SQL conversions, don't show buildCode step
354356
? simpleStep(

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import {
4242
parseBuildFile,
4343
validateSQLMetadataFile,
4444
createLocalBuildUploadZip,
45+
validateYamlFile,
4546
} from '../../../codewhisperer/service/transformByQ/transformFileHandler'
4647
import { uploadArtifactToS3 } from '../../../codewhisperer/indexNode'
4748
import request from '../../../shared/request'
@@ -50,6 +51,19 @@ import * as nodefs from 'fs' // eslint-disable-line no-restricted-imports
5051
describe('transformByQ', function () {
5152
let fetchStub: sinon.SinonStub
5253
let tempDir: string
54+
const validYamlFile = `name: "custom-dependency-management"
55+
description: "Custom dependency version management for Java migration from JDK 8/11/17 to JDK 17/21"
56+
dependencyManagement:
57+
dependencies:
58+
- identifier: "com.example:library1"
59+
targetVersion: "2.1.0"
60+
versionProperty: "library1.version"
61+
originType: "FIRST_PARTY"
62+
plugins:
63+
- identifier: "com.example.plugin"
64+
targetVersion: "1.2.0"
65+
versionProperty: "plugin.version"`
66+
5367
const validSctFile = `<?xml version="1.0" encoding="UTF-8"?>
5468
<tree>
5569
<instances>
@@ -466,6 +480,17 @@ describe('transformByQ', function () {
466480
assert.strictEqual(expectedWarning, warningMessage)
467481
})
468482

483+
it(`WHEN validateYamlFile on fully valid .yaml file THEN passes validation`, async function () {
484+
const isValidYaml = await validateYamlFile(validYamlFile, { tabID: 'abc123' })
485+
assert.strictEqual(isValidYaml, true)
486+
})
487+
488+
it(`WHEN validateYamlFile on invalid .yaml file THEN fails validation`, async function () {
489+
const invalidYamlFile = validYamlFile.replace('dependencyManagement', 'invalidKey')
490+
const isValidYaml = await validateYamlFile(invalidYamlFile, { tabID: 'abc123' })
491+
assert.strictEqual(isValidYaml, false)
492+
})
493+
469494
it(`WHEN validateMetadataFile on fully valid .sct file THEN passes validation`, async function () {
470495
const isValidMetadata = await validateSQLMetadataFile(validSctFile, { tabID: 'abc123' })
471496
assert.strictEqual(isValidMetadata, true)

0 commit comments

Comments
 (0)