2024-06-23 18:35:04 +00:00
import CodeRepositoryUtil , {
CodeRepositoryResult ,
2024-07-09 16:40:26 +00:00
RepoScriptType ,
2024-06-23 18:35:04 +00:00
} from "./Utils/CodeRepository" ;
2024-06-19 14:06:36 +00:00
import InitUtil from "./Utils/Init" ;
2024-09-05 11:59:59 +00:00
import ServiceRepositoryUtil from "./Utils/ServiceRepository" ;
2024-06-19 14:06:36 +00:00
import { PromiseVoidFunction } from "Common/Types/FunctionTypes" ;
2024-08-07 21:50:32 +00:00
import logger from "Common/Server/Utils/Logger" ;
2024-06-20 10:41:04 +00:00
import CopilotActionUtil from "./Utils/CopilotAction" ;
2024-08-05 19:00:31 +00:00
import CopilotAction from "Common/Models/DatabaseModels/CopilotAction" ;
2024-07-10 20:33:38 +00:00
import {
FixNumberOfCodeEventsInEachRun ,
GetIsCopilotDisabled ,
GetLlmType ,
} from "./Config" ;
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" ;
2024-08-05 19:00:31 +00:00
import ServiceCopilotCodeRepository from "Common/Models/DatabaseModels/ServiceCopilotCodeRepository" ;
2024-06-23 20:29:23 +00:00
import CopilotActionProcessingException from "./Exceptions/CopilotActionProcessingException" ;
2024-08-05 19:00:31 +00:00
import CopilotPullRequest from "Common/Models/DatabaseModels/CopilotPullRequest" ;
2024-09-04 10:51:56 +00:00
import ProcessUtil from "./Utils/Process" ;
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-10 12:50:29 +00:00
// check if copilot is disabled.
2024-09-05 13:30:30 +00:00
2024-07-10 12:50:29 +00:00
if ( GetIsCopilotDisabled ( ) ) {
2024-07-10 12:39:35 +00:00
logger . info ( "Copilot is disabled. Exiting." ) ;
2024-09-04 10:51:56 +00:00
ProcessUtil . haltProcessWithSuccess ( ) ;
2024-07-10 12:39:35 +00:00
}
2024-07-10 20:33:38 +00:00
logger . info ( ` Using ${ GetLlmType ( ) } as the AI model. ` ) ;
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
2024-09-05 16:13:09 +00:00
const codeRepositoryResult : CodeRepositoryResult = await InitUtil . init ( ) ;
2024-07-08 14:40:16 +00:00
2024-09-04 10:51:56 +00:00
// before cloning the repo, check if there are any services to improve.
2024-09-05 11:59:59 +00:00
ServiceRepositoryUtil . setCodeRepositoryResult ( {
2024-09-05 12:28:17 +00:00
codeRepositoryResult ,
2024-09-05 11:59:59 +00:00
} ) ;
2024-09-04 13:52:32 +00:00
const servicesToImprove : ServiceCopilotCodeRepository [ ] =
2024-09-05 11:59:59 +00:00
await ServiceRepositoryUtil . getServicesToImprove ( ) ;
2024-09-04 10:51:56 +00:00
2024-09-05 13:30:30 +00:00
logger . debug ( ` Found ${ servicesToImprove . length } services to improve. ` ) ;
// if no services to improve, then exit.
if ( servicesToImprove . length === 0 ) {
logger . info ( "No services to improve. Exiting." ) ;
ProcessUtil . haltProcessWithSuccess ( ) ;
}
for ( const serviceToImprove of servicesToImprove ) {
logger . debug ( ` - ${ serviceToImprove . serviceCatalog ! . name } ` ) ;
}
2024-07-12 18:02:47 +00:00
await cloneRepository ( {
codeRepositoryResult ,
2024-07-08 14:40:16 +00:00
} ) ;
2024-07-12 18:02:47 +00:00
await setUpRepository ( ) ;
2024-07-08 15:01:51 +00:00
2024-07-12 21:04:18 +00:00
for ( const serviceRepository of servicesToImprove ) {
checkIfCurrentFixCountIsLessThanFixNumberOfCodeEventsInEachRun ( ) ;
2024-06-23 18:35:04 +00:00
2024-09-04 13:52:32 +00:00
const actionsToWorkOn : Array < CopilotAction > =
await CopilotActionUtil . getActionsToWorkOn ( {
serviceCatalogId : serviceRepository.serviceCatalog ! . id ! ,
2024-09-05 16:13:09 +00:00
serviceRepositoryId : serviceRepository.id ! ,
2024-06-19 14:06:36 +00:00
} ) ;
2024-09-04 13:52:32 +00:00
for ( const actionToWorkOn of actionsToWorkOn ) {
2024-06-19 15:29:25 +00:00
checkIfCurrentFixCountIsLessThanFixNumberOfCodeEventsInEachRun ( ) ;
// check copilot events for this file.
2024-06-23 18:35:04 +00:00
let executionResult : CopilotExecutionResult | null = null ;
2024-06-22 18:40:18 +00:00
2024-07-09 16:40:26 +00:00
let currentRetryCount : number = 0 ;
const maxRetryCount : number = 3 ;
while ( currentRetryCount < maxRetryCount ) {
try {
executionResult = await executeAction ( {
serviceRepository ,
2024-09-04 13:52:32 +00:00
copilotAction : actionToWorkOn ,
2024-07-09 16:40:26 +00:00
} ) ;
break ;
} catch ( e ) {
logger . error ( e ) ;
currentRetryCount ++ ;
2024-07-10 12:43:59 +00:00
await CodeRepositoryUtil . discardAllChangesOnCurrentBranch ( ) ;
2024-06-22 18:40:18 +00:00
}
}
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-07-09 16:51:36 +00:00
interface ExecuteActionData {
2024-07-09 16:40:26 +00:00
serviceRepository : ServiceCopilotCodeRepository ;
2024-09-04 13:52:32 +00:00
copilotAction : CopilotAction ;
2024-07-09 16:51:36 +00:00
}
type ExecutionActionFunction = (
data : ExecuteActionData ,
) = > Promise < CopilotExecutionResult | null > ;
const executeAction : ExecutionActionFunction = async (
data : ExecuteActionData ,
) : Promise < CopilotExecutionResult | null > = > {
2024-09-04 13:52:32 +00:00
const { serviceRepository , copilotAction } = data ;
2024-07-09 16:40:26 +00:00
try {
2024-09-05 16:39:47 +00:00
return await CopilotActionService . executeAction ( {
2024-07-09 16:40:26 +00:00
serviceRepository : serviceRepository ,
2024-09-04 13:52:32 +00:00
copilotAction : copilotAction ,
2024-07-09 16:40:26 +00:00
} ) ;
} catch ( e ) {
if ( e instanceof CopilotActionProcessingException ) {
2024-09-04 13:52:32 +00:00
// This is not a serious exception, so we just move on to the next action.
2024-07-09 16:40:26 +00:00
logger . info ( e . message ) ;
return null ;
}
throw e ;
}
} ;
2024-07-12 18:02:47 +00:00
type CloneRepositoryFunction = ( data : {
codeRepositoryResult : CodeRepositoryResult ;
} ) = > Promise < void > ;
const cloneRepository : CloneRepositoryFunction = async ( data : {
codeRepositoryResult : CodeRepositoryResult ;
} ) : Promise < void > = > {
const { codeRepositoryResult } = data ;
logger . info (
` Cloning the repository ${ codeRepositoryResult . codeRepository . name } to a temporary directory. ` ,
) ;
// now clone this repository to a temporary directory - /repository
await CodeRepositoryUtil . cloneRepository ( {
codeRepository : codeRepositoryResult.codeRepository ,
} ) ;
// Check if OneUptime Copilot has setup properly.
const onAfterCloneScript : string | null =
await CodeRepositoryUtil . getRepoScript ( {
scriptType : RepoScriptType.OnAfterClone ,
} ) ;
if ( ! onAfterCloneScript ) {
logger . debug ( "No on-after-clone script found for this repository." ) ;
}
if ( onAfterCloneScript ) {
logger . info ( "Executing on-after-clone script." ) ;
2024-09-05 16:39:47 +00:00
await CodeRepositoryUtil . executeScript ( {
script : onAfterCloneScript ,
} ) ;
2024-07-12 18:02:47 +00:00
logger . info ( "on-after-clone script executed successfully." ) ;
}
logger . info (
` Repository ${ codeRepositoryResult . codeRepository . name } cloned successfully. ` ,
) ;
} ;
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. ` ,
) ;
2024-09-04 10:51:56 +00:00
ProcessUtil . haltProcessWithSuccess ( ) ;
} ;
2024-07-12 18:02:47 +00:00
const setUpRepository : PromiseVoidFunction = async ( ) : Promise < void > = > {
const isSetupProperly : boolean =
await CodeRepositoryUtil . isRepoSetupProperly ( ) ;
if ( isSetupProperly ) {
return ;
}
// if the repo is not set up properly, then check if there's an outstanding setup Pr for this repo.
2024-07-12 19:28:46 +00:00
logger . info ( "Setting up the repository." ) ;
// check if there's an outstanding setup PR for this repo.
const setupPullRequest : CopilotPullRequest | null =
await CodeRepositoryUtil . getOpenSetupPullRequest ( ) ;
if ( setupPullRequest ) {
logger . info (
` There's an open setup PR for this repository: ${ setupPullRequest . pullRequestId } . Please merge this PR to continue using Copilot. Exiting... ` ,
) ;
2024-09-04 10:51:56 +00:00
ProcessUtil . haltProcessWithSuccess ( ) ;
2024-07-12 19:28:46 +00:00
return ;
}
// if there's no setup PR, then create a new setup PR.
const pullRequest : PullRequest = await CodeRepositoryUtil . setUpRepo ( ) ;
logger . info (
"Repository setup PR created - #" +
2024-09-05 15:08:39 +00:00
pullRequest . pullRequestNumber +
". Please megre this PR to continue using Copilot. Exiting.." ,
2024-07-12 19:28:46 +00:00
) ;
2024-09-04 10:51:56 +00:00
ProcessUtil . haltProcessWithSuccess ( ) ;
2024-07-12 18:02:47 +00:00
} ;
2024-06-19 14:06:36 +00:00
export default init ;