@lifeomic/bitrise
Advanced tools
Comparing version 0.10.2-pr-52-980580231-1624917296.0 to 0.10.2
{ | ||
"name": "@lifeomic/bitrise", | ||
"version": "0.10.2-pr-52-980580231-1624917296.0", | ||
"version": "0.10.2", | ||
"description": "Bitrise API client", | ||
@@ -5,0 +5,0 @@ "main": "src/client.js", |
@@ -33,5 +33,10 @@ const isNil = require('lodash/isNil'); | ||
let attributes; | ||
let lastPosition = 0; | ||
// Start with the interval provided, or the default, but if the build | ||
// completes then the interval will be dropped to 0 to pull logs as fast | ||
// as possible | ||
let interval = options.interval || 5000; | ||
do { | ||
if (timestamp) { | ||
await sleep(options.interval || 5000); | ||
if (timestamp && interval > 0) { | ||
await sleep(interval); | ||
} | ||
@@ -45,3 +50,4 @@ | ||
// If the log has already been archived then polling is no good. Just | ||
// download and print the log data. | ||
// download and print the log data. This handles the case where the | ||
// very first request finds an archived build | ||
if (response.data.is_archived && !timestamp) { | ||
@@ -57,4 +63,11 @@ const archiveResponse = await client.get( | ||
if (response.data.log_chunks.length) { | ||
response.data.log_chunks.forEach(({ chunk }) => | ||
process.stdout.write(chunk) | ||
response.data.log_chunks.forEach(({ chunk, position }) => { | ||
// When requesting the logs by timestamps returned from previous | ||
// requests, duplicate chunks are included in the response. Only | ||
// log new chunks | ||
if (position > lastPosition) { | ||
process.stdout.write(chunk); | ||
lastPosition = position; | ||
} | ||
} | ||
); | ||
@@ -76,4 +89,17 @@ lastActive = now; | ||
// If the build is completed and there are no more log chunks | ||
if (!!attributes.build_finished && response.data.log_chunks.length === 0) { | ||
// No need to keep watching a completed build | ||
if (attributes.finished_at) { | ||
if (response.data.log_chunks.length === 0) { | ||
// No need to keep watching a completed build | ||
break; | ||
} | ||
// If the build is done and chuncks are being seeing, then pull them | ||
// as fast as possible | ||
interval = 0; | ||
} | ||
// If the log was being followed and it switched to streaming before the | ||
// end was hit, then end early and warn about missing logs | ||
if (response.data.is_archived) { | ||
process.stdout.write('Build has been archived before all the logs were streamed. Check the Bitrise console for the full logs\n'); | ||
break; | ||
@@ -80,0 +106,0 @@ } |
@@ -131,3 +131,3 @@ const axios = require('axios'); | ||
buildStub.build.status = 1; | ||
buildStub.build.build_finished = new Date().toISOString(); | ||
buildStub.build.finished_at = new Date().toISOString(); | ||
stubArchivedBuildLog({ appSlug, axios: client, buildSlug, logText }); | ||
@@ -151,3 +151,3 @@ | ||
buildStub.build.status = 1; | ||
buildStub.build.build_finished = new Date().toISOString(); | ||
buildStub.build.finished_at = new Date().toISOString(); | ||
// The client fetchs logs until no more log chunks are returned | ||
@@ -168,2 +168,30 @@ // The empty finaly chunck signals the end of the log (when the build is finished) | ||
test.serial('when a build is finished but not archived, the logs are pulled as fast as possible', async (test) => { | ||
const { appSlug, build, buildSlug, client } = test.context; | ||
const logText = ['some log text', 'log text 2', 'log text 3']; | ||
const buildStub = stubGetBuild({ appSlug, axios: client, buildSlug }); | ||
buildStub.build.status = 1; | ||
buildStub.build.finished_at = new Date().toISOString(); | ||
// The client fetchs logs until no more log chunks are returned | ||
// The empty finaly chunck signals the end of the log (when the build is finished) | ||
stubBuildLogStream({ appSlug, axios: client, buildSlug, logChunks: [...logText, ''] }); | ||
// Cause timers to execute immediately | ||
const clock = sinon.stub(global, 'setTimeout').callsArg(0); | ||
// Track writes | ||
const write = sinon.stub(process.stdout, 'write'); | ||
try { | ||
await build.follow(); | ||
for (const chunk of logText) { | ||
sinon.assert.calledWithExactly(write, chunk); | ||
} | ||
sinon.assert.notCalled(clock); | ||
} finally { | ||
clock.restore(); | ||
write.restore(); | ||
} | ||
}); | ||
test('following a failed build that has already finished prints the log output and then errors', async (test) => { | ||
@@ -275,3 +303,4 @@ const { appSlug, build, buildSlug, client } = test.context; | ||
['heartbeat: waiting for build output...\n'], | ||
['line four'] | ||
['line four'], | ||
['Build has been archived before all the logs were streamed. Check the Bitrise console for the full logs\n'] | ||
] | ||
@@ -278,0 +307,0 @@ ); |
@@ -88,19 +88,28 @@ const get = require('lodash/get'); | ||
let previousChunk = null; | ||
while (chunks.length) { | ||
const chunk = chunks.shift(); | ||
const parameters = timestamp > 1 ? `?timestamp=${timestamp - 1}` : ''; | ||
const parameters = timestamp > 1 ? `?timestamp=${new Date(timestamp - 1).toISOString()}` : ''; | ||
const logUrl = `/apps/${appSlug}/builds/${buildSlug}/log${parameters}`; | ||
const newChunk = chunk ? { | ||
chunk, | ||
position: timestamp | ||
} : null; | ||
const newChunks = newChunk ? [newChunk] : []; | ||
// When there are two chunks in a row, then add duplicate values to mimic | ||
// Bitrise sometimes returning duplicate chunks | ||
const oldChunks = newChunk && previousChunk ? [previousChunk] : []; | ||
logStub.withArgs(logUrl).resolves({ | ||
data: { | ||
is_archived: chunks.length === 0, | ||
log_chunks: chunk | ||
? [ | ||
{ | ||
chunk, | ||
position: timestamp | ||
} | ||
] | ||
: [], | ||
timestamp: chunks.length ? timestamp : null | ||
log_chunks: [ | ||
...oldChunks, | ||
...newChunks | ||
], | ||
// When the build is archived, Bitrise starts to return a sentinel date constant | ||
timestamp: chunks.length ? new Date(timestamp).toISOString() : '0001-01-01T00:00:00Z' | ||
}, | ||
@@ -110,2 +119,4 @@ status: 200 | ||
previousChunk = newChunk; | ||
timestamp++; | ||
@@ -112,0 +123,0 @@ } |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
57406
1277
0