Skip to content

Release v3.2.0 #18

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 44 commits into
base: master
Choose a base branch
from
Open

Release v3.2.0 #18

wants to merge 44 commits into from

Conversation

yCodeTech
Copy link
Owner

@yCodeTech yCodeTech commented Mar 6, 2025

This pull request introduces new features, refactors existing methods, and removes deprecated functionality for the valet-windows project. The most notable changes include the addition of a new php:proxy command, improvements to PHP-related functionality, and a significant refactoring of the filesystem and package management code. Below is a categorized summary of the most important changes:

New Features

  • Added the php:proxy command (with alias php) to proxy PHP commands through a site's PHP executable. This includes updates to the README.md to document the command and its usage. [1] [2]
  • Introduced the PhpCgi::getPhpPath method to fetch the PHP executable path for a specified version.
  • Added support for a new share-tool configuration option, defaulting to ngrok. [1] [2]

Refactoring and Code Simplification

  • Refactored the Filesystem class to include new methods like move, unzip, getStub, and convertJunctionsToSymlinks, while simplifying symlink handling. [1] [2] [3] [4]
  • Replaced direct file path references with the new getStub method in multiple components (Acrylic.php, Configuration.php, Nginx.php). [1] [2] [3] [4]

Deprecation and Removals

  • Removed the deprecated confirmation question about uninstalling the outdated cretueusebiu package in the install command.
  • Deleted the Ansicon class and replaced it with a new implementation in the Packages namespace. The new implementation includes enhanced package management functionality. [1] [2]

PHP Command Enhancements

  • Updated the PhpCGI::findPhpVersion method to support returning the executable path with a new getExecPath parameter and improved error handling.
  • Enhanced the php:which command to display the PHP executable path alongside the version. [1] [2]

Documentation Updates

  • Updated the README.md to reflect the new php:proxy command and its alias, as well as other changes like command parity updates and the removal of deprecated functionality. [1] [2] [3]

These changes collectively improve the functionality, maintainability, and user experience of the valet-windows project.

~ These notes have been generated by Copilot

yCodeTech and others added 24 commits March 6, 2025 01:33
…n question about uninstalling the outdated cretueusebiu package.**

And:
- Updated the deprecation section of readme
- Added the 3.2.0 release to the changelog.
…e's PHP executable.

Added:

- Added `php:proxy` command with the alias of `php` and set it's descriptions and usage. Though the command block in cli/valet.php is only to document the command within the CLI and doesn't handle the logic.

- Added the logic for the new `php:proxy` command in the `valet` command script in the project root.

The logic uses PHP's `$argv` global variable to capture command line arguments that is passed to the script to be able to test against and use. The logic is the same in principle as the macOS bash script, it runs the `php:which` command to get the php executable from the site's PHP version. It then runs the PHP executable as a command and proxies the original arguments through to PHP itself.

- Added new `PhpCgi::getPhpPath` method to get the PHP executable path by specifying a version.

Changed:

- Version bumped the macOS valet URL in the `parity` command to make sure the command parity is up to date with the latest MINOR version at the time of release.

- Changed `PhpCGI::findPhpVersion` method to return the executable path if the new `getExecPath` param is `true` otherwise it will default to returning the PHP version. Also changed it's error return value to `false` for easier checking.

- Changed `Configuration::addPhp` method to `return false` if the $phpVersion variable is `false`.

- Changed `Site::whichPhp` method to extract the PHP version from the ansi coloured output, and the raw version string to a new element in the return array.

- Changed the info output in `php:which` command to use the new raw phpVersion string, and added a separate info output to get and display the php executable path using the new new `PhpCgi::getPhpPath` method.

- Changed the docs in README to:
     - Update the table of links for the commands.

     - Document the new `php:proxy` command, and add the parity icon to mark that the command is the same as macOS.

     - Update the `php:which` command example output and add the parity icon to mark that the command is the same as macOS.

     - Update the Command Parity Checker section to check off the `php` proxy command, and add a new macOS command `renew`, which is To Be Decided (TBD) about the possibility of adding it.
…ically on `require`.

Sorted the packages, and bumped versions of `composer/ca-bundle` and `guzzlehttp/guzzle`
…mmunicate with the share tool classes.

Added:

- Add new `Share` class which holds various methods to set and get the share tools (eg. ngrok), and create the share tool class instance to be able to chain their methods.

- Add new `ShareTool` abstract class in the new `ShareTools` directory, with the namespace `Valet\ShareTools`. It acts as the base/parent class that all other share tool classes will extend. It declares abstract methods that requires the child classes to implement, like `start`, `run`, and `getConfig`.

