@@ -20,6 +20,7 @@ import {
2020 TransformationType ,
2121 TransformationCandidateProject ,
2222 RegionProfile ,
23+ sessionJobHistory ,
2324} from '../models/model'
2425import {
2526 createZipManifest ,
@@ -474,6 +475,30 @@ export async function startTransformationJob(
474475 codeTransformRunTimeLatency : calculateTotalLatency ( transformStartTime ) ,
475476 } )
476477 } )
478+
479+ // create local history folder(s) and store metadata
480+ const jobHistoryPath = path . join ( os . homedir ( ) , '.aws' , 'transform' , transformByQState . getProjectName ( ) , jobId )
481+ if ( ! fs . existsSync ( jobHistoryPath ) ) {
482+ fs . mkdirSync ( jobHistoryPath , { recursive : true } )
483+ }
484+ transformByQState . setJobHistoryPath ( jobHistoryPath )
485+ // save a copy of the upload zip
486+ fs . copyFileSync ( transformByQState . getPayloadFilePath ( ) , path . join ( jobHistoryPath , 'zipped-code.zip' ) )
487+
488+ const fields = [
489+ jobId ,
490+ transformByQState . getTransformationType ( ) ,
491+ transformByQState . getSourceJDKVersion ( ) ,
492+ transformByQState . getTargetJDKVersion ( ) ,
493+ transformByQState . getCustomDependencyVersionFilePath ( ) ,
494+ transformByQState . getCustomBuildCommand ( ) ,
495+ transformByQState . getTargetJavaHome ( ) ,
496+ transformByQState . getProjectPath ( ) ,
497+ transformByQState . getStartTime ( ) ,
498+ ]
499+
500+ const jobDetails = fields . join ( '\t' )
501+ fs . writeFileSync ( path . join ( jobHistoryPath , 'metadata.txt' ) , jobDetails )
477502 } catch ( error ) {
478503 getLogger ( ) . error ( `CodeTransformation: ${ CodeWhispererConstants . failedToStartJobNotification } ` , error )
479504 const errorMessage = ( error as Error ) . message . toLowerCase ( )
@@ -724,9 +749,18 @@ export async function postTransformationJob() {
724749 } )
725750 }
726751
727- if ( transformByQState . getPayloadFilePath ( ) ) {
728- // delete original upload ZIP at very end of transformation
729- fs . rmSync ( transformByQState . getPayloadFilePath ( ) , { force : true } )
752+ // delete original upload ZIP at very end of transformation
753+ fs . rmSync ( transformByQState . getPayloadFilePath ( ) , { force : true } )
754+
755+ if (
756+ transformByQState . isSucceeded ( ) ||
757+ transformByQState . isPartiallySucceeded ( ) ||
758+ transformByQState . isCancelled ( )
759+ ) {
760+ // delete the copy of the upload ZIP
761+ fs . rmSync ( path . join ( transformByQState . getJobHistoryPath ( ) , 'zipped-code.zip' ) , { force : true } )
762+ // delete transformation job metadata file (no longer needed)
763+ fs . rmSync ( path . join ( transformByQState . getJobHistoryPath ( ) , 'metadata.txt' ) , { force : true } )
730764 }
731765 // delete temporary build logs file
732766 const logFilePath = path . join ( os . tmpdir ( ) , 'build-logs.txt' )
@@ -739,31 +773,52 @@ export async function postTransformationJob() {
739773 if ( transformByQState . isSucceeded ( ) || transformByQState . isPartiallySucceeded ( ) ) {
740774 await vscode . commands . executeCommand ( 'aws.amazonq.transformationHub.reviewChanges.startReview' )
741775 }
776+
777+ // store job details and diff path locally (history)
778+ // TODO: ideally when job is cancelled, should be stored as CANCELLED instead of FAILED (remove this if statement after bug is fixed)
779+ if ( ! transformByQState . isCancelled ( ) ) {
780+ const historyLogFilePath = path . join ( os . homedir ( ) , '.aws' , 'transform' , 'transformation_history.tsv' )
781+ // create transform folder if necessary
782+ if ( ! fs . existsSync ( historyLogFilePath ) ) {
783+ fs . mkdirSync ( path . dirname ( historyLogFilePath ) , { recursive : true } )
784+ // create headers of new transformation history file
785+ fs . writeFileSync ( historyLogFilePath , 'date\tproject_name\tstatus\tduration\tdiff_patch\tsummary\tjob_id\n' )
786+ }
787+ const latest = sessionJobHistory [ transformByQState . getJobId ( ) ]
788+ const fields = [
789+ latest . startTime ,
790+ latest . projectName ,
791+ latest . status ,
792+ latest . duration ,
793+ transformByQState . isSucceeded ( ) || transformByQState . isPartiallySucceeded ( )
794+ ? path . join ( transformByQState . getJobHistoryPath ( ) , 'diff.patch' )
795+ : '' ,
796+ transformByQState . isSucceeded ( ) || transformByQState . isPartiallySucceeded ( )
797+ ? path . join ( transformByQState . getJobHistoryPath ( ) , 'summary' , 'summary.md' )
798+ : '' ,
799+ transformByQState . getJobId ( ) ,
800+ ]
801+
802+ const jobDetails = fields . join ( '\t' ) + '\n'
803+ fs . writeFileSync ( historyLogFilePath , jobDetails , { flag : 'a' } ) // 'a' flag used to append to file
804+ await vscode . commands . executeCommand (
805+ 'aws.amazonq.transformationHub.updateContent' ,
806+ 'job history' ,
807+ undefined ,
808+ true
809+ )
810+ }
742811}
743812
744813export async function transformationJobErrorHandler ( error : any ) {
745814 if ( ! transformByQState . isCancelled ( ) ) {
746815 // means some other error occurred; cancellation already handled by now with stopTransformByQ
747- await stopJob ( transformByQState . getJobId ( ) )
748816 transformByQState . setToFailed ( )
749817 transformByQState . setPolledJobStatus ( 'FAILED' )
750818 // jobFailureErrorNotification should always be defined here
751- const displayedErrorMessage =
752- transformByQState . getJobFailureErrorNotification ( ) ?? CodeWhispererConstants . failedToCompleteJobNotification
753819 transformByQState . setJobFailureErrorChatMessage (
754820 transformByQState . getJobFailureErrorChatMessage ( ) ?? CodeWhispererConstants . failedToCompleteJobChatMessage
755821 )
756- void vscode . window
757- . showErrorMessage ( displayedErrorMessage , CodeWhispererConstants . amazonQFeedbackText )
758- . then ( ( choice ) => {
759- if ( choice === CodeWhispererConstants . amazonQFeedbackText ) {
760- void submitFeedback (
761- placeholder ,
762- CodeWhispererConstants . amazonQFeedbackKey ,
763- getFeedbackCommentData ( )
764- )
765- }
766- } )
767822 } else {
768823 transformByQState . setToCancelled ( )
769824 transformByQState . setPolledJobStatus ( 'CANCELLED' )
0 commit comments