307 lines
9.9 KiB
PHP
307 lines
9.9 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use Carbon\Carbon;
|
|
use App\Models\Ticket;
|
|
use App\Models\GitlabIssues;
|
|
use App\Models\GitlabLabels;
|
|
use App\Models\GitlabProjects;
|
|
use Illuminate\Console\Command;
|
|
use App\Models\GitlabMilestones;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use App\Enums\Tickets\TicketStatusEnum;
|
|
use GrahamCampbell\GitLab\Facades\GitLab;
|
|
|
|
class UpdateGitlabDatas extends Command
|
|
{
|
|
/**
|
|
* The name and signature of the console command.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $signature = 'app:update-gitlab-datas {--is-cron}';
|
|
|
|
/**
|
|
* The console command description.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $description = 'Fetch some Gitlab datas';
|
|
|
|
/**
|
|
* Execute the console command.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function handle(): void
|
|
{
|
|
$isCron = $this->option('is-cron');
|
|
|
|
$groupId = 23;
|
|
|
|
$this->updateProjectsByGroup($groupId);
|
|
|
|
$this->updateLabelsByGroup($groupId);
|
|
|
|
$projects = GitlabProjects::all();
|
|
|
|
foreach ($projects as $project) {
|
|
$this->updateMilestonesByProject($project);
|
|
$this->updateIssuesByProject($project, $isCron);
|
|
}
|
|
|
|
$this->syncTicketStatus();
|
|
}
|
|
|
|
/**
|
|
* updateProjectsByGroup function
|
|
*
|
|
* @param integer $groupId
|
|
* @return void
|
|
*/
|
|
private function updateProjectsByGroup(int $groupId): void
|
|
{
|
|
$allProjects = [];
|
|
$page = 1;
|
|
do {
|
|
$projects = GitLab::groups()->projects($groupId, [
|
|
'order_by' => 'created_at',
|
|
'sort' => 'asc',
|
|
'per_page' => 100,
|
|
'page' => $page,
|
|
'include_subgroups' => true
|
|
]);
|
|
$allProjects = array_merge($allProjects, $projects);
|
|
$page++;
|
|
} while (!empty($projects));
|
|
|
|
$this->info(sprintf(
|
|
"Fetched %d projects in group %d.",
|
|
count($allProjects),
|
|
$groupId
|
|
));
|
|
|
|
foreach ($allProjects as $project) {
|
|
GitlabProjects::upsert(
|
|
[
|
|
'name' => $project['name'],
|
|
'url' => $project['web_url'],
|
|
'is_archived' => $project['archived'],
|
|
'gitlab_id' => $project['id']
|
|
],
|
|
['gitlab_id']
|
|
);
|
|
}
|
|
|
|
$this->info("Gitlab Projects upsert complete.");
|
|
}
|
|
|
|
/**
|
|
* updateLabelsByGroup function
|
|
*
|
|
* @param integer $groupId
|
|
* @return void
|
|
*/
|
|
private function updateLabelsByGroup(int $groupId): void
|
|
{
|
|
$allLabels = [];
|
|
$page = 1;
|
|
do {
|
|
$labels = GitLab::groups()->labels($groupId, [
|
|
'per_page' => 100,
|
|
'page' => $page,
|
|
]);
|
|
$allLabels = array_merge($allLabels, $labels);
|
|
$page++;
|
|
} while (!empty($labels));
|
|
|
|
$this->info(sprintf(
|
|
"Fetched %d labels in group %d.",
|
|
count($allLabels),
|
|
$groupId
|
|
));
|
|
|
|
foreach ($allLabels as $project) {
|
|
GitlabLabels::upsert(
|
|
[
|
|
'name' => $project['name'],
|
|
'gitlab_id' => $project['id']
|
|
],
|
|
['gitlab_id']
|
|
);
|
|
}
|
|
|
|
$this->info("Gitlab labels upsert complete.");
|
|
}
|
|
|
|
/**
|
|
* updateIssuesByProject function
|
|
*
|
|
* @param GitlabProjects $project
|
|
* @param boolean $isCron
|
|
* @return void
|
|
*/
|
|
private function updateIssuesByProject(GitlabProjects $project, bool $isCron = false): void
|
|
{
|
|
$projectId = $project->gitlab_id;
|
|
$allIssues = [];
|
|
$page = 1;
|
|
|
|
do {
|
|
$params = [
|
|
'order_by' => 'created_at',
|
|
'sort' => 'asc',
|
|
'per_page' => 100,
|
|
'page' => $page,
|
|
'state' => 'all',
|
|
];
|
|
if ($isCron) {
|
|
$params = array_merge($params, ['updated_after' => now()->subDay()]);
|
|
}
|
|
$issues = GitLab::projects()->issues($projectId, $params);
|
|
$allIssues = array_merge($allIssues, $issues);
|
|
$page++;
|
|
} while (!empty($issues));
|
|
|
|
$this->info(sprintf(
|
|
"Fetched %d issues in project %d.",
|
|
count($allIssues),
|
|
$projectId
|
|
));
|
|
|
|
foreach ($allIssues as $issue) {
|
|
GitlabIssues::upsert(
|
|
[
|
|
'title' => $issue['title'],
|
|
'url' => $issue['web_url'],
|
|
'estimate_time' => $issue['time_stats']['time_estimate'] ?? 0,
|
|
'spent_time' => $issue['time_stats']['total_time_spent'] ?? 0,
|
|
'is_closed' => $issue['state'] === 'closed',
|
|
'gitlab_id' => $issue['id'],
|
|
'gitlab_iid' => $issue['iid'],
|
|
'milestone_iid' => $issue['milestone']['iid'] ?? null,
|
|
'gitlab_project_id' => $projectId,
|
|
'g_created_at' => Carbon::parse($issue['created_at'])->format('Y-m-d'),
|
|
'g_updated_at' => Carbon::parse($issue['updated_at'])->format('Y-m-d'),
|
|
'g_closed_at' => !is_null($issue['closed_at'])
|
|
? Carbon::parse($issue['closed_at'])->format('Y-m-d')
|
|
: null,
|
|
'g_due_date' => !is_null($issue['due_date'])
|
|
? Carbon::parse($issue['due_date'])->format('Y-m-d')
|
|
: null
|
|
],
|
|
['gitlab_id']
|
|
);
|
|
|
|
$issueModel = GitlabIssues::where('gitlab_id', $issue['id'])->firstOrFail();
|
|
$labelIds = [];
|
|
|
|
foreach ($issue['labels'] as $labelName) {
|
|
$label = Cache::remember("gitlab_label_{$labelName}", 300, function () use ($labelName) {
|
|
return GitlabLabels::where('name', $labelName)->first();
|
|
});
|
|
|
|
if ($label) {
|
|
$labelIds[] = $label;
|
|
}
|
|
}
|
|
|
|
$issueModel->gitlabLabels()->sync($labelIds);
|
|
}//end foreach
|
|
|
|
$this->info("Gitlab issues upsert complete.");
|
|
}
|
|
|
|
/**
|
|
* updateMilestonesByProject function
|
|
*
|
|
* @param GitlabProjects $project
|
|
* @return void
|
|
*/
|
|
private function updateMilestonesByProject(GitlabProjects $project): void
|
|
{
|
|
$projectId = $project->gitlab_id;
|
|
$allMilestones = [];
|
|
$page = 1;
|
|
|
|
do {
|
|
$milestones = GitLab::milestones()->all($projectId, [
|
|
'per_page' => 100,
|
|
'page' => $page
|
|
]);
|
|
$allMilestones = array_merge($allMilestones, $milestones);
|
|
$page++;
|
|
} while (!empty($milestones));
|
|
|
|
$this->info(sprintf(
|
|
"Fetched %d milestones in project %d.",
|
|
count($allMilestones),
|
|
$projectId
|
|
));
|
|
|
|
foreach ($allMilestones as $milestone) {
|
|
GitlabMilestones::upsert(
|
|
[
|
|
'title' => $milestone['title'],
|
|
'url' => $milestone['web_url'],
|
|
'is_closed' => $milestone['state'] === 'closed',
|
|
'gitlab_id' => $milestone['id'],
|
|
'gitlab_iid' => $milestone['iid'],
|
|
'gitlab_project_id' => $projectId,
|
|
'g_created_at' => Carbon::parse($milestone['created_at'])->format('Y-m-d'),
|
|
'g_updated_at' => Carbon::parse($milestone['updated_at'])->format('Y-m-d'),
|
|
'g_start_date' => !is_null($milestone['start_date'])
|
|
? Carbon::parse($milestone['start_date'])->format('Y-m-d')
|
|
: null,
|
|
'g_due_date' => !is_null($milestone['due_date'])
|
|
? Carbon::parse($milestone['due_date'])->format('Y-m-d')
|
|
: null
|
|
],
|
|
['gitlab_id']
|
|
);
|
|
}//end foreach
|
|
|
|
$this->info("Gitlab milestones upsert complete.");
|
|
}
|
|
|
|
/**
|
|
* Synchronizes ticket statuses based on GitLab issue labels.
|
|
*
|
|
* @return void
|
|
*/
|
|
private function syncTicketStatus(): void
|
|
{
|
|
$tickets = Ticket::whereNotNull('gitlab_issue')->whereNot('status', TicketStatusEnum::archived)->get();
|
|
|
|
foreach ($tickets as $ticket) {
|
|
$gitlabIssue = GitlabIssues::where('url', $ticket->gitlab_issue)->with('gitlabLabels')->first();
|
|
|
|
$gitlabIssueLabels = $gitlabIssue ? $gitlabIssue->gitlabLabels->pluck('name') : [];
|
|
|
|
if ($gitlabIssueLabels) {
|
|
match (true) {
|
|
$gitlabIssueLabels->contains('g-wip') => $this->updateTicketStatus($ticket, TicketStatusEnum::inDev),
|
|
$gitlabIssueLabels->contains('g-production') => $this->updateTicketStatus($ticket, TicketStatusEnum::production),
|
|
default => null,
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Updates the ticket status only if it has changed.
|
|
*
|
|
* @param Ticket $ticket The ticket to update.
|
|
* @param TicketStatusEnum $status The new status to apply.
|
|
*
|
|
* @return void
|
|
*/
|
|
private function updateTicketStatus(Ticket $ticket, TicketStatusEnum $status): void
|
|
{
|
|
if ($ticket->status !== $status && $ticket->status !== TicketStatusEnum::waiting) {
|
|
$ticket->status = $status;
|
|
$ticket->saveOrFail();
|
|
}
|
|
}
|
|
}
|