Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ import {
import { getAuthType } from '../../../auth/utils'
import fs from '../../../shared/fs/fs'
import { setContext } from '../../../shared/vscode/setContext'
import { readHistoryFile } from '../../../codewhisperer/service/transformByQ/transformationHubViewProvider'
import { readHistoryFile } from '../../../codewhisperer/service/transformByQ/transformationHistoryHandler'

// These events can be interactions within the chat,
// or elsewhere in the IDE
Expand Down
88 changes: 26 additions & 62 deletions packages/core/src/codewhisperer/commands/startTransformByQ.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

import * as vscode from 'vscode'
import * as fs from 'fs' // eslint-disable-line no-restricted-imports
import os from 'os'
import path from 'path'
import { getLogger } from '../../shared/logger/logger'
import * as CodeWhispererConstants from '../models/constants'
Expand Down Expand Up @@ -79,6 +78,12 @@ import { convertDateToTimestamp } from '../../shared/datetime'
import { findStringInDirectory } from '../../shared/utilities/workspaceUtils'
import { makeTemporaryToolkitFolder } from '../../shared/filesystemUtilities'
import { AuthUtil } from '../util/authUtil'
import {
cleanupTempJobFiles,
createMetadataFile,
JobMetadata,
writeToHistoryFile,
} from '../service/transformByQ/transformationHistoryHandler'

export function getFeedbackCommentData() {
const jobId = transformByQState.getJobId()
Expand Down Expand Up @@ -477,28 +482,21 @@ export async function startTransformationJob(
})

// create local history folder(s) and store metadata
const jobHistoryPath = path.join(os.homedir(), '.aws', 'transform', transformByQState.getProjectName(), jobId)
if (!fs.existsSync(jobHistoryPath)) {
fs.mkdirSync(jobHistoryPath, { recursive: true })
const metadata: JobMetadata = {
jobId: jobId,
projectName: transformByQState.getProjectName(),
transformationType: transformByQState.getTransformationType() ?? TransformationType.LANGUAGE_UPGRADE,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious here, so what would happen for SQL conversions?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically transformByQState.getTransformationType() should not be undefined at this point, so it will be written as "SQL Conversion" in the metadata file. But the ?? TransformationType.LANGUAGE_UPGRADE is there just in case for some odd reason it is undefined.

sourceJDKVersion: transformByQState.getSourceJDKVersion() ?? JDKVersion.JDK8,
targetJDKVersion: transformByQState.getTargetJDKVersion() ?? JDKVersion.JDK17,
customDependencyVersionFilePath: transformByQState.getCustomDependencyVersionFilePath(),
customBuildCommand: transformByQState.getCustomBuildCommand(),
targetJavaHome: transformByQState.getTargetJavaHome() ?? '',
projectPath: transformByQState.getProjectPath(),
startTime: transformByQState.getStartTime(),
}
transformByQState.setJobHistoryPath(jobHistoryPath)
// save a copy of the upload zip
fs.copyFileSync(transformByQState.getPayloadFilePath(), path.join(jobHistoryPath, 'zipped-code.zip'))

const fields = [
jobId,
transformByQState.getTransformationType(),
transformByQState.getSourceJDKVersion(),
transformByQState.getTargetJDKVersion(),
transformByQState.getCustomDependencyVersionFilePath(),
transformByQState.getCustomBuildCommand(),
transformByQState.getTargetJavaHome(),
transformByQState.getProjectPath(),
transformByQState.getStartTime(),
]

const jobDetails = fields.join('\t')
fs.writeFileSync(path.join(jobHistoryPath, 'metadata.txt'), jobDetails)
const jobHistoryPath = await createMetadataFile(transformByQState.getPayloadFilePath(), metadata)
transformByQState.setJobHistoryPath(jobHistoryPath)
} catch (error) {
getLogger().error(`CodeTransformation: ${CodeWhispererConstants.failedToStartJobNotification}`, error)
const errorMessage = (error as Error).message.toLowerCase()
Expand Down Expand Up @@ -749,24 +747,11 @@ export async function postTransformationJob() {
})
}

// delete original upload ZIP at very end of transformation
fs.rmSync(transformByQState.getPayloadFilePath(), { force: true })

if (
transformByQState.isSucceeded() ||
transformByQState.isPartiallySucceeded() ||
transformByQState.isCancelled()
) {
// delete the copy of the upload ZIP
fs.rmSync(path.join(transformByQState.getJobHistoryPath(), 'zipped-code.zip'), { force: true })
// delete transformation job metadata file (no longer needed)
fs.rmSync(path.join(transformByQState.getJobHistoryPath(), 'metadata.txt'), { force: true })
}
// delete temporary build logs file
const logFilePath = path.join(os.tmpdir(), 'build-logs.txt')
if (fs.existsSync(logFilePath)) {
fs.rmSync(logFilePath, { force: true })
}
await cleanupTempJobFiles(
transformByQState.getJobHistoryPath(),
transformByQState.getPolledJobStatus(),
transformByQState.getPayloadFilePath()
)

