preview comments
This commit is contained in:
parent
cafe9019c1
commit
8dbe3cfe0c
@ -38,7 +38,7 @@ protected function set_deployment_uuid()
|
||||
public function load_prs()
|
||||
{
|
||||
try {
|
||||
['rate_limit_remaining' => $rate_limit_remaining, 'data' => $data] = get_from_git_api($this->application->source, "/repos/{$this->application->git_repository}/pulls");
|
||||
['rate_limit_remaining' => $rate_limit_remaining, 'data' => $data] = git_api(source: $this->application->source, endpoint: "/repos/{$this->application->git_repository}/pulls");
|
||||
$this->rate_limit_remaining = $rate_limit_remaining;
|
||||
$this->pull_requests = $data->sortBy('number')->values();
|
||||
} catch (\Throwable $e) {
|
||||
|
@ -66,7 +66,7 @@ public function load_branches()
|
||||
$this->get_git_source();
|
||||
|
||||
try {
|
||||
['data' => $data] = get_from_git_api($this->git_source, "/repos/{$this->git_repository}/branches");
|
||||
['data' => $data] = git_api(source: $this->git_source, endpoint: "/repos/{$this->git_repository}/branches");
|
||||
$this->branches = collect($data)->pluck('name')->toArray();
|
||||
} catch (\Throwable $e) {
|
||||
return general_error_handler(err: $e, that: $this);
|
||||
|
@ -34,7 +34,6 @@ public function handle(): void
|
||||
{
|
||||
try {
|
||||
$status = get_container_status(server: $this->application->destination->server, container_id: $this->container_name, throwError: false);
|
||||
ray('ApplicationContainerStatusJob', $status);
|
||||
if ($this->pull_request_id) {
|
||||
$preview = ApplicationPreview::findPreviewByApplicationAndPullId($this->application->id, $this->pull_request_id);
|
||||
$preview->status = $status;
|
||||
|
@ -92,13 +92,29 @@ public function __construct(
|
||||
public function handle(): void
|
||||
{
|
||||
try {
|
||||
ray()->clearScreen();
|
||||
if ($this->application->deploymentType() === 'source') {
|
||||
$this->source = $this->application->source->getMorphClass()::where('id', $this->application->source->id)->first();
|
||||
}
|
||||
|
||||
$this->workdir = "/artifacts/{$this->deployment_uuid}";
|
||||
|
||||
if ($this->pull_request_id !== 0) {
|
||||
ray('Deploying pull/' . $this->pull_request_id . '/head for application: ' . $this->application->name);
|
||||
if ($this->application->fqdn) {
|
||||
$preview_fqdn = data_get($this->preview, 'fqdn');
|
||||
$template = $this->application->preview_url_template;
|
||||
$url = Url::fromString($this->application->fqdn);
|
||||
$host = $url->getHost();
|
||||
$schema = $url->getScheme();
|
||||
$random = new Cuid2(7);
|
||||
$preview_fqdn = str_replace('{{random}}', $random, $template);
|
||||
$preview_fqdn = str_replace('{{domain}}', $host, $preview_fqdn);
|
||||
$preview_fqdn = str_replace('{{pr_id}}', $this->pull_request_id, $preview_fqdn);
|
||||
$preview_fqdn = "$schema://$preview_fqdn";
|
||||
$this->preview->fqdn = $preview_fqdn;
|
||||
$this->preview->save();
|
||||
}
|
||||
$this->deploy_pull_request();
|
||||
} else {
|
||||
$this->deploy();
|
||||
@ -203,6 +219,12 @@ private function build_image()
|
||||
}
|
||||
private function deploy_pull_request()
|
||||
{
|
||||
dispatch(new ApplicationPullRequestUpdateJob(
|
||||
application_id: $this->application->id,
|
||||
pull_request_id: $this->pull_request_id,
|
||||
deployment_uuid: $this->deployment_uuid,
|
||||
status: 'in_progress'
|
||||
));
|
||||
$this->build_image_name = "{$this->application->uuid}:pr-{$this->pull_request_id}-build";
|
||||
$this->production_image_name = "{$this->application->uuid}:pr-{$this->pull_request_id}";
|
||||
$this->container_name = generate_container_name($this->application->uuid, $this->pull_request_id);
|
||||
@ -282,12 +304,12 @@ private function next(string $status)
|
||||
]);
|
||||
$this->activity->save();
|
||||
}
|
||||
dispatch(new ApplicationContainerStatusJob(
|
||||
application: $this->application,
|
||||
container_name: $this->container_name,
|
||||
pull_request_id: $this->pull_request_id
|
||||
dispatch(new ApplicationPullRequestUpdateJob(
|
||||
application_id: $this->application->id,
|
||||
pull_request_id: $this->pull_request_id,
|
||||
deployment_uuid: $this->deployment_uuid,
|
||||
status: $status
|
||||
));
|
||||
|
||||
queue_next_deployment($this->application);
|
||||
}
|
||||
private function execute_in_builder(string $command)
|
||||
|
82
app/Jobs/ApplicationPullRequestUpdateJob.php
Executable file
82
app/Jobs/ApplicationPullRequestUpdateJob.php
Executable file
@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Enums\ProcessStatus;
|
||||
use App\Models\Application;
|
||||
use App\Models\ApplicationPreview;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class ApplicationPullRequestUpdateJob implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public string $build_logs_url;
|
||||
public Application $application;
|
||||
public ApplicationPreview $preview;
|
||||
public string $body;
|
||||
|
||||
public function __construct(
|
||||
public string $application_id,
|
||||
public int $pull_request_id,
|
||||
public string $deployment_uuid,
|
||||
public string $status
|
||||
) {
|
||||
}
|
||||
public function handle()
|
||||
{
|
||||
try {
|
||||
$this->application = Application::findOrFail($this->application_id);
|
||||
$this->preview = ApplicationPreview::findPreviewByApplicationAndPullId($this->application->id, $this->pull_request_id);
|
||||
|
||||
$this->build_logs_url = base_url() . "/project/{$this->application->environment->project->uuid}/{$this->application->environment->name}/application/{$this->application->uuid}/deployment/{$this->deployment_uuid}";
|
||||
|
||||
if ($this->status === ProcessStatus::IN_PROGRESS->value) {
|
||||
$this->body = "The preview deployment is in progress. 🟡\n\n";
|
||||
}
|
||||
if ($this->status === ProcessStatus::FINISHED->value) {
|
||||
$this->body = "The preview deployment is ready. 🟢\n\n";
|
||||
if ($this->preview->fqdn) {
|
||||
$this->body .= "[Open Preview]({$this->preview->fqdn}) | ";
|
||||
}
|
||||
}
|
||||
if ($this->status === ProcessStatus::ERROR->value) {
|
||||
$this->body = "The preview deployment failed. 🔴\n\n";
|
||||
}
|
||||
$this->body .= "[Open Build Logs](" . $this->build_logs_url . ")\n\n\n";
|
||||
$this->body .= "Last updated at: " . now()->toDateTimeString() . " CET";
|
||||
|
||||
ray('Updating comment', $this->body);
|
||||
if ($this->preview->pull_request_issue_comment_id) {
|
||||
$this->update_comment();
|
||||
} else {
|
||||
$this->create_comment();
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
ray($e);
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
private function update_comment()
|
||||
{
|
||||
['data' => $data] = git_api(source: $this->application->source, endpoint: "/repos/{$this->application->git_repository}/issues/comments/{$this->preview->pull_request_issue_comment_id}", method: 'patch', data: [
|
||||
'body' => $this->body,
|
||||
], throwError: false);
|
||||
if (data_get($data, 'message') === 'Not Found') {
|
||||
ray('Comment not found. Creating new one.');
|
||||
$this->create_comment();
|
||||
}
|
||||
}
|
||||
private function create_comment()
|
||||
{
|
||||
['data' => $data] = git_api(source: $this->application->source, endpoint: "/repos/{$this->application->git_repository}/issues/{$this->pull_request_id}/comments", method: 'post', data: [
|
||||
'body' => $this->body,
|
||||
]);
|
||||
$this->preview->pull_request_issue_comment_id = $data['id'];
|
||||
$this->preview->save();
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ class ApplicationPreview extends BaseModel
|
||||
'uuid',
|
||||
'pull_request_id',
|
||||
'pull_request_html_url',
|
||||
'pull_request_issue_comment_id',
|
||||
'fqdn',
|
||||
'status',
|
||||
'application_id',
|
||||
|
@ -19,10 +19,18 @@ public function register(): void
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
Http::macro('github', function (string $api_url) {
|
||||
return Http::withHeaders([
|
||||
'Accept' => 'application/vnd.github.v3+json'
|
||||
])->baseUrl($api_url);
|
||||
Http::macro('github', function (string $api_url, string|null $github_access_token = null) {
|
||||
if ($github_access_token) {
|
||||
return Http::withHeaders([
|
||||
'X-GitHub-Api-Version' => '2022-11-28',
|
||||
'Accept' => 'application/vnd.github.v3+json',
|
||||
'Authorization' => "Bearer $github_access_token",
|
||||
])->baseUrl($api_url);
|
||||
} else {
|
||||
return Http::withHeaders([
|
||||
'Accept' => 'application/vnd.github.v3+json',
|
||||
])->baseUrl($api_url);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ function queue_next_deployment(Application $application)
|
||||
application_id: $next_found->application_id,
|
||||
deployment_uuid: $next_found->deployment_uuid,
|
||||
force_rebuild: $next_found->force_rebuild,
|
||||
pull_request_id: $next_found->pull_request_id
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
use App\Models\GithubApp;
|
||||
use App\Models\GitlabApp;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Lcobucci\JWT\Encoding\ChainedFormatter;
|
||||
use Lcobucci\JWT\Encoding\JoseEncoder;
|
||||
@ -47,15 +48,22 @@ function generate_github_jwt_token(GithubApp $source)
|
||||
return $issuedToken;
|
||||
}
|
||||
|
||||
function get_from_git_api(GithubApp|GitlabApp $source, $endpoint)
|
||||
function git_api(GithubApp|GitlabApp $source, string $endpoint, string $method = 'get', array|null $data = null, bool $throwError = true)
|
||||
{
|
||||
if ($source->getMorphClass() == 'App\Models\GithubApp') {
|
||||
if ($source->is_public) {
|
||||
$response = Http::github($source->api_url)->get($endpoint);
|
||||
$response = Http::github($source->api_url)->$method($endpoint);
|
||||
} else {
|
||||
$github_access_token = generate_github_installation_token($source);
|
||||
if ($data && ($method === 'post' || $method === 'patch' || $method === 'put')) {
|
||||
$response = Http::github($source->api_url, $github_access_token)->$method($endpoint, $data);
|
||||
} else {
|
||||
$response = Http::github($source->api_url, $github_access_token)->$method($endpoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
$json = $response->json();
|
||||
if ($response->status() !== 200) {
|
||||
if ($response->failed() && $throwError) {
|
||||
throw new \Exception("Failed to get data from {$source->name} with error: " . $json['message']);
|
||||
}
|
||||
return [
|
||||
|
@ -81,3 +81,16 @@ function set_transanctional_email_settings()
|
||||
"local_domain" => null,
|
||||
]);
|
||||
}
|
||||
|
||||
function base_url()
|
||||
{
|
||||
$settings = InstanceSettings::get();
|
||||
if ($settings->fqdn) {
|
||||
return $settings->fqdn;
|
||||
} else {
|
||||
if (config('app.env') === 'local') {
|
||||
return url('/') . ':8080';
|
||||
}
|
||||
return url('/');
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ public function up(): void
|
||||
$table->string('uuid')->unique();
|
||||
$table->integer('pull_request_id');
|
||||
$table->string('pull_request_html_url');
|
||||
$table->integer('pull_request_issue_comment_id')->nullable();
|
||||
|
||||
$table->string('fqdn')->unique()->nullable();
|
||||
$table->string('status')->default('exited');
|
||||
|
@ -115,7 +115,7 @@ function createGithubApp() {
|
||||
default_permissions: {
|
||||
contents: 'read',
|
||||
metadata: 'read',
|
||||
pull_requests: 'read',
|
||||
pull_requests: 'write',
|
||||
emails: 'read'
|
||||
},
|
||||
default_events: ['pull_request', 'push']
|
||||
|
@ -100,14 +100,13 @@
|
||||
if (!$id || !$branch) {
|
||||
return response('Nothing to do. No id or branch found.');
|
||||
}
|
||||
$applications = Application::where('repository_project_id', $id);
|
||||
$applications = Application::where('repository_project_id', $id)->whereRelation('source', 'is_public', false);
|
||||
if ($x_github_event === 'push') {
|
||||
$applications = $applications->where('git_branch', $branch)->get();
|
||||
}
|
||||
if ($x_github_event === 'pull_request') {
|
||||
$applications = $applications->where('git_branch', $base_branch)->get();
|
||||
}
|
||||
|
||||
if ($applications->isEmpty()) {
|
||||
return response('Nothing to do. No applications found.');
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
"_id": "b3d379ab-e5e4-4ba4-991d-b6c8c6bbcb98",
|
||||
"colId": "e6458286-eef1-401c-be84-860b111d66f0",
|
||||
"containerId": "b8cfd093-5467-44a2-9221-ad0207717310",
|
||||
"name": "Push",
|
||||
"name": "Public Push",
|
||||
"url": "http://localhost:8000/webhooks/source/github/events",
|
||||
"method": "POST",
|
||||
"sortNum": 10000,
|
||||
@ -51,12 +51,12 @@
|
||||
"_id": "b5386afc-ad91-428f-88ac-0f449c5c26fd",
|
||||
"colId": "e6458286-eef1-401c-be84-860b111d66f0",
|
||||
"containerId": "b8cfd093-5467-44a2-9221-ad0207717310",
|
||||
"name": "PR - Opened",
|
||||
"name": "Public PR - Opened",
|
||||
"url": "http://localhost:8000/webhooks/source/github/events",
|
||||
"method": "POST",
|
||||
"sortNum": 20000,
|
||||
"created": "2023-05-31T08:23:28.904Z",
|
||||
"modified": "2023-05-31T09:07:17.450Z",
|
||||
"modified": "2023-06-13T10:01:31.875Z",
|
||||
"headers": [
|
||||
{
|
||||
"name": "X-GitHub-Delivery",
|
||||
@ -99,12 +99,12 @@
|
||||
"_id": "7e7a3abd-dc01-454f-aa80-eaeb2c18aa56",
|
||||
"colId": "e6458286-eef1-401c-be84-860b111d66f0",
|
||||
"containerId": "b8cfd093-5467-44a2-9221-ad0207717310",
|
||||
"name": "PR - Closed",
|
||||
"name": "Public PR - Closed",
|
||||
"url": "http://localhost:8000/webhooks/source/github/events",
|
||||
"method": "POST",
|
||||
"sortNum": 30000,
|
||||
"created": "2023-05-31T09:15:15.833Z",
|
||||
"modified": "2023-05-31T09:15:29.822Z",
|
||||
"modified": "2023-06-13T08:34:27.203Z",
|
||||
"headers": [
|
||||
{
|
||||
"name": "X-GitHub-Delivery",
|
||||
|
Loading…
Reference in New Issue
Block a user