├── .npmrc
├── packages
├── ui5-app
│ ├── .npmrc
│ ├── test-ui5-webapp.cmd
│ ├── webapp
│ │ ├── css
│ │ │ └── style.css
│ │ ├── controller
│ │ │ ├── test
│ │ │ │ └── test.txt
│ │ │ └── MainView.controller.js
│ │ ├── img
│ │ │ └── ui5logo.jpg
│ │ ├── i18n
│ │ │ └── i18n.properties
│ │ ├── model
│ │ │ └── models.js
│ │ ├── view
│ │ │ └── MainView.view.xml
│ │ ├── index.html
│ │ ├── manifest.json
│ │ └── Component.js
│ ├── test-ui5-webapp-tp.cmd
│ ├── webapp_tp
│ │ ├── controller
│ │ │ ├── test
│ │ │ │ └── test.txt
│ │ │ └── MainView.controller.js
│ │ ├── css
│ │ │ └── style.css
│ │ ├── img
│ │ │ └── ui5logo.jpg
│ │ ├── i18n
│ │ │ └── i18n.properties
│ │ ├── model
│ │ │ └── models.js
│ │ ├── view
│ │ │ └── MainView.view.xml
│ │ ├── index.html
│ │ ├── manifest.json
│ │ └── Component.js
│ ├── test-ui5-webapp-create-tp.cmd
│ ├── test-ui5-deployer-cli-configfile.cmd
│ ├── README.md
│ ├── test-ui5-deployer-cli-tmp.cmd
│ ├── test-ui5-deployer-cli-tmp-empty.cmd
│ ├── .ui5deployrc-tmp
│ ├── .ui5deployrc-tmp-tp
│ ├── .ui5deployrc-tmp-create-tp
│ ├── ui5-webapp-tp.yaml
│ ├── ui5-webapp.yaml
│ ├── ui5-webapp-create-tp.yaml
│ ├── package.json
│ └── Gruntfile.js
├── grunt-nwabap-ui5uploader
│ ├── .npmrc
│ ├── tasks
│ │ ├── lib
│ │ │ └── Logger.js
│ │ └── grunt-nwabap-ui5uploader.js
│ ├── package.json
│ ├── CHANGELOG.md
│ └── README.md
├── ui5-nwabap-deployer-cli
│ ├── .npmrc
│ ├── bin
│ │ └── cli.js
│ ├── CHANGELOG.md
│ ├── lib
│ │ ├── log
│ │ │ └── Logger.js
│ │ ├── commands
│ │ │ ├── undeploy.js
│ │ │ └── deploy.js
│ │ └── config
│ │ │ └── configHandler.js
│ ├── package.json
│ └── README.md
├── ui5-nwabap-deployer-core
│ ├── .npmrc
│ ├── README.md
│ ├── package.json
│ ├── lib
│ │ ├── Util.js
│ │ ├── UI5ABAPRepoClient.js
│ │ ├── TransportManager.js
│ │ ├── AdtClient.js
│ │ └── ui5-nwabap-deployer-core.js
│ └── CHANGELOG.md
└── ui5-task-nwabap-deployer
│ ├── .npmrc
│ ├── ui5.yaml
│ ├── lib
│ ├── Logger.js
│ └── ui5-task-nwabap-deployer.js
│ ├── package.json
│ ├── CHANGELOG.md
│ └── README.md
├── .eslintignore
├── .github
└── workflows
│ └── pr-validation.yml
├── package.json
├── .eslintrc.json
├── .gitignore
├── README.md
└── LICENSE
/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
--------------------------------------------------------------------------------
/packages/ui5-app/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
--------------------------------------------------------------------------------
/packages/grunt-nwabap-ui5uploader/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
--------------------------------------------------------------------------------
/packages/ui5-nwabap-deployer-cli/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
--------------------------------------------------------------------------------
/packages/ui5-nwabap-deployer-core/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
--------------------------------------------------------------------------------
/packages/ui5-task-nwabap-deployer/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
--------------------------------------------------------------------------------
/packages/ui5-app/test-ui5-webapp.cmd:
--------------------------------------------------------------------------------
1 | ui5 build --config ./ui5-webapp.yaml
--------------------------------------------------------------------------------
/packages/ui5-app/webapp/css/style.css:
--------------------------------------------------------------------------------
1 | /* Enter your custom styles here */
--------------------------------------------------------------------------------
/packages/ui5-app/test-ui5-webapp-tp.cmd:
--------------------------------------------------------------------------------
1 | ui5 build --config ./ui5-webapp-tp.yaml
--------------------------------------------------------------------------------
/packages/ui5-app/webapp/controller/test/test.txt:
--------------------------------------------------------------------------------
1 | Test file for upload test.
--------------------------------------------------------------------------------
/packages/ui5-app/webapp_tp/controller/test/test.txt:
--------------------------------------------------------------------------------
1 | Test file for upload test.
--------------------------------------------------------------------------------
/packages/ui5-app/webapp_tp/css/style.css:
--------------------------------------------------------------------------------
1 | /* Enter your custom styles here */
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | # default
2 | dist/
3 | node_modules/
4 |
5 | # test
6 | packages/ui5-app/
--------------------------------------------------------------------------------
/packages/ui5-app/test-ui5-webapp-create-tp.cmd:
--------------------------------------------------------------------------------
1 | ui5 build --config ./ui5-webapp-create-tp.yaml
--------------------------------------------------------------------------------
/packages/ui5-app/webapp/img/ui5logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pfefferf/ui5-nwabap-deployer/HEAD/packages/ui5-app/webapp/img/ui5logo.jpg
--------------------------------------------------------------------------------
/packages/ui5-app/webapp_tp/img/ui5logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pfefferf/ui5-nwabap-deployer/HEAD/packages/ui5-app/webapp_tp/img/ui5logo.jpg
--------------------------------------------------------------------------------
/packages/ui5-app/test-ui5-deployer-cli-configfile.cmd:
--------------------------------------------------------------------------------
1 | ../../node_modules/.bin/ui5-deployer deploy --config ./.ui5deployrc-tmp --user developer --pwd notMyRealPwd
--------------------------------------------------------------------------------
/packages/ui5-app/webapp/i18n/i18n.properties:
--------------------------------------------------------------------------------
1 | title=Test grunt-nwapap-ui5uploader
2 | btnTxt=Press Me
3 | txtValue=Test for uploading UI5 sources to NW ABAP via grunt plugin.
--------------------------------------------------------------------------------
/packages/ui5-app/webapp_tp/i18n/i18n.properties:
--------------------------------------------------------------------------------
1 | title=Test grunt-nwapap-ui5uploader
2 | btnTxt=Press Me
3 | txtValue=Test for uploading UI5 sources to NW ABAP via grunt plugin.
--------------------------------------------------------------------------------
/packages/ui5-task-nwabap-deployer/ui5.yaml:
--------------------------------------------------------------------------------
1 | specVersion: "1.0"
2 | kind: extension
3 | type: task
4 | metadata:
5 | name: ui5-task-nwabap-deployer
6 | task:
7 | path: lib/ui5-task-nwabap-deployer.js
--------------------------------------------------------------------------------
/packages/ui5-app/README.md:
--------------------------------------------------------------------------------
1 | # UI5 application for testing
2 |
3 | This test application is used to test the `grunt-nwabap-ui5uploader`, the `ui5-nwabap-deployer` and the `ui5-nwabap-deployer-cli` tooling.
--------------------------------------------------------------------------------
/packages/ui5-app/test-ui5-deployer-cli-tmp.cmd:
--------------------------------------------------------------------------------
1 | ../../node_modules/.bin/ui5-deployer deploy --cwd ./webapp --server http://vhcala4hci:50000 --client 001 --language EN --package $TMP --bspContainer ZZ_GUI5UP_TMP01 --bspContainerText "Test UI5 Upload" --user developer --pwd notMyRealPwd
--------------------------------------------------------------------------------
/packages/ui5-app/test-ui5-deployer-cli-tmp-empty.cmd:
--------------------------------------------------------------------------------
1 | ../../node_modules/.bin/ui5-deployer deploy --cwd ./webapp_empty --server http://vhcala4hci:50000 --client 001 --language EN --package $TMP --bspContainer ZZ_GUI5UP_TMP01 --bspContainerText "Test UI5 Upload" --user developer --pwd notMyRealPwd
--------------------------------------------------------------------------------
/packages/ui5-app/.ui5deployrc-tmp:
--------------------------------------------------------------------------------
1 | {
2 | "cwd": "./webapp",
3 | "files": "**/*.*",
4 | "server": "http://vhcala4hci:50000",
5 | "client": "001",
6 | "useStrictSSL": false,
7 | "language": "EN",
8 | "package": "$TMP",
9 | "bspContainer": "ZZ_GUI5UP_TMP01",
10 | "bspContainerText": "Test UI5 Upload",
11 | "testMode": false
12 | }
13 |
--------------------------------------------------------------------------------
/packages/ui5-app/webapp/model/models.js:
--------------------------------------------------------------------------------
1 | sap.ui.define([
2 | "sap/ui/model/resource/ResourceModel"
3 | ], function(ResourceModel) {
4 | "use strict";
5 |
6 | return {
7 | createResourceModel: function(sBundleName) {
8 | var oResourceModel = new ResourceModel({
9 | "bundleName": sBundleName
10 | });
11 | return oResourceModel;
12 | }
13 |
14 | };
15 |
16 | });
--------------------------------------------------------------------------------
/packages/ui5-app/webapp_tp/model/models.js:
--------------------------------------------------------------------------------
1 | sap.ui.define([
2 | "sap/ui/model/resource/ResourceModel"
3 | ], function(ResourceModel) {
4 | "use strict";
5 |
6 | return {
7 | createResourceModel: function(sBundleName) {
8 | var oResourceModel = new ResourceModel({
9 | "bundleName": sBundleName
10 | });
11 | return oResourceModel;
12 | }
13 |
14 | };
15 |
16 | });
--------------------------------------------------------------------------------
/.github/workflows/pr-validation.yml:
--------------------------------------------------------------------------------
1 | name: pr-validation
2 |
3 | on:
4 | pull_request:
5 | branches: [ master ]
6 | jobs:
7 | validation:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v2
11 | - uses: actions/setup-node@v2
12 | with:
13 | node-version: '18'
14 | - run: npm install
15 | - run: npm run lint
16 |
--------------------------------------------------------------------------------
/packages/ui5-app/webapp/controller/MainView.controller.js:
--------------------------------------------------------------------------------
1 | sap.ui.define([
2 | "sap/ui/core/mvc/Controller",
3 | "sap/m/MessageToast"
4 | ], function(Controller, MessageToast) {
5 | "use strict";
6 |
7 | return Controller.extend("de.fpf.test.controller.MainView", {
8 | onPress: function(){
9 | MessageToast.show('Button pressed', {duration: 2000});
10 | }
11 | });
12 |
13 | });
--------------------------------------------------------------------------------
/packages/ui5-app/webapp_tp/controller/MainView.controller.js:
--------------------------------------------------------------------------------
1 | sap.ui.define([
2 | "sap/ui/core/mvc/Controller",
3 | "sap/m/MessageToast"
4 | ], function(Controller, MessageToast) {
5 | "use strict";
6 |
7 | return Controller.extend("de.fpf.test.controller.MainView", {
8 | onPress: function(){
9 | MessageToast.show('Button pressed', {duration: 2000});
10 | }
11 | });
12 |
13 | });
--------------------------------------------------------------------------------
/packages/ui5-app/.ui5deployrc-tmp-tp:
--------------------------------------------------------------------------------
1 | {
2 | "cwd": "./webapp_tp",
3 | "files": "**/*.*",
4 | "server": "http://vhcala4hci:50000",
5 | "client": "001",
6 | "useStrictSSL": false,
7 | "language": "EN",
8 | "package": "ZZ_UI5_REPOSITORY",
9 | "bspContainer": "ZZ_GUI5UP_TMP02",
10 | "bspContainerText": "Test UI5 Upload",
11 | "transportNo": "A4HK900098"
12 | }
13 |
--------------------------------------------------------------------------------
/packages/ui5-task-nwabap-deployer/lib/Logger.js:
--------------------------------------------------------------------------------
1 | const oLogger = require("@ui5/logger").getLogger("builder:customtask:nwabap-deployer");
2 |
3 | class Logger {
4 | log(message) {
5 | oLogger.info(message);
6 | }
7 |
8 | error(message) {
9 | oLogger.error(message);
10 | }
11 |
12 | logVerbose(message) {
13 | oLogger.verbose(message);
14 | }
15 | }
16 |
17 | module.exports = Logger;
18 |
--------------------------------------------------------------------------------
/packages/ui5-app/.ui5deployrc-tmp-create-tp:
--------------------------------------------------------------------------------
1 | {
2 | "cwd": "./webapp_tp",
3 | "files": "**/*.*",
4 | "server": "http://vhcala4hci:50000",
5 | "client": "001",
6 | "useStrictSSL": false,
7 | "language": "EN",
8 | "package": "ZZ_UI5_REPOSITORY",
9 | "bspContainer": "ZZ_GUI5UP_TMP02",
10 | "bspContainerText": "Test UI5 Upload",
11 | "createTransport": true,
12 | "transportText": "Test UI5 Deployment",
13 | "transportUseLocked": true
14 | }
15 |
--------------------------------------------------------------------------------
/packages/grunt-nwabap-ui5uploader/tasks/lib/Logger.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const PREFIX = "NWABAP UI5UPLOADER: ";
4 |
5 | class Logger {
6 | constructor(oGrunt) {
7 | this._oGrunt = oGrunt;
8 | }
9 |
10 | log(message) {
11 | this._oGrunt.log.writeln(PREFIX + message);
12 | }
13 |
14 | error(message) {
15 | this._oGrunt.log.writeln(PREFIX + message);
16 | }
17 |
18 | logVerbose(message) {
19 | this._oGrunt.verbose.writeln(PREFIX + message);
20 | }
21 | }
22 |
23 | module.exports = Logger;
24 |
--------------------------------------------------------------------------------
/packages/ui5-app/ui5-webapp-tp.yaml:
--------------------------------------------------------------------------------
1 | specVersion: "2.0"
2 | type: application
3 | metadata:
4 | name: ui5-app-webapp
5 | resources:
6 | configuration:
7 | paths:
8 | webapp: webapp_tp
9 | builder:
10 | customTasks:
11 | - name: ui5-task-nwabap-deployer
12 | afterTask: generateVersionInfo
13 | configuration:
14 | resources:
15 | pattern: "**/*.*"
16 | ui5:
17 | language: EN
18 | transportNo: A4HK900098
19 | package: ZZ_FP_UI5_REPOSITORY
20 | bspContainer: ZZ_GUI5UP_TMP02
21 | bspContainerText: Test UI5 Upload
--------------------------------------------------------------------------------
/packages/ui5-app/ui5-webapp.yaml:
--------------------------------------------------------------------------------
1 | specVersion: "2.0"
2 | type: application
3 | metadata:
4 | name: ui5-app-webapp
5 | resources:
6 | configuration:
7 | paths:
8 | webapp: webapp
9 | builder:
10 | customTasks:
11 | - name: ui5-task-nwabap-deployer
12 | afterTask: generateVersionInfo
13 | configuration:
14 | connection:
15 | customQueryParams:
16 | spnego: disabled/sap/bc/adt/cts/transports
17 | test2: 2
18 | resources:
19 | pattern: "**/*.*"
20 | ui5:
21 | language: EN
22 | package: $TMP
23 | bspContainer: ZZ_GUI5UP_TMP01
24 | bspContainerText: Test UI5 Upload
--------------------------------------------------------------------------------
/packages/ui5-nwabap-deployer-cli/bin/cli.js:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env node
2 | const scriptName = "ui5-deployer";
3 | const yargs = require("yargs");
4 | const deployCommand = require("../lib/commands/deploy");
5 | const undeployCommand = require("../lib/commands/undeploy");
6 |
7 | yargs(process.argv.slice(2))
8 | .usage("\nUI5 Deployer to deploy UI5 sources to a SAP ABAP system.")
9 | .scriptName(scriptName)
10 | .command(deployCommand)
11 | .command(undeployCommand)
12 | .demandCommand(1, "Command required. Please have a look at the help documentation above.")
13 | .strictCommands(true)
14 | .strictOptions(true)
15 | .help(true)
16 | .locale("en")
17 | .argv;
18 |
--------------------------------------------------------------------------------
/packages/ui5-app/webapp/view/MainView.view.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/packages/ui5-app/webapp_tp/view/MainView.view.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/packages/ui5-app/ui5-webapp-create-tp.yaml:
--------------------------------------------------------------------------------
1 | specVersion: "2.0"
2 | type: application
3 | metadata:
4 | name: ui5-app-webapp
5 | resources:
6 | configuration:
7 | paths:
8 | webapp: webapp_tp
9 | builder:
10 | customTasks:
11 | - name: ui5-task-nwabap-deployer
12 | afterTask: generateVersionInfo
13 | configuration:
14 | resources:
15 | pattern: "**/*.*"
16 | ui5:
17 | language: EN
18 | createTransport: true
19 | transportUseLocked: true
20 | transportUseUserMatch: false
21 | transportText: Test UIW-NWABAP-DEPLOYER Create Transport
22 | package: ZZ_FP_UI5_REPOSITORY
23 | bspContainer: ZZ_GUI5UP_TMP02
24 | bspContainerText: Test UI5 Upload
--------------------------------------------------------------------------------
/packages/ui5-app/webapp/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Test
9 |
10 |
17 |
18 |
19 |
20 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/packages/ui5-app/webapp_tp/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Test
9 |
10 |
17 |
18 |
19 |
20 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ui5-nwabap-deployer",
3 | "description": "UI5 Deployer to SAP NetWeaver ABAP",
4 | "version": "2.1.0",
5 | "author": {
6 | "name": "Florian Pfeffer",
7 | "email": "florian.pfeffer@outlook.com"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/pfefferf/ui5-nwabap-deployer.git"
12 | },
13 | "bugs": {
14 | "url": "https://github.com/pfefferf/ui5-nwabap-deployer/issues"
15 | },
16 | "license": "Apache-2.0",
17 | "licenses": [
18 | {
19 | "type": "Apache-2.0",
20 | "url": "https://github.com/pfefferf/ui5-nwabap-deployer/blob/master/LICENSE"
21 | }
22 | ],
23 | "keywords": [
24 | "SAP NetWeaver ABAP",
25 | "UI5 Repository",
26 | "SAPUI5",
27 | "OpenUI5"
28 | ],
29 | "devDependencies": {
30 | "eslint": "^8.34.0",
31 | "eslint-config-google": "^0.14.0"
32 | },
33 | "scripts": {
34 | "lint": "eslint ./",
35 | "lint:fix": "eslint ./ --fix"
36 | },
37 | "workspaces": [
38 | "./packages/*"
39 | ]
40 | }
41 |
--------------------------------------------------------------------------------
/packages/ui5-nwabap-deployer-core/README.md:
--------------------------------------------------------------------------------
1 | [](https://badge.fury.io/js/ui5-nwabap-deployer-core)
2 |
3 | # ui5-nwabap-deployer-core
4 |
5 | `ui5-nwabap-deployer-core` provides the core functionality to deploy UI5 sources to a SAP NetWeaver ABAP application server.
6 | It is used by the modules [grunt-nwabap-ui5uploader](https://github.com/pfefferf/ui5-nwabap-deployer/blob/master/packages/grunt-nwabap-ui5uploader/README.md) and the UI5 Tooling custom task [ui5-task-nwabap-deployer](https://github.com/pfefferf/ui5-nwabap-deployer/blob/master/packages/ui5-task-nwabap-deployer/README.md). In addition it is used for the UI5 Deployer CLI tooling [ui5-nwabap-deployer-cli](https://github.com/pfefferf/ui5-nwabap-deployer/blob/master/packages/ui5-nwabap-deployer-cli/README.md).
7 |
8 | ## Release History
9 |
10 | [CHANGELOG.md](https://github.com/pfefferf/ui5-nwabap-deployer/blob/master/packages/ui5-nwabap-deployer-core/CHANGELOG.md)
11 |
12 | ## License
13 |
14 | [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0)
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "node": true,
4 | "es6": true
5 | },
6 | "parserOptions": {
7 | "ecmaVersion": 2017
8 | },
9 | "extends": ["eslint:recommended", "google"],
10 | "rules": {
11 | "quotes": [
12 | "error",
13 | "double",
14 | { "allowTemplateLiterals": true }
15 | ],
16 | "semi": [
17 | "error",
18 | "always"
19 | ],
20 | "no-negated-condition": "off",
21 | "require-jsdoc": "off",
22 | "no-mixed-requires": "off",
23 | "max-len": "off",
24 | "no-implicit-coercion": [
25 | 2,
26 | { "allow": ["!!"] }
27 | ],
28 | "comma-dangle": "off",
29 | "no-tabs": "off",
30 | "no-console": "off",
31 | "valid-jsdoc": "off",
32 | "linebreak-style": "off",
33 | "indent": "off",
34 | "no-async-promise-executor": "off",
35 | "no-prototype-builtins": "off",
36 | "object-curly-spacing": "off"
37 | },
38 | "root": true
39 | }
--------------------------------------------------------------------------------
/packages/ui5-task-nwabap-deployer/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ui5-task-nwabap-deployer",
3 | "version": "2.1.1",
4 | "description": "UI5 Tooling Task for deploying UI5 sources to a SAP NetWeaver ABAP system",
5 | "author": {
6 | "name": "Florian Pfeffer",
7 | "email": "florian.pfeffer@outlook.com"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/pfefferf/ui5-nwabap-deployer.git"
12 | },
13 | "bugs": {
14 | "url": "https://github.com/pfefferf/ui5-nwabap-deployer/issues"
15 | },
16 | "license": "Apache-2.0",
17 | "licenses": [
18 | {
19 | "type": "Apache-2.0",
20 | "url": "https://github.com/pfefferf/ui5-nwabap-deployer/blob/master/LICENSE"
21 | }
22 | ],
23 | "engines": {
24 | "node": ">= 12",
25 | "npm": ">= 7"
26 | },
27 | "main": "lib/ui5-task-nwabap-deployer.js",
28 | "directories": {
29 | "lib": "lib"
30 | },
31 | "scripts": {},
32 | "dependencies": {
33 | "@ui5/logger": "^2.0.0",
34 | "ui5-nwabap-deployer-core": "^2.2.0",
35 | "dotenv": "^8.2.0"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/packages/grunt-nwabap-ui5uploader/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "grunt-nwabap-ui5uploader",
3 | "version": "2.2.0",
4 | "description": "UI5 source upload to SAP NetWeaver ABAP",
5 | "author": {
6 | "name": "Florian Pfeffer",
7 | "email": "florian.pfeffer@outlook.com"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/pfefferf/ui5-nwabap-deployer.git"
12 | },
13 | "bugs": {
14 | "url": "https://github.com/pfefferf/ui5-nwabap-deployer/issues"
15 | },
16 | "license": "Apache-2.0",
17 | "licenses": [
18 | {
19 | "type": "Apache-2.0",
20 | "url": "https://github.com/pfefferf/ui5-nwabap-deployer/blob/master/LICENSE"
21 | }
22 | ],
23 | "engines": {
24 | "node": ">= 12",
25 | "npm": ">= 7"
26 | },
27 | "keywords": [
28 | "gruntplugin",
29 | "SAP NetWeaver ABAP",
30 | "UI5 Repository",
31 | "SAPUI5",
32 | "OpenUI5"
33 | ],
34 | "devDependencies": {
35 | "grunt": "^1.0.1"
36 | },
37 | "dependencies": {
38 | "ui5-nwabap-deployer-core": "^2.2.0"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/packages/ui5-nwabap-deployer-core/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ui5-nwabap-deployer-core",
3 | "version": "2.2.6",
4 | "description": "UI5 Deployer to SAP NetWeaver - Core",
5 | "author": {
6 | "name": "Florian Pfeffer",
7 | "email": "florian.pfeffer@outlook.com"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/pfefferf/ui5-nwabap-deployer.git"
12 | },
13 | "bugs": {
14 | "url": "https://github.com/pfefferf/ui5-nwabap-deployer/issues"
15 | },
16 | "license": "Apache-2.0",
17 | "licenses": [
18 | {
19 | "type": "Apache-2.0",
20 | "url": "https://github.com/pfefferf/ui5-nwabap-deployer/blob/master/LICENSE"
21 | }
22 | ],
23 | "engines": {
24 | "node": ">= 12",
25 | "npm": ">= 7"
26 | },
27 | "main": "lib/ui5-nwabap-deployer-core.js",
28 | "directories": {
29 | "lib": "lib"
30 | },
31 | "files": [
32 | "lib"
33 | ],
34 | "scripts": {},
35 | "dependencies": {
36 | "axios": "^1.12.0",
37 | "retry-axios": "^2.6.0",
38 | "xmldoc": "^2.0.2",
39 | "yazl": "^3.3.1"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/packages/ui5-app/webapp/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "_version": "1.12.0",
3 | "sap.app": {
4 | "id": "de.fpf.test.UploadTest01",
5 | "type": "application",
6 | "i18n": "i18n/i18n.properties",
7 | "applicationVersion": {
8 | "version": "1.0.0"
9 | },
10 | "title": "{{appTitle}}",
11 | "description": "{{appDescription}}",
12 | "ach": "ach"
13 | },
14 | "sap.ui": {
15 | "technology": "UI5",
16 | "icons": {
17 | "icon": "",
18 | "favIcon": "",
19 | "phone": "",
20 | "phone@2": "",
21 | "tablet": "",
22 | "tablet@2": ""
23 | },
24 | "deviceTypes": {
25 | "desktop": true,
26 | "tablet": true,
27 | "phone": true
28 | }
29 | },
30 | "sap.ui5": {
31 | "dependencies": {
32 | "minUI5Version": "1.60.1",
33 | "libs": {
34 | "sap.ui.core": {},
35 | "sap.ui.layout": {},
36 | "sap.m": {}
37 | }
38 | },
39 | "contentDensities": {
40 | "compact": true,
41 | "cozy": true
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/packages/ui5-app/webapp_tp/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "_version": "1.12.0",
3 | "sap.app": {
4 | "id": "de.fpf.test.UploadTest02_TP",
5 | "type": "application",
6 | "i18n": "i18n/i18n.properties",
7 | "applicationVersion": {
8 | "version": "1.0.0"
9 | },
10 | "title": "{{appTitle}}",
11 | "description": "{{appDescription}}",
12 | "ach": "ach"
13 | },
14 | "sap.ui": {
15 | "technology": "UI5",
16 | "icons": {
17 | "icon": "",
18 | "favIcon": "",
19 | "phone": "",
20 | "phone@2": "",
21 | "tablet": "",
22 | "tablet@2": ""
23 | },
24 | "deviceTypes": {
25 | "desktop": true,
26 | "tablet": true,
27 | "phone": true
28 | }
29 | },
30 | "sap.ui5": {
31 | "dependencies": {
32 | "minUI5Version": "1.60.1",
33 | "libs": {
34 | "sap.ui.core": {},
35 | "sap.ui.layout": {},
36 | "sap.m": {}
37 | }
38 | },
39 | "contentDensities": {
40 | "compact": true,
41 | "cozy": true
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/packages/ui5-nwabap-deployer-cli/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 2.2.0 (2021-07-21)
2 |
3 | ### Features
4 | - New option `testMode` for deployment execution in test mode.
5 |
6 | ## 2.1.0 (2021-06-21)
7 |
8 | ### Features
9 | - `undeploy` command supports undeploying a UI5 application.
10 |
11 | ## 2.0.0 (2021-06-18)
12 |
13 | ### Features
14 | - Usage of /UI5/ABAP_REPOSITORY_SRV service for deployment instead of Team Provider API.
15 | Team Provider API was set to deprecated. As a consequence starting from version 2.0.0 this deployer supports only systems with at least SAP_UI 753 component installed.
16 | For all previous versions, version 1.x.x of this deployer needs to be used.
17 |
18 | ## 1.0.4 (2021-05-02)
19 |
20 | ### Fixes
21 | - Exit process; use exitCode instead of hard process.exit call.
22 |
23 | ## 1.0.3 (2021-05-02)
24 |
25 | ### Fixes
26 | - Exit process with status 1 in case of errors.
27 |
28 | ## 1.0.2 (2021-04-30)
29 |
30 | ### Features
31 | - Support for bearer token authorization.
32 |
33 | ## 1.0.1 (2021-04-10)
34 |
35 | ### Fixes
36 | - Correction of typos in demandCommand message.
37 |
38 | ## 1.0.0 (2021-04-10)
39 |
40 | ### General
41 | - Initial release.
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (https://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # TypeScript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 |
60 | # next.js build output
61 | .next
62 |
63 | # build directories
64 | dist/
--------------------------------------------------------------------------------
/packages/ui5-nwabap-deployer-cli/lib/log/Logger.js:
--------------------------------------------------------------------------------
1 | const winston = require("winston");
2 |
3 | class Logger {
4 | constructor() {
5 | this.logger = winston.createLogger({
6 | transports: [
7 | new winston.transports.Console({
8 | format: winston.format.combine(
9 | winston.format.timestamp({
10 | format: "YYYY-MM-DD HH:mm:ss"
11 | }),
12 | winston.format.colorize(),
13 | winston.format.printf((msg) => {
14 | if (typeof(msg.message) === "object") {
15 | return `${msg.timestamp} ${msg.level}: ${JSON.stringify(msg.message, null, 4)}`;
16 | }
17 | return `${msg.timestamp} ${msg.level}: ${msg.message}`;
18 | })
19 | )
20 | })
21 | ]
22 | });
23 | }
24 |
25 | log(message) {
26 | this.logger.info(message);
27 | }
28 |
29 | error(message) {
30 | this.logger.error(message);
31 | }
32 |
33 | logVerbose(message) {
34 | this.logger.verbose(message);
35 | }
36 | }
37 |
38 | module.exports = Logger;
39 |
--------------------------------------------------------------------------------
/packages/ui5-app/webapp/Component.js:
--------------------------------------------------------------------------------
1 | sap.ui.define([
2 | "sap/ui/core/UIComponent",
3 | "sap/ui/Device",
4 | "de/fpf/test/model/models"
5 | ], function(UIComponent, Device, models) {
6 | "use strict";
7 |
8 | return UIComponent.extend("de.fpf.test.Component", {
9 |
10 | metadata: {
11 | "version": "1.0.0",
12 | "rootView": {
13 | viewName: "de.fpf.test.view.MainView",
14 | type: sap.ui.core.mvc.ViewType.XML
15 | },
16 | "dependencies": {
17 | "libs": ["sap.ui.core", "sap.m", "sap.ui.layout"]
18 | },
19 | "config": {
20 | "i18nBundle": "de.fpf.test.i18n.i18n",
21 | "icon": "",
22 | "favIcon": "",
23 | "phone": "",
24 | "phone@2": "",
25 | "tablet": "",
26 | "tablet@2": ""
27 | }
28 | },
29 |
30 | /**
31 | * The component is initialized by UI5 automatically during the startup of the app and calls the init method once.
32 | * In this method, the resource and application models are set.
33 | * @public
34 | * @override
35 | */
36 | init: function() {
37 | var mConfig = this.getMetadata().getConfig();
38 |
39 | // set the i18n model
40 | this.setModel(models.createResourceModel(mConfig.i18nBundle), "i18n");
41 |
42 | // call the base component's init function
43 | UIComponent.prototype.init.apply(this, arguments);
44 | }
45 | });
46 |
47 | });
--------------------------------------------------------------------------------
/packages/ui5-app/webapp_tp/Component.js:
--------------------------------------------------------------------------------
1 | sap.ui.define([
2 | "sap/ui/core/UIComponent",
3 | "sap/ui/Device",
4 | "de/fpf/test/model/models"
5 | ], function(UIComponent, Device, models) {
6 | "use strict";
7 |
8 | return UIComponent.extend("de.fpf.test.Component", {
9 |
10 | metadata: {
11 | "version": "1.0.0",
12 | "rootView": {
13 | viewName: "de.fpf.test.view.MainView",
14 | type: sap.ui.core.mvc.ViewType.XML
15 | },
16 | "dependencies": {
17 | "libs": ["sap.ui.core", "sap.m", "sap.ui.layout"]
18 | },
19 | "config": {
20 | "i18nBundle": "de.fpf.test.i18n.i18n",
21 | "icon": "",
22 | "favIcon": "",
23 | "phone": "",
24 | "phone@2": "",
25 | "tablet": "",
26 | "tablet@2": ""
27 | }
28 | },
29 |
30 | /**
31 | * The component is initialized by UI5 automatically during the startup of the app and calls the init method once.
32 | * In this method, the resource and application models are set.
33 | * @public
34 | * @override
35 | */
36 | init: function() {
37 | var mConfig = this.getMetadata().getConfig();
38 |
39 | // set the i18n model
40 | this.setModel(models.createResourceModel(mConfig.i18nBundle), "i18n");
41 |
42 | // call the base component's init function
43 | UIComponent.prototype.init.apply(this, arguments);
44 | }
45 | });
46 |
47 | });
--------------------------------------------------------------------------------
/packages/ui5-nwabap-deployer-cli/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ui5-nwabap-deployer-cli",
3 | "version": "2.2.0",
4 | "description": "Deploying UI5 sources to a SAP NetWeaver ABAP system using CLI",
5 | "author": {
6 | "name": "Florian Pfeffer",
7 | "email": "florian.pfeffer@outlook.com"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/pfefferf/ui5-nwabap-deployer.git"
12 | },
13 | "bugs": {
14 | "url": "https://github.com/pfefferf/ui5-nwabap-deployer/issues"
15 | },
16 | "license": "Apache-2.0",
17 | "licenses": [
18 | {
19 | "type": "Apache-2.0",
20 | "url": "https://github.com/pfefferf/ui5-nwabap-deployer/blob/master/LICENSE"
21 | }
22 | ],
23 | "engines": {
24 | "node": ">= 12",
25 | "npm": ">= 7"
26 | },
27 | "bin": {
28 | "ui5-deployer": "./bin/cli.js"
29 | },
30 | "directories": {
31 | "bin": "./bin",
32 | "lib": "./lib"
33 | },
34 | "scripts": { },
35 | "dependencies": {
36 | "glob": "^11.0.3",
37 | "ui5-nwabap-deployer-core": "^2.2.0",
38 | "winston": "^3.3.3",
39 | "yargs": "^18.0.0"
40 | },
41 | "keywords": [
42 | "UI5",
43 | "SAPUI5",
44 | "OpenUI5",
45 | "CLI",
46 | "ui5-deployer",
47 | "SAP",
48 | "NetWeaver",
49 | "ABAP"
50 | ]
51 | }
52 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ui5-nwabap-deployer
2 | UI5 Deployer to SAP NetWeaver ABAP application server
3 |
4 | This monorepo manages following packages which are used for deploying UI5 sources to a SAP NetWeaver ABAP application server.
5 | - [grunt-nwabap-ui5uploader](./packages/grunt-nwabap-ui5uploader/README.md): Grunt task to deploy UI5 sources.
6 | - [ui5-task-nwabap-deployer](./packages/ui5-task-nwabap-deployer/README.md): UI5 Tooling custom task to deploy UI5 sources.
7 | - [ui5-nwabap-deployer-cli](./packages/ui5-nwabap-deployer-cli/README.md): CLI to deploy UI5 sources.
8 |
9 | All tools use as base the [ui5-nwabap-deployer-core](./packages/ui5-nwabap-deployer-core/README.md) package which provides the core functionality for the UI5 source deployment.
10 |
11 | Starting from version 2.0.0 the deployer functionalities use the OData Service [/UI5/ABAP_RESPOSITORY_SRV](https://ui5.sap.com/#/topic/a883327a82ef4cc792f3c1e7b7a48de8) for deploying UI5 sources. Please make sure that the service is activated on your system (for details you can check SAP note [2999557](https://launchpad.support.sap.com/#/notes/2999557)). The new service does some sanity checks like e.g. virus scans. If you have not configured virus scan profiles or want to disable virus scanning please have a look to SAP note [2437892](https://launchpad.support.sap.com/#/notes/2437892).
12 | Current deployer versions starting from version 2.0.0 can be used with SAP systems on which component SAP_UI 753 is installed. On systems with a lower version of component SAP_UI, you have to use version 1.x.x of this deployer.
--------------------------------------------------------------------------------
/packages/ui5-nwabap-deployer-core/lib/Util.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | /**
4 | * Object type
5 | * @type {{file: string, folder: string}}
6 | */
7 | const OBJECT_TYPE = {
8 | file: "file",
9 | folder: "folder"
10 | };
11 |
12 | /**
13 | * HTTP status
14 | * @type {{ok: number, created: number, bad_request: number, not_authorized: number, not_found: number, not_allowed: number}}
15 | */
16 | const HTTPSTAT = {
17 | ok: 200,
18 | created: 201,
19 | no_content: 204,
20 | bad_request: 400,
21 | not_authorized: 403,
22 | not_found: 404,
23 | not_allowed: 405,
24 | int_error: 500
25 | };
26 |
27 | /**
28 | * Modification Identifier
29 | * @type {{create: string, update: string, delete: string}}
30 | */
31 | const MODIDF = {
32 | create: "create",
33 | update: "update",
34 | delete: "delete"
35 | };
36 |
37 | /**
38 | * Split a value into the path and object information
39 | * @param {string} sValue values like /test/test1.txt
40 | * @return {{path: string, obj: string}} Path object
41 | */
42 | function splitIntoPathAndObject(sValue) {
43 | const aValues = sValue.split("/");
44 | const sObject = aValues.pop();
45 | let sPath = aValues.join("/");
46 | if (sPath.length > 0 && sPath.charAt(0) !== "/") {
47 | sPath = "/" + sPath;
48 | }
49 | return {
50 | path: sPath,
51 | obj: sObject
52 | };
53 | }
54 |
55 | /**
56 | *
57 | * @param {object} oError error
58 | * @return {string} response error string
59 | */
60 | function createResponseError(oError) {
61 | if (oError) {
62 | return String(oError);
63 | }
64 |
65 | return null;
66 | }
67 |
68 | /**
69 | * export
70 | */
71 | exports.OBJECT_TYPE = OBJECT_TYPE;
72 | exports.HTTPSTAT = HTTPSTAT;
73 | exports.MODIDF = MODIDF;
74 | exports.splitIntoPathAndObject = splitIntoPathAndObject;
75 | exports.createResponseError = createResponseError;
76 |
--------------------------------------------------------------------------------
/packages/ui5-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ui5-app",
3 | "version": "2.2.0",
4 | "description": "Test",
5 | "author": {
6 | "name": "Florian Pfeffer",
7 | "email": "florian.pfeffer@outlook.com"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/pfefferf/ui5-nwabap-deployer.git"
12 | },
13 | "bugs": {
14 | "url": "https://github.com/pfefferf/ui5-nwabap-deployer/issues"
15 | },
16 | "license": "Apache-2.0",
17 | "licenses": [
18 | {
19 | "type": "Apache-2.0",
20 | "url": "https://github.com/pfefferf/ui5-nwabap-deployer/blob/master/LICENSE"
21 | }
22 | ],
23 | "engines": {
24 | "node": ">= 12",
25 | "npm": ">= 7"
26 | },
27 | "devDependencies": {
28 | "@ui5/cli": "^3.0.0",
29 | "grunt": "^1.0.1",
30 | "grunt-nwabap-ui5uploader": "2.1.0",
31 | "ui5-nwabap-deployer-cli": "2.2.0",
32 | "ui5-task-nwabap-deployer": "2.1.0"
33 | },
34 | "ui5": {
35 | "dependencies": [
36 | "ui5-task-nwabap-deployer"
37 | ]
38 | },
39 | "scripts": {
40 | "deploy": "ui5 build --config ui5-webapp.yaml",
41 | "deploy:only": "ui5 build --config ui5-webapp.yaml --exclude-task * --include-task ui5-task-nwabap-deployer",
42 | "deploy:tp": "ui5 build --config ui5-webapp-tp.yaml",
43 | "deploy:create-tp": "ui5 build --config ui5-webapp-create-tp.yaml",
44 | "deploy:cli": "ui5-deployer deploy",
45 | "deploy:cli:conf": "ui5-deployer deploy --config .ui5deployrc-tmp",
46 | "deploy:cli:conf:tp": "ui5-deployer deploy --config .ui5deployrc-tmp-tp",
47 | "deploy:cli:conf:create-tp": "ui5-deployer deploy --config .ui5deployrc-tmp-create-tp",
48 | "undeploy:cli": "ui5-deployer undeploy",
49 | "undeploy:cli:conf": "ui5-deployer undeploy --config .ui5deployrc-tmp",
50 | "undeploy:cli:conf:tp": "ui5-deployer undeploy --config .ui5deployrc-tmp-tp",
51 | "undeploy:cli:conf:create-tp": "ui5-deployer undeploy --config .ui5deployrc-tmp-create-tp",
52 | "deploy:grunt:testmode": "grunt nwabap_ui5uploader:upload_webapp --testMode=true"
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/packages/ui5-app/Gruntfile.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | module.exports = function (grunt) {
4 |
5 | grunt.loadNpmTasks("grunt-nwabap-ui5uploader");
6 |
7 | const sUser = grunt.option("user");
8 | const sPwd = grunt.option("pwd");
9 | const sServer = grunt.option("server");
10 | const bTestMode = !!grunt.option("testMode");
11 |
12 | grunt.initConfig({
13 |
14 | // test configurations
15 | nwabap_ui5uploader: {
16 | options: {
17 | conn: {
18 | server: sServer,
19 | customQueryParams: {
20 | spnego: "disabled/test1/test2",
21 | test2: "test2Value"
22 | },
23 | testMode: bTestMode
24 | },
25 | auth: {
26 | user: sUser,
27 | pwd: sPwd
28 | }
29 | },
30 | upload_webapp: {
31 | options: {
32 | ui5: {
33 | package: "$TMP",
34 | bspcontainer: "ZZ_GUI5UP_TMP01",
35 | bspcontainer_text: "Test Grunt UI5 upload"
36 | },
37 | resources: {
38 | cwd: "webapp",
39 | src: "**/*.*"
40 | }
41 | }
42 | },
43 | upload_webapp_with_transport: {
44 | options: {
45 | ui5: {
46 | package: "ZZ_FP_UI5_REPOSITORY",
47 | bspcontainer: "ZZ_GUI5UP_TMP02",
48 | bspcontainer_text: "Test Grunt UI5 upload",
49 | create_transport: true,
50 | transport_use_locked: true,
51 | transport_text: "Test Transport"
52 | },
53 | resources: {
54 | cwd: "webapp_tp",
55 | src: "**/*.*"
56 | }
57 | }
58 | }
59 | }
60 | });
61 |
62 | grunt.registerTask("test", ["nwabap_ui5uploader:upload_webapp"]);
63 | grunt.registerTask("test_tp", ["nwabap_ui5uploader:upload_webapp_with_transport"]);
64 | };
65 |
--------------------------------------------------------------------------------
/packages/grunt-nwabap-ui5uploader/tasks/grunt-nwabap-ui5uploader.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const Logger = require("./lib/Logger");
4 | const path = require("path");
5 | const ui5Deployercore = require("ui5-nwabap-deployer-core");
6 |
7 | module.exports = function(grunt) {
8 | grunt.registerMultiTask("nwabap_ui5uploader", "UI5 source upload to SAP NetWeaver ABAP", async function() {
9 | const oLogger = new Logger(grunt);
10 | // eslint-disable-next-line no-invalid-this
11 | const done = this.async();
12 |
13 | oLogger.log("Start deploying UI5 sources.");
14 |
15 | // options
16 | // eslint-disable-next-line no-invalid-this
17 | const oOptions = this.options({
18 | resources: {}
19 | });
20 |
21 | // get file names
22 | if (!oOptions.resources || !oOptions.resources.cwd || !oOptions.resources.src) {
23 | grunt.fail.warn("Resources configuration not (fully) specified.");
24 | done();
25 | return;
26 | }
27 |
28 | const aFiles = [];
29 |
30 | grunt.file.expand({
31 | cwd: oOptions.resources.cwd,
32 | filter: "isFile",
33 | dot: true
34 | }, oOptions.resources.src).forEach(function(sFilePath) {
35 | const sCompleteFilePath = path.join(oOptions.resources.cwd, sFilePath);
36 | aFiles.push({
37 | path: sFilePath,
38 | content: grunt.file.read(sCompleteFilePath, { encoding: null})
39 | });
40 | });
41 |
42 | const oDeployOptions = {
43 | conn: {
44 | server: oOptions.conn.server,
45 | client: oOptions.conn.client,
46 | useStrictSSL: oOptions.conn.useStrictSSL,
47 | proxy: oOptions.conn.proxy,
48 | testMode: !!oOptions.conn.testMode,
49 | customQueryParams: oOptions.conn.customQueryParams ? oOptions.conn.customQueryParams : {}
50 | },
51 | auth: {
52 | user: oOptions.auth.user,
53 | pwd: oOptions.auth.pwd
54 | },
55 | ui5: {
56 | language: oOptions.ui5.language,
57 | transportno: oOptions.ui5.transportno,
58 | package: oOptions.ui5.package,
59 | bspcontainer: oOptions.ui5.bspcontainer,
60 | bspcontainer_text: oOptions.ui5.bspcontainer_text,
61 | create_transport: !!oOptions.ui5.create_transport,
62 | transport_text: oOptions.ui5.transport_text,
63 | transport_use_user_match: !!oOptions.ui5.transport_use_user_match,
64 | transport_use_locked: !!oOptions.ui5.transport_use_locked
65 | }
66 | };
67 |
68 | try {
69 | await ui5Deployercore.deployUI5toNWABAP(oDeployOptions, aFiles, oLogger);
70 | oLogger.log("UI5 sources successfully deployed.");
71 | } catch (oError) {
72 | oLogger.error(oError);
73 | grunt.fail.warn("Error occurred while deploying UI5 sources.");
74 | }
75 |
76 | done();
77 | });
78 | };
79 |
--------------------------------------------------------------------------------
/packages/ui5-task-nwabap-deployer/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 2.1.1 (2023-02-15)
2 |
3 | ### Fixes
4 | - Support UI5 Tooling 3.0 in respect to reduce build time by defining that no dependencies are required.
5 |
6 | ## 2.1.0 (2021-07-21)
7 |
8 | ### Features
9 | - New option `testMode` for deployment execution in test mode.
10 |
11 | ## 2.0.0 (2021-06-18)
12 |
13 | ### Features
14 | - Usage of /UI5/ABAP_REPOSITORY_SRV service for deployment instead of Team Provider API.
15 | Team Provider API was set to deprecated. As a consequence starting from version 2.0.0 this deployer supports only systems with at least SAP_UI 753 component installed.
16 | For all previous versions, version 1.x.x of this deployer needs to be used.
17 |
18 | ## 1.0.15 (2020-09-25)
19 |
20 | ### Feature
21 | - Support of `connection.customQueryParams` configuration option to be able to transfer custom parameters to the backend (for instance to bypass SAML2 or SPNEGO authentication).
22 |
23 | ## 1.0.14 (2020-09-04)
24 |
25 | ### Fixes
26 | - Fixed issue of undefined properties in case no complete connection configuration is provided.
27 |
28 | ## 1.0.13 (2020-08-31)
29 |
30 | ### Features
31 | - New environment variable `UI5_TASK_NWABAP_DEPLOYER__CLIENT` to support setting of SAP client via environment.
32 |
33 | ## 1.0.12 (2020-04-29)
34 |
35 | ### Fixes
36 | - Throw error in case connection configuration details are missing (instead of just writing a log entry).
37 |
38 | ## 1.0.11 (2020-04-27)
39 |
40 | ### General
41 | - Update dependency for ui5-nwabap-deployer-core package to v1.0.6 + setting for automatic update of ui5-nwabap-deployer-core package.
42 |
43 | ## 1.0.10 (2020-04-15)
44 |
45 | ### General
46 | - Update dependency for ui5-nwabap-deployer-core package to v1.0.5.
47 | - Update dependency to new UI5 Tooling 2.0 release.
48 |
49 | ## 1.0.9 (2020-03-17)
50 |
51 | ### General
52 | - Update dependency for ui5-nwabap-deployer-core package to v1.0.4.
53 |
54 | ## 1.0.8 (2020-03-11)
55 |
56 | ### General
57 | - Update dependency for ui5-nwabap-deployer-core package to v1.0.3.
58 |
59 | ## 1.0.7 (2020-03-06)
60 |
61 | ### Fixes
62 | - In case of errors, UI5 tooling build infrastructure logic was not correctly informed. Thanks to [@vobu](https://twitter.com/vobu) for the fix.
63 |
64 | ## 1.0.6 (2020-01-24)
65 |
66 | ### General
67 | - Update dependency for ui5-nwabap-deployer-core package to v1.0.2.
68 |
69 | ## 1.0.5 (2019-12-20)
70 |
71 | ### General
72 | - Optimization to use files provided by UI5 Tooling workspace. Before that change, files were read again from file system. Due to that change option `resources.path` is not used anymore.
73 |
74 | ### Features
75 | - Support of `.env` file to define environment variables for local development purposes; applied by the [dotenv](https://www.npmjs.com/package/dotenv) module.
76 |
77 | ## 1.0.4 (2019-12-02)
78 |
79 | ### Fixes
80 | - In case that all UI5 Tooling tasks were excluded (via the --exclude-task option) and just the deployer task was executed, an error occurred, because of the missing resources.
81 |
82 | ## 1.0.3 (2019-11-28)
83 |
84 | ### Features
85 | - `configuration.resources.path` is optional; if not set `dist` is used by default.
86 | - New supported environment variable `UI5_TASK_NWABAP_DEPLOYER__TRANSPORTNO` to be able to set transport number in a dynamic way in the pipeline. Avoids hard coded transport numbers in ui5.yaml configuration files which need to updated again and again.
87 |
88 | ## 1.0.2 (2019-11-28)
89 |
90 | ### Fixes
91 | - Ensure that files are available in resources path when deployment is started.
92 |
93 | ## 1.0.1 (2019-11-26)
94 |
95 | ### Fixes
96 | - Missing ui5.yaml file in published NPM package.
97 |
98 | ## 1.0.0 (2019-11-16)
99 |
100 | ### General
101 | - Initial release.
--------------------------------------------------------------------------------
/packages/ui5-nwabap-deployer-cli/lib/commands/undeploy.js:
--------------------------------------------------------------------------------
1 | const Logger = require("../log/Logger");
2 | const configHandler = require("../config/configHandler");
3 | const ui5DeployerCore = require("ui5-nwabap-deployer-core");
4 |
5 | const builder = (yargs) => {
6 | return yargs
7 | .option("config", { description: "Path to configuration file, default: './ui5deployrc'", string: true })
8 | .option("server", { description: "ABAP Server (form: protocol://host:port)", string: true })
9 | .option("client", { description: "ABAP Client", string: true })
10 | .option("useStrictSSL", { description: "Use Strict SSL, default: true", boolean: true })
11 | .option("proxy", { description: "Proxy (form: protocol://host:port)", string: true })
12 | .option("customQueryParams", { description: "Custom Query Parameters", array: true })
13 | .option("user", { description: "ABAP User", string: true })
14 | .option("pwd", { description: "ABAP User Password", string: true })
15 | .option("bearerToken", { description: "Bearer token for authorization", string: true })
16 | .option("language", { description: "Language for deployment, default: EN", string: true })
17 | .option("package", { description: "ABAP Package", string: true })
18 | .option("bspContainer", { description: "BSP container", string: true })
19 | .option("transportNo", { description: "Transport Number", string: true })
20 | .option("createTransport", { description: "Create a new transport, default: false", boolean: true })
21 | .option("transportText", { description: "Text for new created transport", string: true })
22 | .option("transportUseLocked", { description: "Use an existing transport in which the BSP container is locked, default: false", boolean: true });
23 | };
24 |
25 | const handler = async (argv) => {
26 | const logger = new Logger();
27 |
28 | logger.log("UI5 Deployer: Start undeploying UI5 sources.");
29 |
30 | let configData = undefined;
31 | try {
32 | configData = configHandler.readConfigData(argv.config || "./.ui5deployrc");
33 | } catch (error) {
34 | logger.error(`Error reading configuration file. Error: ${error.message}`);
35 | return;
36 | }
37 |
38 | if (argv.config && !configData) {
39 | logger.error(`No configuration found in config file '${argv.config}'. Please check the file and the content.`);
40 | return;
41 | }
42 |
43 | let undeployOptions = configHandler.mapConfigToOptions(configData, initUndeployOptions());
44 | undeployOptions = configHandler.mapArgumentsToOptions(argv, undeployOptions);
45 |
46 | try {
47 | await ui5DeployerCore.undeployUI5fromNWABAP(undeployOptions, logger);
48 | logger.log("UI5 Deployer: UI5 sources successfully undeployed.");
49 | } catch (error) {
50 | if (error) {
51 | logger.error(error.message);
52 | process.exitCode = 1;
53 | }
54 | }
55 | };
56 |
57 | const initUndeployOptions = () => {
58 | return {
59 | conn: {
60 | server: undefined,
61 | client: undefined,
62 | useStrictSSL: true,
63 | proxy: undefined,
64 | customQueryParams: {}
65 | },
66 | auth: {
67 | user: undefined,
68 | pwd: undefined,
69 | bearerToken: undefined
70 | },
71 | ui5: {
72 | language: "EN",
73 | transportno: undefined,
74 | bspcontainer: undefined,
75 | create_transport: false,
76 | transport_text: undefined,
77 | transport_use_locked: false
78 | }
79 | };
80 | };
81 |
82 | module.exports = {
83 | command: "undeploy",
84 | desc: "Undeploy UI5 sources from a SAP ABAP system.",
85 | builder: builder,
86 | handler: handler
87 | };
88 |
--------------------------------------------------------------------------------
/packages/ui5-nwabap-deployer-core/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 2.2.6 (2025-03-13)
2 |
3 | ## Fixes
4 | - Update axios to fix vulnerabilities.
5 |
6 | ## 2.2.5 (2024-09-26)
7 |
8 | ## Fixes
9 | - Downgrade retry-axios package.
10 |
11 | ## 2.2.4 (2024-09-26)
12 |
13 | ## Fixes
14 | - Update axios to fix vulnerabilities.
15 |
16 | ## 2.2.3 (2021-08-09)
17 |
18 | ## Fixes
19 | - Deployment was not cancelled in case an error appeared which was not returned in the errordetails array response.
20 |
21 | ## 2.2.2 (2021-07-23)
22 |
23 | ### Fixes
24 | - Execute transport related checks for test mode too.
25 |
26 | ## 2.2.1 (2021-07-22)
27 |
28 | ### Fixes
29 | - Enhance backend response message handling for test mode to support different SAP_UI component versions.
30 |
31 | ## 2.2.0 (2021-07-21)
32 |
33 | ### Features
34 | - New option `testMode` for deployment execution in test mode.
35 |
36 | ## 2.1.0 (2021-06-21)
37 |
38 | ### Features
39 | - Support for undeploying a UI5 application.
40 |
41 | ## 2.0.0 (2021-06-18)
42 |
43 | ### Features
44 | - Usage of /UI5/ABAP_REPOSITORY_SRV service for deployment instead of Team Provider API.
45 | Team Provider API was set to deprecated. As a consequence starting from version 2.0.0 this deployer supports only systems with at least SAP_UI 753 component installed.
46 | For all previous versions, version 1.x.x of this deployer needs to be used.
47 |
48 | ## 1.0.23 (2021-06-10)
49 |
50 | ### Fixes
51 | - Fix of issue in response code handling, which avoided proper error handling (thanks to [Fjaoos](https://github.com/Fjaoos) for analyzing and fixing).
52 |
53 | ## 1.0.22 (2021-05-28)
54 |
55 | ### Fixes
56 | - Improve change detection mode for files with carriage return and line feed characters.
57 |
58 | ## 1.0.21 (2021-05-13)
59 |
60 | ### Features
61 | - Deploy a file only if the content is changed.
62 |
63 | ## 1.0.20 (2021-04-30)
64 |
65 | ### Fixes
66 | - Fix bearer token handling.
67 |
68 | ## 1.0.19 (2021-04-30)
69 |
70 | ### Features
71 | - Support for bearer token authorization.
72 |
73 | ## 1.0.18 (2021-04-16)
74 |
75 | ### Features
76 | - Deployment module returns information like used deployment options.
77 |
78 | ## 1.0.17 (2021-04-13)
79 |
80 | ### Fixes
81 | - Removed mandatory check on client, because if no client is provided in configuration the default client will be used.
82 |
83 | ## 1.0.16 (2021-04-10)
84 |
85 | ### Fixes
86 | - Additional check that server and client information is provided.
87 |
88 | ## 1.0.15 (2021-04-07)
89 |
90 | ### Fixes
91 | - `useStrictSSL` option was not considered correctly.
92 |
93 | ## 1.0.14 (2021-03-24)
94 |
95 | ### Fixes
96 | - Do not create an additional unused transport when a transport creation is required, but the usage of an existing transport is required too (and a transport with a lock on the BSP application exists).
97 |
98 | ## 1.0.13 (2021-03-19)
99 |
100 | ### Fixes
101 | - Correct Content-Type header setting for creation of a transport request on ABAP system >= 7.5 (thanks to [ffleige](https://github.com/ffleige)).
102 |
103 | ## 1.0.12 (2021-03-18)
104 |
105 | ### Fixes
106 | - Removed logging of `retry-axios` error object due to possible circular dependencies.
107 |
108 | ## 1.0.11 (2021-01-25)
109 |
110 | ### Fixes
111 | - Option to use a transport in which the object is already locked did not work in case a BSP container was created and then removed, but the transport lock entry still exists.
112 |
113 | ## 1.0.10 (2020-09-25)
114 |
115 | ### Features
116 | - Support of `connection.customQueryParams` configuration option to be able to transfer custom parameters to the backend (for instance to bypass SAML2 or SPNEGO authentication).
117 |
118 | ## 1.0.9 (2020-09-17)
119 |
120 | ### Fixes
121 | - Set ADT Client request body length to maximum; avoids errors that request body is longer than defined max. value.
122 |
123 | ## 1.0.8 (2020-09-04)
124 |
125 | ### Fixes
126 | - Fixed access to undefined response object in case no connection to backend can be established.
127 |
128 | ## 1.0.7 (2020-05-15)
129 |
130 | ### Fixes
131 | - Client option was not considered.
132 |
133 | ## 1.0.6 (2020-04-27)
134 |
135 | ### Fixes
136 | - Proxy option was not considered correctly.
137 |
138 | ## 1.0.5 (2020-04-15)
139 |
140 | ### Fixes
141 | - Local package detection considers all packages starting with a `$` sign, instead of just the `$TMP` package.
142 |
143 | ## 1.0.4 (2020-03-17)
144 |
145 | ### General
146 | - Replaced deprecated `request` module.
147 | - Updated to `async` version 3.
148 |
149 | ## 1.0.3 (2020-03-11)
150 |
151 | ### Fixes
152 | - In case the `ui5.transport_use_user_match` option was used, but no transport exists, the option `ui5.create_transport` was ignored.
153 |
154 | ## 1.0.2 (2020-01-24)
155 |
156 | ### Fixes
157 | - Upload of files with special characters (e.g. ~) in name was confirmed, but the upload failed, because some special characters are not allowed for file names.
158 |
159 | ## 1.0.1 (2019-12-20)
160 |
161 | ### General
162 | - Enhanced interface to accept file contents.
163 |
164 | ## 1.0.0 (2019-11-16)
165 |
166 | ### General
167 | - Initial release.
--------------------------------------------------------------------------------
/packages/ui5-nwabap-deployer-cli/lib/config/configHandler.js:
--------------------------------------------------------------------------------
1 | const fs = require("fs");
2 |
3 | const readConfigData = (configFile) => {
4 | if (!fs.existsSync(configFile)) {
5 | return undefined;
6 | }
7 | return JSON.parse(fs.readFileSync(configFile, { encoding: "utf-8" }));
8 | };
9 |
10 | const mapConfigToOptions = (configData, options) => {
11 | const result = Object.assign(options);
12 |
13 | if (!configData) {
14 | return result;
15 | }
16 |
17 | if (configData.server) {
18 | result.conn.server = configData.server;
19 | }
20 | if (configData.client) {
21 | result.conn.client = configData.client;
22 | }
23 | if (configData.useStrictSSL !== undefined) {
24 | result.conn.useStrictSSL = !!configData.useStrictSSL;
25 | }
26 | if (configData.proxy) {
27 | result.conn.proxy = configData.proxy;
28 | }
29 | if (configData.testMode !== undefined) {
30 | result.conn.testMode = !!configData.testMode;
31 | }
32 | if (configData.customQueryParams) {
33 | Object.keys(configData.customQueryParams).forEach((key) => {
34 | result.conn.customQueryParams[key] = configData.customQueryParams[key];
35 | });
36 | }
37 |
38 | if (configData.user) {
39 | result.auth.user = configData.user;
40 | }
41 | if (configData.pwd) {
42 | result.auth.pwd = configData.pwd;
43 | }
44 | if (configData.bearerToken) {
45 | result.auth.bearer_token = configData.bearerToken;
46 | }
47 |
48 | if (configData.language) {
49 | result.ui5.language = configData.language;
50 | }
51 | if (configData.transportNo) {
52 | result.ui5.transportno = configData.transportNo;
53 | }
54 | if (configData.package) {
55 | result.ui5.package = configData.package;
56 | }
57 | if (configData.bspContainer) {
58 | result.ui5.bspcontainer = configData.bspContainer;
59 | }
60 | if (configData.bspContainerText) {
61 | result.ui5.bspcontainer_text = configData.bspContainerText;
62 | }
63 | if (configData.createTransport !== undefined) {
64 | result.ui5.create_transport = !!configData.createTransport;
65 | }
66 | if (configData.transportText) {
67 | result.ui5.transport_text = configData.transportText;
68 | }
69 | if (configData.transportUseUserMatch !== undefined) {
70 | result.ui5.transport_use_user_match = !!configData.transportUseUserMatch;
71 | }
72 | if (configData.transportUseLocked !== undefined) {
73 | result.ui5.transport_use_locked = !!configData.transportUseLocked;
74 | }
75 |
76 | return result;
77 | };
78 |
79 | const mapArgumentsToOptions = (argv, options) => {
80 | const result = Object.assign(options);
81 |
82 | if (argv.server) {
83 | result.conn.server = argv.server;
84 | }
85 | if (argv.client) {
86 | result.conn.client = argv.client;
87 | }
88 | if (argv.useStrictSSL !== undefined) {
89 | result.conn.useStrictSSL = !!argv.useStrictSSL;
90 | }
91 | if (argv.proxy) {
92 | result.conn.proxy = argv.proxy;
93 | }
94 | if (argv.testMode !== undefined) {
95 | result.conn.testMode = !!argv.testMode;
96 | }
97 | if (argv.customQueryParams) {
98 | argv.customQueryParams.forEach((queryParam) => {
99 | const keyValue = queryParam.split("=");
100 | if (keyValue.length === 2) {
101 | result.conn.customQueryParams[keyValue[0]] = keyValue[1];
102 | }
103 | });
104 | }
105 |
106 | if (argv.user) {
107 | result.auth.user = argv.user;
108 | }
109 | if (argv.pwd) {
110 | result.auth.pwd = argv.pwd;
111 | }
112 | if (argv.bearerToken) {
113 | result.auth.bearer_token = argv.bearerToken;
114 | }
115 |
116 | if (argv.language) {
117 | result.ui5.language = argv.language;
118 | }
119 | if (argv.transportNo) {
120 | result.ui5.transportno = argv.transportNo;
121 | }
122 | if (argv.package) {
123 | result.ui5.package = argv.package;
124 | }
125 | if (argv.bspContainer) {
126 | result.ui5.bspcontainer = argv.bspContainer;
127 | }
128 | if (argv.bspContainerText) {
129 | result.ui5.bspcontainer_text = argv.bspContainerText;
130 | }
131 | if (argv.createTransport !== undefined) {
132 | result.ui5.create_transport = !!argv.createTransport;
133 | }
134 | if (argv.transportText) {
135 | result.ui5.transport_text = argv.transportText;
136 | }
137 | if (argv.transportUseUserMatch !== undefined) {
138 | result.ui5.transport_use_user_match = !!argv.transportUseUserMatch;
139 | }
140 | if (argv.transportUseLocked !== undefined) {
141 | result.ui5.transport_use_locked = !!argv.transportUseLocked;
142 | }
143 |
144 | return result;
145 | };
146 |
147 | module.exports = {
148 | readConfigData: readConfigData,
149 | mapConfigToOptions: mapConfigToOptions,
150 | mapArgumentsToOptions: mapArgumentsToOptions
151 | };
152 |
--------------------------------------------------------------------------------
/packages/ui5-nwabap-deployer-cli/lib/commands/deploy.js:
--------------------------------------------------------------------------------
1 | const Logger = require("../log/Logger");
2 | const glob = require("glob");
3 | const fs = require("fs");
4 | const path = require("path");
5 | const configHandler = require("../config/configHandler");
6 | const ui5DeployerCore = require("ui5-nwabap-deployer-core");
7 |
8 | const builder = (yargs) => {
9 | return yargs
10 | .option("config", { description: "Path to configuration file, default: './ui5deployrc'", string: true })
11 | .option("cwd", { description: "Directory in which files are located, default: './dist'", string: true })
12 | .option("files", { description: "Files (Glob Pattern), default: '**/*.*'", string: true })
13 | .option("server", { description: "ABAP Server (form: protocol://host:port)", string: true })
14 | .option("client", { description: "ABAP Client", string: true })
15 | .option("useStrictSSL", { description: "Use Strict SSL, default: true", boolean: true })
16 | .option("proxy", { description: "Proxy (form: protocol://host:port)", string: true })
17 | .option("testMode", { description: "Test Mode deployment, default: false", boolean: true })
18 | .option("customQueryParams", { description: "Custom Query Parameters", array: true })
19 | .option("user", { description: "ABAP User", string: true })
20 | .option("pwd", { description: "ABAP User Password", string: true })
21 | .option("bearerToken", { description: "Bearer token for authorization", string: true })
22 | .option("language", { description: "Language for deployment, default: EN", string: true })
23 | .option("package", { description: "ABAP Package", string: true })
24 | .option("bspContainer", { description: "BSP container", string: true })
25 | .option("bspContainerText", { description: "BSP container text", string: true })
26 | .option("transportNo", { description: "Transport Number", string: true })
27 | .option("createTransport", { description: "Create a new transport, default: false", boolean: true })
28 | .option("transportText", { description: "Text for new created transport", string: true })
29 | .option("transportUseUserMatch", { description: "Try to find an existing transport for the user, default: false", boolean: true })
30 | .option("transportUseLocked", { description: "Use an existing transport in which the BSP container is locked, default: false", boolean: true });
31 | };
32 |
33 | const handler = async (argv) => {
34 | const logger = new Logger();
35 |
36 | logger.log("UI5 Deployer: Start deploying UI5 sources.");
37 |
38 | let configData = undefined;
39 | try {
40 | configData = configHandler.readConfigData(argv.config || "./.ui5deployrc");
41 | } catch (error) {
42 | logger.error(`Error reading configuration file. Error: ${error.message}`);
43 | return;
44 | }
45 |
46 | if (argv.config && !configData) {
47 | logger.error(`No configuration found in config file '${argv.config}'. Please check the file and the content.`);
48 | return;
49 | }
50 |
51 | let argCwd = "./dist";
52 | if (configData && configData.cwd) {
53 | argCwd = configData.cwd;
54 | }
55 | if (argv.cwd) {
56 | argCwd = argv.cwd;
57 | }
58 |
59 | let argFiles = "**/*.*";
60 | if (configData && configData.files) {
61 | argFiles = configData.files;
62 | }
63 | if (argv.files) {
64 | argFiles = argv.files;
65 | }
66 |
67 | let deployOptions = configHandler.mapConfigToOptions(configData, initDeployOptions());
68 | deployOptions = configHandler.mapArgumentsToOptions(argv, deployOptions);
69 |
70 | const files = glob.sync(argFiles, {
71 | cwd: argCwd,
72 | dot: true,
73 | nodir: true
74 | });
75 |
76 | const fileContents = [];
77 |
78 | files.forEach((file) => {
79 | fileContents.push({
80 | path: file,
81 | content: fs.readFileSync(path.join(argCwd, file))
82 | });
83 | });
84 |
85 | try {
86 | await ui5DeployerCore.deployUI5toNWABAP(deployOptions, fileContents, logger);
87 | logger.log("UI5 Deployer: UI5 sources successfully deployed.");
88 | } catch (error) {
89 | if (error) {
90 | logger.error(error.message);
91 | process.exitCode = 1;
92 | }
93 | }
94 | };
95 |
96 | const initDeployOptions = () => {
97 | return {
98 | conn: {
99 | server: undefined,
100 | client: undefined,
101 | useStrictSSL: true,
102 | proxy: undefined,
103 | testMode: false,
104 | customQueryParams: {}
105 | },
106 | auth: {
107 | user: undefined,
108 | pwd: undefined,
109 | bearerToken: undefined
110 | },
111 | ui5: {
112 | language: "EN",
113 | transportno: undefined,
114 | package: undefined,
115 | bspcontainer: undefined,
116 | bspcontainer_text: undefined,
117 | create_transport: false,
118 | transport_text: undefined,
119 | transport_use_user_match: false,
120 | transport_use_locked: false
121 | }
122 | };
123 | };
124 |
125 | module.exports = {
126 | command: "deploy",
127 | desc: "Deploy UI5 sources to a SAP ABAP system.",
128 | builder: builder,
129 | handler: handler
130 | };
131 |
--------------------------------------------------------------------------------
/packages/ui5-task-nwabap-deployer/README.md:
--------------------------------------------------------------------------------
1 | [](https://badge.fury.io/js/ui5-task-nwabap-deployer)
2 |
3 | # ui5-task-nwabap-deployer
4 |
5 | `ui5-task-nwabap-deployer` is a custom UI5 Tooling task which allows to directly deploy the builded sources to a SAP NetWeaver ABAP application server.
6 |
7 | Starting from version 2.0.0 this deployer uses the OData Service [/UI5/ABAP_RESPOSITORY_SRV](https://ui5.sap.com/#/topic/a883327a82ef4cc792f3c1e7b7a48de8) for deploying UI5 sources. Please make sure that the service is activated on your system (for details you can check SAP note [2999557](https://launchpad.support.sap.com/#/notes/2999557)). The new service does some sanity checks like e.g. virus scans. If you have not configured virus scan profiles or want to disable virus scanning please have a look to SAP note [2437892](https://launchpad.support.sap.com/#/notes/2437892).
8 | Current deployer versions starting from version 2.0.0 can be used with SAP systems on which component SAP_UI 753 is installed. On systems with a lower version of component SAP_UI, you have to use version 1.x.x of this deployer.
9 |
10 | ## Install
11 | ```bash
12 | npm install ui5-task-nwabap-deployer --save-dev
13 | ```
14 |
15 | ## Configuration Options (in `$yourapp/ui5.yaml`)
16 |
17 | - resources
18 | - pattern: optional `string` | `array` glob pattern to match files for deployment (e.g. `**/*.*` to match all files); if not set `**/*.*` is used
19 | - connection
20 | - server: `string` SAP NetWeaver ABAP application server information in form `protocol://host:port` (alternative: set environment variable `UI5_TASK_NWABAP_DEPLOYER__SERVER`)
21 | - client: optional `string` Client of SAP NetWeaver ABAP application server; if not set default client of server is used (alternative: set environment variable `UI5_TASK_NWABAP_DEPLOYER__CLIENT`)
22 | - useStrictSSL: optional `true|false` SSL mode handling. In case of self signed certificates the useStrictSSL mode option can be set to false to allow a deployment of files; default value: `true`
23 | - proxy: optional `string` Proxy to be used for communication to SAP NetWeaver ABAP application server (e.g. `http://myproxyhost:3128`).
24 | - testMode: optional `boolean` Do deployment in test mode (alternative: set environment variable UI5_TASK_NWABAP_DEPLOYER__TESTMODE).
25 | - customQueryParams: option key/value query parameter values added to the call to the SAP NetWeaver ABAP application server
26 | - authentication
27 | - user: `string`User used for logon to SAP NetWeaver ABAP application server (alternative: set environment variable `UI5_TASK_NWABAP_DEPLOYER__USER`)
28 | - password: `string` Password used for logon to SAP NetWeaver ABAP application server (alternative: set environment variable `UI5_TASK_NWABAP_DEPLOYER__PASSWORD`)
29 | - ui5
30 | - language: optional `string` Language for deployment (e.g. EN); default value `EN`
31 | - package: `string` Defines the development package in which the BSP container for the UI5 sources is available or should be created.
32 | - bspContainer: `string` Defines the name of the BSP container used for the storage of the UI5 sources. Length is restricted to 15 characters (exclusive customer specific namespaces, e.g. /YYY/).
33 | - bspContainerText: `string` Defines the description of the BSP container.
34 | - transportNo: optional (in case package is set to `$TMP`) `string` Defines the transport number which logs the changes (alternative: set environment variable `UI5_TASK_NWABAP_DEPLOYER__TRANSPORTNO`).
35 | - createTransport: optional `true|false` Set this option to true in case a new transport should be created each time the application is deployed.
36 | - transportText: optional `string` Text for transport to be created.
37 | - transportUseUserMatch: optional `true|false` It will be tried to find a transport request of the given user. If no transport is found and createTransport is enabled a new one will be created and used for further file deployments.
38 | - transportUseLocked: optional `true|false` If a deployment failed due to the BSP application is locked in another transport, the old (original one) transport will be used to deploy the files.
39 |
40 | ## Usage
41 |
42 | 1. Define the dependency in `$yourapp/package.json`. Since UI5 tooling version 3.0 the `ui5.dependencies` setting is not required anymore.
43 | ```json
44 | ...
45 | "devDependencies": {
46 | // ...
47 | "ui5-task-nwabap-deployer": "*"
48 | // ...
49 | },
50 | "ui5": {
51 | "dependencies": [
52 | // ...
53 | "ui5-task-nwabap-deployer",
54 | // ...
55 | ]
56 | }
57 | ...
58 | ```
59 |
60 | 2. Configure it in `$yourapp/ui5.yaml`
61 | ```yaml
62 | builder:
63 | customTasks:
64 | - name: ui5-task-nwabap-deployer
65 | afterTask: generateVersionInfo
66 | configuration:
67 | resources:
68 | pattern: "**/*.*"
69 | connection:
70 | server: http://myserver:8000
71 | customQueryParams:
72 | myCustomParameter1: myCustomValue1
73 | myCustomParameter2: myCustomValue2
74 | authentication:
75 | user: myUser
76 | password: myPassword
77 | ui5:
78 | language: EN
79 | package: ZZ_UI5_REPO
80 | bspContainer: ZZ_UI5_TRACKED
81 | bspContainerText: UI5 Upload
82 | transportNo: DEVK900000
83 | ```
84 |
85 | ## Further Information
86 |
87 | ### Environment Variables
88 | For development purposes environment variables can be stored in a `.env` file. They are automatically applied by the [dotenv](https://www.npmjs.com/package/dotenv) module.
89 |
90 | ## Release History
91 |
92 | [CHANGELOG.md](https://github.com/pfefferf/ui5-nwabap-deployer/blob/master/packages/ui5-task-nwabap-deployer/CHANGELOG.md)
93 |
94 | ## License
95 |
96 | [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0)
97 |
--------------------------------------------------------------------------------
/packages/ui5-task-nwabap-deployer/lib/ui5-task-nwabap-deployer.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const Logger = require("./Logger");
4 | const ui5DeployerCore = require("ui5-nwabap-deployer-core");
5 | require("dotenv").config();
6 |
7 | /**
8 | * UI5 Tooling Task for deploying UI5 Sources to a SAP NetWeaver ABAP system
9 | *
10 | * @param {Object} parameters Parameters
11 | * @param {module:@ui5/fs.DuplexCollection} parameters.workspace DuplexCollection to read and write files
12 | * @param {module:@ui5/fs.AbstractReader} parameters.dependencies Reader or Collection to read dependency files
13 | * @param {Object} parameters.options Options
14 | * @param {string} parameters.options.projectName Project name
15 | * @param {string} [parameters.options.configuration] Task configuration if given in ui5.yaml
16 | * @returns {Promise} Promise resolving with undefined once data has been written
17 | */
18 | module.exports = async function({ workspace, options }) {
19 | const oLogger = new Logger();
20 |
21 | oLogger.log("Start deploying UI5 sources.");
22 |
23 | if ((options.configuration && !options.configuration.connection) && !process.env.UI5_TASK_NWABAP_DEPLOYER__SERVER) {
24 | return Promise.reject(new Error("Please provide a connection configuration."));
25 | }
26 |
27 | if (options.configuration && !options.configuration.connection) {
28 | options.configuration.connection = {};
29 | }
30 |
31 | let bTestMode = process.env.UI5_TASK_NWABAP_DEPLOYER__TESTMODE === "true";
32 |
33 | if (options.configuration && options.configuration.connection.testMode) {
34 | bTestMode = !!options.configuration.connection.testMode;
35 | }
36 |
37 | let sServer = process.env.UI5_TASK_NWABAP_DEPLOYER__SERVER;
38 |
39 | if (options.configuration && options.configuration.connection && options.configuration.connection.server) {
40 | sServer = options.configuration.connection.server;
41 | }
42 |
43 | let sClient = process.env.UI5_TASK_NWABAP_DEPLOYER__CLIENT;
44 |
45 | if (options.configuration && options.configuration.connection && options.configuration.connection.client) {
46 | sClient = options.configuration.connection.client;
47 | }
48 |
49 | if ((options.configuration && !options.configuration.authentication) &&
50 | (!process.env.UI5_TASK_NWABAP_DEPLOYER__USER || !process.env.UI5_TASK_NWABAP_DEPLOYER__PASSWORD)) {
51 | return Promise.reject(new Error("Please provide an authentication configuration or set authentication environment variables (user name and password)."));
52 | }
53 |
54 | let sUser = process.env.UI5_TASK_NWABAP_DEPLOYER__USER;
55 | let sPassword = process.env.UI5_TASK_NWABAP_DEPLOYER__PASSWORD;
56 |
57 | if (options.configuration && options.configuration.authentication && options.configuration.authentication.user) {
58 | sUser = options.configuration.authentication.user;
59 | }
60 |
61 | if (options.configuration && options.configuration.authentication && options.configuration.authentication.password) {
62 | sPassword = options.configuration.authentication.password;
63 | }
64 |
65 | if (options.configuration && !options.configuration.ui5) {
66 | return Promise.reject(new Error("Please provide a UI5 configuration."));
67 | }
68 |
69 | let sTransportNo = process.env.UI5_TASK_NWABAP_DEPLOYER__TRANSPORTNO;
70 | if (options.configuration && options.configuration.ui5 && options.configuration.ui5.transportNo) {
71 | sTransportNo = options.configuration.ui5.transportNo;
72 | }
73 |
74 | let sResourcePattern = "**/*.*";
75 | if (options.configuration && options.configuration.resources && options.configuration.resources.pattern) {
76 | sResourcePattern = options.configuration.resources.pattern;
77 | }
78 |
79 | return workspace.byGlob(sResourcePattern).then((resources) => {
80 | return Promise.all(resources.map(async (resource) => {
81 | if (options.projectNamespace) {
82 | resource.setPath(resource.getPath().replace(
83 | new RegExp(`^/resources/${options.projectNamespace}`), ""));
84 | }
85 | let sPath = resource.getPath();
86 | if (sPath.startsWith("/")) {
87 | sPath = sPath.substring(1);
88 | }
89 | return {
90 | path: sPath,
91 | content: await resource.getBuffer()
92 | };
93 | }));
94 | }).then(async (aFiles) => {
95 | const oDeployOptions = {
96 | conn: {
97 | server: sServer,
98 | client: sClient,
99 | useStrictSSL: options.configuration.connection.useStrictSSL,
100 | proxy: options.configuration.connection.proxy,
101 | customQueryParams: options.configuration.connection.customQueryParams ? options.configuration.connection.customQueryParams : {},
102 | testMode: bTestMode
103 | },
104 | auth: {
105 | user: sUser,
106 | pwd: sPassword
107 | },
108 | ui5: {
109 | language: options.configuration.ui5.language,
110 | transportno: sTransportNo,
111 | package: options.configuration.ui5.package,
112 | bspcontainer: options.configuration.ui5.bspContainer,
113 | bspcontainer_text: options.configuration.ui5.bspContainerText,
114 | create_transport: !!options.configuration.ui5.createTransport,
115 | transport_text: options.configuration.ui5.transportText,
116 | transport_use_user_match: !!options.configuration.ui5.transportUseUserMatch,
117 | transport_use_locked: !!options.configuration.ui5.transportUseLocked
118 | }
119 | };
120 |
121 | try {
122 | await ui5DeployerCore.deployUI5toNWABAP(oDeployOptions, aFiles, oLogger);
123 | oLogger.log("UI5 sources successfully deployed.");
124 | } catch (oError) {
125 | oLogger.error(oError);
126 | throw new Error(oError);
127 | }
128 | }).then(() => {
129 | return Promise.resolve();
130 | }).catch((oError) => {
131 | return Promise.reject(oError);
132 | });
133 | };
134 |
135 | /**
136 | * Callback function to define the list of required dependencies. No dependencies required for this custom task.
137 | *
138 | */
139 | module.exports.determineRequiredDependencies = async function({availableDependencies, getDependencies, getProject, options}) {
140 | return new Set();
141 | };
142 |
--------------------------------------------------------------------------------
/packages/ui5-nwabap-deployer-core/lib/UI5ABAPRepoClient.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const AdtClient = require("./AdtClient");
4 | const yazl = require("yazl");
5 | const util = require("./Util");
6 |
7 | module.exports = class UI5ABAPRepoClient {
8 | /**
9 | * UI5ABAPRepoClient constructor
10 | * @public
11 | * @param {object} oOptions Options for deployment
12 | * @param {object} oLogger
13 | */
14 | constructor(oOptions, oLogger) {
15 | this.init(oOptions, oLogger);
16 | }
17 |
18 | /**
19 | * Init client
20 | * @param {object} oOptions Options for deployment
21 | * @param {object} oLogger
22 | */
23 | init(oOptions, oLogger) {
24 | this._oOptions = oOptions;
25 | this._oLogger = oLogger;
26 | this._client = new AdtClient(oOptions.conn, oOptions.auth, oOptions.ui5.language, oLogger);
27 | }
28 |
29 | /**
30 | * Construbt UI5 ABAP Repository Service URL
31 | * @returns {string} UI5 ABAP Repository Service URL
32 | */
33 | getServiceUrl() {
34 | return `${this._oOptions.conn.server}/sap/opu/odata/UI5/ABAP_REPOSITORY_SRV/Repositories`;
35 | }
36 |
37 | /**
38 | * Check if Repo is existing
39 | * @returns (boolean) repository existing
40 | */
41 | async isRepoExisting() {
42 | await this._client.determineCSRFTokenPromise();
43 |
44 | const sUrl = `${this.getServiceUrl()}('${encodeURIComponent(this._oOptions.ui5.bspcontainer)}')`;
45 |
46 | const oRequestOptions = {
47 | method: "GET",
48 | url: sUrl,
49 | headers: {
50 | "Content-Type": "application/json"
51 | },
52 | body: {}
53 | };
54 |
55 | const oResponse = await this._client.sendRequestPromise(oRequestOptions);
56 | return oResponse.statusCode === util.HTTPSTAT.ok ? true : false;
57 | }
58 |
59 | /**
60 | * UI5 repo deployment
61 | * @param {Array} aFiles Files to be deployed
62 | */
63 | async deployRepo(aFiles) {
64 | const isRepoExisting = await this.isRepoExisting();
65 | await this._client.determineCSRFTokenPromise();
66 |
67 | function stream2buffer(readableStream) {
68 | return new Promise((resolve, reject) => {
69 | const chunks = [];
70 | readableStream.on("data", (chunk) => {
71 | chunks.push(chunk);
72 | }).on("end", () => {
73 | resolve(Buffer.concat(chunks));
74 | }).on("error", (err) => {
75 | reject(err);
76 | });
77 | });
78 | }
79 |
80 | const zip = new yazl.ZipFile();
81 |
82 | aFiles.forEach((file) => {
83 | zip.addBuffer(file.content, file.path);
84 | });
85 | zip.end({ forceZip64Format: false });
86 |
87 | const zipBuffer = await stream2buffer(zip.outputStream);
88 |
89 | let sUrl = `${this.getServiceUrl()}`;
90 |
91 | if (isRepoExisting) {
92 | sUrl = sUrl + `('${encodeURIComponent(this._oOptions.ui5.bspcontainer)}')`;
93 | }
94 |
95 | sUrl = sUrl + "?CodePage='UTF8'";
96 |
97 | if (this._oOptions.ui5.transportno) {
98 | sUrl = sUrl + "&TransportRequest=" + this._oOptions.ui5.transportno;
99 | }
100 |
101 | if (this._oOptions.conn.testMode) {
102 | sUrl = sUrl + "&TestMode=TRUE";
103 | }
104 |
105 | const oRequestOptions = {
106 | method: isRepoExisting ? "PUT" : "POST",
107 | url: sUrl,
108 | headers: {
109 | "Content-Type": "application/json"
110 | },
111 | body: {
112 | "Name": this._oOptions.ui5.bspcontainer,
113 | "Package": this._oOptions.ui5.package,
114 | "Description": this._oOptions.ui5.bspcontainer_text,
115 | "ZipArchive": zipBuffer.toString("base64"),
116 | "Info": "ui5-nwabap-deployer-core"
117 | }
118 | };
119 |
120 | const oResponse = await this._client.sendRequestPromise(oRequestOptions);
121 |
122 | if (this.doesResponseContainAnError(oResponse)) {
123 | throw new Error(util.createResponseError(typeof oResponse.body === "object" ? JSON.stringify(oResponse.body, null, 4) : oResponse.body));
124 | }
125 | }
126 |
127 | /**
128 | * UI5 repo undeployment
129 | */
130 | async undeployRepo() {
131 | const isRepoExisting = await this.isRepoExisting();
132 | await this._client.determineCSRFTokenPromise();
133 |
134 | if (!isRepoExisting) {
135 | throw new Error(util.createResponseError(`BSP Container ${this._oOptions.ui5.bspcontainer} does not exist. Undeploy cancelled.`));
136 | }
137 |
138 | let sUrl = `${this.getServiceUrl()}`;
139 | sUrl = sUrl + `('${encodeURIComponent(this._oOptions.ui5.bspcontainer)}')`;
140 |
141 | sUrl = sUrl + "?CodePage='UTF8'";
142 |
143 | if (this._oOptions.ui5.transportno) {
144 | sUrl = sUrl + "&TransportRequest=" + this._oOptions.ui5.transportno;
145 | }
146 |
147 | if (this._oOptions.conn.testMode) {
148 | sUrl = sUrl + "&TestMode=TRUE";
149 | }
150 |
151 | const oRequestOptions = {
152 | method: "DELETE",
153 | url: sUrl
154 | };
155 |
156 | const oResponse = await this._client.sendRequestPromise(oRequestOptions);
157 |
158 | if (this.doesResponseContainAnError(oResponse)) {
159 | throw new Error(util.createResponseError(typeof oResponse.body === "object" ? JSON.stringify(oResponse.body, null, 4) : oResponse.body));
160 | }
161 | }
162 |
163 | /**
164 | * Check if response contains an error.
165 | * @param {Object} oResponse Request response
166 | * @returns {boolean} Info if response contains an error
167 | */
168 | doesResponseContainAnError(oResponse) {
169 | let bErrorOccurred = false;
170 |
171 | let errorDetails = null;
172 |
173 | if (oResponse.body && oResponse.body.errordetails) {
174 | errorDetails = oResponse.body.errordetails;
175 | }
176 |
177 | if (oResponse.body && oResponse.body.error && oResponse.body.error.innererror && oResponse.body.error.innererror.errordetails && oResponse.body.error.innererror.errordetails.length > 0) {
178 | errorDetails = oResponse.body.error.innererror.errordetails;
179 | }
180 |
181 | if (errorDetails) {
182 | const idx = errorDetails.findIndex((errordetail) => {
183 | return errordetail.severity === "error";
184 | });
185 |
186 | bErrorOccurred = idx !== -1;
187 | } else if (oResponse.statusCode !== util.HTTPSTAT.ok && oResponse.statusCode !== util.HTTPSTAT.created && oResponse.statusCode !== util.HTTPSTAT.no_content) {
188 | bErrorOccurred = true;
189 | }
190 |
191 | return bErrorOccurred;
192 | }
193 | };
194 |
--------------------------------------------------------------------------------
/packages/ui5-nwabap-deployer-core/lib/TransportManager.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const util = require("util");
4 | const fsutil = require("./Util");
5 | const CTS_BASE_URL_TRANSPORTS = "/sap/bc/adt/cts/transports";
6 | const CTS_BASE_URL_TRANSPORTCHECKS = "/sap/bc/adt/cts/transportchecks";
7 | const AdtClient = require("./AdtClient");
8 | const XMLDocument = require("xmldoc").XmlDocument;
9 |
10 | /**
11 | * creates and releases transport requests
12 | * @param {object} oOptions
13 | * @param {object} oOptions.conn connection info
14 | * @param {string} oOptions.conn.server server url
15 | * @param {string} oOptions.conn.client sap client id
16 | * @param {boolean} oOptions.conn.useStrictSSL force encrypted connection
17 | * @param {string} oOptions.conn.proxy set connection proxy
18 | * @param {string} oOptions.auth.user username
19 | * @param {string} oOptions.auth.pwd password
20 | * @param {Logger} oLogger
21 | * @constructor
22 | */
23 | function TransportManager(oOptions, oLogger) {
24 | this._client = new AdtClient(oOptions.conn, oOptions.auth, undefined, oLogger);
25 | this._oLogger = oLogger;
26 | }
27 |
28 | TransportManager.prototype.createTransport = function(sPackageName, sRequestText, fnCallback) {
29 | const sPayload = this.getCreateTransportPayload(sPackageName, sRequestText);
30 |
31 | const sUrl = this._client.buildUrl(CTS_BASE_URL_TRANSPORTS);
32 | this._client.determineCSRFToken(function() {
33 | const oRequestOptions = {
34 | method: "POST",
35 | url: sUrl,
36 | headers: {
37 | "accept": "*/*",
38 | "content-type": "application/vnd.sap.as+xml; charset=UTF-8; dataname=com.sap.adt.CreateCorrectionRequest"
39 | },
40 | body: sPayload
41 | };
42 |
43 | this._client.sendRequest(oRequestOptions, function(oError, oResponse) {
44 | if (oError) {
45 | fnCallback(new Error(fsutil.createResponseError(oError)));
46 | return;
47 | } else if (oResponse.statusCode !== fsutil.HTTPSTAT.ok) {
48 | fnCallback(new Error(`Operation Create Transport: Expected status code ${fsutil.HTTPSTAT.ok}, actual status code ${oResponse.statusCode}`));
49 | return;
50 | } else {
51 | const sTransportNo = oResponse.body.split("/").pop();
52 | this._oLogger.log("Creation of transport request required. Number of created transport request: " + sTransportNo);
53 | fnCallback(null, sTransportNo);
54 | return;
55 | }
56 | }.bind(this));
57 | }.bind(this));
58 | };
59 |
60 | TransportManager.prototype.createTransportPromise = function(sPackageName, sRequestText) {
61 | const that = this;
62 | return new Promise((resolve, reject) => {
63 | that.createTransport(sPackageName, sRequestText, (error, result) => {
64 | if (error) {
65 | reject(error);
66 | } else {
67 | resolve(result);
68 | }
69 | });
70 | });
71 | };
72 |
73 | /**
74 | * Determines if a transport with the given text already exists. If true the callback returns the transport no
75 | * otherwise the cb returns null.
76 | * @param {Function} fnCallback
77 | */
78 | TransportManager.prototype.determineExistingTransport = function(fnCallback) {
79 | const sUrl = this._client.buildUrl(CTS_BASE_URL_TRANSPORTS + "?_action=FIND&trfunction=K");
80 |
81 | const oRequestOptions = {
82 | url: sUrl,
83 | headers: {
84 | "accept": "*/*"
85 | }
86 | };
87 |
88 | this._client.sendRequest(oRequestOptions, function(oError, oResponse) {
89 | if (oError) {
90 | fnCallback(new Error(fsutil.createResponseError(oError)));
91 | return;
92 | } else if (oResponse.statusCode !== fsutil.HTTPSTAT.ok) {
93 | fnCallback(new Error(`Operation Existing Transport Determination: Expected status code ${fsutil.HTTPSTAT.ok}, actual status code ${oResponse.statusCode}`));
94 | return;
95 | } else {
96 | if (!oResponse.body) {
97 | return fnCallback(null, null);
98 | }
99 | const oParsed = new XMLDocument(oResponse.body);
100 | const transportNo = oParsed.valueWithPath("asx:values.DATA.CTS_REQ_HEADER.TRKORR");
101 | fnCallback(null, transportNo);
102 | return;
103 | }
104 | });
105 | };
106 |
107 | TransportManager.prototype.getCreateTransportPayload = function(sPackageName, sRequestText) {
108 | const sTemplate = "" +
109 | "" +
110 | "" +
111 | "" +
112 | "I" +
113 | "%s" +
114 | "%s" +
115 | "" +
116 | "" +
117 | "";
118 |
119 | return util.format(sTemplate, sPackageName, sRequestText);
120 | };
121 |
122 | /**
123 | * Determine transport number for BSP Container; available in case BSP Container is already locked.
124 | * @param {string} sPackageName package name
125 | * @param {string} sBspContainer BSP Container
126 | * @returns {Promise} Promise resolving to null or found transport number
127 | */
128 | TransportManager.prototype.determineExistingTransportForBspContainer = function(sPackageName, sBspContainer) {
129 | return new Promise(function(resolve, reject) {
130 | const oRequestOptions = {
131 | method: "POST",
132 | url: this._client.buildUrl(CTS_BASE_URL_TRANSPORTCHECKS),
133 | headers: {
134 | "accept": "*/*",
135 | "content-type": "application/vnd.sap.as+xml; charset=UTF-8; dataname=com.sap.adt.transport.service.checkData"
136 | },
137 | body: "" +
138 | "" +
139 | "" +
140 | "" +
141 | "R3TR" +
142 | "" +
143 | "" + sBspContainer + "" +
144 | "" + sPackageName + "" +
145 | "" +
146 | "I" +
147 | "" +
148 | "" +
149 | "" +
150 | ""
151 | };
152 |
153 | this._client.determineCSRFToken(function() {
154 | this._client.sendRequest(oRequestOptions, function(oError, oResponse) {
155 | if (oError) {
156 | reject(new Error(fsutil.createResponseError(oError)));
157 | return;
158 | } else if (oResponse.statusCode !== fsutil.HTTPSTAT.ok) {
159 | reject(new Error(`Operation Existing Transport Determination for BSP Container: Expected status code ${fsutil.HTTPSTAT.ok}, actual status code ${oResponse.statusCode}`));
160 | return;
161 | } else {
162 | if (!oResponse.body) {
163 | return resolve(null);
164 | }
165 | const oParsed = new XMLDocument(oResponse.body);
166 | const transportNo = oParsed.valueWithPath("asx:values.DATA.LOCKS.CTS_OBJECT_LOCK.LOCK_HOLDER.REQ_HEADER.TRKORR");
167 | return resolve(transportNo);
168 | }
169 | });
170 | }.bind(this));
171 | }.bind(this));
172 | };
173 |
174 | module.exports = TransportManager;
175 |
--------------------------------------------------------------------------------
/packages/grunt-nwabap-ui5uploader/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 2.2.0 (2023-11-16)
2 |
3 | ### Fixes
4 | - Do grunt.fail.warn to raise exit code.
5 |
6 | ## 2.1.0 (2021-07-21)
7 |
8 | ### Features
9 | - New option `testMode` for deployment execution in test mode.
10 |
11 | ## 2.0.0 (2021-06-18)
12 |
13 | ### Features
14 | - Usage of /UI5/ABAP_REPOSITORY_SRV service for deployment instead of Team Provider API.
15 | Team Provider API was set to deprecated. As a consequence starting from version 2.0.0 this deployer supports only systems with at least SAP_UI 753 component installed.
16 | For all previous versions, version 1.x.x of this deployer needs to be used.
17 |
18 | ## 1.0.7 (2020-09-25)
19 |
20 | ### Feature
21 | - Support of `options.conn.customQueryParams` configuration option to be able to transfer custom parameters to the backend (for instance to bypass SAML2 or SPNEGO authentication).
22 |
23 | ## 1.0.6 (2020-04-27)
24 |
25 | ### General
26 | - Update dependency for ui5-nwabap-deployer-core package to v1.0.6 + setting for automatic update of ui5-nwabap-deployer-core package.
27 |
28 | ## 1.0.5 (2020-04-15)
29 |
30 | ### General
31 | - Update dependency for ui5-nwabap-deployer-core package to v1.0.5.
32 |
33 | ## 1.0.4 (2020-03-17)
34 |
35 | ### General
36 | - Update dependency for ui5-nwabap-deployer-core package to v1.0.4.
37 |
38 | ## 1.0.3 (2020-03-11)
39 |
40 | ### General
41 | - Update dependency for ui5-nwabap-deployer-core package to v1.0.3.
42 |
43 | ## 1.0.2 (2020-01-24)
44 |
45 | ### Fixes
46 | - Update depedency to ui5-nwabap-deployer-core to fix an issue regarding upload of files with special characters in their name.
47 |
48 | ## 1.0.1 (2019-12-20)
49 |
50 | ### General
51 | - Update dependency for ui5-nwabap-deployer-core package to v1.0.2.
52 |
53 | ## 1.0.0 (2019-11-24)
54 |
55 | ### General
56 | - Usage of ui5-nwabap-deployer-core package.
57 |
58 | ## 0.3.4 (2019-05-16)
59 |
60 | ### Features
61 | - In case the creation of a transport request is required via option `options.ui5.create_transport`, the number of the created transport request is logged in form "Creation of transport request required. Number of created transport request: \".
62 |
63 | ## 0.3.3 (2019-01-14)
64 |
65 | ### Fixes
66 | - Fixed issue regarding response status code check (thanks to [BurnerPat](https://github.com/BurnerPat)).
67 |
68 | ## 0.3.2 (2019-01-03)
69 |
70 | ### General
71 | - More detailed information in case an ADT API call fails (expected HTTP Status Code, actual HTTP Status Code, response body).
72 |
73 | ## 0.3.1 (2018-11-26)
74 |
75 | ### Fixes
76 | - Fixed issue in check if a transport for the user exists.
77 |
78 | ## 0.3.0 (2018-11-19)
79 |
80 | ### General
81 | - Replaced `unirest` library by `request` library, because of a better maintenance support.
82 | - Removal of duplicated code.
83 | - Support for Node versions < 5.0.0 skipped.
84 |
85 | ## 0.2.10 (2018-09-07)
86 |
87 | ### Features
88 | - Option `options.conn.proxy` added to specify a proxy for SAP NetWeaver ABAP server communcation (thanks to [anomistu](https://github.com/anomistu)).
89 |
90 | ## 0.2.9 (2018-06-01)
91 |
92 | ### Fixes
93 | - Removal of ISO-8859-1 to avoid side issues when project is edited in different editors.
94 |
95 | ## 0.2.8 (2018-05-02)
96 |
97 | ### Fixes
98 | - Fixed issue that "properties" files were uploaded with UTF-8 charset instead of ISO-8859-1 charset (thanks to [stockbal](https://github.com/stockbal)).
99 |
100 | ## 0.2.7 (2018-04-06)
101 |
102 | ### Fixes
103 | - Fixed issues for `transport_use_user_match' option (thanks to [stockbal](https://github.com/stockbal)).
104 |
105 | ## 0.2.6 (2018-04-05)
106 |
107 | ### Fixes
108 | - Fixed issues for `create_transport` option (thanks to [stockbal](https://github.com/stockbal)).
109 |
110 | ## 0.2.5 (2018-03-22)
111 |
112 | ### Fixes
113 | - Increased the backoff reconnect time interval.
114 |
115 | ## 0.2.4 (2018-03-22)
116 |
117 | ### Features
118 | - Reconnect if request was aborted due to a syscall error.
119 |
120 | ## 0.2.3 (2018-03-13)
121 |
122 | ### Fixes
123 | - In case of using the parameter to use a locked transport, an error occurred if no response body was available when the check was done for a locked transport.
124 |
125 | ## 0.2.2 (2018-02-27)
126 |
127 | ### General
128 | - NPM package dependencies updated.
129 |
130 | ### Features
131 | - Options `options.ui5.transport_use_user_match` and `options.ui5.transport_use_locked` added for specific cases. These options allow to reuse an existing not released transport for a user or the usage of a not released transport by which the UI5 application BSP container is locked. Thanks to [@mxschmitt](https://github.com/mxschmitt) for adding these options.
132 |
133 | ## 0.2.1 (2018-01-23)
134 |
135 | ### Features
136 | - Option `options.ui5.create_transport` and `options.ui5.transport_text` added to be able to create a new transport for each upload. Thanks to [@themasch](https://github.com/themasch) for adding that feature.
137 |
138 | ## 0.2.0 (2017-05-29)
139 |
140 | ### General
141 | - Grunt dependency updated to 1.0.1, to avoid security vulnerabilities of 0.4.5.
142 |
143 | ## 0.1.19 (2017-02-10)
144 |
145 | ### General
146 | - Adjustment of copyright information (year).
147 | - Now also tested with NW ABAP 7.51.
148 |
149 | ## 0.1.18 (2016-12-14)
150 |
151 | ### Fixes
152 | - Application index was recalculated independent of option setting.
153 |
154 | ## 0.1.17 (2016-12-12)
155 |
156 | ### Fixes
157 | - Error forwarding in case CSRF Token determination fails.
158 |
159 | ## 0.1.16 (2016-11-18)
160 |
161 | ### General
162 | - Switched from JSHint to ESLint linting.
163 | - Support for Node versions < 4.0.0 skipped.
164 | - Logging changed to an "immediate" logging. Folder/File actions are displayed immediately instead of collecting them.
165 | - Slashes at the end of a defined server URL are ignored.
166 |
167 | ## 0.1.15 (2016-10-25)
168 |
169 | ### General
170 | - Code simplification regarding sap-language parameter.
171 |
172 | ## 0.1.14 (2016-10-21)
173 |
174 | ### Fixes
175 | - BSP container length check excludes customer specific namespaces.
176 | - Deletion requests are fired with sap-language parameter.
177 |
178 | ## 0.1.13 (2016-09-30)
179 |
180 | ### General
181 | - Readme update.
182 |
183 | ## 0.1.12 (2016-09-28)
184 |
185 | ### General
186 | - Update dependency to Unirest 0.5.1
187 |
188 | ### Fixes
189 | - Client parameter handling
190 |
191 | ## 0.1.11 (2016-09-27)
192 |
193 | ### General
194 | - Added Travis CI support.
195 |
196 | ## 0.1.10 (2016-08-04)
197 |
198 | ### Fixes
199 | - Crash caused by empty files fixed.
200 |
201 | ## 0.1.9 (2016-08-01)
202 |
203 | ### Features
204 | - Option `options.conn.client` added to be able to specify a SAP client (in case no default client is maintained in system).
205 |
206 | ## 0.1.8 (2016-07-25)
207 |
208 | ### Features
209 | - Option `options.ui5.calc_appindex` steers if the SAPUI5 application index is recalculated (program /UI5/APP_INDEX_CALCULATE). Thanks to [@olirogers](https://github.com/olirogers) for adding this feature.
210 |
211 | ## 0.1.7 (2016-06-17)
212 |
213 | ### Fixes
214 | - Ensure ES 5.1 compatibility.
215 |
216 | ## 0.1.6 (2016-06-13)
217 |
218 | ### Fixes
219 | - Namespace handling for file comparison.
220 |
221 | ## 0.1.5 (2016-06-13)
222 |
223 | ### Features
224 | - Option `options.conn.useStrictSSL` steers if a strict SSL mode check has to be executed. In case of self signed certificates it can be set to `false` to allow an upload of files.
225 |
226 | ### Fixes
227 | - Correct encoding of namespaces for file upload.
228 |
229 | ## 0.1.4 (2016-06-08)
230 |
231 | ### Features
232 | - Option `options.ui5.language` introduced to be able to specify objects original language (e.g. for BSP Container).
233 |
234 | ## 0.1.3 (2016-04-01)
235 |
236 | ### General
237 | - Readme update.
238 |
239 | ## 0.1.2 (2016-03-30)
240 |
241 | ### General
242 | - Minor issues.
243 |
244 | ## 0.1.1 (2016-03-25)
245 |
246 | ### General
247 | - Readme update.
248 |
249 | ## 0.1.0 (2016-03-25)
250 |
251 | ### General
252 | - Initial release.
--------------------------------------------------------------------------------
/packages/ui5-nwabap-deployer-core/lib/AdtClient.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const axios = require("axios");
4 | const rax = require("retry-axios");
5 | const https = require("https");
6 | const util = require("./Util");
7 | const ADT_BASE_URL = "/sap/bc/adt/";
8 |
9 | /**
10 | *
11 | * @param {object} oConnection
12 | * @param {string} oConnection.server NW server
13 | * @param {string} oConnection.client NW Client
14 | * @param {boolean} oConnection.useStrictSSL use strict SSL connection
15 | * @param {string} oConnection.proxy proxy
16 | * @param {object} oAuth
17 | * @param {string} oAuth.user user
18 | * @param {string} oAuth.pwd password
19 | * @param {string} sLanguage language
20 | * @param {Logger} oLogger logger
21 | * @constructor
22 | */
23 | function AdtClient(oConnection, oAuth, sLanguage, oLogger) {
24 | this._oOptions = {
25 | auth: oAuth,
26 | conn: oConnection,
27 | lang: sLanguage
28 | };
29 |
30 | // remove suffix slashes from server URL
31 | if (this._oOptions.conn && this._oOptions.conn.server) {
32 | this._oOptions.conn.server = this._oOptions.conn.server.replace(/\/*$/, "");
33 | }
34 |
35 | this._oLogger = oLogger;
36 | }
37 |
38 | /**
39 | * Construct the base Url for server access
40 | * @private
41 | * @return {string} base URL
42 | */
43 | AdtClient.prototype._constructBaseUrl = function() {
44 | return this._oOptions.conn.server + ADT_BASE_URL;
45 | };
46 |
47 | /**
48 | * Determine a CSRF Token which is necessary for POST/PUT/DELETE operations; also the sapCookie is determined
49 | * @private
50 | * @param {function} fnCallback callback function
51 | * @return {void}
52 | */
53 | AdtClient.prototype.determineCSRFToken = function(fnCallback) {
54 | if (this._sCSRFToken !== undefined) {
55 | fnCallback();
56 | return;
57 | }
58 |
59 | const sUrl = this.buildUrl(ADT_BASE_URL + "discovery");
60 |
61 | const oRequestOptions = {
62 | url: sUrl,
63 | headers: {
64 | "X-CSRF-Token": "Fetch",
65 | "accept": "*/*"
66 | }
67 | };
68 |
69 | this.sendRequest(oRequestOptions, function(oError, oResponse) {
70 | if (oError) {
71 | fnCallback(oError);
72 | return;
73 | } else if (oResponse.statusCode !== util.HTTPSTAT.ok) {
74 | fnCallback(new Error(`Operation CSRF Token Determination: Expected status code ${util.HTTPSTAT.ok}, actual status code ${oResponse.statusCode}, response body '${oResponse.body}'`));
75 | return;
76 | } else {
77 | this._sCSRFToken = oResponse.headers["x-csrf-token"];
78 | this._sSAPCookie = "";
79 | for (let i = 0; i < oResponse.headers["set-cookie"].length; i++) {
80 | this._sSAPCookie += oResponse.headers["set-cookie"][i] + ";";
81 | }
82 |
83 | fnCallback(null);
84 | return;
85 | }
86 | }.bind(this));
87 | };
88 |
89 | /**
90 | * Determine a CSRF Token which is necessary for POST/PUT/DELETE operations; also the sapCookie is determined; promisified version
91 | * @private
92 | * @returns {Promise}
93 | */
94 | AdtClient.prototype.determineCSRFTokenPromise = function() {
95 | const that = this;
96 | return new Promise((resolve, reject) => {
97 | that.determineCSRFToken((error, result) => {
98 | if (error) {
99 | reject(error);
100 | } else {
101 | resolve(result);
102 | }
103 | });
104 | });
105 | };
106 |
107 | AdtClient.prototype.buildUrl = function(sUrl) {
108 | return this._oOptions.conn.server + sUrl;
109 | };
110 |
111 | /**
112 | * Send a request to the server (adds additional information before sending, e.g. authentication information)
113 | * @param {object} oRequestOptions request options object
114 | * @param {function} fnRequestCallback Callback for request
115 | */
116 | AdtClient.prototype.sendRequest = async function(oRequestOptions, fnRequestCallback) {
117 | const that = this;
118 |
119 | const fnAddQueryParam = (oOptions, sParamName, sParamValue) => {
120 | if (!sParamValue) {
121 | return;
122 | }
123 |
124 | if (!oOptions.hasOwnProperty("params")) {
125 | oOptions.params = {};
126 | }
127 | oOptions.params[sParamName] = sParamValue;
128 | };
129 |
130 | const fnAddHeader = (oOptions, sHeaderKey, sHeaderValue) => {
131 | if (!sHeaderValue) {
132 | return;
133 | }
134 |
135 | if (!oOptions.hasOwnProperty("headers")) {
136 | oOptions.headers = {};
137 | }
138 | oOptions.headers[sHeaderKey] = sHeaderValue;
139 | };
140 |
141 | const oAxiosReqOptions = {};
142 | oAxiosReqOptions.url = oRequestOptions.url || "";
143 | oAxiosReqOptions.method = oRequestOptions.method || "GET";
144 | oAxiosReqOptions.headers = oRequestOptions.headers || {};
145 | oAxiosReqOptions.data = oRequestOptions.body;
146 |
147 | oAxiosReqOptions.httpsAgent = new https.Agent({
148 | rejectUnauthorized: that._oOptions.conn.useStrictSSL
149 | });
150 |
151 | if (that._oOptions.auth) {
152 | if (that._oOptions.auth.bearer_token) {
153 | fnAddHeader(oAxiosReqOptions, "authorization", "Bearer " + that._oOptions.auth.bearer_token);
154 | } else {
155 | oAxiosReqOptions.auth = {
156 | username: that._oOptions.auth.user,
157 | password: that._oOptions.auth.pwd
158 | };
159 | }
160 | }
161 |
162 | if (that._oOptions.conn.proxy) {
163 | try {
164 | const oProxyUrl = new URL(that._oOptions.conn.proxy);
165 |
166 | oAxiosReqOptions.proxy = {
167 | host: oProxyUrl.hostname,
168 | port: oProxyUrl.port
169 | };
170 |
171 | if (oProxyUrl.username && oProxyUrl.password) {
172 | oAxiosReqOptions.proxy.auth = {
173 | username: oProxyUrl.username,
174 | password: oProxyUrl.password
175 | };
176 | }
177 | } catch (oError) {
178 | fnRequestCallback(oError, null);
179 | }
180 | }
181 |
182 | fnAddQueryParam(oAxiosReqOptions, "sap-language", that._oOptions.lang);
183 | fnAddQueryParam(oAxiosReqOptions, "sap-client", that._oOptions.conn.client);
184 |
185 | if (that._oOptions.conn.customQueryParams) {
186 | Object.keys(that._oOptions.conn.customQueryParams).forEach((sKey) => {
187 | fnAddQueryParam(oAxiosReqOptions, sKey, encodeURIComponent(that._oOptions.conn.customQueryParams[sKey]));
188 | });
189 | }
190 |
191 | fnAddHeader(oAxiosReqOptions, "x-csrf-token", this._sCSRFToken);
192 | fnAddHeader(oAxiosReqOptions, "cookie", this._sSAPCookie);
193 |
194 | rax.attach();
195 | oAxiosReqOptions.raxConfig = {
196 | retry: 5,
197 | retryDelay: 500,
198 | onRetryAttempt: (oRaxError) => {
199 | const oCfg = rax.getConfig(oRaxError);
200 | that._oLogger.log("Connection error has occurred; retry attempt " + oCfg.currentRetryAttempt);
201 | }
202 | };
203 |
204 | oAxiosReqOptions.validateStatus = (status) => {
205 | return status < 999; // request must always return a response
206 | };
207 |
208 | oAxiosReqOptions.maxBodyLength = Infinity;
209 | oAxiosReqOptions.maxContentLength = Infinity;
210 |
211 | try {
212 | const oResponse = await axios(oAxiosReqOptions);
213 | oResponse.statusCode = oResponse.status;
214 | oResponse.body = oResponse.data;
215 | fnRequestCallback(null, oResponse);
216 | } catch (oRequestError) {
217 | if (oRequestError.response) {
218 | fnRequestCallback(oRequestError.message + "\n\rError message body: " + oRequestError.response.data, null);
219 | } else {
220 | fnRequestCallback(oRequestError.message, null);
221 | }
222 | }
223 | };
224 |
225 | /**
226 | * Send a request to the server - promisified
227 | * @param {object} oRequestOptions request options object
228 | */
229 | AdtClient.prototype.sendRequestPromise = function(oRequestOptions) {
230 | const that = this;
231 | return new Promise((resolve, reject) => {
232 | that.sendRequest(oRequestOptions, (error, result) => {
233 | if (error) {
234 | reject(error);
235 | } else {
236 | resolve(result);
237 | }
238 | });
239 | });
240 | };
241 |
242 | module.exports = AdtClient;
243 |
--------------------------------------------------------------------------------
/packages/ui5-nwabap-deployer-cli/README.md:
--------------------------------------------------------------------------------
1 | [](https://badge.fury.io/js/ui5-nwabap-deployer-cli)
2 |
3 | # ui5-nwabap-deployer-cli
4 |
5 | `ui5-nwabap-deployer-cli` is a CLI tooling which allows to deploy UI5 sources to a SAP NetWeaver ABAP application server.
6 |
7 | Starting from version 2.0.0 this deployer uses the OData Service [/UI5/ABAP_RESPOSITORY_SRV](https://ui5.sap.com/#/topic/a883327a82ef4cc792f3c1e7b7a48de8) for deploying UI5 sources. Please make sure that the service is activated on your system (for details you can check SAP note [2999557](https://launchpad.support.sap.com/#/notes/2999557)). The new service does some sanity checks like e.g. virus scans. If you have not configured virus scan profiles or want to disable virus scanning please have a look to SAP note [2437892](https://launchpad.support.sap.com/#/notes/2437892).
8 | Current deployer versions starting from version 2.0.0 can be used with SAP systems on which component SAP_UI 753 is installed. On systems with a lower version of component SAP_UI, you have to use version 1.x.x of this deployer.
9 |
10 | ## Install
11 |
12 | ### Global Installation
13 | ```bash
14 | npm install -g ui5-nwabap-deployer-cli
15 | ```
16 |
17 | Global installation makes the command `ui5-deployer` globally available.
18 |
19 | ### Local Installation
20 | ```bash
21 | npm install ui5-nwabap-deployer-cli --save-dev
22 | ```
23 | Local installation requires the execution of the tool like `./node_modules/.bin/ui5-deployer`.
24 |
25 | ## CLI Options for `ui5-deployer`
26 |
27 | Following base CLI options are available:
28 | - `help`: shows the CLI help, execute `ui5-deployer --help`
29 | - `version`: shows the CLI version, execute `ui5-deployer --version`
30 |
31 | ## CLI Commands for `ui5-deployer`
32 |
33 | ### deploy
34 |
35 | The `deploy` command deploys UI5 sources to an ABAP system. It provides following arguments.
36 |
37 | |Option|Description|Mandatory|Default Value|
38 | |:-|:-|:-|:-|
39 | |config |Configuration file containing options for. By default for a file './.ui5deployrc' is searched. If no file is found, it is ignored. Options defined in the configuration file are always overwritten in case they are applied on the command line. Consider to never store the user and password in the config file if the file is shared, provide them as command line arguments.|-|-|
40 | |cwd |Directory in which files for deployment are available.|X|./dist|
41 | |files |Glob pattern to match files for deployment.|X|**/\*.\*|
42 | |server |SAP NetWeaver ABAP application server information in form protocol://host:port|X|-|
43 | |client |Client of SAP NetWeaver ABAP application server; if not set default client of server is used.|-|-|
44 | |testMode |Deployment to be done in test mode.|-|false|
45 | |user |User used for logon to SAP NetWeaver ABAP application server.|X (in case no bearer token is used)|-|
46 | |pwd |Password used for logon to SAP NetWeaver ABAP application server.|X (in case no bearer token is used)|-|
47 | |bearerToken |Bearer token used for authorization.|X (in user/pwd is not used)|-|
48 | |useStrictSSL |SSL mode handling. In case of self signed certificates the useStrictSSL mode option can be set to false to allow a deployment of files.|-|true|
49 | |proxy |Proxy to be used for communication to SAP NetWeaver ABAP application server, form protocol://host:port|-|-|
50 | |customQueryParams |Additional query parameters to be appended to the server calls. To be provided in form `parameterName=parameterValue`|-|-|
51 | |language |Language for deployment.|-|EN|
52 | |package |Defines the development package in which the BSP container for the UI5 sources is available or should be created.|X|-|
53 | |bspContainer |Defines the name of the BSP container used for the storage of the UI5 sources. Length is restricted to 15 characters (exclusive customer specific namespaces, e.g. /YYY/).|X|-|
54 | |bspContainerText |Defines the description of the BSP container.|X|-|
55 | |transportNo |Defines the transport number which logs the changes|X (in case sources are not deployed as local objects)|-|
56 | |createTransport |Set this option to true in case a new transport should be created each time the application is deployed.|-|false|
57 | |transportText |Text for transport to be created.|X (in case a transport has to be created)|-|
58 | |transportUseLocked |If a deployment failed due to the BSP application is locked in another transport, the old (original one) transport will be used to deploy the files.|-|false|
59 | |transportUseUserMatch |It will be tried to find a transport request of the given user. If no transport is found and createTransport is enabled a new one will be created and used for further file deployments.|-|false|
60 |
61 | Providing the options for the `deploy` command can be done by a configuration file. By default the command searches for a file `./ui5deployrc`. Using the option `--config` an alternative file name can be provided. In the configuration file all options can be provided which are available as command line arguments. The configuration must be provided as JSON object.
62 |
63 | Configuration file example with dummy data. Consider: Do not configure the user/password and bearer token in the file if shared; provide them as command line arguments.
64 | ```json
65 | {
66 | "cwd": "./dist",
67 | "files": "**/*.*",
68 | "server": "http://localhost:8000",
69 | "client": "100",
70 | "testMode": false,
71 | "user": "testuser",
72 | "pwd": "abcd1234",
73 | "bearerToken": "eadfadfdsf...",
74 | "useStrictSSL": false,
75 | "proxy": "http://proxy:3000",
76 | "customQueryParams": {
77 | "parameter1": "Test",
78 | "parameter2": 1234
79 | },
80 | "language": "EN",
81 | "package": "ZZ_UI5_REPOSITORY",
82 | "bspContainer": "ZZ_UI5_TEST",
83 | "bspContainerText": "Test UI5 Upload",
84 | "transportNo": "A4HK900000",
85 | "createTransport": false,
86 | "transportText": "Test Transport",
87 | "transportUseLocked": false,
88 | "transportUseUserMatch": false
89 | }
90 | ```
91 |
92 | In a configuration file not all options must be maintained. It is possible to maintain standard options in the configuration file and provide other ones as command line arguments (like the user and password or the transport number). If an option is defined in the configuration file and provided as command line argument, always the value from the command line argument is taken.
93 |
94 | ### undeploy
95 |
96 | The `undeploy` command undeploys UI5 sources from an ABAP system. It provides following arguments.
97 |
98 | |Option|Description|Mandatory|Default Value|
99 | |:-|:-|:-|:-|
100 | |config |Configuration file containing options for. By default for a file './.ui5deployrc' is searched. If no file is found, it is ignored. Options defined in the configuration file are always overwritten in case they are applied on the command line. Consider to never store the user and password in the config file if the file is shared, provide them as command line arguments.|-|-|
101 | |server |SAP NetWeaver ABAP application server information in form protocol://host:port|X|-|
102 | |client |Client of SAP NetWeaver ABAP application server; if not set default client of server is used.|-|-|
103 | |user |User used for logon to SAP NetWeaver ABAP application server.|X (in case no bearer token is used)|-|
104 | |pwd |Password used for logon to SAP NetWeaver ABAP application server.|X (in case no bearer token is used)|-|
105 | |bearerToken |Bearer token used for authorization.|X (in user/pwd is not used)|-|
106 | |useStrictSSL |SSL mode handling. In case of self signed certificates the useStrictSSL mode option can be set to false to allow a deployment of files.|-|true|
107 | |proxy |Proxy to be used for communication to SAP NetWeaver ABAP application server, form protocol://host:port|-|-|
108 | |customQueryParams |Additional query parameters to be appended to the server calls. To be provided in form `parameterName=parameterValue`|-|-|
109 | |language |Language for deployment.|-|EN|
110 | |package |Defines the development package in which the BSP container for the UI5 sources is available.|X|-|
111 | |bspContainer |Defines the name of the BSP container used for the storage of the UI5 sources. Length is restricted to 15 characters (exclusive customer specific namespaces, e.g. /YYY/).|X|-|
112 | |transportNo |Defines the transport number which logs the changes|X (in case sources are not deployed as local objects)|-|
113 | |createTransport |Set this option to true in case a new transport should be created each time the application is undeployed.|-|false|
114 | |transportText |Text for transport to be created.|X (in case a transport has to be created)|-|
115 | |transportUseLocked |If an undeployment failed due to the BSP application is locked in another transport, the old (original one) transport will be used to undeploy the files.|-|false|
116 |
117 | Providing the options for the `undeploy` command can be done by a configuration file. By default the command searches for a file `./ui5deployrc`. Using the option `--config` an alternative file name can be provided. In the configuration file all options can be provided which are available as command line arguments. The configuration must be provided as JSON object. The same configuration file as for the `deploy` command can be used. Not relevant settings are ignored.
118 |
119 | ## Examples for `deploy` command
120 |
121 | ### Deploy an UI5 app with creation/reusage of transport - command line arguments only
122 |
123 | ```bash
124 | ui5-deployer deploy --server http://localhost:8000 --client "001" --user DEVELOPER --pwd myDeveloperPwd --package ZZ_UI5_REPOSITORY --bspContainer ZZ_UI5_TEST --bspContainerText "Crazy UI5 App" --createTransport true --transportText "UI5 App Development" --transportUseLocked true
125 | ```
126 |
127 | ### Deploy an UI5 app - specific configuration file + user/password as command line arguments
128 | ```bash
129 | ui5-deployer deploy --config ./.myspecificui5deployconfig --user DEVELOPER --pwd myDeveloperPwd
130 | ```
131 |
132 | ## Examples for `undeploy` command
133 |
134 | ### Undeploy an UI5 app with creation/reusage of transport -- command line arguments only
135 |
136 | ```bash
137 | ui5-deployer undeploy --server http://localhost:8000 --client "001" --user DEVELOPER --pwd myDeveloperPwd --package ZZ_UI5_REPOSITORY --bspContainer ZZ_UI5_TEST --createTransport true --transportText "UI5 App Development" --transportUseLocked true
138 | ```
139 |
140 | ### Undeploy an UI5 app - specific configuration file + user/password as command line arguments
141 | ```bash
142 | ui5-deployer undeploy --config ./.myspecificui5deployconfig --user DEVELOPER --pwd myDeveloperPwd
143 | ```
144 |
145 | ## Release History
146 |
147 | [CHANGELOG.md](https://github.com/pfefferf/ui5-nwabap-deployer/blob/master/packages/ui5-nwabap-deployer-cli/CHANGELOG.md)
148 |
149 | ## License
150 |
151 | [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0)
152 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/packages/grunt-nwabap-ui5uploader/README.md:
--------------------------------------------------------------------------------
1 | [](https://badge.fury.io/js/grunt-nwabap-ui5uploader)
2 |
3 | # grunt-nwabap-ui5uploader
4 |
5 | 'grunt-nwabap-ui5uploader' is a Grunt Plugin which allows a developer to deploy SAPUI5/OpenUI5 sources to a SAP NetWeaver ABAP system as part of the Grunt task chain.
6 |
7 | Starting from version 2.0.0 this deployer uses the OData Service [/UI5/ABAP_RESPOSITORY_SRV](https://ui5.sap.com/#/topic/a883327a82ef4cc792f3c1e7b7a48de8) for deploying UI5 sources. Please make sure that the service is activated on your system (for details you can check SAP note [2999557](https://launchpad.support.sap.com/#/notes/2999557)). The new service does some sanity checks like e.g. virus scans. If you have not configured virus scan profiles or want to disable virus scanning please have a look to SAP note [2437892](https://launchpad.support.sap.com/#/notes/2437892).
8 | Current deployer versions starting from version 2.0.0 can be used with SAP systems on which component SAP_UI 753 is installed. On systems with a lower version of component SAP_UI, you have to use version 1.x.x of this deployer.
9 |
10 | Some further information can be found in the [SAP Community](https://blogs.sap.com/2016/03/25/grunt-plugin-to-upload-ui5-sources-to-netweaver-abap/).
11 |
12 |
13 | ## Getting Started
14 |
15 | ## Installation and Pre-Conditions
16 |
17 | ### Grunt
18 | This plugin requires Grunt `1.0.1`
19 |
20 | If you haven't used [Grunt](http://gruntjs.com/) before, be sure to check out the [Getting Started](http://gruntjs.com/getting-started) guide, as it explains how to create a [Gruntfile](http://gruntjs.com/sample-gruntfile) as well as install and use Grunt plugins. Once you are familiar with that process, you may install this plugin with this command:
21 |
22 | ```shell
23 | npm install grunt-nwabap-ui5uploader --save-dev
24 | ```
25 |
26 | Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:
27 |
28 | ```js
29 | grunt.loadNpmTasks('grunt-nwabap-ui5uploader');
30 | ```
31 |
32 |
33 | ### ABAP Development Tool Services
34 | The ABAP Development Tool Services have to be activated on the SAP NetWeaver ABAP System (transaction SICF, path /sap/bc/adt).
35 | The user used for uploading the sources needs to have the authorization to use the ADT Services and to create/modify BSP applications.
36 | The plugin is tested with NW 7.40 and NW 7.5x systems.
37 |
38 | ## Task "nwabap_ui5uploader"
39 |
40 | ### Overview
41 | In your project's Gruntfile, add a section named `nwabap_ui5uploader` to the data object passed into `grunt.initConfig()`.
42 |
43 | ```js
44 | grunt.initConfig({
45 | nwabap_ui5uploader: {
46 | options: {
47 | // Task-specific options go here.
48 | },
49 | your_target: {
50 | // Target-specific file lists and/or options go here.
51 | },
52 | }
53 | });
54 | ```
55 |
56 | ### Options
57 |
58 | #### options.conn.server
59 | Type: `String`
60 |
61 | Defines SAP NetWeaver ABAP server (for instance 'http://myserver:8000').
62 |
63 | #### options.conn.client
64 | Type: `String`
65 |
66 | Optional parameter to specify the client (transferred as sap-client URL parameter). In case the option is not specified the default client is used if specified.
67 |
68 | #### options.conn.useStrictSSL
69 | Type: `Boolean`
70 | Default: `true`
71 |
72 | SSL mode handling. In case of self signed certificates the useStrictSSL mode option can be set to `false` to allow an upload of files.
73 |
74 | #### options.conn.proxy
75 | Type: `String`
76 |
77 | Optional parameter to specify proxy used for communication with SAP NetWeaver ABAP server (for instance 'http://myproxyhost:3128').
78 |
79 | #### options.conn.testMode
80 | Type: `Boolean`
81 | Default: `false`
82 |
83 | Optional parameter to define if upload is done in test mode or not.
84 |
85 | #### options.conn.customQueryParams
86 | Type: `Object`
87 |
88 | Optional parameter with key/value pairs of custom parameters which are added to the call to the SAP NetWeaver ABAP server. For instance:
89 | ```js
90 | customQueryParams: {
91 | myCustomParameter1: 'myCustomValue1',
92 | myCustomParameter2: 'myCustomValue2'
93 | }
94 | ```
95 |
96 | #### options.auth.user
97 | Type: `String`
98 |
99 | Defines the user which is used for access to the SAP NetWeaver ABAP server. It is not recommended to store the user in the Grunt file. It should be passed as argument.
100 |
101 | #### options.auth.pwd
102 | Type: `String`
103 |
104 | Defines the users password for access to the SAP NetWeaver ABAP server. It is not recommended to store the password in the Grunt file. It should be passed as argument. Do also not store the password as not masked value in a CI server environment. Use plugins to create masked variables (for instance the 'Mask Passwords Plugin' for Jenkins).
105 |
106 | #### options.ui5.language
107 | Type: `String`
108 | Default: `EN`
109 |
110 | Defines the objects original language.
111 |
112 | #### options.ui5.package
113 | Type: `String`
114 |
115 | Defines the development package in which the BSP container for the UI5 sources is available or should be created.
116 |
117 | #### options.ui5.bspcontainer
118 | Type: `String`
119 |
120 | Defines the name of the BSP container used for the storage of the UI5 sources. Length is restricted to 15 characters (exclusive customer specific namespaces, e.g. /YYY/).
121 |
122 | #### options.ui5.bspcontainer_text
123 | Type: `String`
124 |
125 | Defines the description of the BSP container.
126 |
127 | #### options.ui5.transportno
128 | Type: `String`
129 | Optional in case options.ui5.package is set to '$TMP'.
130 |
131 | Defines the transport number which logs the changes. For the transport number it would also make sense to pass it via an argument.
132 |
133 | #### options.ui5.create_transport
134 | Type: `Boolean`
135 | Default: `false`
136 |
137 | Set this option to true in case a new transport should be created each time the application is uploaded.
138 |
139 | #### options.ui5.transport_text
140 | Type: `String`
141 |
142 | Optional in case options.ui5.create_transport is set to false.
143 |
144 | Text for the new transport to be created.
145 |
146 | #### options.ui5.transport_use_user_match
147 | Type: `Boolean`
148 | Default: `false`
149 |
150 | Optional, if set to true, it will be tried to find a transport request of the given user. If no transport is found and `create_transport` is enabled a new one will be created and used for further file uploads.
151 |
152 | #### options.ui5.transport_use_locked
153 | Type: `Boolean`
154 | Default: `false`
155 |
156 | Optional, if set to true and a file upload failed due the BSP application is locked in another transport, the old (original one) one will be used to upload the files.
157 |
158 | #### options.resources.cwd
159 | Type: `String`
160 |
161 | Defines the base folder which contains the sources (for instance 'build'). It should be avoided to use everything from the ``webapp`` folder, because some directories in it should not be packaged and uploaded into a BSP application. To create a build, use another grunt task to copy the relevant files to the ``build`` folder. In addition for instance you can use the [openui5_preload](https://github.com/SAP/grunt-openui5#openui5_preload) task from the ``grunt-openui5`` plugin to create a component preload file.
162 |
163 | #### options.resources.src
164 | Type: `String` or `array of String`
165 |
166 | Defines files for upload.
167 |
168 | ### Usage Examples
169 |
170 | #### Upload to '$TMP' package
171 |
172 | ```js
173 | var sUser = grunt.option('user');
174 | var sPwd = grunt.option('pwd');
175 |
176 | grunt.initConfig({
177 | nwabap_ui5uploader: {
178 | options: {
179 | conn: {
180 | server: 'http://myserver:8000',
181 | },
182 | auth: {
183 | user: sUser,
184 | pwd: sPwd
185 | }
186 | },
187 | upload_build: {
188 | options: {
189 | ui5: {
190 | package: '$TMP',
191 | bspcontainer: 'ZZ_UI5_LOCAL',
192 | bspcontainer_text: 'UI5 upload local objects'
193 | },
194 | resources: {
195 | cwd: 'build-folder',
196 | src: '**/*.*'
197 | }
198 | }
199 | }
200 | }
201 | });
202 | ```
203 |
204 | #### Upload to a transport tracked package
205 |
206 | ```js
207 | var sUser = grunt.option('user');
208 | var sPwd = grunt.option('pwd');
209 |
210 | grunt.initConfig({
211 | nwabap_ui5uploader: {
212 | options: {
213 | conn: {
214 | server: 'http://myserver:8000',
215 | },
216 | auth: {
217 | user: sUser,
218 | pwd: sPwd
219 | }
220 | },
221 | upload_build: {
222 | options: {
223 | ui5: {
224 | package: 'ZZ_UI5_REPO',
225 | bspcontainer: 'ZZ_UI5_TRACKED',
226 | bspcontainer_text: 'UI5 upload',
227 | transportno: 'DEVK900000'
228 | },
229 | resources: {
230 | cwd: 'build-folder',
231 | src: '**/*.*'
232 | }
233 | }
234 | }
235 | }
236 | });
237 | ```
238 |
239 | #### Upload to a transport tracked package, creating a new transport for each upload
240 |
241 | ```js
242 | var sUser = grunt.option('user');
243 | var sPwd = grunt.option('pwd');
244 |
245 | grunt.initConfig({
246 | nwabap_ui5uploader: {
247 | options: {
248 | conn: {
249 | server: 'http://myserver:8000',
250 | },
251 | auth: {
252 | user: sUser,
253 | pwd: sPwd
254 | }
255 | },
256 | upload_build: {
257 | options: {
258 | ui5: {
259 | package: 'ZZ_UI5_REPO',
260 | bspcontainer: 'ZZ_UI5_TRACKED',
261 | bspcontainer_text: 'UI5 upload',
262 | create_transport: true,
263 | transport_text: 'Transport for ZZ_UI5_TRACKED container'
264 | },
265 | resources: {
266 | cwd: 'build-folder',
267 | src: '**/*.*'
268 | }
269 | }
270 | }
271 | }
272 | });
273 | ```
274 |
275 | #### Upload to different servers
276 |
277 | ```js
278 | var sUser = grunt.option('user');
279 | var sPwd = grunt.option('pwd');
280 |
281 | grunt.initConfig({
282 | nwabap_ui5uploader: {
283 | upload_build_740: {
284 | options: {
285 | conn: {
286 | server: 'http://myserver740:8000',
287 | },
288 | auth: {
289 | user: sUser,
290 | pwd: sPwd
291 | },
292 | ui5: {
293 | package: 'ZZ_UI5_REPO',
294 | bspcontainer: 'ZZ_UI5_TRACKED',
295 | bspcontainer_text: 'UI5 upload',
296 | transportno: 'DEVK900000'
297 | },
298 | resources: {
299 | cwd: 'build-folder',
300 | src: '**/*.*'
301 | }
302 | }
303 | },
304 | upload_build_750: {
305 | options: {
306 | conn: {
307 | server: 'http://myserver750:8000',
308 | },
309 | auth: {
310 | user: sUser,
311 | pwd: sPwd
312 | },
313 | ui5: {
314 | package: 'ZZ_UI5_REPO',
315 | bspcontainer: 'ZZ_UI5_TRACKED',
316 | bspcontainer_text: 'UI5 upload',
317 | transportno: 'DEVK900000'
318 | },
319 | resources: {
320 | cwd: 'build-folder',
321 | src: '**/*.*'
322 | }
323 | }
324 | }
325 | }
326 | });
327 | ```
328 |
329 | #### Create and reuse a transport request
330 |
331 | ```js
332 | var sUser = grunt.option('user');
333 | var sPwd = grunt.option('pwd');
334 |
335 | grunt.initConfig({
336 | nwabap_ui5uploader: {
337 | options: {
338 | conn: {
339 | server: 'http://myserver:8000',
340 | },
341 | auth: {
342 | user: sUser,
343 | pwd: sPwd
344 | }
345 | },
346 | upload_build: {
347 | options: {
348 | ui5: {
349 | package: 'ZZ_UI5_REPO',
350 | bspcontainer: 'ZZ_UI5_TRACKED',
351 | bspcontainer_text: 'UI5 upload',
352 | create_transport: true,
353 | transport_use_user_match: true,
354 | transport_text: 'Transport for ZZ_UI5_TRACKED container'
355 | },
356 | resources: {
357 | cwd: 'build-folder',
358 | src: '**/*.*'
359 | }
360 | }
361 | }
362 | }
363 | });
364 | ```
365 |
366 | ## Release History
367 |
368 | [CHANGELOG.md](https://github.com/pfefferf/ui5-nwabap-deployer/blob/master/packages/grunt-nwabap-ui5uploader/CHANGELOG.md)
369 |
370 | ## License
371 |
372 | [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0)
373 |
--------------------------------------------------------------------------------
/packages/ui5-nwabap-deployer-core/lib/ui5-nwabap-deployer-core.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const UI5ABAPRepoClient = require("./UI5ABAPRepoClient");
4 | const TransportManager = require("./TransportManager");
5 |
6 | /**
7 | * Set default for language option
8 | * @param {Object} oOptions Options
9 | * @returns {object} Options
10 | */
11 | function setDefaultLanguage(oOptions) {
12 | if (!oOptions.ui5.language) {
13 | oOptions.ui5.language = "EN";
14 | }
15 | return oOptions;
16 | }
17 |
18 | /**
19 | * Set default for use strict ssl option
20 | * @param {Object} oOptions Options
21 | * @returns {Object} Options
22 | */
23 | function setDefaultUseStrictSSL(oOptions) {
24 | if (!oOptions.conn.hasOwnProperty("useStrictSSL")) {
25 | oOptions.conn.useStrictSSL = true;
26 | }
27 | return oOptions;
28 | }
29 |
30 | /**
31 | * Set default test mode to false
32 | * @param {Object} oOptions Options
33 | * @returns {Object} Options
34 | */
35 | function setDefaultTestMode(oOptions) {
36 | if (!oOptions.conn.hasOwnProperty("testMode")) {
37 | oOptions.conn.testMode = false;
38 | }
39 | return oOptions;
40 | }
41 |
42 | /**
43 | * Checks on Connection Options
44 | * @param {Object} oOptions Options
45 | * @param {Object} oLogger Logger
46 | * @returns {Boolean} checks successful?
47 | */
48 | function checkConnectionOptions(oOptions, oLogger) {
49 | if (!oOptions.conn || !oOptions.conn.server) {
50 | oLogger.error("Connection configuration not (fully) specified (check server).");
51 | return false;
52 | }
53 | return true;
54 | }
55 |
56 | /**
57 | * Checks on Authentication Options
58 | * @param {Object} oOptions Options
59 | * @param {Object} oLogger Logger
60 | * @returns {Boolean} checks successful?
61 | */
62 | function checkAuthenticationOptions(oOptions, oLogger) {
63 | if (!oOptions.auth || (!oOptions.auth.bearer_token && (!oOptions.auth.user || !oOptions.auth.pwd)) ) {
64 | oLogger.error("Authentication configuration not correct (check user/password or bearer token).");
65 | return false;
66 | }
67 | return true;
68 | }
69 |
70 | /**
71 | * Checks on Create Transport Options
72 | * @param {Object} oOptions Options
73 | * @param {Object} oLogger Logger
74 | * @returns {Boolean} checks successful?
75 | */
76 | function checkCreateTransport(oOptions, oLogger) {
77 | if (oOptions.ui5.create_transport === true && typeof oOptions.ui5.transport_text !== "string") {
78 | oLogger.error("Please specify a description to be used for the transport to be created.");
79 | return false;
80 | }
81 | return true;
82 | }
83 |
84 | /**
85 | * Checks on Deploy Options
86 | * @param {Object} oOptions Options
87 | * @param {Object} oLogger Logger
88 | * @returns {Boolean} checks successful?
89 | */
90 | function checkDeployOptions(oOptions, oLogger) {
91 | let bCheckSuccessful = true;
92 |
93 | if (!checkConnectionOptions(oOptions, oLogger)) {
94 | bCheckSuccessful = false;
95 | }
96 |
97 | if (!checkAuthenticationOptions(oOptions, oLogger)) {
98 | bCheckSuccessful = false;
99 | }
100 |
101 | if (!oOptions.ui5 || !oOptions.ui5.package || !oOptions.ui5.bspcontainer || !oOptions.ui5.bspcontainer_text) {
102 | oLogger.error("UI5 configuration not (fully) specified (check package, BSP container, BSP container text information).");
103 | bCheckSuccessful = false;
104 | }
105 |
106 | if (oOptions.ui5 && oOptions.ui5.package && !oOptions.ui5.package.startsWith("$") && !oOptions.ui5.transportno &&
107 | oOptions.ui5.create_transport !== true && oOptions.ui5.transport_use_user_match !== true && oOptions.conn.testMode !== true) {
108 | oLogger.error("For non-local packages (package name does not start with a \"$\") a transport number is necessary.");
109 | bCheckSuccessful = false;
110 | }
111 |
112 | if (!checkCreateTransport(oOptions, oLogger)) {
113 | bCheckSuccessful = false;
114 | }
115 |
116 | if (oOptions.ui5 && oOptions.ui5.bspcontainer) {
117 | const bspcontainerExclNamespace = oOptions.ui5.bspcontainer.substring(oOptions.ui5.bspcontainer.lastIndexOf("/") + 1);
118 | if (bspcontainerExclNamespace.length > 15) {
119 | oLogger.error("BSP Container name must not be longer than 15 characters (exclusive customer specific namespace e.g. /YYY/.");
120 | bCheckSuccessful = false;
121 | }
122 | }
123 |
124 | return bCheckSuccessful;
125 | }
126 |
127 | /**
128 | * Checks on Undeploy Options
129 | * @param {Object} oOptions Options
130 | * @param {Object} oLogger Logger
131 | * @returns {Boolean} checks successful?
132 | */
133 | function checkUndeployOptions(oOptions, oLogger) {
134 | let bCheckSuccessful = true;
135 |
136 | if (!checkConnectionOptions(oOptions, oLogger)) {
137 | bCheckSuccessful = false;
138 | }
139 |
140 | if (!checkAuthenticationOptions(oOptions, oLogger)) {
141 | bCheckSuccessful = false;
142 | }
143 |
144 | if (!oOptions.ui5 || !oOptions.ui5.package || !oOptions.ui5.bspcontainer ) {
145 | oLogger.error("Please specify a Package and a BSP container.");
146 | bCheckSuccessful = false;
147 | }
148 |
149 | if (oOptions.ui5 && oOptions.ui5.package && !oOptions.ui5.package.startsWith("$") && !oOptions.ui5.transportno &&
150 | oOptions.ui5.create_transport !== true && oOptions.conn.testMode !== true) {
151 | oLogger.error("For non-local packages (package name does not start with a \"$\") a transport number is necessary.");
152 | bCheckSuccessful = false;
153 | }
154 |
155 | if (!checkCreateTransport(oOptions, oLogger)) {
156 | bCheckSuccessful = false;
157 | }
158 |
159 | return bCheckSuccessful;
160 | }
161 |
162 | /**
163 | * Synchronize Files
164 | * @param {object} oOptions
165 | * @param {object} oLogger
166 | * @param {array} aFiles
167 | */
168 | function syncFiles(oOptions, oLogger, aFiles) {
169 | return new Promise(async (resolve, reject) => {
170 | try {
171 | const oRepoClient = new UI5ABAPRepoClient(oOptions, oLogger);
172 | await oRepoClient.deployRepo(aFiles);
173 | resolve();
174 | return;
175 | } catch (oError) {
176 | reject(oError);
177 | return;
178 | }
179 | });
180 | }
181 |
182 | /**
183 | * Upload the files with an transport which does the user own.
184 | * @param {Object} oTransportManager Transport manager
185 | * @param {Object} oOptions File Store Options
186 | * @param {Object} oLogger Logger
187 | * @Param {Array} aFiles Files
188 | */
189 | async function uploadWithTransportUserMatch(oTransportManager, oOptions, oLogger, aFiles) {
190 | return new Promise((resolve, reject) => {
191 | oTransportManager.determineExistingTransport(async function(oError, sTransportNo) {
192 | if (oError) {
193 | reject(oError);
194 | return;
195 | } else if (sTransportNo) {
196 | oOptions.ui5.transportno = sTransportNo;
197 | try {
198 | await syncFiles(oOptions, oLogger, aFiles);
199 | resolve();
200 | return;
201 | } catch (oError) {
202 | reject(oError);
203 | return;
204 | }
205 | } else if (oOptions.ui5.create_transport === true) {
206 | oTransportManager.createTransport(oOptions.ui5.package, oOptions.ui5.transport_text, async function(oError, sTransportNo) {
207 | if (oError) {
208 | reject(oError);
209 | return;
210 | }
211 | oOptions.ui5.transportno = sTransportNo;
212 | try {
213 | await syncFiles(oOptions, oLogger, aFiles);
214 | resolve();
215 | return;
216 | } catch (oError) {
217 | reject(oError);
218 | return;
219 | }
220 | });
221 | } else {
222 | reject(new Error("No transport found and create transport was disabled!"));
223 | return;
224 | }
225 | });
226 | });
227 | }
228 |
229 | /**
230 | * Central function to deploy UI5 sources to a SAP NetWeaver ABAP system.
231 | * @param {Object} oOptions Options
232 | * @param {Array} aFiles Files to deploy
233 | * @param {Object} oLogger Logger
234 | */
235 | exports.deployUI5toNWABAP = async function(oOptions, aFiles, oLogger) {
236 | return new Promise(async function(resolve, reject) {
237 | let oOptionsAdapted = {};
238 |
239 | oOptionsAdapted = Object.assign(oOptionsAdapted, oOptions);
240 |
241 | oOptionsAdapted = setDefaultLanguage(oOptionsAdapted);
242 | oOptionsAdapted = setDefaultUseStrictSSL(oOptionsAdapted);
243 | oOptionsAdapted = setDefaultTestMode(oOptionsAdapted);
244 |
245 | // checks on options
246 | if (!checkDeployOptions(oOptionsAdapted, oLogger)) {
247 | reject(new Error("Configuration incorrect."));
248 | return;
249 | }
250 |
251 | // verbose log options
252 | oLogger.logVerbose(`Options: ${JSON.stringify(oOptionsAdapted)}`);
253 |
254 | // info about test mode
255 | if (oOptions.conn.testMode) {
256 | oLogger.log("Running in Test Mode - no changes are done.");
257 | }
258 |
259 | // binary determination
260 | const aFilesAdapted = aFiles.map((oFile) => {
261 | return oFile;
262 | });
263 |
264 | // verbose log files
265 | oLogger.logVerbose("Files: " + aFilesAdapted);
266 |
267 | // sync files
268 | const oTransportManager = new TransportManager(oOptionsAdapted, oLogger);
269 | let sExistingTransportNo = null;
270 | try {
271 | sExistingTransportNo = await oTransportManager.determineExistingTransportForBspContainer(oOptionsAdapted.ui5.package, oOptionsAdapted.ui5.bspcontainer);
272 | } catch (oError) {
273 | reject(oError);
274 | return;
275 | }
276 |
277 | if (sExistingTransportNo && !oOptionsAdapted.ui5.transport_use_locked && ((!oOptionsAdapted.ui5 || !oOptionsAdapted.ui5.transportno) || (oOptionsAdapted.ui5 && oOptionsAdapted.ui5.transportno !== sExistingTransportNo))) {
278 | reject(new Error(`BSP container already locked in transport ${sExistingTransportNo}. But it was not configured to reuse a transport with an existing lock.`));
279 | return;
280 | }
281 |
282 | if (sExistingTransportNo && oOptionsAdapted.ui5.transport_use_locked) {
283 | // existing transport lock
284 | oOptionsAdapted.ui5.transportno = sExistingTransportNo;
285 | oLogger.log(`BSP Application ${oOptionsAdapted.ui5.bspcontainer} already locked in transport request ${sExistingTransportNo}. This transport request is used for deployment.`);
286 | try {
287 | await syncFiles(oOptionsAdapted, oLogger, aFilesAdapted);
288 | resolve({ oOptions: oOptionsAdapted });
289 | return;
290 | } catch (oError) {
291 | reject(oError);
292 | return;
293 | }
294 | }
295 |
296 | if (!oOptionsAdapted.ui5.package.startsWith("$") && oOptionsAdapted.ui5.transportno === undefined) {
297 | if (oOptionsAdapted.ui5.transport_use_user_match) {
298 | try {
299 | await uploadWithTransportUserMatch(oTransportManager, oOptionsAdapted, oLogger, aFilesAdapted);
300 | resolve({ oOptions: oOptionsAdapted });
301 | return;
302 | } catch (oError) {
303 | reject(oError);
304 | return;
305 | }
306 | } else if (oOptionsAdapted.ui5.create_transport === true) {
307 | try {
308 | let sTransportNo = "A4HK900000"; // dummy transport for test mode
309 | if (!oOptionsAdapted.conn.testMode) {
310 | sTransportNo = await oTransportManager.createTransportPromise(oOptionsAdapted.ui5.package, oOptionsAdapted.ui5.transport_text);
311 | }
312 | oOptionsAdapted.ui5.transportno = sTransportNo;
313 | } catch (oError) {
314 | reject(oError);
315 | return;
316 | }
317 |
318 | try {
319 | await syncFiles(oOptionsAdapted, oLogger, aFilesAdapted);
320 | resolve({ oOptions: oOptionsAdapted });
321 | return;
322 | } catch (oError) {
323 | reject(oError);
324 | return;
325 | }
326 | } else {
327 | const oError = new Error("No transport configured and 'create transport' and 'use user match' options are disabled.");
328 | reject(oError);
329 | return;
330 | }
331 | } else {
332 | try {
333 | await syncFiles(oOptionsAdapted, oLogger, aFilesAdapted);
334 | resolve({ oOptions: oOptionsAdapted });
335 | return;
336 | } catch (oError) {
337 | reject(oError);
338 | return;
339 | }
340 | }
341 | });
342 | };
343 |
344 | /**
345 | * Central function to undeploy UI5 sources from a SAP NetWeaver ABAP system.
346 | * @param {Object} oOptions Options
347 | * @param {Object} oLogger Logger
348 | */
349 | exports.undeployUI5fromNWABAP = async function(oOptions, oLogger) {
350 | return new Promise(async function(resolve, reject) {
351 | let oOptionsAdapted = {};
352 |
353 | oOptionsAdapted = Object.assign(oOptionsAdapted, oOptions);
354 |
355 | oOptionsAdapted = setDefaultLanguage(oOptionsAdapted);
356 | oOptionsAdapted = setDefaultUseStrictSSL(oOptionsAdapted);
357 | oOptionsAdapted = setDefaultTestMode(oOptionsAdapted);
358 |
359 | // info about test mode
360 | if (oOptions.conn.testMode) {
361 | oLogger.log("Running in Test Mode - no changes are done.");
362 | }
363 |
364 | // checks on options
365 | if (!checkUndeployOptions(oOptionsAdapted, oLogger)) {
366 | reject(new Error("Configuration incorrect."));
367 | return;
368 | }
369 |
370 | // verbose log options
371 | oLogger.logVerbose(`Options: ${JSON.stringify(oOptionsAdapted)}`);
372 |
373 | // determine existing transport
374 | const oTransportManager = new TransportManager(oOptionsAdapted, oLogger);
375 | let sExistingTransportNo = null;
376 | try {
377 | sExistingTransportNo = await oTransportManager.determineExistingTransportForBspContainer(oOptionsAdapted.ui5.package, oOptionsAdapted.ui5.bspcontainer);
378 | } catch (oError) {
379 | reject(oError);
380 | return;
381 | }
382 |
383 | if (sExistingTransportNo && !oOptionsAdapted.ui5.transport_use_locked && ((!oOptionsAdapted.ui5 || !oOptionsAdapted.ui5.transportno) || (oOptionsAdapted.ui5 && oOptionsAdapted.ui5.transportno !== sExistingTransportNo))) {
384 | reject(new Error(`BSP container already locked in transport ${sExistingTransportNo}. But it was not configured to reuse a transport with an existing lock.`));
385 | return;
386 | }
387 |
388 | // use existing transport if required
389 | if (sExistingTransportNo && oOptionsAdapted.ui5.transport_use_locked) {
390 | oOptionsAdapted.ui5.transportno = sExistingTransportNo;
391 | oLogger.log(`BSP Application ${oOptionsAdapted.ui5.bspcontainer} already locked in transport request ${sExistingTransportNo}. This transport request is used for undeploy.`);
392 | }
393 |
394 | // create new transport if necessary
395 | let oRepoClient = new UI5ABAPRepoClient(oOptionsAdapted, oLogger);
396 | let isRepoExisting = false;
397 | try {
398 | isRepoExisting = await oRepoClient.isRepoExisting();
399 | } catch (oError) {
400 | reject(oError);
401 | }
402 |
403 | if (oOptionsAdapted.ui5.create_transport && !sExistingTransportNo && isRepoExisting) {
404 | try {
405 | const sTransportNo = await oTransportManager.createTransportPromise(oOptionsAdapted.ui5.package, oOptionsAdapted.ui5.transport_text);
406 | oOptionsAdapted.ui5.transportno = sTransportNo;
407 | } catch (oError) {
408 | reject(oError);
409 | return;
410 | }
411 | }
412 |
413 | // undeploy
414 | try {
415 | oRepoClient = new UI5ABAPRepoClient(oOptionsAdapted, oLogger);
416 | await oRepoClient.undeployRepo();
417 | resolve({ oOptions: oOptionsAdapted });
418 | return;
419 | } catch (oError) {
420 | reject(oError);
421 | return;
422 | }
423 | });
424 | };
425 |
--------------------------------------------------------------------------------