1
0
mirror of https://github.com/nicoverbruggen/phpmon.git synced 2025-11-05 04:20:06 +01:00

Query latest version of Valet via Packagist

This makes it possible for PHP Monitor to request what the latest
version of Valet is. This isn't wired up to the UI currently, so
this feature isn't enabled yet.

To enable this feature, I would need to add:
- Conditional check for Valet updates (via setting)
- Decide when to run this check (either every X time and at launch)?

Additionally, PHP Monitor should be aware of its own uptime in order
to make periodic checks if the app hasn't been restarted. A check
should ideally occur every week or so if the app is not restarted.

The relevant app update check should also be adjusted to run in a very
similar way. How frequently the app checks for updates might also be
a setting but I don't want to query too often.
This commit is contained in:
2025-08-25 14:37:43 +02:00
parent 6ae104f037
commit 8925fc4f90
5 changed files with 190 additions and 0 deletions

View File

@@ -21,6 +21,19 @@
033D45A02B0D513900070080 /* RemovePhpExtensionCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 033D459D2B0D513900070080 /* RemovePhpExtensionCommand.swift */; }; 033D45A02B0D513900070080 /* RemovePhpExtensionCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 033D459D2B0D513900070080 /* RemovePhpExtensionCommand.swift */; };
033D45A12B0D513900070080 /* RemovePhpExtensionCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 033D459D2B0D513900070080 /* RemovePhpExtensionCommand.swift */; }; 033D45A12B0D513900070080 /* RemovePhpExtensionCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 033D459D2B0D513900070080 /* RemovePhpExtensionCommand.swift */; };
033D45A32B0D531D00070080 /* PhpExtensionManagerView+Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 033D45A22B0D531D00070080 /* PhpExtensionManagerView+Actions.swift */; }; 033D45A32B0D531D00070080 /* PhpExtensionManagerView+Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 033D45A22B0D531D00070080 /* PhpExtensionManagerView+Actions.swift */; };
036C39022E5C883B008DAEDF /* Packagist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C39012E5C883A008DAEDF /* Packagist.swift */; };
036C39032E5C883B008DAEDF /* Packagist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C39012E5C883A008DAEDF /* Packagist.swift */; };
036C39042E5C883B008DAEDF /* Packagist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C39012E5C883A008DAEDF /* Packagist.swift */; };
036C39052E5C883B008DAEDF /* Packagist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C39012E5C883A008DAEDF /* Packagist.swift */; };
036C39082E5C88A7008DAEDF /* PackagistTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C39072E5C88A2008DAEDF /* PackagistTest.swift */; };
036C390A2E5C8CC5008DAEDF /* PackagistP2Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C39092E5C8CBD008DAEDF /* PackagistP2Response.swift */; };
036C390B2E5C8CC5008DAEDF /* PackagistP2Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C39092E5C8CBD008DAEDF /* PackagistP2Response.swift */; };
036C390C2E5C8CC5008DAEDF /* PackagistP2Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C39092E5C8CBD008DAEDF /* PackagistP2Response.swift */; };
036C390D2E5C8CC5008DAEDF /* PackagistP2Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C39092E5C8CBD008DAEDF /* PackagistP2Response.swift */; };
036C390F2E5C8D42008DAEDF /* PackagistError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C390E2E5C8D3B008DAEDF /* PackagistError.swift */; };
036C39102E5C8D42008DAEDF /* PackagistError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C390E2E5C8D3B008DAEDF /* PackagistError.swift */; };
036C39112E5C8D42008DAEDF /* PackagistError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C390E2E5C8D3B008DAEDF /* PackagistError.swift */; };
036C39122E5C8D42008DAEDF /* PackagistError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036C390E2E5C8D3B008DAEDF /* PackagistError.swift */; };
03BFF5272E312C3D007F96FA /* Startup+Timers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03BFF5262E312C39007F96FA /* Startup+Timers.swift */; }; 03BFF5272E312C3D007F96FA /* Startup+Timers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03BFF5262E312C39007F96FA /* Startup+Timers.swift */; };
03BFF5282E312C3D007F96FA /* Startup+Timers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03BFF5262E312C39007F96FA /* Startup+Timers.swift */; }; 03BFF5282E312C3D007F96FA /* Startup+Timers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03BFF5262E312C39007F96FA /* Startup+Timers.swift */; };
03BFF5292E312C3D007F96FA /* Startup+Timers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03BFF5262E312C39007F96FA /* Startup+Timers.swift */; }; 03BFF5292E312C3D007F96FA /* Startup+Timers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03BFF5262E312C39007F96FA /* Startup+Timers.swift */; };
@@ -936,6 +949,10 @@
033D45972B0D4EC600070080 /* InstallPhpExtensionCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstallPhpExtensionCommand.swift; sourceTree = "<group>"; }; 033D45972B0D4EC600070080 /* InstallPhpExtensionCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstallPhpExtensionCommand.swift; sourceTree = "<group>"; };
033D459D2B0D513900070080 /* RemovePhpExtensionCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemovePhpExtensionCommand.swift; sourceTree = "<group>"; }; 033D459D2B0D513900070080 /* RemovePhpExtensionCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemovePhpExtensionCommand.swift; sourceTree = "<group>"; };
033D45A22B0D531D00070080 /* PhpExtensionManagerView+Actions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PhpExtensionManagerView+Actions.swift"; sourceTree = "<group>"; }; 033D45A22B0D531D00070080 /* PhpExtensionManagerView+Actions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PhpExtensionManagerView+Actions.swift"; sourceTree = "<group>"; };
036C39012E5C883A008DAEDF /* Packagist.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Packagist.swift; sourceTree = "<group>"; };
036C39072E5C88A2008DAEDF /* PackagistTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PackagistTest.swift; sourceTree = "<group>"; };
036C39092E5C8CBD008DAEDF /* PackagistP2Response.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PackagistP2Response.swift; sourceTree = "<group>"; };
036C390E2E5C8D3B008DAEDF /* PackagistError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PackagistError.swift; sourceTree = "<group>"; };
03BFF5262E312C39007F96FA /* Startup+Timers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Startup+Timers.swift"; sourceTree = "<group>"; }; 03BFF5262E312C39007F96FA /* Startup+Timers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Startup+Timers.swift"; sourceTree = "<group>"; };
03BFF52B2E313240007F96FA /* StatusMenu+Driver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StatusMenu+Driver.swift"; sourceTree = "<group>"; }; 03BFF52B2E313240007F96FA /* StatusMenu+Driver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StatusMenu+Driver.swift"; sourceTree = "<group>"; };
03CC1FE42E3D220F0050FC18 /* InstallHomebrew.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstallHomebrew.swift; sourceTree = "<group>"; }; 03CC1FE42E3D220F0050FC18 /* InstallHomebrew.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstallHomebrew.swift; sourceTree = "<group>"; };
@@ -1275,6 +1292,24 @@
path = "PHP Versions"; path = "PHP Versions";
sourceTree = "<group>"; sourceTree = "<group>";
}; };
036C38FB2E5C8827008DAEDF /* Packagist */ = {
isa = PBXGroup;
children = (
036C39012E5C883A008DAEDF /* Packagist.swift */,
036C390E2E5C8D3B008DAEDF /* PackagistError.swift */,
036C39092E5C8CBD008DAEDF /* PackagistP2Response.swift */,
);
path = Packagist;
sourceTree = "<group>";
};
036C39062E5C8890008DAEDF /* integration */ = {
isa = PBXGroup;
children = (
036C39072E5C88A2008DAEDF /* PackagistTest.swift */,
);
path = integration;
sourceTree = "<group>";
};
03BFF1D12E3CF4F2004C56A9 /* Provision */ = { 03BFF1D12E3CF4F2004C56A9 /* Provision */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@@ -1844,6 +1879,7 @@
C4F7807A25D7F84B000DBC97 /* unit */, C4F7807A25D7F84B000DBC97 /* unit */,
C471E7AE28F9B4940021E251 /* feature */, C471E7AE28F9B4940021E251 /* feature */,
C471E7BD28F9B90F0021E251 /* ui */, C471E7BD28F9B90F0021E251 /* ui */,
036C39062E5C8890008DAEDF /* integration */,
); );
path = tests; path = tests;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -1929,6 +1965,7 @@
C4AF9F6B275445D300D44ED0 /* Integrations */ = { C4AF9F6B275445D300D44ED0 /* Integrations */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
036C38FB2E5C8827008DAEDF /* Packagist */,
C4463FD029804C13007B93D5 /* Common */, C4463FD029804C13007B93D5 /* Common */,
C4C0E8DA27F887CC002D32A9 /* Nginx */, C4C0E8DA27F887CC002D32A9 /* Nginx */,
C4D89BC42783C98800A02B68 /* Composer */, C4D89BC42783C98800A02B68 /* Composer */,
@@ -2637,6 +2674,7 @@
C415D3B72770F294005EF286 /* Actions.swift in Sources */, C415D3B72770F294005EF286 /* Actions.swift in Sources */,
C4BB39392981AFC700F8E797 /* PhpVersionSource.swift in Sources */, C4BB39392981AFC700F8E797 /* PhpVersionSource.swift in Sources */,
C4C3643928AE4FCE00C0770E /* StatusMenu+Items.swift in Sources */, C4C3643928AE4FCE00C0770E /* StatusMenu+Items.swift in Sources */,
036C39032E5C883B008DAEDF /* Packagist.swift in Sources */,
C4AC51FC27E27F47008528CA /* DomainListKindCell.swift in Sources */, C4AC51FC27E27F47008528CA /* DomainListKindCell.swift in Sources */,
C4CDA893288F1A71007CE25F /* Keys.swift in Sources */, C4CDA893288F1A71007CE25F /* Keys.swift in Sources */,
C43931C529C4BD610069165B /* PhpVersionManagerView.swift in Sources */, C43931C529C4BD610069165B /* PhpVersionManagerView.swift in Sources */,
@@ -2671,6 +2709,7 @@
C47699F128A2F3150060FEB8 /* Warning.swift in Sources */, C47699F128A2F3150060FEB8 /* Warning.swift in Sources */,
54D9E0B227E4F51E003B9AD9 /* HotKeysController.swift in Sources */, 54D9E0B227E4F51E003B9AD9 /* HotKeysController.swift in Sources */,
C4811D2A22D70F9A00B5F6B3 /* MainMenu.swift in Sources */, C4811D2A22D70F9A00B5F6B3 /* MainMenu.swift in Sources */,
036C39102E5C8D42008DAEDF /* PackagistError.swift in Sources */,
C40C7F3027722E8D00DDDCDC /* Logger.swift in Sources */, C40C7F3027722E8D00DDDCDC /* Logger.swift in Sources */,
C41CA5ED2774F8EE00A2C80E /* DomainListVC+Actions.swift in Sources */, C41CA5ED2774F8EE00A2C80E /* DomainListVC+Actions.swift in Sources */,
C412E5FC25700D5300A1FB67 /* HomebrewDecodable.swift in Sources */, C412E5FC25700D5300A1FB67 /* HomebrewDecodable.swift in Sources */,
@@ -2720,6 +2759,7 @@
C476FF9822B0DD830098105B /* Alert.swift in Sources */, C476FF9822B0DD830098105B /* Alert.swift in Sources */,
033D45A32B0D531D00070080 /* PhpExtensionManagerView+Actions.swift in Sources */, 033D45A32B0D531D00070080 /* PhpExtensionManagerView+Actions.swift in Sources */,
C474B00624C0E98C00066A22 /* LocalNotification.swift in Sources */, C474B00624C0E98C00066A22 /* LocalNotification.swift in Sources */,
036C390D2E5C8CC5008DAEDF /* PackagistP2Response.swift in Sources */,
C4D5CFCA27E0F9CD00035329 /* NginxConfigurationFile.swift in Sources */, C4D5CFCA27E0F9CD00035329 /* NginxConfigurationFile.swift in Sources */,
C485707028BF452300539B36 /* PhpDoctorWindowController.swift in Sources */, C485707028BF452300539B36 /* PhpDoctorWindowController.swift in Sources */,
C4CE3BBA27B31F670086CA49 /* ComposerWindow.swift in Sources */, C4CE3BBA27B31F670086CA49 /* ComposerWindow.swift in Sources */,
@@ -2766,6 +2806,7 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
036C39122E5C8D42008DAEDF /* PackagistError.swift in Sources */,
C471E82D28F9BB650021E251 /* AlertableError.swift in Sources */, C471E82D28F9BB650021E251 /* AlertableError.swift in Sources */,
C471E82E28F9BB650021E251 /* Errors.swift in Sources */, C471E82E28F9BB650021E251 /* Errors.swift in Sources */,
C471E82F28F9BB650021E251 /* Alert.swift in Sources */, C471E82F28F9BB650021E251 /* Alert.swift in Sources */,
@@ -2775,6 +2816,7 @@
C4B79EB829CA387F00A483EE /* BrewPhpFormulaeHandler.swift in Sources */, C4B79EB829CA387F00A483EE /* BrewPhpFormulaeHandler.swift in Sources */,
C471E83228F9BB650021E251 /* MenuBarImageGenerator.swift in Sources */, C471E83228F9BB650021E251 /* MenuBarImageGenerator.swift in Sources */,
C4BB393B2981AFC700F8E797 /* PhpVersionSource.swift in Sources */, C4BB393B2981AFC700F8E797 /* PhpVersionSource.swift in Sources */,
036C39052E5C883B008DAEDF /* Packagist.swift in Sources */,
C471E83328F9BB650021E251 /* PMWindowController.swift in Sources */, C471E83328F9BB650021E251 /* PMWindowController.swift in Sources */,
C471E83428F9BB650021E251 /* VersionExtractor.swift in Sources */, C471E83428F9BB650021E251 /* VersionExtractor.swift in Sources */,
C471E83528F9BB650021E251 /* ValetProxy.swift in Sources */, C471E83528F9BB650021E251 /* ValetProxy.swift in Sources */,
@@ -2840,6 +2882,7 @@
C471E86428F9BB650021E251 /* Warning.swift in Sources */, C471E86428F9BB650021E251 /* Warning.swift in Sources */,
C40175BA2903108900763A68 /* ValetInteractor.swift in Sources */, C40175BA2903108900763A68 /* ValetInteractor.swift in Sources */,
C43931C729C4BD610069165B /* PhpVersionManagerView.swift in Sources */, C43931C729C4BD610069165B /* PhpVersionManagerView.swift in Sources */,
036C390A2E5C8CC5008DAEDF /* PackagistP2Response.swift in Sources */,
C4463FCE29804BCB007B93D5 /* RCFile.swift in Sources */, C4463FCE29804BCB007B93D5 /* RCFile.swift in Sources */,
C45B9150295608E300F4EC78 /* ValetServicesManager.swift in Sources */, C45B9150295608E300F4EC78 /* ValetServicesManager.swift in Sources */,
C471E86528F9BB650021E251 /* WarningManager.swift in Sources */, C471E86528F9BB650021E251 /* WarningManager.swift in Sources */,
@@ -2984,6 +3027,7 @@
C471E89228F9BB8F0021E251 /* Alert.swift in Sources */, C471E89228F9BB8F0021E251 /* Alert.swift in Sources */,
033D45A12B0D513900070080 /* RemovePhpExtensionCommand.swift in Sources */, 033D45A12B0D513900070080 /* RemovePhpExtensionCommand.swift in Sources */,
C471E89328F9BB8F0021E251 /* Application.swift in Sources */, C471E89328F9BB8F0021E251 /* Application.swift in Sources */,
036C39022E5C883B008DAEDF /* Packagist.swift in Sources */,
C471E89428F9BB8F0021E251 /* LocalNotification.swift in Sources */, C471E89428F9BB8F0021E251 /* LocalNotification.swift in Sources */,
C441CC592AE8249400DDFACD /* ConfigFSNotifier.swift in Sources */, C441CC592AE8249400DDFACD /* ConfigFSNotifier.swift in Sources */,
C40934A5298EEB2C00D25014 /* CaskFile.swift in Sources */, C40934A5298EEB2C00D25014 /* CaskFile.swift in Sources */,
@@ -3028,6 +3072,7 @@
C471E8B628F9BB8F0021E251 /* MainMenu+Actions.swift in Sources */, C471E8B628F9BB8F0021E251 /* MainMenu+Actions.swift in Sources */,
C471E8B728F9BB8F0021E251 /* StatusMenu.swift in Sources */, C471E8B728F9BB8F0021E251 /* StatusMenu.swift in Sources */,
C471E8B828F9BB8F0021E251 /* StatusMenu+Items.swift in Sources */, C471E8B828F9BB8F0021E251 /* StatusMenu+Items.swift in Sources */,
036C390C2E5C8CC5008DAEDF /* PackagistP2Response.swift in Sources */,
C471E8B928F9BB8F0021E251 /* DomainListCellProtocol.swift in Sources */, C471E8B928F9BB8F0021E251 /* DomainListCellProtocol.swift in Sources */,
C471E8BA28F9BB8F0021E251 /* DomainListTLSCell.swift in Sources */, C471E8BA28F9BB8F0021E251 /* DomainListTLSCell.swift in Sources */,
C43B8FD82BA9C689000C02BE /* UnavailableContentView.swift in Sources */, C43B8FD82BA9C689000C02BE /* UnavailableContentView.swift in Sources */,
@@ -3119,6 +3164,7 @@
C40934A0298EE8E900D25014 /* AppUpdater.swift in Sources */, C40934A0298EE8E900D25014 /* AppUpdater.swift in Sources */,
C4611E5A2AEAD2E20010BE24 /* ConfigManagerWindowController.swift in Sources */, C4611E5A2AEAD2E20010BE24 /* ConfigManagerWindowController.swift in Sources */,
C471E80E28F9BAE80021E251 /* DateExtension.swift in Sources */, C471E80E28F9BAE80021E251 /* DateExtension.swift in Sources */,
036C390F2E5C8D42008DAEDF /* PackagistError.swift in Sources */,
C490E3BA29BCA368006D2DE6 /* App+BrewWatch.swift in Sources */, C490E3BA29BCA368006D2DE6 /* App+BrewWatch.swift in Sources */,
03BFF5272E312C3D007F96FA /* Startup+Timers.swift in Sources */, 03BFF5272E312C3D007F96FA /* Startup+Timers.swift in Sources */,
C471E7D028F9BA630021E251 /* FileSystemProtocol.swift in Sources */, C471E7D028F9BA630021E251 /* FileSystemProtocol.swift in Sources */,
@@ -3301,6 +3347,7 @@
C40C5C9D2846A40600E28255 /* Preset.swift in Sources */, C40C5C9D2846A40600E28255 /* Preset.swift in Sources */,
C4CE7F9729683B43000102CF /* PhpVersionNumberCollection.swift in Sources */, C4CE7F9729683B43000102CF /* PhpVersionNumberCollection.swift in Sources */,
C4F30B09278E1A0E00755FCE /* CustomPrefs.swift in Sources */, C4F30B09278E1A0E00755FCE /* CustomPrefs.swift in Sources */,
036C39082E5C88A7008DAEDF /* PackagistTest.swift in Sources */,
C40FE738282ABA4F00A302C2 /* AppVersion.swift in Sources */, C40FE738282ABA4F00A302C2 /* AppVersion.swift in Sources */,
C415D3E92770F692005EF286 /* AppDelegate+InterApp.swift in Sources */, C415D3E92770F692005EF286 /* AppDelegate+InterApp.swift in Sources */,
C4E49DEE28F764A00026AC4E /* TestableCommand.swift in Sources */, C4E49DEE28F764A00026AC4E /* TestableCommand.swift in Sources */,
@@ -3321,10 +3368,12 @@
C4E2E86528FC2F1B003B070C /* XCPMApplication.swift in Sources */, C4E2E86528FC2F1B003B070C /* XCPMApplication.swift in Sources */,
C4E49DE828F764050026AC4E /* ActiveCommand.swift in Sources */, C4E49DE828F764050026AC4E /* ActiveCommand.swift in Sources */,
C489E0BC2A220A4200323F5E /* FakeBrewFormulaeHandler.swift in Sources */, C489E0BC2A220A4200323F5E /* FakeBrewFormulaeHandler.swift in Sources */,
036C390B2E5C8CC5008DAEDF /* PackagistP2Response.swift in Sources */,
C4CE3BBB27B324230086CA49 /* MainMenu+Switcher.swift in Sources */, C4CE3BBB27B324230086CA49 /* MainMenu+Switcher.swift in Sources */,
C4B79ECC29CA475900A483EE /* RemovePhpVersionCommand.swift in Sources */, C4B79ECC29CA475900A483EE /* RemovePhpVersionCommand.swift in Sources */,
C43B8FD62BA9C689000C02BE /* UnavailableContentView.swift in Sources */, C43B8FD62BA9C689000C02BE /* UnavailableContentView.swift in Sources */,
C4FD87AA29AB9ABD0002D701 /* PhpConfigChecker.swift in Sources */, C4FD87AA29AB9ABD0002D701 /* PhpConfigChecker.swift in Sources */,
036C39112E5C8D42008DAEDF /* PackagistError.swift in Sources */,
C485707D28BF45A200539B36 /* WarningView.swift in Sources */, C485707D28BF45A200539B36 /* WarningView.swift in Sources */,
C4F7809C25D80344000DBC97 /* CommandTest.swift in Sources */, C4F7809C25D80344000DBC97 /* CommandTest.swift in Sources */,
C44CCD4127AFE2FC00CE40E5 /* AlertableError.swift in Sources */, C44CCD4127AFE2FC00CE40E5 /* AlertableError.swift in Sources */,
@@ -3347,6 +3396,7 @@
C4EA3C482BA4F947007B0BA7 /* CustomButtonStyles.swift in Sources */, C4EA3C482BA4F947007B0BA7 /* CustomButtonStyles.swift in Sources */,
C4F2E43B27530F750020E974 /* PhpInstallation.swift in Sources */, C4F2E43B27530F750020E974 /* PhpInstallation.swift in Sources */,
C4F780BD25D80B65000DBC97 /* Constants.swift in Sources */, C4F780BD25D80B65000DBC97 /* Constants.swift in Sources */,
036C39042E5C883B008DAEDF /* Packagist.swift in Sources */,
C44C198E276E3A1C0072762D /* TerminalProgressWindowController.swift in Sources */, C44C198E276E3A1C0072762D /* TerminalProgressWindowController.swift in Sources */,
C4B79EBD29CA38DB00A483EE /* BrewCommand.swift in Sources */, C4B79EBD29CA38DB00A483EE /* BrewCommand.swift in Sources */,
C485707828BF456300539B36 /* Warning.swift in Sources */, C485707828BF456300539B36 /* Warning.swift in Sources */,

View File

@@ -0,0 +1,74 @@
//
// Untitled.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 25/08/2025.
// Copyright © 2025 Nico Verbruggen. All rights reserved.
//
import Foundation
class Packagist {
static func getLatestStableVersion(packageName: String) async throws -> VersionNumber {
guard let url = URL(string: "https://repo.packagist.org/p2/\(packageName).json") else {
throw PackagistError.invalidURL
}
let agent = "phpmon/\(App.shortVersion)"
var request = URLRequest(url: url)
request.setValue(agent, forHTTPHeaderField: "User-Agent")
do {
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
let code = (response as? HTTPURLResponse)?.statusCode ?? 0
throw PackagistError.networkError(NSError(domain: "", code: code, userInfo: nil))
}
let decodedResponse = try JSONDecoder()
.decode(PackagistP2Response.self, from: data)
guard let versionsArray = decodedResponse.packages[packageName] else {
throw PackagistError.unexpectedResponseStructure
}
// Filter for stable versions using the version_normalized string.
// A stable version typically does not have a hyphen (-) indicating a pre-release.
let stableVersions = versionsArray.filter { version in
guard let versionNormalized = version.version_normalized else {
return false
}
// Filter out versions with a hyphen, which are usually unstable.
return !versionNormalized.contains("-")
}
// Sort the filtered versions using version_normalized, which is designed for lexicographical sorting.
let sortedVersions = stableVersions.sorted { (version1, version2) -> Bool in
guard let v1 = version1.version_normalized, let v2 = version2.version_normalized else {
return false
}
return v1.lexicographicallyPrecedes(v2)
}
// The last element of the sorted array is the latest version
guard let latestVersionInfo = sortedVersions.last,
let latestVersion = latestVersionInfo.version else {
throw PackagistError.noStableVersions
}
return try! VersionNumber.parse(latestVersion)
} catch {
// Catch any errors that occurred and re-throw them as our custom error type for better diagnostics.
if let decodingError = error as? DecodingError {
throw PackagistError.jsonDecodingError(decodingError)
} else if let urlError = error as? URLError {
throw PackagistError.networkError(urlError)
} else {
throw error
}
}
}
}

