Artifact Management on SAP BTP facilitates the generation of project metadata comprising of multiple modules of different technologies, bundles the module into one single deployment artifact and supports one click deploy to Cloud Foundry
- Access to project properties
- Access to VSCode workspace
- Provide list of modules and items of each module
- Watchers to notify of changes to project
- Support of tags and filter
- Capability to Test run
- Capability to generate MTA yaml and MTAR
- Deployment of MTAR to Cloud Foundry
- Plugins for SAP technologies such as MDK, FioriElement, CAP, XSUAA
- Node.JS 12 or higher
- CAP Development Kit (
npm install -g @sap/cds-dk
)
-
MTAR builder (
npm install -g mbt
) - Install [lerna] for mono-repo building (
npm install -g lerna
) - Install MDK-Tools,
npm install @sap/mdk-tools -g
-
Cloud Foundary CLI, Install cf-cli and run command
cf install-plugin multiapps
.
npm i -g @sap/artifact-management
There are two main sets of classes provided by the library.
-
ProjectApi
,ProjectImpl
: These are the interface and implmentation classes respectively for project level usages. -
WorkspaceApi
,WorkspaceImpl
: These are the interface and implmentation classes respectively for Workspace level usages.
You can import the module in your code as follows:
import { ProjectImpl } from '@sap/artifact-management';
To initialise Project API, instance of ProjectImpl has to be created which takes absolute path of a project.
import { ProjectImpl } from '@sap/artifact-management';
const path = '<my-application-folder-root-path>';
/**
* readModuleAsProject Default value is false.
* If the boolean is false, then only lcap/cap projects are read.
* If true then any project can also be read.
*/
const readModuleAsProject = false
const project = new ProjectImpl(path ,readModuleAsProject);
To initialise Workspace API, instance of WorkspaceImpl has to be created.
import { WorkspaceImpl } from '@sap/artifact-management';
const path = '<my-workspace-root-path>';
const workspace = new WorkspaceImpl(path);
or
import * as vscode from 'vscode';
import { WorkspaceImpl } from '@sap/artifact-management';
const workspace = new WorkspaceImpl(vscode);
The library also provides the object CommandExecutor to help create customized CLI tools. On BAS, for example, use the basctl tool to call Project API which resides on an BAS extenison.
Get all the projects in the workspace. Get the project based on tag if provided and Return type is array of ProjectAPIs / Returns ProjectAPI based on the tag.
getProjects(tag?: Tag) : Promise<ProjectApi[]>
- tag: (Optional)
Tag
value which can be used to filter projects.
- array of
ProjectApi
instance orundefined
import {Tag} from @sap/artifact-management' //Optional
const ws = new WorkspaceImpl(workspacePath);
const projects = await ws.getProjects();
Get the project with specific path.Return the ProjectAPI object based on the path.
getProject(path: string) : Promise<ProjectApi>
- path: the path of a project. It could be absolute or relative.
-
ProjectApi
instance orundefined
const ws = new WorkspaceImpl(workspacePath);
const path = '/Users/me/projects/lcap-project';
const project = await ws.getProject(path);
Get all project Uris in the workspace.
getProjectUris(): Promise<string[]>
- array of
string
orundefined
const ws = new WorkspaceImpl(workspacePath);
const projectUris = await ws.getProjectUris();
it detects File addition or deletions in workspace and triggers the updated event
startWatch() : void
void
const ws = new WorkspaceImpl(workspacePath);
await ws.startWatch();
it stops the watch event
stopWatch() : void
void
const ws = new WorkspaceImpl(workspacePath);
await ws.stopWatch();
it captures the add/remove events for the folders in the Workspace
onWorkspaceChanged(handler: (event: string, folders: string[]) => void) : void
- a
function
which takes a stringevent
("add" | "remove") and array ofstring
as arguments
void
import * as vscode from 'vscode';
const ws = new WorkspaceImpl(vscode);
ws.onWorkspaceChanged((event: string, folders: WorkspaceFolder[]) => {
// add implementation
});
it returns an IPluginManager instance which can be used to register the custom plugin.
getPluginManager() : IPluginManager
- an
IPluginManager
instance
import * as vscode from 'vscode';
const ws = new WorkspaceImpl(vscode);
const pluginManager = ws.getPluginManager();
pluginManager.register(customPlugin);
Read the entire project and return the information about project, its CAP modules and their items.
read(logger? : IChildLogger, tag? : Tag): Promise<Project | undefined>;
- logger: (Optional) An instance of IChildLogger which can be implemented by consumers of Project API.
- tag: (Optional)
Tag
value which can be used to filter projects.
-
Project
instance orundefined
import {Tag} from @sap/artifact-management' //Optional
const api = new ProjectImpl(projectPath);
const project = await api.read();
dev-project show <my-application-folder-root absolute path>
{
"type": "com.sap.cap",
"path": "<Absolute Path of Project>",
"prefix": "DemoProject",
"cloudService": "com.DemoProject",
"name": "DemoProject",
"tags": [
"project",
"cap"
],
"modules": [
{
"type": "com.sap.security.XsSecurity",
"name": "_To_Be_Generated_",
"path": "",
"items": []
}
]
}
Reads only Project level information without reading its modules and items. If there are MTA extension files in the project, the file list of MTA extension will be added to the info property in the returned PorjectData object.
getProjectInfo(logger? : IChildLogger): Promise<ProjectData | undefined>;
- logger: (Optional) An instance of IChildLogger which can be implemented by consumers of Project API.
-
ProjectData
orundefined
const api = new ProjectImpl(projectPath);
const project = await api.getProjectInfo();
dev-project get-project-info <my-application-folder-root absolute path>
{
"type": "com.sap.cap",
"path": "<Absolute Path of Project>",
"prefix": "DemoProject",
"cloudService": "com.DemoProject",
"name": "DemoProject",
"tags": [
"project",
"cap"
],
"info": {
"mtaExtensions": [
"extension1.mtaext",
"extension2.mtaext"
]
}
}
Reads only module level information for all the modules in the project without reading their items.
getModules(logger? : IChildLogger): Promise<ModuleData[] | undefined>;
- logger: (Optional) An instance of IChildLogger which can be implemented by consumers of this library.
- Array of
ModuleData
orundefined
const api = new ProjectImpl(projectPath);
const project = await api.getModules();
dev-project get-modules-info <my-application-folder-root absolute path>
[
{
"type": "com.sap.security.XsSecurity",
"name": "_To_Be_Generated_",
"path": ""
}
]
Read the entire project and return the information about all the items/entities in the project.
readItems(filter? : ItemFilter, logger? : IChildLogger) : Promise<Item[]>;
- filter: (Optional)
ItemFilter
which can be used to filter items in the project. - logger: (Optional) An instance of IChildLogger which can be implemented by consumers of this library.
- An array of
Item
import {ItemFilter} from @sap/artifact-management' //Optional
const api = new ProjectImpl(projectPath);
const project = await api.readItems();
Read all items
dev-project list-items <my-application-folder-root absolute path>
[
{
"external": false,
"name": "fioriApp",
"namespace": "sap.ui.demoproject",
"path": "db/schema.cds",
"ref": "sap.ui.demoproject.fioriApp",
"tags": [
"item",
"cap"
],
"type": "com.sap.cds/Entity"
},
...
...
...
]
Read the entire project and return the information about all the detail items/entities in the project.
readDetailItems(filter? : ItemFilter, logger? : IChildLogger) : Promise<Item[]>;
- filter: (Optional)
ItemFilter
which can be used to filter items in the project. - logger: (Optional) An instance of IChildLogger which can be implemented by consumers of this library.
- An array of
Item
import {ItemFilter} from @sap/artifact-management' //Optional
const api = new ProjectImpl(projectPath);
const project = await api.readDetailItems();
Read all items with detail information
dev-project list-detail-items <my-application-folder-root absolute path>
[
{
"external": false,
"name": "fioriApp",
"namespace": "sap.ui.demoproject",
"path": "db/schema.cds",
"ref": "sap.ui.demoproject.fioriApp",
"tags": [
"item",
"cap"
],
"type": "com.sap.cds/Entity",
"info": {
"attributes": {
"ID": {
"@Core.Computed": true,
"key": true,
"type": "cds.UUID"
},
"name": {
"type": "cds.String",
"length": 100
}
}
}
},
...
...
...
]
Read and watch the items/entities in the project. Any changes in the items addition, deletion or updation which match the watch criteria will be notified by the event updated
which is listened by ItemWatcherApi
.
watchItems(filter? : ItemFilter, logger? : IChildLogger) : Promise<ItemWatcherApi>;
- filter: (Optional)
ItemFilter
which can be used to filter items in the project. - logger: (Optional) An instance of IChildLogger which can be implemented by consumers of this library.
-
ItemWatcherApi
. This can be used to read the updated items.
import {ItemFilter} from @sap/artifact-management' //Optional
const project = new ProjectImpl(projectPath);
const itemWatcher = await project.watchItems();
const items = await itemWatcher.readItems();
itemWatcher.on('updated', () => {
console.log('Items updated');
});
Read all items
dev-project watch-items <my-application-folder-root absolute path>
Items can be filtered on basis of type
, tag
and ref
The filter can be passed in readItems
and watchItems
APIs as an argument which will return items based on the filter. Check readItems
and watchItems
APIs for further information
import {ItemFilter} from @sap/artifact-management'
// Filter by type
const filter: ItemFilter = {types: ["com.sap.cds/Entity"]};
// Filter by tags
const filter: ItemFilter = {tags: {values: ["db", "srv"]}};
// Filter by refs
const filter: ItemFilter= {refs: ["<item ref>"]};
const api = new ProjectImpl(projectPath);
const entities = await api.readItems(filter);
run(option?: string[] | undefined, logger? : IChildLogger ) : Promise<void>
It starts the CDS server and watches for any modifications in the files, if any changes detected it automatically restarts to serve the new content
- options: (Optional) run options. Comma separated list of options and their values. e.g. ['port', '8008', 'open']. Currently only supports port number and open option.
- logger: (Optional) An instance of IChildLogger which can be implemented by consumers of this library.
Promise<void>
const api = new ProjectImpl(projectPath);
await api.run();
dev-project run <my-application-folder-root absolute path> port 9039 open
build(options? : MtaGeneratorSettings, logger? : IChildLogger) : Promise<void>;
Generate manifest for the project and all the modules and create a mta.yaml
and <app-name>.mtar
file.
- options: (Optional)
MtaGeneratorSettings
build options. - logger: (Optional) An instance of IChildLogger which can be implemented by consumers of this library.
Promise<void>
const api = new ProjectImpl(projectPath);
await api.build();
dev-project build <my-application-folder-root absolute path>
_schema-version: '3.1'
ID: DemoProject
version: 1.0.0
description: A simple CAP project.
parameters:
enable-parallel-deployments: true
build-parameters:
before-all:
- builder: custom
commands:
- bash -c "cds compile srv --to xsuaa > xs-security.json"
- builder: custom
commands:
- npm install --production
- >-
bash -c "cds -v 2>/dev/null >/dev/null || npm install --no-save
@sap/cds-dk"
- npx cds build --production
modules:
- name: DemoProject-db-deployer
type: hdb
path: gen/db
parameters:
buildpack: nodejs_buildpack
build-parameters:
builder: npm
ignore:
- node_modules
requires:
- name: DemoProject-service-uaa
- name: DemoProject-service-db
...
...
...
resources:
- type: org.cloudfoundry.managed-service
name: DemoProject-service-uaa
parameters:
service: xsuaa
service-plan: application
service-name: DemoProject-uaa
path: xs-security.json
...
...
...
buildV2(options? : MtaGeneratorSettings, logger? : IChildLogger) : Promise<void>;
Generate manifest for the project and the modules specified in .status_tracker file and create a mta.yaml
and mtad.yaml
file.
- options: (Optional)
MtaGeneratorSettings
build options. - logger: (Optional) An instance of IChildLogger which can be implemented by consumers of this library.
Promise<void>
const api = new ProjectImpl(projectPath);
await api.buildV2();
dev-project buildV2 <my-application-folder-root absolute path>
_schema-version: '3.1'
ID: DemoProject
version: 1.0.0
description: A simple CAP project.
parameters:
enable-parallel-deployments: true
build-parameters:
before-all:
- builder: custom
commands:
- bash -c "cds compile srv --to xsuaa > xs-security.json"
- builder: custom
commands:
- npm install --production
- >-
bash -c "cds -v 2>/dev/null >/dev/null || npm install --no-save
@sap/cds-dk"
- npx cds build --production
modules:
- name: DemoProject-db-deployer
type: hdb
path: gen/db
parameters:
buildpack: nodejs_buildpack
build-parameters:
builder: npm
ignore:
- node_modules
requires:
- name: DemoProject-service-uaa
- name: DemoProject-service-db
...
...
...
resources:
- type: org.cloudfoundry.managed-service
name: DemoProject-service-uaa
parameters:
service: xsuaa
service-plan: application
service-name: DemoProject-uaa
path: xs-security.json
...
...
...
buildManifest(options? : MtaGeneratorSettings, logger? : IChildLogger) : Promise<void>;
Generate manifest for the project and all the modules and create a mta.yaml
- logger: (Optional) An instance of IChildLogger which can be implemented by consumers of Project API.
Promise<void>
const api = new ProjectImpl(projectPath);
await api.buildManifest();
or
const api = new ProjectImpl(projectPath);
await api.buildManifest({ui5version: '1.1112.3', ui5theme: 'sap_belize'});
getManifest(logger? : IChildLogger) : Promise<any>;
Get the content of the mta.yaml
file.
- logger: (Optional) An instance of IChildLogger which can be implemented by consumers of Project API.
Promise<any>
./src/project-api/bin/dev-project show-manifest ../risk-management-example
_schema-version: '3.1'
ID: cpapp
version: 1.0.0
description: "A simple CAP project."
parameters:
enable-parallel-deployments: true
build-parameters:
before-all:
- builder: custom
commands:
- npm install --production
...
...
modules:
- name: cpapp-app
type: html5
path: app
build-parameters:
builder: custom
commands:
- bash build.sh
supported-platforms: []
build-result: dist
...
...
deploy(logger? : IChildLogger) : Promise<void>;
Deploy the generated <app-name>.mtar
file to currently targeted CF space.
- logger: (Optional) An instance of IChildLogger which can be implemented by consumers of this library.
Promise<void>
const api = new ProjectImpl(projectPath);
await api.deploy();
Build and deploy in one step
dev-project deploy <my-application-folder-root absolute path>
deployV2(logger? : IChildLogger) : Promise<void>;
Generate the <app-name>.mtar
file based on contents of .status_tracker file and deploy to currently targeted CF space.
- logger: (Optional) An instance of IChildLogger which can be implemented by consumers of this library.
Promise<void>
const api = new ProjectImpl(projectPath);
await api.deployV2();
Build and deploy in one step
dev-project deployV2 <my-application-folder-root absolute path>
getProjectOverviewURL(logger? : IChildLogger) : Promise<string | undefined>;
Get the Project Overview URL of application deployed to currently targeted CF space.
- logger: (Optional) An instance of IChildLogger which can be implemented by consumers of Project API.
Promise<string | undefined>
const api = new ProjectImpl(projectPath);
const projectOverviewURL = await api.getProjectOverviewURL();
dev-project get-projectoverview-url <my-application-folder-root absolute path>
{
applicationOverviewURL : <projectOverviewURL>
}
getApplicationDeploymentSummary(logger? : IChildLogger) : Promise<{ ProjectOverviewURL?: string; DeployedUTCTime?: String; } | undefined>;
Get the Application Deployment Summary of application deployed to currently targeted CF space which contains ProjectOverviewURL and DeployedUTCTime.
- logger: (Optional) An instance of IChildLogger which can be implemented by consumers of Project API.
Promise<{ ProjectOverviewURL?: string; DeployedUTCTime?: String; } | undefined>
const api = new ProjectImpl(projectPath);
const applicationSummary = await api.getApplicationDeploymentSummary();
dev-project get-application-deployment-summary <my-application-folder-root absolute path>
{
applicationOverviewURL : <projectOverviewURL>,
DeployedUTCTime : <deployedUTCTime>
}
getDetailInfo(type: ItemType, ref: string, entityPath?: string, logger? : IChildLogger) :Promise<Item | undefined>;
Get additional detail information about a particular item.
- type:
ItemType
type of the Item. - ref: Unique reference of the Item.
- entityPath: (Optional) Path of the item.
- logger: (Optional) An instance of IChildLogger which can be implemented by consumers of this library.
-
Item
orundefined
import {ItemType} from "src/project-glue/ItemType.ts" //Optional
const api = new ProjectImpl(projectPath);
const entities = await api.getDetailInfo(type, ref, entityPath)
dev-project get-detail-info <my-application-folder-root absolute path> <type> <ref>
{
"type": "com.sap.cds/Entity",
"name": "fioriApp",
"ref": "sap.ui.demoproject.fioriApp",
"path": "schema.cds",
"info": {
"ID": {
"@Core.Computed": true,
"key": true,
"type": "cds.UUID"
},
"title": {
"type": "cds.String",
"length": 100
},
"owner": {
"type": "cds.String"
},
"descr": {
"type": "cds.String"
},
"miti": {
"type": "cds.Association",
"target": "sap.ui.demo.ui5App"
},
"impact": {
"type": "cds.Integer"
},
"criticality": {
"type": "cds.Integer"
}
}
}
getDataInfo(data: any, mainEntityName?: string, logger? : IChildLogger): Promise<any>;
Read and parse an Excel data file (CSV or XML format), or generate the main entity for a data model.
- data: Path of the data file, or a data model parsed from an Excel file.
- mainEntityName: (Optional) Name of the entity taken as the main entity.
- logger: (Optional) An instance of IChildLogger which can be implemented by consumers of this library.
Promise<any>
const api = new ProjectImpl(projectPath);
const data = await api.getDataInfo(filePath);
const dataWithMainEntity = await api.getDataInfo(data, 'mainEntity');
dev-project get-data-info <data file absolute path>
[
{
entity: "test",
labels: [
{ label: "ID", value: "ID" },
{ label: "Capex Request", value: "capex_request" },
{ label: "Total Cost", value: "total_cost" },
{ label: "Department", value: "department" },
],
props: [
{
name: "ID",
kind: "dataType",
type: "UUID",
key: "true",
isComputed: "true",
},
{
name: "capex_request",
kind: "dataType",
type: "Integer",
key: "false",
},
{
name: "total_cost",
kind: "dataType",
type: "Integer",
key: "false"
},
{
name: "department",
kind: "dataType",
type: "String",
key: "false"
},
],
values: [
["2d22e87a-4a74-43e3-8f0c-fa9de4c1d008", "1", "1000000", "Technology"],
["d6a88765-b2a1-4c4a-916d-a10c5d286b53", "2", "1500000", "Products"],
["66c76a6b-da32-41ff-89e8-bd38c787bd86", "3", "2000000", "Technology"],
],
dbProps: ["ID", "capex_request", "total_cost", "department"],
},
]