From 596d8da65e012756f03da31e40d3a2763c7eae68 Mon Sep 17 00:00:00 2001 From: Filip Zajdel <35106656+FilipZajdel@users.noreply.github.com> Date: Thu, 5 Dec 2024 13:01:09 +0100 Subject: [PATCH] Add documentation button (#57) * 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. * Hide documentation button if there is no docs --- 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 | 24 ++++++++++++++++++++++-- scripts/validate-index.ts | 2 ++ site/src/app/AppBlock.tsx | 14 +++++++++++++- site/src/schema.ts | 11 ++++++++--- 9 files changed, 106 insertions(+), 17 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..7de348f 100644 --- a/scripts/generate-index-json.ts +++ b/scripts/generate-index-json.ts @@ -112,17 +112,36 @@ 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], ): 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 ?? await getReadmeUrl(orgId, app); console.log(colours.green(`Fetched data for ${orgId}/${app.name}`)); @@ -143,7 +162,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..cb20055 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); diff --git a/site/src/app/AppBlock.tsx b/site/src/app/AppBlock.tsx index d5c685b..5e069e3 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'; @@ -101,7 +102,7 @@ function AppBlock({ app, setShowingAppDetails }: Props): JSX.Element { const newQueryParams = new VSCodeQueryParams(app); newQueryParams.branch = branch; setQueryParams(newQueryParams); - }}/> + }} /> @@ -111,6 +112,17 @@ function AppBlock({ app, setShowingAppDetails }: Props): JSX.Element { > Instructions + + {!!app.docsUrl + && + 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',