[cli] Add client.cwd to unify all working directory related logic (#10031)

A few commands were still checking on `--cwd` explicitly, which is incorrect since the entrypoint file already handles the directory change.

The new `client.cwd` property is a helper to make writing tests easier. Tests no longer need to `chdir()` explicitly and then revert afterwards.
This commit is contained in:
Nathan Rajlich
2023-05-26 13:42:03 -07:00
committed by GitHub
parent 113b8ac87b
commit ef30a46c03
18 changed files with 1112 additions and 1387 deletions

View File

@@ -0,0 +1,5 @@
---
'vercel': patch
---
Fix `--cwd` flag with a relative path for `env`, `link`, `promote`, and `rollback` subcommands

View File

@@ -133,7 +133,7 @@ const help = () => {
}; };
export default async function main(client: Client): Promise<number> { export default async function main(client: Client): Promise<number> {
const { output } = client; const { cwd, output } = client;
// Ensure that `vc build` is not being invoked recursively // Ensure that `vc build` is not being invoked recursively
if (process.env.__VERCEL_BUILD_RUNNING) { if (process.env.__VERCEL_BUILD_RUNNING) {
@@ -165,8 +165,6 @@ export default async function main(client: Client): Promise<number> {
return 2; return 2;
} }
const cwd = process.cwd();
// Build `target` influences which environment variables will be used // Build `target` influences which environment variables will be used
const target = argv['--prod'] ? 'production' : 'preview'; const target = argv['--prod'] ? 'production' : 'preview';
const yes = Boolean(argv['--yes']); const yes = Boolean(argv['--yes']);

View File

@@ -130,10 +130,9 @@ export default async function main(client: Client) {
return 2; return 2;
} }
const cwd = argv['--cwd'] || process.cwd();
const subArgs = argv._.slice(1); const subArgs = argv._.slice(1);
const { subcommand, args } = getSubcommand(subArgs, COMMAND_CONFIG); const { subcommand, args } = getSubcommand(subArgs, COMMAND_CONFIG);
const { output, config } = client; const { cwd, output, config } = client;
const target = argv['--environment']?.toLowerCase() || 'development'; const target = argv['--environment']?.toLowerCase() || 'development';
if (!isValidEnvTarget(target)) { if (!isValidEnvTarget(target)) {

View File

@@ -90,7 +90,7 @@ export default async function main(client: Client) {
)} instead` )} instead`
); );
} else { } else {
cwd = process.cwd(); cwd = client.cwd;
} }
if (argv['--repo']) { if (argv['--repo']) {

View File

@@ -88,7 +88,7 @@ export default async (client: Client): Promise<number> => {
autoConfirm: Boolean(argv['--yes']), autoConfirm: Boolean(argv['--yes']),
client, client,
commandName: 'promote', commandName: 'promote',
cwd: argv['--cwd'] || process.cwd(), cwd: client.cwd,
projectNameOrId: argv._[2], projectNameOrId: argv._[2],
}); });

View File

@@ -88,7 +88,7 @@ export default async (client: Client): Promise<number> => {
autoConfirm: Boolean(argv['--yes']), autoConfirm: Boolean(argv['--yes']),
client, client,
commandName: 'promote', commandName: 'promote',
cwd: argv['--cwd'] || process.cwd(), cwd: client.cwd,
projectNameOrId: argv._[2], projectNameOrId: argv._[2],
}); });

View File

@@ -144,12 +144,6 @@ const main = async () => {
return 1; return 1;
} }
let cwd = argv['--cwd'];
if (cwd) {
process.chdir(cwd);
}
cwd = process.cwd();
// The second argument to the command can be: // The second argument to the command can be:
// //
// * a path to deploy (as in: `vercel path/`) // * a path to deploy (as in: `vercel path/`)
@@ -277,6 +271,12 @@ const main = async () => {
argv: process.argv, argv: process.argv,
}); });
// The `--cwd` flag is respected for all sub-commands
if (argv['--cwd']) {
client.cwd = argv['--cwd'];
}
const { cwd } = client;
// Gets populated to the subcommand name when a built-in is // Gets populated to the subcommand name when a built-in is
// provided, otherwise it remains undefined for an extension // provided, otherwise it remains undefined for an extension
let subcommand: string | undefined = undefined; let subcommand: string | undefined = undefined;

View File

@@ -207,4 +207,12 @@ export default class Client extends EventEmitter implements Stdio {
output: this.stderr as NodeJS.WriteStream, output: this.stderr as NodeJS.WriteStream,
}); });
} }
get cwd(): string {
return process.cwd();
}
set cwd(v: string) {
process.chdir(v);
}
} }

View File

@@ -1,3 +1,5 @@
const originalCwd = process.cwd();
// Register Jest matcher extensions for CLI unit tests // Register Jest matcher extensions for CLI unit tests
import './matchers'; import './matchers';
@@ -73,6 +75,8 @@ export class MockClient extends Client {
}); });
this.scenario = Router(); this.scenario = Router();
this.reset();
} }
reset() { reset() {
@@ -99,11 +103,14 @@ export class MockClient extends Client {
}; };
this.config = {}; this.config = {};
this.localConfig = {}; this.localConfig = {};
this.localConfigPath = undefined;
this.scenario = Router(); this.scenario = Router();
this.agent?.destroy(); this.agent?.destroy();
this.agent = undefined; this.agent = undefined;
this.cwd = originalCwd;
} }
async startMockServer() { async startMockServer() {
@@ -156,7 +163,7 @@ beforeAll(async () => {
await client.startMockServer(); await client.startMockServer();
}); });
beforeEach(() => { afterEach(() => {
client.reset(); client.reset();
}); });

File diff suppressed because it is too large Load Diff

View File

