From afb6962cef0ad7b59cddaa2df7aa11691fa6b744 Mon Sep 17 00:00:00 2001 From: FilipZajdel Date: Thu, 5 Dec 2024 10:35:50 +0100 Subject: [PATCH 1/2] Add a new button linked to documentation Add a new optional property 'docsUrl' to the index schema that allows to set the documentation's url. In case it isn't used, the readme is automatically linked. If the readme does not exist, the repo url is linked. --- index/hello-nrfcloud.json | 3 ++- package-lock.json | 26 ++++++++++++++++++++++++++ package.json | 1 + resources/output_schema.json | 14 ++++++++++++-- resources/schema.json | 28 ++++++++++++++++++++-------- scripts/generate-index-json.ts | 15 +++++++++++++-- scripts/validate-index.ts | 3 +++ site/src/app/AppBlock.tsx | 11 +++++++++++ site/src/schema.ts | 11 ++++++++--- 9 files changed, 96 insertions(+), 16 deletions(-) diff --git a/index/hello-nrfcloud.json b/index/hello-nrfcloud.json index 607e6d0..904042f 100644 --- a/index/hello-nrfcloud.json +++ b/index/hello-nrfcloud.json @@ -15,7 +15,8 @@ "tag": "v2.0.1", "sdk": "v2.8.0-rc2" } - ] + ], + "docsUrl": "https://hello-nrfcloud.github.io/firmware/html/index.html" } ] } diff --git a/package-lock.json b/package-lock.json index 1a75790..7108a61 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "@octokit/rest": "^20.0.1", "@primer/octicons-react": "^19.8.0", "ajv": "^8.12.0", + "ajv-formats": "3.0.1", "ansi-colors": "^4.1.3", "classnames": "^2.3.2", "date-fns": "^2.30.0", @@ -1167,6 +1168,23 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, "node_modules/ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -4639,6 +4657,14 @@ "uri-js": "^4.2.2" } }, + "ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "requires": { + "ajv": "^8.0.0" + } + }, "ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", diff --git a/package.json b/package.json index bca1b70..9a1fde7 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "@octokit/rest": "^20.0.1", "@primer/octicons-react": "^19.8.0", "ajv": "^8.12.0", + "ajv-formats": "3.0.1", "ansi-colors": "^4.1.3", "classnames": "^2.3.2", "date-fns": "^2.30.0", diff --git a/resources/output_schema.json b/resources/output_schema.json index fd7d58e..58bb9aa 100644 --- a/resources/output_schema.json +++ b/resources/output_schema.json @@ -135,7 +135,14 @@ "dfu", "thread", "matter", - "bt-mesh" + "bt-mesh", + "sidewalk", + "lora-basics-modem", + "CSS", + "FSK", + "ble", + "blecon", + "connectivity" ] } }, @@ -152,7 +159,7 @@ }, "date": { "type": "string", - "format": "date" + "format": "date-time" }, "sdk": { "type": "string" @@ -186,6 +193,9 @@ }, "apps": { "type": "string" + }, + "docsUrl": { + "type": "string" } }, "required": [ diff --git a/resources/schema.json b/resources/schema.json index 8c49bc0..d617b63 100644 --- a/resources/schema.json +++ b/resources/schema.json @@ -75,28 +75,39 @@ "type": "string", "description": "The name of the application license, e.g. \"Apache 2.0\". Inferred from the repo if missing." }, + "apps": { + "type": "string", + "description": "Glob pattern to find directories containing applications.\n\nApplications need a *.conf file and a CMakeLists.txt file at their root. The glob expressions are used to match directories, so no file pattern is necessary.\n\nBy default, the VS Code extension will assume that there's just a single application sitting at the root of the repo." + }, "releases": { "type": "array", + "description": "The collection of project`s releases.", "items": { "type": "object", "properties": { "tag": { - "type": "string" + "type": "string", + "description": "Git tag of the released version." }, "name": { - "type": "string" + "type": "string", + "description": "The title of the release." }, "date": { - "type": "string" + "type": "string", + "format": "date-time", + "description": "The date of publishing the release." }, "sdk": { - "type": "string" + "type": "string", + "description": "The nRF Connect SDK version the release is compatible with." } }, "required": [ "tag", "name", - "date" + "date", + "sdk" ], "additionalProperties": false }, @@ -106,16 +117,17 @@ "type": "string", "description": "The default git branch that the repository is checked out. Inferred from the repo if missing." }, - "apps": { + "docsUrl": { "type": "string", - "description": "Glob pattern to find directories containing applications.\n\nApplications need a *.conf file and a CMakeLists.txt file at their root. The glob expressions are used to match directories, so no file pattern is necessary.\n\nBy default, the VS Code extension will assume that there's just a single application sitting at the root of the repo." + "description": "The url of the addon's documentation" } }, "additionalProperties": false, "required": [ "name", "kind", - "tags" + "tags", + "releases" ] }, "description": "A list of applications contributed by the organization." diff --git a/scripts/generate-index-json.ts b/scripts/generate-index-json.ts index ddb3ae2..91c563c 100644 --- a/scripts/generate-index-json.ts +++ b/scripts/generate-index-json.ts @@ -117,12 +117,22 @@ async function fetchRepoData( app: OrgIndex['apps'][number], ): Promise { try { + const repoUrl = `https://github.com/${orgId}/${app.name}`; + const { data: repoData } = await octokit.repos.get({ owner: orgId, repo: app.name, }); - const repoUrl = `https://github.com/${orgId}/${app.name}`; + let docsUrl = app.docsUrl; + if (docsUrl === undefined) { + const { data } = await octokit.repos.getReadme({ + owner: orgId, + repo: app.name, + }); + + docsUrl = data.html_url ?? repoUrl; + } console.log(colours.green(`Fetched data for ${orgId}/${app.name}`)); @@ -143,7 +153,8 @@ async function fetchRepoData( forks: repoData.forks_count, apps: app.apps, releases: app.releases, - tags: app.tags + tags: app.tags, + docsUrl: docsUrl, }; } catch { throw new Error(`Failed to fetch data for ${orgId}/${app.name}`); diff --git a/scripts/validate-index.ts b/scripts/validate-index.ts index 89e3562..d2d6680 100644 --- a/scripts/validate-index.ts +++ b/scripts/validate-index.ts @@ -4,6 +4,7 @@ */ import Ajv, { ErrorObject } from 'ajv'; +import addFormats from 'ajv-formats'; import colours from 'ansi-colors'; import orgIndexSchema from '../resources/schema.json'; @@ -22,6 +23,7 @@ function reportError(file: string, error: ErrorObject) { async function run() { const ajv = new Ajv(); + addFormats(ajv); const files = await readOrgIndexFiles(); const validate = ajv.compile(orgIndexSchema); @@ -33,6 +35,7 @@ async function run() { if (!isValid) { validate.errors?.forEach((error) => reportError(file, error)); isError = true; + console.log(`${orgIndex} ${file}`) } } diff --git a/site/src/app/AppBlock.tsx b/site/src/app/AppBlock.tsx index d5c685b..ec1495b 100644 --- a/site/src/app/AppBlock.tsx +++ b/site/src/app/AppBlock.tsx @@ -17,6 +17,7 @@ import { StarIcon, TerminalIcon, VerifiedIcon, + BookIcon, } from '@primer/octicons-react'; import { useState } from 'react'; @@ -111,6 +112,16 @@ function AppBlock({ app, setShowingAppDetails }: Props): JSX.Element { > Instructions + + + Documentation +
diff --git a/site/src/schema.ts b/site/src/schema.ts index 593f7f1..eff7d72 100644 --- a/site/src/schema.ts +++ b/site/src/schema.ts @@ -108,7 +108,7 @@ export const appMetadataSchema = { properties: { tag: { type: 'string', description: 'Git tag of the released version.' }, name: { type: 'string', description: 'The title of the release.' }, - date: { type: 'string', format: 'date', description: 'The date of publishing the release.' }, + date: { type: 'string', format: 'date-time', description: 'The date of publishing the release.' }, sdk: { type: 'string', description: 'The nRF Connect SDK version the release is compatible with.' }, }, required: ['tag', 'name', 'date', 'sdk'], @@ -120,6 +120,10 @@ export const appMetadataSchema = { type: 'string', description: 'The default git branch that the repository is checked out. Inferred from the repo if missing.' }, + docsUrl: { + type: 'string', + description: `The url of the addon's documentation` + } }, additionalProperties: false, required: ['name', 'kind', 'tags', 'releases'], @@ -196,7 +200,7 @@ export const appSchema = { properties: { tag: { type: 'string' }, name: { type: 'string' }, - date: { type: 'string', format: 'date' }, + date: { type: 'string', format: 'date-time' }, sdk: { type: 'string' }, }, required: ['tag', 'name', 'date', 'sdk'], @@ -209,7 +213,8 @@ export const appSchema = { forks: { type: 'integer' }, defaultBranch: { type: 'string' }, lastUpdate: { type: 'string', format: 'date-time' }, - apps: { type: 'string' } + apps: { type: 'string' }, + docsUrl: { type: 'string' }, }, required: [ 'id', From 6c10b941efc493767c87ea73ccd1c78b70c6f832 Mon Sep 17 00:00:00 2001 From: FilipZajdel Date: Thu, 5 Dec 2024 11:27:35 +0100 Subject: [PATCH 2/2] Hide documentation button if there is no docs --- scripts/generate-index-json.ts | 27 ++++++++++++++++++--------- scripts/validate-index.ts | 1 - site/src/app/AppBlock.tsx | 21 +++++++++++---------- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/scripts/generate-index-json.ts b/scripts/generate-index-json.ts index 91c563c..7de348f 100644 --- a/scripts/generate-index-json.ts +++ b/scripts/generate-index-json.ts @@ -112,6 +112,23 @@ async function fetchOrgData({ } } +async function getReadmeUrl(orgId: string, app: OrgIndex['apps'][number]): Promise { + let readmeUrl: string | undefined; + + try { + const { data } = await octokit.repos.getReadme({ + owner: orgId, + repo: app.name, + }); + + readmeUrl = data.html_url ?? undefined; + } catch { + readmeUrl = undefined; + } + + return readmeUrl; +} + async function fetchRepoData( orgId: string, app: OrgIndex['apps'][number], @@ -124,15 +141,7 @@ async function fetchRepoData( repo: app.name, }); - let docsUrl = app.docsUrl; - if (docsUrl === undefined) { - const { data } = await octokit.repos.getReadme({ - owner: orgId, - repo: app.name, - }); - - docsUrl = data.html_url ?? repoUrl; - } + let docsUrl = app.docsUrl ?? await getReadmeUrl(orgId, app); console.log(colours.green(`Fetched data for ${orgId}/${app.name}`)); diff --git a/scripts/validate-index.ts b/scripts/validate-index.ts index d2d6680..cb20055 100644 --- a/scripts/validate-index.ts +++ b/scripts/validate-index.ts @@ -35,7 +35,6 @@ async function run() { if (!isValid) { validate.errors?.forEach((error) => reportError(file, error)); isError = true; - console.log(`${orgIndex} ${file}`) } } diff --git a/site/src/app/AppBlock.tsx b/site/src/app/AppBlock.tsx index ec1495b..5e069e3 100644 --- a/site/src/app/AppBlock.tsx +++ b/site/src/app/AppBlock.tsx @@ -102,7 +102,7 @@ function AppBlock({ app, setShowingAppDetails }: Props): JSX.Element { const newQueryParams = new VSCodeQueryParams(app); newQueryParams.branch = branch; setQueryParams(newQueryParams); - }}/> + }} /> @@ -113,15 +113,16 @@ function AppBlock({ app, setShowingAppDetails }: Props): JSX.Element { Instructions - - Documentation - + {!!app.docsUrl + && + Documentation + }