Compare commits

..

8 Commits

Author SHA1 Message Date
luc
53eb71f26d Publish Stable
- now@17.0.2
 - @now/routing-utils@1.5.3
2020-02-06 19:18:35 +01:00
luc
92ffd654b5 Publish Canary
- now@17.0.2-canary.1
2020-02-06 18:53:36 +01:00
Luc
36b83f1606 [now-cli] Use npx or yarn to execute dev command (#3760)
1. Use bundled yarn to run `yarn bin`
2. Skip `yarn bin` if `npx` is used
2020-02-06 17:47:39 +00:00
Steven
7a79f620c0 [tests] Fix changelog script (#3751)
Previously, the changelog script was looking for the last "Publish Stable" commit, but it should really be looking for the last Stable release of Now CLI.

This PR updates the changelog script so that it fetches the latest GH Release (which should be Now CLI) and then compares that to the HEAD.
2020-02-06 14:35:15 +00:00
Steven
f3b286ecf3 Publish Canary
- now@17.0.2-canary.0
 - @now/routing-utils@1.5.3-canary.0
2020-02-06 09:12:19 -05:00
Steven
adf31c3fcc [now-routing-utils] Change behavior of trailingSlash: true redirects (#3745)
This PR changes the behavior of `trailingSlash: true` after we received feedback that files should not be redirected with a trailing slash. This matches the behavior of `serve` and `serve-handler`.

### Examples 
* `/index.html` => serve
* `/assets/style.css` => serve
* `/assets` => redirect to `/assets/`
* `/assets/style` => redirect to `/assets/style/` 

### Additional

In order to avoid duplicate content, this PR also adds redirects to files without a trailing slash.

* `/about.html/` => redirect to `/about.html`
* `/assets/style.css/` => redirect to `/assets/style.css`


Fixes #3731
2020-02-06 09:07:46 -05:00
luc
deacdfc47c Publish Stable
- now@17.0.1
2020-02-06 01:07:15 +01:00
Luc
ac9badbe9e [now-cli] Always output deployment url in stdout (#3753) 2020-02-06 00:58:24 +01:00
9 changed files with 112 additions and 76 deletions

View File

@@ -1,6 +1,6 @@
{ {
"name": "now", "name": "now",
"version": "17.0.0", "version": "17.0.2",
"preferGlobal": true, "preferGlobal": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"description": "The command-line interface for Now", "description": "The command-line interface for Now",

View File

@@ -94,7 +94,6 @@ const printDeploymentStatus = async (
}, },
deployStamp, deployStamp,
isClipboardEnabled, isClipboardEnabled,
quiet,
isFile isFile
) => { ) => {
const isProdDeployment = target === 'production'; const isProdDeployment = target === 'production';
@@ -144,11 +143,6 @@ const printDeploymentStatus = async (
.catch(error => output.debug(`Error copying to clipboard: ${error}`)); .catch(error => output.debug(`Error copying to clipboard: ${error}`));
} }
// write to stdout
if (quiet) {
process.stdout.write(`https://${deploymentUrl}`);
}
output.print( output.print(
prependEmoji( prependEmoji(
`${isProdDeployment ? 'Production' : 'Preview'}: ${chalk.bold( `${isProdDeployment ? 'Production' : 'Preview'}: ${chalk.bold(
@@ -659,7 +653,6 @@ export default async function main(
deployment, deployment,
deployStamp, deployStamp,
!argv['--no-clipboard'], !argv['--no-clipboard'],
quiet,
isFile isFile
); );
} }

View File

@@ -83,6 +83,7 @@ export default async function processDeployment({
deployStamp, deployStamp,
force, force,
nowConfig, nowConfig,
quiet,
} = args; } = args;
const { debug } = output; const { debug } = output;
@@ -179,6 +180,10 @@ export default async function processDeployment({
printInspectUrl(output, event.payload.url, deployStamp, org.slug); printInspectUrl(output, event.payload.url, deployStamp, org.slug);
if (quiet) {
process.stdout.write(`https://${event.payload.url}`);
}
if (queuedSpinner === null) { if (queuedSpinner === null) {
queuedSpinner = queuedSpinner =
event.payload.readyState === 'QUEUED' event.payload.readyState === 'QUEUED'

View File

@@ -11,7 +11,7 @@ import { randomBytes } from 'crypto';
import serveHandler from 'serve-handler'; import serveHandler from 'serve-handler';
import { watch, FSWatcher } from 'chokidar'; import { watch, FSWatcher } from 'chokidar';
import { parse as parseDotenv } from 'dotenv'; import { parse as parseDotenv } from 'dotenv';
import { basename, dirname, extname, join, delimiter } from 'path'; import { basename, dirname, extname, join } from 'path';
import { getTransformedRoutes, HandleValue } from '@now/routing-utils'; import { getTransformedRoutes, HandleValue } from '@now/routing-utils';
import directoryTemplate from 'serve-handler/src/directory'; import directoryTemplate from 'serve-handler/src/directory';
import getPort from 'get-port'; import getPort from 'get-port';
@@ -27,7 +27,6 @@ import {
detectRoutes, detectRoutes,
detectApiDirectory, detectApiDirectory,
detectApiExtensions, detectApiExtensions,
execAsync,
spawnCommand, spawnCommand,
} from '@now/build-utils'; } from '@now/build-utils';
@@ -1637,12 +1636,6 @@ export default class DevServer {
const cwd = this.cwd; const cwd = this.cwd;
const { stdout: yarnBinStdout } = await execAsync('yarn', ['bin'], {
cwd,
});
const yarnBinPath = yarnBinStdout.trim();
this.output.log( this.output.log(
`Running Dev Command ${chalk.cyan.bold(`${this.devCommand}`)}` `Running Dev Command ${chalk.cyan.bold(`${this.devCommand}`)}`
); );
@@ -1667,21 +1660,27 @@ export default class DevServer {
})}` })}`
); );
let command = devCommand;
const isNpxAvailable = await which('npx') const isNpxAvailable = await which('npx')
.then(() => true) .then(() => true)
.catch(() => false); .catch(() => false);
if (!isNpxAvailable) { if (isNpxAvailable) {
env.PATH = `${yarnBinPath}${delimiter}${env.PATH}`; command = `npx --no-install ${devCommand}`;
} else {
const isYarnAvailable = await which('yarn')
.then(() => true)
.catch(() => false);
if (isYarnAvailable) {
command = `yarn run --silent ${devCommand}`;
}
} }
this.output.debug('Spawning dev command'); this.output.debug(`Spawning dev command: ${command}`);
this.output.debug(`PATH is ${env.PATH}`);
const p = spawnCommand( const p = spawnCommand(command, { stdio: 'inherit', cwd, env });
isNpxAvailable ? `npx --no-install ${devCommand}` : devCommand,
{ stdio: 'inherit', cwd, env }
);
p.on('exit', () => { p.on('exit', () => {
this.devProcessPort = undefined; this.devProcessPort = undefined;

View File

@@ -638,7 +638,7 @@ test(
await testPath(200, '/about/', 'About Page'); await testPath(200, '/about/', 'About Page');
await testPath(200, '/sub/', 'Sub Index Page'); await testPath(200, '/sub/', 'Sub Index Page');
await testPath(200, '/sub/another/', 'Sub Another Page'); await testPath(200, '/sub/another/', 'Sub Another Page');
await testPath(200, '/style.css/', 'body { color: green }'); await testPath(200, '/style.css', 'body { color: green }');
await testPath(308, '/index.html', '', { Location: '/' }); await testPath(308, '/index.html', '', { Location: '/' });
await testPath(308, '/about.html', '', { Location: '/about/' }); await testPath(308, '/about.html', '', { Location: '/about/' });
await testPath(308, '/sub/index.html', '', { Location: '/sub/' }); await testPath(308, '/sub/index.html', '', { Location: '/sub/' });
@@ -653,17 +653,15 @@ test(
'[now dev] test trailingSlash true serve correct content', '[now dev] test trailingSlash true serve correct content',
testFixtureStdio('test-trailing-slash', async (t, port, testPath) => { testFixtureStdio('test-trailing-slash', async (t, port, testPath) => {
await testPath(200, '/', 'Index Page'); await testPath(200, '/', 'Index Page');
await testPath(200, '/index.html/', 'Index Page'); await testPath(200, '/index.html', 'Index Page');
await testPath(200, '/about.html/', 'About Page'); await testPath(200, '/about.html', 'About Page');
await testPath(200, '/sub/', 'Sub Index Page'); await testPath(200, '/sub/', 'Sub Index Page');
await testPath(200, '/sub/index.html/', 'Sub Index Page'); await testPath(200, '/sub/index.html', 'Sub Index Page');
await testPath(200, '/sub/another.html/', 'Sub Another Page'); await testPath(200, '/sub/another.html', 'Sub Another Page');
await testPath(200, '/style.css/', 'body { color: green }'); await testPath(200, '/style.css', 'body { color: green }');
await testPath(308, '/about.html', '', { Location: '/about.html/' }); await testPath(308, '/about.html/', '', { Location: '/about.html' });
await testPath(308, '/style.css/', '', { Location: '/style.css' });
await testPath(308, '/sub', '', { Location: '/sub/' }); await testPath(308, '/sub', '', { Location: '/sub/' });
await testPath(308, '/sub/another.html', '', {
Location: '/sub/another.html/',
});
}) })
); );

View File

@@ -1,6 +1,6 @@
{ {
"name": "@now/routing-utils", "name": "@now/routing-utils",
"version": "1.5.2", "version": "1.5.3",
"description": "ZEIT Now routing utilities", "description": "ZEIT Now routing utilities",
"main": "./dist/index.js", "main": "./dist/index.js",
"types": "./dist/index.d.ts", "types": "./dist/index.d.ts",

View File

@@ -105,10 +105,15 @@ export function convertTrailingSlash(enable: boolean, status = 308): Route[] {
const routes: Route[] = []; const routes: Route[] = [];
if (enable) { if (enable) {
routes.push({ routes.push({
src: '^/(.*[^\\/])$', src: '^/((?:[^/]+/)*[^/\\.]+)$',
headers: { Location: '/$1/' }, headers: { Location: '/$1/' },
status, status,
}); });
routes.push({
src: '^/((?:[^/]+/)*[^/]+\\.\\w+)/$',
headers: { Location: '/$1' },
status,
});
} else { } else {
routes.push({ routes.push({
src: '^/(.*)\\/$', src: '^/(.*)\\/$',

View File

@@ -503,16 +503,41 @@ test('convertTrailingSlash enabled', () => {
const actual = convertTrailingSlash(true); const actual = convertTrailingSlash(true);
const expected = [ const expected = [
{ {
src: '^/(.*[^\\/])$', src: '^/((?:[^/]+/)*[^/\\.]+)$',
headers: { Location: '/$1/' }, headers: { Location: '/$1/' },
status: 308, status: 308,
}, },
{
src: '^/((?:[^/]+/)*[^/]+\\.\\w+)/$',
headers: { Location: '/$1' },
status: 308,
},
]; ];
deepEqual(actual, expected); deepEqual(actual, expected);
const mustMatch = [['/index.html', '/dir', '/dir/index.html', '/foo/bar']]; const mustMatch = [
['/dir', '/dir/foo', '/dir/foo/bar'],
['/foo.html/', '/dir/foo.html/', '/dir/foo/bar.css/', '/dir/about.map.js/'],
];
const mustNotMatch = [['/', '/dir/', '/dir/foo/', '/next.php?page=/']]; const mustNotMatch = [
[
'/',
'/index.html',
'/asset/style.css',
'/asset/about.map.js',
'/dir/',
'/dir/foo/',
'/next.php?page=/',
],
[
'/',
'/foo.html',
'/dir/foo.html',
'/dir/foo/bar.css',
'/dir/about.map.js',
],
];
assertRegexMatches(actual, mustMatch, mustNotMatch); assertRegexMatches(actual, mustMatch, mustNotMatch);
}); });

View File

@@ -1,45 +1,56 @@
const { join } = require('path'); const { join } = require('path');
const { execSync } = require('child_process'); const { execSync } = require('child_process');
const fetch = require('node-fetch');
process.chdir(join(__dirname, '..')); process.chdir(join(__dirname, '..'));
const commit = execSync('git log --pretty=format:"%s %H"') async function main() {
.toString() const res = await fetch(
.trim() 'https://api.github.com/repos/zeit/now/releases/latest'
.split('\n') );
.find(line => line.startsWith('Publish Stable ')) const { tag_name } = await res.json();
.split(' ')
.pop();
if (!commit) { // git log --pretty=format:"- %s [%an]" `git show-ref -s 'now@16.7.3'`...HEAD | grep -v '\- Publish '
throw new Error('Unable to find last publish commit');
if (!tag_name) {
throw new Error('Unable to find last GitHub Release tag.');
}
const log =
execSync(`git log --pretty=format:"- %s [%an]" ${tag_name}...HEAD`)
.toString()
.trim()
.split('\n')
.filter(line => !line.startsWith('- Publish '))
.join('\n') || 'NO CHANGES DETECTED';
console.log(`Changes since the last stable release (${tag_name}):`);
console.log(`\n${log}\n`);
const pkgs =
Array.from(
new Set(
execSync(`git diff --name-only ${tag_name}...HEAD`)
.toString()
.trim()
.split('\n')
.filter(line => line.startsWith('packages/'))
.map(line => line.split('/')[1])
.map(pkgName => {
try {
return require(`../packages/${pkgName}/package.json`).name;
} catch {
// Failed to read package.json (perhaps the pkg was deleted)
}
})
.filter(s => Boolean(s))
)
).join(',') || 'now';
console.log('To publish a stable release, execute the following:');
console.log(
`\nnpx lerna version --message 'Publish Stable' --exact --force-publish=${pkgs}\n`
);
} }
const log = main().catch(console.error);
execSync(`git log --pretty=format:"- %s [%an]" ${commit}...HEAD`)
.toString()
.trim()
.split('\n')
.filter(line => !line.startsWith('- Publish Canary '))
.join('\n') || 'NO CHANGES DETECTED';
console.log(`Changes since the last Stable release (${commit.slice(0, 7)}):`);
console.log(`\n${log}\n`);
const pkgs =
Array.from(
new Set(
execSync(`git diff --name-only ${commit}...HEAD`)
.toString()
.trim()
.split('\n')
.filter(line => line.startsWith('packages/'))
.map(line => line.split('/')[1])
.map(pkgName => require(`../packages/${pkgName}/package.json`).name)
)
).join(',') || 'now';
console.log('To publish a stable release, execute the following:');
console.log(
`\ngit pull && lerna version --message 'Publish Stable' --exact --force-publish=${pkgs}\n`
);