@@ -141,232 +141,206 @@ describe('deploy', () => {
}); });
it('should send a tgz file when `--archive=tgz`', async () => { it('should send a tgz file when `--archive=tgz`', async () => {
const cwd = setupUnitFixture('commands/deploy/static'); const user = useUser();
const originalCwd = process.cwd(); useTeams('team_dummy');
try { useProject({
process.chdir(cwd); ...defaultProject,
name: 'static',
id: 'static',
});
const user = useUser(); let body: any;
useTeams('team_dummy'); client.scenario.post(`/v13/deployments`, (req, res) => {
useProject({ body = req.body;
...defaultProject, res.json({
name: 'static', creator: {
id: 'static', uid: user.id,
username: user.username,
},
id: 'dpl_archive_test',
}); });
});
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: [],
});
});
let body: any; client.cwd = setupUnitFixture('commands/deploy/static');
client.scenario.post(`/v13/deployments`, (req, res) => { client.setArgv('deploy', '--archive=tgz');
body = req.body; const exitCode = await deploy(client);
res.json({ expect(exitCode).toEqual(0);
creator: { expect(body?.files?.length).toEqual(1);
uid: user.id, expect(body?.files?.[0].file).toEqual('.vercel/source.tgz');
username: user.username,
},
id: 'dpl_archive_test',
});
});
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: [],
});
}
);
client.setArgv('deploy', '--archive=tgz');
const exitCode = await deploy(client);
expect(exitCode).toEqual(0);
expect(body?.files?.length).toEqual(1);
expect(body?.files?.[0].file).toEqual('.vercel/source.tgz');
} finally {
process.chdir(originalCwd);
}
}); });
it('should pass flag to skip custom domain assignment', async () => { it('should pass flag to skip custom domain assignment', async () => {
const cwd = setupUnitFixture('commands/deploy/static'); const user = useUser();
const originalCwd = process.cwd(); useTeams('team_dummy');
try { useProject({
process.chdir(cwd); ...defaultProject,
name: 'static',
id: 'static',
});
const user = useUser(); let body: any;
useTeams('team_dummy'); client.scenario.post(`/v13/deployments`, (req, res) => {
useProject({ body = req.body;
...defaultProject, res.json({
name: 'static', creator: {
id: 'static', uid: user.id,
username: user.username,
},
id: 'dpl_archive_test',
}); });
});
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: [],
});
});
let body: any; client.cwd = setupUnitFixture('commands/deploy/static');
client.scenario.post(`/v13/deployments`, (req, res) => { client.setArgv('deploy', '--prod', '--skip-domain');
body = req.body; const exitCode = await deploy(client);
res.json({ expect(exitCode).toEqual(0);
creator: { expect(body).toMatchObject({
uid: user.id, target: 'production',
username: user.username, source: 'cli',
}, autoAssignCustomDomains: false,
id: 'dpl_archive_test', version: 2,
}); });
});
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.setArgv('deploy', '--prod', '--skip-domain');
const exitCode = await deploy(client);
expect(exitCode).toEqual(0);
expect(body).toMatchObject({
target: 'production',
source: 'cli',
autoAssignCustomDomains: false,
version: 2,
});
} finally {
process.chdir(originalCwd);
}
}); });
it('should upload missing files', async () => { it('should upload missing files', async () => {
const cwd = setupUnitFixture('commands/deploy/static'); const cwd = setupUnitFixture('commands/deploy/static');
const originalCwd = process.cwd(); client.cwd = cwd;
// Add random 1mb file // Add random 1mb file
await fs.writeFile(join(cwd, 'data'), randomBytes(bytes('1mb'))); await fs.writeFile(join(cwd, 'data'), randomBytes(bytes('1mb')));
try { const user = useUser();
process.chdir(cwd); useTeams('team_dummy');
useProject({
...defaultProject,
name: 'static',
id: 'static',
});
const user = useUser(); let body: any;
useTeams('team_dummy'); let fileUploaded = false;
useProject({ client.scenario.post(`/v13/deployments`, (req, res) => {
...defaultProject, if (fileUploaded) {
name: 'static', body = req.body;
id: 'static',
});
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({ res.json({
creator: { creator: {
uid: user.id, uid: user.id,
username: user.username, username: user.username,
}, },
id: 'dpl_archive_test', id: 'dpl_archive_test',
readyState: 'READY',
aliasAssigned: true,
alias: [],
}); });
} 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
}); });
client.scenario.get( req.on('end', () => {
`/v10/now/deployments/dpl_archive_test`, fileUploaded = true;
(req, res) => { res.end();
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); client.scenario.get(`/v13/deployments/dpl_archive_test`, (req, res) => {
expect(exitCode).toEqual(0); res.json({
expect(body?.files?.length).toEqual(1); creator: {
expect(body?.files?.[0].file).toEqual('.vercel/source.tgz'); uid: user.id,
expect(uploadingLines.length).toEqual(5); username: user.username,
expect( },
uploadingLines[0].startsWith('Uploading [--------------------]') id: 'dpl_archive_test',
).toEqual(true); readyState: 'READY',
expect( aliasAssigned: true,
uploadingLines[1].startsWith('Uploading [=====---------------]') alias: [],
).toEqual(true); });
expect( });
uploadingLines[2].startsWith('Uploading [==========----------]') client.scenario.get(`/v10/now/deployments/dpl_archive_test`, (req, res) => {
).toEqual(true); res.json({
expect( creator: {
uploadingLines[3].startsWith('Uploading [===============-----]') uid: user.id,
).toEqual(true); username: user.username,
expect( },
uploadingLines[4].startsWith('Uploading [====================]') id: 'dpl_archive_test',
).toEqual(true); readyState: 'READY',
} finally { aliasAssigned: true,
process.chdir(originalCwd); 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);
}); });
}); });

View File

@@ -11,7 +11,6 @@ import { useUser } from '../../mocks/user';
describe('env', () => { describe('env', () => {
describe('pull', () => { describe('pull', () => {
it('should handle pulling', async () => { it('should handle pulling', async () => {
const cwd = setupUnitFixture('vercel-env-pull');
useUser(); useUser();
useTeams('team_dummy'); useTeams('team_dummy');
useProject({ useProject({
@@ -19,7 +18,9 @@ describe('env', () => {
id: 'vercel-env-pull', id: 'vercel-env-pull',
name: 'vercel-env-pull', name: 'vercel-env-pull',
}); });
client.setArgv('env', 'pull', '--yes', '--cwd', cwd); const cwd = setupUnitFixture('vercel-env-pull');
client.cwd = cwd;
client.setArgv('env', 'pull', '--yes');
const exitCodePromise = env(client); const exitCodePromise = env(client);
await expect(client.stderr).toOutput( await expect(client.stderr).toOutput(
'Downloading `development` Environment Variables for Project vercel-env-pull' 'Downloading `development` Environment Variables for Project vercel-env-pull'
@@ -35,7 +36,6 @@ describe('env', () => {
}); });
it('should handle pulling from Preview env vars', async () => { it('should handle pulling from Preview env vars', async () => {
const cwd = setupUnitFixture('vercel-env-pull');
useUser(); useUser();
useTeams('team_dummy'); useTeams('team_dummy');
useProject({ useProject({
@@ -43,15 +43,9 @@ describe('env', () => {
id: 'vercel-env-pull', id: 'vercel-env-pull',
name: 'vercel-env-pull', name: 'vercel-env-pull',
}); });
client.setArgv( const cwd = setupUnitFixture('vercel-env-pull');
'env', client.cwd = cwd;
'pull', client.setArgv('env', 'pull', '--yes', '--environment', 'preview');
'--yes',
'--cwd',
cwd,
'--environment',
'preview'
);
const exitCodePromise = env(client); const exitCodePromise = env(client);
await expect(client.stderr).toOutput( await expect(client.stderr).toOutput(
'Downloading `preview` Environment Variables for Project vercel-env-pull' 'Downloading `preview` Environment Variables for Project vercel-env-pull'
@@ -70,7 +64,6 @@ describe('env', () => {
}); });
it('should handle pulling from specific Git branch', async () => { it('should handle pulling from specific Git branch', async () => {
const cwd = setupUnitFixture('vercel-env-pull');
useUser(); useUser();
useTeams('team_dummy'); useTeams('team_dummy');
useProject({ useProject({
@@ -78,12 +71,12 @@ describe('env', () => {
id: 'vercel-env-pull', id: 'vercel-env-pull',
name: 'vercel-env-pull', name: 'vercel-env-pull',
}); });
const cwd = setupUnitFixture('vercel-env-pull');
client.cwd = cwd;
client.setArgv( client.setArgv(
'env', 'env',
'pull', 'pull',
'--yes', '--yes',
'--cwd',
cwd,
'--environment', '--environment',
'preview', 'preview',
'--git-branch', '--git-branch',
@@ -114,7 +107,6 @@ describe('env', () => {
}); });
it('should handle alternate filename', async () => { it('should handle alternate filename', async () => {
const cwd = setupUnitFixture('vercel-env-pull');
useUser(); useUser();
useTeams('team_dummy'); useTeams('team_dummy');
useProject({ useProject({
@@ -122,7 +114,9 @@ describe('env', () => {
id: 'vercel-env-pull', id: 'vercel-env-pull',
name: 'vercel-env-pull', name: 'vercel-env-pull',
}); });
client.setArgv('env', 'pull', 'other.env', '--yes', '--cwd', cwd); const cwd = setupUnitFixture('vercel-env-pull');
client.cwd = cwd;
client.setArgv('env', 'pull', 'other.env', '--yes');
const exitCodePromise = env(client); const exitCodePromise = env(client);
await expect(client.stderr).toOutput( await expect(client.stderr).toOutput(
'Downloading `development` Environment Variables for Project vercel-env-pull' 'Downloading `development` Environment Variables for Project vercel-env-pull'
@@ -138,7 +132,6 @@ describe('env', () => {
}); });
it('should use given environment', async () => { it('should use given environment', async () => {
const cwd = setupUnitFixture('vercel-env-pull');
useUser(); useUser();
useTeams('team_dummy'); useTeams('team_dummy');
useProject({ useProject({
@@ -146,15 +139,9 @@ describe('env', () => {
id: 'vercel-env-pull', id: 'vercel-env-pull',
name: 'vercel-env-pull', name: 'vercel-env-pull',
}); });
const cwd = setupUnitFixture('vercel-env-pull');
client.setArgv( client.cwd = cwd;
'env', client.setArgv('env', 'pull', '--environment', 'production');
'pull',
'--environment',
'production',
'--cwd',
cwd
);
const exitCodePromise = env(client); const exitCodePromise = env(client);
await expect(client.stderr).toOutput( await expect(client.stderr).toOutput(
`Downloading \`production\` Environment Variables for Project vercel-env-pull` `Downloading \`production\` Environment Variables for Project vercel-env-pull`
@@ -172,7 +159,6 @@ describe('env', () => {
}); });
it('should throw an error when it does not recognize given environment', async () => { it('should throw an error when it does not recognize given environment', async () => {
const cwd = setupUnitFixture('vercel-env-pull');
useUser(); useUser();
useTeams('team_dummy'); useTeams('team_dummy');
useProject({ useProject({
@@ -180,15 +166,14 @@ describe('env', () => {
id: 'vercel-env-pull', id: 'vercel-env-pull',
name: 'vercel-env-pull', name: 'vercel-env-pull',
}); });
const cwd = setupUnitFixture('vercel-env-pull');
client.cwd = cwd;
client.setArgv( client.setArgv(
'env', 'env',
'pull', 'pull',
'.env.production', '.env.production',
'--environment', '--environment',
'something-invalid', 'something-invalid'
'--cwd',
cwd
); );
const exitCodePromise = env(client); const exitCodePromise = env(client);
@@ -200,7 +185,6 @@ describe('env', () => {
}); });
it('should expose production system env variables', async () => { it('should expose production system env variables', async () => {
const cwd = setupUnitFixture('vercel-env-pull');
useUser(); useUser();
useTeams('team_dummy'); useTeams('team_dummy');
useProject({ useProject({
@@ -209,8 +193,9 @@ describe('env', () => {
name: 'vercel-env-pull', name: 'vercel-env-pull',
autoExposeSystemEnvs: true, autoExposeSystemEnvs: true,
}); });
const cwd = setupUnitFixture('vercel-env-pull');
client.setArgv('env', 'pull', 'other.env', '--yes', '--cwd', cwd); client.cwd = cwd;
client.setArgv('env', 'pull', 'other.env', '--yes');
const exitCodePromise = env(client); const exitCodePromise = env(client);
await expect(client.stderr).toOutput( await expect(client.stderr).toOutput(
'Downloading `development` Environment Variables for Project vercel-env-pull' 'Downloading `development` Environment Variables for Project vercel-env-pull'
@@ -228,6 +213,7 @@ describe('env', () => {
it('should show a delta string', async () => { it('should show a delta string', async () => {
const cwd = setupUnitFixture('vercel-env-pull-delta'); const cwd = setupUnitFixture('vercel-env-pull-delta');
client.cwd = cwd;
try { try {
useUser(); useUser();
useTeams('team_dummy'); useTeams('team_dummy');
@@ -237,7 +223,7 @@ describe('env', () => {
name: 'env-pull-delta', name: 'env-pull-delta',
}); });
client.setArgv('env', 'add', 'NEW_VAR', '--cwd', cwd); client.setArgv('env', 'add', 'NEW_VAR');
const addPromise = env(client); const addPromise = env(client);
await expect(client.stderr).toOutput('Whats the value of NEW_VAR?'); await expect(client.stderr).toOutput('Whats the value of NEW_VAR?');
@@ -253,7 +239,7 @@ describe('env', () => {
await expect(addPromise).resolves.toEqual(0); await expect(addPromise).resolves.toEqual(0);
client.setArgv('env', 'pull', '--yes', '--cwd', cwd); client.setArgv('env', 'pull', '--yes');
const pullPromise = env(client); const pullPromise = env(client);
await expect(client.stderr).toOutput( await expect(client.stderr).toOutput(
'Downloading `development` Environment Variables for Project env-pull-delta' 'Downloading `development` Environment Variables for Project env-pull-delta'
@@ -265,13 +251,12 @@ describe('env', () => {
await expect(pullPromise).resolves.toEqual(0); await expect(pullPromise).resolves.toEqual(0);
} finally { } finally {
client.setArgv('env', 'rm', 'NEW_VAR', '--yes', '--cwd', cwd); client.setArgv('env', 'rm', 'NEW_VAR', '--yes');
await env(client); await env(client);
} }
}); });
it('should not show a delta string when it fails to read a file', async () => { it('should not show a delta string when it fails to read a file', async () => {
const cwd = setupUnitFixture('vercel-env-pull-delta-corrupt');
useUser(); useUser();
useTeams('team_dummy'); useTeams('team_dummy');
useProject({ useProject({
@@ -279,15 +264,15 @@ describe('env', () => {
id: 'env-pull-delta-corrupt', id: 'env-pull-delta-corrupt',
name: 'env-pull-delta-corrupt', name: 'env-pull-delta-corrupt',
}); });
const cwd = setupUnitFixture('vercel-env-pull-delta-corrupt');
client.setArgv('env', 'pull', '--yes', '--cwd', cwd); client.cwd = cwd;
client.setArgv('env', 'pull', '--yes');
const pullPromise = env(client); const pullPromise = env(client);
await expect(client.stderr).toOutput('Updated .env.local file'); await expect(client.stderr).toOutput('Updated .env.local file');
await expect(pullPromise).resolves.toEqual(0); await expect(pullPromise).resolves.toEqual(0);
}); });
it('should show that no changes were found', async () => { it('should show that no changes were found', async () => {
const cwd = setupUnitFixture('vercel-env-pull-delta-no-changes');
useUser(); useUser();
useTeams('team_dummy'); useTeams('team_dummy');
useProject({ useProject({
@@ -295,8 +280,8 @@ describe('env', () => {
id: 'env-pull-delta-no-changes', id: 'env-pull-delta-no-changes',
name: 'env-pull-delta-no-changes', name: 'env-pull-delta-no-changes',
}); });
client.cwd = setupUnitFixture('vercel-env-pull-delta-no-changes');
client.setArgv('env', 'pull', '--yes', '--cwd', cwd); client.setArgv('env', 'pull', '--yes');
const pullPromise = env(client); const pullPromise = env(client);
await expect(client.stderr).toOutput('> No changes found.'); await expect(client.stderr).toOutput('> No changes found.');
await expect(client.stderr).toOutput('Updated .env.local file'); await expect(client.stderr).toOutput('Updated .env.local file');
@@ -305,6 +290,7 @@ describe('env', () => {
it('should correctly render delta string when env variable has quotes', async () => { it('should correctly render delta string when env variable has quotes', async () => {
const cwd = setupUnitFixture('vercel-env-pull-delta-quotes'); const cwd = setupUnitFixture('vercel-env-pull-delta-quotes');
client.cwd = cwd;
try { try {
useUser(); useUser();
useTeams('team_dummy'); useTeams('team_dummy');
@@ -329,7 +315,7 @@ describe('env', () => {
] ]
); );
client.setArgv('env', 'pull', '--yes', '--cwd', cwd); client.setArgv('env', 'pull', '--yes');
const pullPromise = env(client); const pullPromise = env(client);
await expect(client.stderr).toOutput( await expect(client.stderr).toOutput(
'Downloading `development` Environment Variables for Project env-pull-delta' 'Downloading `development` Environment Variables for Project env-pull-delta'
@@ -339,13 +325,14 @@ describe('env', () => {
await expect(pullPromise).resolves.toEqual(0); await expect(pullPromise).resolves.toEqual(0);
} finally { } finally {
client.setArgv('env', 'rm', 'NEW_VAR', '--yes', '--cwd', cwd); client.setArgv('env', 'rm', 'NEW_VAR', '--yes');
await env(client); await env(client);
} }
}); });
it('should correctly render delta string when local env variable has quotes', async () => { it('should correctly render delta string when local env variable has quotes', async () => {
const cwd = setupUnitFixture('vercel-env-pull-delta-quotes'); const cwd = setupUnitFixture('vercel-env-pull-delta-quotes');
client.cwd = cwd;
try { try {
useUser(); useUser();
useTeams('team_dummy'); useTeams('team_dummy');
@@ -370,7 +357,7 @@ describe('env', () => {
] ]
); );
client.setArgv('env', 'pull', '.env.testquotes', '--yes', '--cwd', cwd); client.setArgv('env', 'pull', '.env.testquotes', '--yes');
const pullPromise = env(client); const pullPromise = env(client);
await expect(client.stderr).toOutput( await expect(client.stderr).toOutput(
'Downloading `development` Environment Variables for Project env-pull-delta' 'Downloading `development` Environment Variables for Project env-pull-delta'
@@ -380,7 +367,7 @@ describe('env', () => {
await expect(pullPromise).resolves.toEqual(0); await expect(pullPromise).resolves.toEqual(0);
} finally { } finally {
client.setArgv('env', 'rm', 'NEW_VAR', '--yes', '--cwd', cwd); client.setArgv('env', 'rm', 'NEW_VAR', '--yes');
await env(client); await env(client);
} }
}); });

View File

@@ -9,14 +9,13 @@ import type { Project } from '@vercel-internals/types';
describe('git', () => { describe('git', () => {
describe('connect', () => { describe('connect', () => {
const originalCwd = process.cwd();
const fixture = (name: string) => const fixture = (name: string) =>
join(__dirname, '../../fixtures/unit/commands/git/connect', name); join(__dirname, '../../fixtures/unit/commands/git/connect', name);
it('connects an unlinked project', async () => { it('connects an unlinked project', async () => {
const cwd = fixture('unlinked'); const cwd = fixture('unlinked');
client.cwd = cwd;
try { try {
process.chdir(cwd);
await fs.rename(join(cwd, 'git'), join(cwd, '.git')); await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
useUser(); useUser();
useTeams('team_dummy'); useTeams('team_dummy');
@@ -62,13 +61,12 @@ describe('git', () => {
}); });
} finally { } finally {
await fs.rename(join(cwd, '.git'), join(cwd, 'git')); await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
process.chdir(originalCwd);
} }
}); });
it('connects an unlinked project with a remote url', async () => { it('connects an unlinked project with a remote url', async () => {
const cwd = fixture('unlinked'); const cwd = fixture('unlinked');
client.cwd = cwd;
try { try {
process.chdir(cwd);
await fs.rename(join(cwd, 'git'), join(cwd, '.git')); await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
useUser(); useUser();
useTeams('team_dummy'); useTeams('team_dummy');
@@ -119,34 +117,28 @@ describe('git', () => {
}); });
} finally { } finally {
await fs.rename(join(cwd, '.git'), join(cwd, 'git')); await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
process.chdir(originalCwd);
} }
}); });
it('should fail when there is no git config', async () => { it('should fail when there is no git config', async () => {
const cwd = fixture('no-git-config'); client.cwd = fixture('no-git-config');
try { useUser();
process.chdir(cwd); useTeams('team_dummy');
useUser(); useProject({
useTeams('team_dummy'); ...defaultProject,
useProject({ id: 'no-git-config',
...defaultProject, name: 'no-git-config',
id: 'no-git-config', });
name: 'no-git-config', client.setArgv('git', 'connect', '--yes');
}); const exitCode = await git(client);
client.setArgv('git', 'connect', '--yes'); expect(exitCode).toEqual(1);
const exitCode = await git(client); await expect(client.stderr).toOutput(
expect(exitCode).toEqual(1); `Error: No local Git repository found. Run \`git clone <url>\` to clone a remote Git repository first.\n`
await expect(client.stderr).toOutput( );
`Error: No local Git repository found. Run \`git clone <url>\` to clone a remote Git repository first.\n`
);
} finally {
process.chdir(originalCwd);
}
}); });
it('should fail when there is no remote url', async () => { it('should fail when there is no remote url', async () => {
const cwd = fixture('no-remote-url'); const cwd = fixture('no-remote-url');
client.cwd = cwd;
try { try {
process.chdir(cwd);
await fs.rename(join(cwd, 'git'), join(cwd, '.git')); await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
useUser(); useUser();
useTeams('team_dummy'); useTeams('team_dummy');
@@ -163,13 +155,12 @@ describe('git', () => {
); );
} finally { } finally {
await fs.rename(join(cwd, '.git'), join(cwd, 'git')); await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
process.chdir(originalCwd);
} }
}); });
it('should fail when the remote url is bad', async () => { it('should fail when the remote url is bad', async () => {
const cwd = fixture('bad-remote-url'); const cwd = fixture('bad-remote-url');
client.cwd = cwd;
try { try {
process.chdir(cwd);
await fs.rename(join(cwd, 'git'), join(cwd, '.git')); await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
useUser(); useUser();
useTeams('team_dummy'); useTeams('team_dummy');
@@ -190,13 +181,12 @@ describe('git', () => {
); );
} finally { } finally {
await fs.rename(join(cwd, '.git'), join(cwd, 'git')); await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
process.chdir(originalCwd);
} }
}); });
it('should connect a repo to a project that is not already connected', async () => { it('should connect a repo to a project that is not already connected', async () => {
const cwd = fixture('new-connection'); const cwd = fixture('new-connection');
client.cwd = cwd;
try { try {
process.chdir(cwd);
await fs.rename(join(cwd, 'git'), join(cwd, '.git')); await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
useUser(); useUser();
useTeams('team_dummy'); useTeams('team_dummy');
@@ -232,13 +222,12 @@ describe('git', () => {
}); });
} finally { } finally {
await fs.rename(join(cwd, '.git'), join(cwd, 'git')); await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
process.chdir(originalCwd);
} }
}); });
it('should replace an old connection with a new one', async () => { it('should replace an old connection with a new one', async () => {
const cwd = fixture('existing-connection'); const cwd = fixture('existing-connection');
client.cwd = cwd;
try { try {
process.chdir(cwd);
await fs.rename(join(cwd, 'git'), join(cwd, '.git')); await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
useUser(); useUser();
useTeams('team_dummy'); useTeams('team_dummy');
@@ -285,13 +274,12 @@ describe('git', () => {
}); });
} finally { } finally {
await fs.rename(join(cwd, '.git'), join(cwd, 'git')); await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
process.chdir(originalCwd);
} }
}); });
it('should exit when an already-connected repo is connected', async () => { it('should exit when an already-connected repo is connected', async () => {
const cwd = fixture('new-connection'); const cwd = fixture('new-connection');
client.cwd = cwd;
try { try {
process.chdir(cwd);
await fs.rename(join(cwd, 'git'), join(cwd, '.git')); await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
useUser(); useUser();
useTeams('team_dummy'); useTeams('team_dummy');
@@ -324,13 +312,12 @@ describe('git', () => {
expect(exitCode).toEqual(1); expect(exitCode).toEqual(1);
} finally { } finally {
await fs.rename(join(cwd, '.git'), join(cwd, 'git')); await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
process.chdir(originalCwd);
} }
}); });
it('should fail when it cannot find the repository', async () => { it('should fail when it cannot find the repository', async () => {
const cwd = fixture('invalid-repo'); const cwd = fixture('invalid-repo');
client.cwd = cwd;
try { try {
process.chdir(cwd);
await fs.rename(join(cwd, 'git'), join(cwd, '.git')); await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
useUser(); useUser();
useTeams('team_dummy'); useTeams('team_dummy');
@@ -354,13 +341,12 @@ describe('git', () => {
expect(exitCode).toEqual(1); expect(exitCode).toEqual(1);
} finally { } finally {
await fs.rename(join(cwd, '.git'), join(cwd, 'git')); await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
process.chdir(originalCwd);
} }
}); });
it('should connect the default option of multiple remotes', async () => { it('should connect the default option of multiple remotes', async () => {
const cwd = fixture('multiple-remotes'); const cwd = fixture('multiple-remotes');
client.cwd = cwd;
try { try {
process.chdir(cwd);
await fs.rename(join(cwd, 'git'), join(cwd, '.git')); await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
useUser(); useUser();
useTeams('team_dummy'); useTeams('team_dummy');
@@ -404,19 +390,17 @@ describe('git', () => {
}); });
} finally { } finally {
await fs.rename(join(cwd, '.git'), join(cwd, 'git')); await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
process.chdir(originalCwd);
} }
}); });
}); });
describe('disconnect', () => { describe('disconnect', () => {
const originalCwd = process.cwd();
const fixture = (name: string) => const fixture = (name: string) =>
join(__dirname, '../../fixtures/unit/commands/git/connect', name); join(__dirname, '../../fixtures/unit/commands/git/connect', name);
it('should disconnect a repository', async () => { it('should disconnect a repository', async () => {
const cwd = fixture('new-connection'); const cwd = fixture('new-connection');
client.cwd = cwd;
try { try {
process.chdir(cwd);
await fs.rename(join(cwd, 'git'), join(cwd, '.git')); await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
useUser(); useUser();
useTeams('team_dummy'); useTeams('team_dummy');
@@ -453,13 +437,12 @@ describe('git', () => {
expect(exitCode).toEqual(0); expect(exitCode).toEqual(0);
} finally { } finally {
await fs.rename(join(cwd, '.git'), join(cwd, 'git')); await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
process.chdir(originalCwd);
} }
}); });
it('should fail if there is no repository to disconnect', async () => { it('should fail if there is no repository to disconnect', async () => {
const cwd = fixture('new-connection'); const cwd = fixture('new-connection');
client.cwd = cwd;
try { try {
process.chdir(cwd);
await fs.rename(join(cwd, 'git'), join(cwd, '.git')); await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
useUser(); useUser();
useTeams('team_dummy'); useTeams('team_dummy');
@@ -480,13 +463,12 @@ describe('git', () => {
expect(exitCode).toEqual(1); expect(exitCode).toEqual(1);
} finally { } finally {
await fs.rename(join(cwd, '.git'), join(cwd, 'git')); await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
process.chdir(originalCwd);
} }
}); });
it('should connect a given repository', async () => { it('should connect a given repository', async () => {
const cwd = fixture('no-remote-url'); const cwd = fixture('no-remote-url');
client.cwd = cwd;
try { try {
process.chdir(cwd);
await fs.rename(join(cwd, 'git'), join(cwd, '.git')); await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
useUser(); useUser();
useTeams('team_dummy'); useTeams('team_dummy');
@@ -522,13 +504,12 @@ describe('git', () => {
await expect(gitPromise).resolves.toEqual(0); await expect(gitPromise).resolves.toEqual(0);
} finally { } finally {
await fs.rename(join(cwd, '.git'), join(cwd, 'git')); await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
process.chdir(originalCwd);
} }
}); });
it('should prompt when it finds a repository', async () => { it('should prompt when it finds a repository', async () => {
const cwd = fixture('new-connection'); const cwd = fixture('new-connection');
client.cwd = cwd;
try { try {
process.chdir(cwd);
await fs.rename(join(cwd, 'git'), join(cwd, '.git')); await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
useUser(); useUser();
useTeams('team_dummy'); useTeams('team_dummy');
@@ -571,13 +552,12 @@ describe('git', () => {
await expect(gitPromise).resolves.toEqual(0); await expect(gitPromise).resolves.toEqual(0);
} finally { } finally {
await fs.rename(join(cwd, '.git'), join(cwd, 'git')); await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
process.chdir(originalCwd);
} }
}); });
it('should prompt when it finds multiple remotes', async () => { it('should prompt when it finds multiple remotes', async () => {
const cwd = fixture('multiple-remotes'); const cwd = fixture('multiple-remotes');
client.cwd = cwd;
try { try {
process.chdir(cwd);
await fs.rename(join(cwd, 'git'), join(cwd, '.git')); await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
useUser(); useUser();
useTeams('team_dummy'); useTeams('team_dummy');
@@ -621,13 +601,12 @@ describe('git', () => {
await expect(gitPromise).resolves.toEqual(0); await expect(gitPromise).resolves.toEqual(0);
} finally { } finally {
await fs.rename(join(cwd, '.git'), join(cwd, 'git')); await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
process.chdir(originalCwd);
} }
}); });
it('should continue as normal when input matches single git remote', async () => { it('should continue as normal when input matches single git remote', async () => {
const cwd = fixture('new-connection'); const cwd = fixture('new-connection');
client.cwd = cwd;
try { try {
process.chdir(cwd);
await fs.rename(join(cwd, 'git'), join(cwd, '.git')); await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
useUser(); useUser();
useTeams('team_dummy'); useTeams('team_dummy');
@@ -663,7 +642,6 @@ describe('git', () => {
await expect(gitPromise).resolves.toEqual(0); await expect(gitPromise).resolves.toEqual(0);
} finally { } finally {
await fs.rename(join(cwd, '.git'), join(cwd, 'git')); await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
process.chdir(originalCwd);
} }
}); });
}); });

View File

@@ -12,12 +12,10 @@ import {
import { tmpdir } from 'os'; import { tmpdir } from 'os';
describe('link', () => { describe('link', () => {
const origCwd = process.cwd();
it('should prompt for link', async () => { it('should prompt for link', async () => {
const cwd = await mkdtemp(join(tmpdir(), 'cli-')); const cwd = await mkdtemp(join(tmpdir(), 'cli-'));
client.cwd = cwd;
try { try {
process.chdir(cwd);
const user = useUser(); const user = useUser();
useTeams('team_dummy'); useTeams('team_dummy');
const { project } = useProject({ const { project } = useProject({
@@ -50,15 +48,14 @@ describe('link', () => {
expect(projectJson.orgId).toEqual(user.id); expect(projectJson.orgId).toEqual(user.id);
expect(projectJson.projectId).toEqual(project.id); expect(projectJson.projectId).toEqual(project.id);
} finally { } finally {
process.chdir(origCwd);
await remove(cwd); await remove(cwd);
} }
}); });
it('should allow specifying `--project` flag', async () => { it('should allow specifying `--project` flag', async () => {
const cwd = await mkdtemp(join(tmpdir(), 'cli-')); const cwd = await mkdtemp(join(tmpdir(), 'cli-'));
client.cwd = cwd;
try { try {
process.chdir(cwd);
const user = useUser(); const user = useUser();
useTeams('team_dummy'); useTeams('team_dummy');
const { project } = useProject({ const { project } = useProject({
@@ -81,15 +78,14 @@ describe('link', () => {
expect(projectJson.orgId).toEqual(user.id); expect(projectJson.orgId).toEqual(user.id);
expect(projectJson.projectId).toEqual(project.id); expect(projectJson.projectId).toEqual(project.id);
} finally { } finally {
process.chdir(origCwd);
await remove(cwd); await remove(cwd);
} }
}); });
it('should allow overwriting existing link', async () => { it('should allow overwriting existing link', async () => {
const cwd = await mkdtemp(join(tmpdir(), 'cli-')); const cwd = await mkdtemp(join(tmpdir(), 'cli-'));
client.cwd = cwd;
try { try {
process.chdir(cwd);
const user = useUser(); const user = useUser();
useTeams('team_dummy'); useTeams('team_dummy');
const { project: proj1 } = useProject({ const { project: proj1 } = useProject({
@@ -118,7 +114,6 @@ describe('link', () => {
expect(projectJson.orgId).toEqual(user.id); expect(projectJson.orgId).toEqual(user.id);
expect(projectJson.projectId).toEqual(proj2.id); expect(projectJson.projectId).toEqual(proj2.id);
} finally { } finally {
process.chdir(origCwd);
await remove(cwd); await remove(cwd);
} }
}); });

View File

@@ -18,179 +18,160 @@ const fixture = (name: string) =>
join(__dirname, '../../fixtures/unit/commands/list', name); join(__dirname, '../../fixtures/unit/commands/list', name);
describe('list', () => { describe('list', () => {
const originalCwd = process.cwd();
let teamSlug: string; let teamSlug: string;
it('should get deployments from a project linked by a directory', async () => { it('should get deployments from a project linked by a directory', async () => {
const cwd = fixture('with-team'); const user = useUser();
try { const team = useTeams('team_dummy');
process.chdir(cwd); teamSlug = team[0].slug;
useProject({
...defaultProject,
id: 'with-team',
name: 'with-team',
});
const deployment = useDeployment({ creator: user });
const user = useUser(); client.cwd = fixture('with-team');
const team = useTeams('team_dummy'); await list(client);
teamSlug = team[0].slug;
useProject({
...defaultProject,
id: 'with-team',
name: 'with-team',
});
const deployment = useDeployment({ creator: user });
await list(client); const lines = createLineIterator(client.stderr);
const lines = createLineIterator(client.stderr); let line = await lines.next();
expect(line.value).toEqual('Retrieving project…');
let line = await lines.next(); line = await lines.next();
expect(line.value).toEqual('Retrieving project…'); expect(line.value).toEqual(`Fetching deployments in ${team[0].slug}`);
line = await lines.next(); line = await lines.next();
expect(line.value).toEqual(`Fetching deployments in ${team[0].slug}`); const { org } = pluckIdentifiersFromDeploymentList(line.value!);
expect(org).toEqual(team[0].slug);
line = await lines.next(); // skip next line
const { org } = pluckIdentifiersFromDeploymentList(line.value!); await lines.next();
expect(org).toEqual(team[0].slug);
// skip next line line = await lines.next();
await lines.next(); expect(line.value).toEqual('');
line = await lines.next(); line = await lines.next();
expect(line.value).toEqual(''); const header = parseSpacedTableRow(line.value!);
expect(header).toEqual([
'Age',
'Deployment',
'Status',
'Duration',
'Username',
]);
line = await lines.next(); line = await lines.next();
const header = parseSpacedTableRow(line.value!); const data = parseSpacedTableRow(line.value!);
expect(header).toEqual([ data.shift();
'Age', expect(data).toEqual([
'Deployment', `https://${deployment.url}`,
'Status', stateString(deployment.state || ''),
'Duration', getDeploymentDuration(deployment),
'Username', user.username,
]); ]);
line = await lines.next();
const data = parseSpacedTableRow(line.value!);
data.shift();
expect(data).toEqual([
`https://${deployment.url}`,
stateString(deployment.state || ''),
getDeploymentDuration(deployment),
user.username,
]);
} finally {
process.chdir(originalCwd);
}
}); });
it('should get deployments for linked project where the scope is a user', async () => { it('should get deployments for linked project where the scope is a user', async () => {
const cwd = fixture('with-team'); const user = useUser();
try { useTeams('team_dummy');
process.chdir(cwd); useProject({
...defaultProject,
id: 'with-team',
name: 'with-team',
});
const deployment = useDeployment({ creator: user });
const user = useUser(); client.cwd = fixture('with-team');
useTeams('team_dummy'); client.setArgv('-S', user.username);
useProject({ await list(client);
...defaultProject,
id: 'with-team',
name: 'with-team',
});
const deployment = useDeployment({ creator: user });
client.setArgv('-S', user.username); const lines = createLineIterator(client.stderr);
await list(client);
const lines = createLineIterator(client.stderr); let line = await lines.next();
expect(line.value).toEqual('Retrieving project…');
let line = await lines.next(); line = await lines.next();
expect(line.value).toEqual('Retrieving project…'); expect(line.value).toEqual(`Fetching deployments in ${user.username}`);
line = await lines.next(); line = await lines.next();
expect(line.value).toEqual(`Fetching deployments in ${user.username}`); const { org } = pluckIdentifiersFromDeploymentList(line.value!);
expect(org).toEqual(user.username);
line = await lines.next(); // skip next line
const { org } = pluckIdentifiersFromDeploymentList(line.value!); await lines.next();
expect(org).toEqual(user.username);
// skip next line line = await lines.next();
await lines.next(); expect(line.value).toEqual('');
line = await lines.next(); line = await lines.next();
expect(line.value).toEqual(''); const header = parseSpacedTableRow(line.value!);
expect(header).toEqual(['Age', 'Deployment', 'Status', 'Duration']);
line = await lines.next(); line = await lines.next();
const header = parseSpacedTableRow(line.value!); const data = parseSpacedTableRow(line.value!);
expect(header).toEqual(['Age', 'Deployment', 'Status', 'Duration']); data.shift();
line = await lines.next(); expect(data).toEqual([
const data = parseSpacedTableRow(line.value!); 'https://' + deployment.url,
data.shift(); stateString(deployment.state || ''),
getDeploymentDuration(deployment),
expect(data).toEqual([ ]);
'https://' + deployment.url,
stateString(deployment.state || ''),
getDeploymentDuration(deployment),
]);
} finally {
process.chdir(originalCwd);
}
}); });
it('should get the deployments for a specified project', async () => { it('should get the deployments for a specified project', async () => {
const cwd = fixture('with-team'); const user = useUser();
try { const team = useTeams('team_dummy');
process.chdir(cwd); useProject({
...defaultProject,
id: 'with-team',
name: 'with-team',
});
const deployment = useDeployment({ creator: user });
const user = useUser(); client.cwd = fixture('with-team');
const team = useTeams('team_dummy'); client.setArgv(deployment.name);
useProject({ await list(client);
...defaultProject,
id: 'with-team',
name: 'with-team',
});
const deployment = useDeployment({ creator: user });
client.setArgv(deployment.name); const lines = createLineIterator(client.stderr);
await list(client);
const lines = createLineIterator(client.stderr); let line = await lines.next();
expect(line.value).toEqual('Retrieving project…');
let line = await lines.next(); line = await lines.next();
expect(line.value).toEqual('Retrieving project…'); expect(line.value).toEqual(
`Fetching deployments in ${teamSlug || team[0].slug}`
);
line = await lines.next(); line = await lines.next();
expect(line.value).toEqual( const { org } = pluckIdentifiersFromDeploymentList(line.value!);
`Fetching deployments in ${teamSlug || team[0].slug}` expect(org).toEqual(teamSlug || team[0].slug);
);
line = await lines.next(); // skip next line
const { org } = pluckIdentifiersFromDeploymentList(line.value!); await lines.next();
expect(org).toEqual(teamSlug || team[0].slug);
// skip next line line = await lines.next();
await lines.next(); expect(line.value).toEqual('');
line = await lines.next(); line = await lines.next();
expect(line.value).toEqual(''); const header = parseSpacedTableRow(line.value!);
expect(header).toEqual([
'Age',
'Deployment',
'Status',
'Duration',
'Username',
]);
line = await lines.next(); line = await lines.next();
const header = parseSpacedTableRow(line.value!); const data = parseSpacedTableRow(line.value!);
expect(header).toEqual([ data.shift();
'Age', expect(data).toEqual([
'Deployment', `https://${deployment.url}`,
'Status', stateString(deployment.state || ''),
'Duration', getDeploymentDuration(deployment),
'Username', user.username,
]); ]);
line = await lines.next();
const data = parseSpacedTableRow(line.value!);
data.shift();
expect(data).toEqual([
`https://${deployment.url}`,
stateString(deployment.state || ''),
getDeploymentDuration(deployment),
user.username,
]);
} finally {
process.chdir(originalCwd);
}
}); });
}); });

View File

@@ -13,20 +13,10 @@ import sleep from '../../../src/util/sleep';
jest.setTimeout(60000); jest.setTimeout(60000);
describe('promote', () => { describe('promote', () => {
it('should error if cwd is invalid', async () => {
client.setArgv('promote', '--cwd', __filename);
const exitCodePromise = promote(client);
await expect(client.stderr).toOutput(
'Error: Support for single file deployments has been removed.'
);
await expect(exitCodePromise).resolves.toEqual(1);
});
it('should error if timeout is invalid', async () => { it('should error if timeout is invalid', async () => {
const { cwd } = initPromoteTest(); const { cwd } = initPromoteTest();
client.setArgv('promote', '--yes', '--cwd', cwd, '--timeout', 'foo'); client.cwd = cwd;
client.setArgv('promote', '--yes', '--timeout', 'foo');
const exitCodePromise = promote(client); const exitCodePromise = promote(client);
await expect(client.stderr).toOutput('Error: Invalid timeout "foo"'); await expect(client.stderr).toOutput('Error: Invalid timeout "foo"');
@@ -35,7 +25,8 @@ describe('promote', () => {
it('should error if invalid deployment ID', async () => { it('should error if invalid deployment ID', async () => {
const { cwd } = initPromoteTest(); const { cwd } = initPromoteTest();
client.setArgv('promote', '????', '--yes', '--cwd', cwd); client.cwd = cwd;
client.setArgv('promote', '????', '--yes');
const exitCodePromise = promote(client); const exitCodePromise = promote(client);
await expect(client.stderr).toOutput( await expect(client.stderr).toOutput(
@@ -46,7 +37,8 @@ describe('promote', () => {
it('should error if deployment not found', async () => { it('should error if deployment not found', async () => {
const { cwd } = initPromoteTest(); const { cwd } = initPromoteTest();
client.setArgv('promote', 'foo', '--yes', '--cwd', cwd); client.cwd = cwd;
client.setArgv('promote', 'foo', '--yes');
const exitCodePromise = promote(client); const exitCodePromise = promote(client);
await expect(client.stderr).toOutput('Fetching deployment "foo" in '); await expect(client.stderr).toOutput('Fetching deployment "foo" in ');
@@ -59,7 +51,8 @@ describe('promote', () => {
it('should show status when not promoting', async () => { it('should show status when not promoting', async () => {
const { cwd } = initPromoteTest(); const { cwd } = initPromoteTest();
client.setArgv('promote', '--yes', '--cwd', cwd); client.cwd = cwd;
client.setArgv('promote', '--yes');
const exitCodePromise = promote(client); const exitCodePromise = promote(client);
await expect(client.stderr).toOutput( await expect(client.stderr).toOutput(
@@ -72,7 +65,8 @@ describe('promote', () => {
it('should promote by deployment id', async () => { it('should promote by deployment id', async () => {
const { cwd, previousDeployment } = initPromoteTest(); const { cwd, previousDeployment } = initPromoteTest();
client.setArgv('promote', previousDeployment.id, '--yes', '--cwd', cwd); client.cwd = cwd;
client.setArgv('promote', previousDeployment.id, '--yes');
const exitCodePromise = promote(client); const exitCodePromise = promote(client);
await expect(client.stderr).toOutput( await expect(client.stderr).toOutput(
@@ -90,7 +84,8 @@ describe('promote', () => {
it('should promote by deployment url', async () => { it('should promote by deployment url', async () => {
const { cwd, previousDeployment } = initPromoteTest(); const { cwd, previousDeployment } = initPromoteTest();
client.setArgv('promote', previousDeployment.url, '--yes', '--cwd', cwd); client.cwd = cwd;
client.setArgv('promote', previousDeployment.url, '--yes');
const exitCodePromise = promote(client); const exitCodePromise = promote(client);
await expect(client.stderr).toOutput( await expect(client.stderr).toOutput(
@@ -110,16 +105,17 @@ describe('promote', () => {
const { cwd, previousDeployment, project } = initPromoteTest({ const { cwd, previousDeployment, project } = initPromoteTest({
promotePollCount: 10, promotePollCount: 10,
}); });
client.cwd = cwd;
// start the promote // start the promote
client.setArgv('promote', previousDeployment.id, '--yes', '--cwd', cwd); client.setArgv('promote', previousDeployment.id, '--yes');
promote(client); promote(client);
// need to wait for the promote request to be accepted // need to wait for the promote request to be accepted
await sleep(300); await sleep(300);
// get the status // get the status
client.setArgv('promote', '--yes', '--cwd', cwd); client.setArgv('promote', '--yes');
const exitCodePromise = promote(client); const exitCodePromise = promote(client);
await expect(client.stderr).toOutput( await expect(client.stderr).toOutput(
@@ -139,8 +135,8 @@ describe('promote', () => {
promotePollCount: 10, promotePollCount: 10,
promoteStatusCode: 500, promoteStatusCode: 500,
}); });
client.cwd = cwd;
client.setArgv('promote', previousDeployment.id, '--yes', '--cwd', cwd); client.setArgv('promote', previousDeployment.id, '--yes');
const exitCodePromise = promote(client); const exitCodePromise = promote(client);
await expect(client.stderr).toOutput( await expect(client.stderr).toOutput(
@@ -157,7 +153,8 @@ describe('promote', () => {
const { cwd, previousDeployment } = initPromoteTest({ const { cwd, previousDeployment } = initPromoteTest({
promoteJobStatus: 'failed', promoteJobStatus: 'failed',
}); });
client.setArgv('promote', previousDeployment.id, '--yes', '--cwd', cwd); client.cwd = cwd;
client.setArgv('promote', previousDeployment.id, '--yes');
const exitCodePromise = promote(client); const exitCodePromise = promote(client);
await expect(client.stderr).toOutput( await expect(client.stderr).toOutput(
@@ -185,7 +182,8 @@ describe('promote', () => {
], ],
promoteJobStatus: 'failed', promoteJobStatus: 'failed',
}); });
client.setArgv('promote', previousDeployment.id, '--yes', '--cwd', cwd); client.cwd = cwd;
client.setArgv('promote', previousDeployment.id, '--yes');
const exitCodePromise = promote(client); const exitCodePromise = promote(client);
await expect(client.stderr).toOutput( await expect(client.stderr).toOutput(
@@ -209,15 +207,8 @@ describe('promote', () => {
const { cwd, previousDeployment } = initPromoteTest({ const { cwd, previousDeployment } = initPromoteTest({
promotePollCount: 10, promotePollCount: 10,
}); });
client.setArgv( client.cwd = cwd;
'promote', client.setArgv('promote', previousDeployment.id, '--yes', '--timeout', '1');
previousDeployment.id,
'--yes',
'--cwd',
cwd,
'--timeout',
'1'
);
const exitCodePromise = promote(client); const exitCodePromise = promote(client);
await expect(client.stderr).toOutput( await expect(client.stderr).toOutput(
@@ -236,15 +227,8 @@ describe('promote', () => {
it('should immediately exit after requesting promote', async () => { it('should immediately exit after requesting promote', async () => {
const { cwd, previousDeployment } = initPromoteTest(); const { cwd, previousDeployment } = initPromoteTest();
client.setArgv( client.cwd = cwd;
'promote', client.setArgv('promote', previousDeployment.id, '--yes', '--timeout', '0');
previousDeployment.id,
'--yes',
'--cwd',
cwd,
'--timeout',
'0'
);
const exitCodePromise = promote(client); const exitCodePromise = promote(client);
await expect(client.stderr).toOutput( await expect(client.stderr).toOutput(
@@ -261,12 +245,13 @@ describe('promote', () => {
it('should error if deployment belongs to different team', async () => { it('should error if deployment belongs to different team', async () => {
const { cwd, previousDeployment } = initPromoteTest(); const { cwd, previousDeployment } = initPromoteTest();
client.cwd = cwd;
previousDeployment.team = { previousDeployment.team = {
id: 'abc', id: 'abc',
name: 'abc', name: 'abc',
slug: 'abc', slug: 'abc',
}; };
client.setArgv('promote', previousDeployment.id, '--yes', '--cwd', cwd); client.setArgv('promote', previousDeployment.id, '--yes');
const exitCodePromise = promote(client); const exitCodePromise = promote(client);
await expect(client.stderr).toOutput( await expect(client.stderr).toOutput(

View File

@@ -13,20 +13,10 @@ import sleep from '../../../src/util/sleep';
jest.setTimeout(60000); jest.setTimeout(60000);
describe('rollback', () => { describe('rollback', () => {
it('should error if cwd is invalid', async () => {
client.setArgv('rollback', '--cwd', __filename);
const exitCodePromise = rollback(client);
await expect(client.stderr).toOutput(
'Error: Support for single file deployments has been removed.'
);
await expect(exitCodePromise).resolves.toEqual(1);
});
it('should error if timeout is invalid', async () => { it('should error if timeout is invalid', async () => {
const { cwd } = initRollbackTest(); const { cwd } = initRollbackTest();
client.setArgv('rollback', '--yes', '--cwd', cwd, '--timeout', 'foo'); client.cwd = cwd;
client.setArgv('rollback', '--yes', '--timeout', 'foo');
const exitCodePromise = rollback(client); const exitCodePromise = rollback(client);
await expect(client.stderr).toOutput('Error: Invalid timeout "foo"'); await expect(client.stderr).toOutput('Error: Invalid timeout "foo"');
@@ -35,7 +25,8 @@ describe('rollback', () => {
it('should error if invalid deployment ID', async () => { it('should error if invalid deployment ID', async () => {
const { cwd } = initRollbackTest(); const { cwd } = initRollbackTest();
client.setArgv('rollback', '????', '--yes', '--cwd', cwd); client.cwd = cwd;
client.setArgv('rollback', '????', '--yes');
const exitCodePromise = rollback(client); const exitCodePromise = rollback(client);
await expect(client.stderr).toOutput( await expect(client.stderr).toOutput(
@@ -46,7 +37,8 @@ describe('rollback', () => {
it('should error if deployment not found', async () => { it('should error if deployment not found', async () => {
const { cwd } = initRollbackTest(); const { cwd } = initRollbackTest();
client.setArgv('rollback', 'foo', '--yes', '--cwd', cwd); client.cwd = cwd;
client.setArgv('rollback', 'foo', '--yes');
const exitCodePromise = rollback(client); const exitCodePromise = rollback(client);
await expect(client.stderr).toOutput( await expect(client.stderr).toOutput(
@@ -58,7 +50,8 @@ describe('rollback', () => {
it('should show status when not rolling back', async () => { it('should show status when not rolling back', async () => {
const { cwd } = initRollbackTest(); const { cwd } = initRollbackTest();
client.setArgv('rollback', '--yes', '--cwd', cwd); client.cwd = cwd;
client.setArgv('rollback', '--yes');
const exitCodePromise = rollback(client); const exitCodePromise = rollback(client);
await expect(client.stderr).toOutput( await expect(client.stderr).toOutput(
@@ -71,7 +64,8 @@ describe('rollback', () => {
it('should rollback by deployment id', async () => { it('should rollback by deployment id', async () => {
const { cwd, previousDeployment } = initRollbackTest(); const { cwd, previousDeployment } = initRollbackTest();
client.setArgv('rollback', previousDeployment.id, '--yes', '--cwd', cwd); client.cwd = cwd;
client.setArgv('rollback', previousDeployment.id, '--yes');
const exitCodePromise = rollback(client); const exitCodePromise = rollback(client);
await expect(client.stderr).toOutput( await expect(client.stderr).toOutput(
@@ -89,7 +83,8 @@ describe('rollback', () => {
it('should rollback by deployment url', async () => { it('should rollback by deployment url', async () => {
const { cwd, previousDeployment } = initRollbackTest(); const { cwd, previousDeployment } = initRollbackTest();
client.setArgv('rollback', previousDeployment.url, '--yes', '--cwd', cwd); client.cwd = cwd;
client.setArgv('rollback', previousDeployment.url, '--yes');
const exitCodePromise = rollback(client); const exitCodePromise = rollback(client);
await expect(client.stderr).toOutput( await expect(client.stderr).toOutput(
@@ -109,16 +104,17 @@ describe('rollback', () => {
const { cwd, previousDeployment, project } = initRollbackTest({ const { cwd, previousDeployment, project } = initRollbackTest({
rollbackPollCount: 10, rollbackPollCount: 10,
}); });
client.cwd = cwd;
// start the rollback // start the rollback
client.setArgv('rollback', previousDeployment.id, '--yes', '--cwd', cwd); client.setArgv('rollback', previousDeployment.id, '--yes');
rollback(client); rollback(client);
// need to wait for the rollback request to be accepted // need to wait for the rollback request to be accepted
await sleep(300); await sleep(300);
// get the status // get the status
client.setArgv('rollback', '--yes', '--cwd', cwd); client.setArgv('rollback', '--yes');
const exitCodePromise = rollback(client); const exitCodePromise = rollback(client);
await expect(client.stderr).toOutput( await expect(client.stderr).toOutput(
@@ -138,8 +134,9 @@ describe('rollback', () => {
rollbackPollCount: 10, rollbackPollCount: 10,
rollbackStatusCode: 500, rollbackStatusCode: 500,
}); });
client.cwd = cwd;
client.setArgv('rollback', previousDeployment.id, '--yes', '--cwd', cwd); client.setArgv('rollback', previousDeployment.id, '--yes');
const exitCodePromise = rollback(client); const exitCodePromise = rollback(client);
await expect(client.stderr).toOutput( await expect(client.stderr).toOutput(
@@ -155,7 +152,8 @@ describe('rollback', () => {
const { cwd, previousDeployment } = initRollbackTest({ const { cwd, previousDeployment } = initRollbackTest({
rollbackJobStatus: 'failed', rollbackJobStatus: 'failed',
}); });
client.setArgv('rollback', previousDeployment.id, '--yes', '--cwd', cwd); client.cwd = cwd;
client.setArgv('rollback', previousDeployment.id, '--yes');
const exitCodePromise = rollback(client); const exitCodePromise = rollback(client);
await expect(client.stderr).toOutput( await expect(client.stderr).toOutput(
@@ -183,7 +181,8 @@ describe('rollback', () => {
], ],
rollbackJobStatus: 'failed', rollbackJobStatus: 'failed',
}); });
client.setArgv('rollback', previousDeployment.id, '--yes', '--cwd', cwd); client.cwd = cwd;
client.setArgv('rollback', previousDeployment.id, '--yes');
const exitCodePromise = rollback(client); const exitCodePromise = rollback(client);
await expect(client.stderr).toOutput( await expect(client.stderr).toOutput(
@@ -207,12 +206,11 @@ describe('rollback', () => {
const { cwd, previousDeployment } = initRollbackTest({ const { cwd, previousDeployment } = initRollbackTest({
rollbackPollCount: 10, rollbackPollCount: 10,
}); });
client.cwd = cwd;
client.setArgv( client.setArgv(
'rollback', 'rollback',
previousDeployment.id, previousDeployment.id,
'--yes', '--yes',
'--cwd',
cwd,
'--timeout', '--timeout',
'1' '1'
); );
@@ -233,12 +231,11 @@ describe('rollback', () => {
it('should immediately exit after requesting rollback', async () => { it('should immediately exit after requesting rollback', async () => {
const { cwd, previousDeployment } = initRollbackTest(); const { cwd, previousDeployment } = initRollbackTest();
client.cwd = cwd;
client.setArgv( client.setArgv(
'rollback', 'rollback',
previousDeployment.id, previousDeployment.id,
'--yes', '--yes',
'--cwd',
cwd,
'--timeout', '--timeout',
'0' '0'
); );
@@ -263,7 +260,8 @@ describe('rollback', () => {
name: 'abc', name: 'abc',
slug: 'abc', slug: 'abc',
}; };
client.setArgv('rollback', previousDeployment.id, '--yes', '--cwd', cwd); client.cwd = cwd;
client.setArgv('rollback', previousDeployment.id, '--yes');
const exitCodePromise = rollback(client); const exitCodePromise = rollback(client);
await expect(client.stderr).toOutput( await expect(client.stderr).toOutput(

View File

@@ -306,10 +306,9 @@ describe('createGitMeta', () => {
} }
}); });
it('uses the repo url for a connected project', async () => { it('uses the repo url for a connected project', async () => {
const originalCwd = process.cwd();
const directory = fixture('connected-repo'); const directory = fixture('connected-repo');
client.cwd = directory;
try { try {
process.chdir(directory);
await fs.rename(join(directory, 'git'), join(directory, '.git')); await fs.rename(join(directory, 'git'), join(directory, '.git'));
useUser(); useUser();
@@ -343,7 +342,6 @@ describe('createGitMeta', () => {
}); });
} finally { } finally {
await fs.rename(join(directory, '.git'), join(directory, 'git')); await fs.rename(join(directory, '.git'), join(directory, 'git'));
process.chdir(originalCwd);
} }
}); });
}); });