-
Notifications
You must be signed in to change notification settings - Fork 35
Account for package metadata that doesn't include filename when deriving hashed filename #496
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
base: release_1.4.1
Are you sure you want to change the base?
Changes from all commits
09abd75
df45edd
a56991c
76d2870
e66cc29
a29caf5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -687,21 +687,30 @@ function get_banners( $banners ) : array { | |
| * @return string | ||
| */ | ||
| function get_hashed_filename( $metadata ) : string { | ||
| $filename = $metadata->filename; | ||
| $type = str_replace( 'wp-', '', $metadata->type ); | ||
| $did_hash = '-' . get_did_hash( $metadata->id ); | ||
|
|
||
| list( $slug, $file ) = explode( '/', $filename, 2 ); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When
and the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the problem is that
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, the general package spec doesn’t require it so I think it makes sense that we support that scenario as a fallback. Arguably, WP determines the bootstrap file dynamically based on header presence (and themes don’t even need it) so I think should probably refactor this eventually.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We did update the spec and it now requires it.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @afragen I think the spec shouldn't require it. None of the WP packages have that concept (at least from the existing WP-org API perspective). I created #500 to illustrate how WP core resolves the In #500 I demonstrate how we can resolve all the necessary filename data from the canonical places in WP without having to assume or deal with mismatches on the filesystem (what |
||
| if ( 'plugin' === $type ) { | ||
| if ( ! str_contains( $slug, $did_hash ) ) { | ||
| $slug .= $did_hash; | ||
| } | ||
| $filename = $slug . '/' . $file; | ||
| } else { | ||
| $filename = $slug . $did_hash; | ||
| // Use the slug from the filename, if present. | ||
| list( $slug, $file ) = array_pad( explode( '/', $metadata->filename ?? '', 2 ), 2, '' ); | ||
| if ( '' === $slug ) { | ||
| $slug = $metadata->slug ?? ''; | ||
| } | ||
|
|
||
| // Default to slug matching the plugin filename, if not specified. | ||
| if ( '' === $file ) { | ||
| $file = $slug . '.php'; | ||
| } | ||
|
|
||
| // Append DID hash to slug if not already present. | ||
| if ( ! str_ends_with( $slug, $did_hash ) ) { | ||
| $slug .= $did_hash; | ||
| } | ||
|
|
||
| // WP plugins must include the plugin filename. | ||
| if ( 'wp-plugin' === ( $metadata->type ?? '' ) ) { | ||
| return $slug . '/' . $file; | ||
| } | ||
|
|
||
| return $filename; | ||
| return $slug; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, not sure I understand why a function named
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It returns the filename only for Feel free to push an update or I can update it if you can advise on the updated logic here. |
||
| } | ||
|
|
||
| /** | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,178 @@ | ||
| <?php | ||
| /** | ||
| * Tests for FAIR\Packages\get_hashed_filename(). | ||
| * | ||
| * @package FAIR | ||
| */ | ||
|
|
||
| use FAIR\Packages\MetadataDocument; | ||
| use function FAIR\Packages\get_did_hash; | ||
| use function FAIR\Packages\get_hashed_filename; | ||
|
|
||
| /** | ||
| * Tests for FAIR\Packages\get_hashed_filename(). | ||
| * | ||
| * @covers FAIR\Packages\get_hashed_filename | ||
| */ | ||
| class GetHashedFilenameTest extends WP_UnitTestCase { | ||
|
|
||
| /** | ||
| * Test that plugin filenames append the DID hash to the directory name. | ||
| */ | ||
| public function test_should_hash_plugin_directory_name() { | ||
| $metadata = $this->create_metadata_document( | ||
| [ | ||
| 'filename' => 'example/example.php', | ||
| 'slug' => 'example', | ||
| 'type' => 'wp-plugin', | ||
| ] | ||
| ); | ||
|
|
||
| $this->assertSame( 'example-' . get_did_hash( $metadata->id ) . '/example.php', get_hashed_filename( $metadata ) ); | ||
| } | ||
|
|
||
| /** | ||
| * Test that missing plugin filenames fall back to the slug. | ||
| */ | ||
| public function test_should_fall_back_to_slug_when_plugin_filename_missing() { | ||
| $metadata = $this->create_metadata_document( | ||
| [ | ||
| 'filename' => null, | ||
| 'slug' => 'example', | ||
| 'type' => 'wp-plugin', | ||
| ] | ||
| ); | ||
|
|
||
| $this->assertSame( 'example-' . get_did_hash( $metadata->id ) . '/example.php', get_hashed_filename( $metadata ) ); | ||
| } | ||
|
|
||
| /** | ||
| * Test that malformed plugin filenames still produce a valid hashed path. | ||
| */ | ||
| public function test_should_recover_when_plugin_filename_has_no_main_file() { | ||
| $metadata = $this->create_metadata_document( | ||
| [ | ||
| 'filename' => 'example', | ||
| 'slug' => 'example', | ||
| 'type' => 'wp-plugin', | ||
| ] | ||
| ); | ||
|
|
||
| $this->assertSame( 'example-' . get_did_hash( $metadata->id ) . '/example.php', get_hashed_filename( $metadata ) ); | ||
| } | ||
|
|
||
| /** | ||
| * Test that theme filenames append the DID hash to the slug. | ||
| */ | ||
| public function test_should_hash_theme_slug() { | ||
| $metadata = $this->create_metadata_document( | ||
| [ | ||
| 'filename' => 'example', | ||
| 'slug' => 'example', | ||
| 'type' => 'wp-theme', | ||
| ] | ||
| ); | ||
|
|
||
| $this->assertSame( 'example-' . get_did_hash( $metadata->id ), get_hashed_filename( $metadata ) ); | ||
| } | ||
|
|
||
| /** | ||
| * Test that missing non-plugin filenames still fall back to the slug. | ||
| */ | ||
| public function test_should_fall_back_to_slug_for_non_plugin_when_filename_missing() { | ||
| $metadata = $this->create_metadata_document( | ||
| [ | ||
| 'filename' => null, | ||
| 'slug' => 'example', | ||
| 'type' => 'wp-theme', | ||
| ] | ||
| ); | ||
|
|
||
| $this->assertSame( 'example-' . get_did_hash( $metadata->id ), get_hashed_filename( $metadata ) ); | ||
| } | ||
|
|
||
| /** | ||
| * Test that a pre-hashed plugin slug is not hashed twice. | ||
| */ | ||
| public function test_should_not_append_hash_twice_for_plugin_slug() { | ||
| $hash = get_did_hash( 'did:plc:example1234567890123456789' ); | ||
| $metadata = $this->create_metadata_document( | ||
| [ | ||
| 'filename' => 'example-' . $hash . '/example.php', | ||
| 'slug' => 'example-' . $hash, | ||
| 'type' => 'wp-plugin', | ||
| ] | ||
| ); | ||
|
|
||
| $this->assertSame( 'example-' . $hash . '/example.php', get_hashed_filename( $metadata ) ); | ||
| } | ||
|
|
||
| /** | ||
| * Test that a hash-like substring in the middle of the slug still gets the DID hash appended. | ||
| */ | ||
| public function test_should_append_hash_when_same_value_appears_in_middle_of_plugin_slug() { | ||
| $hash = get_did_hash( 'did:plc:example1234567890123456789' ); | ||
| $slug = 'vendor-' . $hash . '-plugin'; | ||
| $metadata = $this->create_metadata_document( | ||
| [ | ||
| 'filename' => $slug . '/' . $slug . '.php', | ||
| 'slug' => $slug, | ||
| 'type' => 'wp-plugin', | ||
| ] | ||
| ); | ||
|
|
||
| $this->assertSame( $slug . '-' . $hash . '/' . $slug . '.php', get_hashed_filename( $metadata ) ); | ||
| } | ||
|
|
||
| /** | ||
| * Test that empty plugin filenames behave the same as missing filenames. | ||
| */ | ||
| public function test_should_fall_back_to_slug_when_plugin_filename_is_empty_string() { | ||
| $metadata = $this->create_metadata_document( | ||
| [ | ||
| 'filename' => '', | ||
| 'slug' => 'example', | ||
| 'type' => 'wp-plugin', | ||
| ] | ||
| ); | ||
|
|
||
| $this->assertSame( 'example-' . get_did_hash( $metadata->id ) . '/example.php', get_hashed_filename( $metadata ) ); | ||
| } | ||
|
|
||
| /** | ||
| * Test that a missing type is treated as non-plugin metadata. | ||
| * | ||
| * This covers the operator precedence difference between | ||
| * `'wp-plugin' === ( $metadata->type ?? '' )` and | ||
| * `'wp-plugin' === $metadata->type ?? ''`. | ||
| */ | ||
| public function test_should_treat_missing_type_as_non_plugin_metadata() { | ||
| $metadata = (object) [ | ||
| 'id' => 'did:plc:example1234567890123456789', | ||
| 'slug' => 'example', | ||
| 'filename' => 'example/example.php', | ||
| ]; | ||
|
|
||
| $this->assertSame( 'example-' . get_did_hash( $metadata->id ), get_hashed_filename( $metadata ) ); | ||
| } | ||
|
|
||
| /** | ||
| * Create a metadata document for testing. | ||
| * | ||
| * @param array $overrides Document overrides. | ||
| * @return MetadataDocument | ||
| */ | ||
| private function create_metadata_document( array $overrides ) : MetadataDocument { | ||
| $metadata = new MetadataDocument(); | ||
| $metadata->id = 'did:plc:example1234567890123456789'; | ||
| $metadata->type = 'wp-plugin'; | ||
| $metadata->slug = 'example'; | ||
| $metadata->filename = 'example/example.php'; | ||
|
|
||
| foreach ( $overrides as $key => $value ) { | ||
| $metadata->{$key} = $value; | ||
| } | ||
|
|
||
| return $metadata; | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure the output type is always correct and use the constant value from the global namespace since that is what
defined( 'FAIR_DEFAULT_REPO_DOMAIN' )checks for.