diff --git a/app/Services/MailDev.php b/app/Services/MailDev.php index fe3134d..3bd4275 100644 --- a/app/Services/MailDev.php +++ b/app/Services/MailDev.php @@ -9,18 +9,6 @@ class MailDev extends BaseService protected $organization = 'maildev'; protected $imageName = 'maildev'; protected $defaultPort = 1025; - protected $defaultPrompts = [ - [ - 'shortname' => 'port', - 'prompt' => 'Which host port would you like %s to use?', - // Default is set in the constructor - ], - [ - 'shortname' => 'tag', - 'prompt' => 'Which tag (version) of %s would you like to use?', - 'default' => '2.0.5', - ], - ]; protected $prompts = [ [ 'shortname' => 'web_port', diff --git a/app/Shell/DockerTags.php b/app/Shell/DockerTags.php index 6b977a6..0c8bc01 100644 --- a/app/Shell/DockerTags.php +++ b/app/Shell/DockerTags.php @@ -11,6 +11,7 @@ class DockerTags { protected $guzzle; protected $service; + protected $armArchitectures = ['arm64', 'aarch64']; public function __construct(Client $guzzle, BaseService $service) { @@ -29,8 +30,8 @@ public function resolveTag($tag): string public function getLatestTag(): string { - $numericTags = $this->getTags()->reject(function ($tag) { - return ! is_numeric($tag[0]); + $numericTags = $this->getTags()->filter(function ($tag) { + return preg_match('/^v?\d/', $tag); }); if ($numericTags->isEmpty()) { @@ -45,23 +46,12 @@ public function getTags(): Collection $response = json_decode($this->getTagsResponse()->getContents(), true); $platform = $this->platform(); - [$numericTags, $alphaTags] = collect($response['results']) - ->when($platform === 'arm64', $this->armSupportedImagesOnlyFilter()) - ->when($platform !== 'arm64', $this->nonArmOnlySupportImagesFilter()) + return collect($response['results']) + ->when(in_array($platform, $this->armArchitectures, true), $this->armSupportedImagesOnlyFilter()) + ->when(! in_array($platform, $this->armArchitectures, true), $this->nonArmOnlySupportImagesFilter()) ->pluck('name') - ->partition(function ($tag) { - return is_numeric($tag[0]); - }); - - $sortedTags = $alphaTags->sortDesc(SORT_NATURAL) - ->concat($numericTags->sortDesc(SORT_NATURAL)); - - if ($sortedTags->contains('latest')) { - $sortedTags->splice($sortedTags->search('latest'), 1); - $sortedTags->prepend('latest'); - } - - return $sortedTags->values()->filter(); + ->sort(new VersionComparator) + ->values(); } /** @@ -73,9 +63,15 @@ protected function armSupportedImagesOnlyFilter() { return function ($tags) { return $tags->filter(function ($tag) { - return collect($tag['images']) - ->pluck('architecture') - ->contains('arm64'); + $supportedArchs = collect($tag['images'])->pluck('architecture'); + + foreach ($this->armArchitectures as $arch) { + if ($supportedArchs->contains($arch)) { + return true; + } + } + + return false; }); }; } @@ -98,7 +94,7 @@ protected function nonArmOnlySupportImagesFilter() // still be other options in the supported architectures // so we can consider that the tag is not arm-only. - return $supportedArchitectures->diff(['arm64'])->count() > 0; + return $supportedArchitectures->diff($this->armArchitectures)->count() > 0; }); }; } diff --git a/app/Shell/ElasticDockerTags.php b/app/Shell/ElasticDockerTags.php index 75b426b..2efc750 100644 --- a/app/Shell/ElasticDockerTags.php +++ b/app/Shell/ElasticDockerTags.php @@ -14,7 +14,12 @@ public function getTags(): Collection ->reverse() ->filter(function ($tag) { return ! Str::contains($tag, 'SNAPSHOT'); - }); + }) + ->filter(function ($tag) { + return ! Str::startsWith($tag, 'sha256-'); + }) + ->sort(new VersionComparator) + ->values(); } protected function getAuthResponse(): StreamInterface diff --git a/app/Shell/GitHubDockerTags.php b/app/Shell/GitHubDockerTags.php index b9a64e8..63602ec 100644 --- a/app/Shell/GitHubDockerTags.php +++ b/app/Shell/GitHubDockerTags.php @@ -10,7 +10,9 @@ class GitHubDockerTags extends DockerTags { public function getTags(): Collection { - return collect(json_decode($this->getTagsResponse(), true)['tags']); + return collect(json_decode($this->getTagsResponse(), true)['tags']) + ->sort(new VersionComparator) + ->values(); } public function getLatestTag(): string diff --git a/app/Shell/MicrosoftDockerTags.php b/app/Shell/MicrosoftDockerTags.php index 6197676..054ee5d 100644 --- a/app/Shell/MicrosoftDockerTags.php +++ b/app/Shell/MicrosoftDockerTags.php @@ -14,7 +14,7 @@ public function getLatestTag(): string public function getTags(): Collection { return collect(json_decode($this->getTagsResponse(), true)['tags']) - ->reverse() + ->sort(new VersionComparator) ->values(); } diff --git a/app/Shell/MinioDockerTags.php b/app/Shell/MinioDockerTags.php index 04f0bfc..616283b 100644 --- a/app/Shell/MinioDockerTags.php +++ b/app/Shell/MinioDockerTags.php @@ -29,23 +29,13 @@ public function getLatestTag(): string public function getTags(): Collection { $response = json_decode($this->getTagsResponse()->getContents(), true); - $tags = collect($response['results'])->map->name->reject(function ($tag) { - return Str::endsWith($tag, 'fips'); - }); - - [$releaseTags, $otherTags] = $tags - ->partition(function ($tag) { - return Str::startsWith($tag, 'RELEASE.'); - }); - - $sortedTags = $releaseTags->sortDesc(SORT_NATURAL) - ->concat($otherTags->sortDesc(SORT_NATURAL)); - - if ($sortedTags->contains('latest')) { - $sortedTags->splice($sortedTags->search('latest'), 1); - $sortedTags->prepend('latest'); - } - return $sortedTags; + return collect($response['results']) + ->pluck('name') + ->reject(function ($tag) { + return Str::endsWith($tag, 'fips'); + }) + ->sort(new VersionComparator) + ->values(); } } diff --git a/app/Shell/MongoDockerTags.php b/app/Shell/MongoDockerTags.php index 8e83a2f..21dc834 100644 --- a/app/Shell/MongoDockerTags.php +++ b/app/Shell/MongoDockerTags.php @@ -11,10 +11,11 @@ public function getTags(): Collection { $response = json_decode($this->getTagsResponse()->getContents(), true); return collect($response['results']) - ->map - ->name + ->pluck('name') + ->sort(new VersionComparator) ->filter(function ($tag) { return ! Str::contains($tag, 'windowsservercore'); - }); + }) + ->values(); } } diff --git a/app/Shell/QuayDockerTags.php b/app/Shell/QuayDockerTags.php index efbabb3..98c0971 100644 --- a/app/Shell/QuayDockerTags.php +++ b/app/Shell/QuayDockerTags.php @@ -20,10 +20,7 @@ public function getLatestTag(): string public function getTags(): Collection { return collect(json_decode($this->getTagsResponse()->getContents(), true)['tags']) - ->map(function ($release) { - return $release['name']; - }) - ; + ->pluck('name'); } protected function tagsUrlTemplate(): string diff --git a/app/Shell/VersionComparator.php b/app/Shell/VersionComparator.php new file mode 100644 index 0000000..8609c58 --- /dev/null +++ b/app/Shell/VersionComparator.php @@ -0,0 +1,49 @@ +startsAsSemver($a) && ! $this->startsAsSemver($b)) { + return -1; + } + + if ($this->startsAsSemver($b) && ! $this->startsAsSemver($a)) { + return 1; + } + + if ($this->stableSemver($a) && ! $this->stableSemver($b)) { + return -1; + } + + if ($this->stableSemver($b) && ! $this->stableSemver($a)) { + return 1; + } + + return Comparator::greaterThan(preg_replace('/^v/', '', $a), preg_replace('/^v/', '', $b)) ? -1 : 1; + } + + private function stableSemver(string $version): bool + { + return preg_match('/^v?[\d.]+$/', $version); + } + + private function startsAsSemver(string $version): bool + { + return preg_match('/^v?[\d.]+/', $version); + } +} diff --git a/composer.json b/composer.json index 26a9c96..702d936 100644 --- a/composer.json +++ b/composer.json @@ -20,6 +20,7 @@ "ext-json": "*", "ext-pcntl": "*", "ext-posix": "*", + "composer/semver": "^3.4", "guzzlehttp/psr7": "^2.6" }, "require-dev": { diff --git a/tests/Feature/DockerTagsTest.php b/tests/Feature/DockerTagsTest.php index 3197e30..64c54a0 100644 --- a/tests/Feature/DockerTagsTest.php +++ b/tests/Feature/DockerTagsTest.php @@ -42,7 +42,7 @@ function it_sorts_the_versions_naturally() $tags = collect($dockerTags->getTags()); $this->assertEquals('latest', $tags->shift()); - $this->assertEquals('bullseye', $tags->shift()); + $this->assertEquals('16.2', $tags->shift()); } /** @test */ diff --git a/tests/Feature/VersionComparatorTest.php b/tests/Feature/VersionComparatorTest.php new file mode 100644 index 0000000..0c77198 --- /dev/null +++ b/tests/Feature/VersionComparatorTest.php @@ -0,0 +1,32 @@ +assertEquals($expectedOrder, $this->sort($versions)); + } + + private function sort(array $versions): array + { + return collect($versions) + ->sort(new VersionComparator) + ->values() + ->all(); + } +}