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

Blueprints: Merging Blueprints #49

Open
adamziel opened this issue May 23, 2023 · 8 comments
Open

Blueprints: Merging Blueprints #49

adamziel opened this issue May 23, 2023 · 8 comments
Labels
enhancement New feature or request

Comments

@adamziel
Copy link
Collaborator

adamziel commented May 23, 2023

I want to be able to merge these two Blueprints:

{
    "landingPage": "/wp-admin/",
    "steps": [
        // .. Set up a blog ...
    ]
}
{
    "steps": [
        // .. Set up a woo store ...
    ]
}

And get a single Blueprint which sets up a site that's both a blog and a store

Known plugins with a Blueprint.json file

Let's use these Blueprints to explore the merging process

Related

@seanmorris
Copy link

seanmorris commented Nov 27, 2023

@adamziel For semver combinations, (ie "php": ">=7.4 <8.0") would it be appropriate to use logical-and space notation here? https://devhints.io/semver (see: Combining ranges)

It looks to be supported by the major semver libs in both JS & PHP:

https://www.npmjs.com/package/semver#advanced-range-syntax

https://getcomposer.org/doc/articles/versions.md#version-range
https://packagist.org/packages/composer/semver

@adamziel
Copy link
Collaborator Author

@seanmorris that could be an interesting direction! Probably nothing to worry about for now, though – the constraints field isn't supported at the moment. I was envisioning it while writing up this issue, but noone ever asked to actually implement it so maybe the demand isn't there.

@adamziel
Copy link
Collaborator Author

This Blueprint.json for the interactive-code-block plugin could come handy when exploring this issue: https://github.com/WordPress/playground-tools/blob/trunk/packages/interactive-code-block/public/blueprint.json @seanmorris

@dmsnell
Copy link
Member

dmsnell commented Nov 27, 2023

Consider each step and each property of the Blueprint as its own datatype. If we do that and take inspiration from the Monoid type class, we can think of each type having an append method (as well as an empty value empty that provides a no-op when appended to another).

For a PHP version the empty value is going to be >= 1 or perhaps for our sake >= 5.6.4. The append needs to find the intersection of intervals.

For steps we probably need to separate out those which demand sequence and those which don't. For plugins and theme installations then, the empty value is just an empty list, and the append merges two lists with uniqueness.

For inherently irreconcilable properties like landingPage we can form a deterministic semantic: first-in-wins or last-in-wins. The empty value is the default / and the append is replacement.

And so on.

@adamziel
Copy link
Collaborator Author

adamziel commented Nov 28, 2023

Oooh Monoid-ization is an interesting idea @dmsnell, thank you for that – I love it. In other words, the mental model is that each Blueprint is already a function composition like below:

blueprint_a = (phpVersion 7.0) . (installPlugin "gutenberg") . ( landingPage "/" )
blueprint_b = (installTheme "pendant" ) . (phpVersion 8.2) . (installPlugin "classic-editor")

But if so, merging them both would be just composing all the functions together:

blueprint_c =  blueprint_a . blueprint_b

Or perhaps even:

blueprint_a = (phpVersion 7.0) >>= (installPlugin "gutenberg") >>= ( landingPage "/" )
blueprint_b = (installTheme "pendant" ) >>= (phpVersion 8.2) >>= (installPlugin "classic-editor")
blueprint_c = blueprint_a >>= blueprint_b

@dmsnell
Copy link
Member

dmsnell commented Nov 28, 2023

the mental model is that each Blueprint is already a function composition like below:

more specifically, each kind of property in the Blueprint is, and any properties/steps that aren't explicitly defined are implicitly there with their empty value.

this is based on the idea that the properties are probably independent and most things are append-only. e.g. there's no removePlugin step.

const finalBlueprints = allBlueprints.reduce( mergeBlueprints, emptyBlueprints );

@seanmorris
Copy link

@adamziel not sure why this wasn't on the board, pulling it in.

adamziel referenced this issue in WordPress/playground-tools Feb 7, 2024
Adds a `playground` plugin for plugin-preview functionality and
renames the plugin to WordPress Playground.

Requires:
WordPress/wordpress-playground#745 .
https://github.com/WordPress/wordpress-playground/issues/419

## Why?

Users want to be able to preview plugins on their own sites before
actually committing to installing them live.

## Testing Instructions

- Checkout the project and copy the plugin to your local WordPress
install:
```bash
git checkout sm-collector-plugin
cp packages/collector/ [PATH_TO_YOUR_WORDPRESS]/wp-content/plugins/
```
- Open your local WordPress install and activate the WordPress
Playground plugin
- Start Playground by clicking on Tools > Sandbox Site in wp-admin
- After the site loads it should have the same content as your site
(files and database)

### Testing Previews
- Install this plugin on a site
- Navigate to `plugins` > `add new`
- Search for "Akismet"
- You should now see a `Preview Now` button next to the `Install Now`
button.
- Click `Preview now`, and you should see Playground boot your site with
the plugin activated.

---------

Co-authored-by: Sean Morris <[email protected]>
Co-authored-by: Adam Zielinski <[email protected]>
@adamziel adamziel transferred this issue from WordPress/wordpress-playground Feb 29, 2024
@adamziel
Copy link
Collaborator Author

Surfacing this relevant comment from Running Multiple Blueprints:

@swissspidy so if I understand correctly, you would like to:

  1. Set up a WordPress site with a Blueprint
  2. Run another Blueprint against that same WordPress site

...like in multi-stage Docker builds?

If so, you should be able to do it with:

npx @wp-playground/cli@latest run-blueprint --blueprint=my-blueprint.json --mount-before-install="./my-wp-dir:/wordpress"
npx @wp-playground/cli@latest run-blueprint --blueprint=remote-blueprint.json --mount-before-install="./my-wp-dir:/wordpress"

This will use your local directory as the base site without forcefully installing WordPress in VFS and using that.

I would love to support that natively in the Playground webapp. It should be fairly easy with the upcoming first-class support for stored sites. We could accept multiple Blueprints via the Query API or, alternatively, consider a run-blueprint step.

It related to Merging Blueprints, except merging would run two Blueprints at once and with sequential runs we could run the first Blueprint, wait a month, and run a second one. This seems similar to Docker base images.

Perhaps the "multistage build" strategy could become the first official way of "merging Blueprints". It's not quite merging, sure, but perhaps merging was the wrong idea all along. Multistage seems clean, doesn't require any special resolution rules, and conveniently it gives us multistage builds for free. And if it's ever not enough, then we can discuss where it falls short and how to address that. Ha! Thank you @swissspidy! This is why I really like letting some of these architectural problems simmer for a long time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Status: Backlog
Development

No branches or pull requests

3 participants