New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@adobe/aio-lib-cloudmanager

Package Overview
Dependencies
Maintainers
18
Versions
40
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@adobe/aio-lib-cloudmanager - npm Package Compare versions

Comparing version 1.0.1 to 1.1.0

.github/ISSUE_TEMPLATE/bug_report.md

7

CHANGELOG.md
# Changelog
# [1.1.0](https://github.com/adobe/aio-lib-cloudmanager/compare/1.0.1...1.1.0) (2021-06-30)
### Features
* **execution:** add tailExecutionStepLog method. fixes [#170](https://github.com/adobe/aio-lib-cloudmanager/issues/170) ([#171](https://github.com/adobe/aio-lib-cloudmanager/issues/171)) ([36dbcb0](https://github.com/adobe/aio-lib-cloudmanager/commit/36dbcb05fea4bf9ca40cdcd35d6ebe3185e250fc))
## [1.0.1](https://github.com/adobe/aio-lib-cloudmanager/compare/1.0.0...1.0.1) (2021-06-30)

@@ -4,0 +11,0 @@

2

package.json
{
"name": "@adobe/aio-lib-cloudmanager",
"version": "1.0.1",
"version": "1.1.0",
"description": "Adobe I/O Cloud Manager Library",

@@ -5,0 +5,0 @@ "repository": {

@@ -159,2 +159,3 @@ <!--

* [.getExecutionStepLog(programId, pipelineId, executionId, action, logFile, outputStream)](#CloudManagerAPI+getExecutionStepLog) ⇒ <code>Promise.&lt;object&gt;</code>
* [.tailExecutionStepLog(programId, pipelineId, action, logFile, outputStream)](#CloudManagerAPI+tailExecutionStepLog) ⇒ [<code>Promise.&lt;PipelineExecutionStepState&gt;</code>](#PipelineExecutionStepState)
* [.listAvailableLogOptions(programId, environmentId)](#CloudManagerAPI+listAvailableLogOptions) ⇒ <code>Promise.&lt;Array.&lt;LogOptionRepresentation&gt;&gt;</code>

@@ -376,2 +377,18 @@ * [.downloadLogs(programId, environmentId, service, name, days, outputDirectory)](#CloudManagerAPI+downloadLogs) ⇒ <code>Promise.&lt;Array.&lt;DownloadedLog&gt;&gt;</code>

<a name="CloudManagerAPI+tailExecutionStepLog"></a>
### cloudManagerAPI.tailExecutionStepLog(programId, pipelineId, action, logFile, outputStream) ⇒ [<code>Promise.&lt;PipelineExecutionStepState&gt;</code>](#PipelineExecutionStepState)
Tail step log to an output stream.
**Kind**: instance method of [<code>CloudManagerAPI</code>](#CloudManagerAPI)
**Returns**: [<code>Promise.&lt;PipelineExecutionStepState&gt;</code>](#PipelineExecutionStepState) - the completed step state
| Param | Type | Description |
| --- | --- | --- |
| programId | <code>string</code> | the program id |
| pipelineId | <code>string</code> | the pipeline id |
| action | <code>string</code> | the action |
| logFile | <code>string</code> | the log file to select a non-default value |
| outputStream | <code>object</code> | the output stream to write to |
<a name="CloudManagerAPI+listAvailableLogOptions"></a>

@@ -378,0 +395,0 @@

@@ -31,3 +31,3 @@ /*

PipelineStepMetrics, Environment, LogOptionRepresentation,
DownloadedLog, PipelineUpdate, Variable, IPAllowedList */ // for linter
DownloadedLog, PipelineUpdate, Variable, IPAllowedList, PipelineExecutionStepState */ // for linter

@@ -609,2 +609,80 @@ /**

async _refreshStepState (href) {
return this._get(href, codes.ERROR_REFRESH_STEP_STATE).then(res => {
return res.json()
}, e => {
throw e
})
}
async _getExecutionStepLogUrl (href) {
return this._get(href, codes.ERROR_GET_LOG).then(async (res) => {
const json = await res.json()
if (json.redirect) {
return json.redirect
} else {
throw new codes.ERROR_NO_LOG_REDIRECT({ messageValues: [res.url, JSON.stringify(json)] })
}
}, e => {
throw e
})
}
/**
* Tail step log to an output stream.
*
* @param {string} programId the program id
* @param {string} pipelineId the pipeline id
* @param {string} action the action
* @param {string} logFile the log file to select a non-default value
* @param {object} outputStream the output stream to write to
* @returns {Promise<PipelineExecutionStepState>} the completed step state
*/
async tailExecutionStepLog (programId, pipelineId, action, logFile, outputStream) {
if (!outputStream) {
outputStream = logFile
logFile = undefined
}
const currentExecution = halfred.parse(await this.getCurrentExecution(programId, pipelineId))
let stepState = findStepState(currentExecution, action)
if (!stepState) {
throw new codes.ERROR_FIND_STEP_STATE({ messageValues: [action, currentExecution.id] })
}
if (stepState.status === 'RUNNING') {
const selfStateHref = stepState.link(rels.self).href
let link = stepState.link(rels.stepLogs).href
if (logFile) {
link = `${link}?file=${logFile}`
}
const tailingSasUrl = await this._getExecutionStepLogUrl(link)
let currentStartLimit = 0
while (stepState.status === 'RUNNING') {
const options = {
headers: {
Range: `bytes=${currentStartLimit}-`,
},
}
const res = await fetch(tailingSasUrl, options)
if (res.status === 206) {
const contentLength = res.headers.get('content-length')
await this._pipeBody(res.body, outputStream)
currentStartLimit = parseInt(currentStartLimit) + parseInt(contentLength)
console.log(currentStartLimit)
} else if (res.status === 416 || res.status === 404) {
// 416 means there's more data potentially available; 404 means the log isn't ready yet
// these are different things, but we can treat them the same way -- wait a few seconds
await sleep(5000)
}
stepState = await this._refreshStepState(selfStateHref)
}
} else {
throw new codes.ERROR_STEP_STATE_NOT_RUNNING({ messageValues: [action, currentExecution.id] })
}
return stepState
}
async _findEnvironment (programId, environmentId) {

@@ -611,0 +689,0 @@ const environments = await this.listEnvironments(programId)

@@ -105,1 +105,3 @@ /*

E('ERROR_UNSUPPORTED_ADVANCE_STEP', 'Advancing the step %s is not supported in the CLI at present.')
E('ERROR_REFRESH_STEP_STATE', 'Cannot refresh step state: %s')
E('ERROR_STEP_STATE_NOT_RUNNING', 'The %s step in execution %s is not currently running.')

@@ -19,13 +19,27 @@ /*

let writable
let written = ''
let written
let flushWritable
let originalSetTimeout
beforeEach(() => {
written = ''
const write = sinon.stub().callsFake((chunk, enc, callback) => callback())
writable = new Writable({ write })
writable.on('finish', () => {
flushWritable = () => {
written = write.args.map(args => args[0]).map(a => a.toString('utf8')).join('')
})
}
writable.on('finish', flushWritable)
originalSetTimeout = global.setTimeout
global.setTimeout = jest.fn().mockImplementation((cb) => cb())
})
afterEach(() => {
global.setTimeout = originalSetTimeout
})
test('getCurrentExecution - failure', async () => {

@@ -482,1 +496,109 @@ expect.assertions(2)

})
test('tailExecutionStepLog - failure no current execution', async () => {
expect.assertions(3)
const sdkClient = await createSdkClient()
const result = sdkClient.tailExecutionStepLog('5', '5', 'build', writable)
await expect(result instanceof Promise).toBeTruthy()
await expect(result).rejects.toEqual(
new codes.ERROR_GET_EXECUTION({ messageValues: 'https://cloudmanager.adobe.io/api/program/5/pipeline/5/execution (404 Not Found)' }),
)
expect(written).toEqual('')
})
test('tailExecutionStepLog - step not running', async () => {
fetchMock.setPipeline7Execution('1003')
expect.assertions(3)
const sdkClient = await createSdkClient()
const result = sdkClient.tailExecutionStepLog('5', '7', 'build', writable)
await expect(result instanceof Promise).toBeTruthy()
await expect(result).rejects.toEqual(
new codes.ERROR_STEP_STATE_NOT_RUNNING({ messageValues: ['build', '1003'] }),
)
expect(written).toEqual('')
})
test('tailExecutionStepLog - bad step name', async () => {
fetchMock.setPipeline7Execution('1003')
expect.assertions(3)
const sdkClient = await createSdkClient()
const result = sdkClient.tailExecutionStepLog('5', '7', 'BUILD', writable)
await expect(result instanceof Promise).toBeTruthy()
await expect(result).rejects.toEqual(
new codes.ERROR_FIND_STEP_STATE({ messageValues: ['BUILD', '1003'] }),
)
expect(written).toEqual('')
})
test('tailExecutionStepLog - step log endpoint returns error', async () => {
fetchMock.setPipeline7Execution('1017')
expect.assertions(3)
const sdkClient = await createSdkClient()
const result = sdkClient.tailExecutionStepLog('5', '7', 'build', 'error', writable)
await expect(result instanceof Promise).toBeTruthy()
await expect(result).rejects.toEqual(
new codes.ERROR_GET_LOG({ messageValues: ['https://cloudmanager.adobe.io/api/program/5/pipeline/7/execution/1017/phase/4596/step/8492/logs?file=error', '(404 Not Found)'] }),
)
expect(written).toEqual('')
})
test('tailExecutionStepLog - step log endpoint returns no redirect', async () => {
fetchMock.setPipeline7Execution('1017')
expect.assertions(3)
const sdkClient = await createSdkClient()
const result = sdkClient.tailExecutionStepLog('5', '7', 'build', 'noredirect', writable)
await expect(result instanceof Promise).toBeTruthy()
await expect(result).rejects.toEqual(
new codes.ERROR_NO_LOG_REDIRECT({ messageValues: ['https://cloudmanager.adobe.io/api/program/5/pipeline/7/execution/1017/phase/4596/step/8492/logs?file=noredirect', '{"garbage":"true"}'] }),
)
expect(written).toEqual('')
})
test('tailExecutionStepLog - success', async () => {
fetchMock.setPipeline7Execution('1017')
expect.assertions(7)
const sdkClient = await createSdkClient()
const result = sdkClient.tailExecutionStepLog('5', '7', 'build', writable)
await expect(result instanceof Promise).toBeTruthy()
await expect(result).resolves.toBeTruthy()
await expect(fetchMock.called('tail-step-log-1017-first')).toBe(true)
await expect(fetchMock.called('tail-step-log-1017-second')).toBe(true)
await expect(fetchMock.called('tail-step-log-1017-third')).toBe(true)
await expect(fetchMock.calls('tail-step-log-1017-third').length).toEqual(2)
flushWritable()
expect(written).toEqual('some log message\nsome second log message\nsome third log message\n')
})
test('tailExecutionStepLog - faling refresh', async () => {
fetchMock.setPipeline7Execution('1018')
expect.assertions(4)
const sdkClient = await createSdkClient()
const result = sdkClient.tailExecutionStepLog('5', '7', 'build', writable)
await expect(result instanceof Promise).toBeTruthy()
await expect(result).rejects.toEqual(
new codes.ERROR_REFRESH_STEP_STATE({ messageValues: ['https://cloudmanager.adobe.io/api/program/5/pipeline/7/execution/1018/phase/4596/step/8492', '(500 Internal Server Error)'] }),
)
await expect(fetchMock.called('tail-step-log-1018-first')).toBe(true)
flushWritable()
expect(written).toEqual('some log message\n')
})

@@ -162,3 +162,3 @@ {

},
"id": "1001",
"id": "1003",
"programId": "5",

@@ -165,0 +165,0 @@ "pipelineId": "7",

@@ -1417,2 +1417,3 @@ /*

1001: require('./data/execution1001.json'),
1003: require('./data/execution1003.json'),
1005: require('./data/execution1005.json'),

@@ -1430,2 +1431,4 @@ 1006: require('./data/execution1006.json'),

1016: require('./data/execution1016.json'),
1017: require('./data/execution1017.json'),
1018: require('./data/execution1018.json'),
}

@@ -1493,3 +1496,100 @@ mockResponseWithMethod('https://cloudmanager.adobe.io/api/program/5/pipeline/7/execution', 'GET', () => pipeline7Executions[executionForPipeline7])

})
mockResponseWithMethod('https://cloudmanager.adobe.io/api/program/5/pipeline/7/execution/1017/phase/4596/step/8492/logs?file=error', 'GET', 404)
mockResponseWithMethod('https://cloudmanager.adobe.io/api/program/5/pipeline/7/execution/1017/phase/4596/step/8492/logs?file=noredirect', 'GET', {
garbage: 'true',
})
mockResponseWithMethod('https://cloudmanager.adobe.io/api/program/5/pipeline/7/execution/1017/phase/4596/step/8492/logs', 'GET', {
redirect: 'https://filestore/for-tailing.txt',
})
fetchMock.mock({
url: 'https://filestore/for-tailing.txt',
headers: { range: 'bytes=0-' },
name: 'tail-step-log-1017-first',
}, () => {
const logResponse = new Readable()
logResponse.push('some log message\n')
logResponse.push(null)
return {
status: 206,
headers: {
'content-length': '1000',
},
body: logResponse,
}
}, { sendAsJson: false })
fetchMock.mock({
url: 'https://filestore/for-tailing.txt',
headers: { range: 'bytes=1000-' },
name: 'tail-step-log-1017-second',
}, () => {
const logResponse = new Readable()
logResponse.push('some second log message\n')
logResponse.push(null)
return {
status: 206,
headers: {
'content-length': '1000',
},
body: logResponse,
}
}, { sendAsJson: false })
let execution1017StepLogCounter = 0
fetchMock.mock({
url: 'https://filestore/for-tailing.txt',
headers: { range: 'bytes=2000-' },
name: 'tail-step-log-1017-third',
}, () => {
execution1017StepLogCounter++
if (execution1017StepLogCounter === 1) {
return {
status: 416,
}
} else {
const logResponse = new Readable()
logResponse.push('some third log message\n')
logResponse.push(null)
return {
status: 206,
headers: {
'content-length': '1000',
},
body: logResponse,
}
}
}, { sendAsJson: false })
let execution1017StepCounter = 0
fetchMock.mock('https://cloudmanager.adobe.io/api/program/5/pipeline/7/execution/1017/phase/4596/step/8492', () => {
execution1017StepCounter++
if (execution1017StepCounter < 4) {
return pipeline7Executions[1017]._embedded.stepStates[1]
} else {
const cloned = _.cloneDeep(pipeline7Executions[1017]._embedded.stepStates[1])
cloned.status = 'FINISHED'
return cloned
}
})
mockResponseWithMethod('https://cloudmanager.adobe.io/api/program/5/pipeline/7/execution/1018/phase/4596/step/8492/logs', 'GET', {
redirect: 'https://filestore/for-tailing1018.txt',
})
fetchMock.mock({
url: 'https://filestore/for-tailing1018.txt',
headers: { range: 'bytes=0-' },
name: 'tail-step-log-1018-first',
}, () => {
const logResponse = new Readable()
logResponse.push('some log message\n')
logResponse.push(null)
return {
status: 206,
headers: {
'content-length': '1000',
},
body: logResponse,
}
}, { sendAsJson: false })
fetchMock.mock('https://cloudmanager.adobe.io/api/program/5/pipeline/7/execution/1018/phase/4596/step/8492', 500)
fetchMock.mock('https://cloudmanager.adobe.io/api/program/7', 404)

@@ -1496,0 +1596,0 @@ fetchMock.mock('https://cloudmanager.adobe.io/api/program/4/environment/10/variables', 404)

@@ -19,3 +19,3 @@ /*

let writable
let written = ''
let written

@@ -27,2 +27,3 @@ let flushWritable

beforeEach(() => {
written = ''
const write = sinon.stub().callsFake((chunk, enc, callback) => callback())

@@ -29,0 +30,0 @@ writable = new Writable({ write })

@@ -146,2 +146,12 @@ /**

/**
* Tail step log to an output stream.
* @param programId - the program id
* @param pipelineId - the pipeline id
* @param action - the action
* @param logFile - the log file to select a non-default value
* @param outputStream - the output stream to write to
* @returns the completed step state
*/
tailExecutionStepLog(programId: string, pipelineId: string, action: string, logFile: string, outputStream: any): Promise<PipelineExecutionStepState>;
/**
* List the log options available for an environment

@@ -148,0 +158,0 @@ * @param programId - the program id

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc