Skip to content

Explore CI for TOML definitions #627

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: CI

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Install dependencies
run: yarn

- name: Expand liquid
run: yarn expand-liquid

- name: Validate schemas
run: yarn validate-schemas
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
"@graphql-codegen/cli": "^3.2.2",
"@graphql-codegen/typescript": "^3.0.2",
"@graphql-codegen/typescript-operations": "^3.0.2",
"graphql": "^16.6.0"
"graphql": "^16.6.0",
"ajv": "8.17.1"
},
"scripts": {
"expand-liquid": "node ./util/expand-liquid.js",
"validate-schemas": "node ./util/validate-schemas.js",
"typegen": "yarn workspaces run graphql-code-generator --config package.json",
"test-js": "yarn expand-liquid vanilla-js && yarn && yarn typegen && yarn workspaces run test run",
"test-ts": "yarn expand-liquid typescript && yarn && yarn typegen && yarn workspaces run test run"
Expand Down
130 changes: 130 additions & 0 deletions util/validate-schemas.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import fs from 'node:fs/promises';
import path from 'node:path';

import toml from '@iarna/toml';
import Ajv from 'ajv';

const schema = {
type: 'object',
properties: {
api_version: {
type: 'string',
pattern: '^(202\\d{1}-\\d{2}|unstable)$', // Matches "202X-XX" format
},
extensions: {
type: 'array',
items: {
type: 'object',
properties: {
description: { type: 'string' },
handle: { type: 'string' },
name: { type: 'string' },
type: { type: 'string' },
// build: {
// type: 'object',
// properties: {
// command: { type: 'string' },
// path: { type: 'string' },
// additionalProperties: true, // Allow other properties in build
// },
// required: ['command', 'path'],
// },
// ui: {
// type: 'object',
// properties: {
// paths: {
// type: 'object',
// properties: {
// create: { type: 'string' },
// details: { type: 'string' },
// additionalProperties: { type: 'string' }, // Allow other paths
// },
// additionalProperties: true, // Allow other keys in paths
// },
// additionalProperties: true, // Allow other properties in ui
// },
// additionalProperties: true, // Allow other keys in ui
// },
// targeting: {
// type: 'array',
// items: {
// type: 'object',
// properties: {
// export: { type: 'string' },
// input_query: { type: 'string' },
// target: { type: 'string' },
// additionalProperties: true, // Allow other properties in targeting item
// },
// required: ['export', 'input_query', 'target'],
// additionalProperties: true, // Allow other keys in targeting item
// },
// },
// additionalProperties: true, // Allow other properties in extension
},
required: ['description', 'handle', 'name', 'type', 'build'],
additionalProperties: true, // Allow other keys in extension
},
},
additionalProperties: true, // Allow other top-level properties
},
required: ['api_version'],
// required: ['api_version', 'extensions'],
additionalProperties: true, // Allow other top-level keys
};

const ajv = new Ajv();
const compiledAjv = ajv.compile(schema);

async function findExtensionTomlFiles(directory) {
const files = await fs.readdir(directory);
const matchingFiles = [];

for (const file of files) {
if (file === 'node_modules') {
continue;
}

const fullPath = path.join(directory, file);
const stats = await fs.stat(fullPath);

if (stats.isFile() && file === 'shopify.extension.toml') {
matchingFiles.push(fullPath);
} else if (stats.isDirectory()) {
// Recursively search subdirectories
const subDirectoryFiles = await findExtensionTomlFiles(fullPath);
matchingFiles.push(...subDirectoryFiles);
}
}

return matchingFiles;
}

async function testSchema(filename) {
await fs.readFile(filename, 'utf8')
.then(data => {
const parsedData = toml.parse(data);
const isValid = compiledAjv(parsedData);

if (isValid) {
console.log(`Validation successful for ${filename}`);
} else {
console.error(`Validation failed for ${filename}:`);
console.error(compiledAjv.errors);

process.exit(-1)
}
})
.catch(_ => {
throw new Error(`Error reading file ${filename}.`);
});
}

async function test() {
const filenames = await findExtensionTomlFiles('./');

filenames.forEach(filename => {
testSchema(filename);
});
}

await test();