Skip to content

Commit d23fc4e

Browse files
authored
Merge pull request #363 from asgrim/self-update-before-pie-phar-available
Handle scenario where pie.phar is not uploaded to the latest release yet
2 parents d8d4e5d + be768fa commit d23fc4e

File tree

6 files changed

+96
-15
lines changed

6 files changed

+96
-15
lines changed

src/Command/SelfUpdateCommand.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Php\Pie\File\FullPathToSelf;
1414
use Php\Pie\File\SudoFilePut;
1515
use Php\Pie\SelfManage\Update\FetchPieReleaseFromGitHub;
16+
use Php\Pie\SelfManage\Update\PiePharMissingFromLatestRelease;
1617
use Php\Pie\SelfManage\Update\ReleaseMetadata;
1718
use Php\Pie\SelfManage\Verify\FailedToVerifyRelease;
1819
use Php\Pie\SelfManage\Verify\VerifyPieReleaseUsingAttestation;
@@ -92,8 +93,15 @@ public function execute(InputInterface $input, OutputInterface $output): int
9293

9394
$output->writeln('Downloading the latest nightly release.');
9495
} else {
95-
$latestRelease = $fetchLatestPieRelease->latestReleaseMetadata();
96-
$pieVersion = PieVersion::get();
96+
try {
97+
$latestRelease = $fetchLatestPieRelease->latestReleaseMetadata();
98+
} catch (PiePharMissingFromLatestRelease $piePharMissingFromLatestRelease) {
99+
$output->writeln(sprintf('<error>%s</error>', $piePharMissingFromLatestRelease->getMessage()));
100+
101+
return Command::FAILURE;
102+
}
103+
104+
$pieVersion = PieVersion::get();
97105

98106
if (preg_match('/^(?<tag>.+)@(?<hash>[a-f0-9]{7})$/', $pieVersion, $matches)) {
99107
// Have to change the version to something the Semver library understands

src/Downloading/GithubPackageReleaseAssets.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ private function getReleaseAssetsForPackage(
7979
Assert::notNull($package->downloadUrl());
8080

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

101-
Assert::isArray($decodedRepsonse);
102-
Assert::keyExists($decodedRepsonse, 'assets');
103-
Assert::isList($decodedRepsonse['assets']);
101+
Assert::isArray($decodedResponse);
102+
Assert::keyExists($decodedResponse, 'assets');
103+
Assert::isList($decodedResponse['assets']);
104104

105105
return array_map(
106106
static function (array $asset): array {
@@ -111,7 +111,7 @@ static function (array $asset): array {
111111

112112
return $asset;
113113
},
114-
$decodedRepsonse['assets'],
114+
$decodedResponse['assets'],
115115
);
116116
}
117117
}

src/SelfManage/Update/FetchPieRelease.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
/** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */
1010
interface FetchPieRelease
1111
{
12+
/** @throws PiePharMissingFromLatestRelease */
1213
public function latestReleaseMetadata(): ReleaseMetadata;
1314

1415
/** Download the given pie.phar and return the filename (should be a temp file) */

src/SelfManage/Update/FetchPieReleaseFromGitHub.php

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
use function array_filter;
1414
use function array_map;
15+
use function count;
1516
use function file_put_contents;
1617
use function reset;
1718
use function sys_get_temp_dir;
@@ -34,7 +35,7 @@ public function latestReleaseMetadata(): ReleaseMetadata
3435
{
3536
$url = $this->githubApiBaseUrl . self::PIE_LATEST_RELEASE_URL;
3637

37-
$decodedRepsonse = $this->httpDownloader->get(
38+
$decodedResponse = $this->httpDownloader->get(
3839
$url,
3940
[
4041
'retry-auth-failure' => true,
@@ -45,11 +46,11 @@ public function latestReleaseMetadata(): ReleaseMetadata
4546
],
4647
)->decodeJson();
4748

48-
Assert::isArray($decodedRepsonse);
49-
Assert::keyExists($decodedRepsonse, 'tag_name');
50-
Assert::stringNotEmpty($decodedRepsonse['tag_name']);
51-
Assert::keyExists($decodedRepsonse, 'assets');
52-
Assert::isList($decodedRepsonse['assets']);
49+
Assert::isArray($decodedResponse);
50+
Assert::keyExists($decodedResponse, 'tag_name');
51+
Assert::stringNotEmpty($decodedResponse['tag_name']);
52+
Assert::keyExists($decodedResponse, 'assets');
53+
Assert::isList($decodedResponse['assets']);
5354

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

6364
return $asset;
6465
},
65-
$decodedRepsonse['assets'],
66+
$decodedResponse['assets'],
6667
),
6768
static function (array $asset): bool {
6869
return $asset['name'] === self::PIE_PHAR_NAME;
6970
},
7071
);
72+
73+
if (! count($assetsNamedPiePhar)) {
74+
throw PiePharMissingFromLatestRelease::fromRelease($decodedResponse['tag_name']);
75+
}
76+
7177
$firstAssetNamedPiePhar = reset($assetsNamedPiePhar);
7278

7379
return new ReleaseMetadata(
74-
$decodedRepsonse['tag_name'],
80+
$decodedResponse['tag_name'],
7581
$firstAssetNamedPiePhar['browser_download_url'],
7682
);
7783
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Php\Pie\SelfManage\Update;
6+
7+
use RuntimeException;
8+
9+
use function sprintf;
10+
11+
class PiePharMissingFromLatestRelease extends RuntimeException
12+
{
13+
/** @param non-empty-string $tagName */
14+
public static function fromRelease(string $tagName): self
15+
{
16+
return new self(sprintf(
17+
'PIE release %s does not have a pie.phar attached yet, try again in a few minutes.',
18+
$tagName,
19+
));
20+
}
21+
}

test/unit/SelfManage/Update/FetchPieReleaseFromGitHubTest.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Composer\Util\Http\Response;
99
use Composer\Util\HttpDownloader;
1010
use Php\Pie\SelfManage\Update\FetchPieReleaseFromGitHub;
11+
use Php\Pie\SelfManage\Update\PiePharMissingFromLatestRelease;
1112
use Php\Pie\SelfManage\Update\ReleaseMetadata;
1213
use PHPUnit\Framework\Attributes\CoversClass;
1314
use PHPUnit\Framework\TestCase;
@@ -72,6 +73,50 @@ public function testLatestReleaseMetadata(): void
7273
self::assertSame(self::TEST_GITHUB_URL . '/path/to/pie.phar', $latestRelease->downloadUrl);
7374
}
7475

76+
public function testLatestReleaseNotHavingPiePharThrowsException(): void
77+
{
78+
$httpDownloader = $this->createMock(HttpDownloader::class);
79+
$authHelper = $this->createMock(AuthHelper::class);
80+
81+
$url = self::TEST_GITHUB_URL . '/repos/php/pie/releases/latest';
82+
$authHelper
83+
->method('addAuthenticationHeader')
84+
->willReturn(['Authorization: Bearer fake-token']);
85+
$httpDownloader->expects(self::once())
86+
->method('get')
87+
->with(
88+
$url,
89+
[
90+
'retry-auth-failure' => true,
91+
'http' => [
92+
'method' => 'GET',
93+
'header' => ['Authorization: Bearer fake-token'],
94+
],
95+
],
96+
)
97+
->willReturn(
98+
new Response(
99+
['url' => $url],
100+
200,
101+
[],
102+
json_encode([
103+
'tag_name' => '1.2.3',
104+
'assets' => [
105+
[
106+
'name' => 'not-pie.phar',
107+
'browser_download_url' => self::TEST_GITHUB_URL . '/do/not/download/this',
108+
],
109+
],
110+
]),
111+
),
112+
);
113+
114+
$fetch = new FetchPieReleaseFromGitHub(self::TEST_GITHUB_URL, $httpDownloader, $authHelper);
115+
116+
$this->expectException(PiePharMissingFromLatestRelease::class);
117+
$fetch->latestReleaseMetadata();
118+
}
119+
75120
public function testDownloadContent(): void
76121
{
77122
$url = self::TEST_GITHUB_URL . '/path/to/pie.phar';

0 commit comments

Comments
 (0)