Skip to content

chore: add json schema for clients config #4657

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

Merged
merged 6 commits into from
Mar 26, 2025
Merged
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
1 change: 1 addition & 0 deletions config/clients.config.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"$schema": "./clients.schema.json",
"csharp": {
"clients": [
"abtesting",
Expand Down
98 changes: 98 additions & 0 deletions config/clients.schema.json
Original file line number Diff line number Diff line change
@@ -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
}
}
12 changes: 8 additions & 4 deletions scripts/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = '';

Expand All @@ -47,7 +51,7 @@ export const GENERATORS = Object.entries(clientsConfig).reduce(

current[key] = {
additionalProperties: {},
...gen,
...opts,
output,
client: clientName,
language: language as Language,
Expand Down
10 changes: 7 additions & 3 deletions scripts/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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];

Expand Down Expand Up @@ -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);
}

/**
Expand All @@ -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
Expand Down
13 changes: 8 additions & 5 deletions scripts/husky/pre-commit.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion scripts/release/updateAPIVersions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import type { Changelog, Versions } from './types.ts';
async function updateConfigFiles(versionsToRelease: Versions): Promise<void> {
// 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;
}
}
Expand Down