// attempt download for user
// TODO: refactor as explained here https://github.com/aws/aws-toolkit-vscode/pull/6519/files#r1946873107
Expand All @@ -777,35 +762,14 @@ export async function postTransformationJob() {
// store job details and diff path locally (history)
// TODO: ideally when job is cancelled, should be stored as CANCELLED instead of FAILED (remove this if statement after bug is fixed)
if (!transformByQState.isCancelled()) {
const historyLogFilePath = path.join(os.homedir(), '.aws', 'transform', 'transformation_history.tsv')
// create transform folder if necessary
if (!fs.existsSync(historyLogFilePath)) {
fs.mkdirSync(path.dirname(historyLogFilePath), { recursive: true })
// create headers of new transformation history file
fs.writeFileSync(historyLogFilePath, 'date\tproject_name\tstatus\tduration\tdiff_patch\tsummary\tjob_id\n')
}
const latest = sessionJobHistory[transformByQState.getJobId()]
const fields = [
await writeToHistoryFile(
latest.startTime,
latest.projectName,
latest.status,
latest.duration,
transformByQState.isSucceeded() || transformByQState.isPartiallySucceeded()
? path.join(transformByQState.getJobHistoryPath(), 'diff.patch')
: '',
transformByQState.isSucceeded() || transformByQState.isPartiallySucceeded()
? path.join(transformByQState.getJobHistoryPath(), 'summary', 'summary.md')
: '',
transformByQState.getJobId(),
]

const jobDetails = fields.join('\t') + '\n'
fs.writeFileSync(historyLogFilePath, jobDetails, { flag: 'a' }) // 'a' flag used to append to file
await vscode.commands.executeCommand(
'aws.amazonq.transformationHub.updateContent',
'job history',
undefined,
true
transformByQState.getJobHistoryPath()
)
}
}
Expand Down
12 changes: 1 addition & 11 deletions packages/core/src/codewhisperer/models/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,7 @@ export const noChangesMadeMessage = "I didn't make any changes for this transfor

export const noOngoingJobMessage = 'No ongoing job.'

export const nothingToShowMessage = 'Nothing to show'
export const noJobHistoryMessage = 'No job history'

export const jobStartedNotification =
'Amazon Q is transforming your code. It can take 10 to 30 minutes to upgrade your code, depending on the size of your project. To monitor progress, go to the Transformation Hub.'
Expand Down Expand Up @@ -941,13 +941,3 @@ export const displayFindingsSuffix = '_displayFindings'

export const displayFindingsDetectorName = 'DisplayFindings'
export const findingsSuffix = '_codeReviewFindings'

export interface HistoryObject {
startTime: string
projectName: string
status: string
duration: string
diffPath: string
summaryPath: string
jobId: string
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import { AbsolutePathDetectedError } from '../../../amazonqGumby/errors'
import { getLogger } from '../../../shared/logger/logger'
import AdmZip from 'adm-zip'
import { IManifestFile } from './humanInTheLoopManager'
import { ExportResultArchiveStructure } from '../../../shared/utilities/download'
import { isFileNotFoundError } from '../../../shared/errors'

export async function getDependenciesFolderInfo(): Promise<FolderInfo> {
const dependencyFolderName = `${CodeWhispererConstants.dependencyFolderName}${globals.clock.Date.now()}`
Expand Down Expand Up @@ -348,3 +350,40 @@ export async function parseVersionsListFromPomFile(xmlString: string): Promise<I

return { latestVersion, majorVersions, minorVersions, status }
}

/**
* Saves a copy of the diff patch, summary, and build logs (if any) locally
*
* @param pathToArchiveDir path to the archive directory where the artifacts are unzipped
* @param pathToDestinationDir destination directory (will create directories if path doesn't exist already)
*/
export async function copyArtifacts(pathToArchiveDir: string, pathToDestinationDir: string) {
// create destination path if doesn't exist already
// mkdir() will not raise an error if path exists
await fs.mkdir(pathToDestinationDir)

const diffPath = path.join(pathToArchiveDir, ExportResultArchiveStructure.PathToDiffPatch)
const summaryPath = path.join(pathToArchiveDir, ExportResultArchiveStructure.PathToSummary)

try {
await fs.copy(diffPath, path.join(pathToDestinationDir, 'diff.patch'))
// make summary directory if needed
await fs.mkdir(path.join(pathToDestinationDir, 'summary'))
await fs.copy(summaryPath, path.join(pathToDestinationDir, 'summary', 'summary.md'))
} catch (error) {
getLogger().error('Code Transformation: Error saving local copy of artifacts: %s', (error as Error).message)
}

const buildLogsPath = path.join(path.dirname(summaryPath), 'buildCommandOutput.log')
try {
await fs.copy(buildLogsPath, path.join(pathToDestinationDir, 'summary', 'buildCommandOutput.log'))
} catch (error) {
// build logs won't exist for SQL conversions (not an error)
if (!isFileNotFoundError(error)) {
getLogger().error(
'Code Transformation: Error saving local copy of build logs: %s',
(error as Error).message
)
}
}
}
Loading
Loading