Skip to content

Commit 8e46f3d

Browse files
committed
Render templates using env before dereferencing
Allows using `${{ env.anything }}` in `$ref`s. See stepci/stepci#220 for a use case explanation.
1 parent df1e528 commit 8e46f3d

File tree

4 files changed

+100
-3
lines changed

4 files changed

+100
-3
lines changed

src/index.ts

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { CookieJar, Cookie } from 'tough-cookie'
2-
import { renderObject as liquidlessRenderObject } from 'liquidless'
2+
import { renderObject as liquidlessRenderObject, renderString as liquidlessRenderString } from 'liquidless'
33
import { fake } from 'liquidless-faker'
44
import { naughtystring } from 'liquidless-naughtystrings'
55
import { EventEmitter } from 'node:events'
@@ -200,14 +200,55 @@ function renderObject<T extends object>(
200200
})
201201
}
202202

203+
function renderString(
204+
string: string,
205+
props: object,
206+
): string {
207+
return liquidlessRenderString(string, props, {
208+
filters: {
209+
fake,
210+
naughtystring
211+
},
212+
delimiters: templateDelimiters
213+
})
214+
}
215+
216+
function map$refs(obj: any, transform: (value: any) => any): void {
217+
for (let key in obj) {
218+
if (key === '$ref') {
219+
obj[key] = transform(obj[key]);
220+
} else if (typeof obj[key] === 'object' && obj[key] !== null) {
221+
map$refs(obj[key], transform);
222+
}
223+
}
224+
}
225+
203226
// Run from test file
204227
export async function runFromYAML(yamlString: string, options?: WorkflowOptions): Promise<WorkflowResult> {
205-
const workflow = yaml.load(yamlString)
206-
const dereffed = await $RefParser.dereference(workflow as any, {
228+
// Parse YAML file
229+
const workflow = yaml.load(yamlString) as any
230+
231+
// Render templates in `workflow.env`, giving `options?.env` as the only available props
232+
workflow.env = renderObject(workflow.env, { env: { ...options?.env } })
233+
234+
// Render templates in `$ref`s, giving `workflow.env` and `options?.env` as the only available props
235+
const env = { ...workflow.env, ...options?.env }
236+
map$refs(workflow, (value) => {
237+
if (typeof value === 'object') {
238+
return renderObject(value, { env })
239+
} else {
240+
return renderString(value, { env })
241+
}
242+
})
243+
244+
// Dereference `$ref`s
245+
const dereffed = await $RefParser.dereference(workflow, {
207246
dereference: {
208247
circular: 'ignore'
209248
}
210249
}) as unknown as Workflow
250+
251+
// Run the workflow
211252
return run(dereffed, options)
212253
}
213254

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
version: '1.1'
2+
name: Process templates using env in `$ref`s (https://github.com/stepci/stepci/issues/220)
3+
env:
4+
host: ${{ env.petstore }}/api/v3
5+
tests:
6+
example:
7+
steps:
8+
- http:
9+
method: POST
10+
url: ${{ env.host }}/user
11+
headers:
12+
Content-Type: application/json
13+
json:
14+
{
15+
'id': 10,
16+
'username': 'theUser',
17+
'firstName': 'John',
18+
'lastName': 'James',
19+
'email': '[email protected]',
20+
'password': '12345',
21+
'phone': '12345',
22+
'userStatus': 1,
23+
}
24+
check:
25+
schema:
26+
$ref: ${{ env.host }}/openapi.yaml#/components/schemas/User

tests/templating-in-$refs.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
version: '1.1'
2+
name: Process templates using env in `$ref`s (https://github.com/stepci/stepci/issues/220)
3+
env:
4+
host: https://petstore3.swagger.io/api/v3
5+
tests:
6+
example:
7+
steps:
8+
- http:
9+
method: POST
10+
url: ${{ env.host }}/user
11+
headers:
12+
Content-Type: application/json
13+
json:
14+
{
15+
'id': 10,
16+
'username': 'theUser',
17+
'firstName': 'John',
18+
'lastName': 'James',
19+
'email': '[email protected]',
20+
'password': '12345',
21+
'phone': '12345',
22+
'userStatus': 1,
23+
}
24+
check:
25+
schema:
26+
$ref: ${{ env.host }}/openapi.yaml#/components/schemas/User

tests/test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,7 @@ import { EventEmitter } from 'node:events'
44
const ee = new EventEmitter()
55
runFromFile('./tests/basic.yml').then(({ result }) => console.log(result.tests[0].steps))
66
runFromFile('./tests/multipart.yml').then(({ result }) => console.log(result.tests[0].steps))
7+
runFromFile('./tests/templating-in-$refs.yml')
8+
.then(({ result }) => console.log(result.tests[0].steps))
9+
runFromFile('./tests/templating-in-$refs-external-env.yml', { env: { petstore: "https://petstore3.swagger.io" }})
10+
.then(({ result }) => console.log(result.tests[0].steps))

0 commit comments

Comments
 (0)