Skip to content
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

Add support for intermediary URLs such as EDD #49

Open
wants to merge 20 commits into
base: dev
Choose a base branch
from

Conversation

mcaskill
Copy link
Contributor

@mcaskill mcaskill commented Jul 23, 2024

Fix #22 by allowing a package URL indirection to take place.

Continuation of #45 to implement suggested changes.

Summary of suggested changes by @ffraenz to implement:

  • "[...] we need to find a way to target specific packages/dist URLs in extra.private-composer-installer. [...] This way multiple packages (from the same vendor) could reuse the same config. I would keep a config generic to allow for future additions that may be unrelated to an indirection feature."
  • "[...] go with a simple dot-notation string e.g. foo.bar.0.download_url to specify [keys]."
  • "Keep in mind that dist URLs without any placeholders should be ignored by this plugin to not alter unrelated packages. An indirection call must only be made if an indirection is actually configured (I think that's not the case right now in your code)."

Additional features:

  • Add support to check if the intermediary's version satisfies the package's version.
  • Add support for intermediary's that serve response as serialize()-ed data.
    Requires dependency on composer/semver.

Example:

"indirection": {
	"http": {
		"method": "POST"
	},
	"ssl": {
		"passphrase": "{%PACKAGE_SSL_PW}"
	},
	"parse": {
		"format": "json",
		"download_key": "data.0.download_url",
		"version_key": "data.0.version"
	}
}

Note

[2024-08-09] Feature branch has been unit tested but has not been tested yet with an actual indirect package.

Important

[2024-08-06] This pull request's branch is based on mcaskill:feature/maintenance #50 in order to work.

src/Plugin.php Outdated Show resolved Hide resolved
@mcaskill mcaskill changed the title Support EDD Add support for intermediary URLs such as EDD Jul 25, 2024
Add `strict_types` declaration to test files.
Add missing `config.allow-plugins` to `composer.json` files for Composer 2.2.0 and newer.

See https://getcomposer.org/allow-plugins
mcaskill added a commit to mcaskill/private-composer-installer that referenced this pull request Aug 6, 2024
Ensure platform requirement (PHP) is checked to ensure the appropriate dependencies are installed.

For example, ignoring that the platform is PHP 8.0 would install a version of symfony/console that expectes PHP 8.1.
Include testing for PHP 8.1, 8.2, 8.3, and 8.4 (allow to fail).
mcaskill added a commit to mcaskill/private-composer-installer that referenced this pull request Aug 6, 2024
Raphaël Droz and others added 7 commits August 6, 2024 13:40
Changed:
- Rewrite the summary of the method's block comment.
- Improve formatting, description, and example of `indirection` settings.
- Add notice to description about feature only being supported by Composer 2.
Use a "dot" notation string instead of a multidimensional array to specify a key path.

See: ffraenz#45 (comment) @ffraenz
Given the final download URL is most likely temporary and signed makes it unreliable as a cache key.
Check dist URL for URI fragment that matches a preset from the root package's extra object.

Update README to document presets and which options are root-only.
Intercept bad configuration, requests, and responses, to throw contextual exceptions to identify the affected private package.
@mcaskill mcaskill marked this pull request as ready for review August 9, 2024 19:41
@mcaskill
Copy link
Contributor Author

mcaskill commented Aug 9, 2024

This pull request is ready for review and testing.

Below are my responses to @ffraenz's comments on the previous pull request.


[…]

What I have in mind is adding a hash suffix #config-1 to the dist URL that we may use to target a specific configuration in extra.private-composer-installer.configs (for lack of a better name). This way multiple packages (from the same vendor) could reuse the same config. I would keep a config generic to allow for future additions that may be unrelated to an indirection feature.

[…]

A possible issue with a hash suffix for the preset is that a hash suffix might already be defined or will be appended by fulfillVersionPlaceholder()'s fallback.

Example: https://example.com/api/download?v=foo#preset-1#v1.2.3

I have not tested the integrity of cache keys and the lock file with preset fragments.


I don't like the way you provide the key location in the JSON payload using an object structure. I would go with a simple dot-notation string e.g. foo.bar.0.download_url to specify it.

Resolved.


Keep in mind that dist URLs without any placeholders should be ignored by this plugin to not alter unrelated packages. An indirection call must only be made if an indirection is actually configured (I think that's not the case right now in your code).

The proposed changes expects the inline package to either:

  • reference a root-level preset (extra.private-composer-installer.presets.*.indirection) from the private package's dist URL's fragment;
  • or define a package-level extra.private-composer-installer.indirection.

@ffraenz
Copy link
Owner

ffraenz commented Sep 2, 2024

@mcaskill Thank you so much for your work! I will come back to you and review it ASAP.

@ffraenz ffraenz changed the base branch from main to dev September 2, 2024 15:53
@mcaskill
Copy link
Contributor Author

mcaskill commented Sep 2, 2024

I just remembered a missing requirement to make this feature reliable: validate that the intermediary's version matches the author's required version in the package.

For example, EasyDigitalDownloads and Gravity Forms only ever offer the most recent version of their WordPress plugin.

The proposed parse.key should be renamed to parse.download_key and a parse.version_key be added.

We did this junaidbhura/composer-wp-pro-plugins to avoid downloading a newer version and caching it under the older version's key. For that Composer plugin, we added a requirement on composer/semver. We would have to see if we might be able to get away with just version_compare(). We would need the same requirement to ensure we can match the version formats and variations between author and vendor.

From `parse.key` to `parse.download_key` for forward compatibility with new keys.
Changed:
- Moved logic to search for key or key path in response body to a new static protected method `findValueInResponseBody()` for forward compatibility with new keys.
- Moved validation of download URL to a new static protected `sanitizeDownloadUrl()`.
- Replaced `$packageName` parameter with `$package`in method `fetchIndirection()` to allow greater control of indirection handling.
The `parse.version_key` setting, if specified, will attempt to ensure that the intermediary's download matches the package's required version constraint. This is necessary for Gravity Forms and plugins that use EDD.

This commit requires a dependency on composer/semver for proper version comparisons.
@mcaskill
Copy link
Contributor Author

mcaskill commented Sep 3, 2024

I've done some additional work today to add support for a version_key, support for unserialize() (Gravity Forms uses serialize() for its response), and a clean-up of tests. I'll try to push these changes tomorrow.

The `parse.format` now accepts either `json` or `serialize` (used by vendors such as Gravity Forms).

Improved error handling for intermediary JSON responses to exclude the intermediary URL from the message.
Changed:
- Renamed and sorted methods to better describe their intent.
- Refactored tests to use data providers to aggregate repetitive logic.
- Moved repretitive fixtures to static methods to reduce repetitive values.
@mcaskill
Copy link
Contributor Author

mcaskill commented Sep 3, 2024

I've deployed the latest changes and this should be ready for review and advanced testing.
I have not tested them in a real world scenario yet.

The decrease in coverage reported by Coveralls is because only the report for Composer v1 is submitted. This new feature is limited to Composer v2.

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.

Support plugins served by EDD
3 participants