Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 16 additions & 16 deletions .github/ISSUE_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<!--- STOP! Before you open an issue please search this repository's issues to see if it has already been reported. This helps reduce duplicate issues from being created. -->
<!--- SECURITY DISCLOSURE: If this is a security disclosure please follow the guidelines in CONTRIBUTING.md. This helps keep folks from accidentally releasing vulnerabilities before the maintainers get a chance to fix the issue. -->
### Expected Behaviour
### Actual Behaviour
### Reproduce Scenario (including but not limited to)
#### Steps to Reproduce
#### Platform and Version
#### Sample Code that illustrates the problem
#### Logs taken while reproducing problem
<!--- STOP! Before you open an issue please search this repository's issues to see if it has already been reported. This helps reduce duplicate issues from being created. -->
<!--- SECURITY DISCLOSURE: If this is a security disclosure please follow the guidelines in CONTRIBUTING.md. This helps keep folks from accidentally releasing vulnerabilities before the maintainers get a chance to fix the issue. -->

### Expected Behaviour

### Actual Behaviour

### Reproduce Scenario (including but not limited to)

#### Steps to Reproduce

#### Platform and Version

#### Sample Code that illustrates the problem

#### Logs taken while reproducing problem
90 changes: 45 additions & 45 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,45 +1,45 @@
<!--- Provide a general summary of your changes in the Title above -->
## Description
<!--- Describe your changes in detail -->
## Related Issue
<!--- This project only accepts pull requests related to open issues -->
<!--- If suggesting a new feature or change, please discuss it in an issue first -->
<!--- If fixing a bug, there should be an issue describing it with steps to reproduce -->
<!--- Please link to the issue here: -->
## Motivation and Context
<!--- Why is this change required? What problem does it solve? -->
## How Has This Been Tested?
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->
## Screenshots (if appropriate):
## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
## Checklist:
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [ ] I have signed the [Adobe Open Source CLA](http://opensource.adobe.com/cla.html).
- [ ] My code follows the code style of this project.
- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [ ] I have read the **CONTRIBUTING** document.
- [ ] I have added tests to cover my changes.
- [ ] All new and existing tests passed.
<!--- Provide a general summary of your changes in the Title above -->

## Description

<!--- Describe your changes in detail -->

## Related Issue

<!--- This project only accepts pull requests related to open issues -->
<!--- If suggesting a new feature or change, please discuss it in an issue first -->
<!--- If fixing a bug, there should be an issue describing it with steps to reproduce -->
<!--- Please link to the issue here: -->

## Motivation and Context

<!--- Why is this change required? What problem does it solve? -->

## How Has This Been Tested?

<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->

## Screenshots (if appropriate):

## Types of changes

<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->

- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)

## Checklist:

<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->

