Skip to content

Commit

Permalink
feat(SCIRestClient): add public methods getArtifactType and isActionS…
Browse files Browse the repository at this point in the history
…upported (#16)

chore(docs): complete the docs

feat(SCIRestClient): add public method for determining the artifact type from the artifacts manifest file

feat(SCIRestClient): add public method to check whether an API action is supported for the given artifact directory
  • Loading branch information
marcelschork committed Mar 14, 2023
1 parent d8feb01 commit abc4ade
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 59 deletions.
62 changes: 47 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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: '<artifactId>',
artifactType: '<IntegrationFlow | MessageMapping | ValueMapping | ScriptCollection>',
artifactName: '<artifactName>'
artifactContent: '<base64EncodedZip>'
integrationPackageId: '<integrationPackageId>',
Id: '<artifactId>',
Type: '<IntegrationFlow | MessageMapping | ValueMapping | ScriptCollection>',
Name: '<artifactName>'
Content: '<base64EncodedZip>'
PackageId: '<integrationPackageId>',
});
```

### Update an artifact
#### Update an artifact

```js
await this.updateArtifact({
artifactId: '<artifactId>',
artifactType: '<IntegrationFlow | MessageMapping | ValueMapping | ScriptCollection>',
artifactName: '<artifactName>'
artifactContent: '<base64EncodedZip>'
Id: '<artifactId>',
Version: '<artifactVersion'>,
Type: '<IntegrationFlow | MessageMapping | ValueMapping | ScriptCollection>',
Name: '<artifactName>'
Content: '<base64EncodedZip>'
});
```

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
Expand All @@ -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('<integrationPackageId>', '<pathToArtifactDirectory>');
await SCIRestClient.updateArtifactFromDirectory('<pathToArtifactDirectory>');
```

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('<artifactId>', '<artifactVersion>', '<artifactType');
```

The method creates a new version of the artifact, but this is just a placeholder. Afterwards to content needs to uploaded via `updateArtifact(...)`. It's recommended to just call the update method directly in case you don't need any special logic for creating new versions.

#### Check if API action is supported for artifact

```js
import APIAction from 'sci-rest-client/client/APIAction';

// const isActionSupported = sciRestClient.isActionSupported(APIAction.Update, '<pathToArtifactDirectory>');
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('<pathToArtifactDirectory>');
```

# Test

Expand Down Expand Up @@ -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

Expand Down
27 changes: 27 additions & 0 deletions src/lib/client/SCIRestClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand All @@ -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 = [];
Expand Down
4 changes: 2 additions & 2 deletions src/test/Testpackage/MessageMapping/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
@@ -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
Expand Down
26 changes: 17 additions & 9 deletions src/test/integration/IntegrationFlow.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand All @@ -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();
});

Expand All @@ -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',
});
Expand All @@ -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);
});
});
30 changes: 19 additions & 11 deletions src/test/integration/MessageMapping.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand All @@ -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) => {
Expand All @@ -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,
Expand All @@ -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);
});
});
32 changes: 19 additions & 13 deletions src/test/integration/ScriptCollection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand All @@ -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) => {
Expand All @@ -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);
});
});
Loading

0 comments on commit abc4ade

Please sign in to comment.