Add state to comment, webhook bug fixing

This commit is contained in:
Matej Bačo
2023-05-28 13:39:48 +02:00
parent bf5855d101
commit fb02e12db2
6 changed files with 178 additions and 41 deletions
+1 -1
View File
@@ -1091,7 +1091,7 @@ App::get('/v1/functions/:functionId/deployments/:deploymentId')
}
$build = $dbForProject->getDocument('builds', $deployment->getAttribute('buildId', ''));
$deployment->setAttribute('status', $build->getAttribute('status', 'processing'));
$deployment->setAttribute('status', $build->getAttribute('status', 'waiting'));
$deployment->setAttribute('buildStderr', $build->getAttribute('stderr', ''));
$deployment->setAttribute('buildStdout', $build->getAttribute('stdout', ''));
+59 -27
View File
@@ -12,6 +12,7 @@ use Utopia\VCS\Adapter\Git\GitHub;
use Appwrite\Extend\Exception;
use Appwrite\Network\Validator\Host;
use Appwrite\Utopia\Database\Validator\Queries\Installations;
use Appwrite\Vcs\Comment;
use Utopia\Database\Query;
use Utopia\Database\ID;
use Utopia\Database\Permission;
@@ -30,7 +31,7 @@ App::get('/v1/vcs/github/installations')
->label('sdk.response.code', Response::STATUS_CODE_MOVED_PERMANENTLY)
->label('sdk.response.type', Response::CONTENT_TYPE_HTML)
->label('sdk.methodType', 'webAuth')
->param('redirect', '', fn($clients) => new Host($clients), 'URL to redirect back to your Git authorization. Only console hostnames are allowed.', true, ['clients'])
->param('redirect', '', fn ($clients) => new Host($clients), 'URL to redirect back to your Git authorization. Only console hostnames are allowed.', true, ['clients'])
->inject('response')
->inject('project')
->action(function (string $redirect, Response $response, Document $project) {
@@ -225,24 +226,22 @@ App::get('v1/vcs/github/installations/:installationId/repositories/:repositoryId
$response->dynamic(new Document([
'branches' => \array_map(function ($branch) {
return [ 'name' => $branch ];
return ['name' => $branch];
}, $branches),
'total' => \count($branches),
]), Response::MODEL_BRANCH_LIST);
});
$createGitDeployments = function (array $vcsRepos, string $branchName, string $SHA, Database $dbForConsole, callable $getProjectDB, Request $request) {
$createGitDeployments = function (array $vcsRepos, string $branchName, string $SHA, string $commentId, Database $dbForConsole, callable $getProjectDB, Request $request) {
foreach ($vcsRepos as $resource) {
$resourceType = $resource->getAttribute('resourceType');
if ($resourceType === "function") {
$projectId = $resource->getAttribute('projectId');
//TODO: Why is Authorization::skip needed?
$project = Authorization::skip(fn () => $dbForConsole->getDocument('projects', $projectId));
$dbForProject = $getProjectDB($project);
$functionId = $resource->getAttribute('resourceId');
//TODO: Why is Authorization::skip needed?
$function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId));
$deploymentId = ID::unique();
$vcsRepoId = $resource->getId();
@@ -256,6 +255,18 @@ $createGitDeployments = function (array $vcsRepos, string $branchName, string $S
$activate = true;
}
if (empty($commentId)) {
$latestDeployment = Authorization::skip(fn () => $dbForProject->findOne('deployments', [
Query::equal('vcsRepositoryId', [$vcsRepoId]),
Query::equal('branch', [$branchName]),
Query::equal('resourceType', ['functions']),
Query::orderDesc('$createdAt'),
]));
if ($latestDeployment !== false && !$latestDeployment->isEmpty()) {
$commentId = $latestDeployment->getAttribute('vcsCommentId', '');
}
}
$deployment = $dbForProject->createDocument('deployments', new Document([
'$id' => $deploymentId,
'$permissions' => [
@@ -273,6 +284,7 @@ $createGitDeployments = function (array $vcsRepos, string $branchName, string $S
'vcsInstallationInternalId' => $vcsInstallationInternalId,
'vcsRepositoryId' => $vcsRepoId,
'vcsRepositoryInternalId' => $vcsRepoInternalId,
'vcsCommentId' => $commentId,
'branch' => $branchName,
'search' => implode(' ', [$deploymentId, $function->getAttribute('entrypoint')]),
'activate' => $activate,
@@ -326,7 +338,7 @@ App::post('/v1/vcs/github/incomingwebhook')
Query::limit(100),
]);
$createGitDeployments($vcsRepos, $branchName, $SHA, $dbForConsole, $getProjectDB, $request);
$createGitDeployments($vcsRepos, $branchName, $SHA, '', $dbForConsole, $getProjectDB, $request);
} elseif ($event == $github::EVENT_INSTALLATION) {
if ($parsedPayload["action"] == "deleted") {
// TODO: Use worker for this job instead (update function as well)
@@ -365,30 +377,50 @@ App::post('/v1/vcs/github/incomingwebhook')
Query::orderDesc('$createdAt')
]);
if (\count($vcsRepos) === 0) {
$createGitDeployments($vcsRepos, $branchName, '', $dbForConsole, $getProjectDB, $request);
}
if (\count($vcsRepos) !== 0) {
$comment = new Comment();
// TODO: Use for loop instead
$vcsRepo = $vcsRepos[0];
foreach ($vcsRepos as $vcsRepo) {
$projectId = $vcsRepo->getAttribute('projectId');
$project = Authorization::skip(fn () => $dbForConsole->getDocument('projects', $projectId));
$dbForProject = $getProjectDB($project);
$projectId = $vcsRepo->getAttribute('projectId');
//TODO: Why is Authorization::skip needed?
$project = Authorization::skip(fn () => $dbForConsole->getDocument('projects', $projectId));
$dbForProject = $getProjectDB($project);
$vcsRepoId = $vcsRepo->getId();
$deployment = Authorization::skip(fn () => $dbForProject->findOne('deployments', [
Query::equal('vcsRepositoryId', [$vcsRepoId]),
Query::equal('branch', [$branchName]),
Query::orderDesc('$createdAt'),
]));
$vcsRepoId = $vcsRepo->getId();
if ($deployment !== false && !$deployment->isEmpty()) {
$buildId = $deployment->getAttribute('buildId');
$build = Authorization::skip(fn () => $dbForProject->getDocument('builds', $buildId));
$buildStatus = $build->getAttribute('status');
$comment = "| Build Status |\r\n | --------------- |\r\n | $buildStatus |";
$github->addComment($owner, $repositoryName, $pullRequestNumber, $comment);
$deployment = Authorization::skip(fn () => $dbForProject->findOne('deployments', [
Query::equal('vcsRepositoryId', [$vcsRepoId]),
Query::equal('branch', [$branchName]),
Query::equal('resourceType', ['functions']),
Query::orderDesc('$createdAt'),
]));
if (!$deployment || $deployment->isEmpty()) {
$function = Authorization::skip(fn () => $dbForProject->findOne('functions', [
Query::equal('vcsRepositoryId', [$vcsRepoId]),
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 = '';
if (!$comment->isEmpty()) {
$commentId = $github->createComment($owner, $repositoryName, $pullRequestNumber, $comment->generateComment());
}
$createGitDeployments($vcsRepos, $branchName, '', $commentId, $dbForConsole, $getProjectDB, $request);
}
}
}
+17 -10
View File
@@ -7,6 +7,7 @@ use Appwrite\Resque\Worker;
use Appwrite\Utopia\Response\Model\Deployment;
use Executor\Executor;
use Appwrite\Usage\Stats;
use Appwrite\Vcs\Comment;
use Utopia\Database\DateTime;
use Utopia\App;
use Utopia\CLI\Console;
@@ -163,9 +164,10 @@ class BuildsV1 extends Worker
}
$commentId = $deployment->getAttribute('vcsCommentId');
if ($commentId) {
$comment = "| Build Status |\r\n | --------------- |\r\n | Processing |";
$github->updateComment($owner, $repositoryName, $commentId, $comment);
$comment = new Comment();
$comment->parseComment($github->getComment($owner, $repositoryName, $commentId));
$comment->addBuild($project, $function, 'processing', $deployment->getId());
$github->updateComment($owner, $repositoryName, $commentId, $comment->generateComment());
}
} else {
$build = $dbForProject->createDocument('builds', new Document([
@@ -201,8 +203,10 @@ class BuildsV1 extends Worker
if ($isVcsEnabled) {
$commentId = $deployment->getAttribute('vcsCommentId');
if ($commentId) {
$comment = "| Build Status |\r\n | --------------- |\r\n | Building |";
$github->updateComment($owner, $repositoryName, $commentId, $comment);
$comment = new Comment();
$comment->parseComment($github->getComment($owner, $repositoryName, $commentId));
$comment->addBuild($project, $function, 'building', $deployment->getId());
$github->updateComment($owner, $repositoryName, $commentId, $comment->generateComment());
}
}
@@ -303,15 +307,16 @@ class BuildsV1 extends Worker
$build->setAttribute('stdout', $response['stdout']);
if ($isVcsEnabled) {
$status = 'ready';
if ($SHA !== "" && $owner !== "") {
$github->updateCommitStatus($repositoryName, $SHA, $owner, "success", "Deployment is successful!", $targetUrl, "Appwrite Deployment");
}
$commentId = $deployment->getAttribute('vcsCommentId');
if ($commentId) {
$comment = "| Build Status |\r\n | --------------- |\r\n | $status |";
$github->updateComment($owner, $repositoryName, $commentId, $comment);
$comment = new Comment();
$comment->parseComment($github->getComment($owner, $repositoryName, $commentId));
$comment->addBuild($project, $function, 'ready', $deployment->getId());
$github->updateComment($owner, $repositoryName, $commentId, $comment->generateComment());
}
}
@@ -355,8 +360,10 @@ class BuildsV1 extends Worker
$commentId = $deployment->getAttribute('vcsCommentId');
if ($commentId) {
$comment = "| Build Status |\r\n | --------------- |\r\n | $status |";
$github->updateComment($owner, $repositoryName, $commentId, $comment);
$comment = new Comment();
$comment->parseComment($github->getComment($owner, $repositoryName, $commentId));
$comment->addBuild($project, $function, 'failed', $deployment->getId());
$github->updateComment($owner, $repositoryName, $commentId, $comment->generateComment());
}
}
} finally {
Generated
+2 -2
View File
@@ -3090,7 +3090,7 @@
"source": {
"type": "git",
"url": "https://github.com/utopia-php/vcs.git",
"reference": "1331193f6ba0443a87f4fd665a8f91dc07817370"
"reference": "9215381b4fde95e26ab1f01d5add6d2d428d6fd7"
},
"require": {
"adhocore/jwt": "^1.1",
@@ -3135,7 +3135,7 @@
"utopia",
"vcs"
],
"time": "2023-05-26T08:41:54+00:00"
"time": "2023-05-28T10:14:37+00:00"
},
{
"name": "utopia-php/websocket",
@@ -66,7 +66,7 @@ class Deployment extends Model
])
->addRule('status', [
'type' => self::TYPE_STRING,
'description' => 'The deployment status. Possible values are "processing", "building", "pending", "ready", and "failed".',
'description' => 'The deployment status. Possible values are "processing", "building", "waiting", "ready", and "failed".',
'default' => '',
'example' => 'ready',
])
+98
View File
@@ -0,0 +1,98 @@
<?php
namespace Appwrite\Vcs;
use Utopia\Database\Document;
class Comment
{
protected string $statePrefix = '[appwrite]: #';
/**
* @var mixed[] $builds
*/
protected array $builds = [];
public function isEmpty(): bool
{
return \count($this->builds) === 0;
}
public function addBuild(Document $project, Document $function, string $buildStatus, string $deploymentId): void
{
// Unique index
$id = $project->getId() . '_' . $function->getId();
$this->builds[$id] = [
'projectName' => $project->getAttribute('name'),
'projectId' => $project->getId(),
'functionName' => $function->getAttribute('name'),
'functionId' => $function->getId(),
'buildStatus' => $buildStatus,
'deploymentId' => $deploymentId
];
}
public function generateComment(): string
{
$json = \json_encode($this->builds);
$text = $this->statePrefix . \base64_encode($json) . "\n\n";
$projects = [];
foreach ($this->builds as $id => $build) {
if (!\array_key_exists($build['projectId'], $projects)) {
$projects[$build['projectId']] = [
'name' => $build['projectName'],
'functions' => []
];
}
$projects[$build['projectId']]['functions'][$build['functionId']] = [
'name' => $build['functionName'],
'status' => $build['buildStatus'],
'deploymentId' => $build['deploymentId']
];
}
$text .= "> Bored? Read random [Wikipedia Page](https://en.wikipedia.org/wiki/Special:Random).\n\n";
foreach ($projects as $projectId => $project) {
$text .= "### {$project['name']} `{$projectId}`\n\n";
$text .= "| Function | Status | Execute |\n";
$text .= "| :- | :- | :- |\n";
foreach ($project['functions'] as $functionId => $function) {
$status = match ($function['status']) {
'waiting' => '⌛ Waiting',
'processing' => '🤔 Processing',
'building' => '🛠️ Building',
'ready' => '✅ Ready',
'failed' => '❌ Failed',
};
$execute = $function['status'] === 'ready' ? "[HTTP](#) \\| [Console](#)" : '_Build must be ready first_';
$text .= "| **{$function['name']}** `{$functionId}` | {$status} ([Logs](#)) | {$execute} |\n";
}
$text .= "\n";
}
return $text;
}
public function parseComment(string $comment): self
{
$state = \explode("\n", $comment)[0] ?? '';
$state = substr($state, strlen($this->statePrefix));
$json = \base64_decode($state);
$builds = \json_decode($json, true);
$this->builds = $builds;
return $this;
}
}