Browse Source

Validation script, CI check, more schemas

Leszek Wiesner 4 years ago
parent
commit
a083201cb0

+ 20 - 0
.github/workflows/content-directory-schemas.yml

@@ -0,0 +1,20 @@
+name: content-directory-schemas
+on: [pull_request, push]
+
+jobs:
+  schemas_checks:
+    name: Checks
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        node-version: [12.x]
+    steps:
+    - uses: actions/checkout@v1
+    - name: Use Node.js ${{ matrix.node-version }}
+      uses: actions/setup-node@v1
+      with:
+        node-version: ${{ matrix.node-version }}
+    - name: validate
+      run: |
+        yarn install --frozen-lockfile
+        yarn workspace content-directory-schemas validate

+ 4 - 0
content-directory-schemas/README.md

@@ -1,6 +1,10 @@
 ### Content directory json schemas and inputs
+
 #### Working in `VSCode`
 1. Create `.vscode` folder inside your working directory (if doesn't already exist)
 1. Copy `vscode-recommended.settings.json` into `.vscode` directory and rename it to `settings.json` (or merge it with the exsisting `settings.json`)
 1. If your working directory is not `content-directory-schema`, modify the `"url"` properties under `"json.schemas"` to match the relative paths from your working directory (ie. if inside root monorepo directory, you will need to add `/content-directory-schema`)
 1. Get the benefit of live-validation of files inside `inputs`! (you must follow the `*Class.json`, `*Schema.json` naming pattern)
+
+#### Validate via CLI
+Run `yarn workspace cd-schemas validate` or `yarn validate` (if inside `content-directory-schemas`) to validate json schemas and all inputs in the `/inputs` directory.

+ 4 - 0
content-directory-schemas/inputs/classes/10_LicenseClass.json

@@ -0,0 +1,4 @@
+{
+  "name": "License",
+  "description": "Describes a license the media can be published under"
+}

+ 4 - 0
content-directory-schemas/inputs/classes/7_VideoMediaEncodingClass.json

@@ -0,0 +1,4 @@
+{
+  "name": "VideoMediaEncoding",
+  "description": "Available encoding format for the video media"
+}

+ 4 - 0
content-directory-schemas/inputs/classes/8_KnownLicenseClass.json

@@ -0,0 +1,4 @@
+{
+  "name": "KnownLicenseType",
+  "description": "A commonly recognized license (ie. CC_BY_SA)"
+}

+ 4 - 0
content-directory-schemas/inputs/classes/9_UserDefinedLicenseClass.json

@@ -0,0 +1,4 @@
+{
+  "name": "UserDefinedLicense",
+  "description": "Custom license defined by the user"
+}

+ 17 - 0
content-directory-schemas/inputs/schemas/10_LicenseSchema.json

@@ -0,0 +1,17 @@
+{
+  "classId": 10,
+  "newProperties": [
+    {
+      "name": "knownLicense",
+      "description": "Reference to a known license",
+      "required": false,
+      "property_type": { "Single": { "Reference": { "classId": 8 } } }
+    },
+    {
+      "name": "userDefinedLicense",
+      "description": "Reference to user-defined license",
+      "required": false,
+      "property_type": { "Single": { "Reference": { "classId": 9, "sameOwner": true } } }
+    }
+  ]
+}

+ 12 - 0
content-directory-schemas/inputs/schemas/7_VideoMediaEncoding.json

@@ -0,0 +1,12 @@
+{
+  "classId": 7,
+  "newProperties": [
+    {
+      "name": "Name",
+      "description": "The name of the encoding format (ie. H264_mpeg4)",
+      "required": true,
+      "unique": true,
+      "property_type": { "Single": { "Text": 32 } }
+    }
+  ]
+}

+ 39 - 0
content-directory-schemas/inputs/schemas/8_KnownLicenseSchema.json

@@ -0,0 +1,39 @@
+{
+  "classId": 8,
+  "newProperties": [
+    {
+      "name": "code",
+      "description": "Short, commonly recognized code of the licence (ie. CC_BY_SA)",
+      "required": true,
+      "unique": true,
+      "property_type": {
+        "Single": { "Text": 16 }
+      }
+    },
+    {
+      "name": "name",
+      "description": "Full, descriptive name of the license (ie. Creative Commons - Attribution-NonCommercial-NoDerivs)",
+      "required": false,
+      "unique": true,
+      "property_type": {
+        "Single": { "Text": 64 }
+      }
+    },
+    {
+      "name": "description",
+      "description": "Short description of the license conditions",
+      "required": false,
+      "property_type": {
+        "Single": { "Text": 1024 }
+      }
+    },
+    {
+      "name": "url",
+      "description": "An url pointing to full license content",
+      "required": false,
+      "property_type": {
+        "Single": { "Text": 256 }
+      }
+    }
+  ]
+}

+ 13 - 0
content-directory-schemas/inputs/schemas/9_UserDefinedLicenseSchema.json

@@ -0,0 +1,13 @@
+{
+  "classId": 9,
+  "newProperties": [
+    {
+      "name": "content",
+      "description": "Custom license content",
+      "required": true,
+      "property_type": {
+        "Single": { "Text": 65535 }
+      }
+    }
+  ]
+}

+ 25 - 0
content-directory-schemas/package.json

@@ -0,0 +1,25 @@
+{
+  "name": "cd-schemas",
+  "version": "0.1.0",
+  "description": "JSON schemas, inputs and related tooling for Joystream content directory 2.0",
+  "author": "Joystream contributors",
+  "scripts": {
+    "validate": "ts-node ./scripts/validate.ts"
+  },
+  "dependencies": {
+    "ajv": "6.12.5"
+  },
+  "devDependencies": {
+    "ts-node": "^8.8.2",
+    "typescript": "^3.9.7"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/Joystream/joystream.git"
+  },
+  "license": "GPL-3.0-only",
+  "bugs": {
+    "url": "https://github.com/Joystream/joystream/issues"
+  },
+  "homepage": "https://github.com/Joystream/joystream"
+}

+ 58 - 0
content-directory-schemas/scripts/validate.ts

@@ -0,0 +1,58 @@
+import Ajv from 'ajv'
+import fs from 'fs'
+import path from 'path'
+import CreateClassSchema from '../schemas/CreateClass.schema.json'
+import AddClassSchemaSchema from '../schemas/AddClassSchema.schema.json'
+
+const INPUTS_LOCATION = path.join(__dirname, '../inputs')
+
+type JsonSchema = {
+  schemaName: string
+  jsonSchema: Record<string, unknown>
+  relatedInputDirectory: string
+}
+
+const schemas: JsonSchema[] = [
+  { schemaName: 'CreateClass', jsonSchema: CreateClassSchema, relatedInputDirectory: 'classes' },
+  { schemaName: 'AddClassSchema', jsonSchema: AddClassSchemaSchema, relatedInputDirectory: 'schemas' },
+]
+
+const ajv = new Ajv({ allErrors: true })
+
+schemas.forEach(({ schemaName, jsonSchema, relatedInputDirectory }) => {
+  // Validate the schema itself
+  console.log(`Validating schema for ${schemaName}...`)
+  if (!ajv.validateSchema(jsonSchema)) {
+    console.log(`\nERROR! ${schemaName} - schema validation failed!`)
+    console.log(ajv.errorsText(undefined, { separator: '\n' }))
+    console.log('\n')
+    process.exitCode = 100
+    return
+  }
+
+  // Validate inputs
+  console.log('Validating inputs...')
+  fs.readdirSync(path.join(INPUTS_LOCATION, relatedInputDirectory)).forEach((fileName) => {
+    const inputRelativePath = path.join(relatedInputDirectory, fileName)
+    console.log(`Validating ${inputRelativePath}...`)
+    const inputJson = fs.readFileSync(path.join(INPUTS_LOCATION, inputRelativePath)).toString()
+    let inputData
+    try {
+      inputData = JSON.parse(inputJson)
+    } catch (e) {
+      console.log(`\nERROR: ${inputRelativePath} - cannot parse the json!`)
+      console.log('\n')
+      process.exitCode = 100
+      return
+    }
+
+    if (!ajv.validate(jsonSchema, inputData)) {
+      console.log(`\nERROR! ${inputRelativePath} - validation failed!`)
+      console.log(ajv.errorsText(undefined, { separator: '\n' }))
+      console.log('\n')
+      process.exitCode = 100
+    }
+  })
+
+  console.log('\n\n')
+})

+ 21 - 0
content-directory-schemas/tsconfig.json

@@ -0,0 +1,21 @@
+{
+  "compilerOptions": {
+    "target": "ES2017",
+    "module": "commonjs",
+    "strict": true,
+    "noImplicitAny": true,
+    "noUnusedLocals": true,
+    "noImplicitReturns": true,
+    "moduleResolution": "node",
+    "allowSyntheticDefaultImports": true,     /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
+    "esModuleInterop": true,                  /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
+    "declaration": true,
+    "resolveJsonModule": true,
+    "types" : [
+      "node"
+    ],
+    "forceConsistentCasingInFileNames": true,
+    "baseUrl": "."
+  },
+  "include": [ "scripts/**/*" ]
+}

+ 2 - 1
package.json

@@ -21,7 +21,8 @@
     "devops/prettier-config",
     "pioneer",
     "pioneer/packages/*",
-    "utils/api-examples"
+    "utils/api-examples",
+    "content-directory-schemas"
   ],
   "resolutions": {
     "@polkadot/api": "1.26.1",

+ 10 - 0
yarn.lock

@@ -5724,6 +5724,16 @@ ajv-keywords@^3.1.0, ajv-keywords@^3.4.1:
   resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
   integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==
 
+ajv@6.12.5:
+  version "6.12.5"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.5.tgz#19b0e8bae8f476e5ba666300387775fb1a00a4da"
+  integrity sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag==
+  dependencies:
+    fast-deep-equal "^3.1.1"
+    fast-json-stable-stringify "^2.0.0"
+    json-schema-traverse "^0.4.1"
+    uri-js "^4.2.2"
+
 ajv@^6.1.0, ajv@^6.12.0, ajv@^6.12.2, ajv@^6.12.3:
   version "6.12.3"
   resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.3.tgz#18c5af38a111ddeb4f2697bd78d68abc1cabd706"