Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions src/Command/SelfUpdateCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use Php\Pie\File\FullPathToSelf;
use Php\Pie\File\SudoFilePut;
use Php\Pie\SelfManage\Update\FetchPieReleaseFromGitHub;
use Php\Pie\SelfManage\Update\PiePharMissingFromLatestRelease;
use Php\Pie\SelfManage\Update\ReleaseMetadata;
use Php\Pie\SelfManage\Verify\FailedToVerifyRelease;
use Php\Pie\SelfManage\Verify\VerifyPieReleaseUsingAttestation;
Expand Down Expand Up @@ -92,8 +93,15 @@ public function execute(InputInterface $input, OutputInterface $output): int

$output->writeln('Downloading the latest nightly release.');
} else {
$latestRelease = $fetchLatestPieRelease->latestReleaseMetadata();
$pieVersion = PieVersion::get();
try {
$latestRelease = $fetchLatestPieRelease->latestReleaseMetadata();
} catch (PiePharMissingFromLatestRelease $piePharMissingFromLatestRelease) {
$output->writeln(sprintf('<error>%s</error>', $piePharMissingFromLatestRelease->getMessage()));

return Command::FAILURE;
}

$pieVersion = PieVersion::get();

if (preg_match('/^(?<tag>.+)@(?<hash>[a-f0-9]{7})$/', $pieVersion, $matches)) {
// Have to change the version to something the Semver library understands
Expand Down
10 changes: 5 additions & 5 deletions src/Downloading/GithubPackageReleaseAssets.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ private function getReleaseAssetsForPackage(
Assert::notNull($package->downloadUrl());

try {
$decodedRepsonse = $httpDownloader->get(
$decodedResponse = $httpDownloader->get(
$this->githubApiBaseUrl . '/repos/' . $package->githubOrgAndRepository() . '/releases/tags/' . $package->version(),
[
'retry-auth-failure' => true,
Expand All @@ -98,9 +98,9 @@ private function getReleaseAssetsForPackage(
throw $t;
}

Assert::isArray($decodedRepsonse);
Assert::keyExists($decodedRepsonse, 'assets');
Assert::isList($decodedRepsonse['assets']);
Assert::isArray($decodedResponse);
Assert::keyExists($decodedResponse, 'assets');
Assert::isList($decodedResponse['assets']);

return array_map(
static function (array $asset): array {
Expand All @@ -111,7 +111,7 @@ static function (array $asset): array {

return $asset;
},
$decodedRepsonse['assets'],
$decodedResponse['assets'],
);
}
}
1 change: 1 addition & 0 deletions src/SelfManage/Update/FetchPieRelease.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
/** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */
interface FetchPieRelease
{
/** @throws PiePharMissingFromLatestRelease */
public function latestReleaseMetadata(): ReleaseMetadata;

/** Download the given pie.phar and return the filename (should be a temp file) */
Expand Down
22 changes: 14 additions & 8 deletions src/SelfManage/Update/FetchPieReleaseFromGitHub.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

use function array_filter;
use function array_map;
use function count;
use function file_put_contents;
use function reset;
use function sys_get_temp_dir;
Expand All @@ -34,7 +35,7 @@ public function latestReleaseMetadata(): ReleaseMetadata
{
$url = $this->githubApiBaseUrl . self::PIE_LATEST_RELEASE_URL;

$decodedRepsonse = $this->httpDownloader->get(
$decodedResponse = $this->httpDownloader->get(
$url,
[
'retry-auth-failure' => true,
Expand All @@ -45,11 +46,11 @@ public function latestReleaseMetadata(): ReleaseMetadata
],
)->decodeJson();

Assert::isArray($decodedRepsonse);
Assert::keyExists($decodedRepsonse, 'tag_name');
Assert::stringNotEmpty($decodedRepsonse['tag_name']);
Assert::keyExists($decodedRepsonse, 'assets');
Assert::isList($decodedRepsonse['assets']);
Assert::isArray($decodedResponse);
Assert::keyExists($decodedResponse, 'tag_name');
Assert::stringNotEmpty($decodedResponse['tag_name']);
Assert::keyExists($decodedResponse, 'assets');
Assert::isList($decodedResponse['assets']);

$assetsNamedPiePhar = array_filter(
array_map(
Expand All @@ -62,16 +63,21 @@ static function (array $asset): array {

return $asset;
},
$decodedRepsonse['assets'],
$decodedResponse['assets'],
),
static function (array $asset): bool {
return $asset['name'] === self::PIE_PHAR_NAME;
},
);

if (! count($assetsNamedPiePhar)) {
throw PiePharMissingFromLatestRelease::fromRelease($decodedResponse['tag_name']);
}

$firstAssetNamedPiePhar = reset($assetsNamedPiePhar);

return new ReleaseMetadata(
$decodedRepsonse['tag_name'],
$decodedResponse['tag_name'],
$firstAssetNamedPiePhar['browser_download_url'],
);
}
Expand Down
21 changes: 21 additions & 0 deletions src/SelfManage/Update/PiePharMissingFromLatestRelease.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace Php\Pie\SelfManage\Update;

use RuntimeException;

use function sprintf;

class PiePharMissingFromLatestRelease extends RuntimeException
{
/** @param non-empty-string $tagName */
public static function fromRelease(string $tagName): self
{
return new self(sprintf(
'PIE release %s does not have a pie.phar attached yet, try again in a few minutes.',
$tagName,
));
}
}
45 changes: 45 additions & 0 deletions test/unit/SelfManage/Update/FetchPieReleaseFromGitHubTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Composer\Util\Http\Response;
use Composer\Util\HttpDownloader;
use Php\Pie\SelfManage\Update\FetchPieReleaseFromGitHub;
use Php\Pie\SelfManage\Update\PiePharMissingFromLatestRelease;
use Php\Pie\SelfManage\Update\ReleaseMetadata;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\TestCase;
Expand Down Expand Up @@ -72,6 +73,50 @@ public function testLatestReleaseMetadata(): void
self::assertSame(self::TEST_GITHUB_URL . '/path/to/pie.phar', $latestRelease->downloadUrl);
}

public function testLatestReleaseNotHavingPiePharThrowsException(): void
{
$httpDownloader = $this->createMock(HttpDownloader::class);
$authHelper = $this->createMock(AuthHelper::class);

$url = self::TEST_GITHUB_URL . '/repos/php/pie/releases/latest';
$authHelper
->method('addAuthenticationHeader')
->willReturn(['Authorization: Bearer fake-token']);
$httpDownloader->expects(self::once())
->method('get')
->with(
$url,
[
'retry-auth-failure' => true,
'http' => [
'method' => 'GET',
'header' => ['Authorization: Bearer fake-token'],
],
],
)
->willReturn(
new Response(
['url' => $url],
200,
[],
json_encode([
'tag_name' => '1.2.3',
'assets' => [
[
'name' => 'not-pie.phar',
'browser_download_url' => self::TEST_GITHUB_URL . '/do/not/download/this',
],
],
]),
),
);

$fetch = new FetchPieReleaseFromGitHub(self::TEST_GITHUB_URL, $httpDownloader, $authHelper);

$this->expectException(PiePharMissingFromLatestRelease::class);
$fetch->latestReleaseMetadata();
}

public function testDownloadContent(): void
{
$url = self::TEST_GITHUB_URL . '/path/to/pie.phar';
Expand Down
Loading