@sap/html5-app-deployer
Advanced tools
Comparing version
@@ -8,2 +8,7 @@ # Change Log | ||
## 3.0.0 - 2021-03-11 | ||
### Added | ||
- Asynchroneus upload support | ||
## 2.3.1 - 2021-02-16 | ||
@@ -10,0 +15,0 @@ |
@@ -13,2 +13,3 @@ /* eslint-disable no-console */ | ||
var DestinationUtils = require('./destination-utils'); | ||
var GACDHandler = require('./gacd-handler'); | ||
@@ -31,4 +32,4 @@ exports.startDeployer = startDeployer; | ||
var resourcesFolder; | ||
var loggingLevel = process.env.APP_LOG_LEVEL || 'error'; | ||
// define logger | ||
var loggingLevel = process.env.APP_LOG_LEVEL || 'info'; | ||
// define logger | ||
log.setLoggingLevel(loggingLevel); | ||
@@ -40,9 +41,9 @@ try { | ||
log.logMessage('info', 'Application Deployer started ..', {'CODE': '2000'}); | ||
// Get service | ||
// Get service | ||
service = utils.getService(); | ||
// Validate service | ||
// Validate service | ||
utils.validateService(service); | ||
// Get resources folder | ||
// Get resources folder | ||
resourcesFolder = utils.getResourcesFolder(service); | ||
// validateResourcesFolder | ||
// validateResourcesFolder | ||
utils.validateResourcesFolder(resourcesFolder); | ||
@@ -72,3 +73,3 @@ } catch (e) { | ||
var folderEntries = fs.readdirSync(resourcesPath); | ||
// Get Token, Archive and Upload | ||
// Get Token, Archive and Upload | ||
utils.obtainToken(service, function (err, token) { | ||
@@ -79,32 +80,42 @@ if (err) { | ||
async.each(folderEntries, | ||
function (appDirName, iterateCb) { // for each entry | ||
var appResourcesPath = path.join(resourcesPath, appDirName); | ||
if (utils.isZipFile(appResourcesPath)){ | ||
appsZips.push(appResourcesPath); | ||
return iterateCb(); | ||
} else { | ||
var applicationZip = path.join(buildDirectory, appDirName + '.zip'); | ||
utils.archive(appResourcesPath, buildDirectory, applicationZip, | ||
function (err) { | ||
if (err) { | ||
return iterateCb(err); | ||
} | ||
log.logMessage('info', 'Archiver has been finalized and the output file ' + appDirName + '.zip descriptor has closed', {'code': '2001'}); | ||
appsZips.push(applicationZip); | ||
iterateCb(); | ||
}); | ||
} | ||
}, function (err) { // after finish all entries | ||
function (appDirName, iterateCb) { // for each entry | ||
var appResourcesPath = path.join(resourcesPath, appDirName); | ||
if (utils.isZipFile(appResourcesPath)){ | ||
appsZips.push(appResourcesPath); | ||
return iterateCb(); | ||
} else { | ||
var applicationZip = path.join(buildDirectory, appDirName + '.zip'); | ||
utils.archive(appResourcesPath, buildDirectory, applicationZip, | ||
function (err) { | ||
if (err) { | ||
return cb(err); | ||
return iterateCb(err); | ||
} | ||
utils.upload(service, token, appsZips, function (err) { | ||
if (err) { | ||
cb(err); | ||
} | ||
else { | ||
cb(); | ||
} | ||
}); | ||
log.logMessage('info', 'Archiver has been finalized and the output file ' + appDirName + '.zip descriptor has closed', {'code': '2001'}); | ||
appsZips.push(applicationZip); | ||
iterateCb(); | ||
}); | ||
} | ||
}, function (err) { // after finish all entries | ||
if (err) { | ||
return cb(err); | ||
} | ||
let contentZipPath = path.join(buildDirectory, 'content.zip'); | ||
let gacdHandler = new GACDHandler(service,token,contentZipPath); | ||
if (process.env.ASYNC_UPLOAD){ | ||
utils.archiveFiles(appsZips,buildDirectory,contentZipPath) | ||
.then(() => gacdHandler.upload()) | ||
.then(() => gacdHandler.deploy()) | ||
.then(() => { | ||
gacdHandler.pollDeployStatus(); | ||
cb(); | ||
}) | ||
.catch((err) => { | ||
cb(err); | ||
}); | ||
} else { | ||
utils.upload(service, token, appsZips, function (err) { | ||
cb(err); | ||
}); | ||
} | ||
}); | ||
}); | ||
@@ -116,2 +127,3 @@ } | ||
var deployId = process.env.DEPLOY_ID || 'none'; | ||
var isAsyncUpload = process.env.ASYNC_UPLOAD; | ||
if (err) { | ||
@@ -134,3 +146,3 @@ console.log('Upload of html5 applications content failed ',err); | ||
if (deployId !== 'none') { // Scenario of Deploy plugin | ||
if (deployId !== 'none' && !isAsyncUpload) { // Scenario of Deploy plugin | ||
if (err) { | ||
@@ -143,2 +155,5 @@ log.logMessage('error', 'Deployment of html5 application content failed [Deployment Id: %s]', deployId, {'CODE': '2007'}); | ||
} | ||
if (process.env.TEST_MODE){ | ||
return cb(err); | ||
} | ||
setInterval(function () { | ||
@@ -150,5 +165,8 @@ log.logMessage('info', 'Waiting for deploy service to stop the application', {'CODE': '2008'}); | ||
if (!err) { // don't leave app started if failed | ||
// For hanging the process | ||
// For hanging the process | ||
if (process.env.TEST_MODE){ | ||
return cb(); | ||
} | ||
var port = process.env.PORT || 3000; | ||
// eslint-disable-next-line no-unused-vars | ||
// eslint-disable-next-line no-unused-vars | ||
server = http.createServer(function (req, res) { | ||
@@ -155,0 +173,0 @@ }).listen(port); |
@@ -67,3 +67,3 @@ /* eslint-disable no-console */ | ||
throw Error('The resources folder is invalid because it contains the file - ' + entry + | ||
'; the resources folder should contain application folders and/or zip files.'); | ||
'; the resources folder should contain application folders and/or zip files.'); | ||
} | ||
@@ -75,4 +75,4 @@ }); | ||
if (!service.credentials || !service.credentials.uri | ||
|| !service.credentials.uaa || !service.credentials.uaa.url | ||
|| !service.credentials.uaa.clientid || !service.credentials.uaa.clientsecret) { | ||
|| !service.credentials.uaa || !service.credentials.uaa.url | ||
|| !service.credentials.uaa.clientid || !service.credentials.uaa.clientsecret) { | ||
throw Error('Incomplete credentials for html5 applications repository service'); | ||
@@ -82,4 +82,31 @@ } | ||
exports.archiveFiles = function (appsZips, buildDirectory, buildFile) { | ||
return new Promise((resolve, reject) => { | ||
if (!fs.existsSync(buildDirectory)) { | ||
fs.mkdirSync(buildDirectory); | ||
} | ||
var output = fs.createWriteStream(buildFile); | ||
var archive = archiver('zip', { | ||
store: true | ||
}); | ||
output.on('close', function () { | ||
// When archive finished - send it | ||
resolve(); | ||
}); | ||
archive.on('error', function (err) { | ||
reject(new Error('Archiving failed. ' + err)); | ||
}); | ||
archive.pipe(output); | ||
appsZips.forEach((appZip) => { | ||
let parts = appZip.split('/'); | ||
let fileName = parts[parts.length - 1]; | ||
archive.append(fs.createReadStream(appZip), {name: fileName}); | ||
}); | ||
archive.finalize(); | ||
}); | ||
}; | ||
exports.archive = function (zipResources, buildDirectory, buildFile, cb) { | ||
// Create build directory | ||
// Create build directory | ||
if (!fs.existsSync(buildDirectory)) { | ||
@@ -94,3 +121,3 @@ fs.mkdirSync(buildDirectory); | ||
output.on('close', function () { | ||
// When archive finished - send it | ||
// When archive finished - send it | ||
cb(); | ||
@@ -112,8 +139,8 @@ }); | ||
} | ||
if (res.statusCode === 201) { | ||
else if (res && res.statusCode === 201) { | ||
cb(); | ||
} | ||
else { | ||
cb(new Error('Error while uploading resources to Server; Status: ' + res.statusCode + | ||
' Response: ' + JSON.stringify(body))); | ||
cb(new Error('Error while uploading resources to Server; Status: ' + (res && res.statusCode) + | ||
' Response: ' + JSON.stringify(body))); | ||
} | ||
@@ -135,21 +162,21 @@ }); | ||
}, | ||
function (err, res, body) { | ||
try { | ||
if (err) { | ||
cb(new Error('Error while obtaining token. ' + err)); | ||
} | ||
else if (res.statusCode === 200) { | ||
if (!JSON.parse(body).access_token) { | ||
cb(new Error('Bad token')); | ||
} else { | ||
cb(null, JSON.parse(body).access_token); | ||
} | ||
function (err, res, body) { | ||
try { | ||
if (err) { | ||
cb(new Error('Error while obtaining token. ' + err)); | ||
} | ||
else if (res.statusCode === 200) { | ||
if (!JSON.parse(body).access_token) { | ||
cb(new Error('Bad token')); | ||
} else { | ||
cb(new Error('Error while obtaining aaaa token; Status: ' + res.statusCode + | ||
' Response: ' + JSON.stringify(body))); | ||
cb(null, JSON.parse(body).access_token); | ||
} | ||
} catch (e) { | ||
cb(new Error('Error while parsing UAA response; ' + e)); | ||
} else { | ||
cb(new Error('Error while obtaining aaaa token; Status: ' + res.statusCode + | ||
' Response: ' + JSON.stringify(body))); | ||
} | ||
}); | ||
} catch (e) { | ||
cb(new Error('Error while parsing UAA response; ' + e)); | ||
} | ||
}); | ||
}; | ||
@@ -233,3 +260,3 @@ | ||
} | ||
var buffer = new Buffer(4100); | ||
var buffer = Buffer.alloc(4100); | ||
var fd = fs.openSync(filePath,'r'); | ||
@@ -242,2 +269,2 @@ fs.readSync(fd, buffer, 0, 4100); | ||
return false; | ||
} | ||
} |
@@ -6,3 +6,3 @@ { | ||
}, | ||
"version": "2.3.1", | ||
"version": "3.0.0", | ||
"description": "HTML5 application deployer", | ||
@@ -21,3 +21,3 @@ "main": "index.js", | ||
"chai": "3.5.0", | ||
"mocha": "3.0.2", | ||
"mocha": "8.3.0", | ||
"eslint": "3.2.2", | ||
@@ -27,9 +27,9 @@ "connect": "3.6.2", | ||
"multer": "1.3.0", | ||
"istanbul": "0.4.4", | ||
"istanbul": "0.4.5", | ||
"test-console": "1.1.0", | ||
"express": "4.16.2", | ||
"sinon": "4.2.2", | ||
"gulp": "^3.9.1", | ||
"gulp": "4.0.2", | ||
"gulp-eslint": "^4.0.0", | ||
"gulp-mocha": "^4.3.1", | ||
"gulp-mocha": "8.0.0", | ||
"sonarqube-scanner": "^2.1.2" | ||
@@ -39,3 +39,3 @@ }, | ||
"start": "node index.js", | ||
"test": "node node_modules/istanbul/lib/cli.js cover node_modules/mocha/bin/_mocha test -- --recursive --check-leaks", | ||
"test": "node node_modules/istanbul/lib/cli.js cover node_modules/mocha/bin/_mocha test --recursive --check-leaks", | ||
"lint": "eslint -c .eslintrc -f stylish lib/ index.js", | ||
@@ -42,0 +42,0 @@ "ipscan": "node ./node_modules/whitesource/bin/whitesource run", |
@@ -219,2 +219,8 @@ @sap/html5-app-deployer | ||
## Asynchronous Upload | ||
You can specify that upload content should be performed asynchronously by adding environment variable ASYNC_UPLOAD to manifest.yaml or mta.yaml files. | ||
Asynchronous upload means that the html5 applications content will be handled synchronously to HTML5 Application Repository but the internal file validation and processing will be performed asynchronously. | ||
In this setup, you will have to check the html5 application deployer logs to verify that the upload was completed successfully. | ||
Using asynchronous upload is specially important when triggering upload of service instance with large content (more than 10 MB). In such cases synchronous upload might cause health check errors or connection timeout during upload. | ||
## Automatic Creation of Destination Configurations | ||
@@ -221,0 +227,0 @@ When using HTML5 Application Deployer in SAP Managed Approuter flows you can configure the automatic creation of the required instance level destination configurations. |
Sorry, the diff of this file is not supported yet
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
Unidentified License
License(Experimental) Something that seems like a license was found, but its contents could not be matched with a known license.
Found 1 instance in 1 package
Unidentified License
License(Experimental) Something that seems like a license was found, but its contents could not be matched with a known license.
Found 1 instance in 1 package
76198
15.81%12
9.09%760
34.04%304
2.01%18
50%