feat/ajout-de-fonctionnalites (#1)
All checks were successful
Auto Tag Develop / tag (push) Successful in 6s
All checks were successful
Auto Tag Develop / tag (push) Successful in 6s
Reviewed-on: #1 Co-authored-by: tristan <tristan@yuno.malio.fr> Co-committed-by: tristan <tristan@yuno.malio.fr>
This commit was merged in pull request #1.
This commit is contained in:
41
src/Service/DeployService.php
Normal file
41
src/Service/DeployService.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use App\Entity\Environment;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
final class DeployService
|
||||
{
|
||||
/**
|
||||
* @return array{success: bool, output: string, exitCode: int}
|
||||
*/
|
||||
public function deploy(Environment $environment, string $tag): array
|
||||
{
|
||||
$scriptPath = $environment->getDeployScriptPath();
|
||||
|
||||
if (null === $scriptPath || !file_exists($scriptPath)) {
|
||||
return [
|
||||
'success' => false,
|
||||
'output' => sprintf('Deploy script not found: %s', $scriptPath ?? 'null'),
|
||||
'exitCode' => 1,
|
||||
];
|
||||
}
|
||||
|
||||
$process = new Process(
|
||||
['bash', $scriptPath, $tag],
|
||||
dirname($scriptPath),
|
||||
);
|
||||
$process->setTimeout(300);
|
||||
|
||||
$process->run();
|
||||
|
||||
return [
|
||||
'success' => $process->isSuccessful(),
|
||||
'output' => $process->getOutput() . $process->getErrorOutput(),
|
||||
'exitCode' => $process->getExitCode() ?? 1,
|
||||
];
|
||||
}
|
||||
}
|
||||
100
src/Service/DockerService.php
Normal file
100
src/Service/DockerService.php
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
final class DockerService
|
||||
{
|
||||
/**
|
||||
* @return array{status: string, image: string, version: string, startedAt: string}
|
||||
*/
|
||||
public function getContainerStatus(string $containerName): array
|
||||
{
|
||||
$process = new Process([
|
||||
'docker', 'inspect',
|
||||
'--format', '{{.State.Status}}||{{.Config.Image}}||{{.State.StartedAt}}',
|
||||
$containerName,
|
||||
]);
|
||||
$process->setTimeout(10);
|
||||
$process->run();
|
||||
|
||||
if (!$process->isSuccessful()) {
|
||||
return [
|
||||
'status' => 'not_found',
|
||||
'image' => '',
|
||||
'version' => '',
|
||||
'startedAt' => '',
|
||||
];
|
||||
}
|
||||
|
||||
$parts = explode('||', trim($process->getOutput()));
|
||||
|
||||
if (\count($parts) < 3) {
|
||||
return [
|
||||
'status' => 'not_found',
|
||||
'image' => '',
|
||||
'version' => '',
|
||||
'startedAt' => '',
|
||||
];
|
||||
}
|
||||
|
||||
$image = $parts[1];
|
||||
$version = 'latest';
|
||||
if (str_contains($image, ':')) {
|
||||
$version = substr($image, strrpos($image, ':') + 1);
|
||||
}
|
||||
|
||||
return [
|
||||
'status' => $parts[0],
|
||||
'image' => $image,
|
||||
'version' => $version,
|
||||
'startedAt' => $parts[2],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{cpuPercent: float, memoryUsage: string, memoryLimit: string, memoryPercent: float}
|
||||
*/
|
||||
public function getContainerStats(string $containerName): array
|
||||
{
|
||||
$process = new Process([
|
||||
'docker', 'stats', '--no-stream',
|
||||
'--format', '{{.CPUPerc}}||{{.MemUsage}}||{{.MemPerc}}',
|
||||
$containerName,
|
||||
]);
|
||||
$process->setTimeout(10);
|
||||
$process->run();
|
||||
|
||||
if (!$process->isSuccessful()) {
|
||||
return [
|
||||
'cpuPercent' => 0.0,
|
||||
'memoryUsage' => '',
|
||||
'memoryLimit' => '',
|
||||
'memoryPercent' => 0.0,
|
||||
];
|
||||
}
|
||||
|
||||
$parts = explode('||', trim($process->getOutput()));
|
||||
|
||||
if (\count($parts) < 3) {
|
||||
return [
|
||||
'cpuPercent' => 0.0,
|
||||
'memoryUsage' => '',
|
||||
'memoryLimit' => '',
|
||||
'memoryPercent' => 0.0,
|
||||
];
|
||||
}
|
||||
|
||||
$memParts = explode(' / ', $parts[1]);
|
||||
|
||||
return [
|
||||
'cpuPercent' => (float) rtrim($parts[0], '%'),
|
||||
'memoryUsage' => $memParts[0] ?? '',
|
||||
'memoryLimit' => $memParts[1] ?? '',
|
||||
'memoryPercent' => (float) rtrim($parts[2], '%'),
|
||||
];
|
||||
}
|
||||
}
|
||||
93
src/Service/GiteaRegistryService.php
Normal file
93
src/Service/GiteaRegistryService.php
Normal file
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
|
||||
final readonly class GiteaRegistryService
|
||||
{
|
||||
public function __construct(
|
||||
private HttpClientInterface $httpClient,
|
||||
#[Autowire('%env(GITEA_API_URL)%')]
|
||||
private string $giteaApiUrl,
|
||||
#[Autowire('%env(GITEA_API_TOKEN)%')]
|
||||
private string $giteaApiToken,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* List available tags for a container image.
|
||||
*
|
||||
* @param string $registryImage e.g. "gitea.malio.fr/malio-dev/sirh"
|
||||
*
|
||||
* @return list<string>
|
||||
*/
|
||||
public function listTags(string $registryImage): array
|
||||
{
|
||||
$parts = explode('/', $registryImage);
|
||||
|
||||
if (\count($parts) < 3) {
|
||||
throw new \InvalidArgumentException(sprintf('Invalid registry image format: "%s". Expected "registry/owner/package".', $registryImage));
|
||||
}
|
||||
|
||||
$owner = $parts[1];
|
||||
$package = implode('/', \array_slice($parts, 2));
|
||||
|
||||
$bearerToken = $this->getBearerToken($owner, $package);
|
||||
|
||||
$url = sprintf('%s/v2/%s/%s/tags/list', $this->giteaApiUrl, $owner, $package);
|
||||
|
||||
$response = $this->httpClient->request('GET', $url, [
|
||||
'headers' => [
|
||||
'Authorization' => sprintf('Bearer %s', $bearerToken),
|
||||
],
|
||||
'timeout' => 10,
|
||||
]);
|
||||
|
||||
$data = $response->toArray();
|
||||
|
||||
$tags = $data['tags'] ?? [];
|
||||
|
||||
usort($tags, function (string $a, string $b): int {
|
||||
$aIsVersion = str_starts_with($a, 'v');
|
||||
$bIsVersion = str_starts_with($b, 'v');
|
||||
|
||||
if ($aIsVersion && $bIsVersion) {
|
||||
return version_compare(ltrim($b, 'v'), ltrim($a, 'v'));
|
||||
}
|
||||
|
||||
if ($aIsVersion) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ($bIsVersion) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return strcmp($a, $b);
|
||||
});
|
||||
|
||||
return $tags;
|
||||
}
|
||||
|
||||
private function getBearerToken(string $owner, string $package): string
|
||||
{
|
||||
$tokenUrl = sprintf(
|
||||
'%s/v2/token?service=container_registry&scope=repository:%s/%s:pull',
|
||||
$this->giteaApiUrl,
|
||||
$owner,
|
||||
$package,
|
||||
);
|
||||
|
||||
$response = $this->httpClient->request('GET', $tokenUrl, [
|
||||
'auth_basic' => [$this->giteaApiToken, ''],
|
||||
'timeout' => 10,
|
||||
]);
|
||||
|
||||
$data = $response->toArray();
|
||||
|
||||
return $data['token'] ?? throw new \RuntimeException('Failed to obtain bearer token from Gitea registry.');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user