Skip to content

Commit

Permalink
Tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanpisa committed Jun 15, 2023
1 parent 474a0b6 commit d45d4d7
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 84 deletions.
63 changes: 63 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,67 @@
[![Rockero](https://img.shields.io/badge/Rockero-yellow)](https://rockero.cz)
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE)

Our deployer simplifies management of your staging and development client sites on your `Forge` server by allowing easy deployment of dev/staging branches and pull requests.

If your repository's site does not exist in Forge, our deployer will automatically create the site and handle the initial setup with repository, database, and environment.

**URL examples of deployed applications:**

For `main` branch:

```bash
https://{your-application}.dev.{your-domain}.com
```

For `staging` branch:

```bash
https://{your-application}.staging.{your-domain}.com
```

For pull requests:

```bash
https://{your-application}-{pull-request-number}.dev.{your-domain}.com
```

## Setup

1. Begin by creating a new repository in your GitHub account and use this repostitory as the template.

2. Next, create a new `Forge` site for the deployer and perform the initial deployment.

3. To configure your project, please fill in the required values for your `.env` file below:

```
# Your custom deployer token for requests verification, you will use it in GitHub workflows.
DEPLOYER_TOKEN=
# Credentials of your `Forge` and also ID of the server, where you would like to have your dev/staging sites.
FORGE_API_KEY=
FORGE_SERVER_ID=
FORGE_DOMAIN=
# GitHub tokens are used to automatically add comments with application URLs to your pull requests.
GITHUB_OWNER=
GITHUB_TOKEN=
```

4. Add the following job to your GitHub workflows using the code below:

```yaml
deploy:
runs-on: ubuntu-latest

steps:
- name: Deployment
uses: fjogeleit/http-request-action@master
with:
url: "http://your-deployer.com/deploy/${{ github.event.repository.name }}/event/${{ github.event_name }}"
method: "POST"
bearerToken: ${{ secrets.YOUR_DEPLOYER_TOKEN }}
timeout: 600000
data: '{"branch": "${{ github.ref_name }}", "number": "${{ github.event.pull_request.number }}"}'
```

The deployer is now ready to deploy your commits upon request. Happy deploying!
7 changes: 4 additions & 3 deletions app/Actions/DeployPullRequestAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ class DeployPullRequestAction
public function run(Server $server, string $repository, string|int $number): ?Site
{
$pullRequest = Http::github()->get('repos/' . config('services.github.owner') . '/' . $repository . '/pulls/' . $number)->json();
$url = $pullRequest['id'] . '.dev.' . config('services.forge.domain');
$pullRequestId = $pullRequest['id'];
$url = "{$repository}-{$pullRequestId}.dev." . config('services.forge.domain');

if ($site = $server->site($url)) {
return $site->deploySite();
return $site->deploySite(false);
}

$initialDeployment = new InitialDeployment($url, $pullRequest['id'], $repository, $pullRequest['base']['ref']);
$initialDeployment = new InitialDeployment($url, $pullRequestId, $repository, $pullRequest['base']['ref']);
$site = $this->initialDeploy($initialDeployment, $number);

// Post comment with domain on the github PR
Expand Down
17 changes: 17 additions & 0 deletions app/Http/Controllers/DeployController.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,21 @@ public function deployPullRequest(Server $server, string $repository, string $nu

return response()->json(['success' => true, 'site' => $site]);
}

/**
* Handle deployment of the given event.
*/
public function deployEvent(Server $server, string $repository, string $event): JsonResponse
{
$site = match ($event) {
'pull_request' => app(DeployPullRequestAction::class)->run($server, $repository, request()->input('number')),
default => app(DeployBranchAction::class)->run($server, $repository, request()->input('branch'))
};

if (! $site) {
return response()->json(['success' => false], 409);
}

return response()->json(['success' => true, 'site' => $site]);
}
}
1 change: 1 addition & 0 deletions app/Support/InitialDeployment.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ public function run(): ?Site
'domain' => $this->domain,
'project_type' => 'php',
'nginx_template' => 2972,
'database' => $this->database,
]);

// Install repository
Expand Down
1 change: 1 addition & 0 deletions routes/web.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@
Route::middleware(EnsureTokenIsValid::class)->group(function () {
Route::post('deploy/{repository}/{branch}', [DeployController::class, 'deployBranch']);
Route::post('deploy/{repository}/pull/{number}', [DeployController::class, 'deployPullRequest']);
Route::post('deploy/{repository}/event/{event}', [DeployController::class, 'deployEvent']);
});
36 changes: 0 additions & 36 deletions tests/Feature/BranchDeploymentTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Laravel\Forge\Forge;
use Laravel\Forge\Resources\Site;
use RuntimeException;
use Tests\TestCase;

class BranchDeploymentTest extends TestCase
Expand Down Expand Up @@ -51,10 +50,7 @@ public function deploys_main_branch()
->with(987, [
'domain' => 'foobar.dev.deploy.com',
'project_type' => 'php',
'directory' => '/foobar.dev.deploy.com',
'isolated' => false,
'database' => 'dev_foobar',
'php_version' => 'php81',
'nginx_template' => 2972,
]);

Expand Down Expand Up @@ -139,36 +135,4 @@ public function returns_409_when_subsequent_deployment_is_unsuccessful()

$this->post('deploy/foobar/main')->assertStatus(409);
}

