Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions .github/workflows/tests-external.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,16 @@ permissions:

jobs:
tests:
name: Tests (External)
name: ${{ matrix.adapter }}
runs-on: ubuntu-latest

if: github.event.label.name == 'test'

strategy:
fail-fast: false
matrix:
adapter: [gitea, forgejo, github, gitlab, gogs]

steps:
- name: Check out the repo
uses: actions/checkout@v4
Expand All @@ -26,15 +31,15 @@ jobs:
TESTS_GITHUB_APP_IDENTIFIER: ${{ secrets.TESTS_GITHUB_APP_IDENTIFIER }}
TESTS_GITHUB_INSTALLATION_ID: ${{ secrets.TESTS_GITHUB_INSTALLATION_ID }}
run: |
docker compose up -d
docker compose --profile ${{ matrix.adapter }} up -d
sleep 15

- name: Doctor
run: |
docker compose logs
docker compose --profile ${{ matrix.adapter }} logs
docker ps
docker network ls

- name: Run Tests
run: |
docker compose exec -T tests vendor/bin/phpunit --configuration phpunit.xml tests
docker compose exec -T tests vendor/bin/phpunit --configuration phpunit.xml --testsuite ${{ matrix.adapter }}
13 changes: 9 additions & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@ permissions:

jobs:
tests:
name: Tests
name: ${{ matrix.adapter }}
runs-on: ubuntu-latest
if: github.event.pull_request.head.repo.full_name == github.repository

strategy:
fail-fast: false
matrix:
adapter: [gitea, forgejo, github, gitlab, gogs]

steps:
- name: Check out the repo
uses: actions/checkout@v4
Expand All @@ -22,15 +27,15 @@ jobs:
TESTS_GITHUB_APP_IDENTIFIER: ${{ secrets.TESTS_GITHUB_APP_IDENTIFIER }}
TESTS_GITHUB_INSTALLATION_ID: ${{ secrets.TESTS_GITHUB_INSTALLATION_ID }}
run: |
docker compose up -d
docker compose --profile ${{ matrix.adapter }} up -d
sleep 15

- name: Doctor
run: |
docker compose logs
docker compose --profile ${{ matrix.adapter }} logs
docker ps
docker network ls

- name: Run Tests
run: |
docker compose exec -T tests vendor/bin/phpunit --configuration phpunit.xml tests
docker compose exec -T tests vendor/bin/phpunit --configuration phpunit.xml --testsuite ${{ matrix.adapter }}
24 changes: 24 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,30 @@ This will allow the Utopia-php community to have sufficient discussion about the

