Skip to content

Commit

Permalink
Merge pull request #40 from bbompk/main
Browse files Browse the repository at this point in the history
Feature: Allow YAML multiple documents
  • Loading branch information
GrantBirki authored Nov 8, 2023
2 parents 3add42f + 5b538b5 commit 53e8286
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 7 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# JSON and YAML - Validator ✅
# JSON and YAML - Validator ✅

[![CodeQL](https://github.com/grantbirki/json-yaml-validate/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/grantbirki/json-yaml-validate/actions/workflows/codeql-analysis.yml) [![test](https://github.com/grantbirki/json-yaml-validate/actions/workflows/test.yml/badge.svg)](https://github.com/grantbirki/json-yaml-validate/actions/workflows/test.yml) [![acceptance-test](https://github.com/GrantBirki/json-yaml-validate/actions/workflows/acceptance-test.yml/badge.svg)](https://github.com/GrantBirki/json-yaml-validate/actions/workflows/acceptance-test.yml) [![package-check](https://github.com/grantbirki/json-yaml-validate/actions/workflows/package-check.yml/badge.svg)](https://github.com/grantbirki/json-yaml-validate/actions/workflows/package-check.yml) [![lint](https://github.com/grantbirki/json-yaml-validate/actions/workflows/lint.yml/badge.svg)](https://github.com/grantbirki/json-yaml-validate/actions/workflows/lint.yml) [![coverage](./badges/coverage.svg)](./badges/coverage.svg)

Expand Down
16 changes: 16 additions & 0 deletions __tests__/fixtures/yaml/multiple/invalid.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
# spec:
---
apiVersion: v1
kind: Service
metadata:
name: nginx: service
labels:
app: nginx
# spec:
16 changes: 16 additions & 0 deletions __tests__/fixtures/yaml/multiple/yaml1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
# spec:
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
labels:
app: nginx
# spec:
37 changes: 36 additions & 1 deletion __tests__/functions/yaml-validator.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ beforeEach(() => {
process.env.INPUT_YAML_AS_JSON = false
process.env.INPUT_USE_DOT_MATCH = 'true'
process.env.INPUT_FILES = ''
process.env.INPUT_ALLOW_MULTIPLE_DOCUMENTS = 'false'
})

test('successfully validates a yaml file with a schema', async () => {
Expand Down Expand Up @@ -111,7 +112,9 @@ test('fails to validate a yaml file without using a schema', async () => {
errors: [
{
path: null,
message: 'Invalid YAML'
message: 'Invalid YAML',
error:
'YAMLParseError Nested mappings are not allowed in compact mappings at line 4, column 17'
}
]
}
Expand Down Expand Up @@ -237,3 +240,35 @@ test('skips all files when yaml_as_json is true, even invalid ones', async () =>
'skipping yaml since it should be treated as json: __tests__/fixtures/yaml/invalid/skip-bad.yaml'
)
})

test('successfully validates a yaml file with multiple documents but fails on the other', async () => {
process.env.INPUT_ALLOW_MULTIPLE_DOCUMENTS = 'true'
process.env.INPUT_BASE_DIR = '__tests__/fixtures/yaml/multiple'
expect(await yamlValidator(excludeMock)).toStrictEqual({
failed: 1,
passed: 1,
skipped: 0,
success: false,
violations: [
{
file: '__tests__/fixtures/yaml/multiple/invalid.yaml',
errors: [
{
path: null,
message: 'Invalid YAML',
error:
'YAMLParseError Nested mappings are not allowed in compact mappings at line 13, column 9'
}
]
}
]
})
expect(infoMock).toHaveBeenCalledWith(
`multiple documents found in file: __tests__/fixtures/yaml/multiple/yaml1.yaml`
)
expect(errorMock).toHaveBeenCalledWith(
expect.stringMatching(
'❌ failed to parse YAML file: __tests__/fixtures/yaml/multiple/invalid.yaml'
)
)
})
4 changes: 4 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ inputs:
description: The full path to the .gitignore file to use if use_gitignore is set to "true" (e.g. ./src/.gitignore) - Default is ".gitignore" which uses the .gitignore file in the root of the repository
required: false
default: ".gitignore"
allow_multiple_documents:
description: Whether or not to allow multiple documents in a single YAML file - "true" or "false" - Default is "false"
required: false
default: "false"
outputs:
success:
description: Whether or not the validation was successful for all files - "true" or "false"
Expand Down
31 changes: 26 additions & 5 deletions src/functions/yaml-validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as core from '@actions/core'
import validateSchema from 'yaml-schema-validator'
import {readFileSync} from 'fs'
import {fdir} from 'fdir'
import {parse} from 'yaml'
import {parse, parseAllDocuments} from 'yaml'

// Helper function to validate all yaml files in the baseDir
export async function yamlValidator(exclude) {
Expand All @@ -13,6 +13,9 @@ export async function yamlValidator(exclude) {
const yamlExcludeRegex = core.getInput('yaml_exclude_regex')
const yamlAsJson = core.getBooleanInput('yaml_as_json')
const useDotMatch = core.getBooleanInput('use_dot_match')
const allowMultipleDocuments = core.getBooleanInput(
'allow_multiple_documents'
)
let files = core.getMultilineInput('files').filter(Boolean)

// remove trailing slash from baseDir
Expand Down Expand Up @@ -83,10 +86,25 @@ export async function yamlValidator(exclude) {
continue
}

let multipleDocuments = false

try {
// try to parse the yaml file
parse(readFileSync(fullPath, 'utf8'))
} catch {
if (allowMultipleDocuments) {
let documents = parseAllDocuments(readFileSync(fullPath, 'utf8'))
for (let doc of documents) {
if (doc.errors.length > 0) {
// format and show the first error
throw doc.errors[0]
}
parse(doc.toString()) // doc.toString() will throw an error if the document is invalid
}
core.info(`multiple documents found in file: ${fullPath}`)
multipleDocuments = true
} else {
parse(readFileSync(fullPath, 'utf8'))
}
} catch (err) {
// if the yaml file is invalid, log an error and set success to false
core.error(`❌ failed to parse YAML file: ${fullPath}`)
result.success = false
Expand All @@ -96,7 +114,9 @@ export async function yamlValidator(exclude) {
errors: [
{
path: null,
message: 'Invalid YAML'
message: 'Invalid YAML',
// format error message
error: err.toString().split(':').slice(0, 2).join('')
}
]
})
Expand All @@ -108,7 +128,8 @@ export async function yamlValidator(exclude) {
!yamlSchema ||
yamlSchema === '' ||
yamlSchema === null ||
yamlSchema === undefined
yamlSchema === undefined ||
multipleDocuments
) {
result.passed++
core.info(`${fullPath} is valid`)
Expand Down

0 comments on commit 53e8286

Please sign in to comment.