From fc7f659ab45a6828a1ab05a35dbe856a4a2b5f87 Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Tue, 18 Jun 2019 18:04:05 +0200 Subject: [PATCH] [FIX] generateManifestBundle: Only glob files from project namespace manifestBundler can only include resources from paths that are based on the projects namespace (see regex in manifestBundler ZIP creation). For other paths the bundling fails because yazl can't add absolute paths. Also, only resources located in the projects "/resources" should be relevant for manifest bundling. The latter resovles https://github.com/UI5Lab/UI5Lab-library-simple/issues/11 where with UI5 CLI v1.5.1 the only problem left is, that generateManifestBundle tries to bundle manifest.json resources found in the libraries /test-resources. --- lib/tasks/bundlers/generateManifestBundle.js | 46 ++-- lib/types/library/LibraryBuilder.js | 2 +- .../tasks/bundlers/generateManifestBundle.js | 208 ++++++++---------- 3 files changed, 119 insertions(+), 137 deletions(-) diff --git a/lib/tasks/bundlers/generateManifestBundle.js b/lib/tasks/bundlers/generateManifestBundle.js index fa5b19192..4f740e139 100644 --- a/lib/tasks/bundlers/generateManifestBundle.js +++ b/lib/tasks/bundlers/generateManifestBundle.js @@ -16,25 +16,29 @@ const BUNDLE_NAME = "manifest-bundle.zip"; * @param {string} parameters.options.namespace Namespace of the application/library * @returns {Promise} Promise resolving with undefined once data has been written */ -module.exports = function({workspace, options}) { - return workspace.byGlob(`/**/{${DESCRIPTOR},*${PROPERTIES_EXT}}`) - .then((allResources) => { - if (allResources.length > 0) { - return manifestBundler({ - resources: allResources, - options: { - descriptor: DESCRIPTOR, - propertiesExtension: PROPERTIES_EXT, - bundleName: BUNDLE_NAME, - namespace: options.namespace - } - }).then((processedResources) => { - return Promise.all(processedResources.map((resource) => { - return workspace.write(resource); - })); - }); - } else { - log.verbose(`Could not find a "${DESCRIPTOR}" file for project ${options.projectName}, creation of "${BUNDLE_NAME}" is skipped!`); - } - }); +module.exports = async function({workspace, options}) { + if (!options || !options.projectName || !options.namespace) { + throw new Error("[generateManifestBundle]: One or more mandatory options not provided"); + } + + const allResources = await workspace.byGlob(`/resources/${options.namespace}/**/{${DESCRIPTOR},*${PROPERTIES_EXT}}`); + if (allResources.length === 0) { + log.verbose(`Could not find a "${DESCRIPTOR}" file for project ${options.projectName}, ` + + `creation of "${BUNDLE_NAME}" is skipped!`); + return; + } + + const processedResources = await manifestBundler({ + resources: allResources, + options: { + descriptor: DESCRIPTOR, + propertiesExtension: PROPERTIES_EXT, + bundleName: BUNDLE_NAME, + namespace: options.namespace + } + }); + + await Promise.all(processedResources.map((resource) => { + return workspace.write(resource); + })); }; diff --git a/lib/types/library/LibraryBuilder.js b/lib/types/library/LibraryBuilder.js index af3cb5d65..806278ee8 100644 --- a/lib/types/library/LibraryBuilder.js +++ b/lib/types/library/LibraryBuilder.js @@ -123,7 +123,7 @@ class LibraryBuilder extends AbstractBuilder { return generateManifestBundle({ workspace: resourceCollections.workspace, options: { - projectType: project.type, + projectName: project.metadata.name, namespace: project.metadata.namespace } }); diff --git a/test/lib/tasks/bundlers/generateManifestBundle.js b/test/lib/tasks/bundlers/generateManifestBundle.js index 401924204..3cb5e9b5b 100644 --- a/test/lib/tasks/bundlers/generateManifestBundle.js +++ b/test/lib/tasks/bundlers/generateManifestBundle.js @@ -1,19 +1,105 @@ const test = require("ava"); const path = require("path"); +const sinon = require("sinon"); +const mock = require("mock-require"); + const chai = require("chai"); chai.use(require("chai-fs")); const assert = chai.assert; - +const {promisify} = require("util"); +const extractZip = promisify(require("extract-zip")); +const recursive = require("recursive-readdir"); const ui5Builder = require("../../../../"); const builder = ui5Builder.builder; +const generateManifestBundle = require("../../../../lib/tasks/bundlers/generateManifestBundle"); + +test.serial("generateManifestBundle", async (t) => { + const byGlobStub = sinon.stub().resolves(["some resource", "some other resource"]); + const writeStub = sinon.stub().resolves(); + const workspace = { + byGlob: byGlobStub, + write: writeStub + }; + + const manifestBundlerStub = sinon.stub().resolves(["some new resource", "some other new resource"]); + mock("../../../../lib/processors/bundlers/manifestBundler", manifestBundlerStub); + const generateManifestBundle = mock.reRequire("../../../../lib/tasks/bundlers/generateManifestBundle"); + + + await generateManifestBundle({ + workspace, + options: { + projectName: "some project", + namespace: "some/project" + } + }); + t.deepEqual(byGlobStub.callCount, 1, "workspace.byGlob got called once"); + t.deepEqual(byGlobStub.getCall(0).args[0], "/resources/some/project/**/{manifest.json,*.properties}", + "workspace.byGlob got called with the correct arguments"); + + t.deepEqual(manifestBundlerStub.callCount, 1, "manifestBundler got called once"); + t.deepEqual(manifestBundlerStub.getCall(0).args[0], { + resources: ["some resource", "some other resource"], + options: { + descriptor: "manifest.json", + propertiesExtension: ".properties", + bundleName: "manifest-bundle.zip", + namespace: "some/project" + } + }, "manifestBundler got called with the correct arguments"); + + t.deepEqual(writeStub.callCount, 2, "workspace.write got called twice"); + t.deepEqual(writeStub.getCall(0).args[0], "some new resource", + "workspace.write got called with the correct arguments"); + t.deepEqual(writeStub.getCall(1).args[0], "some other new resource", + "workspace.write got called with the correct arguments"); + + mock.stop("../../../../lib/processors/bundlers/manifestBundler"); +}); + +test.serial("generateManifestBundle with no resources", async (t) => { + const byGlobStub = sinon.stub().resolves([]); + const workspace = { + byGlob: byGlobStub + }; + + const manifestBundlerStub = sinon.stub().resolves([]); + mock("../../../../lib/processors/bundlers/manifestBundler", manifestBundlerStub); + const generateManifestBundle = mock.reRequire("../../../../lib/tasks/bundlers/generateManifestBundle"); + + + await generateManifestBundle({ + workspace, + options: { + projectName: "some project", + namespace: "some/project" + } + }); + t.deepEqual(byGlobStub.callCount, 1, "workspace.byGlob got called once"); + t.deepEqual(byGlobStub.getCall(0).args[0], "/resources/some/project/**/{manifest.json,*.properties}", + "workspace.byGlob got called with the correct arguments"); + + t.deepEqual(manifestBundlerStub.callCount, 0, "manifestBundler not called"); + + mock.stop("../../../../lib/processors/bundlers/manifestBundler"); +}); + +test("generateManifestBundle with missing parameters", async (t) => { + const error = await t.throwsAsync(generateManifestBundle({})); + t.deepEqual(error.message, "[generateManifestBundle]: One or more mandatory options not provided", + "Rejected with correct error message"); +}); + + +/* =================== + Integration Tests +*/ + const applicationBPath = path.join(__dirname, "..", "..", "..", "fixtures", "application.b"); const libraryCore = path.join(__dirname, "..", "..", "..", "fixtures", "sap.ui.core-evo"); const libraryKPath = path.join(__dirname, "..", "..", "..", "fixtures", "library.k"); -const {promisify} = require("util"); -const extractZip = promisify(require("extract-zip")); -const recursive = require("recursive-readdir"); const findFiles = (folder) => { return new Promise((resolve, reject) => { @@ -91,113 +177,7 @@ const applicationBTree = { "id": "application.b", "version": "1.0.0", "path": applicationBPath, - "dependencies": [ - { - "id": "library.d", - "version": "1.0.0", - "path": path.join(applicationBPath, "..", "library.d"), - "dependencies": [], - "_level": 1, - "specVersion": "0.1", - "type": "library", - "metadata": { - "name": "library.d", - "namespace": "library/d", - "copyright": "Some fancy copyright" - }, - "resources": { - "configuration": { - "paths": { - "src": "main/src", - "test": "main/test" - } - }, - "pathMappings": { - "/resources/": "main/src", - "/test-resources/": "main/test" - } - } - }, - { - "id": "library.a", - "version": "1.0.0", - "path": path.join(applicationBPath, "..", "collection", "library.a"), - "dependencies": [], - "_level": 1, - "specVersion": "0.1", - "type": "library", - "metadata": { - "name": "library.a", - "namespace": "library/a", - "copyright": "${copyright}" - }, - "resources": { - "configuration": { - "paths": { - "src": "src", - "test": "test" - } - }, - "pathMappings": { - "/resources/": "src", - "/test-resources/": "test" - } - } - }, - { - "id": "library.b", - "version": "1.0.0", - "path": path.join(applicationBPath, "..", "collection", "library.b"), - "dependencies": [], - "_level": 1, - "specVersion": "0.1", - "type": "library", - "metadata": { - "name": "library.b", - "namespace": "library/b", - "copyright": "${copyright}" - }, - "resources": { - "configuration": { - "paths": { - "src": "src", - "test": "test" - } - }, - "pathMappings": { - "/resources/": "src", - "/test-resources/": "test" - } - } - }, - { - "id": "library.c", - "version": "1.0.0", - "path": path.join(applicationBPath, "..", "collection", "library.c"), - "dependencies": [], - "_level": 1, - "specVersion": "0.1", - "type": "library", - "metadata": { - "name": "library.c", - "namespace": "library/c", - "copyright": "${copyright}" - }, - "resources": { - "configuration": { - "paths": { - "src": "src", - "test": "test" - } - }, - "pathMappings": { - "/resources/": "src", - "/test-resources/": "test" - } - } - } - ], - "builder": {}, + "dependencies": [], "_level": 0, "specVersion": "0.1", "type": "application", @@ -232,8 +212,7 @@ const libraryKTree = { "type": "library", "metadata": { "name": "sap.ui.core", - "namespace": "sap/ui/core", - "copyright": "Some fancy copyright" + "namespace": "sap/ui/core" }, "resources": { "configuration": { @@ -252,8 +231,7 @@ const libraryKTree = { "type": "library", "metadata": { "name": "library.k", - "namespace": "library/k", - "copyright": "UI development toolkit for HTML5 (OpenUI5)\n * (c) Copyright 2009-xxx SAP SE or an SAP affiliate company.\n * Licensed under the Apache License, Version 2.0 - see LICENSE.txt." + "namespace": "library/k" }, "resources": { "configuration": {