mirror of
https://github.com/standardebooks/web.git
synced 2025-07-15 10:56:46 -04:00
Refactor projects fetching commits from Github
This commit is contained in:
parent
323b8030b9
commit
3b9ea27391
3 changed files with 110 additions and 58 deletions
|
@ -1,5 +1,12 @@
|
||||||
<?
|
<?
|
||||||
|
use function Safe\curl_exec;
|
||||||
|
use function Safe\curl_getinfo;
|
||||||
|
use function Safe\curl_init;
|
||||||
|
use function Safe\curl_setopt;
|
||||||
|
use function Safe\json_decode;
|
||||||
use function Safe\preg_match;
|
use function Safe\preg_match;
|
||||||
|
use function Safe\preg_replace;
|
||||||
|
|
||||||
use Safe\DateTimeImmutable;
|
use Safe\DateTimeImmutable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -137,6 +144,18 @@ class Project{
|
||||||
public function Create(): void{
|
public function Create(): void{
|
||||||
$this->Validate();
|
$this->Validate();
|
||||||
|
|
||||||
|
try{
|
||||||
|
$this->FetchLatestCommit();
|
||||||
|
}
|
||||||
|
catch(Exceptions\AppException){
|
||||||
|
// Pass; it's OK if this fails during creation.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't let the started date be later than the first commit date. This can happen if the producer starts to commit before their project is approved on the mailing list.
|
||||||
|
if($this->LastCommitTimestamp !== null && $this->LastCommitTimestamp > $this->Started){
|
||||||
|
$this->Started = $this->LastCommitTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
// Is this ebook already released?
|
// Is this ebook already released?
|
||||||
if(!$this->Ebook->IsPlaceholder()){
|
if(!$this->Ebook->IsPlaceholder()){
|
||||||
throw new Exceptions\EbookIsNotAPlaceholderException();
|
throw new Exceptions\EbookIsNotAPlaceholderException();
|
||||||
|
@ -233,6 +252,65 @@ class Project{
|
||||||
$this->PropertyFromHttp('ReviewerUserId');
|
$this->PropertyFromHttp('ReviewerUserId');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exceptions\AppException If the operation faile.d
|
||||||
|
*/
|
||||||
|
public function FetchLatestCommit(?string $apiKey = null): void{
|
||||||
|
$headers = [
|
||||||
|
'Accept: application/vnd.github+json',
|
||||||
|
'X-GitHub-Api-Version: 2022-11-28',
|
||||||
|
'User-Agent: Standard Ebooks' // Required by GitHub.
|
||||||
|
];
|
||||||
|
|
||||||
|
if($apiKey !== null){
|
||||||
|
$headers[] = 'Authorization: Bearer ' . $apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
// First, we check if the repo has been renamed. If so, update the repo now.
|
||||||
|
$curl = curl_init($this->VcsUrl);
|
||||||
|
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, Enums\HttpMethod::Head->value); // Only perform HTTP HEAD.
|
||||||
|
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
|
||||||
|
curl_exec($curl);
|
||||||
|
|
||||||
|
/** @var string $finalUrl */
|
||||||
|
$finalUrl = curl_getinfo($curl, CURLINFO_EFFECTIVE_URL);
|
||||||
|
// Were we redirected?
|
||||||
|
if($finalUrl != $this->VcsUrl){
|
||||||
|
$this->VcsUrl = $finalUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now check the actual commits.
|
||||||
|
$url = preg_replace('|^https://github.com/|iu', 'https://api.github.com/repos/', $this->VcsUrl . '/commits');
|
||||||
|
|
||||||
|
$curl = curl_init($url);
|
||||||
|
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||||||
|
|
||||||
|
try{
|
||||||
|
$response = curl_exec($curl);
|
||||||
|
/** @var int $httpCode */
|
||||||
|
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||||||
|
|
||||||
|
if(!is_string($response)){
|
||||||
|
throw new Exceptions\AppException('Response from GitHub was not a string: ' . $response);
|
||||||
|
}
|
||||||
|
|
||||||
|
if($httpCode != Enums\HttpCode::Ok->value){
|
||||||
|
throw new Exception('HTTP code from GitHub was: ' . $httpCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var array<stdClass> $commits */
|
||||||
|
$commits = json_decode($response);
|
||||||
|
|
||||||
|
if(sizeof($commits) > 0){
|
||||||
|
$this->LastCommitTimestamp = new DateTimeImmutable($commits[0]->commit->committer->date);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception $ex){
|
||||||
|
throw new Exceptions\AppException('Error in update-project-commits for URL <' . $url . '>: ' . $ex->getMessage(), 0, $ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ***********
|
// ***********
|
||||||
// ORM METHODS
|
// ORM METHODS
|
||||||
|
|
|
@ -2,87 +2,55 @@
|
||||||
<?
|
<?
|
||||||
require_once('/standardebooks.org/web/lib/Core.php');
|
require_once('/standardebooks.org/web/lib/Core.php');
|
||||||
|
|
||||||
|
use function Safe\file_get_contents;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterate over all `Project`s that are in progress or stalled and get their latest GitHub commit. If the commit is more than 30 days old, mark the `Project` as stalled.
|
* Iterate over all `Project`s that are in progress or stalled and get their latest GitHub commit. If the commit is more than 30 days old, mark the `Project` as stalled.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use function Safe\curl_exec;
|
|
||||||
use function Safe\curl_getinfo;
|
|
||||||
use function Safe\curl_init;
|
|
||||||
use function Safe\curl_setopt;
|
|
||||||
use function Safe\file_get_contents;
|
|
||||||
use function Safe\json_decode;
|
|
||||||
use function Safe\preg_replace;
|
|
||||||
|
|
||||||
use Safe\DateTimeImmutable;
|
use Safe\DateTimeImmutable;
|
||||||
|
|
||||||
$apiToken = trim(file_get_contents('/standardebooks.org/config/secrets/se-vcs-bot@api.github.com'));
|
|
||||||
|
|
||||||
$headers = [
|
|
||||||
'Accept: application/vnd.github+json',
|
|
||||||
'Authorization: Bearer ' . $apiToken,
|
|
||||||
'X-GitHub-Api-Version: 2022-11-28',
|
|
||||||
'User-Agent: Standard Ebooks' // Required by GitHub.
|
|
||||||
];
|
|
||||||
|
|
||||||
$projects = array_merge(
|
$projects = array_merge(
|
||||||
Project::GetAllByStatus(Enums\ProjectStatusType::InProgress),
|
Project::GetAllByStatus(Enums\ProjectStatusType::InProgress),
|
||||||
Project::GetAllByStatus(Enums\ProjectStatusType::Stalled)
|
Project::GetAllByStatus(Enums\ProjectStatusType::Stalled)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$apiKey = trim(file_get_contents('/standardebooks.org/config/secrets/se-vcs-bot@api.github.com'));
|
||||||
|
$oldestAllowedCommitTimestamp = new DateTimeImmutable('30 days ago');
|
||||||
|
|
||||||
foreach($projects as $project){
|
foreach($projects as $project){
|
||||||
// First, we check if the repo has been renamed. If so, update the repo now.
|
|
||||||
$curl = curl_init($project->VcsUrl);
|
|
||||||
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, Enums\HttpMethod::Head->value); // Only perform HTTP HEAD.
|
|
||||||
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
|
|
||||||
curl_exec($curl);
|
|
||||||
|
|
||||||
$finalUrl = curl_getinfo($curl, CURLINFO_EFFECTIVE_URL);
|
|
||||||
// Were we redirected?
|
|
||||||
if($finalUrl != $project->VcsUrl){
|
|
||||||
$project->VcsUrl = $finalUrl;
|
|
||||||
$project->Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now check the actual commits.
|
|
||||||
$url = preg_replace('|^https://github.com/|iu', 'https://api.github.com/repos/', $project->VcsUrl . '/commits');
|
|
||||||
|
|
||||||
$curl = curl_init($url);
|
|
||||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
|
||||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
|
||||||
|
|
||||||
try{
|
try{
|
||||||
$response = curl_exec($curl);
|
$project->FetchLatestCommit($apiKey);
|
||||||
/** @var int $httpCode */
|
|
||||||
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
|
||||||
|
|
||||||
if(!is_string($response)){
|
if(
|
||||||
throw new Exception('Response from GitHub was not a string: ' . $response);
|
$project->Status == Enums\ProjectStatusType::InProgress
|
||||||
}
|
&&
|
||||||
|
$project->LastCommitTimestamp !== null
|
||||||
if($httpCode != Enums\HttpCode::Ok->value){
|
&&
|
||||||
throw new Exception('HTTP code from GitHub was: ' . $httpCode);
|
$project->LastCommitTimestamp < $oldestAllowedCommitTimestamp
|
||||||
}
|
){
|
||||||
|
// An active `Project` has stalled.
|
||||||
/** @var array<stdClass> $commits */
|
|
||||||
$commits = json_decode($response);
|
|
||||||
|
|
||||||
if(sizeof($commits) > 0){
|
|
||||||
$project->LastCommitTimestamp = new DateTimeImmutable($commits[0]->commit->committer->date);
|
|
||||||
}
|
|
||||||
|
|
||||||
if($project->LastCommitTimestamp !== null && $project->LastCommitTimestamp < new DateTimeImmutable('30 days ago')){
|
|
||||||
$project->Status = Enums\ProjectStatusType::Stalled;
|
$project->Status = Enums\ProjectStatusType::Stalled;
|
||||||
}
|
}
|
||||||
else{
|
elseif(
|
||||||
|
$project->Status == Enums\ProjectStatusType::Stalled
|
||||||
|
&&
|
||||||
|
$project->LastCommitTimestamp !== null
|
||||||
|
&&
|
||||||
|
$project->LastCommitTimestamp >= $oldestAllowedCommitTimestamp
|
||||||
|
){
|
||||||
// Revive previously-stalled `Project`s.
|
// Revive previously-stalled `Project`s.
|
||||||
$project->Status = Enums\ProjectStatusType::InProgress;
|
$project->Status = Enums\ProjectStatusType::InProgress;
|
||||||
}
|
}
|
||||||
|
|
||||||
$project->Save();
|
$project->Save();
|
||||||
}
|
}
|
||||||
catch(Exception $ex){
|
catch(Exceptions\AppException $ex){
|
||||||
Log::WriteErrorLogEntry('Error in update-project-commits for URL <' . $url . '>: ' . $ex->getMessage());
|
Log::WriteErrorLogEntry($ex->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
sleep(1);
|
sleep(1);
|
||||||
|
|
|
@ -20,6 +20,7 @@ $includeStatus = $includeStatus ?? true;
|
||||||
<th scope="col">Status</th>
|
<th scope="col">Status</th>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
<th/>
|
<th/>
|
||||||
|
<th/>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@ -38,10 +39,10 @@ $includeStatus = $includeStatus ?? true;
|
||||||
<? } ?>
|
<? } ?>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<?= $project->LastCommitTimestamp?->format(Enums\DateTimeFormat::ShortDate->value) ?>
|
<?= $project->Started->format(Enums\DateTimeFormat::ShortDate->value) ?>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<?= $project->Started->format(Enums\DateTimeFormat::ShortDate->value) ?>
|
<?= $project->LastCommitTimestamp?->format(Enums\DateTimeFormat::ShortDate->value) ?>
|
||||||
</td>
|
</td>
|
||||||
<? if($includeStatus){ ?>
|
<? if($includeStatus){ ?>
|
||||||
<td class="status">
|
<td class="status">
|
||||||
|
@ -51,6 +52,11 @@ $includeStatus = $includeStatus ?? true;
|
||||||
<td>
|
<td>
|
||||||
<a href="<?= Formatter::EscapeHtml($project->VcsUrl) ?>">GitHub</a>
|
<a href="<?= Formatter::EscapeHtml($project->VcsUrl) ?>">GitHub</a>
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
<? if($project->DiscussionUrl !== null){ ?>
|
||||||
|
<a href="<?= Formatter::EscapeHtml($project->DiscussionUrl) ?>">Discussion</a>
|
||||||
|
<? } ?>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue