diff --git a/config/clients.config.json b/config/clients.config.json index 30adc378ade..626a2cba06b 100644 --- a/config/clients.config.json +++ b/config/clients.config.json @@ -1,4 +1,5 @@ { + "$schema": "./clients.schema.json", "csharp": { "clients": [ "abtesting", diff --git a/config/clients.schema.json b/config/clients.schema.json new file mode 100644 index 00000000000..43b7c167c58 --- /dev/null +++ b/config/clients.schema.json @@ -0,0 +1,98 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "clients": { + "oneOf": [ + { + "type": "array", + "items": { + "type": "string", + "enum": [ + "abtesting", + "analytics", + "composition", + "ingestion", + "insights", + "monitoring", + "personalization", + "query-suggestions", + "recommend", + "search" + ] + } + }, + { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "enum": [ + "algoliasearch", + "abtesting", + "analytics", + "composition", + "composition-full", + "ingestion", + "insights", + "monitoring", + "personalization", + "query-suggestions", + "recommend", + "search" + ] + }, + "output": { "type": "string" } + }, + "required": ["name", "output"], + "additionalProperties": false + } + } + ] + }, + "folder": { "type": "string", "description": "the output folder of your client, usually matching the github repository name, e.g. clients/algoliasearch-client-dart" }, + "gitRepoId": { "type": "string", "description": "the github repository name, without the organization or username that owns it, e.g. algoliasearch-client-php"}, + "packageVersion": { "type": "string", "description": "the version to publish the packages with, it must be semver compatible, e.g. 1.2.3" }, + "modelFolder": { "type": "string", "description": "the models folder, e.g. algoliasearch/models"}, + "apiFolder": { "type": "string", "description": "the api folder, e.g. lib/src"}, + "dockerImage": { + "type": "string", + "description": "whether your client requires a custom docker image with specific needs, most clients require 'apic_base'", + "enum": [ + "apic_base", + "apic_ruby", + "apic_swift" + ] + }, + "tests": { + "type": "object", + "properties": { + "extension": { "type": "string", "description": "the test file extension, e.g. .test.ts" }, + "outputFolder": { "type": "string", "description": "the test output folder, e.g. src/generated" } + }, + "required": ["extension", "outputFolder"], + "additionalProperties": false + }, + "snippets": { + "type": "object", + "properties": { + "extension": { "type": "string", "description": "the snippet file extension, e.g. .cs" }, + "outputFolder": { "type": "string", "description": "the snippet output folder, e.g. src" } + }, + "required": ["extension", "outputFolder"], + "additionalProperties": false + }, + "supportedVersions": { + "type": "array", + "description": "hints the CI on what matrix to generate for this client, this must be language specific versions, e.g. versions of node", + "items": { "type": "string" } + } + }, + "required": ["clients", "folder", "gitRepoId", "packageVersion", "modelFolder", "apiFolder", "tests", "snippets"], + "additionalProperties": false + } +} diff --git a/scripts/common.ts b/scripts/common.ts index 3d0288b7142..dafa85eec44 100644 --- a/scripts/common.ts +++ b/scripts/common.ts @@ -30,9 +30,13 @@ export const ROOT_DIR = path.resolve(process.cwd(), '..'); // Build `GENERATORS` from the `clients.config.json` file export const GENERATORS = Object.entries(clientsConfig).reduce( - (current, [language, { clients, folder, ...gen }]) => { - for (const client of clients) { - let output = folder; + (current, [language, opts]) => { + if (typeof opts === 'string') { + return current; + } + + for (const client of opts.clients) { + let output = opts.folder; let key = ''; let clientName = ''; @@ -47,7 +51,7 @@ export const GENERATORS = Object.entries(clientsConfig).reduce( current[key] = { additionalProperties: {}, - ...gen, + ...opts, output, client: clientName, language: language as Language, diff --git a/scripts/config.ts b/scripts/config.ts index 9bbdc4a6af4..6d87518f70f 100644 --- a/scripts/config.ts +++ b/scripts/config.ts @@ -8,6 +8,10 @@ export function getClientsConfigField( pathToField: string[] | string, required: boolean = true, ): any { + if (typeof clientsConfig[language] !== 'object') { + throw new Error(`${language} doesn't exist in clients.config.json`); + } + const config: LanguageConfig = clientsConfig[language]; const path = Array.isArray(pathToField) ? pathToField : [pathToField]; @@ -42,11 +46,11 @@ export function getTestOutputFolder(language: Language): string { } export function getDockerImage(language?: Language): string | undefined { - if (CI || !language || !('dockerImage' in clientsConfig[language])) { + if (CI || !language) { return undefined; } - return getClientsConfigField(language, 'dockerImage'); + return getClientsConfigField(language, 'dockerImage', false); } /** @@ -57,7 +61,7 @@ export function getPackageVersionDefault(language: Language): string { } export function getGitHubUrl(language: Language, options?: { token: string }): string { - const { gitRepoId } = clientsConfig[language]; + const gitRepoId = getClientsConfigField(language, ['gitRepoId']); // GitHub Action provides a default token for authentication // https://docs.github.com/en/actions/security-guides/automatic-token-authentication diff --git a/scripts/husky/pre-commit.mjs b/scripts/husky/pre-commit.mjs index e8d0d993532..02036ed3687 100755 --- a/scripts/husky/pre-commit.mjs +++ b/scripts/husky/pre-commit.mjs @@ -18,11 +18,14 @@ async function run(command) { export function getPatterns() { const entries = patterns; - for (const [language, { tests }] of Object.entries(clientConfig)) { - entries.unshift(`tests/output/${language}/${tests.outputFolder}/client/**`); - entries.unshift(`tests/output/${language}/${tests.outputFolder}/requests/**`); - entries.unshift(`tests/output/${language}/${tests.outputFolder}/e2e/**`); - entries.unshift(`tests/output/${language}/${tests.outputFolder}/benchmark/**`); + for (const [language, opts] of Object.entries(clientConfig)) { + if (typeof opts !== 'object') { + continue; + } + entries.unshift(`tests/output/${language}/${opts.tests.outputFolder}/client/**`); + entries.unshift(`tests/output/${language}/${opts.tests.outputFolder}/requests/**`); + entries.unshift(`tests/output/${language}/${opts.tests.outputFolder}/e2e/**`); + entries.unshift(`tests/output/${language}/${opts.tests.outputFolder}/benchmark/**`); } return entries; } diff --git a/scripts/release/updateAPIVersions.ts b/scripts/release/updateAPIVersions.ts index 4941ab4f118..2f619efc2c6 100755 --- a/scripts/release/updateAPIVersions.ts +++ b/scripts/release/updateAPIVersions.ts @@ -13,7 +13,7 @@ import type { Changelog, Versions } from './types.ts'; async function updateConfigFiles(versionsToRelease: Versions): Promise { // update the other versions in clients.config.json for (const lang of Object.keys(versionsToRelease) as Language[]) { - if (versionsToRelease[lang]?.next) { + if (typeof clientsConfig[lang] == 'object' && versionsToRelease[lang]?.next) { clientsConfig[lang].packageVersion = versionsToRelease[lang].next; } }