The class also holds shared methods like `currentTunnelUrl` and `findHttpTunnelUrl` that don't need to be implemented by the child classes because the code doesn't need to be changed.

- Add the new `Share` class to the facades.php.

Changed:

- Move `Ngrok` class into the `ShareTools` directory, and changing it's namespace and it extends the new `ShareTool` class.

- Move the `currentTunnelUrl` and `findHttpTunnelUrl` methods from Ngrok to the parent `ShareTool` class.

- Change `getNgrokConfig` method name to the new `getConfig`. Also change all references to the method.

- Change the `Facade` class to check if the class called is `Ngrok`, and append the `ShareTools` string to the default `Valet` namespace to create the ShareTools namespace. This is so that we can call Ngrok methods statically in the main valet.php file. Like `Ngrok::run` for the `ngrok` command.
…es to use the new `Share` class.

Added:

- Add new `share-tool` class to get or set the name of the currently selected share tool. Only supported option at the moment is `ngrok`.

- Added a conditional check in `set-ngrok-token` command to check that the current share tool is set to ngrok. If it's not, there's no point setting the token, so output a message.

- Added a conditional check in `share` and `fetch-share-url` commands to check if there is current share tool set, if it's not set (ie. null), there's no point going further, so output a message.

Changed:

- Change `share` command to use the new `Share` class and using the `shareTool` method to get the current share tool's class instance. Then we can access the tool's `start` method directly via method chaining.

- Change the `Ngrok` class in `fetch-share-url` command for the new `Share` class, where the `currentTunnelUrl` method now lives.
…e tunnel endpoints.

- Change `currentTunnelUrl` method  to be inline with the macOS Valet and loop through both the defined tunnel localhost endpoints and retry 5 times each.

- Change `findHttpTunnelUrl` method back to using the object operator, that was changed in commit 2ea79e6. Because we are no longer changing the object to an array, so we need to change it. This is more inline with macOS Valet code.
…mands are together, making it more organised.
`$retries` is defined twice, instead of defining the `$fn` for the 2nd param.
…reTool` method into `__construct`.

And change `getShareToolInstance` method to a private method
…races on same line as content.

This allows the empty facade class declarations to have their closing brace on the same line, instead of spanning 2 lines. This makes it easier to scan-read.
…ions for backwards compatibility.

- Add `symfony/polyfill-php80` dependency. This package contains various backward compatible polyfills for features that was added in PHP 8.0, including `str_contains`, `str_starts_with`, and `str_ends_with`.

https://github.com/symfony/polyfill/blob/1.x/src/Php80/README.md

- Remove `str_ends_with` and `str_starts_with` helper function as these will be handled by the Symfony package.
- Remove the unused `SUDO_USER` from the `user` helper function since Windows doesn't set `SUDO_USER` environment variable at all, so this is redundant code.

- Refactored the `user` helper function to have the `USERNAME` variable return by default, and only return the `USER` if it's set. I'm not convinced `USER` is ever used on Windows either, but for now we'll keep it.

- Add URLs to the Laravel docs for `resolve`, `retry`, and `tap` helper functions where their functionality was based off.
- Dropping the intention to add Expose as a share tool because it just doesn't work. Can't even add the auth token without triggering cURL errors about a SSL certificate problem.

There seems to be loads of github issues related to some kind of SSL problem, with no real solution. Expose also lacks complete documentation for the CLI.

- Remove TODO for add `share-tool` command as completed.

- Changed the TODO to "Add support for other share tools" and removed some open source client links as they are no good.
- Move all functions into a new `Server` class.

- Simplify various server.php code by adding the code into a new method in the `Server` class, and use it in the server.php. Eg. `uriFromRequestUri`, `siteNameFromHttpHost`, `domainFromSiteName`, etc.

- Change all method names to camelCase, and rename these specific methods to be more precise names:

 `show_valet_404` -> `show404`

`get_valet_site_path` -> `sitePath`

`valet_default_site_path` -> `defaultSitePath`

`valet_support_wildcard_dns` -> `supportWildcardDnsDomains

- Change the `showDirectoryListing` method to output the contents of the file instead of using the HTML for the directory listing, which would output an empty document with the title.
As per the docs [1], `mklink` params are `/D` for symbolic link, `/H` for hard link, and `/J` for directory junction.

Currently, site links are created as a directory junction. This is not a real symbolic link, and PHP's `is_link` function always fails. To fix, we use the proper param `/D` to create a real symlink.

[1] https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/mklink
yCodeTech added 15 commits April 8, 2025 06:03
…d installer privileges

The `/D` param of `mklink` command not only requires elevated privileges, but also trusted installer privileges.

