Skip to content

Commit b6415d0

Browse files
authored
Merge pull request #84 from juheiseflink/contrib_support_multiple_docs_for_yaml_as_json
Changing JSON validator to be able to deal with multiple docs when YAML is treated as JSON
2 parents 0f7b97d + 77a3e38 commit b6415d0

File tree

9 files changed

+188
-48
lines changed

9 files changed

+188
-48
lines changed

.github/workflows/acceptance-test.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,14 @@ jobs:
6666
yaml_schema: ./__tests__/fixtures/schemas/flat.yaml
6767
files: |
6868
__tests__/acceptance/flat_yaml/flat.yaml
69+
70+
- name: acceptance test - multi yaml as json
71+
uses: ./
72+
id: json-yaml-validate-multi-yaml-as-json-test
73+
with:
74+
comment: "true"
75+
allow_multiple_documents: true
76+
yaml_as_json: true
77+
json_schema: ./__tests__/fixtures/schemas/schema1.json
78+
files: |
79+
__tests__/fixtures/yaml_as_json/valid_multi/yaml1.yaml

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,7 @@ secrets.json
3131
*.key
3232
*.secret
3333
*.secrets
34+
35+
# jetbrains
36+
.idea
37+
*.iml
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
foo: "1" # invalid type, value should be int
3+
bar: "ok"
4+
---
5+
foo: 2
6+
foobar: "not ok" # invalid key, additionalProperties not allowed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
foo: 1
3+
bar: "ok"
4+
---
5+
foo: 2
6+
bar: "also ok"

__tests__/functions/json-validator.test.js

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ beforeEach(() => {
2929
process.env.INPUT_JSON_SCHEMA_VERSION = 'draft-07'
3030
process.env.INPUT_AJV_STRICT_MODE = 'true'
3131
process.env.INPUT_AJV_CUSTOM_REGEXP_FORMATS = ''
32+
process.env.INPUT_ALLOW_MULTIPLE_DOCUMENTS = 'false'
3233
})
3334

3435
test('successfully validates a json file with a schema', async () => {
@@ -583,7 +584,7 @@ test('test that validator throws error when custom_ajv_regexp_format does not co
583584
}
584585
})
585586

586-
test('test that schema compile throws error when attemting to validate a json to a schema with unknown format', async () => {
587+
test('test that schema compile throws error when attempting to validate a json to a schema with unknown format', async () => {
587588
expect.assertions(1)
588589
try {
589590
process.env.INPUT_JSON_SCHEMA =
@@ -597,3 +598,47 @@ test('test that schema compile throws error when attemting to validate a json to
597598
)
598599
}
599600
})
601+
602+
test('yamlAsJson: successful validation of a multi-document-file', async () => {
603+
process.env.INPUT_YAML_AS_JSON = 'true'
604+
process.env.INPUT_ALLOW_MULTIPLE_DOCUMENTS = 'true'
605+
process.env.INPUT_BASE_DIR = '__tests__/fixtures/yaml_as_json/valid_multi'
606+
let result = await jsonValidator(excludeMock)
607+
expect(result).toStrictEqual({
608+
failed: 0,
609+
passed: 1,
610+
skipped: 0,
611+
success: true,
612+
violations: []
613+
})
614+
})
615+
616+
test('yamlAsJson: failed validation of a multi-document-file', async () => {
617+
process.env.INPUT_YAML_AS_JSON = 'true'
618+
process.env.INPUT_ALLOW_MULTIPLE_DOCUMENTS = 'true'
619+
process.env.INPUT_BASE_DIR = '__tests__/fixtures/yaml_as_json/invalid_multi'
620+
let result = await jsonValidator(excludeMock)
621+
expect(result).toStrictEqual({
622+
failed: 1,
623+
passed: 0,
624+
skipped: 0,
625+
success: false,
626+
violations: [
627+
{
628+
file: '__tests__/fixtures/yaml_as_json/invalid_multi/yaml1.yaml',
629+
errors: [
630+
{
631+
document: 0,
632+
message: 'must be integer',
633+
path: '/foo'
634+
},
635+
{
636+
document: 1,
637+
message: 'must NOT have additional properties',
638+
path: null
639+
}
640+
]
641+
}
642+
]
643+
})
644+
})

badges/coverage.svg

Lines changed: 1 addition & 1 deletion
Loading

dist/index.js

Lines changed: 56 additions & 22 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/functions/json-validator.js

Lines changed: 57 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import AjvDraft04 from 'ajv-draft-04'
66
import addFormats from 'ajv-formats'
77
import {readFileSync} from 'fs'
88
import {fdir} from 'fdir'
9-
import {parse} from 'yaml'
9+
import {parse, parseAllDocuments} from 'yaml'
1010
import {globSync} from 'glob'
1111

1212
// Helper function to setup the schema
@@ -95,6 +95,9 @@ export async function jsonValidator(exclude) {
9595
const yamlExtension = core.getInput('yaml_extension')
9696
const yamlExtensionShort = core.getInput('yaml_extension_short')
9797
const useDotMatch = core.getBooleanInput('use_dot_match')
98+
const allowMultipleDocuments = core.getBooleanInput(
99+
'allow_multiple_documents'
100+
)
98101
let patterns = core.getMultilineInput('files').filter(Boolean)
99102

100103
core.debug(`yaml_as_json: ${yamlAsJson}`)
@@ -206,8 +209,11 @@ export async function jsonValidator(exclude) {
206209
fullPath.endsWith(yamlExtensionShort))
207210
) {
208211
core.debug(`attempting to process yaml file: '${fullPath}' as json`)
209-
data = parse(readFileSync(fullPath, 'utf8'))
210-
212+
if (allowMultipleDocuments === true) {
213+
data = parseAllDocuments(readFileSync(fullPath, 'utf8'))
214+
} else {
215+
data = parse(readFileSync(fullPath, 'utf8'))
216+
}
211217
// if the file is a json file
212218
} else {
213219
data = JSON.parse(readFileSync(fullPath, 'utf8'))
@@ -229,32 +235,60 @@ export async function jsonValidator(exclude) {
229235
continue
230236
}
231237

232-
// if a jsonSchema is provided, validate the json against it
233-
const valid = validate(data)
234-
if (!valid) {
235-
// if the json file is invalid against the schema, log an error and set success to false
238+
// ensure data is always an array; in case of single-document-mode it'll
239+
// have just one element.
240+
// this is required to support multi-doc files when yamlAsJson is true
241+
if (yamlAsJson === true && allowMultipleDocuments === true) {
242+
let newData = []
243+
data.forEach(doc => {
244+
newData.push(doc.toJS())
245+
})
246+
data = newData
247+
}
248+
if (allowMultipleDocuments !== true) {
249+
data = [data]
250+
}
251+
252+
if (Array.isArray(data)) {
253+
core.debug(`${data.length} object(s) found in file: ${fullPath}`)
254+
}
255+
256+
let allValid = true
257+
let allErrors = []
258+
259+
// perform the validation for each document
260+
data.forEach((doc, index) => {
261+
const valid = validate(doc)
262+
if (valid) {
263+
return
264+
}
265+
266+
// validation failed, record the error
267+
allValid = false
268+
allErrors.push(
269+
...validate.errors.map(error => {
270+
let errorValue = {
271+
path: error.instancePath || null,
272+
message: error.message
273+
}
274+
// when we have multiple documents, we need to add the document index
275+
if (allowMultipleDocuments && yamlAsJson === true) {
276+
errorValue.document = index
277+
}
278+
return errorValue
279+
})
280+
)
281+
})
282+
283+
if (!allValid) {
236284
core.error(
237-
`❌ failed to parse JSON file: ${fullPath}\n${JSON.stringify(
238-
validate.errors
239-
)}`
285+
`❌ failed to parse JSON file: ${fullPath}\n${JSON.stringify(allErrors)}`
240286
)
241287
result.success = false
242288
result.failed++
243-
244-
// add the errors to the result object (path and message)
245-
// where path is the path to the property that failed validation
246-
var errors = []
247-
for (const error of validate.errors) {
248-
errors.push({
249-
path: error.instancePath || null,
250-
message: error.message
251-
})
252-
}
253-
254-
// add the file and errors to the result object
255289
result.violations.push({
256290
file: `${fullPath}`,
257-
errors: errors
291+
errors: allErrors
258292
})
259293
continue
260294
}

0 commit comments

Comments
 (0)