2023-05-22 22:58:13 +12:00
< ? php
2023-06-18 23:38:37 +12:00
use Appwrite\Auth\OAuth2\Github as OAuth2Github ;
2023-06-16 21:07:47 +12:00
use Swoole\Coroutine as Co ;
2023-05-22 22:58:13 +12:00
use Utopia\App ;
use Appwrite\Event\Build ;
use Appwrite\Event\Delete ;
use Utopia\Database\Database ;
use Utopia\Database\Document ;
use Appwrite\Utopia\Request ;
use Appwrite\Utopia\Response ;
use Utopia\Validator\Text ;
use Utopia\VCS\Adapter\Git\GitHub ;
use Appwrite\Extend\Exception ;
2023-05-26 10:29:08 +12:00
use Appwrite\Network\Validator\Host ;
2023-05-22 22:58:13 +12:00
use Appwrite\Utopia\Database\Validator\Queries\Installations ;
2023-05-28 23:39:48 +12:00
use Appwrite\Vcs\Comment ;
2023-06-18 23:38:37 +12:00
use Utopia\Database\DateTime ;
2023-05-22 22:58:13 +12:00
use Utopia\Database\Query ;
2023-05-23 01:02:55 +12:00
use Utopia\Database\ID ;
use Utopia\Database\Permission ;
use Utopia\Database\Role ;
2023-05-22 22:58:13 +12:00
use Utopia\Database\Validator\Authorization ;
2023-06-14 06:44:44 +12:00
use Utopia\Detector\Adapter\CPP ;
use Utopia\Detector\Adapter\Dart ;
use Utopia\Detector\Adapter\Deno ;
use Utopia\Detector\Adapter\Dotnet ;
use Utopia\Detector\Adapter\Java ;
use Utopia\Detector\Adapter\JavaScript ;
use Utopia\Detector\Adapter\PHP ;
use Utopia\Detector\Adapter\Python ;
use Utopia\Detector\Adapter\Ruby ;
use Utopia\Detector\Adapter\Swift ;
use Utopia\Detector\Detector ;
2023-06-18 23:38:37 +12:00
use Utopia\Validator\Boolean ;
2023-05-22 22:58:13 +12:00
2023-06-16 21:07:47 +12:00
use function Swoole\Coroutine\batch ;
2023-05-22 22:58:13 +12:00
App :: get ( '/v1/vcs/github/installations' )
-> desc ( 'Install GitHub App' )
-> groups ([ 'api' , 'vcs' ])
-> label ( 'scope' , 'public' )
-> label ( 'origin' , '*' )
-> label ( 'sdk.auth' , [])
-> label ( 'sdk.namespace' , 'vcs' )
-> label ( 'sdk.method' , 'createGitHubInstallation' )
-> label ( 'sdk.description' , '' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_MOVED_PERMANENTLY )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_HTML )
-> label ( 'sdk.methodType' , 'webAuth' )
2023-05-28 23:39:48 +12:00
-> param ( 'redirect' , '' , fn ( $clients ) => new Host ( $clients ), 'URL to redirect back to your Git authorization. Only console hostnames are allowed.' , true , [ 'clients' ])
2023-05-22 22:58:13 +12:00
-> inject ( 'response' )
-> inject ( 'project' )
2023-05-26 10:29:08 +12:00
-> action ( function ( string $redirect , Response $response , Document $project ) {
2023-05-22 22:58:13 +12:00
$projectId = $project -> getId ();
2023-05-26 10:29:08 +12:00
$state = \json_encode ([
'projectId' => $projectId ,
'redirect' => $redirect
]);
2023-05-22 22:58:13 +12:00
$appName = App :: getEnv ( 'VCS_GITHUB_APP_NAME' );
$response
-> addHeader ( 'Cache-Control' , 'no-store, no-cache, must-revalidate, max-age=0' )
-> addHeader ( 'Pragma' , 'no-cache' )
2023-05-26 10:29:08 +12:00
-> redirect ( " https://github.com/apps/ $appName /installations/new? " . \http_build_query ([
'state' => $state
]));
2023-05-22 22:58:13 +12:00
});
2023-06-18 23:38:37 +12:00
App :: get ( '/v1/vcs/github/redirect' )
-> desc ( 'Capture installation and authorization from GitHub App' )
2023-05-22 22:58:13 +12:00
-> groups ([ 'api' , 'vcs' ])
-> label ( 'scope' , 'public' )
2023-06-22 22:59:41 +12:00
-> label ( 'error' , __DIR__ . '/../../views/general/error.phtml' )
-> param ( 'installation_id' , '' , new Text ( 256 ), 'GitHub installation ID' , true )
-> param ( 'setup_action' , '' , new Text ( 256 ), 'GitHub setup actuon type' , true )
-> param ( 'state' , '' , new Text ( 2048 ), 'GitHub state. Contains info sent when starting authorization flow.' , true )
2023-06-18 23:38:37 +12:00
-> param ( 'code' , '' , new Text ( 2048 ), 'OAuth2 code.' , true )
2023-05-26 20:44:08 +12:00
-> inject ( 'gitHub' )
2023-06-18 23:38:37 +12:00
-> inject ( 'user' )
2023-06-09 03:24:27 +12:00
-> inject ( 'project' )
2023-05-22 22:58:13 +12:00
-> inject ( 'request' )
-> inject ( 'response' )
-> inject ( 'dbForConsole' )
2023-06-18 23:38:37 +12:00
-> action ( function ( string $installationId , string $setupAction , string $state , string $code , GitHub $github , Document $user , Document $project , Request $request , Response $response , Database $dbForConsole ) {
2023-06-23 19:01:51 +12:00
if ( empty ( $state )) {
2023-06-22 22:59:41 +12:00
throw new Exception ( Exception :: GENERAL_ARGUMENT_INVALID , 'Installation requests from organisation members for the Appwrite GitHub App are currently unsupported. To proceed with the installation, login to the Appwrite Console and install the GitHub App.' );
}
2023-06-23 19:01:51 +12:00
2023-05-26 10:29:08 +12:00
$state = \json_decode ( $state , true );
$redirect = $state [ 'redirect' ] ? ? '' ;
2023-06-18 23:38:37 +12:00
$projectId = $state [ 'projectId' ] ? ? '' ;
2023-05-26 10:29:08 +12:00
2023-06-18 23:38:37 +12:00
$project = $dbForConsole -> getDocument ( 'projects' , $projectId );
2023-06-09 03:24:27 +12:00
2023-05-26 10:29:08 +12:00
if ( empty ( $redirect )) {
$redirect = $request -> getProtocol () . '://' . $request -> getHostname () . " /console/project- $projectId /settings/git-installations " ;
}
2023-05-22 22:58:13 +12:00
if ( $project -> isEmpty ()) {
2023-06-06 19:50:52 +12:00
$response
-> addHeader ( 'Cache-Control' , 'no-store, no-cache, must-revalidate, max-age=0' )
-> addHeader ( 'Pragma' , 'no-cache' )
-> redirect ( $redirect );
2023-06-22 22:59:41 +12:00
return ;
2023-05-22 22:58:13 +12:00
}
2023-06-18 23:38:37 +12:00
$personalSlug = '' ;
2023-05-26 10:29:08 +12:00
2023-06-18 23:38:37 +12:00
// OAuth Authroization
if ( ! empty ( $code )) {
$oauth2 = new OAuth2Github ( App :: getEnv ( 'VCS_GITHUB_CLIENT_ID' , '' ), App :: getEnv ( 'VCS_GITHUB_CLIENT_SECRET' , '' ), " " );
$accessToken = $oauth2 -> getAccessToken ( $code );
$refreshToken = $oauth2 -> getRefreshToken ( $code );
$accessTokenExpiry = $oauth2 -> getAccessTokenExpiry ( $code );
$personalSlug = $oauth2 -> getUserSlug ( $accessToken );
2023-05-22 22:58:13 +12:00
2023-06-18 23:38:37 +12:00
$user = $user
-> setAttribute ( 'vcsGithubAccessToken' , $accessToken )
-> setAttribute ( 'vcsGithubRefreshToken' , $refreshToken )
-> setAttribute ( 'vcsGithubAccessTokenExpiry' , DateTime :: addSeconds ( new \DateTime (), ( int ) $accessTokenExpiry ));
$dbForConsole -> updateDocument ( 'users' , $user -> getId (), $user );
}
2023-05-22 22:58:13 +12:00
2023-06-18 23:38:37 +12:00
// Create / Update installation
if ( ! empty ( $installationId )) {
$privateKey = App :: getEnv ( 'VCS_GITHUB_PRIVATE_KEY' );
$githubAppId = App :: getEnv ( 'VCS_GITHUB_APP_ID' );
$github -> initialiseVariables ( $installationId , $privateKey , $githubAppId );
$owner = $github -> getOwnerName ( $installationId );
$projectInternalId = $project -> getInternalId ();
$vcsInstallation = $dbForConsole -> findOne ( 'vcsInstallations' , [
Query :: equal ( 'installationId' , [ $installationId ]),
Query :: equal ( 'projectInternalId' , [ $projectInternalId ])
2023-05-22 22:58:13 +12:00
]);
2023-06-18 23:38:37 +12:00
if ( $vcsInstallation === false || $vcsInstallation -> isEmpty ()) {
$teamId = $project -> getAttribute ( 'teamId' , '' );
$vcsInstallation = new Document ([
'$id' => ID :: unique (),
'$permissions' => [
Permission :: read ( Role :: team ( ID :: custom ( $teamId ))),
Permission :: update ( Role :: team ( ID :: custom ( $teamId ), 'owner' )),
Permission :: update ( Role :: team ( ID :: custom ( $teamId ), 'developer' )),
Permission :: delete ( Role :: team ( ID :: custom ( $teamId ), 'owner' )),
Permission :: delete ( Role :: team ( ID :: custom ( $teamId ), 'developer' )),
],
'installationId' => $installationId ,
'projectId' => $projectId ,
'projectInternalId' => $projectInternalId ,
'provider' => 'github' ,
'organization' => $owner ,
'personal' => $personalSlug === $owner
]);
$vcsInstallation = $dbForConsole -> createDocument ( 'vcsInstallations' , $vcsInstallation );
} else {
$vcsInstallation = $vcsInstallation -> setAttribute ( 'organization' , $owner );
$vcsInstallation = $vcsInstallation -> setAttribute ( 'personal' , $personalSlug === $owner );
$vcsInstallation = $dbForConsole -> updateDocument ( 'vcsInstallations' , $vcsInstallation -> getId (), $vcsInstallation );
}
2023-06-22 22:59:41 +12:00
} else {
throw new Exception ( Exception :: GENERAL_ARGUMENT_INVALID , 'Installation of the Appwrite GitHub App on organization accounts is restricted to organization owners. As a member of the organization, you do not have the necessary permissions to install this GitHub App. Please contact the organization owner to create the installation from the Appwrite console.' );
2023-05-22 22:58:13 +12:00
}
$response
-> addHeader ( 'Cache-Control' , 'no-store, no-cache, must-revalidate, max-age=0' )
-> addHeader ( 'Pragma' , 'no-cache' )
2023-05-26 10:29:08 +12:00
-> redirect ( $redirect );
2023-05-22 22:58:13 +12:00
});
2023-06-08 03:50:32 +12:00
App :: get ( '/v1/vcs/github/installations/:installationId/repositories' )
2023-05-22 22:58:13 +12:00
-> desc ( 'List repositories' )
-> groups ([ 'api' , 'vcs' ])
-> label ( 'scope' , 'public' )
-> label ( 'sdk.namespace' , 'vcs' )
-> label ( 'sdk.method' , 'listRepositories' )
-> label ( 'sdk.description' , '' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_REPOSITORY_LIST )
-> param ( 'installationId' , '' , new Text ( 256 ), 'Installation Id' )
-> param ( 'search' , '' , new Text ( 256 ), 'Search term to filter your list results. Max length: 256 chars.' , true )
2023-05-26 20:44:08 +12:00
-> inject ( 'gitHub' )
2023-05-22 22:58:13 +12:00
-> inject ( 'response' )
-> inject ( 'project' )
-> inject ( 'dbForConsole' )
2023-05-26 20:44:08 +12:00
-> action ( function ( string $vcsInstallationId , string $search , GitHub $github , Response $response , Document $project , Database $dbForConsole ) {
2023-05-22 22:58:13 +12:00
if ( empty ( $search )) {
$search = " " ;
}
2023-06-08 03:50:32 +12:00
$installation = $dbForConsole -> getDocument ( 'vcsInstallations' , $vcsInstallationId , [
2023-05-22 22:58:13 +12:00
Query :: equal ( 'projectInternalId' , [ $project -> getInternalId ()])
]);
if ( $installation -> isEmpty ()) {
throw new Exception ( Exception :: INSTALLATION_NOT_FOUND );
}
$installationId = $installation -> getAttribute ( 'installationId' );
$privateKey = App :: getEnv ( 'VCS_GITHUB_PRIVATE_KEY' );
$githubAppId = App :: getEnv ( 'VCS_GITHUB_APP_ID' );
$github -> initialiseVariables ( $installationId , $privateKey , $githubAppId );
$page = 1 ;
2023-06-16 21:07:47 +12:00
$perPage = 100 ;
$loadPage = function ( $page ) use ( $github , $perPage ) {
$repos = $github -> listRepositoriesForGitHubApp ( $page , $perPage );
return $repos ;
};
$reposPages = batch ([
function () use ( $loadPage ) {
return $loadPage ( 1 );
},
function () use ( $loadPage ) {
return $loadPage ( 2 );
},
function () use ( $loadPage ) {
return $loadPage ( 3 );
}
]);
2023-05-22 22:58:13 +12:00
2023-06-16 21:07:47 +12:00
$page += 3 ;
$repos = [];
foreach ( $reposPages as $reposPage ) {
$repos = \array_merge ( $repos , $reposPage );
}
// All 3 pages were full, we paginate more
2023-06-17 02:43:37 +12:00
if ( \count ( $repos ) === 3 * $perPage ) {
2023-06-16 21:07:47 +12:00
do {
$reposPage = $loadPage ( $page );
$repos = array_merge ( $repos , $reposPage );
$page ++ ;
} while ( \count ( $reposPage ) === $perPage );
}
2023-05-22 22:58:13 +12:00
// Filter repositories based on search parameter
if ( ! empty ( $search )) {
$repos = array_filter ( $repos , function ( $repo ) use ( $search ) {
2023-06-16 21:07:47 +12:00
return \str_contains ( \strtolower ( $repo [ 'name' ]), \strtolower ( $search ));
2023-05-22 22:58:13 +12:00
});
}
// Sort repositories by last modified date in descending order
usort ( $repos , function ( $repo1 , $repo2 ) {
2023-06-16 21:07:47 +12:00
return \strtotime ( $repo2 [ 'pushed_at' ]) - \strtotime ( $repo1 [ 'pushed_at' ]);
2023-05-22 22:58:13 +12:00
});
// Limit the maximum results to 5
2023-06-16 21:07:47 +12:00
$repos = \array_slice ( $repos , 0 , 5 );
2023-05-22 22:58:13 +12:00
2023-06-19 02:08:53 +12:00
$repos = \array_map ( function ( $repo ) use ( $installation ) {
2023-05-27 23:55:34 +12:00
$repo [ 'id' ] = \strval ( $repo [ 'id' ]);
2023-06-09 03:24:27 +12:00
$repo [ 'pushedAt' ] = $repo [ 'pushed_at' ];
2023-06-19 02:08:53 +12:00
$repo [ 'provider' ] = $installation -> getAttribute ( 'provider' , '' );
$repo [ 'organization' ] = $installation -> getAttribute ( 'organization' , '' );
2023-05-27 23:55:34 +12:00
return new Document ( $repo );
}, $repos );
2023-05-22 22:58:13 +12:00
$response -> dynamic ( new Document ([
'repositories' => $repos ,
'total' => \count ( $repos ),
]), Response :: MODEL_REPOSITORY_LIST );
});
2023-06-18 23:38:37 +12:00
App :: post ( '/v1/vcs/github/installations/:installationId/repositories' )
-> desc ( 'Create repository' )
-> groups ([ 'api' , 'vcs' ])
-> label ( 'scope' , 'public' )
-> label ( 'sdk.namespace' , 'vcs' )
-> label ( 'sdk.method' , 'createRepository' )
-> label ( 'sdk.description' , '' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_REPOSITORY )
-> param ( 'installationId' , '' , new Text ( 256 ), 'Installation Id' )
-> param ( 'name' , '' , new Text ( 256 ), 'Repository name (slug)' )
-> param ( 'private' , '' , new Boolean ( false ), 'Mark repository public or private' )
-> inject ( 'gitHub' )
-> inject ( 'user' )
-> inject ( 'response' )
-> inject ( 'project' )
-> inject ( 'dbForConsole' )
-> action ( function ( string $vcsInstallationId , string $name , bool $private , GitHub $github , Document $user , Response $response , Document $project , Database $dbForConsole ) {
$installation = $dbForConsole -> getDocument ( 'vcsInstallations' , $vcsInstallationId , [
Query :: equal ( 'projectInternalId' , [ $project -> getInternalId ()])
]);
if ( $installation -> isEmpty ()) {
throw new Exception ( Exception :: INSTALLATION_NOT_FOUND );
}
if ( $installation -> getAttribute ( 'personal' , false ) === true ) {
$oauth2 = new OAuth2Github ( App :: getEnv ( 'VCS_GITHUB_CLIENT_ID' , '' ), App :: getEnv ( 'VCS_GITHUB_CLIENT_SECRET' , '' ), " " );
$accessToken = $user -> getAttribute ( 'vcsGithubAccessToken' );
$refreshToken = $user -> getAttribute ( 'vcsGithubRefreshToken' );
$accessTokenExpiry = $user -> getAttribute ( 'vcsGithubAccessTokenExpiry' );
$isExpired = new \DateTime ( $accessTokenExpiry ) < new \DateTime ( 'now' );
if ( $isExpired ) {
$oauth2 -> refreshTokens ( $refreshToken );
$accessToken = $oauth2 -> getAccessToken ( '' );
$refreshToken = $oauth2 -> getRefreshToken ( '' );
$verificationId = $oauth2 -> getUserID ( $accessToken );
if ( empty ( $verificationId )) {
throw new Exception ( Exception :: GENERAL_RATE_LIMIT_EXCEEDED , " Another request is currently refreshing OAuth token. Please try again. " );
}
$user = $user
-> setAttribute ( 'vcsGithubAccessToken' , $accessToken )
-> setAttribute ( 'vcsGithubRefreshToken' , $refreshToken )
-> setAttribute ( 'vcsGithubAccessTokenExpiry' , DateTime :: addSeconds ( new \DateTime (), ( int ) $oauth2 -> getAccessTokenExpiry ( '' )));
$dbForConsole -> updateDocument ( 'users' , $user -> getId (), $user );
}
$repository = $oauth2 -> createRepository ( $accessToken , $name , $private );
} else {
$installationId = $installation -> getAttribute ( 'installationId' );
$privateKey = App :: getEnv ( 'VCS_GITHUB_PRIVATE_KEY' );
$githubAppId = App :: getEnv ( 'VCS_GITHUB_APP_ID' );
$github -> initialiseVariables ( $installationId , $privateKey , $githubAppId );
$owner = $github -> getOwnerName ( $installationId );
$repository = $github -> createRepository ( $owner , $name , $private );
}
$repository [ 'id' ] = \strval ( $repository [ 'id' ]);
$repository [ 'pushedAt' ] = $repository [ 'pushed_at' ];
2023-06-22 22:59:41 +12:00
$repository [ 'organization' ] = $installation -> getAttribute ( 'organization' , '' );
$repository [ 'provider' ] = $installation -> getAttribute ( 'provider' , '' );
2023-06-18 23:38:37 +12:00
$response -> dynamic ( new Document ( $repository ), Response :: MODEL_REPOSITORY );
});
2023-06-08 03:50:32 +12:00
App :: get ( '/v1/vcs/github/installations/:installationId/repositories/:repositoryId' )
-> desc ( 'Get repository' )
-> groups ([ 'api' , 'vcs' ])
-> label ( 'scope' , 'public' )
-> label ( 'sdk.namespace' , 'vcs' )
-> label ( 'sdk.method' , 'getRepository' )
-> label ( 'sdk.description' , '' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_REPOSITORY )
-> param ( 'installationId' , '' , new Text ( 256 ), 'Installation Id' )
-> param ( 'repositoryId' , '' , new Text ( 256 ), 'Repository Id' )
-> inject ( 'gitHub' )
-> inject ( 'response' )
-> inject ( 'project' )
-> inject ( 'dbForConsole' )
-> action ( function ( string $vcsInstallationId , string $repositoryId , GitHub $github , Response $response , Document $project , Database $dbForConsole ) {
$installation = $dbForConsole -> getDocument ( 'vcsInstallations' , $vcsInstallationId , [
Query :: equal ( 'projectInternalId' , [ $project -> getInternalId ()])
]);
if ( $installation -> isEmpty ()) {
throw new Exception ( Exception :: INSTALLATION_NOT_FOUND );
}
$installationId = $installation -> getAttribute ( 'installationId' );
$privateKey = App :: getEnv ( 'VCS_GITHUB_PRIVATE_KEY' );
$githubAppId = App :: getEnv ( 'VCS_GITHUB_APP_ID' );
$github -> initialiseVariables ( $installationId , $privateKey , $githubAppId );
$owner = $github -> getOwnerName ( $installationId );
$repositoryName = $github -> getRepositoryName ( $repositoryId );
if ( empty ( $repositoryName )) {
throw new Exception ( Exception :: REPOSITORY_NOT_FOUND );
}
$repository = $github -> getRepository ( $owner , $repositoryName );
2023-06-09 03:24:27 +12:00
$repository [ 'id' ] = \strval ( $repository [ 'id' ]);
$repository [ 'pushedAt' ] = $repository [ 'pushed_at' ];
2023-06-19 02:08:53 +12:00
$repository [ 'organization' ] = $installation -> getAttribute ( 'organization' , '' );
$repository [ 'provider' ] = $installation -> getAttribute ( 'provider' , '' );
2023-06-09 03:24:27 +12:00
2023-06-08 03:50:32 +12:00
$response -> dynamic ( new Document ( $repository ), Response :: MODEL_REPOSITORY );
});
App :: get ( '/v1/vcs/github/installations/:installationId/repositories/:repositoryId/branches' )
2023-05-26 10:29:08 +12:00
-> desc ( 'List Repository Branches' )
-> groups ([ 'api' , 'vcs' ])
-> label ( 'scope' , 'public' )
-> label ( 'sdk.namespace' , 'vcs' )
-> label ( 'sdk.method' , 'listRepositoryBranches' )
-> label ( 'sdk.description' , '' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_BRANCH_LIST )
-> param ( 'installationId' , '' , new Text ( 256 ), 'Installation Id' )
-> param ( 'repositoryId' , '' , new Text ( 256 ), 'Repository Id' )
2023-05-26 20:44:08 +12:00
-> inject ( 'gitHub' )
2023-05-26 10:29:08 +12:00
-> inject ( 'response' )
-> inject ( 'project' )
-> inject ( 'dbForConsole' )
2023-05-26 20:44:08 +12:00
-> action ( function ( string $vcsInstallationId , string $repositoryId , GitHub $github , Response $response , Document $project , Database $dbForConsole ) {
2023-06-08 03:50:32 +12:00
$installation = $dbForConsole -> getDocument ( 'vcsInstallations' , $vcsInstallationId , [
2023-05-26 10:29:08 +12:00
Query :: equal ( 'projectInternalId' , [ $project -> getInternalId ()])
]);
if ( $installation -> isEmpty ()) {
throw new Exception ( Exception :: INSTALLATION_NOT_FOUND );
}
$installationId = $installation -> getAttribute ( 'installationId' );
$privateKey = App :: getEnv ( 'VCS_GITHUB_PRIVATE_KEY' );
$githubAppId = App :: getEnv ( 'VCS_GITHUB_APP_ID' );
$github -> initialiseVariables ( $installationId , $privateKey , $githubAppId );
$owner = $github -> getOwnerName ( $installationId );
$repoName = $github -> getRepositoryName ( $repositoryId );
$branches = $github -> listBranches ( $owner , $repoName );
$response -> dynamic ( new Document ([
'branches' => \array_map ( function ( $branch ) {
2023-05-28 23:39:48 +12:00
return [ 'name' => $branch ];
2023-05-26 10:29:08 +12:00
}, $branches ),
'total' => \count ( $branches ),
]), Response :: MODEL_BRANCH_LIST );
});
2023-06-17 22:07:30 +12:00
$createGitDeployments = function ( GitHub $github , string $installationId , string $repositoryId , array $vcsRepos , string $branchName , string $SHA , string $commentId , Database $dbForConsole , callable $getProjectDB , Request $request ) {
2023-05-25 17:30:52 +12:00
foreach ( $vcsRepos as $resource ) {
$resourceType = $resource -> getAttribute ( 'resourceType' );
if ( $resourceType === " function " ) {
$projectId = $resource -> getAttribute ( 'projectId' );
$project = Authorization :: skip ( fn () => $dbForConsole -> getDocument ( 'projects' , $projectId ));
$dbForProject = $getProjectDB ( $project );
$functionId = $resource -> getAttribute ( 'resourceId' );
2023-06-09 23:34:46 +12:00
$function = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'functions' , $functionId ));
2023-05-25 17:30:52 +12:00
$deploymentId = ID :: unique ();
$vcsRepoId = $resource -> getId ();
$vcsRepoInternalId = $resource -> getInternalId ();
$vcsInstallationId = $resource -> getAttribute ( 'vcsInstallationId' );
$vcsInstallationInternalId = $resource -> getAttribute ( 'vcsInstallationInternalId' );
2023-06-09 23:34:46 +12:00
$productionBranch = $function -> getAttribute ( 'vcsBranch' );
2023-05-25 17:30:52 +12:00
$activate = false ;
if ( $branchName == $productionBranch ) {
$activate = true ;
}
2023-05-29 23:51:03 +12:00
$latestDeployment = Authorization :: skip ( fn () => $dbForProject -> findOne ( 'deployments' , [
2023-06-17 22:07:30 +12:00
Query :: equal ( 'vcsRepositoryId' , [ $repositoryId ]),
2023-06-09 23:34:46 +12:00
Query :: equal ( 'vcsBranch' , [ $branchName ]),
2023-05-29 23:51:03 +12:00
Query :: equal ( 'resourceType' , [ 'functions' ]),
Query :: orderDesc ( '$createdAt' ),
]));
$latestCommentId = $commentId ? ? '' ;
if ( empty ( $latestCommentId )) {
// Empty comment ID is push event. We try to take ID from last deplyoment
2023-05-28 23:39:48 +12:00
if ( $latestDeployment !== false && ! $latestDeployment -> isEmpty ()) {
2023-05-29 23:51:03 +12:00
$latestCommentId = $latestDeployment -> getAttribute ( 'vcsCommentId' , '' );
}
} else {
// Known comment ID is pull request event. If deployment exists already, we skip
if ( $latestDeployment !== false && ! $latestDeployment -> isEmpty ()) {
$latestDeployment -> setAttribute ( 'vcsCommentId' , $latestCommentId );
Authorization :: skip ( fn () => $dbForProject -> updateDocument ( 'deployments' , $latestDeployment -> getId (), $latestDeployment ));
continue ;
2023-05-28 23:39:48 +12:00
}
}
2023-06-17 22:07:30 +12:00
$owner = $github -> getOwnerName ( $installationId );
$repositoryName = $github -> getRepositoryName ( $repositoryId );
if ( empty ( $latestCommentId )) {
2023-06-19 02:08:53 +12:00
$comment = new Comment ();
$comment -> addBuild ( $project , $function , 'waiting' , $deploymentId );
2023-06-17 22:07:30 +12:00
$pullRequest = $github -> getBranchPullRequest ( $owner , $repositoryName , $branchName );
if ( ! empty ( $pullRequest )) {
$pullRequestNumber = \strval ( $pullRequest [ 'number' ]);
$latestCommentId = $github -> createComment ( $owner , $repositoryName , $pullRequestNumber , $comment -> generateComment ());
}
} else {
2023-06-19 02:08:53 +12:00
$comment = new Comment ();
$comment -> parseComment ( $github -> getComment ( $owner , $repositoryName , $latestCommentId ));
$comment -> addBuild ( $project , $function , 'waiting' , $deploymentId );
2023-06-17 22:07:30 +12:00
$latestCommentId = $github -> updateComment ( $owner , $repositoryName , $latestCommentId , $comment -> generateComment ());
}
2023-05-25 17:30:52 +12:00
$deployment = $dbForProject -> createDocument ( 'deployments' , new Document ([
'$id' => $deploymentId ,
'$permissions' => [
Permission :: read ( Role :: any ()),
Permission :: update ( Role :: any ()),
Permission :: delete ( Role :: any ()),
],
'resourceId' => $functionId ,
'resourceType' => 'functions' ,
'entrypoint' => $function -> getAttribute ( 'entrypoint' ),
'installCommand' => $function -> getAttribute ( 'installCommand' ),
'buildCommand' => $function -> getAttribute ( 'buildCommand' ),
'type' => 'vcs' ,
'vcsInstallationId' => $vcsInstallationId ,
'vcsInstallationInternalId' => $vcsInstallationInternalId ,
2023-06-17 22:07:30 +12:00
'vcsRepositoryId' => $repositoryId ,
'vcsRepositoryDocId' => $vcsRepoId ,
'vcsRepositoryDocInternalId' => $vcsRepoInternalId ,
'vcsCommentId' => \strval ( $latestCommentId ),
2023-06-09 03:24:27 +12:00
'vcsBranch' => $branchName ,
2023-05-25 17:30:52 +12:00
'search' => implode ( ' ' , [ $deploymentId , $function -> getAttribute ( 'entrypoint' )]),
'activate' => $activate ,
]));
2023-06-19 02:08:53 +12:00
$targetUrl = $request -> getProtocol () . '://' . $request -> getHostname () . " /console/project- $projectId /functions/function- $functionId " ;
2023-05-25 17:30:52 +12:00
2023-06-08 03:50:32 +12:00
if ( ! empty ( $SHA ) && $function -> getAttribute ( 'vcsSilentMode' , false ) === false ) {
2023-05-29 23:51:03 +12:00
$functionName = $function -> getAttribute ( 'name' );
$projectName = $project -> getAttribute ( 'name' );
$name = " { $functionName } ( { $projectName } ) " ;
$message = 'Starting...' ;
$repositoryId = $resource -> getAttribute ( 'repositoryId' );
$repositoryName = $github -> getRepositoryName ( $repositoryId );
$owner = $github -> getOwnerName ( $installationId );
$github -> updateCommitStatus ( $repositoryName , $SHA , $owner , 'pending' , $message , $targetUrl , $name );
}
2023-05-25 17:30:52 +12:00
$buildEvent = new Build ();
$buildEvent
-> setType ( BUILD_TYPE_DEPLOYMENT )
-> setResource ( $function )
-> setDeployment ( $deployment )
-> setTargetUrl ( $targetUrl )
-> setSHA ( $SHA )
-> setProject ( $project )
-> trigger ();
//TODO: Add event?
}
}
};
2023-05-22 22:58:13 +12:00
App :: post ( '/v1/vcs/github/incomingwebhook' )
-> desc ( 'Captures GitHub Webhook Events' )
-> groups ([ 'api' , 'vcs' ])
-> label ( 'scope' , 'public' )
2023-05-26 20:44:08 +12:00
-> inject ( 'gitHub' )
2023-05-22 22:58:13 +12:00
-> inject ( 'request' )
-> inject ( 'response' )
-> inject ( 'dbForConsole' )
2023-05-23 16:37:25 +12:00
-> inject ( 'getProjectDB' )
2023-05-22 22:58:13 +12:00
-> action (
2023-05-26 20:44:08 +12:00
function ( GitHub $github , Request $request , Response $response , Database $dbForConsole , callable $getProjectDB ) use ( $createGitDeployments ) {
2023-06-15 22:37:28 +12:00
$signature = $request -> getHeader ( 'x-hub-signature-256' , '' );
2023-05-22 22:58:13 +12:00
$payload = $request -> getRawPayload ();
2023-06-15 22:37:28 +12:00
$signatureKey = App :: getEnv ( 'VCS_GITHUB_WEBHOOK_SECRET' , '' );
2023-06-15 22:38:03 +12:00
2023-06-15 22:37:28 +12:00
$valid = $github -> validateWebhook ( $payload , $signature , $signatureKey );
2023-06-15 22:38:03 +12:00
if ( ! $valid ) {
2023-06-15 22:37:28 +12:00
throw new Exception ( Exception :: GENERAL_ACCESS_FORBIDDEN , " Invalid webhook signature. " );
}
$event = $request -> getHeader ( 'x-github-event' , '' );
2023-05-22 22:58:13 +12:00
$privateKey = App :: getEnv ( 'VCS_GITHUB_PRIVATE_KEY' );
$githubAppId = App :: getEnv ( 'VCS_GITHUB_APP_ID' );
$parsedPayload = $github -> parseWebhookEventPayload ( $event , $payload );
if ( $event == $github :: EVENT_PUSH ) {
$branchName = $parsedPayload [ " branch " ];
$repositoryId = $parsedPayload [ " repositoryId " ];
$installationId = $parsedPayload [ " installationId " ];
$SHA = $parsedPayload [ " SHA " ];
$owner = $parsedPayload [ " owner " ];
2023-05-29 23:51:03 +12:00
$github -> initialiseVariables ( $installationId , $privateKey , $githubAppId );
2023-05-22 22:58:13 +12:00
//find functionId from functions table
2023-06-08 03:50:32 +12:00
$vcsRepos = $dbForConsole -> find ( 'vcsRepos' , [
2023-05-22 22:58:13 +12:00
Query :: equal ( 'repositoryId' , [ $repositoryId ]),
Query :: limit ( 100 ),
]);
2023-06-17 22:07:30 +12:00
$createGitDeployments ( $github , $installationId , $repositoryId , $vcsRepos , $branchName , $SHA , '' , $dbForConsole , $getProjectDB , $request );
2023-05-22 22:58:13 +12:00
} elseif ( $event == $github :: EVENT_INSTALLATION ) {
if ( $parsedPayload [ " action " ] == " deleted " ) {
2023-05-26 10:29:08 +12:00
// TODO: Use worker for this job instead (update function as well)
2023-05-22 22:58:13 +12:00
$installationId = $parsedPayload [ " installationId " ];
2023-06-08 03:50:32 +12:00
$vcsInstallations = $dbForConsole -> find ( 'vcsInstallations' , [
2023-05-22 22:58:13 +12:00
Query :: equal ( 'installationId' , [ $installationId ]),
Query :: limit ( 1000 )
]);
foreach ( $vcsInstallations as $installation ) {
2023-06-08 03:50:32 +12:00
$vcsRepos = $dbForConsole -> find ( 'vcsRepos' , [
2023-05-22 22:58:13 +12:00
Query :: equal ( 'vcsInstallationId' , [ $installation -> getId ()]),
Query :: limit ( 1000 )
]);
foreach ( $vcsRepos as $repo ) {
2023-06-08 03:50:32 +12:00
$dbForConsole -> deleteDocument ( 'vcsRepos' , $repo -> getId ());
2023-05-22 22:58:13 +12:00
}
2023-06-08 03:50:32 +12:00
$dbForConsole -> deleteDocument ( 'vcsInstallations' , $installation -> getId ());
2023-05-22 22:58:13 +12:00
}
}
} elseif ( $event == $github :: EVENT_PULL_REQUEST ) {
if ( $parsedPayload [ " action " ] == " opened " or $parsedPayload [ " action " ] == " reopened " ) {
$branchName = $parsedPayload [ " branch " ];
$repositoryId = $parsedPayload [ " repositoryId " ];
$installationId = $parsedPayload [ " installationId " ];
$pullRequestNumber = $parsedPayload [ " pullRequestNumber " ];
$repositoryName = $parsedPayload [ " repositoryName " ];
$owner = $parsedPayload [ " owner " ];
2023-05-29 23:51:03 +12:00
2023-05-22 22:58:13 +12:00
$github -> initialiseVariables ( $installationId , $privateKey , $githubAppId );
2023-06-08 03:50:32 +12:00
$vcsRepos = $dbForConsole -> find ( 'vcsRepos' , [
2023-05-22 22:58:13 +12:00
Query :: equal ( 'repositoryId' , [ $repositoryId ]),
Query :: orderDesc ( '$createdAt' )
]);
2023-05-28 23:39:48 +12:00
if ( \count ( $vcsRepos ) !== 0 ) {
$comment = new Comment ();
foreach ( $vcsRepos as $vcsRepo ) {
$projectId = $vcsRepo -> getAttribute ( 'projectId' );
$project = Authorization :: skip ( fn () => $dbForConsole -> getDocument ( 'projects' , $projectId ));
$dbForProject = $getProjectDB ( $project );
$vcsRepoId = $vcsRepo -> getId ();
$deployment = Authorization :: skip ( fn () => $dbForProject -> findOne ( 'deployments' , [
2023-06-17 22:07:30 +12:00
Query :: equal ( 'vcsRepositoryDocId' , [ $vcsRepoId ]),
2023-06-09 03:24:27 +12:00
Query :: equal ( 'vcsBranch' , [ $branchName ]),
2023-05-28 23:39:48 +12:00
Query :: equal ( 'resourceType' , [ 'functions' ]),
Query :: orderDesc ( '$createdAt' ),
]));
if ( ! $deployment || $deployment -> isEmpty ()) {
$function = Authorization :: skip ( fn () => $dbForProject -> findOne ( 'functions' , [
2023-06-17 22:07:30 +12:00
Query :: equal ( 'vcsRepositoryDocId' , [ $vcsRepoId ]),
2023-05-28 23:39:48 +12:00
Query :: orderDesc ( '$createdAt' ),
]));
$build = new Document ([]);
} else {
$function = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'functions' , $deployment -> getAttribute ( 'resourceId' , '' )));
$build = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'builds' , $deployment -> getAttribute ( 'buildId' , '' )));
}
if ( ! $function || $function -> isEmpty ()) {
continue ;
}
$status = ! $build || $build -> isEmpty () ? 'waiting' : $build -> getAttribute ( 'status' , 'waiting' );
$deploymentId = ! $build || $build -> isEmpty () ? '' : $build -> getAttribute ( 'deploymentId' , '' );
$comment -> addBuild ( $project , $function , $status , $deploymentId );
}
$commentId = '' ;
2023-06-08 03:50:32 +12:00
if ( ! $comment -> isEmpty () && $function -> getAttribute ( 'vcsSilentMode' , false ) === false ) {
2023-05-28 23:39:48 +12:00
$commentId = $github -> createComment ( $owner , $repositoryName , $pullRequestNumber , $comment -> generateComment ());
}
2023-05-25 17:30:52 +12:00
2023-06-17 22:07:30 +12:00
$createGitDeployments ( $github , $installationId , $repositoryId , $vcsRepos , $branchName , '' , $commentId , $dbForConsole , $getProjectDB , $request );
2023-05-22 22:58:13 +12:00
}
}
}
$response -> json ( $parsedPayload );
}
);
App :: get ( '/v1/vcs/installations' )
-> groups ([ 'api' , 'vcs' ])
-> desc ( 'List installations' )
-> label ( 'scope' , 'public' )
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'vcs' )
-> label ( 'sdk.method' , 'listInstallations' )
-> label ( 'sdk.description' , '/docs/references/vcs/list-installations.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_INSTALLATION_LIST )
-> param ( 'queries' , [], new Installations (), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode ( ', ' , Installations :: ALLOWED_ATTRIBUTES ), true )
-> param ( 'search' , '' , new Text ( 256 ), 'Search term to filter your list results. Max length: 256 chars.' , true )
-> inject ( 'response' )
-> inject ( 'project' )
2023-06-06 19:50:52 +12:00
-> inject ( 'dbForProject' )
2023-05-22 22:58:13 +12:00
-> inject ( 'dbForConsole' )
2023-06-06 19:50:52 +12:00
-> action ( function ( array $queries , string $search , Response $response , Document $project , Database $dbForProject , Database $dbForConsole ) {
2023-05-22 22:58:13 +12:00
$queries = Query :: parseQueries ( $queries );
$queries [] = Query :: equal ( 'projectInternalId' , [ $project -> getInternalId ()]);
if ( ! empty ( $search )) {
$queries [] = Query :: search ( 'search' , $search );
}
// Get cursor document if there was a cursor query
$cursor = Query :: getByType ( $queries , Query :: TYPE_CURSORAFTER , Query :: TYPE_CURSORBEFORE );
$cursor = reset ( $cursor );
if ( $cursor ) {
/** @var Query $cursor */
$vcsInstallationId = $cursor -> getValue ();
2023-06-08 03:50:32 +12:00
$cursorDocument = $dbForConsole -> getDocument ( 'vcsInstallations' , $vcsInstallationId );
2023-05-22 22:58:13 +12:00
if ( $cursorDocument -> isEmpty ()) {
throw new Exception ( Exception :: GENERAL_CURSOR_NOT_FOUND , " Installation ' { $vcsInstallationId } ' for the 'cursor' value not found. " );
}
$cursor -> setValue ( $cursorDocument );
}
$filterQueries = Query :: groupByType ( $queries )[ 'filters' ];
2023-06-08 03:50:32 +12:00
$results = $dbForConsole -> find ( 'vcsInstallations' , $queries );
$total = $dbForConsole -> count ( 'vcsInstallations' , $filterQueries , APP_LIMIT_COUNT );
2023-06-06 19:50:52 +12:00
if ( \count ( $results ) > 0 ) {
$installationIds = \array_map ( fn ( $result ) => $result -> getId (), $results );
$functions = Authorization :: skip ( fn () => $dbForProject -> find ( 'functions' , [
Query :: equal ( 'vcsInstallationId' , \array_unique ( $installationIds )),
Query :: limit ( APP_LIMIT_SUBQUERY )
]));
foreach ( $results as $result ) {
$installationFunctions = \array_filter ( $functions , fn ( $function ) => $function -> getAttribute ( 'vcsInstallationId' ) === $result -> getId ());
$result -> setAttribute ( 'functions' , $installationFunctions );
}
}
2023-05-22 22:58:13 +12:00
$response -> dynamic ( new Document ([
2023-06-06 19:50:52 +12:00
'installations' => $results ,
'total' => $total ,
2023-05-22 22:58:13 +12:00
]), Response :: MODEL_INSTALLATION_LIST );
});
2023-06-08 03:50:32 +12:00
App :: get ( '/v1/vcs/installations/:installationId' )
-> groups ([ 'api' , 'vcs' ])
2023-06-13 23:13:02 +12:00
-> desc ( 'Get installation' )
2023-06-08 03:50:32 +12:00
-> label ( 'scope' , 'public' )
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'vcs' )
-> label ( 'sdk.method' , 'getInstallation' )
-> label ( 'sdk.description' , '/docs/references/vcs/get-installation.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_INSTALLATION )
-> param ( 'installationId' , '' , new Text ( 256 ), 'Installation Id' )
-> inject ( 'response' )
-> inject ( 'project' )
-> inject ( 'dbForProject' )
-> inject ( 'dbForConsole' )
-> action ( function ( string $installationId , Response $response , Document $project , Database $dbForProject , Database $dbForConsole ) {
$installation = $dbForConsole -> getDocument ( 'vcsInstallations' , $installationId );
if ( $installation === false || $installation -> isEmpty ()) {
throw new Exception ( Exception :: INSTALLATION_NOT_FOUND );
}
if ( $installation -> getAttribute ( 'projectInternalId' ) !== $project -> getInternalId ()) {
throw new Exception ( Exception :: INSTALLATION_NOT_FOUND );
}
$functions = Authorization :: skip ( fn () => $dbForProject -> find ( 'functions' , [
Query :: equal ( 'vcsInstallationId' , [ $installation -> getId ()]),
Query :: limit ( APP_LIMIT_SUBQUERY )
]));
$installation -> setAttribute ( 'functions' , $functions );
$response -> dynamic ( $installation , Response :: MODEL_INSTALLATION );
});
2023-05-22 22:58:13 +12:00
App :: delete ( '/v1/vcs/installations/:installationId' )
-> groups ([ 'api' , 'vcs' ])
-> desc ( 'Delete Installation' )
-> label ( 'scope' , 'public' )
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'vcs' )
-> label ( 'sdk.method' , 'deleteInstallation' )
-> label ( 'sdk.description' , '/docs/references/vcs/delete-installation.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_NOCONTENT )
-> label ( 'sdk.response.model' , Response :: MODEL_NONE )
-> param ( 'installationId' , '' , new Text ( 256 ), 'Installation Id' )
-> inject ( 'response' )
-> inject ( 'project' )
-> inject ( 'dbForConsole' )
-> inject ( 'deletes' )
-> action ( function ( string $vcsInstallationId , Response $response , Document $project , Database $dbForConsole , Delete $deletes ) {
2023-06-08 03:50:32 +12:00
$installation = $dbForConsole -> getDocument ( 'vcsInstallations' , $vcsInstallationId , [
2023-05-22 22:58:13 +12:00
Query :: equal ( 'projectInternalId' , [ $project -> getInternalId ()])
]);
if ( $installation -> isEmpty ()) {
throw new Exception ( Exception :: INSTALLATION_NOT_FOUND );
}
2023-06-08 03:50:32 +12:00
if ( ! $dbForConsole -> deleteDocument ( 'vcsInstallations' , $installation -> getId ())) {
2023-05-22 22:58:13 +12:00
throw new Exception ( Exception :: GENERAL_SERVER_ERROR , 'Failed to remove installation from DB' );
}
$deletes
-> setType ( DELETE_TYPE_DOCUMENT )
-> setDocument ( $installation );
$response -> noContent ();
});
2023-06-14 06:44:44 +12:00
App :: get ( '/v1/vcs/github/installations/:installationId/repositories/:repositoryId/detection' )
-> desc ( 'Detect function settings like runtime for specified root directory' )
-> groups ([ 'api' , 'vcs' ])
-> label ( 'scope' , 'public' )
-> label ( 'sdk.namespace' , 'vcs' )
-> label ( 'sdk.method' , 'createRepositoryDetection' )
-> label ( 'sdk.description' , '' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_DETECTION )
-> param ( 'installationId' , '' , new Text ( 256 ), 'Installation Id' )
-> param ( 'repositoryId' , '' , new Text ( 256 ), 'Repository Id' )
-> param ( 'rootDirectoryPath' , '' , new Text ( 256 ), 'Path to Root Directory' , true )
-> inject ( 'gitHub' )
-> inject ( 'response' )
-> inject ( 'project' )
-> inject ( 'dbForConsole' )
-> action ( function ( string $vcsInstallationId , string $repositoryId , string $rootDirectoryPath , GitHub $github , Response $response , Document $project , Database $dbForConsole ) {
$installation = $dbForConsole -> getDocument ( 'vcsInstallations' , $vcsInstallationId , [
Query :: equal ( 'projectInternalId' , [ $project -> getInternalId ()])
]);
if ( $installation -> isEmpty ()) {
throw new Exception ( Exception :: INSTALLATION_NOT_FOUND );
}
$installationId = $installation -> getAttribute ( 'installationId' );
$privateKey = App :: getEnv ( 'VCS_GITHUB_PRIVATE_KEY' );
$githubAppId = App :: getEnv ( 'VCS_GITHUB_APP_ID' );
$github -> initialiseVariables ( $installationId , $privateKey , $githubAppId );
$owner = $github -> getOwnerName ( $installationId );
$repositoryName = $github -> getRepositoryName ( $repositoryId );
if ( empty ( $repositoryName )) {
throw new Exception ( Exception :: REPOSITORY_NOT_FOUND );
}
$files = $github -> listRepositoryContents ( $owner , $repositoryName , $rootDirectoryPath );
$languages = $github -> getRepositoryLanguages ( $owner , $repositoryName );
$detectorFactory = new Detector ( $files , $languages );
$detectorFactory
-> addDetector ( new JavaScript ())
-> addDetector ( new PHP ())
-> addDetector ( new Python ())
-> addDetector ( new Dart ())
-> addDetector ( new Swift ())
-> addDetector ( new Ruby ())
-> addDetector ( new Java ())
-> addDetector ( new CPP ())
-> addDetector ( new Deno ())
-> addDetector ( new Dotnet ());
$runtime = $detectorFactory -> detect ();
$detection = [];
$detection [ 'runtime' ] = $runtime ;
$response -> dynamic ( new Document ( $detection ), Response :: MODEL_DETECTION );
2023-06-15 22:37:28 +12:00
});