mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
feat: implement custom triggers for VCS builds
This commit is contained in:
@@ -841,6 +841,28 @@ return [
|
||||
'array' => true,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('providerBranches'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 128,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => [],
|
||||
'array' => true,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('providerPaths'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 128,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => [],
|
||||
'array' => true,
|
||||
'filters' => [],
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
@@ -1320,6 +1342,28 @@ return [
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('providerBranches'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 128,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => [],
|
||||
'array' => true,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('providerPaths'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 128,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => [],
|
||||
'array' => true,
|
||||
'filters' => [],
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
|
||||
+1
-1
@@ -84,7 +84,7 @@
|
||||
"utopia-php/storage": "1.0.*",
|
||||
"utopia-php/system": "0.10.*",
|
||||
"utopia-php/telemetry": "0.2.*",
|
||||
"utopia-php/vcs": "3.*",
|
||||
"utopia-php/vcs": "dev-ser-401 as 3.0.99",
|
||||
"utopia-php/websocket": "1.0.*",
|
||||
"matomo/device-detector": "6.4.*",
|
||||
"dragonmantank/cron-expression": "3.4.*",
|
||||
|
||||
Generated
+19
-10
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "f9225f2b580de0ccb796b2fb8c881384",
|
||||
"content-hash": "695d5fa15d0688d195c3848af81bb0bf",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
@@ -5216,16 +5216,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/vcs",
|
||||
"version": "3.0.1",
|
||||
"version": "dev-ser-401",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/vcs.git",
|
||||
"reference": "0efe842d695acb4b184f5306a836169c771fbcea"
|
||||
"reference": "b37bf9c465db41b25bd741783ae36bf6b898fbdb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/0efe842d695acb4b184f5306a836169c771fbcea",
|
||||
"reference": "0efe842d695acb4b184f5306a836169c771fbcea",
|
||||
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/b37bf9c465db41b25bd741783ae36bf6b898fbdb",
|
||||
"reference": "b37bf9c465db41b25bd741783ae36bf6b898fbdb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5259,9 +5259,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/vcs/issues",
|
||||
"source": "https://github.com/utopia-php/vcs/tree/3.0.1"
|
||||
"source": "https://github.com/utopia-php/vcs/tree/ser-401"
|
||||
},
|
||||
"time": "2026-03-23T15:58:31+00:00"
|
||||
"time": "2026-03-24T03:31:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/websocket",
|
||||
@@ -8433,9 +8433,18 @@
|
||||
"time": "2024-11-07T12:36:22+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
"aliases": [
|
||||
{
|
||||
"package": "utopia-php/vcs",
|
||||
"version": "dev-ser-401",
|
||||
"alias": "3.0.99",
|
||||
"alias_normalized": "3.0.99.0"
|
||||
}
|
||||
],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": {},
|
||||
"stability-flags": {
|
||||
"utopia-php/vcs": 20
|
||||
},
|
||||
"prefer-stable": true,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
@@ -8456,5 +8465,5 @@
|
||||
"platform-dev": {
|
||||
"ext-fileinfo": "*"
|
||||
},
|
||||
"plugin-api-version": "2.9.0"
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
||||
|
||||
+4
-1
@@ -133,7 +133,10 @@ class Update extends Action
|
||||
$providerCommitAuthor = $commitDetails["commitAuthor"] ?? '';
|
||||
$providerCommitAuthorUrl = $commitDetails["commitAuthorUrl"] ?? '';
|
||||
|
||||
$this->createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthor, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, $providerPullRequestId, true, $dbForPlatform, $authorization, $queueForBuilds, $getProjectDB, $platform);
|
||||
$prFiles = $github->getPullRequestFiles($owner, $providerRepositoryName, $providerPullRequestId);
|
||||
$providerAffectedFiles = array_column($prFiles, 'filename');
|
||||
|
||||
$this->createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthor, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, $providerPullRequestId, $providerAffectedFiles, true, $dbForPlatform, $authorization, $queueForBuilds, $getProjectDB, $platform);
|
||||
|
||||
$response->noContent();
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ trait Deployment
|
||||
string $providerCommitMessage,
|
||||
string $providerCommitUrl,
|
||||
string $providerPullRequestId,
|
||||
array $providerAffectedFiles = [],
|
||||
bool $external,
|
||||
Database $dbForPlatform,
|
||||
Authorization $authorization,
|
||||
@@ -90,6 +91,11 @@ trait Deployment
|
||||
$resource = $authorization->skip(fn () => $dbForProject->getDocument($resourceCollection, $resourceId));
|
||||
$resourceInternalId = $resource->getSequence();
|
||||
|
||||
if (!$this->isResourceBuildable($resource, $providerBranch, $providerAffectedFiles, $logBase)) {
|
||||
Span::add("{$logBase}.build.skipped", 'true');
|
||||
continue;
|
||||
}
|
||||
|
||||
$deploymentId = ID::unique();
|
||||
$repositoryId = $repository->getId();
|
||||
$repositoryInternalId = $repository->getSequence();
|
||||
@@ -525,4 +531,72 @@ trait Deployment
|
||||
{
|
||||
return System::getEnv('_APP_BUILDS_QUEUE_NAME', Event::BUILDS_QUEUE_NAME);
|
||||
}
|
||||
|
||||
private function isResourceBuildable(Document $resource, string $providerBranch, array $providerAffectedFiles, string $logBase): bool
|
||||
{
|
||||
$allowedBranches = $resource->getAttribute('providerBranches', []);
|
||||
if (!$this->matchesPatterns($providerBranch, $allowedBranches)) {
|
||||
Span::add("{$logBase}.build.skipped.reason", 'branch');
|
||||
return false;
|
||||
}
|
||||
|
||||
$allowedPaths = $resource->getAttribute('providerPaths', []);
|
||||
if (!empty($allowedPaths) && !empty($providerAffectedFiles)) {
|
||||
$pathMatched = false;
|
||||
foreach ($providerAffectedFiles as $file) {
|
||||
if ($this->matchesPatterns($file, $allowedPaths)) {
|
||||
$pathMatched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$pathMatched) {
|
||||
Span::add("{$logBase}.build.skipped.reason", 'path');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function matchesPatterns(string $subject, array $patterns): bool
|
||||
{
|
||||
if (empty($patterns)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$include = array_filter($patterns, fn ($p) => !str_starts_with($p, '!'));
|
||||
$exclude = array_filter($patterns, fn ($p) => str_starts_with($p, '!'));
|
||||
|
||||
foreach ($include as $pattern) {
|
||||
if ($this->matchGlob($subject, $pattern)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($exclude as $pattern) {
|
||||
if ($this->matchGlob($subject, substr($pattern, 1))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return empty($include);
|
||||
}
|
||||
|
||||
private function matchGlob(string $subject, string $pattern): bool
|
||||
{
|
||||
$regex = preg_replace_callback(
|
||||
'/\*\*|\*|\?|[^*?]+/',
|
||||
static function (array $m): string {
|
||||
return match ($m[0]) {
|
||||
'**' => '.*',
|
||||
'*' => '[^/]*',
|
||||
'?' => '[^/]',
|
||||
default => preg_quote($m[0], '/'),
|
||||
};
|
||||
},
|
||||
$pattern
|
||||
);
|
||||
|
||||
return (bool) preg_match('/^' . $regex . '$/', $subject);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,7 +164,8 @@ class Create extends Action
|
||||
|
||||
// Create new deployment only on push (not committed by us) and not when branch is created or deleted
|
||||
if ($providerCommitAuthorEmail !== APP_VCS_GITHUB_EMAIL && !$providerBranchCreated && !$providerBranchDeleted) {
|
||||
$this->createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthorName, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, '', false, $dbForPlatform, $authorization, $queueForBuilds, $getProjectDB, $platform);
|
||||
$providerAffectedFiles = $parsedPayload['affectedFiles'] ?? [];
|
||||
$this->createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthorName, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, '', $providerAffectedFiles, false, $dbForPlatform, $authorization, $queueForBuilds, $getProjectDB, $platform);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,7 +217,8 @@ class Create extends Action
|
||||
Query::orderDesc('$createdAt')
|
||||
]));
|
||||
|
||||
$this->createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthor, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, $providerPullRequestId, $external, $dbForPlatform, $authorization, $queueForBuilds, $getProjectDB, $platform);
|
||||
$providerAffectedFiles = $parsedPayload['affectedFiles'] ?? [];
|
||||
$this->createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthor, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, $providerPullRequestId, $providerAffectedFiles, $external, $dbForPlatform, $authorization, $queueForBuilds, $getProjectDB, $platform);
|
||||
} elseif ($action == "closed") {
|
||||
// Allowed external contributions cleanup
|
||||
|
||||
|
||||
Reference in New Issue
Block a user