2024-06-23 18:35:04 +00:00
import CodeRepositoryUtil , {
CodeRepositoryResult ,
} from "./Utils/CodeRepository" ;
2024-06-19 14:06:36 +00:00
import InitUtil from "./Utils/Init" ;
import ServiceRepositoryUtil from "./Utils/ServiceRepository" ;
import Dictionary from "Common/Types/Dictionary" ;
import { PromiseVoidFunction } from "Common/Types/FunctionTypes" ;
import CodeRepositoryFile from "CommonServer/Utils/CodeRepository/CodeRepositoryFile" ;
import logger from "CommonServer/Utils/Logger" ;
2024-06-20 10:41:04 +00:00
import CopilotActionUtil from "./Utils/CopilotAction" ;
import CopilotActionType from "Common/Types/Copilot/CopilotActionType" ;
import CopilotAction from "Model/Models/CopilotAction" ;
2024-06-19 15:29:25 +00:00
import { FixNumberOfCodeEventsInEachRun } from "./Config" ;
2024-06-20 11:30:06 +00:00
import CopiotActionTypeOrder from "./Types/CopilotActionTypeOrder" ;
2024-06-22 12:34:54 +00:00
import CopilotActionService , {
CopilotExecutionResult ,
} from "./Service/CopilotActions/Index" ;
import CopilotActionStatus from "Common/Types/Copilot/CopilotActionStatus" ;
2024-06-23 18:35:04 +00:00
import PullRequest from "Common/Types/CodeRepository/PullRequest" ;
import ServiceRepository from "Model/Models/ServiceRepository" ;
2024-06-23 20:29:23 +00:00
import CopilotActionProcessingException from "./Exceptions/CopilotActionProcessingException" ;
2024-06-27 14:48:52 +00:00
// import ArrayUtil from "Common/Types/ArrayUtil";
2024-06-19 15:29:25 +00:00
2024-06-22 12:34:54 +00:00
let currentFixCount : number = 1 ;
2024-06-19 14:06:36 +00:00
const init : PromiseVoidFunction = async ( ) : Promise < void > = > {
2024-07-08 15:19:19 +00:00
await CodeRepositoryUtil . setAuthorIdentity ( {
email : "copilot@oneuptime.com" ,
name : "OneUptime Copilot" ,
} ) ;
2024-07-08 15:36:22 +00:00
const codeRepositoryResult : CodeRepositoryResult = await InitUtil . init ( ) ;
2024-07-08 14:40:16 +00:00
2024-07-08 17:15:27 +00:00
if ( codeRepositoryResult . servicesToImprove . length === 0 ) {
2024-07-08 17:06:06 +00:00
logger . info ( "No services to improve. Exiting." ) ;
haltProcessWithSuccess ( ) ;
}
2024-07-08 15:01:51 +00:00
logger . info (
` Cloning the repository ${ codeRepositoryResult . codeRepository . name } to a temporary directory. ` ,
) ;
2024-07-08 14:40:16 +00:00
// now clone this repository to a temporary directory - /repository
await CodeRepositoryUtil . cloneRepository ( {
codeRepository : codeRepositoryResult.codeRepository ,
} ) ;
2024-07-08 15:01:51 +00:00
logger . info (
` Repository ${ codeRepositoryResult . codeRepository . name } cloned successfully. ` ,
) ;
2024-06-23 18:35:04 +00:00
for ( const serviceToImrove of codeRepositoryResult . servicesToImprove ) {
2024-06-19 15:29:25 +00:00
checkIfCurrentFixCountIsLessThanFixNumberOfCodeEventsInEachRun ( ) ;
2024-06-23 18:35:04 +00:00
const serviceRepository : ServiceRepository =
serviceToImrove . serviceRepository ;
2024-06-19 14:06:36 +00:00
const filesInService : Dictionary < CodeRepositoryFile > =
await ServiceRepositoryUtil . getFilesInServiceDirectory ( {
serviceRepository ,
} ) ;
logger . info (
2024-06-23 18:35:04 +00:00
` Files found in ${ serviceRepository . serviceCatalog ? . name } : ${
Object . keys ( filesInService ) . length
2024-06-19 14:06:36 +00:00
} ` ,
) ;
2024-06-19 15:29:25 +00:00
2024-06-27 14:48:52 +00:00
// const files: Array<CodeRepositoryFile> = ArrayUtil.shuffle(
// Object.values(filesInService),
// ); // shuffle the files to avoid fixing the same file in each run.
const files : Array < CodeRepositoryFile > = Object . values ( filesInService ) ;
2024-06-23 20:29:23 +00:00
for ( const file of files ) {
2024-06-19 15:29:25 +00:00
checkIfCurrentFixCountIsLessThanFixNumberOfCodeEventsInEachRun ( ) ;
// check copilot events for this file.
2024-06-20 10:41:04 +00:00
const copilotActions : Array < CopilotAction > =
await CopilotActionUtil . getCopilotActions ( {
2024-06-19 20:03:54 +00:00
serviceCatalogId : serviceRepository.serviceCatalog ! . id ! ,
2024-06-19 15:29:25 +00:00
filePath : file.filePath ,
} ) ;
2024-06-23 18:35:04 +00:00
// check if there's an open PR for this file.
const openPullRequests : Array < PullRequest > =
CodeRepositoryUtil . getOpenPRForFile ( {
pullRequests : serviceToImrove.pullRequests ,
filePath : file.filePath ,
} ) ;
if ( openPullRequests . length > 0 ) {
const prNumbers : string = openPullRequests
. map ( ( pr : PullRequest ) = > {
return ` # ${ pr . pullRequestNumber . toString ( ) } ` ;
} )
. join ( ", " ) ;
// this file already has an open PR. Ignore this file and move to the next file.
logger . info (
` File ${ file . filePath } already has an open PR ${ prNumbers } . Moving to next file. ` ,
) ;
continue ;
}
2024-06-20 10:41:04 +00:00
const eventsCompletedOnThisFile : Array < CopilotActionType > = [ ] ;
2024-06-19 15:29:25 +00:00
2024-06-20 10:41:04 +00:00
for ( const copilotAction of copilotActions ) {
2024-06-19 15:29:25 +00:00
if (
2024-06-20 10:41:04 +00:00
copilotAction . copilotActionType &&
eventsCompletedOnThisFile . includes ( copilotAction . copilotActionType )
2024-06-19 15:29:25 +00:00
) {
continue ;
}
// add to eventsCompletedOnThisFile
2024-06-20 10:41:04 +00:00
eventsCompletedOnThisFile . push ( copilotAction . copilotActionType ! ) ;
2024-06-19 15:29:25 +00:00
}
2024-06-20 10:41:04 +00:00
let nextEventToFix : CopilotActionType | undefined = undefined ;
2024-06-19 15:29:25 +00:00
2024-06-20 11:30:06 +00:00
for ( const copilotActionType of CopiotActionTypeOrder ) {
2024-06-20 10:41:04 +00:00
if ( ! eventsCompletedOnThisFile . includes ( copilotActionType ) ) {
nextEventToFix = copilotActionType ;
2024-06-19 15:29:25 +00:00
break ;
}
}
if ( ! nextEventToFix ) {
2024-07-08 17:15:27 +00:00
logger . info (
` All fixes completed on ${ file . filePath } . Moving to next file. ` ,
) ;
2024-06-19 15:29:25 +00:00
continue ;
}
2024-06-23 18:35:04 +00:00
let executionResult : CopilotExecutionResult | null = null ;
2024-06-22 18:40:18 +00:00
try {
2024-06-23 18:35:04 +00:00
executionResult = await CopilotActionService . execute ( {
serviceRepository : serviceRepository ,
copilotActionType : nextEventToFix ,
2024-06-27 14:48:52 +00:00
input : {
2024-06-27 13:15:18 +00:00
currentFilePath : file.filePath , // this is the file path where optimization is needed or should start from.
files : filesInService ,
2024-06-23 18:35:04 +00:00
} ,
} ) ;
2024-06-22 18:40:18 +00:00
} catch ( e ) {
2024-06-23 20:29:23 +00:00
if ( e instanceof CopilotActionProcessingException ) {
// This is not a serious exception, so we just move on to the next file.
2024-06-22 18:40:18 +00:00
logger . info ( e . message ) ;
2024-06-23 20:29:23 +00:00
continue ;
2024-06-22 18:40:18 +00:00
} else {
throw e ;
}
}
2024-06-22 12:34:54 +00:00
2024-06-23 18:35:04 +00:00
if (
executionResult &&
executionResult . status === CopilotActionStatus . PR_CREATED
) {
2024-06-22 12:34:54 +00:00
currentFixCount ++ ;
}
2024-06-19 15:29:25 +00:00
}
2024-06-19 14:06:36 +00:00
}
} ;
2024-06-19 20:03:54 +00:00
const checkIfCurrentFixCountIsLessThanFixNumberOfCodeEventsInEachRun : VoidFunction =
2024-06-19 15:29:25 +00:00
( ) : void = > {
if ( currentFixCount <= FixNumberOfCodeEventsInEachRun ) {
return ;
}
logger . info (
` Copilot has fixed ${ FixNumberOfCodeEventsInEachRun } code events. Thank you for using Copilot. If you wish to fix more code events, please run Copilot again. ` ,
) ;
haltProcessWithSuccess ( ) ;
} ;
2024-06-19 20:03:54 +00:00
const haltProcessWithSuccess : VoidFunction = ( ) : void = > {
2024-06-19 15:29:25 +00:00
process . exit ( 0 ) ;
} ;
2024-06-19 14:06:36 +00:00
export default init ;