{"id":23651852,"url":"https://github.com/microfocus/alm-octane-js-rest-sdk","last_synced_at":"2025-06-20T11:07:11.547Z","repository":{"id":18948521,"uuid":"82655394","full_name":"MicroFocus/alm-octane-js-rest-sdk","owner":"MicroFocus","description":"NodeJS wrapper for the OpenText Core Software Delivery Platform and Software Delivery Management REST API","archived":false,"fork":false,"pushed_at":"2025-05-09T12:50:44.000Z","size":521,"stargazers_count":9,"open_issues_count":0,"forks_count":12,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-06-13T14:44:55.117Z","etag":null,"topics":["csdp","opentext","sdm","sdp"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MicroFocus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-02-21T08:31:21.000Z","updated_at":"2025-05-07T11:36:19.000Z","dependencies_parsed_at":"2024-06-13T12:04:50.608Z","dependency_job_id":"7827244f-b39a-4863-be97-ba94afd9df1d","html_url":"https://github.com/MicroFocus/alm-octane-js-rest-sdk","commit_stats":{"total_commits":122,"total_committers":15,"mean_commits":8.133333333333333,"dds":0.7213114754098361,"last_synced_commit":"8418e1ade55ae4c0dfc0e54818d051eda7987486"},"previous_names":["hpsoftware/alm-octane-js-rest-sdk"],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/MicroFocus/alm-octane-js-rest-sdk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MicroFocus%2Falm-octane-js-rest-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MicroFocus%2Falm-octane-js-rest-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MicroFocus%2Falm-octane-js-rest-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MicroFocus%2Falm-octane-js-rest-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MicroFocus","download_url":"https://codeload.github.com/MicroFocus/alm-octane-js-rest-sdk/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MicroFocus%2Falm-octane-js-rest-sdk/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260933186,"owners_count":23084949,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csdp","opentext","sdm","sdp"],"created_at":"2024-12-28T16:48:39.360Z","updated_at":"2025-06-20T11:07:06.529Z","avatar_url":"https://github.com/MicroFocus.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Node-Octane\n\nA Node.js wrapper for the Open Text ALM Octane and ValueEdge REST API.\n\n## Table of contents\n1. [Installation](#installation)\n1. [Introduction](#introduction)\n1. [Octane object](#octane-object)\n    * [Import](#import)\n    * [Parameters](#octane-params)\n    * [Methods](#methods)\n        * [create](#create)\n        * [get](#get)\n        * [update](#update)\n        * [updateBulk](#updateBulk)\n        * [delete](#delete)\n        * [getAttachmentContent](#getAttachmentContent)\n        * [uploadAttachment](#uploadAttachment)\n        * [executeCustomRequest](#executeCustomRequest)\n        * [authenticate](#authenticate)\n        * [signOut](#signOut)\n    * [Octane.entityTypes](#octane-entity-types)\n    * [Octane.operationTypes](#octane-operation-types)\n1. [Usage examples](#usage-examples)\n    * [Get metadata](#get-metadata)\n    * [Get entities](#get-entities)\n    * [Delete entities](#delete-entities)\n    * [Create entities](#create-entities)\n    * [Update entities](#update-entities)\n    * [Attachments](#attachments)\n    * [Query](#query)\n1. [Tests](#tests)\n1. [What's new](#whats-new)\n1. [Disclaimer](#disclaimer)\n\n## Installation\n\nInstall via npm\n\n```bash\n$ npm i @microfocus/alm-octane-js-rest-sdk\n```\n\n## Introduction\n\nThis SDK contains two use cases: the generic one which can be used out of the box, namely the Octane object, \nand also the OctaneVanilla object which needs the default.json generated file. \n\nThe recommended way to use this SDK is to use the Octane object as the OctaneVanilla version is error-prone due\nto the fact that it needs regeneration every time the API is changed or fields are added. \n\nThe docs for the original version of the SDK can be found [here](/lib/generate-routes/README.md).\n\n## Octane object\nThe following sections expose the functionality of the generic version of the SDK. \n\n#### Import\n\n```javascript\nimport { Octane } from '@microfocus/alm-octane-js-rest-sdk';\n\n```\n\n#### Octane(params) \u003ca name=\"octane-params\"\u003e\u003c/a\u003e\n\nParams can have the following members:\n\nMandatory parameters:\n\n- ```server``` - The alm Octane server URL.\n\n- ```sharedSpace``` - The ALM Octane shared space id.\n\n- ```workspace``` - The ALM Octane workspace id. \n\n- ```user``` - Can be either an existing user's email or an existing API Access key. \n\n- ```password``` - Can be either an existing user's password or an existing API Access secret.\n\nOptional parameters:\n\n- ```proxy``` - A proxy URL. \n\n- ```headers``` - A JSON with header keys and values.\n\nExample:\n\n```javascript\nconst octane = new Octane({\n  server: 'https://myOctane:8080',\n  sharedSpace: 1001,\n  workspace: 1002,\n  user: 'myUser@user.domain',\n  password: 'Password123',\n  headers: {\n    ALM_OCTANE_TECH_PREVIEW: true\n  },\n  proxy: 'http://myProxy:8080'\n})\n```\n\n#### Methods\n\nThe method which actually fires a request is the `execute()` method. This means, only when the `execute()` method is called, the Octane data can be affected or retrieved. The other methods are used solely to set up the request. Please see the [examples](#usage-examples) for a better understanding.\n\nBesides `execute()`, the `signOut()` can be used to send a sign out request to Octane. \n\nThe rest of the methods will not affect directly the Octane data, but add properties to the final URL which will be used for the actual request. Moreover, some of the methods can be chained.\n\n- ```create(entityName, body)``` \u003ca name=\"create\"\u003e\u003c/a\u003e\n    \n    *Parameters* : \n    - **entityName** - Contains the name of the affected Octane entity. The recommended way to use the entity names is to use the [Octane.entityTypes](#octane-entity-types) entries. \n    - **body** - A JSON containing *field name* and *field value* pairs which will be used to crate the entity. Field names can be obtained by querying the field metadata of Octane. More information about the Octane field metadata can be found [here](https://admhelp.microfocus.com/octane/en/15.0.20/Online/Content/API/MetadataFields.htm). Examples on how to retrieve metadata using the SDK can be found [here](#get-metadata).\n        \n    *Behavior*:\n    \n    This method does not fire the request but builds up to the final URL and defines the request method.\n    \n    The method will set the next request to take action on the entity type defined by *entityName*. When the request will be executed, the created entities will have the type provided by *entityName* and the attributes defined in the *body* JSON.\n    \n    *Methods which can be chained*:\n    \n    The only chaining allowed is with the `execute()` method, resulting in firing a request to Octane and thus creating the entity defined in the *body* JSON.\n    \n         \n- ```get(entityName)``` \u003ca name=\"get\"\u003e\u003c/a\u003e\n\n    *Parameters* : \n    - **entityName** - Contains the name of the Octane entity which will be fetched. The recommended way to use the entity names is to use the [Octane.entityTypes](#octane-entity-types) entries. \n    \n    *Behavior*\n   \n   This method does not fire the request but builds up to the final request URL and defines the request method. When the get request will be executed, the returned entities will have the type provided by entityName.\n   \n   *Methods which can be chained*\n   - `execute()` - Will fire the request to create all the defined entities.\n   - `at(id)` - Defines which entity will be targeted for the next request. The input for this method is the id of the targeted entity.\n   - `fields(fields)` - The fields parameter represents an array with names of fields relevant for the entity which will be affected by the request. When the request will be fired, the entities affected will contain the listed fields. Please inspect the field metadata before passing field names to this method.\n   - `orderBy(fields)` - The fields parameter represent an array with names of fields which is relevant for the order in which the entities will be processed. Adding a '-' at the beginning of any field name will fetch the entities in a descending order (ex: [id, '-name']). Please inspect the field metadata before passing field names to this method.\n   - `query(query)` - Defines an Octane-specific filter. When the request will be executed, only the entities filtered by the query will be gathered.\n   - `limit(limit)` - When a query returns a large set of data, the results are returned in a series of pages. There is a default limit set for the entities fetched in a page. However, the user can set a custom limit by providing an integer greater that 0.\n   - `offset(offset)` - When a query returns a large set of data, the results are returned in a series of pages. There is a default limit set for the entities fetched in a page. Based on that limit, multiple pages are formed. To select the desired range of entities, the offset must be provided as a number which sets the index of the entity which will be fetched first. If the offset is not provided, 0 is used instead.\n    \n- ```update(entityName, body)``` \u003ca name=\"update\"\u003e\u003c/a\u003e\n     \n    *Parameters* : \n    - **entityName** - Contains the name of the affected Octane entity. The recommended way to use the entity names is to use the [Octane.entityTypes](#octane-entity-types) entries. \n    - **body** - A JSON containing *field name* and *field value* pairs which will be used to update the entity. Field names can be obtained by querying the field metadata of Octane. More information about the Octane field metadata can be found [here](https://admhelp.microfocus.com/octane/en/15.0.20/Online/Content/API/MetadataFields.htm). Examples on how to retrieve metadata using the SDK can be found [here](#get-metadata).\n        \n    *Behavior*:\n    \n    This method does not fire the request but builds up to the final URL and defines the request method. When the request will be executed, the updated entity will have the type provided by entityName and the attributes defined in the body JSON.\n    \u003e This method affects a single entity. To target an entity for update the id must be provided and this can be done in the following two ways:\n    \u003e - provide the id in the body JSON\n    \u003e - provide the at(id) method, available in this class, with the desired id. The at(id) method can be chained to update method.\n    \n    *Methods which can be chained*\n     - `execute()` - Will fire the request to update the entity for the built query.\n     - `at(id)` - Defines which entity will be targeted for the next request. The input for this method is the id of the targeted entity. If this is chained to the `update` method, the id field in the body of the JSON is not mandatory.\n    \n- ```updateBulk(entityName, body)``` \u003ca name=\"updateBulk\"\u003e\u003c/a\u003e\n     \n    *Parameters* : \n     - **entityName** - Contains the name of the affected Octane entity. The recommended way to use the entity names is to use the [Octane.entityTypes](#octane-entity-types) entries. \n     - **body** - A JSON containing *field name* and *field value* pairs which will be used to update the entity. Field names can be obtained by querying the field metadata of Octane. More information about the Octane field metadata can be found [here](https://admhelp.microfocus.com/octane/en/15.0.20/Online/Content/API/MetadataFields.htm). Examples on how to retrieve metadata using the SDK can be found [here](#get-metadata).\n    \n    *Behavior*:\n    \n    This method does not fire the request but builds up to the final URL and defines the request method. When the request will be executed, the updated entities will have the type provided by entityName and the attributes defined in the body JSON. Every entity in the body JSON must have an existing id to target existing entities in Octane. This method affects multiple entities.\n    \n    *Methods which can be chained*\n    - `execute()` - Will fire the request to update all the entities for the built query.\n    - `query(query)` - Defines an Octane-specific filter. When the request will be executed, only the entities filtered by the query will be affected. In this case the body of the request does not have to contain ids for the entities.\n     \n- ```delete(entityName)``` \u003ca name=\"delete\"\u003e\u003c/a\u003e\n    \n    *Parameters* : \n    - **entityName** - Contains the name of the Octane entity which will be fetched. The recommended way to use the entity names is to use the [Octane.entityTypes](#octane-entity-types) entries. \n        \n    *Behavior*\n       \n    This method does not fire the request but builds up to the final request URL and defines the request method. When the delete request will be executed, all the selected entities will be deleted.\n    \u003e This method must be chained with `query()` or `at()`, which are described below.\n    \n   *Methods which can be chained*\n   - `execute()` - Will fire the request to delete all the entities which were selected using a query or an id.\n   - `at(id)` - Defines which entity will be targeted for the next request. The input for this method is the id of the targeted entity.\n   - `query(query)` - Defines an Octane-specific filter. When the request will be executed, only the entities filtered by the query will be deleted.\n\n- ```getAttachmentContent()``` \u003ca name=\"getAttachmentContent\"\u003e\u003c/a\u003e\n    \n    *Behavior*\n    \n    This method does not fire the request but builds up to the final request URL and defines the request method. When the get request will be executed it will return the attachment content. Information about requests which involve attachments can be found [here](https://admhelp.microfocus.com/octane/en/15.0.20/Online/Content/API/Attachments_HowTo.htm)\n    \n    \u003e This method must be chained with `at()` to fetch the correct data.  \n                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         \n    *Methods which can be chained*\n     - `execute()` - Will fire the request to get the content of the attachment which was selected using an id.\n     - `at(id)` - Defines which entity will be targeted for the next request. The input for this method is the id of the targeted entity.\n\n- ```uploadAttachment(attachmentName, attachmentData, ownerName, ownerReference)``` \u003ca name=\"uploadAttachment\"\u003e\u003c/a\u003e\n    \n    *Parameters*\n    - **attachmentName** - The name which will be used for attachment creation.\n    - **attachmentData** - The content of the attachment which will be uploaded later.\n    - **ownerName** - The name of the entity where the attachment will be uploaded, like \"owner_release\". The possible owner fields can be found in the field metadata of attachments.\n     - **ownerReference** - The reference of the entity where the attachment will be uploaded. This can be an id of entity, or a JSON with the type and id of the entity.\n    \n    *Behavior*\n    \n    This method does not fire the request but builds up to the final URL and defines the request method.\n    \n    When the request will be executed, the created attachment will have the name provided by attachmentName, the content defined by attachmentData and it will be under the entity provided by ownerName and ownerReference.  Information about requests which involve attachments can be found [here](https://admhelp.microfocus.com/octane/en/15.0.20/Online/Content/API/Attachments_HowTo.htm)\n       \n    *Methods which can be chained*\n     - `execute()` - Will fire the request to create the attachment defined by attachmentData and it will be under the entity provided by ownerName and ownerReference.\n\n- ```executeCustomRequest (customUrl, operation, body, headers)``` \u003ca name=\"executeCustomRequest\"\u003e\u003c/a\u003e\n\n  *Parameters*\n    - **customUrl** - The url to which the request will be sent to. The URL should exclude the server and point to the desired resource.\n    - **operation** - The type of operation that will be executed by the requester. The recommended way to use the entity names is to use the [Octane.operationTypes](#octane-operation-types) entries.\n    - **body** - The body of the custom request. This is an optional parameter and it will default to undefined.\n    - **headers** - Custom headers object. This must be a JSON where the key: value pairs represent the headers. This is an optional parameter and it will default to undefined.\n  \n  *Behavior*\n\n  This method fires the request and **does not** need any additional call to `execute()`.\n  If the request executes successfully it returns the body of the response.\n\n- ```authenticate()``` \u003ca name=\"authenticate\"\u003e\u003c/a\u003e\n\n  *Behavior*\n\n  Fires an authenticate request to Octane. After this request is fulfilled any further operation wll not require to reauthenticate.\n\n- ```signOut()``` \u003ca name=\"signOut\"\u003e\u003c/a\u003e\n\n     *Behavior*\n     \n     Fires a sign out request to Octane. After this request is fulfilled any further operation wll need to reauthenticate.\n\n#### Octane.entityTypes \u003ca name=\"octane-entity-types\"\u003e\u003c/a\u003e\n\nThe Octane.entityTypes JSON contains all the entities present in the public API of ALM Octane. This can be used in order\nto access Octane entities.\n\n#### Octane.operationTypes \u003ca name=\"octane-operation-types\"\u003e\u003c/a\u003e\n\nThe Octane.operationTypes JSON contains all the operations that can be executed via the public API of ALM Octane. This can be used in order\nto generate custom requests.\n\n## Usage examples\n\n#### Get metadata\n\n```javascript\n  const octane = new Octane(...)\n  \n  //get all entities metadata\n  const entitiesMetadata = await octane.get(Octane.entityTypes.entitiesMetadata).execute()\n\n  //get all fields metadata\n  const fieldsMetadata = await octane.get(Octane.entityTypes.fieldsMetadata).execute()\n\n  //get all user defined fields\n  const udfMetadata = await octane.get(octane.entityTypes.fieldsMetadata).query(Query.field('is_user_defined').equal(true).build()).execute()\n```\n\n#### Get entities\n```javascript\n  const octane = new Octane(...)\n\n  // get all defects\n  const allDefects = await octane.get(Octane.entityTypes.defects).execute()\n\n  // get defect with id 1001\n  const defect = await octane.get(Octane.entityTypes.defects).at(1001).execute()\n\n  // get defects ordered by name and containing the owner field\n  const richDefect = await octane.get(Octane.entityTypes.defects).fields('name', 'owner').order_by('name').execute()\n\n  // get defects with with ids in the 1001-1050 range\n  const queryDefect = await octane.get(Octane.entityTypes.defects).query(Query.field('id').between(1001, 1050).build()).execute()\n  \n  // get the script of the test with id 1001\n  const testScript = await octane.get(Octane.entityTypes.tests).at(1001).script().execute()\n```\n\n#### Delete entities\n\n```javascript\n  //delete defect with id 1001\n  await octane.delete(Octane.entityTypes.defects).at(1001).execute()\n\n  //delete defects with their name equal to 'new defect'\n  await octane.delete(Ocane.entityTypes.defects).query(Query.field('name').equal('new defect').build()).execute()\n```\n\n#### Create entities\n\n```javascript\n  // create the defect JSON which will be passed for defect creation\n  let defect ={\n    name: 'new defect',\n    description: 'some description here',\n    owner : {\n      type: 'workspace_user',\n      id: '1001'\n    }\n  }\n\n  // send the create request\n  octane.create(Octane.entityTypes.defects, defect).execute()\n```\n\n#### Update entities\n\n```javascript\n  // get the defect which needs to be modified\n  let defect = await octane.get(Octane.entityTypes.defects).at(1001).fields('name', 'description').execute()\n\n  // change some fields\n  defect.name = 'newName'\n  defect.description = 'newDescription'\n\n  // send an update request\n  octane.update(Octane.entityTypes.defects, defect).execute()\n```\n\n#### Attachments\n\n```javascript\n    // get the content of the attachment with id 1001\n    let attachmentContent = await octane.getAttachmentContent(Octane.entityTypes.attachments).at(1001).execute()\n\n    // an attachment will be uploaded for defect with id 1001\n    let attachment = await octane.uploadAttachment('newAttachment.txt', 'This will be the content of the txt file', 'owner_work_item', 1001).execute()\n\n```\n\n#### Custom Requests\n\n```javascript\n    let url = '/api/shared_spaces/1001/users'\n    //get the users from the shared space with id 1001 using the tech preview header\n    let users = await octane.executeCustomRequest(url, Octane.operationTypes.get, undefined, { 'ALM-OCTANE-TECH-PREVIEW': true })\n    //create user in octane\n    let user = await octane.executeCustomRequest(url, Octane.operationTypes.create, { email: 'example@example.com', password: 'examplePassword' })\n```\n\n#### Query\n\nThe Octane REST API supports entities querying by filtering based on field values. To filter, use a query statement, which is \ncomprised of at least one query phrase.\n\nThe client API provides the Query module to help you build the query, rather than writing the complex query statement. To pass\nthese queries to the SDK, use the `build()` method after the query is fully built.\n\n```javascript\nimport { Query } from '@microfocus/alm-octane-js-rest-sdk'\n\n// query statement: \"id EQ 1005\"\nconst query = Query.field('id').equal(1005)\n// get defects with with ids in the 1001-1050 range\n// the build() method is used when passing the query, as mentioned above\nconst queryDefect = await octane.get(Octane.entityTypes.defects).query(Query.field('id').between(1001, 1050).build()).execute()\n\n// query statement: \"name EQ ^test*^\"\nconst query = Query.field('name').equal('test*')\n\n// query statement: \"user_tags EQ {id EQ 1001}\"\nconst query = Query.field('user_tags').equal(Query('id').equal(1001))\n\n// query statement: \"user_tags EQ {id EQ 1001||id EQ 2005}\"\nconst query = Query.field('user_tags').equal(Query.field('id').equal(1001).or(Query.field('id').equal(2005)))\n// or use the shorthand or() method\nconst query = Query.field('user_tags').equal(Query.field('id').equal(1001).or().field('id').equal(2005))\n\n// query statement: \"user_tags EQ {id EQ 1001;id EQ 3008}\"\nconst query = Query.field('user_tags').equal(Query.field('id').equal(1001).and(Query.field('id').equal(3008)))\n// or use the shorthand and() method\nconst query = Query.field('user_tags').equal(Query.field('id').equal(1001).and().field('id').equal(3008))\n\n// query statement: \"user_tags EQ {id EQ 1001};user_tags EQ {id EQ 3008}\"\nconst query = Query.field('user_tags').equal(Query.field('id').equal(1001)).and(Query.field('user_tags').equal(Query.field('id').equal(3008)))\n// or use the shorthand and() method\nconst query = Query.field('user_tags').equal(Query.field('id').equal(1001)).and().field('user_tags').equal(Query.field('id').equal(3008))\n// or use the sub query\nconst query1 = Query.field('user_tags').equal(Query.field('id').equal(1001))\nconst query2 = Query.field('user_tags').equal(Query.field('id').equal(3008))\n\n// query statement \"id BTW 1..3\" - notice that there are two parameters\nconst query = Query.field('id').between(1,2)\n\n// query statement \"id IN 1,2,3\" - the parameter has to be an array\nconst query = Query.field('id').inComparison([1,2,3])\n\nconst query = query1.and(query2)\n\n// for null use either Query.NULL for non-reference fields or Query.NULL_REFERENCE for references (Query.NONE still exists for backwards-compatibility\n// and is the same as Query.NULL_REFERENCE)\nconst query1 = Query.field('string_field').equal(Query.NULL)\nconst query2 = Query.field('reference_field').equal(Query.NULL_REFERENCE)\n```\n\n## Tests\nRun all tests\n\n```bash\n$ npm test\n```\n\nOr run a specific test\n\n```bash\n$ npm test test/query.js\n```\n\n## What's new :newspaper: \u003ca name=\"whats-new\"\u003e\u003c/a\u003e\n* 24.2.1\n  * Added support for providing custom cookie header\n\n* 24.2.0\n  * HTTP Proxy support\n  * Added ability to use proxy with credentials\n\n* 23.3.1\n    * Rebranding\n\n* 23.3.0\n    * Query parameter is now encoded \n\n* 16.1.100-3\n    * Hotfix for allowing strings as custom request bodies\n\n* 16.1.100-2\n    * Hotfix for Query class usage in JS\n\n* 16.1.100 \n    * Added autocomplete feature\n\n* 16.0.400\n    * Changed HTTP library from `request-promise-native` to `axios`\n    * Added `authenticate()` method to `Octane` class\n    * Added `executeCustomRequest()` method to `Octane` class which allows user to send requests to custom URLs\n\n* 15.0.20\n    * A generic way to interact with the ALM Octane API has been implemented as `Octane` class\n    * The OctaneVanilla code has moved from ES5 to ES6\n    * Old functionality is implemented in the `OctaneVanilla` class\n    * The documentation for `OctaneVanilla` functionality can be found [here](/lib/generate-routes/README.md)\n\n## Disclaimer\nCertain versions of software accessible here may contain branding from Hewlett-Packard Company (now HP Inc.) and \nHewlett Packard Enterprise Company.  As of September 1, 2017, the software is now offered by Micro Focus, a separately \nowned and operated company. Any reference to the HP and Hewlett Packard Enterprise/HPE marks is historical in nature, \nand the HP and Hewlett Packard Enterprise/HPE marks are the property of their respective owners.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmicrofocus%2Falm-octane-js-rest-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmicrofocus%2Falm-octane-js-rest-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmicrofocus%2Falm-octane-js-rest-sdk/lists"}