/** @test */
public function throws_exception_when_deployment_fails()
{
config()->set('services.github.owner', 'rockero-cz');
config()->set('services.forge.domain', 'deploy.com');
config()->set('services.forge.server_id', 987);

$forge = $this->mock(Forge::class);

$forge->shouldReceive('sites')->andReturn([]);
$forge->shouldReceive('createSite')->andReturn(new Site(['id' => 876, 'serverId' => 987]));
$forge->shouldReceive('installGitRepositoryOnSite');
$forge->shouldReceive('siteEnvironmentFile')->andReturn('');
$forge->shouldReceive('updateSiteEnvironmentFile');
$forge->shouldReceive('updateSiteDeploymentScript');
$forge->shouldReceive('obtainLetsEncryptCertificate');
$forge->shouldReceive('deploySite');

$forge->shouldReceive('get')
->with('servers/987/sites/876/deployment-history')
->andReturn([
'deployments' => [
['status' => 'failed'],
],
]);

$this->withoutExceptionHandling();
$this->expectException(RuntimeException::class);

$this->post('deploy/foobar/main');
}
}
53 changes: 8 additions & 45 deletions tests/Feature/PullRequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use Illuminate\Support\Facades\Http;
use Laravel\Forge\Forge;
use Laravel\Forge\Resources\Site;
use RuntimeException;
use Tests\TestCase;

class PullRequestTest extends TestCase
Expand All @@ -18,7 +17,7 @@ public function deploys_pull_request_site()
// Site ID: 876

config()->set('services.forge.server_id', 987);
config()->set('services.forge.domain', 'deploy.cz');
config()->set('services.forge.domain', 'rockero.cz');
config()->set('services.github.owner', 'rockero-cz');
config()->set('project.deployer.token', 'fake-token');

Expand Down Expand Up @@ -60,12 +59,9 @@ public function deploys_pull_request_site()
// Assert methods have been called
$forge->shouldHaveReceived('createSite')
->with(987, [
'domain' => '123.dev.deploy.cz',
'domain' => 'foobar-123.dev.rockero.cz',
'project_type' => 'php',
'directory' => '/123.dev.deploy.cz',
'isolated' => false,
'database' => '123',
'php_version' => 'php81',
'nginx_template' => 2972,
]);

Expand All @@ -79,14 +75,14 @@ public function deploys_pull_request_site()

$forge->shouldHaveReceived('updateSiteEnvironmentFile')
->with(987, 876, implode("\n", [
'APP_URL=https://123.dev.deploy.cz',
'APP_URL=https://foobar-123.dev.rockero.cz',
'DB_DATABASE=123',
'DB_USERNAME=root',
]));

$forge->shouldHaveReceived('updateSiteDeploymentScript')
->with(987, 876, implode(' && ', [
'cd /home/forge/123.dev.deploy.cz',
'cd /home/forge/foobar-123.dev.rockero.cz',
'git fetch origin refs/pull/1/merge',
'git checkout FETCH_HEAD',
'$FORGE_COMPOSER install --no-interaction --prefer-dist --optimize-autoloader',
Expand All @@ -95,14 +91,14 @@ public function deploys_pull_request_site()
]));

$forge->shouldHaveReceived('obtainLetsEncryptCertificate')
->with(987, 876, ['domains' => ['123.dev.deploy.cz']], false);
->with(987, 876, ['domains' => ['foobar-123.dev.rockero.cz']], false);

$forge->shouldHaveReceived('deploySite')
->with(987, 876);

$forge->shouldHaveReceived('executeSiteCommand')
->with(987, 876, ['command' => implode(' && ', [
'cd /home/forge/123.dev.deploy.cz',
'cd /home/forge/foobar-123.dev.rockero.cz',
'php artisan key:generate --force',
'php artisan storage:link',
'php artisan db:seed --force --no-interaction',
Expand All @@ -126,7 +122,7 @@ public function deploys_existing_site()
]);

$site = $this->spy(Site::class);
$site->name = '123.dev.deploy.com';
$site->name = 'foobar-123.dev.deploy.com';
$site->shouldReceive('deploySite')
->andReturn($site);

Expand Down Expand Up @@ -154,7 +150,7 @@ public function returns_500_when_subsequent_deployment_is_unsuccessful()
]);

$site = $this->mock(Site::class);
$site->name = '123.dev.deploy.com';
$site->name = 'foobar-123.dev.deploy.com';

$site->shouldReceive('deploySite')
->andReturn(null); // <--
Expand All @@ -167,37 +163,4 @@ public function returns_500_when_subsequent_deployment_is_unsuccessful()

$this->withHeaders(['Authorization' => 'Bearer fake-token'])->post('deploy/foobar/pull/1')->assertStatus(409);
}

/** @test */
public function throws_exception_when_deployment_fails()
{
config()->set('services.github.owner', 'rockero-cz');
config()->set('services.forge.domain', 'deploy.com');
config()->set('services.forge.server_id', 987);
config()->set('project.deployer.token', 'fake-token');

$forge = $this->mock(Forge::class);

$forge->shouldReceive('sites')->andReturn([]);
$forge->shouldReceive('createSite')->andReturn(new Site(['id' => 876, 'serverId' => 987]));
$forge->shouldReceive('installGitRepositoryOnSite');
$forge->shouldReceive('siteEnvironmentFile')->andReturn('');
$forge->shouldReceive('updateSiteEnvironmentFile');
$forge->shouldReceive('updateSiteDeploymentScript');
$forge->shouldReceive('obtainLetsEncryptCertificate');
$forge->shouldReceive('deploySite');

$forge->shouldReceive('get')
->with('servers/987/sites/876/deployment-history')
->andReturn([
'deployments' => [
['status' => 'failed'],
],
]);

$this->withoutExceptionHandling();
$this->expectException(RuntimeException::class);

$this->withHeaders(['Authorization' => 'Bearer fake-token'])->post('deploy/foobar/main');
}
}

0 comments on commit d45d4d7

Please sign in to comment.