- Added new `asTrustedInstaller` param to `Commandline::sudo` method to determine whether to run gsudo as a "member of NT SERVICE\TrustedInstaller". The param defaults to `false`.

- Fixed the `Filesystem::symlink` command to use `CommandLine::sudo` to run the command, setting the new `asTrustedInstaller` param to `true` to allow gsudo to run with trusted installer privileges and create a symlink site.
- Remove the `is_dir` check from the symlink part of the code since the `unlink` and `rmdir` does both symlinked files and folders.

- Remove `file_exists` check since it was only checking for files and the code is the same as the symlink. Combine it into the `isLink` check to also check for files with the new `isFile` method instead of `file_exists`.

- Refactor `isLink` method since we're dealing with real symlinks now instead of junctions, so the PHP `is_link` function works as intended now.

- Add new `isFile` method that is a wrapper around the PHP `is_file` function to check if a path is a normal file.
…d path doesn't exist.

- Change the PHP functions `is_link` and `readlink` to use the `isLink` and `readLink` methods instead.

- Fix the check to determine if the resolved symlinked path doesn't exist by using `file_exists` PHP function. This is because `readlink` will always resolve it's target path and will never return false, so it doesn't really check if it exists or not.
…a quiet mode to `sudo`.

- Add a `$quiet` bool param to the method's signature and add the output redirection if param is `true`; ie. add quiet mode.

- Change `sudo` in the `symlink` method to run in quiet mode.
- Move the `Configuration::prune` and `	Site::pruneLinks` method calls from valet.php into their own separate methods in `Upgrader` to be called from `onEveryRun` method.

- Add a call to `onEveryRun` method in valet.php
- Add new `Filesystem::convertJunctionsToSymlinks` method to remove the old Windows junction links, and re-link the sites as real symlinks.

- Add new `Filesystem::getJunctionLinks` method to get all the site links that are junctions.

This uses the Windows `dir` command to get details about all the linked directories, and piping the output to `findstr` command to narrow down the selection to only those that are defined as a `JUNCTION`. We then obtain the link name and the full site path from the details to be used in `convertJunctionsToSymlinks` method.

- Add `convertJunctionsToSymlinks` method in the `Upgrader` to call the `Filesystem::convertJunctionsToSymlinks` only if a config key is false/not present.

The config key prevents the upgrade running again, since it's only a one-time upgrade.
…L certificates.

- When securing/unsecuring a site, valet uses `certutil` Windows command to add/delete SSL certificates from the machine store, which requires elevated privileges.

But `certutil` has a `-user` option to store the certificates in the user store instead of machine store, which doesn't require privileges. So added the option to all `certutil` usages.
… github

Removed:

- Removed all `gsudo` files.

Added:

- Added new `Gsudo` class with namespace `Packages\Gsudo`.

    In this class:
    - The latest version of Gsudo portable will be downloaded using Guzzle and unzipped using Windows CMD `tar` command.

    - The X64 files will be moved into a main `gsudo` directory in Valet's bin. All other files and directories are removed.

    - Configures Gsudo to use `CacheMode Auto`.

- Added `runAsSystem` and `runAsTrustedInstalled` methods in the `Gsudo` class to elevate Gsudo to system account level, or trusted installer level.

- Added `Filesystem::move` method to copy a file to a location and deletes from the old location; effectively moving the file.

- Added `Filesystem::unzip` method to unzip a zip file into the location. Uses Windows CMD `tar` command.

- Added `getTarExecutable` helper function to return the path to `tar.exe` which resides in `C:\Windows\System32` directory.

    This is needed because just using `tar` as a command might not get the correct `tar` syntax if bash is installed. Bash also installs it's own global version of the `tar` command with a very different set of options. So outright specifying the Windows `tar` executable prevents any clashes.

- Added Gsudo class to the facades.

- Added a call to `Gsudo::install` in Valet's `install` and `sudo` commands to install Gsudo.

Removed:

- Removed the Gsudo command (path and flags) from the `CommandLine::sudo` method, in favour of using the new `Gsudo` class methods.

Changed:

- Changed  `CommandLine::sudo` method to run gsudo using the new `Gsudo::runAsSystem` and `Gsudo::runAsTrustedInstalled` methods.

    Running these methods statically is not allowed here, so to get around it we have to setup a new `Gsudo` instance using the `resolve` helper function, and access the methods in the normal way.
…om github

Removed:

- Removed all `ansicon` files.

- Removed the `__construct` methods from `Ansicon` and `Gsudo` classes, since they will now be using their parent's `__construct` method instead.

Added:

- Added new `GithubPackage` abstract class in the `Packages` directory with the namespace `Valet\Packages`. It acts as the base/parent class that all other package classes will extend. It declares abstract methods that requires the child classes to implement, like `install`.

