Design: Projects
This is a work in progress - I'm trying to capture the design as it evolves.
Last Update: 25th October.
Working code in the projects
branch.
- A project is a set of files that represent a complete, redistributable Node-RED application.
- The Runtime runs a single project at any one time, but the Editor provides an easy way to switch between projects.
- A project exists locally on disk, but can be linked to a remote git repository
Projects exist in the directory ~/.node-red/projects/
.node-red/
├── node_modules
├── package.json
├── projects
│ └── my-project
│ ├── .git
| ├── .gitignore
│ ├── flow.json
│ ├── flow_cred.json
│ ├── package.json
│ ├── README.md
│ └── settings.json
└── settings.js
-
A default project consists of:
- flow.json / flow_cred.json – the flow & credential files
- package.json – lists any node module dependencies
- README.md – documentation for the flow
- settings.json – project specific settings
-
The name of the flow file (default
flow.json
) will be customisable -
The editor will provide facilities to edit each of these files in the appropriate context.
-
TBD: A project could contain other files (such as public/html content). Should NR allows you to edit/manage them as well? We don’t want to become a generic IDE.
- The package.json file is the standard npm format.
- It lists the npm dependencies and any other project metadata.
- The dependencies do not get installed in the project directory – they get installed at the top level of the user directory (as they would today).
- It includes a
node-red
section, under which there is asettings
section
25-Oct: The purpose of the settings.json
file is not fully defined yet.
- The settings.json file contains project specific settings. They are a subset of those available in the top-level settings.js file. TBD: exactly what settings are supported.
- The settings file is strictly JSON. It cannot contain code as it must be reloadable without side-effects and be writeable by the runtime.
- Introduces the concept of flow-variables:
- Extend the existing $(ENV_VAR) support to include properties defined in the settings file.
- This makes it easier to deploy a flow to two different environments with environment-specific flow properties.
- TBD: describe the workflow for that.
- Runtime use of Projects
- Feature Flag
- Storage API
- Admin API
The goal is to minimise the changes needed in the core of the runtime. There is no need for the core runtime to be aware of projects - it just runs the flows it is given.
The current model is the runtime loads its flows/credentials from the Storage API (getFlows
) and we already provide an API to tell the runtime to reload its flows from Storage. None of that needs to change. The concept of projects will exist within the Storage layer.
getFlows/Credentials
will return the current active project flows. When the active project changes, the runtime is told to reload its flows and the storage api will return the new project's flows.
The projects feature will be behind a feature flag. The flag will be on by default but automatically disabled if:
- the user's settings file explicitly disabled projects (for example, in hosted environments)
- the storage plugin does not support the new projects api
The storage api will be extended to include the basic projects api. Not all storage implementations will be required to implement the project apis.
StorageModule.projects = {
init: init,
listProjects: Projects.list,
getActiveProject: getActiveProject,
setActiveProject: setActiveProject,
getProject: getProject,
createProject: createProject,
updateProject: updateProject,
getFiles: getFiles,
getFile: getFile,
stageFile: stageFile,
unstageFile: unstageFile,
commit: commit,
getFileDiff: getFileDiff,
getCommits: getCommits,
getCommit: getCommit,
}
Note: this api will grow as the feature is developed - this isn't the final API.
...
This API is subject to change as the implementation evolves.
-
GET /
- List projects -
POST /
- Create project -
PUT /:id
- Update project -
GET /:id
- Get project -
DELETE /:id
- Delete project (TODO) -
GET /:id/files
- Get a projects file listing -
GET /:id/files/:treeish/:filePath
- Get a file for a given treeish description, -
POST /:id/stage/:filePath
- Stage a file from the working dir to index -
POST /:id/stage
- Stage multiple files from the working dir to index -
POST /:id/commit
- Commit the current index -
DELETE /:id/stage/:filePath
- Unstage a file from the index -
DELETE /:id/stage
- Unstage multiple files from the index -
GET /:id/diff/:type/:filePath
- Get a file diff (type = tree | index) -
GET /:id/commits
- Get the project commits -
GET /:id/commits/:sha
- Get an individual commit
Returns a list of all projects available in the editor.
{
"active": "the name of the active project",
"projects": [
"project-a",
"another-project"
]
}
Notes: this may change to provide a bit more meta-data about each project rather than a flat list.
Create a new project.
{
"name": "my-new-project",
"remote": {
"url": "https://my-git-url.git"
}
"credentialSecret": "my-secret-key"
}
Notes:
- if
remote
isn't specified, this is a local-only project - if
remote
is specified and auth is required... need to design the flows
Get a project's metadata
{
"name": "my-project",
"description": "my-project\n====\n\nA Node-RED Project\n\n",
"dependencies": {
"node-red-node-random": "0.0.13"
}
}
If a project is in some sort of error state, its meta data will include an errors
property:
{
"name": "my-project",
...
"errors": [
{"error":"error_code","message":"error_description"}
]
}
Possible values for error_code
are:
-
invalid_credential_secret
- the credentials are encrypted and we don't have the key -
missing_dependencies
- modules listed in the project's package.json file are not installed -
missing_flow_file
- the cloned project does not appear to contain a flow file
Update an existing project.
Available actions include:
- sets the active project
- update the credentialSecret
- update remote repository details, including providing credentials when needed.
Note: need to refine how credentials can be challenged for and provided.
{
"active": true
}
Delete the project
Get a list of project files - subject to change with Version Control API design
Get an individual file's contents - - subject to change with Version Control API design
Update an individual file's contents - - subject to change with Version Control API design
- Create an empty project
- Create project with remote repo - no authentication needed
- Create project with remote repo - authentication needed
- Create a project as a copy of an existing one
- Set the active project in the runtime
client runtime
------ -------
{ POST /projects
"name": "<name>" ------------------> - create project directory
} - git init
- create default files
REDIRECT GET /projects/<name>
<-----------------
client runtime
------ -------
{ POST /projects
"name": "<name>" ------------------> - create project directory
"remote": { - git init
"url": "<giturl>" - git pull remote
}
}
REDIRECT GET /projects/<name>
<-----------------
client runtime
------ -------
{ POST /projects
"name": "<name>" ------------------> - create project directory
"remote": { - git init
"url": "<giturl>" - git pull remote
} - auth-fail - delete project directory
}
400: { error: "git_auth_fail", message: ""}
<-----------------
- gather auth info from user
{ POST /projects
"name": "<name>" ------------------> - create project directory
"remote": { - git init
"url": "<giturl>", - git pull remote inc credentials
"auth": {
"username": "nick",
"password": "pass"
}
}
REDIRECT GET /projects/<name>
<-----------------
client runtime
------ -------
{ POST /projects
"name": "<toName>", ------------------> - create project directory
"copy": "<fromName>" - git init
} - git pull from existing project
REDIRECT GET /projects/<toName>
<-----------------
client runtime
------ -------
{ PUT /projects/<name>
"active": "true" ------------------> - update the active project
} - tell the runtime to reload its flows
REDIRECT GET /projects/<name>
<-----------------