1
0
Fork 0
mirror of synced 2024-07-15 19:36:08 +12:00
appwrite/app/workers/builds.php

584 lines
26 KiB
PHP
Raw Normal View History

2022-01-24 11:25:46 +13:00
<?php
2023-06-13 18:26:36 +12:00
use Swoole\Coroutine as Co;
2022-04-19 04:21:45 +12:00
use Appwrite\Event\Event;
2022-11-16 07:13:17 +13:00
use Appwrite\Event\Func;
2022-03-01 00:50:27 +13:00
use Appwrite\Messaging\Adapter\Realtime;
2022-01-24 11:25:46 +13:00
use Appwrite\Resque\Worker;
2022-04-19 04:21:45 +12:00
use Appwrite\Utopia\Response\Model\Deployment;
2022-02-04 14:29:40 +13:00
use Executor\Executor;
2022-08-09 18:28:38 +12:00
use Appwrite\Usage\Stats;
use Appwrite\Vcs\Comment;
use Utopia\Database\DateTime;
2022-01-24 11:25:46 +13:00
use Utopia\App;
use Utopia\CLI\Console;
2023-02-06 09:07:46 +13:00
use Utopia\Database\Helpers\ID;
2022-11-18 01:50:17 +13:00
use Utopia\DSN\DSN;
2022-01-24 11:25:46 +13:00
use Utopia\Database\Document;
use Utopia\Config\Config;
use Utopia\Database\Database;
use Utopia\Database\Query;
2022-11-18 06:43:59 +13:00
use Utopia\Storage\Storage;
use Utopia\Database\Validator\Authorization;
use Utopia\VCS\Adapter\Git\GitHub;
2022-01-24 11:25:46 +13:00
2022-04-20 01:13:55 +12:00
require_once __DIR__ . '/../init.php';
2022-01-24 11:25:46 +13:00
Console::title('Builds V1 Worker');
2022-04-20 01:13:55 +12:00
Console::success(APP_NAME . ' build worker v1 has started');
2022-01-24 11:25:46 +13:00
2022-01-25 09:06:29 +13:00
// TODO: Executor should return appropriate response codes.
2022-01-24 11:25:46 +13:00
class BuildsV1 extends Worker
{
2022-04-20 01:13:55 +12:00
private ?Executor $executor = null;
2022-01-24 11:25:46 +13:00
2022-04-20 01:13:55 +12:00
public function getName(): string
2022-01-26 12:45:41 +13:00
{
2022-01-24 11:25:46 +13:00
return "builds";
}
2022-05-10 00:36:29 +12:00
public function init(): void
{
$this->executor = new Executor(App::getEnv('_APP_EXECUTOR_HOST'));
2022-02-04 14:29:40 +13:00
}
2022-01-24 11:25:46 +13:00
public function run(): void
{
$type = $this->args['type'] ?? '';
2022-04-20 01:13:55 +12:00
$project = new Document($this->args['project'] ?? []);
$resource = new Document($this->args['resource'] ?? []);
$deployment = new Document($this->args['deployment'] ?? []);
$template = new Document($this->args['template'] ?? []);
2022-01-24 11:25:46 +13:00
switch ($type) {
case BUILD_TYPE_DEPLOYMENT:
2022-02-17 09:06:22 +13:00
case BUILD_TYPE_RETRY:
2022-04-20 01:13:55 +12:00
Console::info('Creating build for deployment: ' . $deployment->getId());
2023-05-26 20:44:08 +12:00
$github = new GitHub($this->getCache());
2023-08-12 04:52:13 +12:00
$this->buildDeployment($github, $project, $resource, $deployment, $template);
2022-01-24 11:25:46 +13:00
break;
2022-01-24 11:25:46 +13:00
default:
throw new \Exception('Invalid build type');
2022-01-24 11:25:46 +13:00
break;
}
}
2023-02-07 01:54:37 +13:00
/**
* @throws \Utopia\Database\Exception\Authorization
* @throws \Utopia\Database\Exception\Structure
* @throws Throwable
*/
2023-08-12 04:52:13 +12:00
protected function buildDeployment(GitHub $github, Document $project, Document $function, Document $deployment, Document $template)
2022-01-24 11:25:46 +13:00
{
2022-11-17 01:19:29 +13:00
global $register;
2022-08-13 19:57:04 +12:00
$dbForProject = $this->getProjectDB($project);
$dbForConsole = $this->getConsoleDB();
2022-04-20 01:13:55 +12:00
$function = $dbForProject->getDocument('functions', $function->getId());
2022-01-24 11:25:46 +13:00
if ($function->isEmpty()) {
throw new Exception('Function not found', 404);
}
2022-04-20 01:13:55 +12:00
$deployment = $dbForProject->getDocument('deployments', $deployment->getId());
if ($deployment->isEmpty()) {
throw new Exception('Deployment not found', 404);
2022-01-24 11:25:46 +13:00
}
2023-08-23 01:16:07 +12:00
if (empty($deployment->getAttribute('entrypoint', ''))) {
2023-08-23 20:16:52 +12:00
throw new Exception('Entrypoint for your Appwrite Function is missing. Please specify it when making deployment or update the entrypoint under your function\'s "Settings" > "Configuration" > "Entrypoint".', 500);
2023-08-23 01:16:07 +12:00
}
2023-09-05 05:53:25 +12:00
$version = $function->getAttribute('version', 'v2');
$runtimes = Config::getParam($version === 'v2' ? 'runtimes-v2' : 'runtimes', []);
2022-01-24 11:25:46 +13:00
$key = $function->getAttribute('runtime');
$runtime = isset($runtimes[$key]) ? $runtimes[$key] : null;
if (\is_null($runtime)) {
throw new Exception('Runtime "' . $function->getAttribute('runtime', '') . '" is not supported');
}
// Realtime preparation
$allEvents = Event::generateEvents('functions.[functionId].deployments.[deploymentId].update', [
'functionId' => $function->getId(),
'deploymentId' => $deployment->getId()
]);
2022-07-14 02:02:49 +12:00
$startTime = DateTime::now();
2023-03-29 02:21:42 +13:00
$durationStart = \microtime(true);
$buildId = $deployment->getAttribute('buildId', '');
$isNewBuild = empty($buildId);
2023-08-19 18:15:47 +12:00
if ($isNewBuild) {
2022-08-15 02:22:38 +12:00
$buildId = ID::unique();
$build = $dbForProject->createDocument('builds', new Document([
'$id' => $buildId,
'$permissions' => [],
'startTime' => $startTime,
'deploymentInternalId' => $deployment->getInternalId(),
'deploymentId' => $deployment->getId(),
'status' => 'processing',
'path' => '',
'runtime' => $function->getAttribute('runtime'),
'source' => $deployment->getAttribute('path', ''),
'sourceType' => strtolower(App::getEnv('_APP_STORAGE_DEVICE', Storage::DEVICE_LOCAL)),
2023-08-06 02:50:28 +12:00
'logs' => '',
'endTime' => null,
'duration' => 0,
'size' => 0
]));
$deployment->setAttribute('buildId', $build->getId());
$deployment->setAttribute('buildInternalId', $build->getInternalId());
$deployment = $dbForProject->updateDocument('deployments', $deployment->getId(), $deployment);
} else {
$build = $dbForProject->getDocument('builds', $buildId);
}
$source = $deployment->getAttribute('path', '');
$installationId = $deployment->getAttribute('installationId', '');
$providerRepositoryId = $deployment->getAttribute('providerRepositoryId', '');
2023-08-12 04:44:05 +12:00
$providerCommitHash = $deployment->getAttribute('providerCommitHash', '');
$isVcsEnabled = $providerRepositoryId ? true : false;
$owner = '';
$repositoryName = '';
2023-06-20 19:12:33 +12:00
2023-08-19 18:15:47 +12:00
if ($isVcsEnabled) {
$installation = $dbForConsole->getDocument('installations', $installationId);
$providerInstallationId = $installation->getAttribute('providerInstallationId');
$privateKey = App::getEnv('_APP_VCS_GITHUB_PRIVATE_KEY');
$githubAppId = App::getEnv('_APP_VCS_GITHUB_APP_ID');
2023-08-19 18:15:47 +12:00
$github->initializeVariables($providerInstallationId, $privateKey, $githubAppId);
}
2023-08-19 18:15:47 +12:00
try {
if ($isNewBuild && $isVcsEnabled) {
$tmpDirectory = '/tmp/builds/' . $buildId . '/code';
$rootDirectory = $function->getAttribute('providerRootDirectory', '');
$rootDirectory = \rtrim($rootDirectory, '/');
$rootDirectory = \ltrim($rootDirectory, '.');
$rootDirectory = \ltrim($rootDirectory, '/');
$owner = $github->getOwnerName($providerInstallationId);
$repositoryName = $github->getRepositoryName($providerRepositoryId);
$cloneOwner = $deployment->getAttribute('providerRepositoryOwner', $owner);
$cloneRepository = $deployment->getAttribute('providerRepositoryName', $repositoryName);
$branchName = $deployment->getAttribute('providerBranch');
2023-08-21 23:33:07 +12:00
$commitHash = $deployment->getAttribute('providerCommitHash', '');
$gitCloneCommand = $github->generateCloneCommand($cloneOwner, $cloneRepository, $branchName, $tmpDirectory, $rootDirectory, $commitHash);
2023-08-19 18:15:47 +12:00
$stdout = '';
$stderr = '';
2023-08-21 01:27:34 +12:00
Console::execute('mkdir -p /tmp/builds/' . \escapeshellcmd($buildId), '', $stdout, $stderr);
2023-08-19 18:15:47 +12:00
$exit = Console::execute($gitCloneCommand, '', $stdout, $stderr);
if ($exit !== 0) {
throw new \Exception('Unable to clone code repository: ' . $stderr);
}
2023-06-28 23:31:35 +12:00
2023-08-19 18:15:47 +12:00
// Build from template
$templateRepositoryName = $template->getAttribute('repositoryName', '');
$templateOwnerName = $template->getAttribute('ownerName', '');
$templateBranch = $template->getAttribute('branch', '');
2023-06-28 23:31:35 +12:00
2023-08-19 18:15:47 +12:00
$templateRootDirectory = $template->getAttribute('rootDirectory', '');
$templateRootDirectory = \rtrim($templateRootDirectory, '/');
$templateRootDirectory = \ltrim($templateRootDirectory, '.');
$templateRootDirectory = \ltrim($templateRootDirectory, '/');
2023-06-28 23:31:35 +12:00
2023-08-19 18:15:47 +12:00
if (!empty($templateRepositoryName) && !empty($templateOwnerName) && !empty($templateBranch)) {
// Clone template repo
2023-08-21 01:27:34 +12:00
$tmpTemplateDirectory = '/tmp/builds/' . \escapeshellcmd($buildId) . '/template';
2023-08-19 18:15:47 +12:00
$gitCloneCommandForTemplate = $github->generateCloneCommand($templateOwnerName, $templateRepositoryName, $templateBranch, $tmpTemplateDirectory, $templateRootDirectory);
$exit = Console::execute($gitCloneCommandForTemplate, '', $stdout, $stderr);
if ($exit !== 0) {
throw new \Exception('Unable to clone code repository: ' . $stderr);
}
2023-08-19 18:15:47 +12:00
// Ensure directories
Console::execute('mkdir -p ' . $tmpTemplateDirectory . '/' . $templateRootDirectory, '', $stdout, $stderr);
Console::execute('mkdir -p ' . $tmpDirectory . '/' . $rootDirectory, '', $stdout, $stderr);
2023-08-19 18:15:47 +12:00
// Merge template into user repo
Console::execute('cp -rfn ' . $tmpTemplateDirectory . '/' . $templateRootDirectory . '/* ' . $tmpDirectory . '/' . $rootDirectory, '', $stdout, $stderr);
2023-08-19 18:15:47 +12:00
// Commit and push
2023-08-22 19:13:00 +12:00
$exit = Console::execute('git config --global user.email "team@appwrite.io" && git config --global user.name "Appwrite" && cd ' . $tmpDirectory . ' && git add . && git commit -m "Create \'' . \escapeshellcmd($function->getAttribute('name', '')) . '\' function" && git push origin ' . \escapeshellcmd($branchName), '', $stdout, $stderr);
2023-08-19 18:15:47 +12:00
if ($exit !== 0) {
throw new \Exception('Unable to push code repository: ' . $stderr);
}
2023-08-19 18:15:47 +12:00
$exit = Console::execute('cd ' . $tmpDirectory . ' && git rev-parse HEAD', '', $stdout, $stderr);
2023-08-19 18:15:47 +12:00
if ($exit !== 0) {
throw new \Exception('Unable to get vcs commit SHA: ' . $stderr);
}
2023-08-19 18:15:47 +12:00
$providerCommitHash = \trim($stdout);
$authorUrl = "https://github.com/$cloneOwner";
$deployment->setAttribute('providerCommitHash', $providerCommitHash ?? '');
$deployment->setAttribute('providerCommitAuthorUrl', $authorUrl);
$deployment->setAttribute('providerCommitAuthor', 'Appwrite');
$deployment->setAttribute('providerCommitMessage', "Create '" . $function->getAttribute('name', '') . "' function");
$deployment->setAttribute('providerCommitUrl', "https://github.com/$cloneOwner/$cloneRepository/commit/$providerCommitHash");
$deployment = $dbForProject->updateDocument('deployments', $deployment->getId(), $deployment);
/**
* Send realtime Event
*/
$target = Realtime::fromPayload(
// Pass first, most verbose event pattern
event: $allEvents[0],
payload: $build,
project: $project
);
Realtime::send(
projectId: 'console',
payload: $build->getArrayCopy(),
events: $allEvents,
channels: $target['channels'],
roles: $target['roles']
);
}
2023-08-21 01:27:34 +12:00
Console::execute('tar --exclude code.tar.gz -czf /tmp/builds/' . \escapeshellcmd($buildId) . '/code.tar.gz -C /tmp/builds/' . \escapeshellcmd($buildId) . '/code' . (empty($rootDirectory) ? '' : '/' . $rootDirectory) . ' .', '', $stdout, $stderr);
2023-08-19 18:15:47 +12:00
$deviceFunctions = $this->getFunctionsDevice($project->getId());
2023-08-19 18:15:47 +12:00
$fileName = 'code.tar.gz';
$fileTmpName = '/tmp/builds/' . $buildId . '/code.tar.gz';
2023-08-19 18:15:47 +12:00
$path = $deviceFunctions->getPath($deployment->getId() . '.' . \pathinfo($fileName, PATHINFO_EXTENSION));
2023-08-19 18:15:47 +12:00
$result = $deviceFunctions->move($fileTmpName, $path);
2023-08-19 18:15:47 +12:00
if (!$result) {
throw new \Exception("Unable to move file");
}
2023-08-21 01:27:34 +12:00
Console::execute('rm -rf /tmp/builds/' . \escapeshellcmd($buildId), '', $stdout, $stderr);
2023-08-19 18:15:47 +12:00
$source = $path;
2023-08-19 18:15:47 +12:00
$build = $dbForProject->updateDocument('builds', $build->getId(), $build->setAttribute('source', $source));
$this->runGitAction('processing', $github, $providerCommitHash, $owner, $repositoryName, $project, $function, $deployment->getId(), $dbForProject, $dbForConsole);
}
/** Request the executor to build the code... */
$build->setAttribute('status', 'building');
$build = $dbForProject->updateDocument('builds', $buildId, $build);
if ($isVcsEnabled) {
2023-08-12 04:44:05 +12:00
$this->runGitAction('building', $github, $providerCommitHash, $owner, $repositoryName, $project, $function, $deployment->getId(), $dbForProject, $dbForConsole);
}
/** Trigger Webhook */
$deploymentModel = new Deployment();
$deploymentUpdate = new Event(Event::WEBHOOK_QUEUE_NAME, Event::WEBHOOK_CLASS_NAME);
$deploymentUpdate
->setProject($project)
->setEvent('functions.[functionId].deployments.[deploymentId].update')
->setParam('functionId', $function->getId())
->setParam('deploymentId', $deployment->getId())
->setPayload($deployment->getArrayCopy(array_keys($deploymentModel->getRules())))
->trigger();
2022-09-16 21:54:59 +12:00
/** Trigger Functions */
$pools = $register->get('pools');
$connection = $pools->get('queue')->pop();
2022-04-19 04:21:45 +12:00
$functions = new Func($connection->getResource());
$functions
->from($deploymentUpdate)
->trigger();
2022-11-17 06:55:26 +13:00
$connection->reclaim();
2022-04-19 04:21:45 +12:00
/** Trigger Realtime */
$target = Realtime::fromPayload(
// Pass first, most verbose event pattern
event: $allEvents[0],
payload: $build,
project: $project
);
2022-04-19 04:21:45 +12:00
Realtime::send(
projectId: 'console',
payload: $build->getArrayCopy(),
events: $allEvents,
channels: $target['channels'],
roles: $target['roles']
);
$vars = [];
2023-09-05 20:21:36 +12:00
// Shared vars
foreach ($function->getAttribute('varsProject', []) as $var) {
$vars[$var->getAttribute('key')] = $var->getAttribute('value', '');
2023-08-18 18:55:44 +12:00
}
// Function vars
2023-09-05 20:21:36 +12:00
foreach ($function->getAttribute('vars', []) as $var) {
$vars[$var->getAttribute('key')] = $var->getAttribute('value', '');
}
// Appwrite vars
$vars = \array_merge($vars, [
'APPWRITE_FUNCTION_ID' => $function->getId(),
'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name'),
'APPWRITE_FUNCTION_DEPLOYMENT' => $deployment->getId(),
'APPWRITE_FUNCTION_PROJECT_ID' => $project->getId(),
'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime['name'] ?? '',
'APPWRITE_FUNCTION_RUNTIME_VERSION' => $runtime['version'] ?? '',
]);
2022-08-10 21:32:48 +12:00
$command = $deployment->getAttribute('commands', '');
2023-03-29 02:21:42 +13:00
$command = \str_replace('"', '\\"', $command);
2023-06-13 18:26:36 +12:00
$response = null;
$err = null;
2023-06-17 22:07:30 +12:00
// TODO: Remove run() wrapper when switching to new utopia queue. That should be done on Swoole adapter in the libary
Co\run(function () use ($project, $deployment, &$response, $source, $function, $runtime, $vars, $command, &$build, $dbForProject, $allEvents, &$err) {
2023-06-13 18:26:36 +12:00
Co::join([
Co\go(function () use (&$response, $project, $deployment, $source, $function, $runtime, $vars, $command, &$err) {
try {
2023-09-05 05:53:25 +12:00
$version = $function->getAttribute('version', 'v2');
$command = $version === 'v2' ? 'tar -zxf /tmp/code.tar.gz -C /usr/code && cd /usr/local/src/ && ./build.sh' : 'tar -zxf /tmp/code.tar.gz -C /mnt/code && helpers/build.sh "' . $command . '"';
$response = $this->executor->createRuntime(
deploymentId: $deployment->getId(),
2023-08-19 18:15:47 +12:00
projectId: $project->getId(),
source: $source,
image: $runtime['image'],
2023-09-05 05:53:25 +12:00
version: $version,
remove: true,
entrypoint: $deployment->getAttribute('entrypoint'),
destination: APP_STORAGE_BUILDS . "/app-{$project->getId()}",
variables: $vars,
2023-09-05 05:53:25 +12:00
command: $command
);
} catch (Exception $error) {
$err = $error;
}
}),
Co\go(function () use ($project, $deployment, &$response, &$build, $dbForProject, $allEvents, &$err) {
try {
$this->executor->getLogs(
deploymentId: $deployment->getId(),
2023-08-19 18:15:47 +12:00
projectId: $project->getId(),
callback: function ($logs) use (&$response, &$build, $dbForProject, $allEvents, $project) {
if ($response === null) {
$build = $dbForProject->getDocument('builds', $build->getId());
if ($build->isEmpty()) {
throw new Exception('Build not found', 404);
}
2023-08-06 02:50:28 +12:00
$build = $build->setAttribute('logs', $build->getAttribute('logs', '') . $logs);
$build = $dbForProject->updateDocument('builds', $build->getId(), $build);
/**
* Send realtime Event
*/
$target = Realtime::fromPayload(
// Pass first, most verbose event pattern
event: $allEvents[0],
payload: $build,
project: $project
);
Realtime::send(
projectId: 'console',
payload: $build->getArrayCopy(),
events: $allEvents,
channels: $target['channels'],
roles: $target['roles']
);
}
2023-06-13 18:26:36 +12:00
}
);
} catch (Exception $error) {
if (empty($err)) {
$err = $error;
2023-06-13 18:26:36 +12:00
}
}
2023-06-13 23:13:02 +12:00
}),
2023-06-13 18:26:36 +12:00
]);
});
if ($err) {
throw $err;
}
2023-03-15 21:20:25 +13:00
$endTime = DateTime::now();
$durationEnd = \microtime(true);
2022-12-21 01:56:56 +13:00
2022-02-14 10:26:36 +13:00
/** Update the build document */
2022-12-18 20:35:16 +13:00
$build->setAttribute('startTime', DateTime::format((new \DateTime())->setTimestamp($response['startTime'])));
2023-03-15 21:20:25 +13:00
$build->setAttribute('endTime', $endTime);
$build->setAttribute('duration', \intval(\ceil($durationEnd - $durationStart)));
2023-02-03 08:21:00 +13:00
$build->setAttribute('status', 'ready');
2023-03-15 21:20:25 +13:00
$build->setAttribute('path', $response['path']);
2022-12-18 20:20:50 +13:00
$build->setAttribute('size', $response['size']);
2023-08-06 02:50:28 +12:00
$build->setAttribute('logs', $response['output']);
2022-02-17 00:43:21 +13:00
if ($isVcsEnabled) {
2023-08-12 04:44:05 +12:00
$this->runGitAction('ready', $github, $providerCommitHash, $owner, $repositoryName, $project, $function, $deployment->getId(), $dbForProject, $dbForConsole);
}
2022-02-17 00:43:21 +13:00
Console::success("Build id: $buildId created");
/** Set auto deploy */
if ($deployment->getAttribute('activate') === true) {
2022-12-26 01:07:54 +13:00
$function->setAttribute('deploymentInternalId', $deployment->getInternalId());
2022-02-17 00:43:21 +13:00
$function->setAttribute('deployment', $deployment->getId());
$function->setAttribute('live', true);
2022-08-19 22:26:09 +12:00
$function = $dbForProject->updateDocument('functions', $function->getId(), $function);
2022-02-17 00:43:21 +13:00
}
/** Update function schedule */
2022-11-17 01:19:29 +13:00
$dbForConsole = $this->getConsoleDB();
2023-07-28 19:56:07 +12:00
// Inform scheduler if function is still active
2023-08-20 01:00:22 +12:00
$schedule = $dbForConsole->getDocument('schedules', $function->getAttribute('scheduleId'));
$schedule
->setAttribute('resourceUpdatedAt', DateTime::now())
->setAttribute('schedule', $function->getAttribute('schedule'))
->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment')));
Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule));
2022-02-14 10:26:36 +13:00
} catch (\Throwable $th) {
2022-09-03 02:19:36 +12:00
$endTime = DateTime::now();
2023-03-29 02:21:42 +13:00
$durationEnd = \microtime(true);
2022-12-21 01:56:56 +13:00
$build->setAttribute('endTime', $endTime);
2023-03-29 02:21:42 +13:00
$build->setAttribute('duration', \intval(\ceil($durationEnd - $durationStart)));
2022-02-14 10:26:36 +13:00
$build->setAttribute('status', 'failed');
2023-08-06 02:50:28 +12:00
$build->setAttribute('logs', $th->getMessage());
Console::error($th->getMessage());
2023-08-19 18:15:47 +12:00
Console::error($th->getFile() . ':' . $th->getLine());
Console::error($th->getTraceAsString());
2023-05-23 16:37:25 +12:00
if ($isVcsEnabled) {
2023-08-12 04:44:05 +12:00
$this->runGitAction('failed', $github, $providerCommitHash, $owner, $repositoryName, $project, $function, $deployment->getId(), $dbForProject, $dbForConsole);
2023-05-23 16:37:25 +12:00
}
2022-02-17 00:43:21 +13:00
} finally {
$build = $dbForProject->updateDocument('builds', $buildId, $build);
2022-03-01 00:50:27 +13:00
2022-05-24 02:54:50 +12:00
/**
* Send realtime Event
2022-03-01 00:50:27 +13:00
*/
2022-05-10 00:36:29 +12:00
$target = Realtime::fromPayload(
2023-08-21 00:29:43 +12:00
// Pass first, most verbose event pattern
2022-05-10 00:36:29 +12:00
event: $allEvents[0],
payload: $build,
project: $project
);
2022-03-01 00:50:27 +13:00
Realtime::send(
projectId: 'console',
payload: $build->getArrayCopy(),
2022-04-19 04:21:45 +12:00
events: $allEvents,
2022-03-01 00:50:27 +13:00
channels: $target['channels'],
roles: $target['roles']
);
2022-12-13 20:35:05 +13:00
2023-08-21 00:29:43 +12:00
/** Update usage stats */
if (App::getEnv('_APP_USAGE_STATS', 'enabled') === 'enabled') {
$statsd = $register->get('statsd');
$usage = new Stats($statsd);
$usage
->setParam('projectInternalId', $project->getInternalId())
->setParam('projectId', $project->getId())
->setParam('functionId', $function->getId())
->setParam('builds.{scope}.compute', 1)
->setParam('buildStatus', $build->getAttribute('status', ''))
->setParam('buildTime', $build->getAttribute('duration'))
->setParam('networkRequestSize', 0)
->setParam('networkResponseSize', 0)
->submit();
}
}
2022-01-24 11:25:46 +13:00
}
2023-08-19 18:15:47 +12:00
protected function runGitAction(string $status, GitHub $github, string $providerCommitHash, string $owner, string $repositoryName, Document $project, Document $function, string $deploymentId, Database $dbForProject, Database $dbForConsole): void
{
if ($function->getAttribute('providerSilentMode', false) === true) {
return;
}
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
$commentId = $deployment->getAttribute('providerCommentId', '');
if (!empty($providerCommitHash)) {
$message = match ($status) {
'ready' => 'Build succeeded.',
'failed' => 'Build failed.',
'processing' => 'Building...',
default => $status
};
$state = match ($status) {
'ready' => 'success',
'failed' => 'failure',
'processing' => 'pending',
default => $status
};
$functionName = $function->getAttribute('name');
$projectName = $project->getAttribute('name');
$name = "{$functionName} ({$projectName})";
2023-08-12 04:44:05 +12:00
$protocol = App::getEnv('_APP_OPTIONS_FORCE_HTTPS') == 'disabled' ? 'http' : 'https';
$hostname = App::getEnv('_APP_DOMAIN');
$functionId = $function->getId();
$projectId = $project->getId();
$providerTargetUrl = $protocol . '://' . $hostname . "/console/project-$projectId/functions/function-$functionId";
$github->updateCommitStatus($repositoryName, $providerCommitHash, $owner, $state, $message, $providerTargetUrl, $name);
}
2023-06-13 18:26:36 +12:00
if (!empty($commentId)) {
$retries = 0;
2023-08-19 18:15:47 +12:00
while (true) {
$retries++;
try {
$dbForConsole->createDocument('vcsCommentLocks', new Document([
'$id' => $commentId
]));
break;
} catch (Exception $err) {
if ($retries >= 9) {
throw $err;
}
2023-08-19 18:15:47 +12:00
\sleep(1);
}
}
2023-08-19 18:15:47 +12:00
// Wrap in try/finally to ensure lock file gets deleted
2023-06-28 23:31:35 +12:00
try {
$comment = new Comment();
$comment->parseComment($github->getComment($owner, $repositoryName, $commentId));
2023-08-10 12:31:49 +12:00
$comment->addBuild($project, $function, $status, $deployment->getId(), ['type' => 'logs']);
2023-06-28 23:31:35 +12:00
$github->updateComment($owner, $repositoryName, $commentId, $comment->generateComment());
} finally {
$dbForConsole->deleteDocument('vcsCommentLocks', $commentId);
}
2023-06-13 18:26:36 +12:00
}
}
2022-04-20 01:13:55 +12:00
public function shutdown(): void
{
}
2022-01-24 11:25:46 +13:00
}