-
Notifications
You must be signed in to change notification settings - Fork 352
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
451 additions
and
112 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
// This file should be used to wrap API methods that are not part of our open API spec yet | ||
// Once they become part of the spec, js-client should be used | ||
const fetch = require('node-fetch') | ||
|
||
const getHeaders = ({ token }) => { | ||
return { | ||
'Content-Type': 'application/json', | ||
'Authorization': `Bearer ${token}`, | ||
} | ||
} | ||
|
||
const getErrorMessage = async ({ response }) => { | ||
const contentType = response.headers.get('content-type') | ||
if (contentType && contentType.indexOf('application/json') !== -1) { | ||
const json = await response.json() | ||
return json.message | ||
} else { | ||
const text = await response.text() | ||
return text | ||
} | ||
} | ||
|
||
const checkResponse = async ({ response }) => { | ||
if (!response.ok) { | ||
const message = await getErrorMessage({ response }).catch(() => undefined) | ||
const errorPostfix = message && message ? ` and message '${message}'` : '' | ||
throw new Error(`Request failed with status '${response.status}'${errorPostfix}`) | ||
} | ||
} | ||
|
||
const getApiUrl = ({ api }) => { | ||
return `${api.scheme}://${api.host}${api.pathPrefix}` | ||
} | ||
|
||
const apiPost = async ({ api, path, data }) => { | ||
const apiUrl = getApiUrl({ api }) | ||
const response = await fetch(`${apiUrl}/${path}`, { | ||
method: 'POST', | ||
body: JSON.stringify(data), | ||
headers: getHeaders({ token: api.accessToken }), | ||
agent: api.agent, | ||
}) | ||
|
||
await checkResponse({ response }) | ||
|
||
return response | ||
} | ||
|
||
const uploadEdgeHandlers = async ({ api, deployId, bundleBuffer, manifest }) => { | ||
const response = await apiPost({ api, path: `deploys/${deployId}/edge_handlers`, data: manifest }) | ||
const { error, exists, upload_url: uploadUrl } = await response.json() | ||
if (error) { | ||
throw new Error(error) | ||
} | ||
|
||
if (exists) { | ||
return false | ||
} | ||
|
||
if (!uploadUrl) { | ||
throw new Error('Missing upload URL') | ||
} | ||
|
||
const putResponse = await fetch(uploadUrl, { | ||
method: 'PUT', | ||
body: bundleBuffer, | ||
headers: { | ||
'Content-Type': 'application/javascript', | ||
}, | ||
agent: api.agent, | ||
}) | ||
|
||
await checkResponse({ response: putResponse }) | ||
|
||
return true | ||
} | ||
|
||
module.exports = { uploadEdgeHandlers } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
const fs = require('fs') | ||
const { promisify } = require('util') | ||
|
||
const statAsync = promisify(fs.stat) | ||
const readFileAsync = promisify(fs.readFile) | ||
const writeFileAsync = promisify(fs.writeFile) | ||
const accessAsync = promisify(fs.access) | ||
|
||
const readFileAsyncCatchError = async filepath => { | ||
try { | ||
return { content: await readFileAsync(filepath) } | ||
} catch (error) { | ||
return { error } | ||
} | ||
} | ||
|
||
const fileExistsAsync = async filePath => { | ||
try { | ||
await accessAsync(filePath, fs.F_OK) | ||
return true | ||
} catch (_) { | ||
return false | ||
} | ||
} | ||
|
||
module.exports = { statAsync, readFileAsync, readFileAsyncCatchError, writeFileAsync, fileExistsAsync } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
const ora = require('ora') | ||
const logSymbols = require('log-symbols') | ||
|
||
const startSpinner = ({ text }) => { | ||
return ora({ | ||
text, | ||
}).start() | ||
} | ||
|
||
const stopSpinner = ({ spinner, text, error }) => { | ||
if (!spinner) { | ||
return | ||
} | ||
const symbol = error ? logSymbols.error : logSymbols.success | ||
spinner.stopAndPersist({ | ||
text, | ||
symbol, | ||
}) | ||
} | ||
|
||
module.exports = { startSpinner, stopSpinner } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
const path = require('path') | ||
const { statAsync, readFileAsyncCatchError } = require('../lib/fs') | ||
const { uploadEdgeHandlers } = require('../lib/api') | ||
const { startSpinner, stopSpinner } = require('../lib/spinner') | ||
|
||
const MANIFEST_FILENAME = 'manifest.json' | ||
const EDGE_HANDLERS_FOLDER = '.netlify/edge-handlers' | ||
|
||
const validateEdgeHandlerFolder = async ({ site, error }) => { | ||
try { | ||
const resolvedFolder = path.resolve(site.root, EDGE_HANDLERS_FOLDER) | ||
const stat = await statAsync(resolvedFolder) | ||
if (!stat.isDirectory()) { | ||
error(`Edge Handlers folder ${EDGE_HANDLERS_FOLDER} must be a path to a directory`) | ||
} | ||
return resolvedFolder | ||
} catch (e) { | ||
// ignore errors at the moment | ||
// TODO: report error if 'edge_handlers' config exists after | ||
// https://github.com/netlify/build/pull/1829 is published | ||
} | ||
} | ||
|
||
const readBundleAndManifest = async ({ edgeHandlersResolvedFolder, error }) => { | ||
const manifestPath = path.resolve(edgeHandlersResolvedFolder, MANIFEST_FILENAME) | ||
const { content: manifest, error: manifestError } = await readFileAsyncCatchError(manifestPath) | ||
if (manifestError) { | ||
error(`Could not read Edge Handlers manifest file ${manifestPath}: ${manifestError.message}`) | ||
} | ||
|
||
let manifestJson | ||
try { | ||
manifestJson = JSON.parse(manifest) | ||
} catch (e) { | ||
error(`Edge Handlers manifest file is not a valid JSON file: ${e.message}`) | ||
} | ||
|
||
if (!manifestJson.sha) { | ||
error(`Edge Handlers manifest file is missing the 'sha' property`) | ||
} | ||
|
||
const bundlePath = path.resolve(edgeHandlersResolvedFolder, manifestJson.sha) | ||
const { content: bundleBuffer, error: bundleError } = await readFileAsyncCatchError(bundlePath) | ||
|
||
if (bundleError) { | ||
error(`Could not read Edge Handlers bundle file ${bundlePath}: ${bundleError.message}`) | ||
} | ||
|
||
return { bundleBuffer, manifest: manifestJson } | ||
} | ||
|
||
const deployEdgeHandlers = async ({ site, deployId, api, silent, error, warn }) => { | ||
const edgeHandlersResolvedFolder = await validateEdgeHandlerFolder({ site, error }) | ||
if (edgeHandlersResolvedFolder) { | ||
let spinner | ||
try { | ||
spinner = silent | ||
? null | ||
: startSpinner({ text: `Deploying Edge Handlers from directory ${edgeHandlersResolvedFolder}` }) | ||
|
||
const { bundleBuffer, manifest } = await readBundleAndManifest({ edgeHandlersResolvedFolder, error }) | ||
// returns false if the bundle exists, true on success, throws on error | ||
const success = await uploadEdgeHandlers({ | ||
api, | ||
deployId, | ||
bundleBuffer, | ||
manifest, | ||
}) | ||
|
||
const text = success | ||
? `Finished deploying Edge Handlers from directory: ${edgeHandlersResolvedFolder}` | ||
: `Skipped deploying Edge Handlers since the bundle already exists` | ||
stopSpinner({ spinner, text, error: false }) | ||
} catch (e) { | ||
const text = `Failed deploying Edge Handlers: ${e.message}` | ||
stopSpinner({ spinner, text, error: true }) | ||
try { | ||
await api.cancelSiteDeploy({ deploy_id: deployId }) | ||
} catch (e) { | ||
warn(`Failed canceling deploy with id ${deployId}: ${e.message}`) | ||
} | ||
// no need to report the error again | ||
error('') | ||
} | ||
} | ||
} | ||
|
||
module.exports = { deployEdgeHandlers } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.