This is also important for the Utopia-php lead developers to be able to give technical input and different emphasis regarding the feature design and architecture. Some bigger features might need to go through our [RFC process](https://github.com/appwrite/rfc).

## Running Tests

Tests are split by adapter. Each adapter has its own Docker Compose profile and PHPUnit test suite.

To start the stack and run tests for a specific adapter:

```bash
docker compose --profile <adapter> up -d
sleep 15
docker compose exec -T tests vendor/bin/phpunit --configuration phpunit.xml --testsuite <adapter>
```

Where `<adapter>` is one of: `gitea`, `forgejo`, `github`, `gitlab`, `gogs`.

For example, to run Gitea tests:

```bash
docker compose --profile gitea up -d
sleep 15
docker compose exec -T tests vendor/bin/phpunit --configuration phpunit.xml --testsuite gitea
```

The `github` adapter does not require any local services — only the GitHub secrets (`TESTS_GITHUB_PRIVATE_KEY`, `TESTS_GITHUB_APP_IDENTIFIER`, `TESTS_GITHUB_INSTALLATION_ID`) as environment variables.

## Adding A New Adapter

You can follow our [Adding new VCS Adapter](docs/add-new-vcs-adapter.md) tutorial to add a new VCS adapter like GitLab, Bitbucket etc. in this library.
Expand Down
46 changes: 38 additions & 8 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,32 @@ services:
- TESTS_GITLAB_URL=http://gitlab:80
depends_on:
gitea:
condition: service_healthy
condition: service_started
required: false
gitea-bootstrap:
condition: service_completed_successfully
required: false
forgejo:
condition: service_healthy
condition: service_started
required: false
forgejo-bootstrap:
condition: service_completed_successfully
required: false
gogs:
condition: service_healthy
condition: service_started
required: false
gogs-bootstrap:
condition: service_completed_successfully
required: false
gitlab:
condition: service_healthy
condition: service_started
required: false
gitlab-bootstrap:
condition: service_completed_successfully
request-catcher:
required: false
request-catcher:
condition: service_started
required: false

gitea:
image: gitea/gitea:1.21.5
Expand All @@ -46,7 +55,7 @@ services:
- USER_GID=1000
- GITEA__database__DB_TYPE=sqlite3
- GITEA__security__INSTALL_LOCK=true
- GITEA__webhook__ALLOWED_HOST_LIST=*
- GITEA__webhook__ALLOWED_HOST_LIST=*
- GITEA__webhook__SKIP_TLS_VERIFY=true
- GITEA__webhook__DELIVER_TIMEOUT=10
- GITEA__server__LOCAL_ROOT_URL=http://gitea:3000/
Expand All @@ -60,6 +69,8 @@ services:
timeout: 5s
retries: 10
start_period: 10s
profiles:
- gitea

gitea-bootstrap:
image: gitea/gitea:1.21.5
Expand All @@ -81,10 +92,17 @@ services:
echo $$TOKEN > /data/gitea/token.txt;
fi
"
request-catcher:
profiles:
- gitea

request-catcher:
image: appwrite/requestcatcher:1.1.0
ports:
- "5000:5000"
profiles:
- gitea
- forgejo
- gogs

forgejo:
image: codeberg.org/forgejo/forgejo:9
Expand All @@ -105,6 +123,8 @@ services:
timeout: 5s
retries: 10
start_period: 10s
profiles:
- forgejo

forgejo-bootstrap:
image: codeberg.org/forgejo/forgejo:9
Expand All @@ -126,6 +146,8 @@ services:
echo $$TOKEN > /data/gitea/token.txt;
fi
"
profiles:
- forgejo

gogs:
image: gogs/gogs:0.14
Expand All @@ -140,6 +162,8 @@ services:
timeout: 5s
retries: 10
start_period: 15s
profiles:
- gogs

gogs-bootstrap:
image: gogs/gogs:0.14
Expand Down Expand Up @@ -177,6 +201,8 @@ services:
mkdir -p /data/gogs
echo $$TOKEN > /data/gogs/token.txt
fi
profiles:
- gogs

gitlab:
image: gitlab/gitlab-ce:18.10.1-ce.0
Expand All @@ -194,6 +220,8 @@ services:
timeout: 10s
retries: 20
start_period: 300s
profiles:
- gitlab

gitlab-bootstrap:
image: alpine/curl:8.12.1
Expand Down Expand Up @@ -241,9 +269,11 @@ services:
if [ -z "$$TOKEN" ]; then echo "Failed to get token"; exit 1; fi
mkdir -p /gitlab-data
echo $$TOKEN > /gitlab-data/token.txt
profiles:
- gitlab

volumes:
gitea-data:
forgejo-data:
gogs-data:
gitlab-data:
gitlab-data:
18 changes: 15 additions & 3 deletions phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,20 @@
stopOnFailure="false"
>
<testsuites>
<testsuite name="Application Test Suite">
<directory>./tests/</directory>
<testsuite name="gitea">
<file>./tests/VCS/Adapter/GiteaTest.php</file>
</testsuite>
<testsuite name="forgejo">
<file>./tests/VCS/Adapter/ForgejoTest.php</file>
</testsuite>
<testsuite name="github">
<file>./tests/VCS/Adapter/GitHubTest.php</file>
</testsuite>
<testsuite name="gitlab">
<file>./tests/VCS/Adapter/GitLabTest.php</file>
</testsuite>
<testsuite name="gogs">
<file>./tests/VCS/Adapter/GogsTest.php</file>
</testsuite>
</testsuites>
</phpunit>
</phpunit>
8 changes: 6 additions & 2 deletions src/VCS/Adapter/Git/GitLab.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,9 @@ public function createRepository(string $owner, string $repositoryName, bool $pr
if ($statusCode >= 400) {
throw new Exception("Creating repository {$repositoryName} failed with status code {$statusCode}");
}
return is_array($body) ? $body : [];
$result = is_array($body) ? $body : [];
$result['pushed_at'] = $result['last_activity_at'] ?? '';
return $result;
}

public function deleteRepository(string $owner, string $repositoryName): bool
Expand Down Expand Up @@ -152,7 +154,9 @@ public function getRepository(string $owner, string $repositoryName): array
throw new RepositoryNotFound("Repository not found");
}

return $response['body'] ?? [];
$result = $response['body'] ?? [];
$result['pushed_at'] = $result['last_activity_at'] ?? '';
return $result;
}


Expand Down
9 changes: 7 additions & 2 deletions src/VCS/Adapter/Git/Gitea.php
Original file line number Diff line number Diff line change
Expand Up @@ -724,7 +724,8 @@ public function listBranches(string $owner, string $repositoryName): array
for ($currentPage = 1; $currentPage <= $maxPages; $currentPage++) {
$url = "/repos/{$owner}/{$repositoryName}/branches?page={$currentPage}&limit={$perPage}";

$response = $this->call(self::METHOD_GET, $url, ['Authorization' => "token $this->accessToken"]);
// We decode ourselves later, because there is edge-case when Gitea returns empty body instead of empty array
$response = $this->call(self::METHOD_GET, $url, ['Authorization' => "token $this->accessToken"], decode: false);

$responseHeaders = $response['headers'] ?? [];
$responseHeadersStatusCode = $responseHeaders['status-code'] ?? 0;
Expand All @@ -740,7 +741,7 @@ public function listBranches(string $owner, string $repositoryName): array
break;
}

