Skip to content

Commit 11601e0

Browse files
authored
Merge pull request #17 from ernilambar/improve-functions
Improve validation
2 parents 7555b39 + 2871f81 commit 11601e0

File tree

7 files changed

+231
-30
lines changed

7 files changed

+231
-30
lines changed

index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ const wpDeployer = async () => {
6060
console.error(chalk.red(`Invalid SVN URL: ${errorMessage}`))
6161
return EXIT_CONFIG
6262
}
63+
if (error === 'invalid_config') {
64+
console.error(chalk.red(errorMessage || 'Invalid wpDeployer configuration.'))
65+
return EXIT_CONFIG
66+
}
6367

6468
try {
6569
runPreflightSync(settings, { fs, awk })

lib/config-schema.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/**
2+
* JSON Schema validation for merged wp-deployer settings (via Ajv).
3+
* Domain rules JSON Schema cannot express stay in lib/validators and config.js.
4+
*/
5+
6+
import { readFileSync } from 'node:fs'
7+
import { fileURLToPath } from 'node:url'
8+
import { dirname, join } from 'node:path'
9+
import Ajv from 'ajv'
10+
11+
const __dirname = dirname(fileURLToPath(import.meta.url))
12+
13+
const schema = JSON.parse(
14+
readFileSync(join(__dirname, 'schemas', 'config.schema.json'), 'utf8')
15+
)
16+
17+
const ajv = new Ajv({ allErrors: true, strict: true })
18+
const validate = ajv.compile(schema)
19+
20+
/**
21+
* @param {object} settings - Merged settings object
22+
* @returns {{ ok: true } | { ok: false, error: 'username_required' | 'theme_earlier_version_required' | 'invalid_config', errorMessage?: string }}
23+
*/
24+
export function validateSettingsSchema (settings) {
25+
const valid = validate(settings)
26+
if (valid) return { ok: true }
27+
28+
const errors = validate.errors ?? []
29+
const mapped = mapSchemaErrors(errors, settings)
30+
if (mapped) return { ok: false, ...mapped }
31+
32+
return {
33+
ok: false,
34+
error: 'invalid_config',
35+
errorMessage: ajv.errorsText(errors, { separator: '\n' })
36+
}
37+
}
38+
39+
/**
40+
* Preserve stable error codes used by the CLI where they match a schema failure.
41+
* @param {import('ajv').ErrorObject[]} errors
42+
* @param {object} settings
43+
* @returns {{ error: string, errorMessage?: string } | null}
44+
*/
45+
function mapSchemaErrors (errors, settings) {
46+
for (const e of errors) {
47+
const path = e.instancePath ?? ''
48+
const missing = e.params?.missingProperty
49+
50+
if (missing === 'username' || (path === '/username' && e.keyword === 'minLength')) {
51+
return { error: 'username_required' }
52+
}
53+
54+
if (settings.repoType === 'theme') {
55+
if (missing === 'earlierVersion' || (path === '/earlierVersion' && e.keyword === 'minLength')) {
56+
return { error: 'theme_earlier_version_required' }
57+
}
58+
}
59+
}
60+
61+
return null
62+
}

lib/config.js

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55

66
import merge from 'just-merge'
7+
import { validateSettingsSchema } from './config-schema.js'
78
import { validateSvnSafeVersion, validateSvnUrl } from './validators/index.js'
89
import { hasPathUnsafeChars } from './validators/shared.js'
910

@@ -30,7 +31,7 @@ export function getDefaults (pkg) {
3031
/**
3132
* Resolve settings from package.json. Does not exit; returns an error key if validation fails.
3233
* @param {object} pkg - Parsed package.json (must have name, version)
33-
* @returns {{ settings: object, error: null | 'invalid_slug' | 'username_required' | 'theme_earlier_version_required' | 'invalid_svn_url' | 'invalid_new_version' | 'invalid_earlier_version', errorMessage?: string }}
34+
* @returns {{ settings: object, error: null | 'invalid_slug' | 'username_required' | 'theme_earlier_version_required' | 'invalid_config' | 'invalid_svn_url' | 'invalid_new_version' | 'invalid_earlier_version', errorMessage?: string }}
3435
*/
3536
export function resolveSettings (pkg) {
3637
const defaults = getDefaults(pkg)
@@ -74,6 +75,15 @@ export function resolveSettings (pkg) {
7475
}
7576
}
7677

78+
const schemaResult = validateSettingsSchema(settings)
79+
if (!schemaResult.ok) {
80+
return {
81+
settings,
82+
error: schemaResult.error,
83+
...(schemaResult.errorMessage !== undefined && { errorMessage: schemaResult.errorMessage })
84+
}
85+
}
86+
7787
const urlResult = validateSvnUrl(settings.url)
7888
if (!urlResult.ok) {
7989
return {
@@ -84,14 +94,6 @@ export function resolveSettings (pkg) {
8494
}
8595
settings.url = urlResult.value
8696

87-
if (!settings.username) {
88-
return { settings, error: 'username_required' }
89-
}
90-
91-
if (!settings.earlierVersion && settings.repoType === 'theme') {
92-
return { settings, error: 'theme_earlier_version_required' }
93-
}
94-
9597
const newVersionResult = validateSvnSafeVersion(settings.newVersion)
9698
if (!newVersionResult.ok) {
9799
return {

lib/schemas/config.schema.json

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"$id": "https://github.com/ernilambar/wp-deployer/lib/schemas/config.schema.json",
4+
"title": "wp-deployer merged settings",
5+
"description": "Schema for wp-deployer runtime configuration.",
6+
"type": "object",
7+
"required": [
8+
"url",
9+
"slug",
10+
"mainFile",
11+
"username",
12+
"repoType",
13+
"buildDir",
14+
"maxBuffer",
15+
"deployTrunk",
16+
"deployTag",
17+
"deployAssets",
18+
"assetsDir",
19+
"tmpDir",
20+
"earlierVersion",
21+
"newVersion",
22+
"svnPath"
23+
],
24+
"properties": {
25+
"url": { "type": "string" },
26+
"slug": { "type": "string", "minLength": 1 },
27+
"mainFile": { "type": "string", "minLength": 1 },
28+
"username": { "type": "string", "minLength": 1 },
29+
"repoType": { "type": "string", "enum": ["plugin", "theme"] },
30+
"buildDir": { "type": "string", "minLength": 1 },
31+
"maxBuffer": { "type": "integer", "minimum": 1 },
32+
"deployTrunk": { "type": "boolean" },
33+
"deployTag": { "type": "boolean" },
34+
"deployAssets": { "type": "boolean" },
35+
"assetsDir": { "type": "string", "minLength": 1 },
36+
"tmpDir": { "type": "string", "minLength": 1 },
37+
"earlierVersion": { "type": "string" },
38+
"newVersion": { "type": "string", "minLength": 1 },
39+
"svnPath": { "type": "string", "minLength": 1 }
40+
},
41+
"additionalProperties": false,
42+
"if": { "properties": { "repoType": { "const": "theme" } } },
43+
"then": {
44+
"properties": {
45+
"earlierVersion": { "type": "string", "minLength": 1 }
46+
}
47+
}
48+
}

package-lock.json

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

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
},
3131
"homepage": "https://github.com/ernilambar/wp-deployer#readme",
3232
"dependencies": {
33+
"ajv": "^8.18.0",
3334
"chalk": "^5.6.2",
3435
"fs-extra": "^11.3.4",
3536
"just-merge": "^3.2.0"

test/config.test.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,4 +250,24 @@ describe('resolveSettings', () => {
250250
const { error } = resolveSettings(pkg)
251251
assert.strictEqual(error, 'invalid_slug')
252252
})
253+
254+
it('returns invalid_config when merged settings fail JSON Schema (wrong type)', () => {
255+
const pkg = {
256+
...basePkg,
257+
wpDeployer: { username: 'jane', maxBuffer: 'not-a-number' }
258+
}
259+
const { error, errorMessage } = resolveSettings(pkg)
260+
assert.strictEqual(error, 'invalid_config')
261+
assert.ok(errorMessage && errorMessage.length > 0)
262+
})
263+
264+
it('returns invalid_config when wpDeployer sets unknown properties (additionalProperties)', () => {
265+
const pkg = {
266+
...basePkg,
267+
wpDeployer: { username: 'jane', notARealOption: true }
268+
}
269+
const { error, errorMessage } = resolveSettings(pkg)
270+
assert.strictEqual(error, 'invalid_config')
271+
assert.ok(errorMessage && errorMessage.length > 0)
272+
})
253273
})

0 commit comments

Comments
 (0)