Browse Source

Merge branch 'alias' of github.com:zeithq/now into alias

master
Tony Kovanen 9 years ago
parent
commit
7c6df1dd7d
  1. 14
      bin/now-alias
  2. 4
      bin/now-remove
  3. 36
      lib/alias.js
  4. 2
      package.json

14
bin/now-alias

@ -85,7 +85,6 @@ if (argv.help || !subcommand) {
.then(async (token) => { .then(async (token) => {
try { try {
await run(token); await run(token);
exit(0);
} catch (err) { } catch (err) {
if (err.userError) { if (err.userError) {
error(err.message); error(err.message);
@ -108,6 +107,9 @@ async function run (token) {
switch (subcommand) { switch (subcommand) {
case 'list': case 'list':
case 'ls': case 'ls':
const list = await alias.list();
const urls = new Map(list.map(l => [l.uid, l.url]));
const target = null != args[0] ? String(args[0]) : null; const target = null != args[0] ? String(args[0]) : null;
const aliases = await alias.ls(target); const aliases = await alias.ls(target);
const byTarget = new Map(); const byTarget = new Map();
@ -124,12 +126,12 @@ async function run (token) {
const current = new Date(); const current = new Date();
const text = sorted.map(([target, _aliases]) => { const text = sorted.map(([target, _aliases]) => {
const t = table(_aliases.map((_alias) => { return table(_aliases.map((_alias) => {
const _url = chalk.underline(`https://${_alias.alias}`); const _url = chalk.underline(`https://${_alias.alias}`);
const _sourceUrl = chalk.underline(`https://${urls.get(target)}`);
const time = chalk.gray(ms(current - new Date(_alias.created)) + ' ago'); const time = chalk.gray(ms(current - new Date(_alias.created)) + ' ago');
return [_alias.uid, _url, time]; return [_alias.uid, _sourceUrl, _url, time];
}), { align: ['l', 'r', 'l'], hsep: ' '.repeat(6) }); }), { align: ['l', 'r', 'l'], hsep: ' '.repeat(3) });
return chalk.bold(target) + '\n\n' + indent(t, 2);
}).join('\n\n'); }).join('\n\n');
if (text) console.log('\n' + text + '\n'); if (text) console.log('\n' + text + '\n');
@ -193,6 +195,8 @@ async function run (token) {
exit(1); exit(1);
} }
} }
alias.close();
} }
async function sort (aliases) { async function sort (aliases) {

4
bin/now-remove

@ -55,13 +55,13 @@ function readConfirmation (app) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const time = chalk.gray(ms(new Date() - app.created) + ' ago'); const time = chalk.gray(ms(new Date() - app.created) + ' ago');
const tbl = table( const tbl = table(
[[app.uid, time, `https://${app.url}`]], [[app.uid, `https://${app.url}`, time]],
{ align: ['l', 'r', 'l'], hsep: ' '.repeat(6) } { align: ['l', 'r', 'l'], hsep: ' '.repeat(6) }
); );
process.stdout.write('> The following deployment will be removed permanently\n'); process.stdout.write('> The following deployment will be removed permanently\n');
process.stdout.write(' ' + tbl + '\n'); process.stdout.write(' ' + tbl + '\n');
process.stdout.write(` ${chalk.bold.red('> Are you sure?')} ${chalk.gray('[yN] ')}`); process.stdout.write(`${chalk.bold.red('> Are you sure?')} ${chalk.gray('[yN] ')}`);
process.stdin.on('data', (d) => { process.stdin.on('data', (d) => {
process.stdin.pause(); process.stdin.pause();

36
lib/alias.js

@ -76,6 +76,8 @@ export default class Alias extends Now {
} }
async set (deployment, alias) { async set (deployment, alias) {
alias = alias.toLowerCase();
const depl = await this.findDeployment(deployment); const depl = await this.findDeployment(deployment);
if (!depl) { if (!depl) {
const err = new Error(`Deployment not found by "${deployment}". Run ${chalk.dim('`now ls`')} to see your deployments.`); const err = new Error(`Deployment not found by "${deployment}". Run ${chalk.dim('`now ls`')} to see your deployments.`);
@ -91,11 +93,21 @@ export default class Alias extends Now {
alias = toHost(alias); alias = toHost(alias);
} }
await this.createAlias(depl, alias); if (!/\.now\.sh$/.test(alias)) {
console.log(`${chalk.cyan('> Success!')} Set up alias ${chalk.bold(alias)}`); console.log(`> ${chalk.bold(chalk.underline(alias))} is a custom domain.`);
console.log(`> Verifying that ${chalk.bold(chalk.underline(alias))} has a ${chalk.cyan('`CNAME`')} or ${chalk.cyan('`ALIAS`')} record pointing to ${chalk.bold(chalk.underline('alias.zeit.co'))}.`);
await this.verifyOwnership(alias);
}
const { created, uid } = await this.createAlias(depl, alias);
if (created) {
console.log(`${chalk.cyan('> Success!')} Alias created ${chalk.dim(`(${uid})`)}: ${chalk.bold(`https://${depl.url}`)} ${chalk.dim(`(${depl.uid})`)} now points to ${chalk.bold(chalk.underline(`https://${alias}`))}`);
} else {
console.log(`${chalk.cyan('> Success!')} Alias already exists ${chalk.dim(`(${uid})`)}.`);
}
} }
async createAlias (depl, alias) { createAlias (depl, alias) {
return this.retry(async (bail, attempt) => { return this.retry(async (bail, attempt) => {
if (this._debug) console.time(`> [debug] /now/deployments/${depl.uid}/aliases #${attempt}`); if (this._debug) console.time(`> [debug] /now/deployments/${depl.uid}/aliases #${attempt}`);
const res = await this._fetch(`/now/deployments/${depl.uid}/aliases`, { const res = await this._fetch(`/now/deployments/${depl.uid}/aliases`, {
@ -103,23 +115,24 @@ export default class Alias extends Now {
body: { alias } body: { alias }
}); });
if (304 === res.status) return;
const body = await res.json(); const body = await res.json();
if (this._debug) console.timeEnd(`> [debug] /now/deployments/${depl.uid}/aliases #${attempt}`); if (this._debug) console.timeEnd(`> [debug] /now/deployments/${depl.uid}/aliases #${attempt}`);
// 409 conflict is returned if it already exists
if (409 === res.status) return { uid: body.error.uid };
// no retry on authorization problems // no retry on authorization problems
if (403 === res.status) { if (403 === res.status) {
const code = body.error.code; const code = body.error.code;
if ('custom_domain_needs_upgrade' === code) { if ('custom_domain_needs_upgrade' === code) {
const err = new Error(`You are attempting to use a custom domain alias (${chalk.underline(chalk.cyan(alias))}), but this is only enabled for premium accounts. Please upgrade at ${chalk.underline('https://zeit.co/account')}`); const err = new Error(`Custom domains are only enabled for premium accounts. Please upgrade at ${chalk.underline('https://zeit.co/account')}.`);
err.userError = true; err.userError = true;
return bail(err); return bail(err);
} }
if ('alias_in_use' === code) { if ('alias_in_use' === code) {
const err = new Error(`The alias you are trying to configure (${chalk.underline(chalk.cyan(alias))}) is already in use by a different account.`); const err = new Error(`The alias you are trying to configure (${chalk.underline(chalk.bold(alias))}) is already in use by a different account.`);
err.userError = true; err.userError = true;
return bail(err); return bail(err);
} }
@ -138,7 +151,6 @@ export default class Alias extends Now {
if ('cert_missing' === code) { if ('cert_missing' === code) {
console.log(`> Provisioning certificate for ${chalk.underline(chalk.cyan(alias))}`); console.log(`> Provisioning certificate for ${chalk.underline(chalk.cyan(alias))}`);
await this.verifyOwnership();
await this.createCert(); await this.createCert();
// try again, but now having provisioned the certificate // try again, but now having provisioned the certificate
@ -152,10 +164,12 @@ export default class Alias extends Now {
if (200 !== res.status && 304 !== res.status) { if (200 !== res.status && 304 !== res.status) {
throw new Error('Unhandled error'); throw new Error('Unhandled error');
} }
return body;
}); });
} }
async verifyOwnership (domain) { verifyOwnership (domain) {
return this.retry(async (bail, attempt) => { return this.retry(async (bail, attempt) => {
const targets = await resolve4('alias.zeit.co'); const targets = await resolve4('alias.zeit.co');
@ -172,7 +186,7 @@ export default class Alias extends Now {
for (const ip of ips) { for (const ip of ips) {
if (!~targets.indexOf(ip)) { if (!~targets.indexOf(ip)) {
const err = new Error(`The domain ${domain} has an A record ${chalk.bold(ip)} that doesn\'t resolve to ${chalk.bold('alias.zeit.co')}. Make sure the appropriate \`ALIAS\` or \`CNAME\` records are configured.`); const err = new Error(`The domain ${domain} has an A record ${chalk.bold(ip)} that doesn\'t resolve to ${chalk.bold(chalk.underline('alias.zeit.co'))}. Please check your DNS settings.`);
err.userError = true; err.userError = true;
return bail(err); return bail(err);
} }
@ -180,7 +194,7 @@ export default class Alias extends Now {
}); });
} }
async createCert (domain) { createCert (domain) {
return this.retry(async (bail, attempt) => { return this.retry(async (bail, attempt) => {
if (this._debug) console.time(`> [debug] /certs #${attempt}`); if (this._debug) console.time(`> [debug] /certs #${attempt}`);
const res = await this._fetch('/certs', { const res = await this._fetch('/certs', {

2
package.json

@ -14,7 +14,7 @@
"ansi-escapes": "1.4.0", "ansi-escapes": "1.4.0",
"arr-flatten": "1.0.1", "arr-flatten": "1.0.1",
"array-unique": "0.2.1", "array-unique": "0.2.1",
"babel-runtime": "6.9.0", "babel-runtime": "6.5.0",
"bytes": "2.3.0", "bytes": "2.3.0",
"chalk": "1.1.3", "chalk": "1.1.3",
"copy-paste": "1.2.0", "copy-paste": "1.2.0",

Loading…
Cancel
Save