Skip to content

Commit 1a635b1

Browse files
Merge master into feature/cwltail
2 parents d55449a + ae5288b commit 1a635b1

File tree

11 files changed

+153
-60
lines changed

11 files changed

+153
-60
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Feature",
3+
"description": "Amazon Q Code Transformation: allow users to skip running tests"
4+
}

packages/core/src/amazonqGumby/activation.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ import * as vscode from 'vscode'
77
import { Commands } from '../shared/vscode/commands2'
88
import { TransformationHubViewProvider } from '../codewhisperer/service/transformByQ/transformationHubViewProvider'
99
import { ExtContext } from '../shared/extensions'
10-
import { stopTransformByQ } from '../codewhisperer/commands/startTransformByQ'
10+
import {
11+
cleanupTransformationJob,
12+
postTransformationJob,
13+
stopTransformByQ,
14+
} from '../codewhisperer/commands/startTransformByQ'
1115
import { transformByQState } from '../codewhisperer/models/model'
1216
import { ProposedTransformationExplorer } from '../codewhisperer/service/transformByQ/transformationResultsViewProvider'
1317
import { CodeTransformTelemetryState } from './telemetry/codeTransformTelemetryState'
@@ -48,7 +52,9 @@ export async function activate(context: ExtContext) {
4852

4953
Commands.register('aws.amazonq.stopTransformationInHub', async (cancelSrc: CancelActionPositions) => {
5054
if (transformByQState.isRunning()) {
51-
void stopTransformByQ(transformByQState.getJobId(), cancelSrc)
55+
await stopTransformByQ(transformByQState.getJobId(), cancelSrc)
56+
await postTransformationJob()
57+
await cleanupTransformationJob()
5258
}
5359
}),
5460

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

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,12 @@ export class GumbyController {
303303
})
304304
this.messenger.sendJobFinishedMessage(message.tabID, CodeWhispererConstants.jobCancelledChatMessage)
305305
break
306+
case ButtonActions.CONFIRM_SKIP_TESTS_FORM:
307+
await this.handleSkipTestsSelection(message)
308+
break
309+
case ButtonActions.CANCEL_SKIP_TESTS_FORM:
310+
this.messenger.sendJobFinishedMessage(message.tabID, CodeWhispererConstants.jobCancelledChatMessage)
311+
break
306312
case ButtonActions.VIEW_TRANSFORMATION_HUB:
307313
await vscode.commands.executeCommand(GumbyCommands.FOCUS_TRANSFORMATION_HUB, CancelActionPositions.Chat)
308314
this.messenger.sendJobSubmittedMessage(message.tabID)
@@ -334,6 +340,23 @@ export class GumbyController {
334340
}
335341
}
336342

343+
private async handleSkipTestsSelection(message: any) {
344+
const skipTestsSelection = message.formSelectedValues['GumbyTransformSkipTestsForm']
345+
if (skipTestsSelection === CodeWhispererConstants.skipUnitTestsMessage) {
346+
transformByQState.setCustomBuildCommand(CodeWhispererConstants.skipUnitTestsBuildCommand)
347+
} else {
348+
transformByQState.setCustomBuildCommand(CodeWhispererConstants.doNotSkipUnitTestsBuildCommand)
349+
}
350+
telemetry.codeTransform_submitSelection.emit({
351+
codeTransformSessionId: CodeTransformTelemetryState.instance.getSessionId(),
352+
userChoice: skipTestsSelection,
353+
result: MetadataResult.Pass,
354+
})
355+
this.messenger.sendSkipTestsSelectionMessage(skipTestsSelection, message.tabID)
356+
// perform local build
357+
await this.validateBuildWithPromptOnError(message)
358+
}
359+
337360
// prompt user to pick project and specify source JDK version
338361
private async handleUserProjectSelection(message: any) {
339362
await telemetry.codeTransform_submitSelection.run(async () => {
@@ -365,7 +388,8 @@ export class GumbyController {
365388
}
366389

367390
await processTransformFormInput(pathToProject, fromJDKVersion, toJDKVersion)
368-
await this.validateBuildWithPromptOnError(message)
391+
392+
await this.messenger.sendSkipTestsPrompt(message.tabID)
369393
})
370394
}
371395

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

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,45 @@ export class Messenger {
109109
this.dispatcher.sendAuthenticationUpdate(new AuthenticationUpdateMessage(gumbyEnabled, authenticatingTabIDs))
110110
}
111111