$responseBody = $response['body'] ?? [];
$responseBody = \json_decode($response['body'] ?? '', true) ?? [];

if (!is_array($responseBody)) {
break;
Expand Down Expand Up @@ -896,6 +897,10 @@ public function updateCommitStatus(string $repositoryName, string $commitHash, s
*/
public function generateCloneCommand(string $owner, string $repositoryName, string $version, string $versionType, string $directory, string $rootDirectory): string
{
if (empty($rootDirectory)) {
$rootDirectory = '*';
}

$cloneUrl = "{$this->giteaUrl}/{$owner}/{$repositoryName}";
if (!empty($this->accessToken)) {
$cloneUrl = str_replace('://', "://{$owner}:{$this->accessToken}@", $this->giteaUrl) . "/{$owner}/{$repositoryName}";
Expand Down
7 changes: 7 additions & 0 deletions tests/VCS/Adapter/GitHubTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ public function testGetRepository(): void
$repo = $this->vcsAdapter->getRepository($owner, $repositoryName);
$this->assertIsArray($repo);
$this->assertSame($repositoryName, $repo['name']);
$this->assertArrayHasKey('pushed_at', $repo);
$this->assertNotFalse(\strtotime($repo['pushed_at']));
}

public function testGetRepositoryName(): void
Expand Down Expand Up @@ -474,4 +476,9 @@ public function testGetLatestCommit(): void
$this->assertSame('https://avatars.githubusercontent.com/in/287220?v=4', $commitDetails['commitAuthorAvatar']);
$this->assertSame('https://github.com/apps/appwritedemoapp', $commitDetails['commitAuthorUrl']);
}

public function testListBranchesEmptyRepo(): void
{
$this->markTestSkipped('GitHub creates a default branch on repository creation');
}
}
4 changes: 4 additions & 0 deletions tests/VCS/Adapter/GitLabTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ public function testCreateRepository(): void
$this->assertArrayHasKey('name', $result);
$this->assertSame($repositoryName, $result['name']);
$this->assertFalse($result['visibility'] === 'private');
$this->assertArrayHasKey('pushed_at', $result);
$this->assertNotFalse(\strtotime($result['pushed_at']));
} finally {
$this->vcsAdapter->deleteRepository(static::$owner, $repositoryName);
}
Expand All @@ -89,6 +91,8 @@ public function testGetRepository(): void

$this->assertIsArray($result);
$this->assertSame($repositoryName, $result['name']);
$this->assertArrayHasKey('pushed_at', $result);
$this->assertNotFalse(\strtotime($result['pushed_at']));
} finally {
$this->vcsAdapter->deleteRepository(static::$owner, $repositoryName);
}
Expand Down
7 changes: 7 additions & 0 deletions tests/VCS/Adapter/GiteaTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ public function testCreateRepository(): void
$this->assertArrayHasKey('owner', $result);
$this->assertSame($owner, $result['owner']['login']);
$this->assertFalse($result['private']);
$this->assertArrayHasKey('pushed_at', $result);
$this->assertNotFalse(\strtotime($result['pushed_at']));

$this->assertTrue($this->vcsAdapter->deleteRepository(static::$owner, $repositoryName));
}
Expand Down Expand Up @@ -238,6 +240,8 @@ public function testGetRepository(): void
$this->assertIsArray($result);
$this->assertSame($repositoryName, $result['name']);
$this->assertSame(static::$owner, $result['owner']['login']);
$this->assertArrayHasKey('pushed_at', $result);
$this->assertNotFalse(\strtotime($result['pushed_at']));
$this->assertTrue($this->vcsAdapter->deleteRepository(static::$owner, $repositoryName));
}

Expand Down Expand Up @@ -1111,6 +1115,9 @@ public function testSearchRepositories(): void
$repoNames = array_column($result['items'], 'name');
$this->assertContains($repo1Name, $repoNames);
$this->assertContains($repo2Name, $repoNames);

$this->assertArrayHasKey('pushed_at', $result['items'][0]);
$this->assertNotFalse(\strtotime($result['items'][0]['pushed_at']));
} finally {
$this->vcsAdapter->deleteRepository(static::$owner, $repo1Name);
$this->vcsAdapter->deleteRepository(static::$owner, $repo2Name);
Expand Down
Loading
Loading