mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-11 04:22:13 +00:00
[cli] Print upload progress in increments of 25% when non-TTY (#8650)
When running `vc deploy` in a non-TTY context (i.e. CI), limit the number of progress updates to 25% increments (for a total of 5). ``` Uploading [--------------------] (0.0B/71.9MB) Uploading [=====---------------] (18.0MB/71.9MB) Uploading [==========----------] (36.0MB/71.9MB) Uploading [===============-----] (54.0MB/71.9MB) Uploading [====================] (71.9MB/71.9MB) ``` This avoids spamming the user logs with many progress updates.
This commit is contained in:
@@ -115,29 +115,39 @@ export default async function processDeployment({
|
|||||||
.reduce((a: number, b: number) => a + b, 0);
|
.reduce((a: number, b: number) => a + b, 0);
|
||||||
const totalSizeHuman = bytes.format(missingSize, { decimalPlaces: 1 });
|
const totalSizeHuman = bytes.format(missingSize, { decimalPlaces: 1 });
|
||||||
|
|
||||||
uploads.forEach((e: any) =>
|
// When stderr is not a TTY then we only want to
|
||||||
e.on('progress', () => {
|
// print upload progress in 25% increments
|
||||||
const uploadedBytes = uploads.reduce((acc: number, e: any) => {
|
let nextStep = 0;
|
||||||
return acc + e.bytesUploaded;
|
const stepSize = now._client.stderr.isTTY ? 0 : 0.25;
|
||||||
}, 0);
|
|
||||||
|
|
||||||
const bar = progress(uploadedBytes, missingSize);
|
const updateProgress = () => {
|
||||||
if (!bar || uploadedBytes === missingSize) {
|
const uploadedBytes = uploads.reduce((acc: number, e: any) => {
|
||||||
output.spinner(deployingSpinnerVal, 0);
|
return acc + e.bytesUploaded;
|
||||||
} else {
|
}, 0);
|
||||||
const uploadedHuman = bytes.format(uploadedBytes, {
|
|
||||||
decimalPlaces: 1,
|
const bar = progress(uploadedBytes, missingSize);
|
||||||
fixedDecimals: true,
|
if (!bar) {
|
||||||
});
|
output.spinner(deployingSpinnerVal, 0);
|
||||||
|
} else {
|
||||||
|
const uploadedHuman = bytes.format(uploadedBytes, {
|
||||||
|
decimalPlaces: 1,
|
||||||
|
fixedDecimals: true,
|
||||||
|
});
|
||||||
|
const percent = uploadedBytes / missingSize;
|
||||||
|
if (percent >= nextStep) {
|
||||||
output.spinner(
|
output.spinner(
|
||||||
`Uploading ${chalk.reset(
|
`Uploading ${chalk.reset(
|
||||||
`[${bar}] (${uploadedHuman}/${totalSizeHuman})`
|
`[${bar}] (${uploadedHuman}/${totalSizeHuman})`
|
||||||
)}`,
|
)}`,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
|
nextStep += stepSize;
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
);
|
};
|
||||||
|
|
||||||
|
uploads.forEach((e: any) => e.on('progress', updateProgress));
|
||||||
|
updateProgress();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.type === 'file-uploaded') {
|
if (event.type === 'file-uploaded') {
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
|
import bytes from 'bytes';
|
||||||
|
import fs from 'fs-extra';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
import { randomBytes } from 'crypto';
|
||||||
import { fileNameSymbol } from '@vercel/client';
|
import { fileNameSymbol } from '@vercel/client';
|
||||||
import { client } from '../../mocks/client';
|
import { client } from '../../mocks/client';
|
||||||
import deploy from '../../../src/commands/deploy';
|
import deploy from '../../../src/commands/deploy';
|
||||||
@@ -199,4 +202,119 @@ describe('deploy', () => {
|
|||||||
process.chdir(originalCwd);
|
process.chdir(originalCwd);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should upload missing files', async () => {
|
||||||
|
const cwd = setupFixture('commands/deploy/archive');
|
||||||
|
const originalCwd = process.cwd();
|
||||||
|
|
||||||
|
// Add random 1mb file
|
||||||
|
await fs.writeFile(join(cwd, 'data'), randomBytes(bytes('1mb')));
|
||||||
|
|
||||||
|
try {
|
||||||
|
process.chdir(cwd);
|
||||||
|
|
||||||
|
const user = useUser();
|
||||||
|
useTeams('team_dummy');
|
||||||
|
useProject({
|
||||||
|
...defaultProject,
|
||||||
|
name: 'archive',
|
||||||
|
id: 'archive',
|
||||||
|
});
|
||||||
|
|
||||||
|
let body: any;
|
||||||
|
let fileUploaded = false;
|
||||||
|
client.scenario.post(`/v13/deployments`, (req, res) => {
|
||||||
|
if (fileUploaded) {
|
||||||
|
body = req.body;
|
||||||
|
res.json({
|
||||||
|
creator: {
|
||||||
|
uid: user.id,
|
||||||
|
username: user.username,
|
||||||
|
},
|
||||||
|
id: 'dpl_archive_test',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const sha = req.body.files[0].sha;
|
||||||
|
res.status(400).json({
|
||||||
|
error: {
|
||||||
|
code: 'missing_files',
|
||||||
|
message: 'Missing files',
|
||||||
|
missing: [sha],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
client.scenario.post('/v2/files', (req, res) => {
|
||||||
|
// Wait for file to be finished uploading
|
||||||
|
req.on('data', () => {
|
||||||
|
// Noop
|
||||||
|
});
|
||||||
|
req.on('end', () => {
|
||||||
|
fileUploaded = true;
|
||||||
|
res.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
client.scenario.get(`/v13/deployments/dpl_archive_test`, (req, res) => {
|
||||||
|
res.json({
|
||||||
|
creator: {
|
||||||
|
uid: user.id,
|
||||||
|
username: user.username,
|
||||||
|
},
|
||||||
|
id: 'dpl_archive_test',
|
||||||
|
readyState: 'READY',
|
||||||
|
aliasAssigned: true,
|
||||||
|
alias: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
client.scenario.get(
|
||||||
|
`/v10/now/deployments/dpl_archive_test`,
|
||||||
|
(req, res) => {
|
||||||
|
res.json({
|
||||||
|
creator: {
|
||||||
|
uid: user.id,
|
||||||
|
username: user.username,
|
||||||
|
},
|
||||||
|
id: 'dpl_archive_test',
|
||||||
|
readyState: 'READY',
|
||||||
|
aliasAssigned: true,
|
||||||
|
alias: [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// When stderr is not a TTY we expect 5 progress lines to be printed
|
||||||
|
client.stderr.isTTY = false;
|
||||||
|
|
||||||
|
client.setArgv('deploy', '--archive=tgz');
|
||||||
|
const uploadingLines: string[] = [];
|
||||||
|
client.stderr.on('data', data => {
|
||||||
|
if (data.startsWith('Uploading [')) {
|
||||||
|
uploadingLines.push(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
client.stderr.resume();
|
||||||
|
const exitCode = await deploy(client);
|
||||||
|
expect(exitCode).toEqual(0);
|
||||||
|
expect(body?.files?.length).toEqual(1);
|
||||||
|
expect(body?.files?.[0].file).toEqual('.vercel/source.tgz');
|
||||||
|
expect(uploadingLines.length).toEqual(5);
|
||||||
|
expect(
|
||||||
|
uploadingLines[0].startsWith('Uploading [--------------------]')
|
||||||
|
).toEqual(true);
|
||||||
|
expect(
|
||||||
|
uploadingLines[1].startsWith('Uploading [=====---------------]')
|
||||||
|
).toEqual(true);
|
||||||
|
expect(
|
||||||
|
uploadingLines[2].startsWith('Uploading [==========----------]')
|
||||||
|
).toEqual(true);
|
||||||
|
expect(
|
||||||
|
uploadingLines[3].startsWith('Uploading [===============-----]')
|
||||||
|
).toEqual(true);
|
||||||
|
expect(
|
||||||
|
uploadingLines[4].startsWith('Uploading [====================]')
|
||||||
|
).toEqual(true);
|
||||||
|
} finally {
|
||||||
|
process.chdir(originalCwd);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Agent } from 'https';
|
import http from 'http';
|
||||||
|
import https from 'https';
|
||||||
import { Readable } from 'stream';
|
import { Readable } from 'stream';
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import retry from 'async-retry';
|
import retry from 'async-retry';
|
||||||
@@ -78,7 +79,9 @@ export async function* upload(
|
|||||||
debug('Building an upload list...');
|
debug('Building an upload list...');
|
||||||
|
|
||||||
const semaphore = new Sema(50, { capacity: 50 });
|
const semaphore = new Sema(50, { capacity: 50 });
|
||||||
const agent = new Agent({ keepAlive: true });
|
const agent = apiUrl?.startsWith('https://')
|
||||||
|
? new https.Agent({ keepAlive: true })
|
||||||
|
: new http.Agent({ keepAlive: true });
|
||||||
|
|
||||||
shas.forEach((sha, index) => {
|
shas.forEach((sha, index) => {
|
||||||
const uploadProgress = uploads[index];
|
const uploadProgress = uploads[index];
|
||||||
|
|||||||
Reference in New Issue
Block a user