Skip to content

Commit

Permalink
Render templates using env before dereferencing
Browse files Browse the repository at this point in the history
Allows using `${{ env.anything }}` in `$ref`s.

See stepci/stepci#220 for a use case explanation.
  • Loading branch information
RemiBardon committed Jun 23, 2024
1 parent df1e528 commit 8e46f3d
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 3 deletions.
47 changes: 44 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CookieJar, Cookie } from 'tough-cookie'
import { renderObject as liquidlessRenderObject } from 'liquidless'
import { renderObject as liquidlessRenderObject, renderString as liquidlessRenderString } from 'liquidless'
import { fake } from 'liquidless-faker'
import { naughtystring } from 'liquidless-naughtystrings'
import { EventEmitter } from 'node:events'
Expand Down Expand Up @@ -200,14 +200,55 @@ function renderObject<T extends object>(
})
}

function renderString(
string: string,
props: object,
): string {
return liquidlessRenderString(string, props, {
filters: {
fake,
naughtystring
},
delimiters: templateDelimiters
})
}

function map$refs(obj: any, transform: (value: any) => any): void {
for (let key in obj) {
if (key === '$ref') {
obj[key] = transform(obj[key]);
} else if (typeof obj[key] === 'object' && obj[key] !== null) {
map$refs(obj[key], transform);
}
}
}

// Run from test file
export async function runFromYAML(yamlString: string, options?: WorkflowOptions): Promise<WorkflowResult> {
const workflow = yaml.load(yamlString)
const dereffed = await $RefParser.dereference(workflow as any, {
// Parse YAML file
const workflow = yaml.load(yamlString) as any

// Render templates in `workflow.env`, giving `options?.env` as the only available props
workflow.env = renderObject(workflow.env, { env: { ...options?.env } })

// Render templates in `$ref`s, giving `workflow.env` and `options?.env` as the only available props
const env = { ...workflow.env, ...options?.env }
map$refs(workflow, (value) => {
if (typeof value === 'object') {
return renderObject(value, { env })
} else {
return renderString(value, { env })
}
})

// Dereference `$ref`s
const dereffed = await $RefParser.dereference(workflow, {
dereference: {
circular: 'ignore'
}
}) as unknown as Workflow

// Run the workflow
return run(dereffed, options)
}

Expand Down
26 changes: 26 additions & 0 deletions tests/templating-in-$refs-external-env.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
version: '1.1'
name: Process templates using env in `$ref`s (https://github.com/stepci/stepci/issues/220)
env:
host: ${{ env.petstore }}/api/v3
tests:
example:
steps:
- http:
method: POST
url: ${{ env.host }}/user
headers:
Content-Type: application/json
json:
{
'id': 10,
'username': 'theUser',
'firstName': 'John',
'lastName': 'James',
'email': '[email protected]',
'password': '12345',
'phone': '12345',
'userStatus': 1,
}
check:
schema:
$ref: ${{ env.host }}/openapi.yaml#/components/schemas/User
26 changes: 26 additions & 0 deletions tests/templating-in-$refs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
version: '1.1'
name: Process templates using env in `$ref`s (https://github.com/stepci/stepci/issues/220)
env:
host: https://petstore3.swagger.io/api/v3
tests:
example:
steps:
- http:
method: POST
url: ${{ env.host }}/user
headers:
Content-Type: application/json
json:
{
'id': 10,
'username': 'theUser',
'firstName': 'John',
'lastName': 'James',
'email': '[email protected]',
'password': '12345',
'phone': '12345',
'userStatus': 1,
}
check:
schema:
$ref: ${{ env.host }}/openapi.yaml#/components/schemas/User
4 changes: 4 additions & 0 deletions tests/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ import { EventEmitter } from 'node:events'
const ee = new EventEmitter()
runFromFile('./tests/basic.yml').then(({ result }) => console.log(result.tests[0].steps))
runFromFile('./tests/multipart.yml').then(({ result }) => console.log(result.tests[0].steps))
runFromFile('./tests/templating-in-$refs.yml')
.then(({ result }) => console.log(result.tests[0].steps))
runFromFile('./tests/templating-in-$refs-external-env.yml', { env: { petstore: "https://petstore3.swagger.io" }})
.then(({ result }) => console.log(result.tests[0].steps))

0 comments on commit 8e46f3d

Please sign in to comment.