112+
public async sendSkipTestsPrompt(tabID: string) {
113+
const formItems: ChatItemFormItem[] = []
114+
formItems.push({
115+
id: 'GumbyTransformSkipTestsForm',
116+
type: 'select',
117+
title: CodeWhispererConstants.skipUnitTestsFormTitle,
118+
mandatory: true,
119+
options: [
120+
{
121+
value: CodeWhispererConstants.runUnitTestsMessage,
122+
label: CodeWhispererConstants.runUnitTestsMessage,
123+
},
124+
{
125+
value: CodeWhispererConstants.skipUnitTestsMessage,
126+
label: CodeWhispererConstants.skipUnitTestsMessage,
127+
},
128+
],
129+
})
130+
131+
this.dispatcher.sendAsyncEventProgress(
132+
new AsyncEventProgressMessage(tabID, {
133+
inProgress: true,
134+
message: CodeWhispererConstants.skipUnitTestsFormMessage,
135+
})
136+
)
137+
138+
this.dispatcher.sendChatPrompt(
139+
new ChatPrompt(
140+
{
141+
message: 'Q Code Transformation',
142+
formItems: formItems,
143+
},
144+
'TransformSkipTestsForm',
145+
tabID,
146+
false
147+
)
148+
)
149+
}
150+
112151
public async sendProjectPrompt(projects: TransformationCandidateProject[], tabID: string) {
113152
const projectFormOptions: { value: any; label: string }[] = []
114153
const detectedJavaVersions = new Array<JDKVersion | undefined>()
@@ -125,7 +164,7 @@ export class Messenger {
125164
formItems.push({
126165
id: 'GumbyTransformProjectForm',
127166
type: 'select',
128-
title: 'Choose a project to transform',
167+
title: CodeWhispererConstants.chooseProjectFormTitle,
129168
mandatory: true,
130169

131170
options: projectFormOptions,
@@ -134,7 +173,7 @@ export class Messenger {
134173
formItems.push({
135174
id: 'GumbyTransformJdkFromForm',
136175
type: 'select',
137-
title: 'Choose the source code version',
176+
title: CodeWhispererConstants.chooseSourceVersionFormTitle,
138177
mandatory: true,
139178
options: [
140179
{
@@ -155,7 +194,7 @@ export class Messenger {
155194
formItems.push({
156195
id: 'GumbyTransformJdkToForm',
157196
type: 'select',
158-
title: 'Choose the target code version',
197+
title: CodeWhispererConstants.chooseTargetVersionFormTitle,
159198
mandatory: true,
160199
options: [
161200
{
@@ -407,7 +446,7 @@ export class Messenger {
407446
projectName: string,
408447
fromJDKVersion: JDKVersion,
409448
toJDKVersion: JDKVersion,
410-
tabID: any
449+
tabID: string
411450
) {
412451
const message = `### Transformation details
413452
-------------
@@ -421,6 +460,11 @@ export class Messenger {
421460
this.dispatcher.sendChatMessage(new ChatMessage({ message, messageType: 'prompt' }, tabID))
422461
}
423462

463+
public sendSkipTestsSelectionMessage(skipTestsSelection: string, tabID: string) {
464+
const message = `Okay, I will ${skipTestsSelection.toLowerCase()} when building your project.`
465+
this.dispatcher.sendChatMessage(new ChatMessage({ message, messageType: 'ai-prompt' }, tabID))
466+
}
467+
424468
public sendHumanInTheLoopInitialMessage(tabID: string, codeSnippet: string) {
425469
let message = `I was not able to upgrade all dependencies. To resolve it, I will try to find an updated depedency in your local Maven repository. I will need additional information from you to continue.`
426470

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ export enum ButtonActions {
1414
STOP_TRANSFORMATION_JOB = 'gumbyStopTransformationJob',
1515
VIEW_TRANSFORMATION_HUB = 'gumbyViewTransformationHub',
1616
CONFIRM_TRANSFORMATION_FORM = 'gumbyTransformFormConfirm',
17+
CONFIRM_SKIP_TESTS_FORM = 'gumbyTransformSkipTestsFormConfirm',
1718
CANCEL_TRANSFORMATION_FORM = 'gumbyTransformFormCancel',
19+
CANCEL_SKIP_TESTS_FORM = 'gumbyTransformSkipTestsFormCancel',
1820
CONFIRM_DEPENDENCY_FORM = 'gumbyTransformDependencyFormConfirm',
1921
CANCEL_DEPENDENCY_FORM = 'gumbyTransformDependencyFormCancel',
2022
CONFIRM_JAVA_HOME_FORM = 'gumbyJavaHomeFormConfirm',

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,10 +274,13 @@ export async function preTransformationUploadCode() {
274274
await telemetry.codeTransform_uploadProject.run(async () => {
275275
telemetry.record({ codeTransformSessionId: CodeTransformTelemetryState.instance.getSessionId() })
276276

277+
const transformZipManifest = new ZipManifest()
278+
// if the user chose to skip unit tests, add the custom build command here
279+
transformZipManifest.customBuildCommand = transformByQState.getCustomBuildCommand()
277280
const zipCodeResult = await zipCode({
278281
dependenciesFolder: transformByQState.getDependencyFolderInfo()!,
279282
modulePath: transformByQState.getProjectPath(),
280-
zipManifest: new ZipManifest(),
283+
zipManifest: transformZipManifest,
281284
})
282285

283286
const payloadFilePath = zipCodeResult.tempFilePath

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,25 @@ export const JDK8VersionNumber = '52'
626626

627627
export const JDK11VersionNumber = '55'
628628

629+
export const chooseProjectFormTitle = 'Choose a project to transform'
630+
631+
export const chooseSourceVersionFormTitle = 'Choose the source code version'
632+
633+
export const chooseTargetVersionFormTitle = 'Choose the target code version'
634+
635+
export const skipUnitTestsFormTitle = 'Choose to skip unit tests'
636+
637+
export const skipUnitTestsFormMessage =
638+
'I will build your project using `mvn test` by default. If you would like me to build your project without running unit tests, I will use `mvn test-compile`.'
639+
640+
export const runUnitTestsMessage = 'Run unit tests'
641+
642+
export const doNotSkipUnitTestsBuildCommand = 'clean test'
643+
644+
export const skipUnitTestsMessage = 'Skip unit tests'
645+
646+
export const skipUnitTestsBuildCommand = 'clean test-compile'
647+
629648
export const planTitle = 'Code Transformation plan by Amazon Q'
630649

631650
export const planIntroductionMessage =

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@ export class ZipManifest {
316316
version: string = '1.0'
317317
hilCapabilities: string[] = ['HIL_1pDependency_VersionUpgrade']
318318
transformCapabilities: string[] = ['EXPLAINABILITY_V1']
319+
customBuildCommand: string = 'clean test'
319320
}
320321

321322
export interface IHilZipManifestParams {
@@ -374,6 +375,8 @@ export class TransformByQState {
374375

375376
private targetJDKVersion: JDKVersion = JDKVersion.JDK17
376377

378+
private customBuildCommand: string = ''
379+
377380
private planFilePath: string = ''
378381
private summaryFilePath: string = ''
379382
private preBuildLogFilePath: string = ''
@@ -437,6 +440,10 @@ export class TransformByQState {
437440
return this.projectPath
438441
}
439442

443+
public getCustomBuildCommand() {
444+
return this.customBuildCommand
445+
}
446+
440447
public getPreBuildLogFilePath() {
441448
return this.preBuildLogFilePath
442449
}
@@ -561,6 +568,10 @@ export class TransformByQState {
561568
this.projectPath = path
562569
}
563570

571+
public setCustomBuildCommand(command: string) {
572+
this.customBuildCommand = command
573+
}
574+
564575
public setStartTime(time: string) {
565576
this.startTime = time
566577
}
@@ -656,6 +667,7 @@ export class TransformByQState {
656667
this.jobFailureMetadata = ''
657668
this.payloadFilePath = ''
658669
this.errorLog = ''
670+
this.customBuildCommand = ''
659671
this.intervalId = undefined
660672
}
661673
}

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

Lines changed: 3 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import * as CodeWhispererConstants from '../../models/constants'
99
import { spawnSync } from 'child_process' // Consider using ChildProcess once we finalize all spawnSync calls
1010
import { CodeTransformBuildCommand, telemetry } from '../../../shared/telemetry/telemetry'
1111
import { CodeTransformTelemetryState } from '../../../amazonqGumby/telemetry/codeTransformTelemetryState'
12-
import { MetadataResult } from '../../../shared/telemetry/telemetryClient'
1312
import { ToolkitError } from '../../../shared/errors'
1413
import { writeLogs } from './transformFileHandler'
1514
import { throwIfCancelled } from './transformApiHandler'
@@ -59,28 +58,6 @@ function installProjectDependencies(dependenciesFolder: FolderInfo, modulePath:
5958
getLogger().error(
6059
`CodeTransformation: Error in running Maven ${argString} command ${baseCommand} = ${errorLog}`
6160
)
62-
let errorReason = ''
63-
if (spawnResult.stdout) {
64-
errorReason = `Maven ${argString}: InstallationExecutionError`
65-
/*
66-
* adding this check here because these mvn commands sometimes generate a lot of output.
67-
* rarely, a buffer overflow has resulted when these mvn commands are run with -X, -e flags
68-
* which are not being used here (for now), but still keeping this just in case.
69-
*/
70-
if (Buffer.byteLength(spawnResult.stdout, 'utf-8') > CodeWhispererConstants.maxBufferSize) {
71-
errorReason += '-BufferOverflow'
72-
}
73-
} else {
74-
errorReason = `Maven ${argString}: InstallationSpawnError`
75-
}
76-
if (spawnResult.error) {
77-
const errorCode = (spawnResult.error as any).code ?? 'UNKNOWN'
78-
errorReason += `-${errorCode}`
79-
}
80-
81-
// Explicitly set metric as failed since no exception was caught
82-
telemetry.record({ result: MetadataResult.Fail, reason: errorReason })
83-
8461
throw new ToolkitError(`Maven ${argString} error`, { code: 'MavenExecutionError' })
8562
} else {
8663
transformByQState.appendToErrorLog(`${baseCommand} ${argString} succeeded`)
@@ -102,11 +79,12 @@ function copyProjectDependencies(dependenciesFolder: FolderInfo, modulePath: str
10279
'-Dmdep.addParentPoms=true',
10380
'-q',
10481
]
82+
10583
let environment = process.env
106-
// if JAVA_HOME not found or not matching project JDK, get user input for it and set here
10784
if (transformByQState.getJavaHome() !== undefined) {
10885
environment = { ...process.env, JAVA_HOME: transformByQState.getJavaHome() }
10986
}
87+
11088
const spawnResult = spawnSync(baseCommand, args, {
11189
cwd: modulePath,
11290
shell: true,
@@ -119,30 +97,9 @@ function copyProjectDependencies(dependenciesFolder: FolderInfo, modulePath: str
11997
errorLog += spawnResult.error ? JSON.stringify(spawnResult.error) : ''
12098
errorLog += `${spawnResult.stderr}\n${spawnResult.stdout}`
12199
transformByQState.appendToErrorLog(`${baseCommand} copy-dependencies failed: \n ${errorLog}`)
122-
let errorReason = ''
123-
if (spawnResult.stdout) {
124-
errorReason = 'Maven Copy: CopyDependenciesExecutionError'
125-
if (Buffer.byteLength(spawnResult.stdout, 'utf-8') > CodeWhispererConstants.maxBufferSize) {
126-
errorReason += '-BufferOverflow'
127-
}
128-
} else {
129-
errorReason = 'Maven Copy: CopyDependenciesSpawnError'
130-
}
131-
if (spawnResult.error) {
132-
const errorCode = (spawnResult.error as any).code ?? 'UNKNOWN'
133-
errorReason += `-${errorCode}`
134-
}
135100
getLogger().info(
136-
`CodeTransformation: Maven copy-dependencies command ${baseCommand} failed, but still continuing with transformation: ${errorReason}, log: ${errorLog}`
101+
`CodeTransformation: Maven copy-dependencies command ${baseCommand} failed, but still continuing with transformation: ${errorLog}`
137102
)
138-
139-
let mavenBuildCommand = transformByQState.getMavenName()
140-
// slashes not allowed in telemetry
141-
if (mavenBuildCommand === './mvnw') {
142-
mavenBuildCommand = 'mvnw'
143-
} else if (mavenBuildCommand === '.\\mvnw.cmd') {
144-
mavenBuildCommand = 'mvnw.cmd'
145-
}
146103
throw new Error('Maven copy-deps error')
147104
} else {
148105
transformByQState.appendToErrorLog(`${baseCommand} copy-dependencies succeeded`)

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

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -142,11 +142,7 @@ export async function validateOpenProjects(
142142
throw new NoMavenJavaProjectsFoundError()
143143
}
144144

145-
/*
146-
* These projects we know must contain a pom.xml and a .java file
147-
* here we try to get the Java version of each project so that we
148-
* can pre-select a default version in the QuickPick for them.
149-
*/
145+
// These projects we know must contain a pom.xml and a .java file
150146
const projectsValidToTransform = await getProjectsValidToTransform(mavenJavaProjects, onProjectFirstOpen)
151147

152148
return projectsValidToTransform

0 commit comments

Comments
 (0)