diff --git a/README.md b/README.md index 98a9149..53fe10e 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,6 @@ This package simplifies the access to the [Integration Content API for SAP Cloud Integration](https://api.sap.com/api/IntegrationContent/overview). It hides all the technical implementation details like - url construction -- session management - csrf token handling - zipping and encoding of artifact content @@ -60,29 +59,32 @@ const integrationPackage = await SCIRestClient.getIntegrationPackage('packageId' await sciRestClient.deleteIntegrationPackage('packageId'); ``` -### Create an artifact +#### Create an artifact ```js const artifact = await this.createArtifact({ - artifactId: '', - artifactType: '', - artifactName: '' - artifactContent: '' - integrationPackageId: '', + Id: '', + Type: '', + Name: '' + Content: '' + PackageId: '', }); ``` -### Update an artifact +#### Update an artifact ```js await this.updateArtifact({ - artifactId: '', - artifactType: '', - artifactName: '' - artifactContent: '' + Id: '', + Version: ', + Type: '', + Name: '' + Content: '' }); ``` +This method is a little special. If the update fails due to a version that doesn't exist, a new version is created under the hood and the update is triggered again automatically. + #### Create an artifact from an artifact directory ```js @@ -94,10 +96,40 @@ The method reads and extracts the required information (id, version, name and ar #### Update an artifact from an artifact directory ```js -await SCIRestClient.updateArtifactFromDirectory('', ''); +await SCIRestClient.updateArtifactFromDirectory(''); ``` -Again the methods reads and extracts the necessary infos from the metadata file mentioned above. But the method is a little special. Once the update fails due to the version read from the metadata doesn't exist, a new version is created under the hood and the update is triggered again automatically. +Again the method reads and extracts the necessary infos from the metadata file mentioned above. +`updateArtifact(...)` is used under the hood, so new versions will be created automatically if necessary. + +#### Create new artifact version + +```js +await this.createNewArtifactVersion('', '', ''); +const isActionSupported = sciRestClient.isActionSupportedForArtifactType(APIAction.Update, 'IntegrationFlow'); + +if(isActionSupported) { + ... +} +``` + +The available APIActions are: `Create`, `Read`, `Update`, `Delete` and `New_Version`. + +#### Get artifact type + +```js +const artifactType = sciRestClient.getArtifactType(''); +``` # Test @@ -133,7 +165,7 @@ Both commands will listen to file changes and execute the corresponding tests ag We welcome any type of contribution (code contributions, pull requests, issues) to this project equally. -ESLint is used to ensure code quality. A Git commit hook will fix lint findings automatically (if possible) and prevent commits with linting errors. Prettier is used for formatting. Staged changes will be formatted automatically before commiting. +ESLint and SonarQube are used to ensure code quality. A Git commit hook will fix lint findings automatically (if possible) and prevent commits with linting errors. Prettier is used for formatting. Staged changes will be formatted automatically before committing. # Release management diff --git a/src/lib/client/SCIRestClient.ts b/src/lib/client/SCIRestClient.ts index d23c620..f12e914 100644 --- a/src/lib/client/SCIRestClient.ts +++ b/src/lib/client/SCIRestClient.ts @@ -323,6 +323,21 @@ export default class SCIRestClient { }); } + /** + * Returns true if the given action is supported + * + * @param {Action} action - The action to check. + * @param {string} artifactDirectoryPath - Path to the directory containing the artifact. + * + * @returns {boolean} - True if the action is supported. + */ + public isActionSupported(action: Action, artifactDirectoryPath: string) { + const artifactType = this.getArtifactType(artifactDirectoryPath); + const artifactAPIMetadata = ArtifactAPIMetadata[artifactType] as ArtifactMetadata; + + return artifactAPIMetadata.supportedActions.includes(action); + } + /** * Returns true if the given action is supported for the given artifact type. * @@ -337,6 +352,18 @@ export default class SCIRestClient { return artifactAPIMetadata.supportedActions.includes(action); } + /** + * Returns the type of the artifact in the given directory. + * + * @param {string} artifactDirectoryPath - Path to the directory containing the artifact. + * + * @returns {ArtifactType} - The type of the artifact. + */ + public getArtifactType(artifactDirectoryPath: string) { + const manifestReader = new ManifestReader(artifactDirectoryPath); + return manifestReader.getArtifactMetadata().Type; + } + private invalidateCSRFToken() { this.csrfToken = ''; this.cookie = []; diff --git a/src/test/Testpackage/MessageMapping/META-INF/MANIFEST.MF b/src/test/Testpackage/MessageMapping/META-INF/MANIFEST.MF index c16ff8d..5c2323c 100644 --- a/src/test/Testpackage/MessageMapping/META-INF/MANIFEST.MF +++ b/src/test/Testpackage/MessageMapping/META-INF/MANIFEST.MF @@ -1,7 +1,7 @@ Manifest-Version: 1.0 Provide-Capability: messagemapping.mapping;version:Version="1.0.0" -Bundle-SymbolicName: mapping -Bundle-Name: mapping +Bundle-SymbolicName: MessageMapping +Bundle-Name: MessageMapping Bundle-Version: 1.0.0 Bundle-ManifestVersion: 2 SAP-NodeType: IFLMAP diff --git a/src/test/integration/IntegrationFlow.test.ts b/src/test/integration/IntegrationFlow.test.ts index 0a9ab45..a78c650 100644 --- a/src/test/integration/IntegrationFlow.test.ts +++ b/src/test/integration/IntegrationFlow.test.ts @@ -5,16 +5,19 @@ import { v4 as uuidv4 } from 'uuid'; import fs, { ReadStream } from 'fs'; import replace from 'replace-in-file'; import { setup, teardown } from '../setupAndTeardown.js'; +import APIAction from '../../lib/client/APIAction.js'; let sciRestClient: SCIRestClient; let artiFactDirectory: string; let randomPackageId = uuidv4().replaceAll('-', ''); +let iFlowDirectory: string; beforeAll(async () => { const setupResult = await setup(); sciRestClient = setupResult.sciRestClient; artiFactDirectory = setupResult.artiFactDirectory; randomPackageId = setupResult.randomPackageId; + iFlowDirectory = path.join(artiFactDirectory, 'Testpackage', 'IntegrationFlow'); }); afterAll(async () => { @@ -23,10 +26,7 @@ afterAll(async () => { describe('Integration flow', () => { it('create an integration flow', async () => { - const integrationFlow = await sciRestClient.createArtifactFromDirectory( - randomPackageId, - path.join(artiFactDirectory, 'Testpackage', 'IntegrationFlow') - ); + const integrationFlow = await sciRestClient.createArtifactFromDirectory(randomPackageId, iFlowDirectory); expect(integrationFlow).toBeDefined(); }); @@ -44,16 +44,13 @@ describe('Integration flow', () => { }); it('update an integration flow', async () => { - const integrationFlow = await sciRestClient.updateArtifactFromDirectory( - path.join(artiFactDirectory, 'Testpackage', 'IntegrationFlow') - ); + const integrationFlow = await sciRestClient.updateArtifactFromDirectory(iFlowDirectory); expect(integrationFlow).toBe(undefined); }); it('upload a new version of an integration flow', async () => { - const integrationFlowDirectory = path.join(artiFactDirectory, 'Testpackage', 'IntegrationFlow'); await replace({ - files: path.join(integrationFlowDirectory, 'META-INF', 'MANIFEST.MF'), + files: path.join(iFlowDirectory, 'META-INF', 'MANIFEST.MF'), from: /1.0.0/g, to: '2.0.0', }); @@ -62,4 +59,15 @@ describe('Integration flow', () => { ); expect(integrationFlow).toBe(undefined); }); + + it('determine the artifact type', () => { + expect(sciRestClient.getArtifactType(iFlowDirectory)).toBe('IntegrationFlow'); + }); + + it('check the supported API actions', () => { + expect(sciRestClient.isActionSupported(APIAction.Create, iFlowDirectory)).toBe(true); + expect(sciRestClient.isActionSupported(APIAction.Update, iFlowDirectory)).toBe(true); + expect(sciRestClient.isActionSupported(APIAction.New_Version, iFlowDirectory)).toBe(true); + expect(sciRestClient.isActionSupported(APIAction.Delete, iFlowDirectory)).toBe(false); + }); }); diff --git a/src/test/integration/MessageMapping.test.ts b/src/test/integration/MessageMapping.test.ts index ada58f7..15873b2 100644 --- a/src/test/integration/MessageMapping.test.ts +++ b/src/test/integration/MessageMapping.test.ts @@ -5,16 +5,19 @@ import { v4 as uuidv4 } from 'uuid'; import fs, { ReadStream } from 'fs'; import replace from 'replace-in-file'; import { setup, teardown } from '../setupAndTeardown.js'; +import APIAction from '../../lib/client/APIAction.js'; let sciRestClient: SCIRestClient; let artiFactDirectory: string; let randomPackageId = uuidv4().replaceAll('-', ''); +let messageMappingDirectory: string; beforeAll(async () => { const setupResult = await setup(); sciRestClient = setupResult.sciRestClient; artiFactDirectory = setupResult.artiFactDirectory; randomPackageId = setupResult.randomPackageId; + messageMappingDirectory = path.join(artiFactDirectory, 'Testpackage', 'MessageMapping'); }); afterAll(async () => { @@ -23,22 +26,17 @@ afterAll(async () => { describe('Message mapping', () => { it('create a message mapping', async () => { - const integrationFlow = await sciRestClient.createArtifactFromDirectory( - randomPackageId, - path.join(artiFactDirectory, 'Testpackage', 'MessageMapping') - ); - expect(integrationFlow).toBeDefined(); + const messageMapping = await sciRestClient.createArtifactFromDirectory(randomPackageId, messageMappingDirectory); + expect(messageMapping).toBeDefined(); }); it('update the message mapping...', async () => { - const messageMapping = await sciRestClient.updateArtifactFromDirectory( - path.join(artiFactDirectory, 'Testpackage', 'MessageMapping') - ); + const messageMapping = await sciRestClient.updateArtifactFromDirectory(messageMappingDirectory); expect(messageMapping).toBe(undefined); }); - it.skip('fetch a message mapping', async () => { - const readStream = (await sciRestClient.getArtifact('IntegrationFlow', '1.0.0', 'IntegrationFlow')) as ReadStream; + it('fetch a message mapping', async () => { + const readStream = (await sciRestClient.getArtifact('MessageMapping', '1.0.0', 'MessageMapping')) as ReadStream; const writer = fs.createWriteStream(path.join(artiFactDirectory, 'test.zip')); const finishPromise = new Promise((resolve, reject) => { @@ -51,7 +49,6 @@ describe('Message mapping', () => { }); it('upload a new version of the message mapping', async () => { - const messageMappingDirectory = path.join(artiFactDirectory, 'Testpackage', 'MessageMapping'); await replace({ files: path.join(messageMappingDirectory, 'META-INF', 'MANIFEST.MF'), from: /1.0.0/g, @@ -62,4 +59,15 @@ describe('Message mapping', () => { ); expect(messageMapping).toBe(undefined); }); + + it('determine the artifact type', () => { + expect(sciRestClient.getArtifactType(messageMappingDirectory)).toBe('MessageMapping'); + }); + + it('check the supported API actions', () => { + expect(sciRestClient.isActionSupported(APIAction.Create, messageMappingDirectory)).toBe(true); + expect(sciRestClient.isActionSupported(APIAction.Update, messageMappingDirectory)).toBe(true); + expect(sciRestClient.isActionSupported(APIAction.New_Version, messageMappingDirectory)).toBe(true); + expect(sciRestClient.isActionSupported(APIAction.Delete, messageMappingDirectory)).toBe(false); + }); }); diff --git a/src/test/integration/ScriptCollection.test.ts b/src/test/integration/ScriptCollection.test.ts index 9c71f42..b8c1a51 100644 --- a/src/test/integration/ScriptCollection.test.ts +++ b/src/test/integration/ScriptCollection.test.ts @@ -5,16 +5,19 @@ import { v4 as uuidv4 } from 'uuid'; import fs, { ReadStream } from 'fs'; import replace from 'replace-in-file'; import { setup, teardown } from '../setupAndTeardown.js'; +import APIAction from '../../lib/client/APIAction.js'; let sciRestClient: SCIRestClient; let artiFactDirectory: string; let randomPackageId = uuidv4().replaceAll('-', ''); +let scriptCollectionDirectory: string; beforeAll(async () => { const setupResult = await setup(); sciRestClient = setupResult.sciRestClient; artiFactDirectory = setupResult.artiFactDirectory; randomPackageId = setupResult.randomPackageId; + scriptCollectionDirectory = path.join(artiFactDirectory, 'Testpackage', 'ScriptCollection'); }); afterAll(async () => { @@ -23,22 +26,17 @@ afterAll(async () => { describe('Script collection', () => { it('create a script collection', async () => { - const integrationFlow = await sciRestClient.createArtifactFromDirectory( - randomPackageId, - path.join(artiFactDirectory, 'Testpackage', 'ScriptCollection') - ); + const integrationFlow = await sciRestClient.createArtifactFromDirectory(randomPackageId, scriptCollectionDirectory); expect(integrationFlow).toBeDefined(); }); it('update the script collection', async () => { - const ScriptCollection = await sciRestClient.updateArtifactFromDirectory( - path.join(artiFactDirectory, 'Testpackage', 'ScriptCollection') - ); + const ScriptCollection = await sciRestClient.updateArtifactFromDirectory(scriptCollectionDirectory); expect(ScriptCollection).toBe(undefined); }); - it.skip('fetch a script collection', async () => { - const readStream = (await sciRestClient.getArtifact('IntegrationFlow', '1.0.0', 'IntegrationFlow')) as ReadStream; + it('fetch a script collection', async () => { + const readStream = (await sciRestClient.getArtifact('ScriptCollection', '1.0.0', 'ScriptCollection')) as ReadStream; const writer = fs.createWriteStream(path.join(artiFactDirectory, 'test.zip')); const finishPromise = new Promise((resolve, reject) => { @@ -51,15 +49,23 @@ describe('Script collection', () => { }); it('upload a new version of the script collection', async () => { - const scriptCollectionDirectory = path.join(artiFactDirectory, 'Testpackage', 'ScriptCollection'); await replace({ files: path.join(scriptCollectionDirectory, 'META-INF', 'MANIFEST.MF'), from: /1.0.0/g, to: '2.0.0', }); - const scriptCollection = await sciRestClient.updateArtifactFromDirectory( - path.join(artiFactDirectory, 'Testpackage', 'ScriptCollection') - ); + const scriptCollection = await sciRestClient.updateArtifactFromDirectory(scriptCollectionDirectory); expect(scriptCollection).toBe(undefined); }); + + it('determine the artifact type', () => { + expect(sciRestClient.getArtifactType(scriptCollectionDirectory)).toBe('ScriptCollection'); + }); + + it('check the supported API actions', () => { + expect(sciRestClient.isActionSupported(APIAction.Create, scriptCollectionDirectory)).toBe(true); + expect(sciRestClient.isActionSupported(APIAction.Update, scriptCollectionDirectory)).toBe(true); + expect(sciRestClient.isActionSupported(APIAction.New_Version, scriptCollectionDirectory)).toBe(true); + expect(sciRestClient.isActionSupported(APIAction.Delete, scriptCollectionDirectory)).toBe(false); + }); }); diff --git a/src/test/integration/ValueMapping.test.ts b/src/test/integration/ValueMapping.test.ts index 3feaaba..1a00b83 100644 --- a/src/test/integration/ValueMapping.test.ts +++ b/src/test/integration/ValueMapping.test.ts @@ -5,16 +5,19 @@ import { v4 as uuidv4 } from 'uuid'; import fs, { ReadStream } from 'fs'; import replace from 'replace-in-file'; import { setup, teardown } from '../setupAndTeardown.js'; +import APIAction from '../../lib/client/APIAction.js'; let sciRestClient: SCIRestClient; let artiFactDirectory: string; let randomPackageId = uuidv4().replaceAll('-', ''); +let valueMappingDirectory: string; beforeAll(async () => { const setupResult = await setup(); sciRestClient = setupResult.sciRestClient; artiFactDirectory = setupResult.artiFactDirectory; randomPackageId = setupResult.randomPackageId; + valueMappingDirectory = path.join(artiFactDirectory, 'Testpackage', 'ValueMapping'); }); afterAll(async () => { @@ -23,20 +26,17 @@ afterAll(async () => { describe('Value mapping', () => { it('create a value mapping', async () => { - const valueMapping = await sciRestClient.createArtifactFromDirectory( - randomPackageId, - path.join(artiFactDirectory, 'Testpackage', 'ValueMapping') - ); + const valueMapping = await sciRestClient.createArtifactFromDirectory(randomPackageId, valueMappingDirectory); expect(valueMapping).toBeDefined(); }); it.skip('update the value mapping', async () => { - const valueMapping = await sciRestClient.updateArtifactFromDirectory(path.join(artiFactDirectory, 'Testpackage', 'ValueMapping')); + const valueMapping = await sciRestClient.updateArtifactFromDirectory(valueMappingDirectory); expect(valueMapping).toBe(undefined); }); - it.skip('fetch a value mapping', async () => { - const readStream = (await sciRestClient.getArtifact('IntegrationFlow', '1.0.0', 'IntegrationFlow')) as ReadStream; + it('fetch a value mapping', async () => { + const readStream = (await sciRestClient.getArtifact('ValueMapping', '1.0.0', 'ValueMapping')) as ReadStream; const writer = fs.createWriteStream(path.join(artiFactDirectory, 'test.zip')); const finishPromise = new Promise((resolve, reject) => { @@ -49,13 +49,23 @@ describe('Value mapping', () => { }); it.skip('upload a new version of the value mapping', async () => { - const valueMappingDirectory = path.join(artiFactDirectory, 'Testpackage', 'ValueMapping'); await replace({ files: path.join(valueMappingDirectory, 'META-INF', 'MANIFEST.MF'), from: /1.0.0/g, to: '2.0.0', }); - const valueMapping = await sciRestClient.updateArtifactFromDirectory(path.join(artiFactDirectory, 'Testpackage', 'ValueMapping')); + const valueMapping = await sciRestClient.updateArtifactFromDirectory(valueMappingDirectory); expect(valueMapping).toBe(undefined); }); + + it('determine the artifact type', () => { + expect(sciRestClient.getArtifactType(valueMappingDirectory)).toBe('ValueMapping'); + }); + + it('check the supported API actions', () => { + expect(sciRestClient.isActionSupported(APIAction.Create, valueMappingDirectory)).toBe(true); + expect(sciRestClient.isActionSupported(APIAction.Update, valueMappingDirectory)).toBe(false); + expect(sciRestClient.isActionSupported(APIAction.New_Version, valueMappingDirectory)).toBe(true); + expect(sciRestClient.isActionSupported(APIAction.Delete, valueMappingDirectory)).toBe(false); + }); });