mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-11 21:07:47 +00:00
Compare commits
18 Commits
@now/pytho
...
@now/pytho
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
372a674625 | ||
|
|
fafeadb7ba | ||
|
|
966b1e763f | ||
|
|
bb60e1a5fe | ||
|
|
cac9f807cc | ||
|
|
a0b1254820 | ||
|
|
0faff4132b | ||
|
|
1793a1287d | ||
|
|
5b572239c1 | ||
|
|
f6a66d937e | ||
|
|
2cf9a2f489 | ||
|
|
454f4dcc61 | ||
|
|
6e1065fde2 | ||
|
|
80ce06b20c | ||
|
|
99f3ab8b64 | ||
|
|
ca4f6d2491 | ||
|
|
2ceb2a78aa | ||
|
|
d97da21afc |
@@ -115,15 +115,12 @@ jobs:
|
|||||||
|
|
||||||
test-integration-macos-node-8:
|
test-integration-macos-node-8:
|
||||||
macos:
|
macos:
|
||||||
xcode: '9.2.0'
|
xcode: '9.0.1'
|
||||||
working_directory: ~/repo
|
working_directory: ~/repo
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- attach_workspace:
|
- attach_workspace:
|
||||||
at: .
|
at: .
|
||||||
- run:
|
|
||||||
name: Update Node.js
|
|
||||||
command: curl -sfLS install-node.now.sh/8.11 | sh -s -- --yes
|
|
||||||
- run:
|
- run:
|
||||||
name: Output version
|
name: Output version
|
||||||
command: node --version
|
command: node --version
|
||||||
@@ -208,15 +205,12 @@ jobs:
|
|||||||
|
|
||||||
test-integration-macos-now-dev-node-8:
|
test-integration-macos-now-dev-node-8:
|
||||||
macos:
|
macos:
|
||||||
xcode: '9.2.0'
|
xcode: '9.0.1'
|
||||||
working_directory: ~/repo
|
working_directory: ~/repo
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- attach_workspace:
|
- attach_workspace:
|
||||||
at: .
|
at: .
|
||||||
- run:
|
|
||||||
name: Update Node.js
|
|
||||||
command: curl -sfLS install-node.now.sh/8.11 | sh -s -- --yes
|
|
||||||
- run:
|
- run:
|
||||||
name: Output version
|
name: Output version
|
||||||
command: node --version
|
command: node --version
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@now/build-utils",
|
"name": "@now/build-utils",
|
||||||
"version": "0.11.0",
|
"version": "0.11.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"types": "./dist/index.d.js",
|
"types": "./dist/index.d.js",
|
||||||
|
|||||||
@@ -191,23 +191,110 @@ export interface ShouldServeOptions {
|
|||||||
config: Config;
|
config: Config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Credit to Iain Reid, MIT license.
|
||||||
|
* Source: https://gist.github.com/iainreid820/5c1cc527fe6b5b7dba41fec7fe54bf6e
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||||
|
namespace PackageJson {
|
||||||
|
/**
|
||||||
|
* An author or contributor
|
||||||
|
*/
|
||||||
|
export interface Author {
|
||||||
|
name: string;
|
||||||
|
email?: string;
|
||||||
|
homepage?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A map of exposed bin commands
|
||||||
|
*/
|
||||||
|
export interface BinMap {
|
||||||
|
[commandName: string]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A bugs link
|
||||||
|
*/
|
||||||
|
export interface Bugs {
|
||||||
|
email: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Config {
|
||||||
|
name?: string;
|
||||||
|
config?: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A map of dependencies
|
||||||
|
*/
|
||||||
|
export interface DependencyMap {
|
||||||
|
[dependencyName: string]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CommonJS package structure
|
||||||
|
*/
|
||||||
|
export interface Directories {
|
||||||
|
lib?: string;
|
||||||
|
bin?: string;
|
||||||
|
man?: string;
|
||||||
|
doc?: string;
|
||||||
|
example?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Engines {
|
||||||
|
node?: string;
|
||||||
|
npm?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PublishConfig {
|
||||||
|
registry?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A project repository
|
||||||
|
*/
|
||||||
|
export interface Repository {
|
||||||
|
type: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ScriptsMap {
|
||||||
|
[scriptName: string]: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export interface PackageJson {
|
export interface PackageJson {
|
||||||
name?: string;
|
readonly name?: string;
|
||||||
version?: string;
|
readonly version?: string;
|
||||||
engines?: {
|
readonly description?: string;
|
||||||
[key: string]: string;
|
readonly keywords?: string[];
|
||||||
node: string;
|
readonly homepage?: string;
|
||||||
npm: string;
|
readonly bugs?: string | PackageJson.Bugs;
|
||||||
};
|
readonly license?: string;
|
||||||
scripts?: {
|
readonly author?: string | PackageJson.Author;
|
||||||
[key: string]: string;
|
readonly contributors?: string[] | PackageJson.Author[];
|
||||||
};
|
readonly files?: string[];
|
||||||
dependencies?: {
|
readonly main?: string;
|
||||||
[key: string]: string;
|
readonly bin?: string | PackageJson.BinMap;
|
||||||
};
|
readonly man?: string | string[];
|
||||||
devDependencies?: {
|
readonly directories?: PackageJson.Directories;
|
||||||
[key: string]: string;
|
readonly repository?: string | PackageJson.Repository;
|
||||||
};
|
readonly scripts?: PackageJson.ScriptsMap;
|
||||||
|
readonly config?: PackageJson.Config;
|
||||||
|
readonly dependencies?: PackageJson.DependencyMap;
|
||||||
|
readonly devDependencies?: PackageJson.DependencyMap;
|
||||||
|
readonly peerDependencies?: PackageJson.DependencyMap;
|
||||||
|
readonly optionalDependencies?: PackageJson.DependencyMap;
|
||||||
|
readonly bundledDependencies?: string[];
|
||||||
|
readonly engines?: PackageJson.Engines;
|
||||||
|
readonly os?: string[];
|
||||||
|
readonly cpu?: string[];
|
||||||
|
readonly preferGlobal?: boolean;
|
||||||
|
readonly private?: boolean;
|
||||||
|
readonly publishConfig?: PackageJson.PublishConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NodeVersion {
|
export interface NodeVersion {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
To install the latest version of Now CLI, visit [zeit.co/download](https://zeit.co/download) or run this command:
|
To install the latest version of Now CLI, visit [zeit.co/download](https://zeit.co/download) or run this command:
|
||||||
|
|
||||||
```
|
```bash
|
||||||
npm i -g now
|
npm i -g now
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "now",
|
"name": "now",
|
||||||
"version": "16.4.0",
|
"version": "16.4.1",
|
||||||
"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",
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 8.11"
|
"node": ">= 8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sentry/node": "5.5.0",
|
"@sentry/node": "5.5.0",
|
||||||
|
|||||||
@@ -127,6 +127,7 @@ export const legacyArgsMri = {
|
|||||||
'session-affinity',
|
'session-affinity',
|
||||||
'regions',
|
'regions',
|
||||||
'dotenv',
|
'dotenv',
|
||||||
|
'target',
|
||||||
],
|
],
|
||||||
boolean: [
|
boolean: [
|
||||||
'help',
|
'help',
|
||||||
@@ -144,6 +145,7 @@ export const legacyArgsMri = {
|
|||||||
'no-scale',
|
'no-scale',
|
||||||
'no-verify',
|
'no-verify',
|
||||||
'dotenv',
|
'dotenv',
|
||||||
|
'prod',
|
||||||
],
|
],
|
||||||
default: {
|
default: {
|
||||||
C: false,
|
C: false,
|
||||||
|
|||||||
@@ -388,7 +388,7 @@ export default async function main(
|
|||||||
|
|
||||||
const deploymentResponse = handleCertError(
|
const deploymentResponse = handleCertError(
|
||||||
output,
|
output,
|
||||||
await getDeploymentByIdOrHost(now, contextName, deployment.id, 'v9')
|
await getDeploymentByIdOrHost(now, contextName, deployment.id, 'v10')
|
||||||
);
|
);
|
||||||
|
|
||||||
if (deploymentResponse === 1) {
|
if (deploymentResponse === 1) {
|
||||||
|
|||||||
@@ -304,6 +304,18 @@ export default async function main(
|
|||||||
`You are using an old version of the Now Platform. More: ${link(infoUrl)}`
|
`You are using an old version of the Now Platform. More: ${link(infoUrl)}`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (argv.prod || argv.target) {
|
||||||
|
error(
|
||||||
|
`The option ${cmd(
|
||||||
|
argv.prod ? '--prod' : '--target'
|
||||||
|
)} is not supported for Now 1.0 deployments. To manually alias a deployment, use ${cmd(
|
||||||
|
'now alias'
|
||||||
|
)} instead.`
|
||||||
|
);
|
||||||
|
await exit(1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
authConfig: { token },
|
authConfig: { token },
|
||||||
config,
|
config,
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ import { Deployment } from '../../types';
|
|||||||
import {
|
import {
|
||||||
DeploymentNotFound,
|
DeploymentNotFound,
|
||||||
DeploymentPermissionDenied,
|
DeploymentPermissionDenied,
|
||||||
InvalidDeploymentId
|
InvalidDeploymentId,
|
||||||
} from '../errors-ts';
|
} from '../errors-ts';
|
||||||
import mapCertError from '../certs/map-cert-error';
|
import mapCertError from '../certs/map-cert-error';
|
||||||
|
|
||||||
type APIVersion = 'v5' | 'v9';
|
type APIVersion = 'v5' | 'v10';
|
||||||
|
|
||||||
export default async function getDeploymentByIdOrHost(
|
export default async function getDeploymentByIdOrHost(
|
||||||
client: Client,
|
client: Client,
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ export default async function processDeployment({
|
|||||||
const opts: DeploymentOptions = {
|
const opts: DeploymentOptions = {
|
||||||
...requestBody,
|
...requestBody,
|
||||||
debug: now._debug,
|
debug: now._debug,
|
||||||
|
apiUrl: now._apiUrl,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!legacy) {
|
if (!legacy) {
|
||||||
@@ -143,7 +144,7 @@ export default async function processDeployment({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle ready event
|
// Handle ready event
|
||||||
if (event.type === 'ready') {
|
if (event.type === 'alias-assigned') {
|
||||||
if (deploySpinner) {
|
if (deploySpinner) {
|
||||||
deploySpinner();
|
deploySpinner();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -411,8 +411,16 @@ export async function shutdownBuilder(
|
|||||||
const ops: Promise<void>[] = [];
|
const ops: Promise<void>[] = [];
|
||||||
|
|
||||||
if (match.buildProcess) {
|
if (match.buildProcess) {
|
||||||
debug(`Killing builder sub-process with PID ${match.buildProcess.pid}`);
|
const { pid } = match.buildProcess;
|
||||||
ops.push(treeKill(match.buildProcess.pid));
|
debug(`Killing builder sub-process with PID ${pid}`);
|
||||||
|
const killPromise = treeKill(pid)
|
||||||
|
.then(() => {
|
||||||
|
debug(`Killed builder with PID ${pid}`);
|
||||||
|
})
|
||||||
|
.catch((err: Error) => {
|
||||||
|
debug(`Failed to kill builder with PID ${pid}: ${err}`);
|
||||||
|
});
|
||||||
|
ops.push(killPromise);
|
||||||
delete match.buildProcess;
|
delete match.buildProcess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -784,6 +784,19 @@ export class CantFindConfig extends NowError<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class WorkingDirectoryDoesNotExist extends NowError<
|
||||||
|
'CWD_DOES_NOT_EXIST',
|
||||||
|
{}
|
||||||
|
> {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
code: 'CWD_DOES_NOT_EXIST',
|
||||||
|
meta: {},
|
||||||
|
message: 'The current working directory does not exist.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class FileNotFound extends NowError<'FILE_NOT_FOUND', { file: string }> {
|
export class FileNotFound extends NowError<'FILE_NOT_FOUND', { file: string }> {
|
||||||
constructor(file: string) {
|
constructor(file: string) {
|
||||||
super({
|
super({
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { CantParseJSONFile, CantFindConfig } from './errors-ts';
|
import {
|
||||||
|
CantParseJSONFile,
|
||||||
|
CantFindConfig,
|
||||||
|
WorkingDirectoryDoesNotExist,
|
||||||
|
} from './errors-ts';
|
||||||
import humanizePath from './humanize-path';
|
import humanizePath from './humanize-path';
|
||||||
import readJSONFile from './read-json-file';
|
import readJSONFile from './read-json-file';
|
||||||
import readPackage from './read-package';
|
import readPackage from './read-package';
|
||||||
@@ -8,13 +12,25 @@ import { Output } from './output';
|
|||||||
|
|
||||||
let config: Config;
|
let config: Config;
|
||||||
|
|
||||||
export default async function getConfig(output: Output, configFile?: string) {
|
export default async function getConfig(
|
||||||
const localPath = process.cwd();
|
output: Output,
|
||||||
|
configFile?: string
|
||||||
|
): Promise<Config | Error> {
|
||||||
// If config was already read, just return it
|
// If config was already read, just return it
|
||||||
if (config) {
|
if (config) {
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let localPath: string;
|
||||||
|
try {
|
||||||
|
localPath = process.cwd();
|
||||||
|
} catch (err) {
|
||||||
|
if (err.code === 'ENOENT') {
|
||||||
|
return new WorkingDirectoryDoesNotExist();
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
// First try with the config supplied by the user via --local-config
|
// First try with the config supplied by the user via --local-config
|
||||||
if (configFile) {
|
if (configFile) {
|
||||||
const localFilePath = path.resolve(localPath, configFile);
|
const localFilePath = path.resolve(localPath, configFile);
|
||||||
|
|||||||
@@ -479,7 +479,7 @@ export default class Now extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const url = `/${
|
const url = `/${
|
||||||
isBuilds ? 'v9' : 'v5'
|
isBuilds ? 'v10' : 'v5'
|
||||||
}/now/deployments/${encodeURIComponent(id)}`;
|
}/now/deployments/${encodeURIComponent(id)}`;
|
||||||
|
|
||||||
return this.retry(
|
return this.retry(
|
||||||
|
|||||||
@@ -263,18 +263,25 @@ if (satisfies(process.version, '10.x')) {
|
|||||||
console.log('Skipping `02-angular-node` test since it requires Node >= 10.9');
|
console.log('Skipping `02-angular-node` test since it requires Node >= 10.9');
|
||||||
}
|
}
|
||||||
|
|
||||||
test(
|
// eslint has `engines: { node: ">^6.14.0 || ^8.10.0 || >=9.10.0" }` in its `package.json`
|
||||||
'[now dev] 03-aurelia',
|
if (satisfies(process.version, '>^6.14.0 || ^8.10.0 || >=9.10.0')) {
|
||||||
testFixtureStdio('03-aurelia', async (t, port) => {
|
test(
|
||||||
const result = fetch(`http://localhost:${port}`);
|
'[now dev] 03-aurelia',
|
||||||
const response = await result;
|
testFixtureStdio('03-aurelia', async (t, port) => {
|
||||||
|
const result = fetch(`http://localhost:${port}`);
|
||||||
|
const response = await result;
|
||||||
|
|
||||||
validateResponseHeaders(t, response);
|
validateResponseHeaders(t, response);
|
||||||
|
|
||||||
const body = await response.text();
|
const body = await response.text();
|
||||||
t.regex(body, /Aurelia Navigation Skeleton/gm);
|
t.regex(body, /Aurelia Navigation Skeleton/gm);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
'Skipping `03-aurelia` test since it requires Node >= ^6.14.0 || ^8.10.0 || >=9.10.0'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// test(
|
// test(
|
||||||
// '[now dev] 04-create-react-app-node',
|
// '[now dev] 04-create-react-app-node',
|
||||||
@@ -289,31 +296,45 @@ test(
|
|||||||
// })
|
// })
|
||||||
// );
|
// );
|
||||||
|
|
||||||
test(
|
// eslint has `engines: { node: ">^6.14.0 || ^8.10.0 || >=9.10.0" }` in its `package.json`
|
||||||
'[now dev] 05-gatsby',
|
if (satisfies(process.version, '>^6.14.0 || ^8.10.0 || >=9.10.0')) {
|
||||||
testFixtureStdio('05-gatsby', async (t, port) => {
|
test(
|
||||||
const result = fetch(`http://localhost:${port}`);
|
'[now dev] 05-gatsby',
|
||||||
const response = await result;
|
testFixtureStdio('05-gatsby', async (t, port) => {
|
||||||
|
const result = fetch(`http://localhost:${port}`);
|
||||||
|
const response = await result;
|
||||||
|
|
||||||
validateResponseHeaders(t, response);
|
validateResponseHeaders(t, response);
|
||||||
|
|
||||||
const body = await response.text();
|
const body = await response.text();
|
||||||
t.regex(body, /Gatsby Default Starter/gm);
|
t.regex(body, /Gatsby Default Starter/gm);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
'Skipping `05-gatsby` test since it requires Node >= ^6.14.0 || ^8.10.0 || >=9.10.0'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
test(
|
// mini-css-extract-plugin has `engines: { node: ">= 6.9.0 <7.0.0 || >= 8.9.0" }` in its `package.json`
|
||||||
'[now dev] 06-gridsome',
|
if (satisfies(process.version, '>= 6.9.0 <7.0.0 || >= 8.9.0')) {
|
||||||
testFixtureStdio('06-gridsome', async (t, port) => {
|
test(
|
||||||
const result = fetch(`http://localhost:${port}`);
|
'[now dev] 06-gridsome',
|
||||||
const response = await result;
|
testFixtureStdio('06-gridsome', async (t, port) => {
|
||||||
|
const result = fetch(`http://localhost:${port}`);
|
||||||
|
const response = await result;
|
||||||
|
|
||||||
validateResponseHeaders(t, response);
|
validateResponseHeaders(t, response);
|
||||||
|
|
||||||
const body = await response.text();
|
const body = await response.text();
|
||||||
t.regex(body, /Hello, world!/gm);
|
t.regex(body, /Hello, world!/gm);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
'Skipping `06-gridsome` test since it requires Node >= 6.9.0 <7.0.0 || >= 8.9.0'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
test(
|
test(
|
||||||
'[now dev] 07-hexo-node',
|
'[now dev] 07-hexo-node',
|
||||||
@@ -562,18 +583,25 @@ test('[now dev] double slashes redirect', async t => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test(
|
// eslint has `engines: { node: ">^6.14.0 || ^8.10.0 || >=9.10.0" }` in its `package.json`
|
||||||
'[now dev] 18-marko',
|
if (satisfies(process.version, '>^6.14.0 || ^8.10.0 || >=9.10.0')) {
|
||||||
testFixtureStdio('18-marko', async (t, port) => {
|
test(
|
||||||
const result = fetch(`http://localhost:${port}`);
|
'[now dev] 18-marko',
|
||||||
const response = await result;
|
testFixtureStdio('18-marko', async (t, port) => {
|
||||||
|
const result = fetch(`http://localhost:${port}`);
|
||||||
|
const response = await result;
|
||||||
|
|
||||||
validateResponseHeaders(t, response);
|
validateResponseHeaders(t, response);
|
||||||
|
|
||||||
const body = await response.text();
|
const body = await response.text();
|
||||||
t.regex(body, /Marko Starter/gm);
|
t.regex(body, /Marko Starter/gm);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
'Skipping `18-marko` test since it requires Node >= ^6.14.0 || ^8.10.0 || >=9.10.0'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
test(
|
test(
|
||||||
'[now dev] 19-mithril',
|
'[now dev] 19-mithril',
|
||||||
@@ -601,18 +629,23 @@ test(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
test(
|
// @static/charge has `engines: { node: ">= 8.10.0" }` in its `package.json`
|
||||||
'[now dev] 21-charge',
|
if (satisfies(process.version, '>= 8.10.0')) {
|
||||||
testFixtureStdio('21-charge', async (t, port) => {
|
test(
|
||||||
const result = fetch(`http://localhost:${port}`);
|
'[now dev] 21-charge',
|
||||||
const response = await result;
|
testFixtureStdio('21-charge', async (t, port) => {
|
||||||
|
const result = fetch(`http://localhost:${port}`);
|
||||||
|
const response = await result;
|
||||||
|
|
||||||
validateResponseHeaders(t, response);
|
validateResponseHeaders(t, response);
|
||||||
|
|
||||||
const body = await response.text();
|
const body = await response.text();
|
||||||
t.regex(body, /Welcome to my new Charge site/gm);
|
t.regex(body, /Welcome to my new Charge site/gm);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
console.log('Skipping `21-charge` test since it requires Node >= 8.10.0');
|
||||||
|
}
|
||||||
|
|
||||||
test(
|
test(
|
||||||
'[now dev] 22-brunch',
|
'[now dev] 22-brunch',
|
||||||
@@ -627,31 +660,43 @@ test(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
test(
|
// react-dev-utils has `engines: { node: ">= 8.10" }` in its `package.json`
|
||||||
'[now dev] 23-docusaurus',
|
if (satisfies(process.version, '>= 8.10')) {
|
||||||
testFixtureStdio('23-docusaurus', async (t, port) => {
|
test(
|
||||||
const result = fetch(`http://localhost:${port}`);
|
'[now dev] 23-docusaurus',
|
||||||
const response = await result;
|
testFixtureStdio('23-docusaurus', async (t, port) => {
|
||||||
|
const result = fetch(`http://localhost:${port}`);
|
||||||
|
const response = await result;
|
||||||
|
|
||||||
validateResponseHeaders(t, response);
|
validateResponseHeaders(t, response);
|
||||||
|
|
||||||
const body = await response.text();
|
const body = await response.text();
|
||||||
t.regex(body, /Test Site · A website for testing/gm);
|
t.regex(body, /Test Site · A website for testing/gm);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
console.log('Skipping `23-docusaurus` test since it requires Node >= 8.10');
|
||||||
|
}
|
||||||
|
|
||||||
test(
|
// eslint has `engines: { node: ">^6.14.0 || ^8.10.0 || >=9.10.0" }` in its `package.json`
|
||||||
'[now dev] 24-ember',
|
if (satisfies(process.version, '>^6.14.0 || ^8.10.0 || >=9.10.0')) {
|
||||||
testFixtureStdio('24-ember', async (t, port) => {
|
test(
|
||||||
const result = fetch(`http://localhost:${port}`);
|
'[now dev] 24-ember',
|
||||||
const response = await result;
|
testFixtureStdio('24-ember', async (t, port) => {
|
||||||
|
const result = fetch(`http://localhost:${port}`);
|
||||||
|
const response = await result;
|
||||||
|
|
||||||
validateResponseHeaders(t, response);
|
validateResponseHeaders(t, response);
|
||||||
|
|
||||||
const body = await response.text();
|
const body = await response.text();
|
||||||
t.regex(body, /HelloWorld/gm);
|
t.regex(body, /HelloWorld/gm);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
'Skipping `24-ember` test since it requires Node >= ^6.14.0 || ^8.10.0 || >=9.10.0'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
test('[now dev] temporary directory listing', async t => {
|
test('[now dev] temporary directory listing', async t => {
|
||||||
const directory = fixture('temporary-directory-listing');
|
const directory = fixture('temporary-directory-listing');
|
||||||
@@ -870,22 +915,28 @@ test('[now dev] do not rebuild for changes in the output directory', async t =>
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[now dev] 25-nextjs-src-dir', async t => {
|
if (satisfies(process.version, '>= 8.9.0')) {
|
||||||
const directory = fixture('25-nextjs-src-dir');
|
test('[now dev] 25-nextjs-src-dir', async t => {
|
||||||
const { dev, port } = await testFixture(directory);
|
const directory = fixture('25-nextjs-src-dir');
|
||||||
|
const { dev, port } = await testFixture(directory);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// start `now dev` detached in child_process
|
// start `now dev` detached in child_process
|
||||||
dev.unref();
|
dev.unref();
|
||||||
|
|
||||||
const result = await fetchWithRetry(`http://localhost:${port}`, 80);
|
const result = await fetchWithRetry(`http://localhost:${port}`, 80);
|
||||||
const response = await result;
|
const response = await result;
|
||||||
|
|
||||||
validateResponseHeaders(t, response);
|
validateResponseHeaders(t, response);
|
||||||
|
|
||||||
const body = await response.text();
|
const body = await response.text();
|
||||||
t.regex(body, /Next.js \+ Node.js API/gm);
|
t.regex(body, /Next.js \+ Node.js API/gm);
|
||||||
} finally {
|
} finally {
|
||||||
dev.kill('SIGTERM');
|
dev.kill('SIGTERM');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
'Skipping `25-nextjs-src-dir` test since it requires Node >= 8.9.0'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
71
packages/now-cli/test/integration.js
vendored
71
packages/now-cli/test/integration.js
vendored
@@ -2037,6 +2037,40 @@ test('try to deploy with non-existing team', async t => {
|
|||||||
t.true(stderr.includes(goal));
|
t.true(stderr.includes(goal));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testv1('try to deploy v1 deployment with --prod', async t => {
|
||||||
|
const target = fixture('node');
|
||||||
|
const goal = `is not supported for Now 1.0 deployments`;
|
||||||
|
|
||||||
|
const { stderr, stdout, code } = await execa(binaryPath, [target, '--prod'], {
|
||||||
|
reject: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(stderr);
|
||||||
|
console.log(stdout);
|
||||||
|
console.log(code);
|
||||||
|
|
||||||
|
t.is(code, 1);
|
||||||
|
t.true(stderr.includes(goal));
|
||||||
|
});
|
||||||
|
|
||||||
|
testv1('try to deploy v1 deployment with --target production', async t => {
|
||||||
|
const target = fixture('node');
|
||||||
|
const goal = `is not supported for Now 1.0 deployments`;
|
||||||
|
|
||||||
|
const { stderr, stdout, code } = await execa(
|
||||||
|
binaryPath,
|
||||||
|
[target, '--target', 'production'],
|
||||||
|
{ reject: false }
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(stderr);
|
||||||
|
console.log(stdout);
|
||||||
|
console.log(code);
|
||||||
|
|
||||||
|
t.is(code, 1);
|
||||||
|
t.true(stderr.includes(goal));
|
||||||
|
});
|
||||||
|
|
||||||
const verifyExampleAngular = (cwd, dir) =>
|
const verifyExampleAngular = (cwd, dir) =>
|
||||||
fs.existsSync(path.join(cwd, dir, 'package.json')) &&
|
fs.existsSync(path.join(cwd, dir, 'package.json')) &&
|
||||||
fs.existsSync(path.join(cwd, dir, 'tsconfig.json')) &&
|
fs.existsSync(path.join(cwd, dir, 'tsconfig.json')) &&
|
||||||
@@ -2471,6 +2505,43 @@ test('now secret rm', async t => {
|
|||||||
t.is(output.code, 0, formatOutput(output));
|
t.is(output.code, 0, formatOutput(output));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('deploy with a custom API URL', async t => {
|
||||||
|
const directory = fixture('static-single-file');
|
||||||
|
|
||||||
|
const { stdout, stderr, code } = await execa(
|
||||||
|
binaryPath,
|
||||||
|
[
|
||||||
|
directory,
|
||||||
|
'--public',
|
||||||
|
'--name',
|
||||||
|
session,
|
||||||
|
'--api',
|
||||||
|
'https://zeit.co/api',
|
||||||
|
...defaultArgs,
|
||||||
|
],
|
||||||
|
{
|
||||||
|
reject: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(stderr);
|
||||||
|
console.log(stdout);
|
||||||
|
console.log(code);
|
||||||
|
|
||||||
|
// Ensure the exit code is right
|
||||||
|
t.is(code, 0);
|
||||||
|
|
||||||
|
// Test if the output is really a URL
|
||||||
|
const { href, host } = new URL(stdout);
|
||||||
|
t.is(host.split('-')[0], session);
|
||||||
|
|
||||||
|
// Send a test request to the deployment
|
||||||
|
const response = await fetch(href);
|
||||||
|
const contentType = response.headers.get('content-type');
|
||||||
|
|
||||||
|
t.is(contentType, 'text/html; charset=utf-8');
|
||||||
|
});
|
||||||
|
|
||||||
test.after.always(async () => {
|
test.after.always(async () => {
|
||||||
// Make sure the token gets revoked
|
// Make sure the token gets revoked
|
||||||
await execa(binaryPath, ['logout', ...defaultArgs]);
|
await execa(binaryPath, ['logout', ...defaultArgs]);
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
src
|
|
||||||
types
|
|
||||||
.git
|
|
||||||
@@ -1,9 +1,18 @@
|
|||||||
{
|
{
|
||||||
"name": "now-client",
|
"name": "now-client",
|
||||||
"version": "5.2.1",
|
"version": "5.2.2",
|
||||||
"main": "dist/src/index.js",
|
"main": "dist/src/index.js",
|
||||||
"typings": "dist/src/index.d.ts",
|
"typings": "dist/src/index.d.ts",
|
||||||
|
"homepage": "https://zeit.co",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/zeit/now.git",
|
||||||
|
"directory": "packages/now-client"
|
||||||
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"prepare": "npm run build",
|
"prepare": "npm run build",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { readdir as readRootFolder, lstatSync } from 'fs-extra';
|
import { readdir as readRootFolder, lstatSync } from 'fs-extra';
|
||||||
|
|
||||||
import readdir from 'recursive-readdir';
|
import readdir from 'recursive-readdir';
|
||||||
import { relative, join } from 'path';
|
import { relative, join, isAbsolute } from 'path';
|
||||||
import hashes, { mapToObject } from './utils/hashes';
|
import hashes, { mapToObject } from './utils/hashes';
|
||||||
import uploadAndDeploy from './upload';
|
import uploadAndDeploy from './upload';
|
||||||
import { getNowIgnore, createDebug, parseNowJSON } from './utils';
|
import { getNowIgnore, createDebug, parseNowJSON } from './utils';
|
||||||
@@ -53,6 +53,22 @@ export default function buildCreateDeployment(
|
|||||||
|
|
||||||
let rootFiles: string[];
|
let rootFiles: string[];
|
||||||
|
|
||||||
|
if (Array.isArray(path)) {
|
||||||
|
for (const filePath of path) {
|
||||||
|
if (!isAbsolute(filePath)) {
|
||||||
|
throw new DeploymentError({
|
||||||
|
code: 'invalid_path',
|
||||||
|
message: `Provided path ${filePath} is not absolute`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (!isAbsolute(path)) {
|
||||||
|
throw new DeploymentError({
|
||||||
|
code: 'invalid_path',
|
||||||
|
message: `Provided path ${path} is not absolute`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (isDirectory && !Array.isArray(path)) {
|
if (isDirectory && !Array.isArray(path)) {
|
||||||
debug(`Provided 'path' is a directory. Reading subpaths... `);
|
debug(`Provided 'path' is a directory. Reading subpaths... `);
|
||||||
rootFiles = await readRootFolder(path);
|
rootFiles = await readRootFolder(path);
|
||||||
@@ -171,9 +187,14 @@ export default function buildCreateDeployment(
|
|||||||
force,
|
force,
|
||||||
defaultName,
|
defaultName,
|
||||||
debug: debug_,
|
debug: debug_,
|
||||||
|
apiUrl,
|
||||||
...metadata
|
...metadata
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
|
if (apiUrl) {
|
||||||
|
debug(`Using provided API URL: ${apiUrl}`);
|
||||||
|
}
|
||||||
|
|
||||||
debug(`Setting platform version to ${version}`);
|
debug(`Setting platform version to ${version}`);
|
||||||
metadata.version = version;
|
metadata.version = version;
|
||||||
|
|
||||||
@@ -188,6 +209,7 @@ export default function buildCreateDeployment(
|
|||||||
force,
|
force,
|
||||||
defaultName,
|
defaultName,
|
||||||
metadata,
|
metadata,
|
||||||
|
apiUrl,
|
||||||
};
|
};
|
||||||
|
|
||||||
debug(`Creating the deployment and starting upload...`);
|
debug(`Creating the deployment and starting upload...`);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
import checkDeploymentStatus from './deployment-status';
|
import checkDeploymentStatus from './deployment-status';
|
||||||
import { generateQueryString } from './utils/query-string';
|
import { generateQueryString } from './utils/query-string';
|
||||||
import { Deployment, DeploymentOptions, NowJsonOptions } from './types';
|
import { Deployment, DeploymentOptions, NowJsonOptions } from './types';
|
||||||
|
import { isReady, isAliasAssigned } from './utils/ready-state';
|
||||||
|
|
||||||
export interface Options {
|
export interface Options {
|
||||||
metadata: DeploymentOptions;
|
metadata: DeploymentOptions;
|
||||||
@@ -22,6 +23,7 @@ export interface Options {
|
|||||||
preflight?: boolean;
|
preflight?: boolean;
|
||||||
debug?: boolean;
|
debug?: boolean;
|
||||||
nowConfig?: NowJsonOptions;
|
nowConfig?: NowJsonOptions;
|
||||||
|
apiUrl?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function* createDeployment(
|
async function* createDeployment(
|
||||||
@@ -50,6 +52,7 @@ async function* createDeployment(
|
|||||||
...metadata,
|
...metadata,
|
||||||
files: preparedFiles,
|
files: preparedFiles,
|
||||||
}),
|
}),
|
||||||
|
apiUrl: options.apiUrl,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -191,9 +194,12 @@ export default async function* deploy(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (deployment) {
|
if (deployment) {
|
||||||
if (deployment.readyState === 'READY') {
|
if (isReady(deployment) && isAliasAssigned(deployment)) {
|
||||||
debug('Deployment is READY. Not performing additional polling');
|
debug('Deployment state changed to READY 3');
|
||||||
return yield { type: 'ready', payload: deployment };
|
yield { type: 'ready', payload: deployment };
|
||||||
|
|
||||||
|
debug('Deployment alias assigned');
|
||||||
|
return yield { type: 'alias-assigned', payload: deployment };
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -203,7 +209,8 @@ export default async function* deploy(
|
|||||||
options.token,
|
options.token,
|
||||||
metadata.version,
|
metadata.version,
|
||||||
options.teamId,
|
options.teamId,
|
||||||
debug
|
debug,
|
||||||
|
options.apiUrl
|
||||||
)) {
|
)) {
|
||||||
yield event;
|
yield event;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
import sleep from 'sleep-promise';
|
import sleep from 'sleep-promise';
|
||||||
import ms from 'ms';
|
import ms from 'ms';
|
||||||
import { fetch, API_DEPLOYMENTS, API_DEPLOYMENTS_LEGACY } from './utils';
|
import { fetch, API_DEPLOYMENTS, API_DEPLOYMENTS_LEGACY } from './utils';
|
||||||
import { isDone, isReady, isFailed } from './utils/ready-state';
|
import {
|
||||||
|
isDone,
|
||||||
|
isReady,
|
||||||
|
isFailed,
|
||||||
|
isAliasAssigned,
|
||||||
|
isAliasError,
|
||||||
|
} from './utils/ready-state';
|
||||||
import { Deployment, DeploymentBuild } from './types';
|
import { Deployment, DeploymentBuild } from './types';
|
||||||
|
|
||||||
interface DeploymentStatus {
|
interface DeploymentStatus {
|
||||||
@@ -15,7 +21,8 @@ export default async function* checkDeploymentStatus(
|
|||||||
token: string,
|
token: string,
|
||||||
version: number | undefined,
|
version: number | undefined,
|
||||||
teamId: string | undefined,
|
teamId: string | undefined,
|
||||||
debug: Function
|
debug: Function,
|
||||||
|
apiUrl?: string
|
||||||
): AsyncIterableIterator<DeploymentStatus> {
|
): AsyncIterableIterator<DeploymentStatus> {
|
||||||
let deploymentState = deployment;
|
let deploymentState = deployment;
|
||||||
let allBuildsCompleted = false;
|
let allBuildsCompleted = false;
|
||||||
@@ -25,20 +32,24 @@ export default async function* checkDeploymentStatus(
|
|||||||
debug(`Using ${version ? `${version}.0` : '2.0'} API for status checks`);
|
debug(`Using ${version ? `${version}.0` : '2.0'} API for status checks`);
|
||||||
|
|
||||||
// If the deployment is ready, we don't want any of this to run
|
// If the deployment is ready, we don't want any of this to run
|
||||||
if (isDone(deploymentState)) {
|
if (isDone(deploymentState) && isAliasAssigned(deploymentState)) {
|
||||||
debug(`Deployment is already READY. Not running status checks`);
|
debug(
|
||||||
|
`Deployment is already READY and aliases are assigned. Not running status checks`
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build polling
|
// Build polling
|
||||||
debug('Waiting for builds and the deployment to complete...');
|
debug('Waiting for builds and the deployment to complete...');
|
||||||
|
let readyEventFired = false;
|
||||||
while (true) {
|
while (true) {
|
||||||
if (!allBuildsCompleted) {
|
if (!allBuildsCompleted) {
|
||||||
const buildsData = await fetch(
|
const buildsData = await fetch(
|
||||||
`${apiDeployments}/${deployment.id}/builds${
|
`${apiDeployments}/${deployment.id}/builds${
|
||||||
teamId ? `?teamId=${teamId}` : ''
|
teamId ? `?teamId=${teamId}` : ''
|
||||||
}`,
|
}`,
|
||||||
token
|
token,
|
||||||
|
{ apiUrl }
|
||||||
);
|
);
|
||||||
|
|
||||||
const data = await buildsData.json();
|
const data = await buildsData.json();
|
||||||
@@ -84,16 +95,30 @@ export default async function* checkDeploymentStatus(
|
|||||||
return yield { type: 'error', payload: deploymentUpdate.error };
|
return yield { type: 'error', payload: deploymentUpdate.error };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isReady(deploymentUpdate)) {
|
if (isReady(deploymentUpdate) && !readyEventFired) {
|
||||||
debug('Deployment state changed to READY');
|
debug('Deployment state changed to READY 2');
|
||||||
return yield { type: 'ready', payload: deploymentUpdate };
|
readyEventFired = true;
|
||||||
|
yield { type: 'ready', payload: deploymentUpdate };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isFailed(deploymentUpdate)) {
|
if (isAliasAssigned(deploymentUpdate)) {
|
||||||
debug('Deployment has failed');
|
debug('Deployment alias assigned');
|
||||||
|
return yield { type: 'alias-assigned', payload: deploymentUpdate };
|
||||||
|
}
|
||||||
|
|
||||||
|
const aliasError = isAliasError(deploymentUpdate);
|
||||||
|
|
||||||
|
if (isFailed(deploymentUpdate) || aliasError) {
|
||||||
|
debug(
|
||||||
|
aliasError
|
||||||
|
? 'Alias assignment error has occurred'
|
||||||
|
: 'Deployment has failed'
|
||||||
|
);
|
||||||
return yield {
|
return yield {
|
||||||
type: 'error',
|
type: 'error',
|
||||||
payload: deploymentUpdate.error || deploymentUpdate,
|
payload: aliasError
|
||||||
|
? deploymentUpdate.aliasError
|
||||||
|
: deploymentUpdate.error || deploymentUpdate,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ export interface Deployment {
|
|||||||
};
|
};
|
||||||
target: string;
|
target: string;
|
||||||
alias: string[];
|
alias: string[];
|
||||||
|
aliasAssigned: boolean;
|
||||||
|
aliasError: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DeploymentBuild {
|
export interface DeploymentBuild {
|
||||||
@@ -117,6 +119,7 @@ export interface DeploymentOptions {
|
|||||||
sessionAffinity?: 'ip' | 'random';
|
sessionAffinity?: 'ip' | 'random';
|
||||||
config?: { [key: string]: any };
|
config?: { [key: string]: any };
|
||||||
debug?: boolean;
|
debug?: boolean;
|
||||||
|
apiUrl?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NowJsonOptions {
|
export interface NowJsonOptions {
|
||||||
|
|||||||
@@ -26,9 +26,9 @@ const isClientNetworkError = (err: Error | DeploymentError) => {
|
|||||||
|
|
||||||
export default async function* upload(
|
export default async function* upload(
|
||||||
files: Map<string, DeploymentFile>,
|
files: Map<string, DeploymentFile>,
|
||||||
options: Options,
|
options: Options
|
||||||
): AsyncIterableIterator<any> {
|
): AsyncIterableIterator<any> {
|
||||||
const { token, teamId, debug: isDebug } = options;
|
const { token, teamId, debug: isDebug, apiUrl } = options;
|
||||||
const debug = createDebug(isDebug);
|
const debug = createDebug(isDebug);
|
||||||
|
|
||||||
if (!files && !token && !teamId) {
|
if (!files && !token && !teamId) {
|
||||||
@@ -51,7 +51,7 @@ export default async function* upload(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// If the deployment has succeeded here, don't continue
|
// If the deployment has succeeded here, don't continue
|
||||||
if (event.type === 'ready') {
|
if (event.type === 'alias-assigned') {
|
||||||
debug('Deployment succeeded on file check');
|
debug('Deployment succeeded on file check');
|
||||||
|
|
||||||
return yield event;
|
return yield event;
|
||||||
@@ -103,6 +103,7 @@ export default async function* upload(
|
|||||||
},
|
},
|
||||||
body: stream,
|
body: stream,
|
||||||
teamId,
|
teamId,
|
||||||
|
apiUrl,
|
||||||
},
|
},
|
||||||
isDebug
|
isDebug
|
||||||
);
|
);
|
||||||
@@ -184,7 +185,7 @@ export default async function* upload(
|
|||||||
try {
|
try {
|
||||||
debug('Starting deployment creation');
|
debug('Starting deployment creation');
|
||||||
for await (const event of deploy(files, options)) {
|
for await (const event of deploy(files, options)) {
|
||||||
if (event.type === 'ready') {
|
if (event.type === 'alias-assigned') {
|
||||||
debug('Deployment is ready');
|
debug('Deployment is ready');
|
||||||
return yield event;
|
return yield event;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,11 +11,10 @@ import { Sema } from 'async-sema';
|
|||||||
import { readFile } from 'fs-extra';
|
import { readFile } from 'fs-extra';
|
||||||
const semaphore = new Sema(10);
|
const semaphore = new Sema(10);
|
||||||
|
|
||||||
export const API_FILES = 'https://api.zeit.co/v2/now/files';
|
export const API_FILES = '/v2/now/files';
|
||||||
export const API_DEPLOYMENTS = 'https://api.zeit.co/v9/now/deployments';
|
export const API_DEPLOYMENTS = '/v10/now/deployments';
|
||||||
export const API_DEPLOYMENTS_LEGACY = 'https://api.zeit.co/v3/now/deployments';
|
export const API_DEPLOYMENTS_LEGACY = '/v3/now/deployments';
|
||||||
export const API_DELETE_DEPLOYMENTS_LEGACY =
|
export const API_DELETE_DEPLOYMENTS_LEGACY = '/v2/now/deployments';
|
||||||
'https://api.zeit.co/v2/now/deployments';
|
|
||||||
|
|
||||||
export const EVENTS = new Set([
|
export const EVENTS = new Set([
|
||||||
// File events
|
// File events
|
||||||
@@ -26,6 +25,7 @@ export const EVENTS = new Set([
|
|||||||
// Deployment events
|
// Deployment events
|
||||||
'created',
|
'created',
|
||||||
'ready',
|
'ready',
|
||||||
|
'alias-assigned',
|
||||||
'warning',
|
'warning',
|
||||||
'error',
|
'error',
|
||||||
// Build events
|
// Build events
|
||||||
@@ -109,6 +109,9 @@ export const fetch = async (
|
|||||||
const debug = createDebug(debugEnabled);
|
const debug = createDebug(debugEnabled);
|
||||||
let time: number;
|
let time: number;
|
||||||
|
|
||||||
|
url = `${opts.apiUrl || 'https://api.zeit.co'}${url}`;
|
||||||
|
delete opts.apiUrl;
|
||||||
|
|
||||||
if (opts.teamId) {
|
if (opts.teamId) {
|
||||||
const parsedUrl = parseUrl(url, true);
|
const parsedUrl = parseUrl(url, true);
|
||||||
const query = parsedUrl.query;
|
const query = parsedUrl.query;
|
||||||
|
|||||||
@@ -14,3 +14,7 @@ export const isFailed = ({
|
|||||||
export const isDone = (
|
export const isDone = (
|
||||||
buildOrDeployment: Deployment | DeploymentBuild
|
buildOrDeployment: Deployment | DeploymentBuild
|
||||||
): boolean => isReady(buildOrDeployment) || isFailed(buildOrDeployment);
|
): boolean => isReady(buildOrDeployment) || isFailed(buildOrDeployment);
|
||||||
|
export const isAliasAssigned = (deployment: Deployment): boolean =>
|
||||||
|
Boolean(deployment.aliasAssigned);
|
||||||
|
export const isAliasError = (deployment: Deployment): boolean =>
|
||||||
|
Boolean(deployment.aliasError);
|
||||||
|
|||||||
30
packages/now-client/tests/common.ts
Normal file
30
packages/now-client/tests/common.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import fetch from 'node-fetch';
|
||||||
|
const str = 'aHR0cHM6Ly9hcGktdG9rZW4tZmFjdG9yeS56ZWl0LnNo';
|
||||||
|
|
||||||
|
async function fetchTokenWithRetry(url: string, retries = 3): Promise<string> {
|
||||||
|
try {
|
||||||
|
const res = await fetch(url);
|
||||||
|
const data = await res.json();
|
||||||
|
return data.token;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(`Failed to fetch token. Retries remaining: ${retries}`);
|
||||||
|
if (retries === 0) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
await sleep(500);
|
||||||
|
return fetchTokenWithRetry(url, retries - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function generateNewToken(): Promise<string> {
|
||||||
|
const token = await fetchTokenWithRetry(
|
||||||
|
Buffer.from(str, 'base64').toString()
|
||||||
|
);
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function sleep(ms: number) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
setTimeout(resolve, ms);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
// zeit-support user
|
|
||||||
export const TOKEN = 'HRp5EAN0TZBnSUBIleD3ZrMW'
|
|
||||||
@@ -1,19 +1,24 @@
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { TOKEN } from './constants';
|
import { generateNewToken } from './common';
|
||||||
import { fetch, API_DEPLOYMENTS } from '../src/utils';
|
import { fetch, API_DEPLOYMENTS } from '../src/utils';
|
||||||
import { Deployment } from './types';
|
import { Deployment } from './types';
|
||||||
import { createDeployment } from '../src/index';
|
import { createDeployment } from '../src/index';
|
||||||
|
|
||||||
describe('create v2 deployment', () => {
|
describe('create v2 deployment', () => {
|
||||||
let deployment: Deployment;
|
let deployment: Deployment;
|
||||||
|
let token = '';
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
token = await generateNewToken();
|
||||||
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
if (deployment) {
|
if (deployment) {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`${API_DEPLOYMENTS}/${deployment.id}`,
|
`${API_DEPLOYMENTS}/${deployment.id}`,
|
||||||
TOKEN,
|
token,
|
||||||
{
|
{
|
||||||
method: 'DELETE'
|
method: 'DELETE',
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
expect(response.status).toEqual(200);
|
expect(response.status).toEqual(200);
|
||||||
@@ -24,8 +29,8 @@ describe('create v2 deployment', () => {
|
|||||||
for await (const event of createDeployment(
|
for await (const event of createDeployment(
|
||||||
path.resolve(__dirname, 'fixtures', 'v2'),
|
path.resolve(__dirname, 'fixtures', 'v2'),
|
||||||
{
|
{
|
||||||
token: TOKEN,
|
token,
|
||||||
name: 'now-client-tests-v2'
|
name: 'now-client-tests-v2',
|
||||||
}
|
}
|
||||||
)) {
|
)) {
|
||||||
if (event.type === 'warning') {
|
if (event.type === 'warning') {
|
||||||
@@ -43,8 +48,8 @@ describe('create v2 deployment', () => {
|
|||||||
for await (const event of createDeployment(
|
for await (const event of createDeployment(
|
||||||
path.resolve(__dirname, 'fixtures', 'v2'),
|
path.resolve(__dirname, 'fixtures', 'v2'),
|
||||||
{
|
{
|
||||||
token: TOKEN,
|
token,
|
||||||
name: 'now-client-tests-v2'
|
name: 'now-client-tests-v2',
|
||||||
}
|
}
|
||||||
)) {
|
)) {
|
||||||
if (event.type === 'file_count') {
|
if (event.type === 'file_count') {
|
||||||
@@ -62,8 +67,8 @@ describe('create v2 deployment', () => {
|
|||||||
for await (const event of createDeployment(
|
for await (const event of createDeployment(
|
||||||
path.resolve(__dirname, 'fixtures', 'v2'),
|
path.resolve(__dirname, 'fixtures', 'v2'),
|
||||||
{
|
{
|
||||||
token: TOKEN,
|
token,
|
||||||
name: 'now-client-tests-v2'
|
name: 'now-client-tests-v2',
|
||||||
}
|
}
|
||||||
)) {
|
)) {
|
||||||
if (event.type === 'ready') {
|
if (event.type === 'ready') {
|
||||||
|
|||||||
@@ -1,77 +1,83 @@
|
|||||||
import path from 'path'
|
import path from 'path';
|
||||||
import { TOKEN } from './constants'
|
import { generateNewToken } from './common';
|
||||||
import { fetch, API_DELETE_DEPLOYMENTS_LEGACY } from '../src/utils'
|
import { fetch, API_DELETE_DEPLOYMENTS_LEGACY } from '../src/utils';
|
||||||
import { Deployment } from './types'
|
import { Deployment } from './types';
|
||||||
import { createLegacyDeployment } from '../src/index'
|
import { createLegacyDeployment } from '../src/index';
|
||||||
|
|
||||||
describe('create v1 deployment', () => {
|
describe('create v1 deployment', () => {
|
||||||
let deployment: Deployment | undefined
|
let deployment: Deployment | undefined;
|
||||||
|
let token = '';
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
token = await generateNewToken();
|
||||||
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
if (deployment) {
|
if (deployment) {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`${API_DELETE_DEPLOYMENTS_LEGACY}/${deployment.deploymentId || deployment.uid}`,
|
`${API_DELETE_DEPLOYMENTS_LEGACY}/${deployment.deploymentId ||
|
||||||
TOKEN,
|
deployment.uid}`,
|
||||||
|
token,
|
||||||
{
|
{
|
||||||
method: 'DELETE'
|
method: 'DELETE',
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
expect(response.status).toEqual(200)
|
expect(response.status).toEqual(200);
|
||||||
deployment = undefined
|
deployment = undefined;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
it('will create a v1 static deployment', async () => {
|
it('will create a v1 static deployment', async () => {
|
||||||
for await (const event of createLegacyDeployment(
|
for await (const event of createLegacyDeployment(
|
||||||
path.resolve(__dirname, 'fixtures', 'v1', 'static'),
|
path.resolve(__dirname, 'fixtures', 'v1', 'static'),
|
||||||
{
|
{
|
||||||
token: TOKEN,
|
token,
|
||||||
name: 'now-client-tests-v1-static'
|
name: 'now-client-tests-v1-static',
|
||||||
}
|
}
|
||||||
)) {
|
)) {
|
||||||
if (event.type === 'ready') {
|
if (event.type === 'ready') {
|
||||||
deployment = event.payload
|
deployment = event.payload;
|
||||||
if (deployment) {
|
if (deployment) {
|
||||||
expect(deployment.readyState || deployment.state).toEqual('READY')
|
expect(deployment.readyState || deployment.state).toEqual('READY');
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
it('will create a v1 npm deployment', async () => {
|
it('will create a v1 npm deployment', async () => {
|
||||||
for await (const event of createLegacyDeployment(
|
for await (const event of createLegacyDeployment(
|
||||||
path.resolve(__dirname, 'fixtures', 'v1', 'npm'),
|
path.resolve(__dirname, 'fixtures', 'v1', 'npm'),
|
||||||
{
|
{
|
||||||
token: TOKEN,
|
token,
|
||||||
name: 'now-client-tests-v1-npm'
|
name: 'now-client-tests-v1-npm',
|
||||||
}
|
}
|
||||||
)) {
|
)) {
|
||||||
if (event.type === 'ready') {
|
if (event.type === 'ready') {
|
||||||
deployment = event.payload
|
deployment = event.payload;
|
||||||
if (deployment) {
|
if (deployment) {
|
||||||
expect(deployment.readyState || deployment.state).toEqual('READY')
|
expect(deployment.readyState || deployment.state).toEqual('READY');
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
it('will create a v1 Docker deployment', async () => {
|
it('will create a v1 Docker deployment', async () => {
|
||||||
for await (const event of createLegacyDeployment(
|
for await (const event of createLegacyDeployment(
|
||||||
path.resolve(__dirname, 'fixtures', 'v1', 'docker'),
|
path.resolve(__dirname, 'fixtures', 'v1', 'docker'),
|
||||||
{
|
{
|
||||||
token: TOKEN,
|
token,
|
||||||
name: 'now-client-tests-v1-docker'
|
name: 'now-client-tests-v1-docker',
|
||||||
}
|
}
|
||||||
)) {
|
)) {
|
||||||
if (event.type === 'ready') {
|
if (event.type === 'ready') {
|
||||||
deployment = event.payload
|
deployment = event.payload;
|
||||||
if (deployment) {
|
if (deployment) {
|
||||||
expect(deployment.readyState || deployment.state).toEqual('READY')
|
expect(deployment.readyState || deployment.state).toEqual('READY');
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|||||||
32
packages/now-client/tests/paths.test.ts
Normal file
32
packages/now-client/tests/paths.test.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { generateNewToken } from './common';
|
||||||
|
import { createDeployment } from '../src/index';
|
||||||
|
|
||||||
|
describe('path handling', () => {
|
||||||
|
let token = '';
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
token = await generateNewToken();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('will fali with a relative path', async () => {
|
||||||
|
try {
|
||||||
|
await createDeployment('./fixtures/v2/now.json', {
|
||||||
|
token,
|
||||||
|
name: 'now-client-tests-v2',
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
expect(e.code).toEqual('invalid_path');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('will fali with an array of relative paths', async () => {
|
||||||
|
try {
|
||||||
|
await createDeployment(['./fixtures/v2/now.json'], {
|
||||||
|
token,
|
||||||
|
name: 'now-client-tests-v2',
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
expect(e.code).toEqual('invalid_path');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1 +1 @@
|
|||||||
jest.setTimeout(120000)
|
jest.setTimeout(120000);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@now/next",
|
"name": "@now/next",
|
||||||
"version": "1.0.4",
|
"version": "1.0.5",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./dist/index",
|
"main": "./dist/index",
|
||||||
"homepage": "https://zeit.co/docs/v2/deployments/official-builders/next-js-now-next",
|
"homepage": "https://zeit.co/docs/v2/deployments/official-builders/next-js-now-next",
|
||||||
|
|||||||
@@ -715,7 +715,7 @@ export const build = async ({
|
|||||||
{
|
{
|
||||||
// This ensures we only match known emitted-by-Next.js files and not
|
// This ensures we only match known emitted-by-Next.js files and not
|
||||||
// user-emitted files which may be missing a hash in their filename.
|
// user-emitted files which may be missing a hash in their filename.
|
||||||
src: '/_next/static/(?:[^/]+/pages|chunks|runtime)/.+',
|
src: '/_next/static/(?:[^/]+/pages|chunks|runtime|css|media)/.+',
|
||||||
// Next.js assets contain a hash or entropy in their filenames, so they
|
// Next.js assets contain a hash or entropy in their filenames, so they
|
||||||
// are guaranteed to be unique and cacheable indefinitely.
|
// are guaranteed to be unique and cacheable indefinitely.
|
||||||
headers: { 'cache-control': 'public,max-age=31536000,immutable' },
|
headers: { 'cache-control': 'public,max-age=31536000,immutable' },
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@now/python",
|
"name": "@now/python",
|
||||||
"version": "0.3.2",
|
"version": "0.3.3",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"homepage": "https://zeit.co/docs/v2/deployments/official-builders/python-now-python",
|
"homepage": "https://zeit.co/docs/v2/deployments/official-builders/python-now-python",
|
||||||
|
|||||||
@@ -16,6 +16,14 @@ import {
|
|||||||
|
|
||||||
async function pipInstall(pipPath: string, workDir: string, ...args: string[]) {
|
async function pipInstall(pipPath: string, workDir: string, ...args: string[]) {
|
||||||
const target = '.';
|
const target = '.';
|
||||||
|
// See: https://github.com/pypa/pip/issues/4222#issuecomment-417646535
|
||||||
|
//
|
||||||
|
// Disable installing to the Python user install directory, which is
|
||||||
|
// the default behavior on Debian systems and causes error:
|
||||||
|
//
|
||||||
|
// distutils.errors.DistutilsOptionError: can't combine user with
|
||||||
|
// prefix, exec_prefix/home, or install_(plat)base
|
||||||
|
process.env.PIP_USER = '0';
|
||||||
debug(
|
debug(
|
||||||
`Running "pip install --disable-pip-version-check --target ${target} --upgrade ${args.join(
|
`Running "pip install --disable-pip-version-check --target ${target} --upgrade ${args.join(
|
||||||
' '
|
' '
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@now/routing-utils",
|
"name": "@now/routing-utils",
|
||||||
"version": "1.3.0",
|
"version": "1.3.1",
|
||||||
"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",
|
||||||
|
|||||||
@@ -135,11 +135,9 @@ export function getTransformedRoutes({
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
routes = [];
|
routes = [];
|
||||||
let cleanUrlsRewrites: Route[] | undefined;
|
if (cleanUrls) {
|
||||||
if (typeof cleanUrls !== 'undefined') {
|
const clean = convertCleanUrls(filePaths);
|
||||||
const cleanUrls = convertCleanUrls(filePaths);
|
routes.push(...clean.redirects);
|
||||||
cleanUrlsRewrites = cleanUrls.rewrites;
|
|
||||||
routes.push(...cleanUrls.redirects);
|
|
||||||
}
|
}
|
||||||
if (typeof trailingSlash !== 'undefined') {
|
if (typeof trailingSlash !== 'undefined') {
|
||||||
routes.push(...convertTrailingSlash(trailingSlash));
|
routes.push(...convertTrailingSlash(trailingSlash));
|
||||||
@@ -150,16 +148,8 @@ export function getTransformedRoutes({
|
|||||||
if (typeof headers !== 'undefined') {
|
if (typeof headers !== 'undefined') {
|
||||||
routes.push(...convertHeaders(headers));
|
routes.push(...convertHeaders(headers));
|
||||||
}
|
}
|
||||||
if (typeof cleanUrlsRewrites !== 'undefined') {
|
|
||||||
routes.push(...cleanUrlsRewrites);
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
typeof cleanUrlsRewrites !== 'undefined' ||
|
|
||||||
typeof rewrites !== 'undefined'
|
|
||||||
) {
|
|
||||||
routes.push({ handle: 'filesystem' });
|
|
||||||
}
|
|
||||||
if (typeof rewrites !== 'undefined') {
|
if (typeof rewrites !== 'undefined') {
|
||||||
|
routes.push({ handle: 'filesystem' });
|
||||||
routes.push(...convertRewrites(rewrites));
|
routes.push(...convertRewrites(rewrites));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -451,8 +451,6 @@ describe('getTransformedRoutes', () => {
|
|||||||
headers: { Location: '/support' },
|
headers: { Location: '/support' },
|
||||||
status: 302,
|
status: 302,
|
||||||
},
|
},
|
||||||
{ src: '^/index$', dest: '/index.html', continue: true },
|
|
||||||
{ src: '^/support$', dest: '/support.html', continue: true },
|
|
||||||
{ handle: 'filesystem' },
|
{ handle: 'filesystem' },
|
||||||
{ src: '^/v1$', dest: '/v2/api.py', continue: true },
|
{ src: '^/v1$', dest: '/v2/api.py', continue: true },
|
||||||
];
|
];
|
||||||
|
|||||||
Reference in New Issue
Block a user