The class also holds shared methods like `download`, and `packagePath` that don't need to be implemented by the child classes because the code doesn't need to be changed.

Changed:

- Changed `Gsudo` class to extend the new parent `GithubPackage` class.

- Moved `downloadGsudo`, `isInstalled`, `gsudoPath`, and `moveX64Files` methods from `Gsudo` class into the new parent `GithubPackage` class.

- Change names of `gsudoPath` and `downloadGsudo` methods to the generalised names `packagePath` and `download` respectively. Also add new params to pass the specific package data.

- Refactor the `Gsudo` class to use the new `GithubPackage` class's shared methods like `download`, and `packagePath`.

- Move the `foreach` in the `Gsudo::install` method into it's own method (`cleanUpPackageDirectory`) in the parent class.

- Moved `Ansicon` class into the `Packages` directory under the new namespace `Valet\Packages`, and changed it to extend the new `GithubPackage` class.

- Changed the `Ansicon::install` method to download the latest version from the Github API using Guzzle and unzip the zip file.

It also creates a `readme.md` file with the contents of the `readme.txt`, just to make it easier to read for development purposes.

- Changed the `runOrExit` method call in `Ansicon` class to use the parent class's new `packagePath` method, which returns the executable path of the specified package.
…with a duplicate directory.

During unzipping the downloaded Ansicon zip file, an error would be thrown because of a weird path with a duplicated `ansicon` directory (`\ansicon\ansicon`).

The error is:

   valet-windows\bin\ansicon\ansicon"' is not recognized as an internal or external command,
operable program or batch file.

When the path is ran behind the scenes of Windows `tar` command, the path is tried to run as command.

Not sure why the `ansicon` directory is duplicated or why the path is trying to be run a command while unzipping.

However, using the `run` method instead of `passthru` somehow fixes the issue.
…ur stubs.

- Added new `Filesystem::getStub` method to get the specified stub file. This is inline with Valet for Mac.

If the user has a custom stub file in a `stubs` directory in the home path (`~/.config/valet/stubs`), then we use the custom stub instead.

- Changed all references of getting a file from the `stubs` directory to use the new `getStub` method.

- Simplified the null coalescing operator (eg `$variable = $variable ?? `) to a null coalescing assignment operator (eg `$variable ??= $variable`). This removes the redundant extra variable.
Removed:
- Removed all `WinSW` bin files.

Added:

- Added new `WinSW` class with the namespace `Valet\Packages`. This class will never clash with the normal `WinSW` class because of the different namespaces.

Because the github release doesn't have a zip, we have to just download the .exe binary from the assets and then download the readme separately. To do this, we use an array of the download args and API URLs and loop through the array to download them.

- Added new `GithubPackage::handleApiRateLimitExceededError` method to handle the Github API "rate limit exceeded" error.

This gets the rate limit and limit reset time from the response headers, and extracts the IP address from the original response error via regex. It then displays the error in the terminal with more information than the original error would have displayed.

- Added new `GithubPackage::calculateTimeToGithubApiLimitReset` method to calculate the time left to reset the Github API rate limit. It uses the reset time from the headers, and gets the time difference from the current time. We then get the difference in minutes and seconds, and construct a human-readable string for the error output.

- Added a call to the new `Packages\WinSW::install` method in the `WinSWFactory::__construct` method to download and install the WinSW package if it's not already installed. `WinSWFactory` class is always called when any services are going to be started, installed, etc. so we can always be sure WinSW package is installed before doing anything with the services.

Changed:

- Changed  `GithubPackage::isInstalled` method to use a more generalised check if the file exists instead of trying to run the file with a help command. Packages like WinSW doesn't have a help command, so we can only test if it's installed by checking if the file exists, so might as well do this for all packages.

- Changed `GithubPacakage::download` method:

    - To make it more generic for all files not just specifically zip files by changing the wording of some comments and variables. Also changed the variable `release` to `response`.

    - To catch guzzle errors and handle them ourselves, like the `API rate limit exceeded` error. We get the error and construct a more readable exception error.

    - To check if the `assets` property exists in the response or if the `name` property equals "README.md". The latter is to detect the direct API call to get the readme, so we can get it's download url. The former is to detect getting a release, so we can obtain the correct asset and get the download url.

    This is needed because the two API responses have different property names and is structured differently.

- Changed the name of the WinSW executable from `WinSW.NET4.exe` to just `winsw.exe` in the `copy` call of the `WinSW::createConfiguration` method. This is because the executable needs to be the same name as the directory, otherwise the `GithubPackage::packagePath` method wouldn't work without some major changes. It's simpler to change the executable name.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant