Skip to content

Commit 7345d34

Browse files
committed
Add tests for redirect rewrites.
1 parent 4e6dca4 commit 7345d34

File tree

2 files changed

+111
-11
lines changed

2 files changed

+111
-11
lines changed

src/index.js

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ const {existsSync} = require('fs')
22
const {appendFile, readFile, readdir, writeFile} = require('fs').promises
33
const {join} = require('path')
44
const {homedir, tmpdir} = require('os')
5-
65
const toml = require('@iarna/toml')
76
const cpx = require('cpx')
87
const build = require('netlify-lambda/lib/build')
8+
const {parseRedirectsFormat} = require('netlify-redirect-parser')
99

1010
const functionsBuildDir = `functions-build-${Date.now()}`
1111
const nimConfig = join(homedir(), '.nimbella')
@@ -188,12 +188,26 @@ module.exports = {
188188
)
189189
apihost = apihost.replace(/^(https:\/\/)/, '')
190190

191+
// Creates or updates the _redirects file; this file takes precedence
192+
// over other redirect declarations, and is processed from top to bottom
193+
//
194+
// First: if we deployed netlify functions to nimbella, scan the redirects
195+
// for matching rewrites with /.netlify/functions/* as their target
196+
// and remap them to their nimbella api end points.
197+
//
198+
// Second: if there is an API path directive input.api, add a matching rule
199+
// to the _redirects file. The target is either the Nimbella namespace/:splat
200+
// or namespace/default/:splat. The latter is used when deploying Netlify functions
201+
// to Nimbella.
202+
//
203+
// The first set of rewrites is pre-pended to the _redirects file, then the second
204+
// set, if any.
205+
191206
if (isActions) {
192207
if (existsSync(redirectsFile)) {
193208
console.log(
194209
"Found _redirects file. We will rewrite rules that redirect (200 rewrites) to '/.netlify/functions/*'."
195210
)
196-
const {parseRedirectsFormat} = require('netlify-redirect-parser')
197211
const {success} = await parseRedirectsFormat(redirectsFile)
198212
redirects.push(...success)
199213
}
@@ -213,7 +227,9 @@ module.exports = {
213227
) {
214228
const redirectPath = redirect.to.split('/.netlify/functions/')[1]
215229
redirectRules.push(
216-
`${redirect.from} https://${apihost}/api/v1/web/${namespace}/default/${redirectPath} 200!`
230+
`${
231+
redirect.from || redirect.path
232+
} https://${apihost}/api/v1/web/${namespace}/default/${redirectPath} 200!`
217233
)
218234
}
219235
}
@@ -237,12 +253,17 @@ module.exports = {
237253
}
238254

239255
if (redirectRules.length > 0) {
240-
if (!existsSync(constants.PUBLISH_DIR)) {
256+
let content = ''
257+
if (existsSync(redirectsFile)) {
258+
content = await readFile(redirectsFile)
259+
} else if (!existsSync(constants.PUBLISH_DIR)) {
241260
const mkdir = require('make-dir')
242261
await mkdir(constants.PUBLISH_DIR)
243262
}
244263

245-
await appendFile(redirectsFile, redirectRules.join('\n'))
264+
// The rewrites take precedence
265+
await writeFile(redirectsFile, redirectRules.join('\n') + '\n')
266+
await appendFile(redirectsFile, content)
246267
}
247268
}
248269
}

test/index.js

Lines changed: 85 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -229,34 +229,113 @@ describe('onPostBuild()', () => {
229229
utils,
230230
constants: {CONFIG_PATH: 'netlify.toml', PUBLISH_DIR: ''},
231231
inputs: {
232-
path: '',
232+
path: '/api',
233233
functions: 'some-dir'
234234
}
235235
}
236236

237237
mockFs({
238238
'netlify.toml': `
239239
[[redirects]]
240-
from = "/*"
240+
from = "/home"
241241
to = "/index.html"
242242
status = 200
243-
`,
243+
244+
[[redirects]]
245+
from = "/somefn"
246+
to = "/.netlify/functions/fn"
247+
status = 200
248+
`,
244249
'some-dir': {
245250
'create.js': '',
246251
'update.js': ''
247252
}
248253
})
254+
249255
await plugin.onPreBuild(pluginInputs)
250256
await plugin.onPostBuild(pluginInputs)
251-
const redirects = String(fs.readFileSync('_redirects'))
257+
const redirects = String(fs.readFileSync('_redirects')).trim().split('\n')
252258
mockFs.restore()
253259

254260
expect(console.log.mock.calls[1][0]).toEqual(
255261
"Found redirect rules in netlify.toml. We will rewrite rules that redirect (200 rewrites) to '/.netlify/functions/*'."
256262
)
257263

258-
expect(redirects).toEqual(
259-
'/* https://somehost/api/v1/web/namespace/default/:splat 200!'
264+
expect(redirects.length).toEqual(2)
265+
expect(redirects[0]).toEqual(
266+
'/somefn https://somehost/api/v1/web/namespace/default/fn 200!'
267+
)
268+
expect(redirects[1]).toEqual(
269+
'/api/* https://somehost/api/v1/web/namespace/default/:splat 200!'
260270
)
261271
})
272+
273+
test('should rewrite existing redirects to .netlify/functions/ in netlify.toml or _redirects if functions are used', async () => {
274+
process.env.NIMBELLA_LOGIN_TOKEN = 'somevalue'
275+
process.env.CONTEXT = 'production'
276+
utils.run.command = jest.fn((cmd) => {
277+
if (cmd === 'nim auth current') return {stdout: 'namespace'}
278+
if (cmd === 'nim auth current --apihost') return {stdout: 'somehost'}
279+
return {stdout: '???'}
280+
})
281+
282+
const pluginInputs = {
283+
utils,
284+
constants: {CONFIG_PATH: 'netlify.toml', PUBLISH_DIR: ''},
285+
inputs: {
286+
path: '/api',
287+
functions: 'some-dir'
288+
}
289+
}
290+
291+
mockFs({
292+
'netlify.toml': `
293+
[[redirects]]
294+
from = "/home"
295+
to = "/index.html"
296+
status = 200
297+
298+
[[redirects]]
299+
from = "/somefn"
300+
to = "/.netlify/functions/fn1"
301+
status = 200
302+
`,
303+
'some-dir': {
304+
'create.js': '',
305+
'update.js': ''
306+
},
307+
_redirects: [
308+
'/mypath https://example.com',
309+
'/fn2 /.netlify/functions/fn2 200'
310+
].join('\n')
311+
})
312+
313+
await plugin.onPreBuild(pluginInputs)
314+
await plugin.onPostBuild(pluginInputs)
315+
const redirects = String(fs.readFileSync('_redirects'))
316+
.split('\n')
317+
.filter((_) => _)
318+
mockFs.restore()
319+
320+
expect(console.log.mock.calls[1][0]).toEqual(
321+
"Found _redirects file. We will rewrite rules that redirect (200 rewrites) to '/.netlify/functions/*'."
322+
)
323+
324+
expect(console.log.mock.calls[2][0]).toEqual(
325+
"Found redirect rules in netlify.toml. We will rewrite rules that redirect (200 rewrites) to '/.netlify/functions/*'."
326+
)
327+
328+
expect(redirects.length).toEqual(5)
329+
expect(redirects[0]).toEqual(
330+
'/fn2 https://somehost/api/v1/web/namespace/default/fn2 200!'
331+
) // _redirects rewrites is first
332+
expect(redirects[1]).toEqual(
333+
'/somefn https://somehost/api/v1/web/namespace/default/fn1 200!'
334+
) // Then toml rewrite
335+
expect(redirects[2]).toEqual(
336+
'/api/* https://somehost/api/v1/web/namespace/default/:splat 200!'
337+
) // And input directive
338+
expect(redirects[3]).toEqual('/mypath https://example.com') // Original rewrites come last
339+
expect(redirects[4]).toEqual('/fn2 /.netlify/functions/fn2 200') // Original rewrites come last
340+
})
262341
})

0 commit comments

Comments
 (0)