if
if copied to clipboard
Build `if-env`
Sub of: #629 -> #650
What: A CLI tool that helps you setup your local environment to run a manifest file.
Why: As a user I want to be able to quickly create an environment to run my manifests, taking all my plugins into account.
Context: We can provide a command line tool that will inspect the package.jsons of the if and all the plugins listed in a manifest and create a unified package.json that can be used to define the environment in which the manifest can run. This will make it easy for users to run manifests and will also be useful scaffolding for our sandboxes, playgrounds and scenario testing. This ticket covers the design and specification but not the actual building of the tool.
DoD
- [ ] Feature merged into
ifmain branch - [ ] Feature documented on if.greensoftware.foundation
SoW
- [ ] TODO
Pre-requisites
- #591
Acceptance Criteria
- [ ] Running
if-envto setup a blank starter environment
GIVEN the user is in a folder
WHEN they run if-env with no parameters
THEN it generates a package.json file in the local directory which contains everything they need to start writing a manifest file with.
AND it generates a template manifest file called manifest.yml with a selection of fields prepopulated to help with development.
Here is a proposal for a template manifest.yml to create if if-env is executed from a folder with no local yaml files:
name: template manifest # rename me!
description: auto-generated template # update description!
tags: # add any tags that will help you to track your manifests
initialize:
outputs:
- yaml # you can add - csv to export to csv
plugins: # add more plugins for your use-case
memory-energy-from-memory-util: # you can name this any way you like!
method: Coefficient # the name of the function exported from the plugin
path: '@grnsft/if-plugins' # the import path
global-config: # anmy config required by the plugin
input-parameter: ['memory/utilization']
coefficient: 0.0001 #kwH/GB
output-parameter: 'memory/energy'
tree:
children: # add a chile for each distinct component you want to measure
child:
pipeline: # the pipeline is an ordered list of plugins you want to execute
- memory-energy-from-memory-util # must match the name in initialize!
config: # any plugin specific, node-level config
inputs:
- timestamp: 2023-12-12T00:00:00.000Z # ISO 8061 string
duration: 3600 # units of seconds
memory/utilization: 10
- [ ] Running
if-envto setup an environment to run a given manifest file
GIVEN the user has this manifest file
name: basic-demo
description:
tags:
initialize:
plugins:
teads-curve:
path: '@grnsft/if-unofficial-plugins'
method: TeadsCurve
global-config:
interpolation: spline
execution:
command: ie --manifest examples/basic.yml
environment:
os: ubuntu
os-version: 22.04.6
node version: v21.4.0
date-time: 2023-12-12T00:00:00.000Z (UTC)
dependencies:
- '@babel/[email protected]'
- '@babel/[email protected]'
- '@commitlint/[email protected]'
- '@commitlint/[email protected]'
- '@grnsft/[email protected]'
- '@grnsft/[email protected] (git+ssh://[email protected]/Green-Software-Foundation/if-plugins.git#8056a9593e3d41786d32dddb3e080bba75a8aa54)
- '@jest/[email protected]'
- '@types/[email protected]'
- '@types/[email protected]'
- '@types/[email protected]'
- '@types/[email protected]'
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
tree:
children:
child-0:
defaults:
cpu/thermal-design-power: 100
pipeline:
- teads-curve
inputs:
- timestamp: 2023-07-06T00:00
duration: 1
cpu/utilization: 20
AND they are in a folder which doesn't contain a package.json
WHEN they run if-env /path/to/<manifest>.yml
THEN it generates a package.json file in the local directory which contains all the script and dependencies required to run the manifest file.
- [ ] Running
if-envto create and install an environment to run a given manifest file
GIVEN the user has this manifest file
name: basic-demo
description:
tags:
initialize:
plugins:
teads-curve:
path: '@grnsft/if-unofficial-plugins'
method: TeadsCurve
global-config:
interpolation: spline
execution:
command: ie --manifest examples/basic.yml
environment:
os: ubuntu
os-version: 22.04.6
node version: v21.4.0
date-time: 2023-12-12T00:00:00.000Z (UTC)
dependencies:
- '@babel/[email protected]'
- '@babel/[email protected]'
- '@commitlint/[email protected]'
- '@commitlint/[email protected]'
- '@grnsft/[email protected]'
- '@grnsft/[email protected] (git+ssh://[email protected]/Green-Software-Foundation/if-plugins.git#8056a9593e3d41786d32dddb3e080bba75a8aa54)
- '@jest/[email protected]'
- '@types/[email protected]'
- '@types/[email protected]'
- '@types/[email protected]'
- '@types/[email protected]'
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
tree:
children:
child-0:
defaults:
cpu/thermal-design-power: 100
pipeline:
- teads-curve
inputs:
- timestamp: 2023-07-06T00:00
duration: 1
cpu/utilization: 20
AND they are in a folder which doesn't contain a package.json
WHEN they run if-env /path/to/manifest.yml --install
THEN it generates a package.json file in the local directory which contains all the script and dependencies required to run the manifest file
AND it runs npm install to install the dependencies.
@jmcook1186 and @narekhovhannisyan
Acceptance Criteria
Given the user has this manifest file: TODO - File with mix of plugibs installed from npm, GitHub, local npm link, and builtins When runs if-env /path/to/manifest.yml Then it generates a file in the local directory called package.json containing this info: TODO
Questions
To flesh out the above acceptance criteria I think we need to answer some questions:
How do we handle when a package that is being used is not in NPM? E.g. the user is using a non published plugin that's just on GitHub.
@narekhovhannisyan what happens when we install a package from GitHub? E.g. npm i https://github.com/user_name/node_project_name
- What does the package.json contain?
- How do we configure the manifest file to use this package? I'm assuming just by looking at the manifest file we won't be able to understand that you need to install it from GH.
How do we get the version numbers?
A) We have a ticket to add version numbers to the manifest file for each plugin, how would we get those? The output manifest file should update the initialise.plugins section to add a version parameter to each plugin which contains the current version of that plugin this manifest was run using B) If the manifest file does not have version numbers should we just install the latest?
Maybe one way is to log the latest commit hash or just the utc date/time if there is no version number available. At least those information allow you to recover a specific state of a repository that matches what you installed.
@jawache The Github project is registered in package.json's dependencies.
- package.json contains something like this when a Github dependency is installed:
{
"dependencies": {
"yourpackage": "https://github.com/yourpackage" // repository name is registered as a package
}
}
- Manifest can include either Github repository link or package name (both can do). But as you said we don't have guarantee that user will put it rather than repo name.
Thanks @narekhovhannisyan, I think we have enough now to refine this properly.
When you install from GitHub you call this command.
npm install https://github.com/Green-Software-Foundation/if-plugins
This adds this record to package.json
{
"name": "copy-plugin",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"@grnsft/if-plugins": "github:Green-Software-Foundation/if-plugins"
}
}
And when you run npm list you get this result
[email protected] /Users/jawache/Development/gsf/copy-plugin
└── @grnsft/[email protected] (git+ssh://[email protected]/Green-Software-Foundation/if-plugins.git#8056a9593e3d41786d32dddb3e080bba75a8aa54)
But when you configure the plugin in the manifest file you lose the link to github and version info.
Since we only contain information like so
operational-carbon:
path: '@grnsft/if-plugins'
method: Multiply
global-config:
input-parameters: ['cpu/energy', 'grid/carbon-intensity']
output-parameter: 'carbon'
Similarly when we install from npm directly like so
npm install @grnsft/if-unofficial-plugins
The package.json looks like this:
{
"name": "copy-plugin",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"@grnsft/if-plugins": "github:Green-Software-Foundation/if-plugins",
"@grnsft/if-unofficial-plugins": "^0.3.1"
}
}
And npm list returns
➜ copy-plugin npm list
[email protected] /Users/jawache/Development/gsf/copy-plugin
├── @grnsft/[email protected] (git+ssh://[email protected]/Green-Software-Foundation/if-plugins.git#8056a9593e3d41786d32dddb3e080bba75a8aa54)
└── @grnsft/[email protected]
So if-env needs to know the exact package names, versions and sources so it can compute the same packge.json as the manifest file was originally run in.
I'll update #591 with the relevant information but to summarize when computing a manifest file we should include the output from npm list in the execution node so that if-env has enough information to be able to generate a package.json that can run this manifest file.
@narekhovhannisyan are you happy with the AC and could implement?
@jmcook1186 and @narekhovhannisyan the only way this works in all cases is if the manifest file is an output manifest file and therefore has information regarding the execution and the dependancies. I've adjusted the AC above so the manifest files has execution blocks and added in a more complex use case with a plugin that's been installed from GitHub instead of NPM.
If it doesn't have an execution node with dependancies, or the plugin being configured isn't in the dependency list, then we perhaps can just assume the name of the package is the same as the path param and assume it's the latest version?
We should warn at least if that's the case. If we agree on that approach we need another AC @jmcook1186.
In terms of implementation I'm leaning towards if-env being selective and just output the configured plugins in the package.json. So in the above example rather than ouput all the same in package.json as exists in the dependancies node, just @grnsft/[email protected] since teads-curve is the only one we are using in the manifest file. What do you think? There are also pros to just listing everything in dependancies in the output package.json.
Makes sense @jawache - I had in mind that the main use case for this is re-execution and verification, so normally you would have an output file for this, not a raw unexecuted manifest.
So what I understand about this is:
-
if-envhas to check that each of the plugins in theinitializeblock has an associated entry in thepackage.json- if it doesn't it tries to grab it using thepath, either grabbing a numbered version or falling back tolatestand if that fails too (the path is just wrong) then it just errors out (invalid path for plugin xor similar). -
if
if-envhas to execute any of the logic described in bullet point 1, then it warns the user as its possible the versions are different to that originally used to execute the given file.
I personally have a weak preference towards if-env being comprehensive in the packages it reports, because you never know where an error might originate from and having that information available could be useful in ways that are hard to anticipate.
@jmcook1186 I see your point and agree, speaking to the intention of this script, it is to mirror the environment the manifest file was run in so perhaps that's the right approach, just output what's in dependencies in manifest to package.json. if there is something screwy in there causing issues we'd want to replicate it.
Perhaps in future updates we can explore other flags like --update to update all the packages to latest version, or --essential-only to mirror what I proposed with just the ones in the manifest file.
I haven't kept the list of estimations, so maybe L or XL
- XS - 1 hr
- S - 1-3 hrs
- M - 4-8 hrs
- L - 1-2 days
- XL - 3-5 days
- XXL - 5+ days
Expected to start working on this on Wed afternoon
@jmcook1186 Should I add a command like -m in this if-env /path/to/<manifest>.yml to be consistent with the other command line tools?
yes please, keep the shortened commands consistent with the other if tooling
@jmcook1186, what is the difference between if-env /path/to/<manifest>.yml and if-env /path/to/<manifest>.yml --install? If there isn't a package.json in the first case (if-env /path/to/if-env /path/to/<manifest>.yml command; if there is a package.json, should it only install dependencies?
if there is no package.json then if-env should create one with the IF core dependencies in the local repository, but not install. If the --install command is included but there is no package.json available then if-env should create it then install it.
@jmcook1186 The manifest.yml template file is not an executed manifest file. However, we require an executed manifest file from the user. Should we provide an executed manifest template?
No, the template will only be used when if-env finds no local yaml files.
The idea is that if-env can recreate a local environment from a given manifest, but if no manifest or package.json is provided then if-env creates templates for you to bootstrap you into your IF project development. Like using create-react-app or similar.
so:
- IF
if-envfinds an output file with anexecutionnode in the local folder then it uses the packages in theexecutionnode to create a localpackage.json - IF
if-envfinds a manifest file in the local folder then it adds the template package.json with the IF dependencies - IF
if-envfinds no yaml files in the local folder then it adds the template package.json with the IF dependencies and adds the template manifest
will finalise today/tomorrow morning
@manushak and @jmcook1186 to have a call in order to try and replicate the issue
Looks like it would be a great idea for @MariamKhalatova to retest this 🙏
@jmcook1186, could you please update the ticket according to our discussion so that @MariamKhalatova can refer to it while testing?
@narekhovhannisyan please review the latest push :)