Add branch-only deployments to Sites without ref tags#10486
Conversation
📝 WalkthroughWalkthroughReplaces the single Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Security Scan Results for PRDocker Image Scan Results
Source Code Scan Results🎉 No vulnerabilities found! |
commit: |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/Appwrite/Platform/Modules/Functions/Workers/Builds.php (1)
1249-1255: Typo: Database::forEach vs foreach.
$dbForPlatform->foreach(...)will fatally error; method isforEach(...)elsewhere in this file.-$dbForPlatform->foreach('rules', function (Document $rule) use ($dbForPlatform, $deployment) { +$dbForPlatform->forEach('rules', function (Document $rule) use ($dbForPlatform, $deployment) {
🧹 Nitpick comments (5)
src/Appwrite/Platform/Modules/Functions/Workers/Builds.php (2)
355-355: Prefer escapeshellarg over escapeshellcmd for paths.Using escapeshellcmd on $tarParamDirectory (a path) is brittle; use escapeshellarg to avoid quoting issues and injection edges.
-Console::execute('tar --exclude code.tar.gz -czf ' . \escapeshellarg($tmpPathFile) . ' -C ' . \escapeshellcmd($tarParamDirectory) . ' .', '', $stdout, $stderr); +Console::execute('tar --exclude code.tar.gz -czf ' . \escapeshellarg($tmpPathFile) . ' -C ' . \escapeshellarg($tarParamDirectory) . ' .', '', $stdout, $stderr);(Repeat the same change at Line 516.)
Also applies to: 516-516
446-452: (Parity) Support template branch in VCS flow as well.Non-VCS path now handles
branch; the VCS+template path still only acceptsversion(tag). If you want consistent behavior, allowbranchhere too.-$templateVersion = $template->getAttribute('version', ''); +$templateVersion = $template->getAttribute('version', ''); +$templateBranch = $template->getAttribute('branch', ''); -if (!empty($templateRepositoryName) && !empty($templateOwnerName) && !empty($templateVersion)) { +if (!empty($templateRepositoryName) && !empty($templateOwnerName) && (!empty($templateVersion) || !empty($templateBranch))) { // Clone template repo $tmpTemplateDirectory = '/tmp/builds/' . $deploymentId . '/template'; - - $gitCloneCommandForTemplate = $github->generateCloneCommand($templateOwnerName, $templateRepositoryName, $templateVersion, GitHub::CLONE_TYPE_TAG, $tmpTemplateDirectory, $templateRootDirectory); + $ref = !empty($templateVersion) ? $templateVersion : $templateBranch; + $type = !empty($templateVersion) ? GitHub::CLONE_TYPE_TAG : GitHub::CLONE_TYPE_BRANCH; + $gitCloneCommandForTemplate = $github->generateCloneCommand($templateOwnerName, $templateRepositoryName, $ref, $type, $tmpTemplateDirectory, $templateRootDirectory);src/Appwrite/Platform/Modules/Sites/Http/Deployments/Direct/Create.php (2)
65-69: Parameter descriptions: avoid “template” wording.These params refer to the source repository, not a template. Adjust copy to prevent confusion.
-->param('repository', '', new Text(128, 0), 'Repository name of the template.') -->param('owner', '', new Text(128, 0), 'The name of the owner of the template.') -->param('rootDirectory', '', new Text(128, 0), 'Path to site code in the template repo.') +->param('repository', '', new Text(128, 0), 'Repository name.') +->param('owner', '', new Text(128, 0), 'Repository owner (user or org).') +->param('rootDirectory', '', new Text(128, 0), 'Path to site code within the repository.')
141-146: Initialize commit details to avoid undefined var notices.
$commitDetailsis used later even if the try-block fails before assignment.-try { - $commitDetails = $github->getLatestCommit($owner, $repository, $branch); -} catch (\Throwable $error) { +try { + $commitDetails = $github->getLatestCommit($owner, $repository, $branch); +} catch (\Throwable $error) { // Ignore; deployment can continue } +// Ensure array shape even on failure +$commitDetails = $commitDetails ?? [];src/Appwrite/Platform/Modules/Sites/Services/Http.php (1)
5-15: Fix ordered imports (Pint: ordered_imports).Sort the Deployments imports to satisfy Pint.
-use Appwrite\Platform\Modules\Sites\Http\Deployments\Create as CreateDeployment; -use Appwrite\Platform\Modules\Sites\Http\Deployments\Delete as DeleteDeployment; -use Appwrite\Platform\Modules\Sites\Http\Deployments\Download\Get as DownloadDeployment; -use Appwrite\Platform\Modules\Sites\Http\Deployments\Duplicate\Create as CreateDuplicateDeployment; -use Appwrite\Platform\Modules\Sites\Http\Deployments\Direct\Create as CreateDirectDeployment; -use Appwrite\Platform\Modules\Sites\Http\Deployments\Get as GetDeployment; -use Appwrite\Platform\Modules\Sites\Http\Deployments\Status\Update as UpdateDeploymentStatus; -use Appwrite\Platform\Modules\Sites\Http\Deployments\Template\Create as CreateTemplateDeployment; -use Appwrite\Platform\Modules\Sites\Http\Deployments\Vcs\Create as CreateVcsDeployment; -use Appwrite\Platform\Modules\Sites\Http\Deployments\XList as ListDeployments; +use Appwrite\Platform\Modules\Sites\Http\Deployments\Create as CreateDeployment; +use Appwrite\Platform\Modules\Sites\Http\Deployments\Delete as DeleteDeployment; +use Appwrite\Platform\Modules\Sites\Http\Deployments\Direct\Create as CreateDirectDeployment; +use Appwrite\Platform\Modules\Sites\Http\Deployments\Download\Get as DownloadDeployment; +use Appwrite\Platform\Modules\Sites\Http\Deployments\Duplicate\Create as CreateDuplicateDeployment; +use Appwrite\Platform\Modules\Sites\Http\Deployments\Get as GetDeployment; +use Appwrite\Platform\Modules\Sites\Http\Deployments\Status\Update as UpdateDeploymentStatus; +use Appwrite\Platform\Modules\Sites\Http\Deployments\Template\Create as CreateTemplateDeployment; +use Appwrite\Platform\Modules\Sites\Http\Deployments\Vcs\Create as CreateVcsDeployment; +use Appwrite\Platform\Modules\Sites\Http\Deployments\XList as ListDeployments;
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (4)
app/config/specs/open-api3-latest-console.jsonis excluded by!app/config/specs/**app/config/specs/open-api3-latest-server.jsonis excluded by!app/config/specs/**app/config/specs/swagger2-latest-console.jsonis excluded by!app/config/specs/**app/config/specs/swagger2-latest-server.jsonis excluded by!app/config/specs/**
📒 Files selected for processing (3)
src/Appwrite/Platform/Modules/Functions/Workers/Builds.php(1 hunks)src/Appwrite/Platform/Modules/Sites/Http/Deployments/Direct/Create.php(1 hunks)src/Appwrite/Platform/Modules/Sites/Services/Http.php(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/Appwrite/Platform/Modules/Sites/Http/Deployments/Direct/Create.php (3)
src/Appwrite/Platform/Modules/Sites/Services/Http.php (2)
Http(37-88)__construct(39-87)src/Appwrite/Event/Event.php (1)
Event(10-653)src/Appwrite/Platform/Modules/Compute/Base.php (1)
redeployVcsSite(112-304)
src/Appwrite/Platform/Modules/Sites/Services/Http.php (1)
src/Appwrite/Platform/Modules/Sites/Http/Deployments/Direct/Create.php (2)
Create(28-231)getName(32-35)
🪛 GitHub Actions: Linter
src/Appwrite/Platform/Modules/Functions/Workers/Builds.php
[error] 1-1: Pint: PSR-12 style issue detected (single_space_...) in Builds.php.
src/Appwrite/Platform/Modules/Sites/Http/Deployments/Direct/Create.php
[error] 1-1: Pint: PSR-12 style issue detected (single_space_...) in Create.php.
src/Appwrite/Platform/Modules/Sites/Services/Http.php
[error] 1-1: Pint: PSR-12 style issue detected: ordered_imports
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Setup & Build Appwrite Image
- GitHub Check: Setup & Build SDK
- GitHub Check: Setup & Build Appwrite Image
- GitHub Check: scan
🔇 Additional comments (1)
src/Appwrite/Platform/Modules/Sites/Services/Http.php (1)
64-65: Registration LGTM.Action is correctly registered; name aligns with CreateDirectDeployment::getName().
src/Appwrite/Platform/Modules/Sites/Http/Deployments/Direct/Create.php
Outdated
Show resolved
Hide resolved
src/Appwrite/Platform/Modules/Sites/Http/Deployments/Direct/Create.php
Outdated
Show resolved
Hide resolved
✨ Benchmark results
⚡ Benchmark Comparison
|
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/Appwrite/Platform/Modules/Functions/Workers/Builds.php (1)
1249-1249: Fix typo: call Database::forEach, not foreach.This is a fatal error at runtime. Match the method used elsewhere in the file.
Apply:
- $dbForPlatform->foreach('rules', function (Document $rule) use ($dbForPlatform, $deployment) { + $dbForPlatform->forEach('rules', function (Document $rule) use ($dbForPlatform, $deployment) {
♻️ Duplicate comments (1)
src/Appwrite/Platform/Modules/Functions/Workers/Builds.php (1)
325-334: Create /tmp/builds before cloning + remove stray blank lines.Without ensuring the parent dir exists, git clone to “/tmp/builds/-template” will fail on fresh workers. This was flagged earlier; still missing here. Also, drop extra blank lines to satisfy Pint.
Apply:
// Clone template repo $tmpTemplateDirectory = '/tmp/builds/' . $deploymentId . '-template'; - + Console::execute('mkdir -p ' . \escapeshellarg('/tmp/builds'), '', $stdout, $stderr); - - if (empty($templateVersion)) { + if (empty($templateVersion)) { $gitCloneCommandForTemplate = $github->generateCloneCommand($templateOwnerName, $templateRepositoryName, $templateBranch, GitHub::CLONE_TYPE_BRANCH, $tmpTemplateDirectory, $templateRootDirectory); } else { // True template $gitCloneCommandForTemplate = $github->generateCloneCommand($templateOwnerName, $templateRepositoryName, $templateVersion, GitHub::CLONE_TYPE_TAG, $tmpTemplateDirectory, $templateRootDirectory); } -
🧹 Nitpick comments (1)
src/Appwrite/Platform/Modules/Functions/Workers/Builds.php (1)
436-452: Parity: support templateBranch in VCS+Template merge path too.The VCS path only clones templates by tag. For consistency with the non‑VCS path and to enable branch-based templates here as well, add branch fallback.
Proposed change:
// Build from template $templateRepositoryName = $template->getAttribute('repositoryName', ''); $templateOwnerName = $template->getAttribute('ownerName', ''); $templateVersion = $template->getAttribute('version', ''); + $templateBranch = $template->getAttribute('branch', ''); $templateRootDirectory = $template->getAttribute('rootDirectory', ''); $templateRootDirectory = \rtrim($templateRootDirectory, '/'); $templateRootDirectory = \ltrim($templateRootDirectory, '.'); $templateRootDirectory = \ltrim($templateRootDirectory, '/'); - if (!empty($templateRepositoryName) && !empty($templateOwnerName) && !empty($templateVersion)) { + if (!empty($templateRepositoryName) && !empty($templateOwnerName) && (!empty($templateVersion) || !empty($templateBranch))) { // Clone template repo $tmpTemplateDirectory = '/tmp/builds/' . $deploymentId . '/template'; - - $gitCloneCommandForTemplate = $github->generateCloneCommand($templateOwnerName, $templateRepositoryName, $templateVersion, GitHub::CLONE_TYPE_TAG, $tmpTemplateDirectory, $templateRootDirectory); + $gitCloneCommandForTemplate = empty($templateVersion) + ? $github->generateCloneCommand($templateOwnerName, $templateRepositoryName, $templateBranch, GitHub::CLONE_TYPE_BRANCH, $tmpTemplateDirectory, $templateRootDirectory) + : $github->generateCloneCommand($templateOwnerName, $templateRepositoryName, $templateVersion, GitHub::CLONE_TYPE_TAG, $tmpTemplateDirectory, $templateRootDirectory);
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/Appwrite/Platform/Modules/Functions/Workers/Builds.php(1 hunks)src/Appwrite/Platform/Modules/Sites/Http/Deployments/Direct/Create.php(1 hunks)src/Appwrite/Platform/Modules/Sites/Services/Http.php(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- src/Appwrite/Platform/Modules/Sites/Services/Http.php
- src/Appwrite/Platform/Modules/Sites/Http/Deployments/Direct/Create.php
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: Benchmark
- GitHub Check: E2E Service Test (Messaging)
- GitHub Check: E2E Service Test (Webhooks)
- GitHub Check: E2E Service Test (Sites)
- GitHub Check: E2E Service Test (Databases/TablesDB)
- GitHub Check: E2E Service Test (Databases/Legacy)
🔇 Additional comments (2)
src/Appwrite/Platform/Modules/Functions/Workers/Builds.php (2)
321-333: Branch fallback logic is correct.Using branch clone when templateVersion is empty, and tag clone otherwise, reads well and preserves backward compatibility.
314-314: Harden templateBranch input (trim + newline/null guard) — verify GitHub::generateCloneCommand shell-safetyNormalize and validate branch to prevent injection/formatting; generateCloneCommand implementation not found in the provided repo output, so its escaping/quoting can't be confirmed.
Location: src/Appwrite/Platform/Modules/Functions/Workers/Builds.php
Apply:
- $templateBranch = $template->getAttribute('branch', ''); + $templateBranch = \trim($template->getAttribute('branch', '')); + if ($templateBranch !== '' && \strpbrk($templateBranch, "\r\n\0") !== false) { + throw new \Exception('Invalid template branch value.'); + }Either apply the change and ensure GitHub::generateCloneCommand properly quotes/escapes branch/ref inputs, or provide the path to the GitHub class/implementation so I can verify it.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/Appwrite/Platform/Modules/Functions/Workers/Builds.php (1)
431-447: VCS+Template still uses deprecated templateVersion; breaks new referenceType/referenceValue flow.This block will no-op now that templates store referenceType/referenceValue, not version.
Apply:
-// Build from template -$templateRepositoryName = $template->getAttribute('repositoryName', ''); -$templateOwnerName = $template->getAttribute('ownerName', ''); -$templateVersion = $template->getAttribute('version', ''); +// Build from template (supports tag/branch/commit) +$templateRepositoryName = $template->getAttribute('repositoryName', ''); +$templateOwnerName = $template->getAttribute('ownerName', ''); +$templateReferenceType = $template->getAttribute('referenceType', ''); +$templateReferenceValue = $template->getAttribute('referenceValue', ''); ... -if (!empty($templateRepositoryName) && !empty($templateOwnerName) && !empty($templateVersion)) { +if (!empty($templateRepositoryName) && !empty($templateOwnerName) && !empty($templateReferenceType) && !empty($templateReferenceValue)) { // Clone template repo $tmpTemplateDirectory = '/tmp/builds/' . $deploymentId . '/template'; - $gitCloneCommandForTemplate = $github->generateCloneCommand($templateOwnerName, $templateRepositoryName, $templateVersion, GitHub::CLONE_TYPE_TAG, $tmpTemplateDirectory, $templateRootDirectory); + $gitCloneCommandForTemplate = $github->generateCloneCommand( + $templateOwnerName, + $templateRepositoryName, + $templateReferenceValue, + $templateReferenceType, + $tmpTemplateDirectory, + $templateRootDirectory + );src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php (1)
89-109: Strengthen validation: require (version) XOR (type + reference) and whitelist type.Prevents empty reference with type set and rejects unknown types early.
Apply:
public function action( ... string $version, string $type, string $reference, ... ) { @@ - if (empty($version) && empty($type) && empty($reference)) { - throw new Exception("Either version or type & reference must be provided"); - } + if (empty($version) && empty($type) && empty($reference)) { + throw new Exception('Either version or (type & reference) must be provided'); + } + // Enforce pairing and exclusivity + if (!empty($type) xor !empty($reference)) { + throw new Exception('Both type and reference must be provided together'); + } + if (!empty($version) && (!empty($type) || !empty($reference))) { + throw new Exception('Provide either version or (type & reference), not both'); + } + + // Whitelist type when provided + if (!empty($type)) { + $allowedRefTypes = [GitHub::CLONE_TYPE_BRANCH, GitHub::CLONE_TYPE_TAG, GitHub::CLONE_TYPE_COMMIT]; + if (!\in_array($type, $allowedRefTypes, true)) { + throw new Exception('Invalid reference type: ' . $type); + } + }
♻️ Duplicate comments (1)
src/Appwrite/Platform/Modules/Functions/Workers/Builds.php (1)
321-331: Ensure /tmp/builds exists before cloning (prevents git clone failure).Parent dir isn’t created in the non‑VCS path; clone to /tmp/builds/-template will fail if /tmp/builds is missing.
Apply:
if (!empty($templateRepositoryName) && !empty($templateOwnerName) && !empty($templateReferenceType) && !empty($templateReferenceValue)) { $stdout = ''; $stderr = ''; // Clone template repo $tmpTemplateDirectory = '/tmp/builds/' . $deploymentId . '-template'; - - $gitCloneCommandForTemplate = $github->generateCloneCommand($templateOwnerName, $templateRepositoryName, $templateReferenceValue, $templateReferenceType, $tmpTemplateDirectory, $templateRootDirectory); + Console::execute('mkdir -p ' . \escapeshellarg('/tmp/builds'), '', $stdout, $stderr); + $gitCloneCommandForTemplate = $github->generateCloneCommand( + $templateOwnerName, + $templateRepositoryName, + $templateReferenceValue, + $templateReferenceType, + $tmpTemplateDirectory, + $templateRootDirectory + );
🧹 Nitpick comments (3)
src/Appwrite/Platform/Modules/Functions/Workers/Builds.php (1)
313-315: Validate template referenceType against known constants.Prevent bad inputs from reaching git by whitelisting allowed types.
Apply:
$templateReferenceType = $template->getAttribute('referenceType', ''); $templateReferenceValue = $template->getAttribute('referenceValue', ''); + +// Guard allowed reference types +$allowedRefTypes = [GitHub::CLONE_TYPE_TAG, GitHub::CLONE_TYPE_BRANCH, GitHub::CLONE_TYPE_COMMIT]; +if (!\in_array($templateReferenceType, $allowedRefTypes, true)) { + throw new \Exception('Invalid template referenceType: ' . $templateReferenceType); +}src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php (1)
68-71: Clarify “type” values in API docs (use tag instead of version).Align wording with GitHub::CLONE_TYPE_* constants.
Apply:
-->param('type', '', new Text(128, 0), 'Type for the reference provided. Can be commit, branch, or version', true) +->param('type', '', new Text(128, 0), 'Type for the reference provided. One of: commit | branch | tag', true)src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php (1)
70-72: Fix param descriptions (site, and use tag instead of version in type list).Small doc correctness.
Apply:
-->param('version', '', new Text(128, 0), 'Version (tag) for the repo linked to the function template.', true) -->param('type', '', new Text(128, 0), 'Type for the reference provided. Can be commit, branch, or version', true) +->param('version', '', new Text(128, 0), 'Version (tag) for the repo linked to the site template.', true) +->param('type', '', new Text(128, 0), 'Type for the reference provided. One of: commit | branch | tag', true)
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php(4 hunks)src/Appwrite/Platform/Modules/Functions/Workers/Builds.php(1 hunks)src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php(4 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php (1)
src/Appwrite/Extend/Exception.php (1)
Exception(7-447)
src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php (2)
src/Appwrite/Extend/Exception.php (1)
Exception(7-447)src/Appwrite/Utopia/Response/Model/Document.php (1)
Document(8-112)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
- GitHub Check: E2E Service Test (Messaging)
- GitHub Check: E2E Service Test (Migrations)
- GitHub Check: E2E Service Test (VCS)
- GitHub Check: E2E Service Test (Tokens)
- GitHub Check: E2E Service Test (Functions)
- GitHub Check: E2E Service Test (Teams)
- GitHub Check: E2E Service Test (Console)
- GitHub Check: E2E Service Test (Proxy)
- GitHub Check: E2E Service Test (Projects)
- GitHub Check: E2E Service Test (Databases/TablesDB)
- GitHub Check: E2E Service Test (Databases/Legacy)
- GitHub Check: E2E Service Test (GraphQL)
- GitHub Check: E2E Service Test (Avatars)
- GitHub Check: E2E Service Test (Account)
- GitHub Check: E2E Service Test (Dev Keys)
- GitHub Check: E2E Service Test (Site Screenshots)
- GitHub Check: E2E General Test
- GitHub Check: Unit Test
- GitHub Check: Setup & Build SDK
- GitHub Check: scan
🔇 Additional comments (2)
src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php (1)
175-183: Deployment type changed to 'vcs' — server-side consumers OK; confirm UI/console
- No direct equality checks for 'manual' in deployment consumers were found; the only literal 'manual' is for function creation: src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php:338.
- Deployment type is read/forwarded (APPWRITE_DEPLOYMENT_TYPE) in: src/Appwrite/Platform/Workers/Functions.php:506, src/Appwrite/Platform/Modules/Functions/Workers/Builds.php:621, src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php:380, app/controllers/general.php:492 — these will receive 'vcs'.
- Action: verify frontend/console and any external consumers accept 'vcs' (outside this repo).
src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php (1)
165-171: Verified — changing deployment 'type' to 'vcs' is safe.No code branches compare deployment.type to 'manual'; VCS behavior is driven by providerRepositoryId/providerBranch and consumers read provider* fields (e.g. src/Appwrite/Platform/Modules/Functions/Workers/Builds.php, app/controllers/api/vcs.php). Non‑VCS template deployments still create 'type' => 'manual' (src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php).
src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php (1)
110-116: Bug: invalid Exception usage and missing XOR validation (can crash and allow partial input).
- Throwing
new Exception("...")passes the message as the type constant and will break error mapping.- Does not enforce
versionXOR (typeANDreference), nor the “both-or-none” constraint fortype/reference.Apply:
- if (empty($version) && empty($type) && empty($reference)) { - throw new Exception("Either version or type & reference must be provided"); - } - - $referenceType = !empty($version) ? GitHub::CLONE_TYPE_TAG : $type; - $referenceValue = !empty($version) ? $version : $reference; + // Enforce: version XOR (type AND reference) + if (empty($version) && (empty($type) || empty($reference))) { + throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Either version or (type & reference) must be provided'); + } + if (!empty($type) xor !empty($reference)) { + throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Both type and reference must be provided together'); + } + if (!empty($version) && (!empty($type) || !empty($reference))) { + throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Provide either version or (type & reference), not both'); + } + // Defense-in-depth (validator already restricts the values) + $allowedRefTypes = [GitHub::CLONE_TYPE_BRANCH, GitHub::CLONE_TYPE_TAG, GitHub::CLONE_TYPE_COMMIT]; + if (!empty($type) && !\in_array($type, $allowedRefTypes, true)) { + throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Invalid reference type: ' . $type); + } + + $referenceType = !empty($version) ? GitHub::CLONE_TYPE_TAG : $type; + $referenceValue = !empty($version) ? $version : $reference;
🧹 Nitpick comments (1)
src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php (1)
71-74: Fix param docs and clarify mutual exclusivity (version XOR type+reference).
- Wording: use “site template” (not “function template”).
- Use “tag” (not “version”) in the
typedescription; values are branch|commit|tag.- Add guidance that clients must send either
versionor (type+reference).Apply:
- ->param('version', '', new Text(128, 0), 'Version (tag) for the repo linked to the function template.', true) - ->param('type', '', new WhiteList(['branch', 'commit', 'tag']), 'Type for the reference provided. Can be commit, branch, or version', true) - ->param('reference', '', new Text(128, 0), 'Reference value, can be a commit hash, branch name, or release tag', true) + ->param('version', '', new Text(128, 0), 'Version (tag) for the repo linked to the site template. Provide either version or (type + reference).', true) + ->param('type', '', new WhiteList(['branch', 'commit', 'tag']), 'Type for the reference provided. Can be commit, branch, or tag.', true) + ->param('reference', '', new Text(128, 0), 'Reference value: commit SHA, branch name, or tag name.', true)
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (4)
app/config/specs/open-api3-latest-console.jsonis excluded by!app/config/specs/**app/config/specs/open-api3-latest-server.jsonis excluded by!app/config/specs/**app/config/specs/swagger2-latest-console.jsonis excluded by!app/config/specs/**app/config/specs/swagger2-latest-server.jsonis excluded by!app/config/specs/**
📒 Files selected for processing (2)
src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php(5 hunks)src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php(5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php
🧰 Additional context used
🧬 Code graph analysis (1)
src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php (2)
src/Appwrite/GraphQL/Types/Mapper.php (1)
param(254-355)src/Appwrite/Extend/Exception.php (1)
Exception(7-447)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
- GitHub Check: E2E Service Test (Messaging)
- GitHub Check: E2E Service Test (VCS)
- GitHub Check: E2E Service Test (Sites)
- GitHub Check: E2E Service Test (FunctionsSchedule)
- GitHub Check: E2E Service Test (Storage)
- GitHub Check: E2E Service Test (Teams)
- GitHub Check: E2E Service Test (Functions)
- GitHub Check: E2E Service Test (Realtime)
- GitHub Check: E2E Service Test (Console)
- GitHub Check: E2E Service Test (Databases/TablesDB)
- GitHub Check: E2E Service Test (Avatars)
- GitHub Check: E2E Service Test (Databases/Legacy)
- GitHub Check: E2E Service Test (Account)
- GitHub Check: E2E Service Test (Site Screenshots)
- GitHub Check: E2E Service Test (Dev Keys)
- GitHub Check: E2E General Test
- GitHub Check: Unit Test
- GitHub Check: Benchmark
- GitHub Check: Setup & Build SDK
- GitHub Check: scan
🔇 Additional comments (3)
src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php (3)
26-26: LGTM: WhiteList validator importImport is correct and aligns with the new
typeenum.
124-126: LGTM: canonical template reference fieldsStoring
referenceType/referenceValueis the right abstraction for VCS-based templates.
92-94: Signature change looks good — regenerate SDKs/GraphQL & update docsBoth Sites and Functions template Create endpoints mark 'type' and 'reference' optional via ->param(..., true) and their action signatures match (src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php, src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php). Run the SDK / OpenAPI & GraphQL generation and confirm generated SDKs/docs expose these optional params.
src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php
Outdated
Show resolved
Hide resolved
src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php
Outdated
Show resolved
Hide resolved
src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php
Outdated
Show resolved
Hide resolved
src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php
Outdated
Show resolved
Hide resolved
src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (3)
src/Appwrite/Utopia/Request/Filters/V21.php (1)
12-17: Scope models are correct — consider centralizing list.
Targets the two template deployment routes only; fine. Optional: lift model names to a private const to avoid typos.src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php (1)
106-108: Build provider links from canonical reference and use strict comparisons.
Precompute repositoryUrl, use it to derive branchUrl, and compare with === to avoid surprises.Apply:
- $branchUrl = $type == GitHub::CLONE_TYPE_BRANCH ? "https://github.com/$owner/$repository/tree/$reference" : ""; - $repositoryUrl = "https://github.com/$owner/$repository"; + $repositoryUrl = "https://github.com/{$owner}/{$repository}"; + $branchUrl = $type === GitHub::CLONE_TYPE_BRANCH ? "{$repositoryUrl}/tree/{$reference}" : ''; @@ - 'providerRepositoryName' => $repository, - 'providerRepositoryOwner' => $owner, - 'providerRepositoryUrl' => $repositoryUrl, - 'providerBranchUrl' => $branchUrl, - 'providerBranch' => $type == GitHub::CLONE_TYPE_BRANCH ? $reference : '', + 'providerRepositoryName' => $repository, + 'providerRepositoryOwner' => $owner, + 'providerRepositoryUrl' => $repositoryUrl, + 'providerBranchUrl' => $branchUrl, + 'providerBranch' => $type === GitHub::CLONE_TYPE_BRANCH ? $reference : '',Also applies to: 156-163
src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php (1)
108-110: Derive URLs from repositoryUrl and use strict comparisons.
Avoid duplicate string assembly and weak equality.Apply:
- $branchUrl = $type == GitHub::CLONE_TYPE_BRANCH ? "https://github.com/$owner/$repository/tree/$reference" : ""; - $repositoryUrl = "https://github.com/$owner/$repository"; + $repositoryUrl = "https://github.com/{$owner}/{$repository}"; + $branchUrl = $type === GitHub::CLONE_TYPE_BRANCH ? "{$repositoryUrl}/tree/{$reference}" : ''; @@ - 'providerRepositoryName' => $repository, - 'providerRepositoryOwner' => $owner, - 'providerRepositoryUrl' => $repositoryUrl, - 'providerBranchUrl' => $branchUrl, - 'providerBranch' => $type == GitHub::CLONE_TYPE_BRANCH ? $reference : '', + 'providerRepositoryName' => $repository, + 'providerRepositoryOwner' => $owner, + 'providerRepositoryUrl' => $repositoryUrl, + 'providerBranchUrl' => $branchUrl, + 'providerBranch' => $type === GitHub::CLONE_TYPE_BRANCH ? $reference : '',Also applies to: 167-175
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (4)
app/config/specs/open-api3-latest-console.jsonis excluded by!app/config/specs/**app/config/specs/open-api3-latest-server.jsonis excluded by!app/config/specs/**app/config/specs/swagger2-latest-console.jsonis excluded by!app/config/specs/**app/config/specs/swagger2-latest-server.jsonis excluded by!app/config/specs/**
📒 Files selected for processing (4)
app/controllers/general.php(2 hunks)src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php(5 hunks)src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php(5 hunks)src/Appwrite/Utopia/Request/Filters/V21.php(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-05-12T06:05:27.133Z
Learnt from: abnegate
PR: appwrite/appwrite#9743
File: src/Appwrite/Utopia/Request.php:33-36
Timestamp: 2025-05-12T06:05:27.133Z
Learning: In Appwrite's architecture, the Request class should only filter parameters when filters are explicitly registered. If no filters are present, all parameters should be passed through, and the route action is responsible for validating which parameters are present/valid.
Applied to files:
src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php
🧬 Code graph analysis (4)
src/Appwrite/Utopia/Request/Filters/V21.php (1)
src/Appwrite/Utopia/Request/Filter.php (1)
Filter(8-57)
app/controllers/general.php (1)
src/Appwrite/Utopia/Request/Filters/V21.php (1)
V21(7-34)
src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
param(254-355)
src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php (2)
src/Appwrite/GraphQL/Types/Mapper.php (1)
param(254-355)src/Appwrite/Utopia/Response/Model/Document.php (1)
Document(8-112)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Setup & Build Appwrite Image
- GitHub Check: Setup & Build Appwrite Image
- GitHub Check: Setup & Build SDK
- GitHub Check: scan
🔇 Additional comments (4)
app/controllers/general.php (2)
26-26: Add V21 filter import — LGTM.
Import alias is correct and consistent with existing V16–V20 usage.
910-912: Apply V21 for requestFormat < 1.8.1 — LGTM, confirm filter order.
Order is V20 then V21, which is desirable for callers on ≤1.7.x. Just confirm Request::addFilter executes in registration order.src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php (1)
113-115: Template stores canonical reference — LGTM.
Persisting referenceType/referenceValue aligns with build worker expectations.src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php (1)
115-117: Template stores canonical reference — LGTM.
Matches Functions flow and Build worker expectations.
src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php
Show resolved
Hide resolved
src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (4)
tests/e2e/Services/Functions/FunctionsCustomServerTest.php (2)
506-559: Branch test: avoid hardcoded 'main' and add Retry to curb flakes.Use template default/provider branch and add #[Retry] to handle transient network/GitHub hiccups.
- public function testCreateFunctionAndDeploymentFromTemplateBranch() + #[Retry(count: 3)] + public function testCreateFunctionAndDeploymentFromTemplateBranch() { $starterTemplate = $this->getTemplate('starter'); @@ - // Deploy using branch + // Deploy using branch + $branch = $starterTemplate['body']['providerBranch'] ?? 'main'; $deployment = $this->createTemplateDeployment( $functionId, [ @@ - 'type' => 'branch', - 'reference' => 'main', + 'type' => 'branch', + 'reference' => $branch, ] );
561-619: Commit test: make resilient to missing latestCommit and add Retry.Skip (not fail) when GitHub is offline/rate‑limited; add #[Retry].
- public function testCreateFunctionAndDeploymentFromTemplateCommit() + #[Retry(count: 3)] + public function testCreateFunctionAndDeploymentFromTemplateCommit() { $starterTemplate = $this->getTemplate('starter'); $this->assertEquals(200, $starterTemplate['headers']['status-code']); - // Ensure we have the latest commit - $this->assertArrayHasKey('latestCommit', $starterTemplate['body']); - $latestCommit = $starterTemplate['body']['latestCommit']; + // Ensure we have the latest commit + if (!isset($starterTemplate['body']['latestCommit'])) { + $this->markTestSkipped('latestCommit could not be resolved from GitHub (rate limit/offline).'); + } + $latestCommit = $starterTemplate['body']['latestCommit'];tests/e2e/Services/Sites/SitesCustomServerTest.php (2)
1611-1680: Branch test: prefer template/default branch and add Retry.Avoid hardcoded 'main'; add #[Retry] to reduce external flakiness.
- public function testCreateSiteFromTemplateBranch() + #[Retry(count: 3)] + public function testCreateSiteFromTemplateBranch() { $template = $this->getTemplate('playground-for-astro'); @@ - $deployment = $this->createTemplateDeployment($siteId, [ + $branch = $template['body']['providerBranch'] ?? 'main'; + $deployment = $this->createTemplateDeployment($siteId, [ 'repository' => $template['providerRepositoryId'], 'owner' => $template['providerOwner'], 'rootDirectory' => $template['frameworks'][0]['providerRootDirectory'], 'type' => 'branch', - 'reference' => 'main', + 'reference' => $branch, 'activate' => true ]);
1682-1755: Commit test: skip when latestCommit missing and add Retry.Guard against GitHub outages/rate limits; add #[Retry].
- public function testCreateSiteFromTemplateCommit() + #[Retry(count: 3)] + public function testCreateSiteFromTemplateCommit() { $template = $this->getTemplate('playground-for-astro'); $this->assertEquals(200, $template['headers']['status-code']); - // Ensure we have the latest commit - $this->assertArrayHasKey('latestCommit', $template['body']); - $latestCommit = $template['body']['latestCommit']; + // Ensure we have the latest commit + if (!isset($template['body']['latestCommit'])) { + $this->markTestSkipped('latestCommit could not be resolved from GitHub (rate limit/offline).'); + } + $latestCommit = $template['body']['latestCommit'];
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
tests/e2e/Services/Functions/FunctionsBase.php(1 hunks)tests/e2e/Services/Functions/FunctionsCustomServerTest.php(2 hunks)tests/e2e/Services/Sites/SitesBase.php(1 hunks)tests/e2e/Services/Sites/SitesCustomServerTest.php(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: atharvadeosthale
PR: appwrite/appwrite#10486
File: src/Appwrite/Utopia/Request/Filters/V21.php:25-33
Timestamp: 2025-09-18T07:42:08.717Z
Learning: In Appwrite's V21 request filter for backward compatibility, clients will never send both old (`version`) and new (`type`/`reference`) parameters simultaneously - they use either the old 1.8.0 format or the new 1.8.1+ format, not a mix of both.
🧬 Code graph analysis (2)
tests/e2e/Services/Sites/SitesCustomServerTest.php (2)
tests/e2e/Services/Sites/SitesBase.php (7)
getDeployment(187-195)getSite(177-185)setupSiteDomain(374-392)cleanupSite(85-94)getTemplate(326-362)setupSite(21-34)createTemplateDeployment(306-314)tests/e2e/Client.php (2)
Client(8-342)setEndpoint(140-145)
tests/e2e/Services/Functions/FunctionsCustomServerTest.php (1)
tests/e2e/Services/Functions/FunctionsBase.php (5)
getTemplate(264-300)createFunction(80-88)createTemplateDeployment(244-252)getDeployment(160-168)cleanupFunction(69-78)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (19)
- GitHub Check: Benchmark
- GitHub Check: E2E Service Test (Messaging)
- GitHub Check: E2E Service Test (VCS)
- GitHub Check: E2E Service Test (Teams)
- GitHub Check: E2E Service Test (Functions)
- GitHub Check: E2E Service Test (FunctionsSchedule)
- GitHub Check: E2E Service Test (Projects)
- GitHub Check: E2E Service Test (Proxy)
- GitHub Check: E2E Service Test (Health)
- GitHub Check: E2E Service Test (Sites)
- GitHub Check: E2E Service Test (Tokens)
- GitHub Check: E2E Service Test (Account)
- GitHub Check: E2E Service Test (Console)
- GitHub Check: E2E Service Test (Locale)
- GitHub Check: E2E Service Test (Databases/TablesDB)
- GitHub Check: E2E Service Test (Site Screenshots)
- GitHub Check: E2E Service Test (Dev Keys)
- GitHub Check: E2E General Test
- GitHub Check: scan
🔇 Additional comments (2)
tests/e2e/Services/Functions/FunctionsCustomServerTest.php (1)
403-405: LGTM: migrate to type/reference for tag deployments.Matches the new API surface; no concerns.
tests/e2e/Services/Sites/SitesCustomServerTest.php (1)
1566-1609: LGTM: Sites template deployment via tag/reference.Aligns with new API; assertions look good.
| // GitHub API to get latest commit from main branch | ||
| $ch = curl_init("https://api.github.com/repos/{$owner}/{$repo}/commits/main"); | ||
| curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | ||
| curl_setopt($ch, CURLOPT_HTTPHEADER, [ | ||
| 'User-Agent: Appwrite', | ||
| 'Accept: application/vnd.github.v3+json' | ||
| ]); | ||
|
|
||
| $response = curl_exec($ch); | ||
| $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); | ||
| curl_close($ch); | ||
|
|
||
| if ($httpCode === 200) { | ||
| $commitData = json_decode($response, true); | ||
| if (isset($commitData['sha'])) { | ||
| $template['body']['latestCommit'] = $commitData['sha']; | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Same resiliency improvements for GitHub lookup as SitesBase.
Avoid hardcoded "main", add short timeouts, support AUTH header, URL‑encode owner/repo.
- // GitHub API to get latest commit from main branch
- $ch = curl_init("https://api.github.com/repos/{$owner}/{$repo}/commits/main");
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($ch, CURLOPT_HTTPHEADER, [
- 'User-Agent: Appwrite',
- 'Accept: application/vnd.github.v3+json'
- ]);
-
- $response = curl_exec($ch);
- $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
- curl_close($ch);
-
- if ($httpCode === 200) {
- $commitData = json_decode($response, true);
- if (isset($commitData['sha'])) {
- $template['body']['latestCommit'] = $commitData['sha'];
- }
- }
+ $ownerEnc = rawurlencode((string)$owner);
+ $repoEnc = rawurlencode((string)$repo);
+ $headers = ['User-Agent: Appwrite', 'Accept: application/vnd.github+json'];
+ $token = \Utopia\System\System::getEnv('GITHUB_TOKEN') ?: \Utopia\System\System::getEnv('GITHUB_API_TOKEN');
+ if ($token) {
+ $headers[] = 'Authorization: Bearer ' . $token;
+ }
+ $branch = $template['body']['providerBranch'] ?? null;
+ if (!$branch) {
+ $ch = curl_init("https://api.github.com/repos/{$ownerEnc}/{$repoEnc}");
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
+ curl_setopt($ch, CURLOPT_TIMEOUT, 5);
+ $repoResp = curl_exec($ch);
+ $repoCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ curl_close($ch);
+ $branch = ($repoCode === 200 && is_string($repoResp))
+ ? (json_decode($repoResp, true)['default_branch'] ?? 'main')
+ : 'main';
+ }
+ $ch = curl_init("https://api.github.com/repos/{$ownerEnc}/{$repoEnc}/commits/{$branch}");
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
+ curl_setopt($ch, CURLOPT_TIMEOUT, 5);
+ $response = curl_exec($ch);
+ $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ curl_close($ch);
+ if ($httpCode === 200 && is_string($response)) {
+ $commitData = json_decode($response, true);
+ if (isset($commitData['sha'])) {
+ $template['body']['latestCommit'] = $commitData['sha'];
+ }
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // GitHub API to get latest commit from main branch | |
| $ch = curl_init("https://api.github.com/repos/{$owner}/{$repo}/commits/main"); | |
| curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | |
| curl_setopt($ch, CURLOPT_HTTPHEADER, [ | |
| 'User-Agent: Appwrite', | |
| 'Accept: application/vnd.github.v3+json' | |
| ]); | |
| $response = curl_exec($ch); | |
| $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); | |
| curl_close($ch); | |
| if ($httpCode === 200) { | |
| $commitData = json_decode($response, true); | |
| if (isset($commitData['sha'])) { | |
| $template['body']['latestCommit'] = $commitData['sha']; | |
| } | |
| } | |
| } | |
| $ownerEnc = rawurlencode((string)$owner); | |
| $repoEnc = rawurlencode((string)$repo); | |
| $headers = ['User-Agent: Appwrite', 'Accept: application/vnd.github+json']; | |
| $token = \Utopia\System\System::getEnv('GITHUB_TOKEN') ?: \Utopia\System\System::getEnv('GITHUB_API_TOKEN'); | |
| if ($token) { | |
| $headers[] = 'Authorization: Bearer ' . $token; | |
| } | |
| $branch = $template['body']['providerBranch'] ?? null; | |
| if (!$branch) { | |
| $ch = curl_init("https://api.github.com/repos/{$ownerEnc}/{$repoEnc}"); | |
| curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | |
| curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); | |
| curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3); | |
| curl_setopt($ch, CURLOPT_TIMEOUT, 5); | |
| $repoResp = curl_exec($ch); | |
| $repoCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); | |
| curl_close($ch); | |
| $branch = ($repoCode === 200 && is_string($repoResp)) | |
| ? (json_decode($repoResp, true)['default_branch'] ?? 'main') | |
| : 'main'; | |
| } | |
| $ch = curl_init("https://api.github.com/repos/{$ownerEnc}/{$repoEnc}/commits/{$branch}"); | |
| curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | |
| curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); | |
| curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3); | |
| curl_setopt($ch, CURLOPT_TIMEOUT, 5); | |
| $response = curl_exec($ch); | |
| $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); | |
| curl_close($ch); | |
| if ($httpCode === 200 && is_string($response)) { | |
| $commitData = json_decode($response, true); | |
| if (isset($commitData['sha'])) { | |
| $template['body']['latestCommit'] = $commitData['sha']; | |
| } | |
| } | |
| } |
🤖 Prompt for AI Agents
In tests/e2e/Services/Functions/FunctionsBase.php around lines 279-297, the
GitHub API call is fragile: it hardcodes "main", lacks timeouts, doesn't support
Authorization, and doesn't URL-encode owner/repo; update the request to use a
branch variable (default from env or parameter instead of hardcoded "main"),
URL-encode $owner and $repo before building the URL, add short curl timeouts
(CURLOPT_CONNECTTIMEOUT and CURLOPT_TIMEOUT), conditionally add an
Authorization: Bearer <token> header when a GITHUB_TOKEN (or similar) is
available, and preserve existing headers; also ensure curl errors and non-200
responses are handled gracefully before accessing json fields.
| // GitHub API to get latest commit from main branch | ||
| $ch = curl_init("https://api.github.com/repos/{$owner}/{$repo}/commits/main"); | ||
| curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | ||
| curl_setopt($ch, CURLOPT_HTTPHEADER, [ | ||
| 'User-Agent: Appwrite', | ||
| 'Accept: application/vnd.github.v3+json' | ||
| ]); | ||
|
|
||
| $response = curl_exec($ch); | ||
| $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); | ||
| curl_close($ch); | ||
|
|
||
| if ($httpCode === 200) { | ||
| $commitData = json_decode($response, true); | ||
| if (isset($commitData['sha'])) { | ||
| $template['body']['latestCommit'] = $commitData['sha']; | ||
| } | ||
| } |
There was a problem hiding this comment.
Harden GitHub commit lookup: respect default branch, add timeouts, optional token, and URL‑encode.
Hardcoding "main" and omitting curl timeouts can cause flakes/hangs in CI; also support private repos/rate limits via a token.
Apply:
- // GitHub API to get latest commit from main branch
- $ch = curl_init("https://api.github.com/repos/{$owner}/{$repo}/commits/main");
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($ch, CURLOPT_HTTPHEADER, [
- 'User-Agent: Appwrite',
- 'Accept: application/vnd.github.v3+json'
- ]);
-
- $response = curl_exec($ch);
- $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
- curl_close($ch);
-
- if ($httpCode === 200) {
- $commitData = json_decode($response, true);
- if (isset($commitData['sha'])) {
- $template['body']['latestCommit'] = $commitData['sha'];
- }
- }
+ // Resolve branch -> prefer template's providerBranch, else repo default_branch, else 'main'
+ $ownerEnc = rawurlencode((string)$owner);
+ $repoEnc = rawurlencode((string)$repo);
+ $headers = ['User-Agent: Appwrite', 'Accept: application/vnd.github+json'];
+ $token = \Utopia\System\System::getEnv('GITHUB_TOKEN') ?: \Utopia\System\System::getEnv('GITHUB_API_TOKEN');
+ if ($token) {
+ $headers[] = 'Authorization: Bearer ' . $token;
+ }
+ $branch = $template['body']['providerBranch'] ?? null;
+ if (!$branch) {
+ $ch = curl_init("https://api.github.com/repos/{$ownerEnc}/{$repoEnc}");
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
+ curl_setopt($ch, CURLOPT_TIMEOUT, 5);
+ $repoResp = curl_exec($ch);
+ $repoCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ curl_close($ch);
+ $branch = ($repoCode === 200 && is_string($repoResp))
+ ? (json_decode($repoResp, true)['default_branch'] ?? 'main')
+ : 'main';
+ }
+ $ch = curl_init("https://api.github.com/repos/{$ownerEnc}/{$repoEnc}/commits/{$branch}");
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
+ curl_setopt($ch, CURLOPT_TIMEOUT, 5);
+ $response = curl_exec($ch);
+ $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ curl_close($ch);
+ if ($httpCode === 200 && is_string($response)) {
+ $commitData = json_decode($response, true);
+ if (isset($commitData['sha'])) {
+ $template['body']['latestCommit'] = $commitData['sha'];
+ }
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // GitHub API to get latest commit from main branch | |
| $ch = curl_init("https://api.github.com/repos/{$owner}/{$repo}/commits/main"); | |
| curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | |
| curl_setopt($ch, CURLOPT_HTTPHEADER, [ | |
| 'User-Agent: Appwrite', | |
| 'Accept: application/vnd.github.v3+json' | |
| ]); | |
| $response = curl_exec($ch); | |
| $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); | |
| curl_close($ch); | |
| if ($httpCode === 200) { | |
| $commitData = json_decode($response, true); | |
| if (isset($commitData['sha'])) { | |
| $template['body']['latestCommit'] = $commitData['sha']; | |
| } | |
| } | |
| // Resolve branch -> prefer template's providerBranch, else repo default_branch, else 'main' | |
| $ownerEnc = rawurlencode((string)$owner); | |
| $repoEnc = rawurlencode((string)$repo); | |
| $headers = ['User-Agent: Appwrite', 'Accept: application/vnd.github+json']; | |
| $token = \Utopia\System\System::getEnv('GITHUB_TOKEN') ?: \Utopia\System\System::getEnv('GITHUB_API_TOKEN'); | |
| if ($token) { | |
| $headers[] = 'Authorization: Bearer ' . $token; | |
| } | |
| $branch = $template['body']['providerBranch'] ?? null; | |
| if (!$branch) { | |
| $ch = curl_init("https://api.github.com/repos/{$ownerEnc}/{$repoEnc}"); | |
| curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | |
| curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); | |
| curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3); | |
| curl_setopt($ch, CURLOPT_TIMEOUT, 5); | |
| $repoResp = curl_exec($ch); | |
| $repoCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); | |
| curl_close($ch); | |
| $branch = ($repoCode === 200 && is_string($repoResp)) | |
| ? (json_decode($repoResp, true)['default_branch'] ?? 'main') | |
| : 'main'; | |
| } | |
| $ch = curl_init("https://api.github.com/repos/{$ownerEnc}/{$repoEnc}/commits/{$branch}"); | |
| curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | |
| curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); | |
| curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3); | |
| curl_setopt($ch, CURLOPT_TIMEOUT, 5); | |
| $response = curl_exec($ch); | |
| $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); | |
| curl_close($ch); | |
| if ($httpCode === 200 && is_string($response)) { | |
| $commitData = json_decode($response, true); | |
| if (isset($commitData['sha'])) { | |
| $template['body']['latestCommit'] = $commitData['sha']; | |
| } | |
| } |
🤖 Prompt for AI Agents
In tests/e2e/Services/Sites/SitesBase.php around lines 341-358, the GitHub
commit lookup is brittle: it hardcodes "main", lacks URL-encoding, timeouts,
optional auth, and robust error handling; update the flow to first GET
https://api.github.com/repos/{owner}/{repo} (with owner/repo URL-encoded) to
read default_branch, then request the commit for that branch; set curl options
CURLOPT_CONNECTTIMEOUT and CURLOPT_TIMEOUT, CURLOPT_FAILONERROR, and add an
Authorization: Bearer <token> header when a GITHUB_TOKEN env var is present to
handle private repos/rate limits; ensure headers include User-Agent and Accept,
check curl_exec for false and handle curl_error, validate HTTP codes before
json_decode, and extract the commit SHA reliably (top-level "sha" or from
"commit") before assigning template['body']['latestCommit'].
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (3)
tests/e2e/Services/Sites/SitesBase.php (1)
336-357: Harden GitHub commit lookup: respect default branch, add timeouts, optional token, and URL‑encode.Current code hardcodes "main", lacks timeouts, and doesn’t support private/rate‑limited repos. Improve resilience and CI stability.
Apply:
- protected function helperGetLatestCommit(string $owner, string $repository): ?string + protected function helperGetLatestCommit(string $owner, string $repository, ?string $branch = null): ?string { - $ch = curl_init("https://api.github.com/repos/{$owner}/{$repository}/commits/main"); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_HTTPHEADER, [ - 'User-Agent: Appwrite', - 'Accept: application/vnd.github.v3+json' - ]); - - $response = curl_exec($ch); - $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); - curl_close($ch); - - if ($httpCode === 200) { - $commitData = json_decode($response, true); - if (isset($commitData['sha'])) { - return $commitData['sha']; - } - } - - return null; + $ownerEnc = rawurlencode((string) $owner); + $repoEnc = rawurlencode((string) $repository); + + $headers = ['User-Agent: Appwrite', 'Accept: application/vnd.github+json']; + $token = System::getEnv('GITHUB_TOKEN') ?: System::getEnv('GITHUB_API_TOKEN'); + if ($token) { + $headers[] = 'Authorization: Bearer ' . $token; + } + + // Resolve branch: prefer provided, else repo default_branch, else 'main' + if ($branch === null || $branch === '') { + $ch = curl_init("https://api.github.com/repos/{$ownerEnc}/{$repoEnc}"); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3); + curl_setopt($ch, CURLOPT_TIMEOUT, 5); + $repoResp = curl_exec($ch); + $repoCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + $branch = ($repoCode === 200 && is_string($repoResp)) + ? (json_decode($repoResp, true)['default_branch'] ?? 'main') + : 'main'; + } + + $branchEnc = rawurlencode((string) $branch); + $ch = curl_init("https://api.github.com/repos/{$ownerEnc}/{$repoEnc}/commits/{$branchEnc}"); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3); + curl_setopt($ch, CURLOPT_TIMEOUT, 5); + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + if ($httpCode === 200 && is_string($response)) { + $commitData = json_decode($response, true); + if (is_array($commitData)) { + if (isset($commitData['sha']) && is_string($commitData['sha'])) { + return $commitData['sha']; + } + // Be tolerant if an array is ever returned + if (isset($commitData[0]['sha']) && is_string($commitData[0]['sha'])) { + return $commitData[0]['sha']; + } + } + } + return null; }tests/e2e/Services/Functions/FunctionsBase.php (1)
274-295: Harden GitHub lookup: encode owner/repo, short timeouts, optional auth, default branch discovery, and error checks.Avoid hardcoding "main" and make this resilient to rate limits and slow networks.
Apply:
- protected function helperGetLatestCommit(string $owner, string $repository): ?string - { - $ch = curl_init("https://api.github.com/repos/{$owner}/{$repository}/commits/main"); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_HTTPHEADER, [ - 'User-Agent: Appwrite', - 'Accept: application/vnd.github.v3+json' - ]); - - $response = curl_exec($ch); - $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); - curl_close($ch); - - if ($httpCode === 200) { - $commitData = json_decode($response, true); - if (isset($commitData['sha'])) { - return $commitData['sha']; - } - } - - return null; - } + protected function helperGetLatestCommit(string $owner, string $repository): ?string + { + $ownerEnc = rawurlencode((string) $owner); + $repoEnc = rawurlencode((string) $repository); + $headers = ['User-Agent: Appwrite', 'Accept: application/vnd.github+json']; + $token = System::getEnv('GITHUB_TOKEN') ?: System::getEnv('GITHUB_API_TOKEN'); + if ($token) { + $headers[] = 'Authorization: Bearer ' . $token; + } + + // Discover default branch + $ch = curl_init("https://api.github.com/repos/{$ownerEnc}/{$repoEnc}"); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3); + curl_setopt($ch, CURLOPT_TIMEOUT, 5); + $repoResp = curl_exec($ch); + $repoCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + $branch = 'main'; + if ($repoCode === 200 && is_string($repoResp)) { + $branch = json_decode($repoResp, true)['default_branch'] ?? 'main'; + } + + // Fetch latest commit on the resolved branch + $ch = curl_init("https://api.github.com/repos/{$ownerEnc}/{$repoEnc}/commits/{$branch}"); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3); + curl_setopt($ch, CURLOPT_TIMEOUT, 5); + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + if ($httpCode === 200 && is_string($response)) { + $commitData = json_decode($response, true); + if (isset($commitData['sha']) && is_string($commitData['sha'])) { + return $commitData['sha']; + } + } + return null; + }tests/e2e/Services/Functions/FunctionsCustomServerTest.php (1)
411-416: Nice: wait for readiness before assertions.Addresses prior flakiness feedback.
🧹 Nitpick comments (5)
tests/e2e/Services/Sites/SitesBase.php (1)
336-357: Thread providerBranch into helperGetLatestCommit and dedupe duplicate helpers
- Add an optional $branch parameter to helperGetLatestCommit and use it in the GitHub URL instead of hardcoding "main".
- Update callers to pass providerBranch where available (e.g. tests/e2e/Services/Sites/SitesCustomServerTest.php:1688, tests/e2e/Services/Functions/FunctionsCustomServerTest.php:577).
- Consolidate duplicate helpers in tests/e2e/Services/Sites/SitesBase.php (≈line 336) and tests/e2e/Services/Functions/FunctionsBase.php (≈line 274) into a shared test utility to avoid drift.
tests/e2e/Services/Functions/FunctionsBase.php (1)
274-295: Deduplicate: share one helper with SitesBase.Extract this GitHub helper to a common test utility to prevent drift between FunctionsBase and SitesBase.
tests/e2e/Services/Functions/FunctionsCustomServerTest.php (3)
364-367: Guard against missing runtime match to avoid undefined offset.Add a sanity check before indexing the filtered array.
- $runtime = array_values(array_filter($starterTemplate['body']['runtimes'], function ($runtime) { - return $runtime['name'] === 'node-22'; - }))[0]; + $matches = array_values(array_filter($starterTemplate['body']['runtimes'], fn($r) => $r['name'] === 'node-22')); + $this->assertNotEmpty($matches, 'starter template is missing runtime node-22'); + $runtime = $matches[0];Also applies to: 377-377, 382-382, 386-386
548-549: Avoid hardcoded 'main' and extend wait to reduce flakes.Use template default branch when available; give builds more time.
- 'type' => 'branch', - 'reference' => 'main', + 'type' => 'branch', + 'reference' => $starterTemplate['body']['providerBranch'] ?? 'main', @@ - }, 50000, 500); + }, 100000, 500);Also applies to: 556-560
571-581: Commit test: rely on robust helper and increase wait budget.After hardening helperGetLatestCommit, bump the readiness wait to match other tests.
- }, 50000, 500); + }, 100000, 500);Also applies to: 628-631
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
tests/e2e/Services/Functions/FunctionsBase.php(1 hunks)tests/e2e/Services/Functions/FunctionsCustomServerTest.php(5 hunks)tests/e2e/Services/Sites/SitesBase.php(1 hunks)tests/e2e/Services/Sites/SitesCustomServerTest.php(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- tests/e2e/Services/Sites/SitesCustomServerTest.php
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: atharvadeosthale
PR: appwrite/appwrite#10486
File: src/Appwrite/Utopia/Request/Filters/V21.php:25-33
Timestamp: 2025-09-18T07:42:08.734Z
Learning: In Appwrite's V21 request filter for backward compatibility, clients will never send both old (`version`) and new (`type`/`reference`) parameters simultaneously - they use either the old 1.8.0 format or the new 1.8.1+ format, not a mix of both.
🧬 Code graph analysis (2)
tests/e2e/Services/Functions/FunctionsBase.php (1)
tests/e2e/Services/Sites/SitesBase.php (1)
helperGetLatestCommit(336-357)
tests/e2e/Services/Functions/FunctionsCustomServerTest.php (1)
tests/e2e/Services/Functions/FunctionsBase.php (6)
getDeployment(160-168)getTemplate(264-272)createFunction(80-88)createTemplateDeployment(244-252)cleanupFunction(69-78)helperGetLatestCommit(274-295)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Setup & Build Appwrite Image
- GitHub Check: Setup & Build SDK
- GitHub Check: Setup & Build Appwrite Image
- GitHub Check: scan
🔇 Additional comments (3)
tests/e2e/Services/Sites/SitesBase.php (1)
336-357: Good extraction into a helper; preserves getTemplate’s contract.Moving GitHub lookup out of getTemplate aligns with the API mirroring requirement and unblocks template changes.
tests/e2e/Services/Functions/FunctionsCustomServerTest.php (2)
403-405: Typed template deployment (tag) looks good.Using type=tag with reference=providerVersion aligns with the new API.
418-425: Good: verify non-zero sizes and total equals sum.Solid assertions to prevent regressions in size accounting.
Also applies to: 434-435
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
tests/e2e/General/UsageTest.php (1)
45-76: Keep alias symmetry and drop duplicate alias lines in trait adaptationsFor consistency with other methods, also alias the SitesBase variant, and remove repeated alias lines to reduce noise.
use SitesBase { FunctionsBase::createDeployment insteadof SitesBase; FunctionsBase::setupDeployment insteadof SitesBase; FunctionsBase::createVariable insteadof SitesBase; FunctionsBase::getVariable insteadof SitesBase; FunctionsBase::listVariables insteadof SitesBase; FunctionsBase::helperGetLatestCommit insteadof SitesBase; FunctionsBase::updateVariable insteadof SitesBase; FunctionsBase::deleteVariable insteadof SitesBase; FunctionsBase::getDeployment insteadof SitesBase; FunctionsBase::listDeployments insteadof SitesBase; FunctionsBase::deleteDeployment insteadof SitesBase; FunctionsBase::setupDuplicateDeployment insteadof SitesBase; FunctionsBase::createDuplicateDeployment insteadof SitesBase; FunctionsBase::createTemplateDeployment insteadof SitesBase; FunctionsBase::getUsage insteadof SitesBase; FunctionsBase::getTemplate insteadof SitesBase; FunctionsBase::getDeploymentDownload insteadof SitesBase; FunctionsBase::cancelDeployment insteadof SitesBase; FunctionsBase::listSpecifications insteadof SitesBase; SitesBase::createDeployment as createDeploymentSite; SitesBase::setupDeployment as setupDeploymentSite; SitesBase::createVariable as createVariableSite; SitesBase::getVariable as getVariableSite; - SitesBase::listVariables as listVariablesSite; - SitesBase::listVariables as listVariablesSite; + SitesBase::listVariables as listVariablesSite; + SitesBase::helperGetLatestCommit as helperGetLatestCommitSite; - SitesBase::updateVariable as updateVariableSite; - SitesBase::updateVariable as updateVariableSite; + SitesBase::updateVariable as updateVariableSite; - SitesBase::deleteVariable as deleteVariableSite; - SitesBase::deleteVariable as deleteVariableSite; + SitesBase::deleteVariable as deleteVariableSite; - SitesBase::getDeployment as getDeploymentSite; - SitesBase::getDeployment as getDeploymentSite; + SitesBase::getDeployment as getDeploymentSite; - SitesBase::listDeployments as listDeploymentsSite; - SitesBase::listDeployments as listDeploymentsSite; + SitesBase::listDeployments as listDeploymentsSite; - SitesBase::deleteDeployment as deleteDeploymentSite; - SitesBase::deleteDeployment as deleteDeploymentSite; + SitesBase::deleteDeployment as deleteDeploymentSite; - SitesBase::setupDuplicateDeployment as setupDuplicateDeploymentSite; - SitesBase::setupDuplicateDeployment as setupDuplicateDeploymentSite; + SitesBase::setupDuplicateDeployment as setupDuplicateDeploymentSite; - SitesBase::createDuplicateDeployment as createDuplicateDeploymentSite; - SitesBase::createDuplicateDeployment as createDuplicateDeploymentSite; + SitesBase::createDuplicateDeployment as createDuplicateDeploymentSite; - SitesBase::createTemplateDeployment as createTemplateDeploymentSite; - SitesBase::createTemplateDeployment as createTemplateDeploymentSite; + SitesBase::createTemplateDeployment as createTemplateDeploymentSite; - SitesBase::getUsage as getUsageSite; - SitesBase::getUsage as getUsageSite; + SitesBase::getUsage as getUsageSite; - SitesBase::getTemplate as getTemplateSite; - SitesBase::getTemplate as getTemplateSite; + SitesBase::getTemplate as getTemplateSite; - SitesBase::getDeploymentDownload as getDeploymentDownloadSite; - SitesBase::getDeploymentDownload as getDeploymentDownloadSite; + SitesBase::getDeploymentDownload as getDeploymentDownloadSite; - SitesBase::cancelDeployment as cancelDeploymentSite; - SitesBase::cancelDeployment as cancelDeploymentSite; + SitesBase::cancelDeployment as cancelDeploymentSite; SitesBase::listSpecifications as listSpecificationsSite; }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
tests/e2e/General/UsageTest.php(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: atharvadeosthale
PR: appwrite/appwrite#10486
File: src/Appwrite/Utopia/Request/Filters/V21.php:25-33
Timestamp: 2025-09-18T07:42:08.734Z
Learning: In Appwrite's V21 request filter for backward compatibility, clients will never send both old (`version`) and new (`type`/`reference`) parameters simultaneously - they use either the old 1.8.0 format or the new 1.8.1+ format, not a mix of both.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
- GitHub Check: E2E Service Test (Tokens)
- GitHub Check: E2E Service Test (Migrations)
- GitHub Check: E2E Service Test (Messaging)
- GitHub Check: E2E Service Test (Teams)
- GitHub Check: E2E Service Test (Webhooks)
- GitHub Check: E2E Service Test (Storage)
- GitHub Check: E2E Service Test (Realtime)
- GitHub Check: E2E Service Test (Locale)
- GitHub Check: E2E Service Test (Avatars)
- GitHub Check: E2E Service Test (Projects)
- GitHub Check: E2E Service Test (Functions)
- GitHub Check: E2E Service Test (Health)
- GitHub Check: E2E Service Test (Databases/Legacy)
- GitHub Check: E2E Service Test (Account)
- GitHub Check: E2E General Test
- GitHub Check: Unit Test
- GitHub Check: E2E Service Test (Site Screenshots)
- GitHub Check: E2E Service Test (Dev Keys)
- GitHub Check: Setup & Build SDK
- GitHub Check: scan
🔇 Additional comments (1)
tests/e2e/General/UsageTest.php (1)
31-31: LGTM — prefer FunctionsBase::helperGetLatestCommit; confirm implementations matchBoth helpers are defined (FunctionsBase: tests/e2e/Services/Functions/FunctionsBase.php:274; SitesBase: tests/e2e/Services/Sites/SitesBase.php:336) and are used from the corresponding *CustomServerTest.php files. Sandbox extraction failed to produce a reliable diff of the full function bodies — run a local diff to confirm behavioral parity, e.g.:
sed -n '/protected function helperGetLatestCommit/,/}/p' tests/e2e/Services/Functions/FunctionsBase.php > /tmp/fn1 && sed -n '/protected function helperGetLatestCommit/,/}/p' tests/e2e/Services/Sites/SitesBase.php > /tmp/fn2 && diff -u /tmp/fn1 /tmp/fn2
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (2)
tests/e2e/Services/Functions/FunctionsCustomServerTest.php (2)
418-425: Addresses prior ask: verify non‑zero sizes and totalNice addition; this covers readiness and size integrity.
503-504: Resolved: don’t assign result of void cleanupFunction()Assignment removed; this fixes the fatal noted earlier.
🧹 Nitpick comments (13)
tests/e2e/Services/Functions/FunctionsCustomServerTest.php (13)
364-367: Guard against missing runtime before indexingarray_filter can return an empty array; indexing [0] would raise a notice/fatal. Assert non‑empty before dereferencing.
Apply this diff:
-$runtime = array_values(array_filter($starterTemplate['body']['runtimes'], function ($runtime) { - return $runtime['name'] === 'node-22'; -}))[0]; +$runtimes = array_values(array_filter($starterTemplate['body']['runtimes'], function ($runtime) { + return $runtime['name'] === 'node-22'; +})); +$this->assertNotEmpty($runtimes, 'node-22 runtime not found in template runtimes'); +$runtime = $runtimes[0];
411-417: Also assert HTTP 200 inside the polling closureAdds early signal if the resource vanishes or returns errors instead of silently looping.
$this->assertEventually(function () use ($functionId, $deploymentId) { $deployment = $this->getDeployment($functionId, $deploymentId); - $this->assertEquals('ready', $deployment['body']['status']); + $this->assertEquals(200, $deployment['headers']['status-code']); + $this->assertEquals('ready', $deployment['body']['status']); }, 50000, 500);
433-435: Also assert buildSize on the list viewValidates parity between single‑item GET and list results.
$this->assertNotEmpty($lastDeployment['$id']); $this->assertGreaterThan(0, $lastDeployment['sourceSize']); +$this->assertGreaterThan(0, $lastDeployment['buildSize']);
506-531: Mark network/VCS test retriable to reduce flakinessBranch deployments can be slow or transient; add Retry to smooth CI flakes.
+#[Retry(count: 3)] public function testCreateFunctionAndDeploymentFromTemplateBranch()
538-550: Avoid hardcoding 'main' branchPrefer the template’s default branch (if exposed in the template payload) and fall back to 'main' only if not present. Please confirm the field name in the response (e.g., a “default branch” field) and use it here.
Would you verify the template response exposes a default-branch field and wire it in here instead of the literal 'main'?
561-567: Assert deployment type is 'vcs'Completes validation that the new VCS flow is used.
$deployment = $this->getDeployment($functionId, $deploymentId); $this->assertEquals(200, $deployment['headers']['status-code']); $this->assertGreaterThan(0, $deployment['body']['sourceSize']); $this->assertGreaterThan(0, $deployment['body']['buildSize']); $totalSize = $deployment['body']['sourceSize'] + $deployment['body']['buildSize']; $this->assertEquals($totalSize, $deployment['body']['totalSize']); +$this->assertEquals('vcs', $deployment['body']['type']);
576-582: External GitHub call: add token support and retries in helperUnauthenticated GitHub API calls are rate‑limited and can flake. Enhance helperGetLatestCommit to use GITHUB_TOKEN if present and retry a few times.
Proposed helper tweak (in tests/e2e/Services/Functions/FunctionsBase.php):
$ch = curl_init("https://api.github.com/repos/{$owner}/{$repository}/commits/main"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $headers = ['User-Agent: Appwrite', 'Accept: application/vnd.github.v3+json']; if ($token = getenv('GITHUB_TOKEN')) { $headers[] = "Authorization: Bearer {$token}"; } curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); // simple retry for ($i = 0; $i < 3; $i++) { $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); if ($httpCode === 200 && $response) break; usleep(250000); }Optionally also add #[Retry(count: 3)] to this test, like the branch test.
583-586: Same runtime guard hereReplicate the empty‑check before indexing as above.
-$runtime = array_values(array_filter($starterTemplate['body']['runtimes'], function ($runtime) { - return $runtime['name'] === 'node-22'; -}))[0]; +$runtimes = array_values(array_filter($starterTemplate['body']['runtimes'], function ($runtime) { + return $runtime['name'] === 'node-22'; +})); +$this->assertNotEmpty($runtimes, 'node-22 runtime not found in template runtimes'); +$runtime = $runtimes[0];
610-622: Assert deployment type is 'vcs' for commit flowMirror the branch test and confirm the new flow.
$deployment = $this->createTemplateDeployment( $functionId, [ 'resourceId' => ID::unique(), 'activate' => true, 'repository' => $starterTemplate['body']['providerRepositoryId'], 'owner' => $starterTemplate['body']['providerOwner'], 'rootDirectory' => $runtime['providerRootDirectory'], 'type' => 'commit', 'reference' => $latestCommit, ] );After readiness and size checks, add:
$this->assertEquals('vcs', $deployment['body']['type']);
627-632: Also assert HTTP 200 in the wait loopConsistent with other suggestions.
$this->assertEventually(function () use ($functionId, $deploymentId) { $deployment = $this->getDeployment($functionId, $deploymentId); - $this->assertEquals('ready', $deployment['body']['status']); + $this->assertEquals(200, $deployment['headers']['status-code']); + $this->assertEquals('ready', $deployment['body']['status']); }, 50000, 500);
633-639: Optionally assert function.active deployment equals this deploymentEnsures the activation flag took effect.
$deployment = $this->getDeployment($functionId, $deploymentId); $this->assertEquals(200, $deployment['headers']['status-code']); $this->assertGreaterThan(0, $deployment['body']['sourceSize']); $this->assertGreaterThan(0, $deployment['body']['buildSize']); $totalSize = $deployment['body']['sourceSize'] + $deployment['body']['buildSize']; $this->assertEquals($totalSize, $deployment['body']['totalSize']); + +$function = $this->getFunction($functionId); +$this->assertEquals(200, $function['headers']['status-code']); +$this->assertEquals($deploymentId, $function['body']['deploymentId']);
511-514: Repeat runtime guard in Branch testSame undefined‑offset risk; add the non‑empty assertion before [0] access.
-$runtime = array_values(array_filter($starterTemplate['body']['runtimes'], function ($runtime) { - return $runtime['name'] === 'node-22'; -}))[0]; +$runtimes = array_values(array_filter($starterTemplate['body']['runtimes'], function ($runtime) { + return $runtime['name'] === 'node-22'; +})); +$this->assertNotEmpty($runtimes, 'node-22 runtime not found in template runtimes'); +$runtime = $runtimes[0];
506-506: Add Retry attribute to both VCS template testsBoth paths hit external providers; make both retriable.
+#[Retry(count: 3)] public function testCreateFunctionAndDeploymentFromTemplateBranch()+#[Retry(count: 3)] public function testCreateFunctionAndDeploymentFromTemplateCommit()Also applies to: 571-571
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
tests/e2e/Services/Functions/FunctionsCustomServerTest.php(5 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
tests/e2e/Services/Functions/FunctionsCustomServerTest.php (1)
tests/e2e/Services/Functions/FunctionsBase.php (6)
getDeployment(160-168)cleanupFunction(69-78)getTemplate(264-272)createFunction(80-88)createTemplateDeployment(244-252)helperGetLatestCommit(274-295)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (19)
- GitHub Check: E2E Service Test (Sites)
- GitHub Check: E2E Service Test (VCS)
- GitHub Check: E2E Service Test (Users)
- GitHub Check: E2E Service Test (Locale)
- GitHub Check: E2E Service Test (Teams)
- GitHub Check: E2E Service Test (Tokens)
- GitHub Check: E2E Service Test (Projects)
- GitHub Check: E2E Service Test (Health)
- GitHub Check: E2E Service Test (Databases/Legacy)
- GitHub Check: E2E Service Test (Databases/TablesDB)
- GitHub Check: E2E Service Test (Account)
- GitHub Check: E2E Service Test (Console)
- GitHub Check: E2E General Test
- GitHub Check: E2E Service Test (Site Screenshots)
- GitHub Check: E2E Service Test (Dev Keys)
- GitHub Check: Unit Test
- GitHub Check: Benchmark
- GitHub Check: Setup & Build SDK
- GitHub Check: scan
🔇 Additional comments (2)
tests/e2e/Services/Functions/FunctionsCustomServerTest.php (2)
377-377: LGTM: using runtime-derived entrypoint/commands/rootDirectoryThis aligns function config with the selected runtime metadata.
Also applies to: 382-382, 386-386
402-405: Template deployment via (type, reference) — goodUsing type=tag with provider version is correct for the tag flow.
src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php
Outdated
Show resolved
Hide resolved
src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (4)
src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php (2)
71-72: Make type and reference required parameters.The empty-string defaults allow these parameters to be omitted or empty, but the endpoint requires both for correct behavior. Remove the defaults to make them required and prevent empty values from reaching the action.
Apply this diff:
- ->param('type', '', new WhiteList(['branch', 'commit', 'tag']), 'Type for the reference provided. Can be commit, branch, or tag') - ->param('reference', '', new Text(128, 0), 'Reference value, can be a commit hash, branch name, or release tag') + ->param('type', null, new WhiteList(['branch', 'commit', 'tag'], required: true), 'Type for the reference provided. Can be commit, branch, or tag') + ->param('reference', null, new Text(128, 1), 'Reference value, can be a commit hash, branch name, or release tag')
167-174: Use strict comparison for type checks.Line 171 uses loose equality (
==) which can lead to unexpected type coercion. Use strict comparison (===) to ensure exact match.Apply this diff:
'providerRepositoryName' => $repository, 'providerRepositoryOwner' => $owner, 'providerRepositoryUrl' => $repositoryUrl, 'providerBranchUrl' => $branchUrl, - 'providerBranch' => $type == GitHub::CLONE_TYPE_BRANCH ? $reference : '', + 'providerBranch' => $type === GitHub::CLONE_TYPE_BRANCH ? $reference : '', 'adapter' => $site->getAttribute('adapter', ''), 'fallbackFile' => $site->getAttribute('fallbackFile', ''), 'type' => 'vcs',src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php (2)
69-70: Make type and reference required parameters.The empty-string defaults allow these parameters to be omitted or empty, but the endpoint requires both for correct behavior. Remove the defaults to make them required and prevent empty values from reaching the action.
Apply this diff:
- ->param('type', '', new WhiteList(['commit', 'branch', 'tag']), 'Type for the reference provided. Can be commit, branch, or tag') - ->param('reference', '', new Text(128, 0), 'Reference value, can be a commit hash, branch name, or release tag') + ->param('type', null, new WhiteList(['commit', 'branch', 'tag'], required: true), 'Type for the reference provided. Can be commit, branch, or tag') + ->param('reference', null, new Text(128, 1), 'Reference value, can be a commit hash, branch name, or release tag')
157-162: Use strict comparison for type checks.Line 161 uses loose equality (
==) which can lead to unexpected type coercion. Use strict comparison (===) to ensure exact match.Apply this diff:
'providerRepositoryName' => $repository, 'providerRepositoryOwner' => $owner, 'providerRepositoryUrl' => $repositoryUrl, 'providerBranchUrl' => $branchUrl, - 'providerBranch' => $type == GitHub::CLONE_TYPE_BRANCH ? $reference : '', + 'providerBranch' => $type === GitHub::CLONE_TYPE_BRANCH ? $reference : '', 'type' => 'vcs', 'activate' => $activate,
🧹 Nitpick comments (2)
src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php (1)
108-109: Build branchUrl only for branch references; use blob path for all types.Currently
branchUrlis built for all reference types. However, based on maintainer feedback, GitHub'sblobpath works for commits, branches, and tags. Consider renaming to reflect this, or verify the URL is appropriate for the given type.For example:
- $branchUrl = "https://github.com/$owner/$repository/blob/$reference"; + $referenceUrl = "https://github.com/$owner/$repository/blob/$reference"; $repositoryUrl = "https://github.com/$owner/$repository";Then update the deployment payload field name accordingly. Alternatively, keep
branchUrlas-is if the field semantics are intentionally broader.src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php (1)
106-108: Build branchUrl only for branch references; use blob path for all types.Currently
branchUrlis built for all reference types. However, based on maintainer feedback, GitHub'sblobpath works for commits, branches, and tags. Consider renaming to reflect this, or verify the URL is appropriate for the given type.For example:
- $branchUrl = "https://github.com/$owner/$repository/blob/$reference"; - + $referenceUrl = "https://github.com/$owner/$repository/blob/$reference"; $repositoryUrl = "https://github.com/$owner/$repository";Then update the deployment payload field name accordingly. Alternatively, keep
branchUrlas-is if the field semantics are intentionally broader.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php(5 hunks)src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php(5 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: atharvadeosthale
Repo: appwrite/appwrite PR: 10486
File: src/Appwrite/Utopia/Request/Filters/V21.php:25-33
Timestamp: 2025-09-18T07:42:08.734Z
Learning: In Appwrite's V21 request filter for backward compatibility, clients will never send both old (`version`) and new (`type`/`reference`) parameters simultaneously - they use either the old 1.8.0 format or the new 1.8.1+ format, not a mix of both.
📚 Learning: 2025-09-18T07:42:08.734Z
Learnt from: atharvadeosthale
Repo: appwrite/appwrite PR: 10486
File: src/Appwrite/Utopia/Request/Filters/V21.php:25-33
Timestamp: 2025-09-18T07:42:08.734Z
Learning: In Appwrite's V21 request filter for backward compatibility, clients will never send both old (`version`) and new (`type`/`reference`) parameters simultaneously - they use either the old 1.8.0 format or the new 1.8.1+ format, not a mix of both.
Applied to files:
src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php
📚 Learning: 2025-05-12T06:05:27.133Z
Learnt from: abnegate
Repo: appwrite/appwrite PR: 9743
File: src/Appwrite/Utopia/Request.php:33-36
Timestamp: 2025-05-12T06:05:27.133Z
Learning: In Appwrite's architecture, the Request class should only filter parameters when filters are explicitly registered. If no filters are present, all parameters should be passed through, and the route action is responsible for validating which parameters are present/valid.
Applied to files:
src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php
📚 Learning: 2025-05-12T06:07:51.470Z
Learnt from: abnegate
Repo: appwrite/appwrite PR: 9743
File: src/Appwrite/Utopia/Request.php:0-0
Timestamp: 2025-05-12T06:07:51.470Z
Learning: In Appwrite's request handling architecture, the Request::getParams() method selects which SDK method to use based on parameter matching, but does not validate required parameters. The action execution flow handles parameter validation separately. This separation of concerns allows for more flexible handling of multi-method routes.
Applied to files:
src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php
🧬 Code graph analysis (2)
src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
param(254-355)
src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
param(254-355)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Setup & Build SDK
- GitHub Check: Setup & Build Appwrite Image
- GitHub Check: Setup & Build Appwrite Image
- GitHub Check: scan
🔇 Additional comments (2)
src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php (1)
115-116: Template payload correctly uses referenceType and referenceValue.The template document now stores the new reference model instead of the legacy
versionfield.src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php (1)
114-115: Template payload correctly uses referenceType and referenceValue.The template document now stores the new reference model instead of the legacy
versionfield.
Edited template deployment route which now accepts
owner,repository,type,reference