View File

@@ -0,0 +1,32 @@
//
// PackagistError.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 25/08/2025.
// Copyright © 2025 Nico Verbruggen. All rights reserved.
//
import Foundation
enum PackagistError: Error, LocalizedError {
case invalidURL
case networkError(Error)
case jsonDecodingError(Error)
case noStableVersions
case unexpectedResponseStructure
var errorDescription: String? {
switch self {
case .invalidURL:
return "The provided URL is invalid."
case .networkError(let error):
return "A network error occurred: \(error.localizedDescription)"
case .jsonDecodingError(let error):
return "Failed to decode JSON: \(error.localizedDescription)"
case .noStableVersions:
return "No stable versions were found for the package."
case .unexpectedResponseStructure:
return "The API response structure was not as expected."
}
}
}

View File

@@ -0,0 +1,16 @@
//
// PackagistP2Response.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 25/08/2025.
// Copyright © 2025 Nico Verbruggen. All rights reserved.
//
struct PackagistP2Response: Codable {
let packages: [String: [PackageInfo]]
}
struct PackageInfo: Codable {
let version: String?
let version_normalized: String?
}

View File

@@ -0,0 +1,18 @@
//
// PackagistTest.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 25/08/2025.
// Copyright © 2025 Nico Verbruggen. All rights reserved.
//
import Testing
struct PackagistTest {
@Test func packagistRetrieval() async {
let packageToCheck = "laravel/valet"
let latestVersion = try? await Packagist.getLatestStableVersion(packageName: packageToCheck)
#expect(latestVersion != nil)
}
}