- [ ] I have signed the [Adobe Open Source CLA](http://opensource.adobe.com/cla.html).
- [ ] My code follows the code style of this project.
- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [ ] I have read the **CONTRIBUTING** document.
- [ ] I have added tests to cover my changes.
- [ ] All new and existing tests passed.
1 change: 1 addition & 0 deletions src/SDKErrors.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ E('ERROR_GET_PROJECT_BY_WORKSPACE', '%s')
E('ERROR_DELETE_CREDENTIAL', '%s')
E('ERROR_CREATE_ORGANIZATION', '%s')
E('ERROR_GET_ORGANIZATIONS', '%s')
E('ERROR_GET_ORGANIZATION_FEATURES', '%s')
E('ERROR_GET_SERVICES_FOR_ORG', '%s')
E('ERROR_GET_SERVICES_FOR_ORG_V2', '%s')
E('ERROR_CREATE_RUNTIME_NAMESPACE', '%s')
Expand Down
56 changes: 56 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,14 @@ const API_HOST = {
stage: 'developers-stage.adobe.io'
}

// Console BFF host. Used by endpoints that are not exposed through the
// public Console API gateway (`API_HOST`) but only through the Console UI's
// backend-for-frontend (e.g. organization feature flags).
const CONSOLE_UI_HOST = {
prod: 'developer.adobe.com',
stage: 'developer-stage.adobe.com'
}

/**
* Returns a Promise that resolves with a new CoreConsoleAPI object
*
Expand Down Expand Up @@ -788,6 +796,54 @@ class CoreConsoleAPI {
}
}

/**
* Get the enabled feature flags for an Organization.
*
* Note: this endpoint is served by the Console UI backend
* (`developer.adobe.com`), not the public Console API gateway, so it does
* not go through the swagger client.
*
* @param {string} organizationId Organization AMS ID
* @returns {Promise<Response>} the response, with `body` set to the feature
* array (e.g. `[{ name: 'RUNTIME', description: '...' }]`)
*/
async getOrganizationFeatures (organizationId) {
const parameters = { orgId: organizationId }
const sdkDetails = { parameters }

// `this.env` is normalized by `init` to a known value (`prod` or `stage`),
// so a direct lookup is safe here.
const host = CONSOLE_UI_HOST[this.env]
const url = `https://${host}/console/api/organizations/${organizationId}/features`

try {
const res = await fetchWithRetry(url, {
headers: {
accept: 'application/json',
authorization: `Bearer ${this.accessToken}`,
'x-api-key': this.apiKey
}
})
if (!res.ok) {
const body = await res.text()
const err = new Error(`${res.status} ${res.statusText}`)
err.response = {
status: res.status,
statusText: res.statusText,
body,
headers: Object.fromEntries(res.headers)
}
throw err
}
const body = await res.json()
// shape the result like the swagger-client responses do, so callers
// can treat this consistently with the rest of the SDK
return { ok: true, status: res.status, statusText: res.statusText, body, data: body }
} catch (err) {
throw new codes.ERROR_GET_ORGANIZATION_FEATURES({ sdkDetails, messageValues: reduceError(err) })
}
}

/**
* Get all Services available to an Organization
*
Expand Down
74 changes: 74 additions & 0 deletions test/index_fetchmock.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,77 @@ describe('getApplicationExtensions (xr api)', () => {
expect(Array.isArray(res.data)).toBe(true)
})
})

describe('getOrganizationFeatures', () => {
/** @private */
function mockFeaturesResponse ({ ok = true, status = 200, statusText = 'OK', body = [] } = {}) {
mockFetch.mockReset()
mockFetch.mockResolvedValueOnce({
ok,
status,
statusText,
headers: new Map(),
json: () => Promise.resolve(body),
text: () => Promise.resolve(typeof body === 'string' ? body : JSON.stringify(body))
})
}

test('returns the features for an org (prod)', async () => {
const sdkClient = await sdk.init('accesstoken', 'apiKey')
mockFeaturesResponse({ body: [{ name: 'RUNTIME', description: 'OpenWhisk runtime' }] })

const res = await sdkClient.getOrganizationFeatures('304327')
expect(res.ok).toBe(true)
expect(res.body).toEqual([{ name: 'RUNTIME', description: 'OpenWhisk runtime' }])
expect(mockFetch).toHaveBeenCalledWith(
'https://developer.adobe.com/console/api/organizations/304327/features',
expect.objectContaining({
headers: expect.objectContaining({
accept: 'application/json',
authorization: 'Bearer accesstoken',
'x-api-key': 'apiKey'
})
})
)
})

test('uses the stage host when env=stage', async () => {
const { STAGE_ENV } = jest.requireActual('@adobe/aio-lib-env')
const sdkClient = await sdk.init('accesstoken', 'apiKey', STAGE_ENV)
mockFeaturesResponse({ body: [] })

await sdkClient.getOrganizationFeatures('304327')
expect(mockFetch).toHaveBeenCalledWith(
'https://developer-stage.adobe.com/console/api/organizations/304327/features',
expect.any(Object)
)
})

test('uses the prod host when env is unknown (init normalises it to prod)', async () => {
const sdkClient = await sdk.init('accesstoken', 'apiKey', 'gibberish')
mockFeaturesResponse({ body: [] })

await sdkClient.getOrganizationFeatures('304327')
expect(mockFetch).toHaveBeenCalledWith(
'https://developer.adobe.com/console/api/organizations/304327/features',
expect.any(Object)
)
})

test('throws ERROR_GET_ORGANIZATION_FEATURES on non-ok response', async () => {
const sdkClient = await sdk.init('accesstoken', 'apiKey')
mockFeaturesResponse({ ok: false, status: 500, statusText: 'Server Error', body: 'boom' })

await expect(sdkClient.getOrganizationFeatures('304327'))
.rejects.toThrow(/ERROR_GET_ORGANIZATION_FEATURES/)
})

test('throws ERROR_GET_ORGANIZATION_FEATURES on network error', async () => {
const sdkClient = await sdk.init('accesstoken', 'apiKey')
mockFetch.mockReset()
mockFetch.mockRejectedValueOnce(new Error('network down'))

await expect(sdkClient.getOrganizationFeatures('304327'))
.rejects.toThrow(/ERROR_GET_ORGANIZATION_FEATURES/)
})
})
Loading