From 308088b249c0fd949931fed34dbdf6206fd706f5 Mon Sep 17 00:00:00 2001 From: nuxen Date: Mon, 20 May 2024 16:05:02 +0200 Subject: [PATCH] feat(ci): Custom Format JSON validation (#1939) Co-authored-by: TRaSH --- .../workflows/custom-format-validation.yml | 44 +++++++++++++++ .vscode/settings.json | 16 +++++- docs/json/radarr/cf/fansub.json | 1 + docs/json/radarr/cf/fastsub.json | 1 + docs/json/sonarr/cf/fansub.json | 1 + docs/json/sonarr/cf/fastsub.json | 1 + docs/json/sonarr/cf/season-pack-spec.json | 15 ------ schemas/base-cf.schema.json | 54 +++++++++++++++++++ schemas/guide-only-cf.schema.json | 50 +++++++++++++++++ schemas/radarr-cf.schema.json | 49 +++++++++++++++++ schemas/sonarr-cf.schema.json | 47 ++++++++++++++++ schemas/specs/edition-spec.json | 25 +++++++++ schemas/specs/indexer-flag-spec.json | 25 +++++++++ schemas/specs/language-spec.json | 24 +++++++++ schemas/specs/quality-modifier-spec.json | 25 +++++++++ schemas/specs/release-group-spec.json | 25 +++++++++ schemas/specs/release-title-spec.json | 25 +++++++++ schemas/specs/release-type-spec.json | 25 +++++++++ schemas/specs/resolution-spec.json | 25 +++++++++ schemas/specs/size-spec.json | 28 ++++++++++ schemas/specs/source-spec.json | 25 +++++++++ schemas/specs/year-spec.json | 29 ++++++++++ 22 files changed, 544 insertions(+), 16 deletions(-) create mode 100644 .github/workflows/custom-format-validation.yml delete mode 100644 docs/json/sonarr/cf/season-pack-spec.json create mode 100644 schemas/base-cf.schema.json create mode 100644 schemas/guide-only-cf.schema.json create mode 100644 schemas/radarr-cf.schema.json create mode 100644 schemas/sonarr-cf.schema.json create mode 100644 schemas/specs/edition-spec.json create mode 100644 schemas/specs/indexer-flag-spec.json create mode 100644 schemas/specs/language-spec.json create mode 100644 schemas/specs/quality-modifier-spec.json create mode 100644 schemas/specs/release-group-spec.json create mode 100644 schemas/specs/release-title-spec.json create mode 100644 schemas/specs/release-type-spec.json create mode 100644 schemas/specs/resolution-spec.json create mode 100644 schemas/specs/size-spec.json create mode 100644 schemas/specs/source-spec.json create mode 100644 schemas/specs/year-spec.json diff --git a/.github/workflows/custom-format-validation.yml b/.github/workflows/custom-format-validation.yml new file mode 100644 index 000000000..fc3b47ba4 --- /dev/null +++ b/.github/workflows/custom-format-validation.yml @@ -0,0 +1,44 @@ +name: Validate Custom Format JSONs + +on: + push: + branches: + - master + paths: + - .github/workflows/custom-format-validation.yml + - docs/json/guide-only/*.json + - docs/json/radarr/cf/*.json + - docs/json/sonarr/cf/*.json + - schemas/**/*.json + pull_request: + paths: + - .github/workflows/custom-format-validation.yml + - docs/json/guide-only/*.json + - docs/json/radarr/cf/*.json + - docs/json/sonarr/cf/*.json + - schemas/**/*.json + +jobs: + validate-json: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4.1.5 + + - name: Setup Python + uses: actions/setup-python@v5.1.0 + with: + python-version: "3.x" + + - name: Install check-jsonschema + run: pip install check-jsonschema + + - name: Validate Guide only Custom Formats + run: check-jsonschema -v --schemafile schemas/guide-only-cf.schema.json docs/json/guide-only/*.json + + - name: Validate Radarr Custom Formats + run: check-jsonschema -v --schemafile schemas/radarr-cf.schema.json docs/json/radarr/cf/*.json + + - name: Validate Sonarr Custom Formats + run: check-jsonschema -v --schemafile schemas/sonarr-cf.schema.json docs/json/sonarr/cf/*.json diff --git a/.vscode/settings.json b/.vscode/settings.json index c3ab32e7c..a6f555802 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,5 +4,19 @@ }, "yaml.schemas": { "https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json": "untitled:Untitled-1" - } + }, + "json.schemas": [ + { + "fileMatch": ["docs/json/guide-only/*.json"], + "url": "./schemas/guide-only-cf.schema.json" + }, + { + "fileMatch": ["docs/json/radarr/cf/*.json"], + "url": "./schemas/radarr-cf.schema.json" + }, + { + "fileMatch": ["docs/json/sonarr/cf/*.json"], + "url": "./schemas/sonarr-cf.schema.json" + } + ] } diff --git a/docs/json/radarr/cf/fansub.json b/docs/json/radarr/cf/fansub.json index f18b1ab4d..20a366fce 100644 --- a/docs/json/radarr/cf/fansub.json +++ b/docs/json/radarr/cf/fansub.json @@ -1,6 +1,7 @@ { "trash_id": "02e48d30a176c91baf9e15de05e5dc6a", "name": "FanSUB", + "includeCustomFormatWhenRenaming": false, "specifications": [ { "name": "FanSUB", diff --git a/docs/json/radarr/cf/fastsub.json b/docs/json/radarr/cf/fastsub.json index 739e98578..91533a30c 100644 --- a/docs/json/radarr/cf/fastsub.json +++ b/docs/json/radarr/cf/fastsub.json @@ -4,6 +4,7 @@ "default": -10000 }, "name": "FastSUB", + "includeCustomFormatWhenRenaming": false, "specifications": [ { "name": "FastSUB", diff --git a/docs/json/sonarr/cf/fansub.json b/docs/json/sonarr/cf/fansub.json index 024d5bacc..f0ca42ebf 100644 --- a/docs/json/sonarr/cf/fansub.json +++ b/docs/json/sonarr/cf/fansub.json @@ -1,6 +1,7 @@ { "trash_id": "84f0acbda9c0c9de783894fb66df25aa", "name": "FanSUB", + "includeCustomFormatWhenRenaming": false, "specifications": [ { "name": "FanSUB", diff --git a/docs/json/sonarr/cf/fastsub.json b/docs/json/sonarr/cf/fastsub.json index 4fb4863a5..b33fea4e3 100644 --- a/docs/json/sonarr/cf/fastsub.json +++ b/docs/json/sonarr/cf/fastsub.json @@ -4,6 +4,7 @@ "default": -10000 }, "name": "FastSUB", + "includeCustomFormatWhenRenaming": false, "specifications": [ { "name": "FastSUB", diff --git a/docs/json/sonarr/cf/season-pack-spec.json b/docs/json/sonarr/cf/season-pack-spec.json deleted file mode 100644 index 048f3061c..000000000 --- a/docs/json/sonarr/cf/season-pack-spec.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "Season Pack", - "includeCustomFormatWhenRenaming": false, - "specifications": [ - { - "name": "Season Packs", - "implementation": "ReleaseTypeSpecification", - "negate": false, - "required": false, - "fields": { - "value": 3 - } - } - ] -} diff --git a/schemas/base-cf.schema.json b/schemas/base-cf.schema.json new file mode 100644 index 000000000..b659f6e7f --- /dev/null +++ b/schemas/base-cf.schema.json @@ -0,0 +1,54 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "defs": { + "trash_id": { + "type": "string", + "pattern": "^([a-fA-F0-9]{32}|guide-only)$" + }, + "trash_scores": { + "type": "object", + "properties": { + "default": { + "type": "integer", + "not": { + "const": 0 + } + } + }, + "patternProperties": { + "^.+$": { + "type": "integer" + } + }, + "additionalProperties": false, + "minProperties": 1 + }, + "trash_regex": { + "type": "string", + "format": "uri" + }, + "trash_description": { + "type": "string", + "minLength": 1 + }, + "name": { + "type": "string", + "minLength": 1 + }, + "baseSpecification": { + "type": "object", + "properties": { + "name": { + "$ref": "#/defs/name" + }, + "negate": { + "type": "boolean" + }, + "required": { + "type": "boolean" + } + }, + "required": ["name", "negate", "required"] + } + } +} diff --git a/schemas/guide-only-cf.schema.json b/schemas/guide-only-cf.schema.json new file mode 100644 index 000000000..c36dfaebf --- /dev/null +++ b/schemas/guide-only-cf.schema.json @@ -0,0 +1,50 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "trash_id": { + "$ref": "base-cf.schema.json#/defs/trash_id" + }, + "trash_scores": { + "$ref": "base-cf.schema.json#/defs/trash_scores" + }, + "trash_regex": { + "$ref": "base-cf.schema.json#/defs/trash_regex" + }, + "trash_description": { + "$ref": "base-cf.schema.json#/defs/trash_description" + }, + "name": { + "$ref": "base-cf.schema.json#/defs/name" + }, + "includeCustomFormatWhenRenaming": { + "type": "boolean" + }, + "specifications": { + "type": "array", + "items": { + "anyOf": [ + { "$ref": "specs/release-title-spec.json" }, + { "$ref": "specs/edition-spec.json" }, + { "$ref": "specs/language-spec.json" }, + { "$ref": "specs/indexer-flag-spec.json" }, + { "$ref": "specs/source-spec.json" }, + { "$ref": "specs/resolution-spec.json" }, + { "$ref": "specs/quality-modifier-spec.json" }, + { "$ref": "specs/size-spec.json" }, + { "$ref": "specs/release-group-spec.json" }, + { "$ref": "specs/release-type-spec.json" }, + { "$ref": "specs/year-spec.json" } + ] + }, + "minItems": 1 + } + }, + "required": [ + "trash_id", + "name", + "includeCustomFormatWhenRenaming", + "specifications" + ], + "additionalProperties": false +} diff --git a/schemas/radarr-cf.schema.json b/schemas/radarr-cf.schema.json new file mode 100644 index 000000000..d138de003 --- /dev/null +++ b/schemas/radarr-cf.schema.json @@ -0,0 +1,49 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "trash_id": { + "$ref": "base-cf.schema.json#/defs/trash_id" + }, + "trash_scores": { + "$ref": "base-cf.schema.json#/defs/trash_scores" + }, + "trash_regex": { + "$ref": "base-cf.schema.json#/defs/trash_regex" + }, + "trash_description": { + "$ref": "base-cf.schema.json#/defs/trash_description" + }, + "name": { + "$ref": "base-cf.schema.json#/defs/name" + }, + "includeCustomFormatWhenRenaming": { + "type": "boolean" + }, + "specifications": { + "type": "array", + "items": { + "anyOf": [ + { "$ref": "specs/release-title-spec.json" }, + { "$ref": "specs/edition-spec.json" }, + { "$ref": "specs/language-spec.json" }, + { "$ref": "specs/indexer-flag-spec.json" }, + { "$ref": "specs/source-spec.json" }, + { "$ref": "specs/resolution-spec.json" }, + { "$ref": "specs/quality-modifier-spec.json" }, + { "$ref": "specs/size-spec.json" }, + { "$ref": "specs/release-group-spec.json" }, + { "$ref": "specs/year-spec.json" } + ] + }, + "minItems": 1 + } + }, + "required": [ + "trash_id", + "name", + "includeCustomFormatWhenRenaming", + "specifications" + ], + "additionalProperties": false +} diff --git a/schemas/sonarr-cf.schema.json b/schemas/sonarr-cf.schema.json new file mode 100644 index 000000000..8ec32857a --- /dev/null +++ b/schemas/sonarr-cf.schema.json @@ -0,0 +1,47 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "trash_id": { + "$ref": "base-cf.schema.json#/defs/trash_id" + }, + "trash_scores": { + "$ref": "base-cf.schema.json#/defs/trash_scores" + }, + "trash_regex": { + "$ref": "base-cf.schema.json#/defs/trash_regex" + }, + "trash_description": { + "$ref": "base-cf.schema.json#/defs/trash_description" + }, + "name": { + "$ref": "base-cf.schema.json#/defs/name" + }, + "includeCustomFormatWhenRenaming": { + "type": "boolean" + }, + "specifications": { + "type": "array", + "items": { + "anyOf": [ + { "$ref": "specs/release-title-spec.json" }, + { "$ref": "specs/language-spec.json" }, + { "$ref": "specs/indexer-flag-spec.json" }, + { "$ref": "specs/source-spec.json" }, + { "$ref": "specs/resolution-spec.json" }, + { "$ref": "specs/size-spec.json" }, + { "$ref": "specs/release-group-spec.json" }, + { "$ref": "specs/release-type-spec.json" } + ] + }, + "minItems": 1 + } + }, + "required": [ + "trash_id", + "name", + "includeCustomFormatWhenRenaming", + "specifications" + ], + "additionalProperties": false +} diff --git a/schemas/specs/edition-spec.json b/schemas/specs/edition-spec.json new file mode 100644 index 000000000..a37814ff8 --- /dev/null +++ b/schemas/specs/edition-spec.json @@ -0,0 +1,25 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "allOf": [ + { "$ref": "../base-cf.schema.json#/defs/baseSpecification" }, + { + "properties": { + "implementation": { + "const": "EditionSpecification" + }, + "fields": { + "type": "object", + "properties": { + "value": { + "type": "string", + "minLength": 1 + } + }, + "required": ["value"], + "additionalProperties": false + } + }, + "required": ["implementation", "fields"] + } + ] +} diff --git a/schemas/specs/indexer-flag-spec.json b/schemas/specs/indexer-flag-spec.json new file mode 100644 index 000000000..c327d9e74 --- /dev/null +++ b/schemas/specs/indexer-flag-spec.json @@ -0,0 +1,25 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "allOf": [ + { "$ref": "../base-cf.schema.json#/defs/baseSpecification" }, + { + "properties": { + "implementation": { + "const": "IndexerFlagSpecification" + }, + "fields": { + "type": "object", + "properties": { + "value": { + "type": "integer", + "enum": [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] + } + }, + "required": ["value"], + "additionalProperties": false + } + }, + "required": ["implementation", "fields"] + } + ] +} diff --git a/schemas/specs/language-spec.json b/schemas/specs/language-spec.json new file mode 100644 index 000000000..320cbe9ac --- /dev/null +++ b/schemas/specs/language-spec.json @@ -0,0 +1,24 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "allOf": [ + { "$ref": "../base-cf.schema.json#/defs/baseSpecification" }, + { + "properties": { + "implementation": { + "const": "LanguageSpecification" + }, + "fields": { + "type": "object", + "properties": { + "value": { + "type": "integer" + } + }, + "required": ["value"], + "additionalProperties": false + } + }, + "required": ["implementation", "fields"] + } + ] +} diff --git a/schemas/specs/quality-modifier-spec.json b/schemas/specs/quality-modifier-spec.json new file mode 100644 index 000000000..2b4e431ac --- /dev/null +++ b/schemas/specs/quality-modifier-spec.json @@ -0,0 +1,25 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "allOf": [ + { "$ref": "../base-cf.schema.json#/defs/baseSpecification" }, + { + "properties": { + "implementation": { + "const": "QualityModifierSpecification" + }, + "fields": { + "type": "object", + "properties": { + "value": { + "type": "integer", + "enum": [1, 2, 3, 4, 5] + } + }, + "required": ["value"], + "additionalProperties": false + } + }, + "required": ["implementation", "fields"] + } + ] +} diff --git a/schemas/specs/release-group-spec.json b/schemas/specs/release-group-spec.json new file mode 100644 index 000000000..10c4aab1b --- /dev/null +++ b/schemas/specs/release-group-spec.json @@ -0,0 +1,25 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "allOf": [ + { "$ref": "../base-cf.schema.json#/defs/baseSpecification" }, + { + "properties": { + "implementation": { + "const": "ReleaseGroupSpecification" + }, + "fields": { + "type": "object", + "properties": { + "value": { + "type": "string", + "minLength": 1 + } + }, + "required": ["value"], + "additionalProperties": false + } + }, + "required": ["implementation", "fields"] + } + ] +} diff --git a/schemas/specs/release-title-spec.json b/schemas/specs/release-title-spec.json new file mode 100644 index 000000000..01c04673f --- /dev/null +++ b/schemas/specs/release-title-spec.json @@ -0,0 +1,25 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "allOf": [ + { "$ref": "../base-cf.schema.json#/defs/baseSpecification" }, + { + "properties": { + "implementation": { + "const": "ReleaseTitleSpecification" + }, + "fields": { + "type": "object", + "properties": { + "value": { + "type": "string", + "minLength": 1 + } + }, + "required": ["value"], + "additionalProperties": false + } + }, + "required": ["implementation", "fields"] + } + ] +} diff --git a/schemas/specs/release-type-spec.json b/schemas/specs/release-type-spec.json new file mode 100644 index 000000000..f8f8e1ebd --- /dev/null +++ b/schemas/specs/release-type-spec.json @@ -0,0 +1,25 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "allOf": [ + { "$ref": "../base-cf.schema.json#/defs/baseSpecification" }, + { + "properties": { + "implementation": { + "const": "ReleaseTypeSpecification" + }, + "fields": { + "type": "object", + "properties": { + "value": { + "type": "integer", + "enum": [0, 1, 2, 3] + } + }, + "required": ["value"], + "additionalProperties": false + } + }, + "required": ["implementation", "fields"] + } + ] +} diff --git a/schemas/specs/resolution-spec.json b/schemas/specs/resolution-spec.json new file mode 100644 index 000000000..79600bc3b --- /dev/null +++ b/schemas/specs/resolution-spec.json @@ -0,0 +1,25 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "allOf": [ + { "$ref": "../base-cf.schema.json#/defs/baseSpecification" }, + { + "properties": { + "implementation": { + "const": "ResolutionSpecification" + }, + "fields": { + "type": "object", + "properties": { + "value": { + "type": "integer", + "enum": [360, 480, 540, 576, 720, 1080, 2160] + } + }, + "required": ["value"], + "additionalProperties": false + } + }, + "required": ["implementation", "fields"] + } + ] +} diff --git a/schemas/specs/size-spec.json b/schemas/specs/size-spec.json new file mode 100644 index 000000000..ef5080592 --- /dev/null +++ b/schemas/specs/size-spec.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "allOf": [ + { "$ref": "../base-cf.schema.json#/defs/baseSpecification" }, + { + "properties": { + "implementation": { + "const": "SizeSpecification" + }, + "fields": { + "type": "object", + "properties": { + "min": { + "type": "integer" + }, + "max": { + "type": "integer", + "minimum": 1 + } + }, + "required": ["min", "max"], + "additionalProperties": false + } + }, + "required": ["implementation", "fields"] + } + ] +} diff --git a/schemas/specs/source-spec.json b/schemas/specs/source-spec.json new file mode 100644 index 000000000..78e66e3f4 --- /dev/null +++ b/schemas/specs/source-spec.json @@ -0,0 +1,25 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "allOf": [ + { "$ref": "../base-cf.schema.json#/defs/baseSpecification" }, + { + "properties": { + "implementation": { + "const": "SourceSpecification" + }, + "fields": { + "type": "object", + "properties": { + "value": { + "type": "integer", + "enum": [1, 2, 3, 4, 5, 6, 7, 8, 9] + } + }, + "required": ["value"], + "additionalProperties": false + } + }, + "required": ["implementation", "fields"] + } + ] +} diff --git a/schemas/specs/year-spec.json b/schemas/specs/year-spec.json new file mode 100644 index 000000000..1870e987d --- /dev/null +++ b/schemas/specs/year-spec.json @@ -0,0 +1,29 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "allOf": [ + { "$ref": "../base-cf.schema.json#/defs/baseSpecification" }, + { + "properties": { + "implementation": { + "const": "SizeSpecification" + }, + "fields": { + "type": "object", + "properties": { + "min": { + "type": "integer", + "minimum": 1 + }, + "max": { + "type": "integer", + "minimum": 1 + } + }, + "required": ["min", "max"], + "additionalProperties": false + } + }, + "required": ["implementation", "fields"] + } + ] +}